@@ -45,9 +45,9 @@ func cacheKey(req *http.Request) string {
4545 }
4646}
4747
48- // CachedResponse returns the cached http.Response for req if present, and nil
48+ // cachedResponse returns the cached http.Response for req if present, and nil
4949// otherwise.
50- func CachedResponse (c Cache , req * http.Request ) (resp * http.Response , err error ) {
50+ func cachedResponse (c Cache , req * http.Request ) (resp * http.Response , err error ) {
5151 cachedVal , ok := c .Get (cacheKey (req ))
5252 if ! ok {
5353 return
@@ -57,37 +57,37 @@ func CachedResponse(c Cache, req *http.Request) (resp *http.Response, err error)
5757 return http .ReadResponse (bufio .NewReader (b ), req )
5858}
5959
60- // MemoryCache is an implemtation of Cache that stores responses in an in-memory map.
61- type MemoryCache struct {
60+ // memoryCache is an implemtation of Cache that stores responses in an in-memory map.
61+ type memoryCache struct {
6262 mu sync.RWMutex
6363 items map [string ][]byte
6464}
6565
6666// Get returns the []byte representation of the response and true if present, false if not
67- func (c * MemoryCache ) Get (key string ) (resp []byte , ok bool ) {
67+ func (c * memoryCache ) Get (key string ) (resp []byte , ok bool ) {
6868 c .mu .RLock ()
6969 resp , ok = c .items [key ]
7070 c .mu .RUnlock ()
7171 return resp , ok
7272}
7373
7474// Set saves response resp to the cache with key
75- func (c * MemoryCache ) Set (key string , resp []byte ) {
75+ func (c * memoryCache ) Set (key string , resp []byte ) {
7676 c .mu .Lock ()
7777 c .items [key ] = resp
7878 c .mu .Unlock ()
7979}
8080
8181// Delete removes key from the cache
82- func (c * MemoryCache ) Delete (key string ) {
82+ func (c * memoryCache ) Delete (key string ) {
8383 c .mu .Lock ()
8484 delete (c .items , key )
8585 c .mu .Unlock ()
8686}
8787
88- // NewMemoryCache returns a new Cache that will store items in an in-memory map
89- func NewMemoryCache () * MemoryCache {
90- c := & MemoryCache {items : map [string ][]byte {}}
88+ // newMemoryCache returns a new Cache that will store items in an in-memory map
89+ func newMemoryCache () * memoryCache {
90+ c := & memoryCache {items : map [string ][]byte {}}
9191 return c
9292}
9393
@@ -98,20 +98,18 @@ type Transport struct {
9898 // The RoundTripper interface actually used to make requests
9999 // If nil, http.DefaultTransport is used
100100 Transport http.RoundTripper
101- Cache Cache
101+
102+ // The Cache interface used to store and retrieve responses.
103+ Cache Cache
104+
102105 // If true, responses returned from the cache will be given an extra header, X-From-Cache
103106 MarkCachedResponses bool
104- }
105107
106- // NewTransport returns a new Transport with the
107- // provided Cache implementation and MarkCachedResponses set to true
108- func NewTransport (c Cache ) * Transport {
109- return & Transport {Cache : c , MarkCachedResponses : true }
110- }
111-
112- // Client returns an *http.Client that caches responses.
113- func (t * Transport ) Client () * http.Client {
114- return & http.Client {Transport : t }
108+ // AroundRoundTrip is an optional func.
109+ // If set, the Transport will call AroundRoundTrip at the start of RoundTrip
110+ // and defer the returned func until the end of RoundTrip.
111+ // Typically used to implement a lock that is held for the duration of the RoundTrip.
112+ AroundRoundTrip func (key string ) func ()
115113}
116114
117115// varyMatches will return false unless all of the cached values for the headers listed in Vary
@@ -136,10 +134,13 @@ func varyMatches(cachedResp *http.Response, req *http.Request) bool {
136134// will be returned.
137135func (t * Transport ) RoundTrip (req * http.Request ) (resp * http.Response , err error ) {
138136 cacheKey := cacheKey (req )
137+ if f := t .AroundRoundTrip ; f != nil {
138+ defer f (cacheKey )()
139+ }
139140 cacheable := (req .Method == "GET" || req .Method == "HEAD" ) && req .Header .Get ("range" ) == ""
140141 var cachedResp * http.Response
141142 if cacheable {
142- cachedResp , err = CachedResponse (t .Cache , req )
143+ cachedResp , err = cachedResponse (t .Cache , req )
143144 } else {
144145 // Need to invalidate an existing value
145146 t .Cache .Delete (cacheKey )
@@ -254,8 +255,8 @@ func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error
254255// ErrNoDateHeader indicates that the HTTP headers contained no Date header.
255256var ErrNoDateHeader = errors .New ("no Date header" )
256257
257- // Date parses and returns the value of the Date header.
258- func Date (respHeaders http.Header ) (date time.Time , err error ) {
258+ // date parses and returns the value of the date header.
259+ func date (respHeaders http.Header ) (date time.Time , err error ) {
259260 dateHeader := respHeaders .Get ("date" )
260261 if dateHeader == "" {
261262 err = ErrNoDateHeader
@@ -299,7 +300,7 @@ func getFreshness(respHeaders, reqHeaders http.Header) (freshness int) {
299300 return fresh
300301 }
301302
302- date , err := Date (respHeaders )
303+ date , err := date (respHeaders )
303304 if err != nil {
304305 return stale
305306 }
@@ -398,7 +399,7 @@ func canStaleOnError(respHeaders, reqHeaders http.Header) bool {
398399 }
399400
400401 if lifetime >= 0 {
401- date , err := Date (respHeaders )
402+ date , err := date (respHeaders )
402403 if err != nil {
403404 return false
404405 }
@@ -541,9 +542,9 @@ func (r *cachingReadCloser) Close() error {
541542 return r .R .Close ()
542543}
543544
544- // NewMemoryCacheTransport returns a new Transport using the in-memory cache implementation
545- func NewMemoryCacheTransport () * Transport {
546- c := NewMemoryCache ()
547- t := NewTransport ( c )
545+ // newMemoryCacheTransport returns a new Transport using the in-memory cache implementation
546+ func newMemoryCacheTransport () * Transport {
547+ c := newMemoryCache ()
548+ t := & Transport { Cache : c , MarkCachedResponses : true }
548549 return t
549550}
0 commit comments