From 3e6dfb313b07f9d9eeeb15f1c956d92e3587c6f5 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 7 Oct 2020 10:20:19 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A5set=20a=20`Cache=20Control`=20heade?= =?UTF-8?q?r=20for=20static=20ressources?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now, each static request returns the file without any cache control header. If you are using `app.Static` to serve your assets, the browser shouldn't cache it. This PR introduces a way to set the cache control header (if the file was found) on the file response to set a custom max-age to e.g. cache it 1 year. --- app.go | 6 ++++++ app_test.go | 20 +++++++++++++++++++- router.go | 11 +++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/app.go b/app.go index 71e8907e..c7067f31 100644 --- a/app.go +++ b/app.go @@ -261,6 +261,12 @@ type Static struct { // The name of the index file for serving a directory. // Optional. Default value "index.html". Index string `json:"index"` + + // The value for the Cache-Control HTTP-header + // that is set on the file response. MaxAge is defined in seconds. + // + // Optional. Default value 0. + MaxAge int `json:"max_age"` } // Default Config values diff --git a/app_test.go b/app_test.go index d5dd4f2e..f8911106 100644 --- a/app_test.go +++ b/app_test.go @@ -562,12 +562,30 @@ func Test_App_Static_Direct(t *testing.T) { utils.AssertEqual(t, nil, err, "app.Test(req)") utils.AssertEqual(t, 200, resp.StatusCode, "Status code") utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "") - utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get(HeaderContentType)) + utils.AssertEqual(t, "text/plain; charset=utf-8", resp.Header.Get("Content-Type")) + utils.AssertEqual(t, "", resp.Header.Get(HeaderCacheControl), "CacheControl Control") + body, err = ioutil.ReadAll(resp.Body) utils.AssertEqual(t, nil, err) utils.AssertEqual(t, true, strings.Contains(string(body), "gofiber.io/support")) } + +// go test -run Test_App_Static_MaxAge +func Test_App_Static_MaxAge(t *testing.T) { + app := New() + + app.Static("/", "./.github", Static{MaxAge: 100}) + + resp, err := app.Test(httptest.NewRequest("GET", "/index.html", nil)) + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, 200, resp.StatusCode, "Status code") + utils.AssertEqual(t, false, resp.Header.Get(HeaderContentLength) == "") + utils.AssertEqual(t, "text/html; charset=utf-8", resp.Header.Get(HeaderContentType)) + utils.AssertEqual(t, "public, max-age=100", resp.Header.Get(HeaderCacheControl), "CacheControl Control") +} + +// go test -run Test_App_Static_Group func Test_App_Static_Group(t *testing.T) { app := New() diff --git a/router.go b/router.go index 5d81e610..63874f37 100644 --- a/router.go +++ b/router.go @@ -7,6 +7,7 @@ package fiber import ( "fmt" "sort" + "strconv" "strings" "time" @@ -338,8 +339,15 @@ func (app *App) registerStatic(prefix, root string, config ...Static) Router { fctx.Response.SetStatusCode(StatusNotFound) }, } + // Set config if provided + var cacheControlValue string if len(config) > 0 { + maxAge := config[0].MaxAge + if maxAge > 0 { + cacheControlValue = "public, max-age=" + strconv.Itoa(maxAge) + } + fs.Compress = config[0].Compress fs.AcceptByteRange = config[0].ByteRange fs.GenerateIndexPages = config[0].Browse @@ -354,6 +362,9 @@ func (app *App) registerStatic(prefix, root string, config ...Static) Router { // Return request if found and not forbidden status := c.fasthttp.Response.StatusCode() if status != StatusNotFound && status != StatusForbidden { + if len(cacheControlValue) > 0 { + c.fasthttp.Response.Header.Set(HeaderCacheControl, cacheControlValue) + } return nil } // Reset response to default