From 48e919a7bf7f3e7da385b710fb3f1d3bd1d56399 Mon Sep 17 00:00:00 2001 From: Moritz Marquardt Date: Mon, 1 Apr 2024 21:59:09 +0200 Subject: [PATCH] Cache empty files & fix #303 (missing content cache) --- server/gitea/cache.go | 14 ++++++++------ server/gitea/client.go | 34 ++++------------------------------ 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/server/gitea/cache.go b/server/gitea/cache.go index 23995d1..8a2b06a 100644 --- a/server/gitea/cache.go +++ b/server/gitea/cache.go @@ -99,6 +99,7 @@ type writeCacheReader struct { cacheKey string cache cache.ICache hasError bool + doNotCache bool } func (t *writeCacheReader) Read(p []byte) (n int, err error) { @@ -108,19 +109,20 @@ func (t *writeCacheReader) Read(p []byte) (n int, err error) { log.Trace().Err(err).Msgf("[cache] original reader for %q has returned an error", t.cacheKey) t.hasError = true } else if n > 0 { - _, _ = t.buffer.Write(p[:n]) + if t.buffer.Len()+n > int(fileCacheSizeLimit) { + t.doNotCache = true + t.buffer.Reset() + } else { + _, _ = t.buffer.Write(p[:n]) + } } return } func (t *writeCacheReader) Close() error { - doWrite := !t.hasError + doWrite := !t.hasError && !t.doNotCache fc := *t.fileResponse fc.Body = t.buffer.Bytes() - if fc.IsEmpty() { - log.Trace().Msg("[cache] file response is empty") - doWrite = false - } if doWrite { err := t.cache.Set(t.cacheKey+"|Metadata", []byte(fc.MetadataAsString()), fileCacheTimeout) if err != nil { diff --git a/server/gitea/client.go b/server/gitea/client.go index 8f98dd9..9ae13dc 100644 --- a/server/gitea/client.go +++ b/server/gitea/client.go @@ -9,7 +9,6 @@ import ( "net/http" "net/url" "path" - "strconv" "strings" "time" @@ -123,19 +122,17 @@ func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource str cachedHeader, cachedStatusCode := cache.createHttpResponse(cacheKey) // TODO: check against some timestamp mismatch?!? if cache.Exists { - log.Debug().Msg("[cache] exists") if cache.IsSymlink { linkDest := string(cache.Body) log.Debug().Msgf("[cache] follow symlink from %q to %q", resource, linkDest) return client.ServeRawContent(targetOwner, targetRepo, ref, linkDest) - } else if !cache.IsEmpty() { + } else { log.Debug().Msgf("[cache] return %d bytes", len(cache.Body)) return io.NopCloser(bytes.NewReader(cache.Body)), cachedHeader, cachedStatusCode, nil - } else if cache.IsEmpty() { - log.Debug().Msg("[cache] is empty") - // TODO: empty files aren't cached anyways; but when closing the issue please make sure that a missing body cache key is also handled correctly. } - } // TODO: handle missing pages if they redirect to a index.html + } else { + return nil, nil, http.StatusNotFound, ErrorNotFound + } } // TODO: metadata not written, is close ever called? log.Trace().Msg("file not in cache") @@ -186,10 +183,6 @@ func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource str mimeType := client.getMimeTypeByExtension(resource) resp.Response.Header.Set(ContentTypeHeader, mimeType) - if !shouldRespBeSavedToCache(resp.Response) { - return reader, resp.Response.Header, resp.StatusCode, err - } - // now we write to cache and respond at the same time fileResp := FileResponse{ Exists: true, @@ -321,22 +314,3 @@ func (client *Client) getMimeTypeByExtension(resource string) string { log.Trace().Msgf("probe mime of %q is %q", resource, mimeType) return mimeType } - -func shouldRespBeSavedToCache(resp *http.Response) bool { - if resp == nil { - return false - } - - contentLengthRaw := resp.Header.Get(ContentLengthHeader) - if contentLengthRaw == "" { - return false - } - - contentLength, err := strconv.ParseInt(contentLengthRaw, 10, 64) - if err != nil { - log.Error().Err(err).Msg("could not parse content length") - } - - // if content to big or could not be determined we not cache it - return contentLength > 0 && contentLength < fileCacheSizeLimit -}