From f576a1a21eccacdd275d9b16514f1bf9252af7d1 Mon Sep 17 00:00:00 2001 From: Gusted Date: Wed, 3 Jun 2026 05:38:47 +0200 Subject: [PATCH] feat: remove `no-transform` in `Cache-Control` header. (#12905) First, why was this header here in the first place? Cloudflare! Cloudflare had a optimization setting called "auto-minfy" and would minify HTML,JS,CSS - this included removing extra whitespaces from `` elements. That's a problem because files are shown per-line with a `` element and thus results in indentation being completely gone. Gitea added a FAQ entry for this [1], but on the same day decided to add the workaround in Gitea, the `no-transform` header [2]. I can't find a reference of this option and some posts suggests it's been removed. Thus it no longer serves a need to be present in Forgejo. That wasn't my intentional motivation to remove this. This header is also causing that HAProxy will not compress responses [3] from Forgejo which is not ideal for Codeberg, this behavior cannot be turned off or be worked around. Potential risk, some other CDN or some other Cloudflare option might still do this removal of whitespace in `` HTML tags, it seems better to disable the feature than to have Forgejo add a header which is also causing other side-effects. I'm not aware of this another CDN of Cloudflare option so I don't want to mark it as breaking. [1]: https://github.com/go-gitea/gitea/pull/20430 [2]: https://github.com/go-gitea/gitea/pull/20432 [3]: https://docs.haproxy.org/3.3/configuration.html#:~:text=the%20response%20contains%20the%20%22no-transform%22%20value%20in%20the%20%22Cache-control%22%20%20%20%20%20header Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12905 Reviewed-by: Otto Reviewed-by: Mathieu Fenniak Reviewed-by: 0ko <0ko@noreply.codeberg.org> --- modules/httpcache/httpcache.go | 6 +++--- routers/common/errpage.go | 2 +- services/context/api.go | 2 +- services/context/context.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/httpcache/httpcache.go b/modules/httpcache/httpcache.go index 311f7215b2..c37ce6c013 100644 --- a/modules/httpcache/httpcache.go +++ b/modules/httpcache/httpcache.go @@ -14,8 +14,8 @@ import ( ) // SetCacheControlInHeader sets suitable cache-control headers in the response -func SetCacheControlInHeader(h http.Header, maxAge time.Duration, additionalDirectives ...string) { - directives := make([]string, 0, 2+len(additionalDirectives)) +func SetCacheControlInHeader(h http.Header, maxAge time.Duration) { + directives := make([]string, 0, 2) // "max-age=0 + must-revalidate" (aka "no-cache") is preferred instead of "no-store" // because browsers may restore some input fields after navigate-back / reload a page. @@ -33,7 +33,7 @@ func SetCacheControlInHeader(h http.Header, maxAge time.Duration, additionalDire h.Set("X-Forgejo-Debug", "RUN_MODE="+setting.RunMode) } - h.Set("Cache-Control", strings.Join(append(directives, additionalDirectives...), ", ")) + h.Set("Cache-Control", strings.Join(directives, ", ")) } func ServeContentWithCacheControl(w http.ResponseWriter, req *http.Request, name string, modTime time.Time, content io.ReadSeeker) { diff --git a/routers/common/errpage.go b/routers/common/errpage.go index 4dc5a58858..19154b4e20 100644 --- a/routers/common/errpage.go +++ b/routers/common/errpage.go @@ -32,7 +32,7 @@ func RenderPanicErrorPage(w http.ResponseWriter, req *http.Request, err any) { routing.UpdatePanicError(req.Context(), err) - httpcache.SetCacheControlInHeader(w.Header(), 0, "no-transform") + httpcache.SetCacheControlInHeader(w.Header(), 0) w.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions) tmplCtx := templates.NewContext(req.Context()) diff --git a/services/context/api.go b/services/context/api.go index a6af94dfde..0284783549 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -293,7 +293,7 @@ func APIContexter() func(http.Handler) http.Handler { ctx.AppendContextValue(apiContextKey, ctx) ctx.AppendContextValueFunc(gitrepo.RepositoryContextKey, func() any { return ctx.Repo.GitRepo }) - httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0, "no-transform") + httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0) ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions) next.ServeHTTP(ctx.Resp, ctx.Req) diff --git a/services/context/context.go b/services/context/context.go index af5ec26143..d5c4f6fd2a 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -177,7 +177,7 @@ func Contexter() func(next http.Handler) http.Handler { } }) - httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0, "no-transform") + httpcache.SetCacheControlInHeader(ctx.Resp.Header(), 0) ctx.Resp.Header().Set(`X-Frame-Options`, setting.CORSConfig.XFrameOptions) ctx.Data["SystemConfig"] = setting.Config()