Skip to content
This repository was archived by the owner on Apr 20, 2023. It is now read-only.

Commit 244e49b

Browse files
committed
Add CanStore option
For more context, see https://developer.chrome.com/docs/web-platform/bfcache-ccns
1 parent d62773c commit 244e49b

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

‎httpcache.go‎

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"net/http"
1717
"net/http/httputil"
1818
"strings"
19+
"sync"
1920
"time"
2021
)
2122

@@ -114,11 +115,36 @@ type Transport struct {
114115
// ShouldCache is an optional func that when it returns false, the response will not be cached.
115116
ShouldCache func(req *http.Request, resp *http.Response, key string) bool
116117

118+
// CanStore is an optional func that when set, is called to determine if a response
119+
// can be stored in the cache.
120+
// If not set, a default implementation is used that checks for 'no-store' in
121+
// the request and response cache-control headers.
122+
//
123+
// Note that this does not imply that the response will be cached, only that it is
124+
// allowed to be cached. The ShouldCache func is called after this to make the final decision.
125+
CanStore func(reqCacheControl, respCacheControl CacheControl) (canStore bool)
126+
117127
// Around is an optional func.
118128
// If set, the Transport will call Around at the start of RoundTrip
119129
// and defer the returned func until the end of RoundTrip.
120130
// Typically used to implement a lock that is held for the duration of the RoundTrip.
121131
Around func(req *http.Request, key string) func()
132+
133+
init sync.Once
134+
}
135+
136+
func (t *Transport) doInit() {
137+
if t.Cache == nil {
138+
panic("no Cache set on Transport")
139+
}
140+
if t.CanStore == nil {
141+
t.CanStore = canStore
142+
}
143+
if t.ShouldCache == nil {
144+
t.ShouldCache = func(req *http.Request, resp *http.Response, key string) bool {
145+
return true
146+
}
147+
}
122148
}
123149

124150
// varyMatches will return false unless all of the cached values for the headers listed in Vary
@@ -142,6 +168,10 @@ func varyMatches(cachedResp *http.Response, req *http.Request) bool {
142168
// to give the server a chance to respond with NotModified. If this happens, then the cached Response
143169
// will be returned.
144170
func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
171+
t.init.Do(func() {
172+
t.doInit()
173+
})
174+
145175
cacheKey := t.cacheKey(req)
146176
if f := t.Around; f != nil {
147177
defer f(req, cacheKey)()
@@ -243,7 +273,7 @@ func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error
243273
}
244274
}
245275

246-
if cacheable && (t.ShouldCache == nil || t.ShouldCache(req, resp, cacheKey)) && canStore(parseCacheControl(req.Header), parseCacheControl(resp.Header)) {
276+
if cacheable && t.ShouldCache(req, resp, cacheKey) && t.CanStore(parseCacheControl(req.Header), parseCacheControl(resp.Header)) {
247277
for _, varyKey := range headerAllCommaSepValues(resp.Header, "vary") {
248278
varyKey = http.CanonicalHeaderKey(varyKey)
249279
fakeHeader := "X-Varied-" + varyKey
@@ -513,7 +543,7 @@ func getEndToEndHeaders(respHeaders http.Header) []string {
513543
return endToEndHeaders
514544
}
515545

516-
func canStore(reqCacheControl, respCacheControl cacheControl) (canStore bool) {
546+
func canStore(reqCacheControl, respCacheControl CacheControl) (canStore bool) {
517547
if _, ok := respCacheControl["no-store"]; ok {
518548
return false
519549
}
@@ -548,10 +578,11 @@ func cloneRequest(r *http.Request) *http.Request {
548578
return r2
549579
}
550580

551-
type cacheControl map[string]string
581+
// CacheControl is a map of the cache-control directives to their values (or "" if no value).
582+
type CacheControl map[string]string
552583

553-
func parseCacheControl(headers http.Header) cacheControl {
554-
cc := cacheControl{}
584+
func parseCacheControl(headers http.Header) CacheControl {
585+
cc := CacheControl{}
555586
ccHeader := headers.Get("Cache-Control")
556587
for _, part := range strings.Split(ccHeader, ",") {
557588
part = strings.Trim(part, " ")

‎httpcache_test.go‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,10 @@ func resetTest() {
180180
s.transport.CacheKey = nil
181181
s.transport.AlwaysUseCachedResponse = nil
182182
s.transport.ShouldCache = nil
183+
s.transport.CanStore = nil
183184
s.transport.EnableETagPair = false
184185
s.transport.MarkCachedResponses = false
186+
s.transport.doInit()
185187
clock = &realClock{}
186188
}
187189

0 commit comments

Comments
 (0)