Merge branch 'main' into main

pull/290/head
6543 2024-03-24 09:29:49 +00:00
commit 376d4e0b7c
5 zmienionych plików z 42 dodań i 17 usunięć

Wyświetl plik

@ -117,7 +117,7 @@ Thank you very much.
Make sure you have [golang](https://go.dev) v1.21 or newer and [just](https://just.systems/man/en/) installed. Make sure you have [golang](https://go.dev) v1.21 or newer and [just](https://just.systems/man/en/) installed.
run `just dev` run `just dev`
now this pages should work: now these pages should work:
- <https://cb_pages_tests.localhost.mock.directory:4430/images/827679288a.jpg> - <https://cb_pages_tests.localhost.mock.directory:4430/images/827679288a.jpg>
- <https://momar.localhost.mock.directory:4430/ci-testing/> - <https://momar.localhost.mock.directory:4430/ci-testing/>

Wyświetl plik

@ -42,7 +42,7 @@ type FileResponse struct {
} }
func (f FileResponse) IsEmpty() bool { func (f FileResponse) IsEmpty() bool {
return len(f.Body) != 0 return len(f.Body) == 0
} }
func (f FileResponse) createHttpResponse(cacheKey string) (header http.Header, statusCode int) { func (f FileResponse) createHttpResponse(cacheKey string) (header http.Header, statusCode int) {
@ -75,13 +75,14 @@ type BranchTimestamp struct {
type writeCacheReader struct { type writeCacheReader struct {
originalReader io.ReadCloser originalReader io.ReadCloser
buffer *bytes.Buffer buffer *bytes.Buffer
rileResponse *FileResponse fileResponse *FileResponse
cacheKey string cacheKey string
cache cache.ICache cache cache.ICache
hasError bool hasError bool
} }
func (t *writeCacheReader) Read(p []byte) (n int, err error) { func (t *writeCacheReader) Read(p []byte) (n int, err error) {
log.Trace().Msgf("[cache] read %q", t.cacheKey)
n, err = t.originalReader.Read(p) n, err = t.originalReader.Read(p)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
log.Trace().Err(err).Msgf("[cache] original reader for %q has returned an error", t.cacheKey) log.Trace().Err(err).Msgf("[cache] original reader for %q has returned an error", t.cacheKey)
@ -93,12 +94,20 @@ func (t *writeCacheReader) Read(p []byte) (n int, err error) {
} }
func (t *writeCacheReader) Close() error { func (t *writeCacheReader) Close() error {
if !t.hasError { doWrite := !t.hasError
fc := *t.rileResponse fc := *t.fileResponse
fc.Body = t.buffer.Bytes() fc.Body = t.buffer.Bytes()
_ = t.cache.Set(t.cacheKey, fc, fileCacheTimeout) if fc.IsEmpty() {
log.Trace().Msg("[cache] file response is empty")
doWrite = false
} }
log.Trace().Msgf("cacheReader for %q saved=%t closed", t.cacheKey, !t.hasError) if doWrite {
err := t.cache.Set(t.cacheKey, fc, fileCacheTimeout)
if err != nil {
log.Trace().Err(err).Msgf("[cache] writer for %q has returned an error", t.cacheKey)
}
}
log.Trace().Msgf("cacheReader for %q saved=%t closed", t.cacheKey, doWrite)
return t.originalReader.Close() return t.originalReader.Close()
} }
@ -111,7 +120,7 @@ func (f FileResponse) CreateCacheReader(r io.ReadCloser, cache cache.ICache, cac
return &writeCacheReader{ return &writeCacheReader{
originalReader: r, originalReader: r,
buffer: bytes.NewBuffer(make([]byte, 0)), buffer: bytes.NewBuffer(make([]byte, 0)),
rileResponse: &f, fileResponse: &f,
cache: cache, cache: cache,
cacheKey: cacheKey, cacheKey: cacheKey,
} }

Wyświetl plik

@ -113,26 +113,27 @@ func (client *Client) GiteaRawContent(targetOwner, targetRepo, ref, resource str
func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource string) (io.ReadCloser, http.Header, int, error) { func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource string) (io.ReadCloser, http.Header, int, error) {
cacheKey := fmt.Sprintf("%s/%s/%s|%s|%s", rawContentCacheKeyPrefix, targetOwner, targetRepo, ref, resource) cacheKey := fmt.Sprintf("%s/%s/%s|%s|%s", rawContentCacheKeyPrefix, targetOwner, targetRepo, ref, resource)
log := log.With().Str("cache_key", cacheKey).Logger() log := log.With().Str("cache_key", cacheKey).Logger()
log.Trace().Msg("try file in cache")
// handle if cache entry exist // handle if cache entry exist
if cache, ok := client.responseCache.Get(cacheKey); ok { if cache, ok := client.responseCache.Get(cacheKey); ok {
cache := cache.(FileResponse) cache := cache.(FileResponse)
cachedHeader, cachedStatusCode := cache.createHttpResponse(cacheKey) cachedHeader, cachedStatusCode := cache.createHttpResponse(cacheKey)
// TODO: check against some timestamp mismatch?!? // TODO: check against some timestamp mismatch?!?
if cache.Exists { if cache.Exists {
log.Debug().Msg("[cache] exists")
if cache.IsSymlink { if cache.IsSymlink {
linkDest := string(cache.Body) linkDest := string(cache.Body)
log.Debug().Msgf("[cache] follow symlink from %q to %q", resource, linkDest) log.Debug().Msgf("[cache] follow symlink from %q to %q", resource, linkDest)
return client.ServeRawContent(targetOwner, targetRepo, ref, linkDest) return client.ServeRawContent(targetOwner, targetRepo, ref, linkDest)
} else { } else if !cache.IsEmpty() {
log.Debug().Msg("[cache] return bytes") log.Debug().Msgf("[cache] return %d bytes", len(cache.Body))
return io.NopCloser(bytes.NewReader(cache.Body)), cachedHeader, cachedStatusCode, nil return io.NopCloser(bytes.NewReader(cache.Body)), cachedHeader, cachedStatusCode, nil
} else if cache.IsEmpty() {
log.Debug().Msg("[cache] is empty")
} }
} else {
return nil, cachedHeader, cachedStatusCode, ErrorNotFound
} }
} }
log.Trace().Msg("file not in cache")
// not in cache, open reader via gitea api // not in cache, open reader via gitea api
reader, resp, err := client.sdkClient.GetFileReader(targetOwner, targetRepo, ref, resource, client.supportLFS) reader, resp, err := client.sdkClient.GetFileReader(targetOwner, targetRepo, ref, resource, client.supportLFS)
if resp != nil { if resp != nil {
@ -156,12 +157,14 @@ func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource str
linkDest = path.Join(path.Dir(resource), linkDest) linkDest = path.Join(path.Dir(resource), linkDest)
// we store symlink not content to reduce duplicates in cache // we store symlink not content to reduce duplicates in cache
if err := client.responseCache.Set(cacheKey, FileResponse{ fileResponse := FileResponse{
Exists: true, Exists: true,
IsSymlink: true, IsSymlink: true,
Body: []byte(linkDest), Body: []byte(linkDest),
ETag: resp.Header.Get(ETagHeader), ETag: resp.Header.Get(ETagHeader),
}, fileCacheTimeout); err != nil { }
log.Trace().Msgf("file response has %d bytes", len(fileResponse.Body))
if err := client.responseCache.Set(cacheKey, fileResponse, fileCacheTimeout); err != nil {
log.Error().Err(err).Msg("[cache] error on cache write") log.Error().Err(err).Msg("[cache] error on cache write")
} }

Wyświetl plik

@ -26,6 +26,7 @@ func Handler(
dnsLookupCache, canonicalDomainCache, redirectsCache cache.ICache, dnsLookupCache, canonicalDomainCache, redirectsCache cache.ICache,
) http.HandlerFunc { ) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) { return func(w http.ResponseWriter, req *http.Request) {
log.Debug().Msg("\n----------------------------------------------------------")
log := log.With().Strs("Handler", []string{req.Host, req.RequestURI}).Logger() log := log.With().Strs("Handler", []string{req.Host, req.RequestURI}).Logger()
ctx := context.New(w, req) ctx := context.New(w, req)

Wyświetl plik

@ -56,6 +56,8 @@ type Options struct {
func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redirectsCache cache.ICache) bool { func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redirectsCache cache.ICache) bool {
log := log.With().Strs("upstream", []string{o.TargetOwner, o.TargetRepo, o.TargetBranch, o.TargetPath}).Logger() log := log.With().Strs("upstream", []string{o.TargetOwner, o.TargetRepo, o.TargetBranch, o.TargetPath}).Logger()
log.Debug().Msg("Start")
if o.TargetOwner == "" || o.TargetRepo == "" { if o.TargetOwner == "" || o.TargetRepo == "" {
html.ReturnErrorPage(ctx, "forge client: either repo owner or name info is missing", http.StatusBadRequest) html.ReturnErrorPage(ctx, "forge client: either repo owner or name info is missing", http.StatusBadRequest)
return true return true
@ -104,13 +106,16 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi
// Handle not found error // Handle not found error
if err != nil && errors.Is(err, gitea.ErrorNotFound) { if err != nil && errors.Is(err, gitea.ErrorNotFound) {
log.Debug().Msg("Handling not found error")
// Get and match redirects // Get and match redirects
redirects := o.getRedirects(giteaClient, redirectsCache) redirects := o.getRedirects(giteaClient, redirectsCache)
if o.matchRedirects(ctx, giteaClient, redirects, redirectsCache) { if o.matchRedirects(ctx, giteaClient, redirects, redirectsCache) {
log.Trace().Msg("redirect")
return true return true
} }
if o.TryIndexPages { if o.TryIndexPages {
log.Trace().Msg("try index page")
// copy the o struct & try if an index page exists // copy the o struct & try if an index page exists
optionsForIndexPages := *o optionsForIndexPages := *o
optionsForIndexPages.TryIndexPages = false optionsForIndexPages.TryIndexPages = false
@ -121,6 +126,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi
return true return true
} }
} }
log.Trace().Msg("try html file with path name")
// compatibility fix for GitHub Pages (/example → /example.html) // compatibility fix for GitHub Pages (/example → /example.html)
optionsForIndexPages.appendTrailingSlash = false optionsForIndexPages.appendTrailingSlash = false
optionsForIndexPages.redirectIfExists = strings.TrimSuffix(ctx.Path(), "/") + ".html" optionsForIndexPages.redirectIfExists = strings.TrimSuffix(ctx.Path(), "/") + ".html"
@ -130,8 +136,11 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi
} }
} }
log.Trace().Msg("not found")
ctx.StatusCode = http.StatusNotFound ctx.StatusCode = http.StatusNotFound
if o.TryIndexPages { if o.TryIndexPages {
log.Trace().Msg("try not found page")
// copy the o struct & try if a not found page exists // copy the o struct & try if a not found page exists
optionsForNotFoundPages := *o optionsForNotFoundPages := *o
optionsForNotFoundPages.TryIndexPages = false optionsForNotFoundPages.TryIndexPages = false
@ -142,6 +151,7 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi
return true return true
} }
} }
log.Trace().Msg("not found page missing")
} }
return false return false
@ -173,10 +183,12 @@ func (o *Options) Upstream(ctx *context.Context, giteaClient *gitea.Client, redi
// Append trailing slash if missing (for index files), and redirect to fix filenames in general // Append trailing slash if missing (for index files), and redirect to fix filenames in general
// o.appendTrailingSlash is only true when looking for index pages // o.appendTrailingSlash is only true when looking for index pages
if o.appendTrailingSlash && !strings.HasSuffix(ctx.Path(), "/") { if o.appendTrailingSlash && !strings.HasSuffix(ctx.Path(), "/") {
log.Trace().Msg("append trailing slash and redirect")
ctx.Redirect(ctx.Path()+"/", http.StatusTemporaryRedirect) ctx.Redirect(ctx.Path()+"/", http.StatusTemporaryRedirect)
return true return true
} }
if strings.HasSuffix(ctx.Path(), "/index.html") && !o.ServeRaw { if strings.HasSuffix(ctx.Path(), "/index.html") && !o.ServeRaw {
log.Trace().Msg("remove index.html from path and redirect")
ctx.Redirect(strings.TrimSuffix(ctx.Path(), "index.html"), http.StatusTemporaryRedirect) ctx.Redirect(strings.TrimSuffix(ctx.Path(), "index.html"), http.StatusTemporaryRedirect)
return true return true
} }