mirror of https://github.com/jlelse/GoBlog
Refactor cache, just use ETag
This commit is contained in:
parent
0f5ddb2e80
commit
a75fa07f57
46
cache.go
46
cache.go
|
@ -2,15 +2,12 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/araddon/dateparse"
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"go.goblog.app/app/pkgs/bufferpool"
|
||||
"golang.org/x/sync/singleflight"
|
||||
|
@ -20,7 +17,6 @@ const (
|
|||
cacheLoggedInKey contextKey = "cacheLoggedIn"
|
||||
cacheExpirationKey contextKey = "cacheExpiration"
|
||||
|
||||
lastModified = "Last-Modified"
|
||||
cacheControl = "Cache-Control"
|
||||
)
|
||||
|
||||
|
@ -88,13 +84,6 @@ func (a *goBlog) cacheMiddleware(next http.Handler) http.Handler {
|
|||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
if ifModifiedSinceHeader := r.Header.Get("If-Modified-Since"); ifModifiedSinceHeader != "" {
|
||||
if t, err := dateparse.ParseAny(ifModifiedSinceHeader); err == nil && t.After(ci.creationTime) {
|
||||
// send 304
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
}
|
||||
// set status code
|
||||
w.WriteHeader(ci.code)
|
||||
// write cached body
|
||||
|
@ -156,24 +145,15 @@ func (a *goBlog) setCacheHeaders(w http.ResponseWriter, cache *cacheItem) {
|
|||
}
|
||||
// Set cache headers
|
||||
w.Header().Set("ETag", cache.eTag)
|
||||
w.Header().Set(lastModified, cache.creationTime.UTC().Format(http.TimeFormat))
|
||||
if w.Header().Get(cacheControl) == "" {
|
||||
if cache.expiration != 0 {
|
||||
w.Header().Set(cacheControl, fmt.Sprintf("public,max-age=%d,stale-while-revalidate=%d", cache.expiration, cache.expiration))
|
||||
} else {
|
||||
exp := a.cfg.Cache.Expiration
|
||||
w.Header().Set(cacheControl, fmt.Sprintf("public,max-age=%d,s-max-age=%d,stale-while-revalidate=%d", exp, exp/3, exp))
|
||||
}
|
||||
}
|
||||
w.Header().Set(cacheControl, "public,no-cache")
|
||||
}
|
||||
|
||||
type cacheItem struct {
|
||||
expiration int
|
||||
creationTime time.Time
|
||||
eTag string
|
||||
code int
|
||||
header http.Header
|
||||
body []byte
|
||||
expiration int
|
||||
eTag string
|
||||
code int
|
||||
header http.Header
|
||||
body []byte
|
||||
}
|
||||
|
||||
// Calculate byte size of cache item using size of header, body and etag
|
||||
|
@ -203,24 +183,12 @@ func (c *cache) getCache(key string, next http.Handler, r *http.Request) *cacheI
|
|||
rec := newCacheRecorder()
|
||||
next.ServeHTTP(rec, cr)
|
||||
item := rec.finish()
|
||||
// Set eTag
|
||||
item.eTag = item.header.Get("ETag")
|
||||
if item.eTag == "" {
|
||||
item.eTag = fmt.Sprintf("%x", sha256.Sum256(item.body))
|
||||
}
|
||||
// Set creation time
|
||||
item.creationTime = time.Now()
|
||||
if lm := item.header.Get(lastModified); lm != "" {
|
||||
if parsedTime, te := dateparse.ParseLocal(lm); te == nil {
|
||||
item.creationTime = parsedTime
|
||||
}
|
||||
}
|
||||
// Set expiration
|
||||
item.expiration, _ = cr.Context().Value(cacheExpirationKey).(int)
|
||||
// Remove problematic headers
|
||||
item.header.Del("Accept-Ranges")
|
||||
item.header.Del("ETag")
|
||||
item.header.Del(lastModified)
|
||||
item.header.Del("Last-Modified")
|
||||
// Save cache
|
||||
if cch := item.header.Get(cacheControl); !containsStrings(cch, "no-store", "private", "no-cache") {
|
||||
cost := int64(item.cost())
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
@ -21,6 +23,10 @@ func newCacheRecorder() *cacheRecorder {
|
|||
|
||||
func (c *cacheRecorder) finish() *cacheItem {
|
||||
c.done = true
|
||||
c.item.eTag = c.item.header.Get("ETag")
|
||||
if c.item.eTag == "" {
|
||||
c.item.eTag = fmt.Sprintf("%x", sha256.Sum256(c.item.body))
|
||||
}
|
||||
return &c.item
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dgraph-io/ristretto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -14,9 +13,8 @@ import (
|
|||
|
||||
func Benchmark_cacheItem_cost(b *testing.B) {
|
||||
ci := &cacheItem{
|
||||
creationTime: time.Now(),
|
||||
eTag: "abc",
|
||||
code: 200,
|
||||
eTag: "abc",
|
||||
code: 200,
|
||||
header: http.Header{
|
||||
"Content-Type": []string{"text/html"},
|
||||
},
|
||||
|
|
2
go.mod
2
go.mod
|
@ -30,7 +30,7 @@ require (
|
|||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/gorilla/sessions v1.2.1
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/hacdias/indieauth/v3 v3.0.1
|
||||
github.com/hacdias/indieauth/v3 v3.1.0
|
||||
github.com/jlaffaye/ftp v0.1.0
|
||||
// master
|
||||
github.com/jlelse/feeds v1.2.1-0.20210704161900-189f94254ad4
|
||||
|
|
4
go.sum
4
go.sum
|
@ -238,8 +238,8 @@ github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z
|
|||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hacdias/indieauth/v3 v3.0.1 h1:b/C2VlqOzijvVJuezFcGhEmMZyCvZgdHgLZIb9BOlxk=
|
||||
github.com/hacdias/indieauth/v3 v3.0.1/go.mod h1:mVMKFOoVMYgGb06HgXiSevyIJu3/GoRo/EujEXSpAKs=
|
||||
github.com/hacdias/indieauth/v3 v3.1.0 h1:aVj9hp9cNCYrlUnSybrG7vNSgJ1/4JIsSa0jsQ3zpHk=
|
||||
github.com/hacdias/indieauth/v3 v3.1.0/go.mod h1:EmGEAbqGNhCnJR6Uk00t83x7ASQeo0EBNf/5XiFvS9w=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
|
|
Loading…
Reference in New Issue