From 0e90cc01120469b3a7743f1502cf7186d0d35122 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Else Date: Thu, 26 Nov 2020 09:44:44 +0100 Subject: [PATCH] Etag and Last-Modified headers --- cache.go | 27 +++++++++++++++++---------- go.mod | 5 +++-- go.sum | 10 ++++++---- templates/header.gohtml | 4 +--- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/cache.go b/cache.go index b8b2bf9..ef96f1e 100644 --- a/cache.go +++ b/cache.go @@ -11,6 +11,7 @@ import ( "strconv" "time" + "github.com/araddon/dateparse" lru "github.com/hashicorp/golang-lru" "golang.org/x/sync/singleflight" ) @@ -42,21 +43,25 @@ func cacheMiddleware(next http.Handler) http.Handler { return getCache(key, next, r), nil }) cache := cacheInterface.(*cacheItem) - var expiresIn int64 = 0 - if cache.expiration != 0 { - expiresIn = cache.creationTime + int64(cache.expiration) - time.Now().Unix() - } // copy cached headers for k, v := range cache.header { w.Header()[k] = v } - setCacheHeaders(w, cache.hash, expiresIn) + setCacheHeaders(w, cache) // check conditional request if ifNoneMatchHeader := r.Header.Get("If-None-Match"); ifNoneMatchHeader != "" && ifNoneMatchHeader == cache.hash { // send 304 w.WriteHeader(http.StatusNotModified) return } + if ifModifiedSinceHeader := r.Header.Get("If-Modified-Since"); ifModifiedSinceHeader != "" { + t, err := dateparse.ParseAny(ifModifiedSinceHeader) + if err == nil && t.Unix() >= cache.creationTime { + // send 304 + w.WriteHeader(http.StatusNotModified) + return + } + } // set status code w.WriteHeader(cache.code) // write cached body @@ -72,14 +77,16 @@ func cacheKey(r *http.Request) string { return r.URL.String() } -func setCacheHeaders(w http.ResponseWriter, hash string, expiresIn int64) { +func setCacheHeaders(w http.ResponseWriter, cache *cacheItem) { w.Header().Del(cacheInternalExpirationHeader) - w.Header().Set("ETag", hash) - if expiresIn != 0 { + w.Header().Set("ETag", cache.hash) + w.Header().Set("Last-Modified", time.Unix(cache.creationTime, 0).UTC().Format(http.TimeFormat)) + if cache.expiration != 0 { + expiresIn := cache.creationTime + int64(cache.expiration) - time.Now().Unix() // Set expires time - w.Header().Set("Cache-Control", fmt.Sprintf("public,max-age=%d", expiresIn)) + w.Header().Set("Cache-Control", fmt.Sprintf("public,max-age=%d,stale-while-revalidate=%d", expiresIn, cache.expiration)) } else { - w.Header().Set("Cache-Control", fmt.Sprintf("public,max-age=%d,s-max-age=%d", appConfig.Cache.Expiration, appConfig.Cache.Expiration/3)) + w.Header().Set("Cache-Control", fmt.Sprintf("public,max-age=%d,s-max-age=%d,stale-while-revalidate=%d", appConfig.Cache.Expiration, appConfig.Cache.Expiration/3, appConfig.Cache.Expiration)) } } diff --git a/go.mod b/go.mod index 402cc6f..d447a98 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/viper v1.7.1 github.com/tdewolff/minify/v2 v2.9.10 + github.com/tdewolff/parse/v2 v2.5.6 // indirect github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2 github.com/writeas/go-nodeinfo v1.0.0 @@ -55,10 +56,10 @@ require ( golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect golang.org/x/text v0.3.4 // indirect - golang.org/x/tools v0.0.0-20201124202034-299f270db459 // indirect + golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect gopkg.in/ini.v1 v1.62.0 // indirect - gopkg.in/yaml.v2 v2.3.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 honnef.co/go/tools v0.0.1-2020.1.6 // indirect willnorris.com/go/microformats v1.1.1 diff --git a/go.sum b/go.sum index 050b25e..771f133 100644 --- a/go.sum +++ b/go.sum @@ -306,6 +306,8 @@ github.com/tdewolff/minify/v2 v2.9.10 h1:p+ifTTl+JMFFLDYNAm7nxQ9XuCG10HTW00wlPAZ github.com/tdewolff/minify/v2 v2.9.10/go.mod h1:U1Nc+/YBSB0FPEarqcgkYH3Ep4DNyyIbOyl5P4eWMuo= github.com/tdewolff/parse/v2 v2.5.5 h1:b7ICJa4I/54JQGEGgTte8DiyJPKcC5g8V773QMzkeUM= github.com/tdewolff/parse/v2 v2.5.5/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= +github.com/tdewolff/parse/v2 v2.5.6 h1:fpy81gxFbbPd0Zv0taPAxXc+c96tdo1tZFYXrr2nQlU= +github.com/tdewolff/parse/v2 v2.5.6/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -474,8 +476,8 @@ golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnf golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201124202034-299f270db459 h1:XrUnpqJ8xqeZHrgPu3FuYCv9/O3MrxnIKh5/+MLDE8Q= -golang.org/x/tools v0.0.0-20201124202034-299f270db459/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b h1:Lq5JUTFhiybGVf28jB6QRpqd13/JPOaCnET17PVzYJE= +golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= @@ -522,8 +524,8 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= diff --git a/templates/header.gohtml b/templates/header.gohtml index 50fb986..3b57ae1 100644 --- a/templates/header.gohtml +++ b/templates/header.gohtml @@ -4,9 +4,7 @@ {{ with .Blog.Description }}

{{ . }}

{{ end }}