update all downstream dependencies

no specific features I'm looking to add, just keeping thing up to date.
Unit tests and my manual testing seems like everything is still working
as expected.
This commit is contained in:
Will Norris 2017-06-01 08:37:05 -07:00
parent 17f19d612f
commit b5984d2822
25 changed files with 1661 additions and 486 deletions

View file

@ -1,21 +1,24 @@
httpcache
=========
A Transport for Go's http.Client that will cache responses according to the HTTP RFC
[![Build Status](https://travis-ci.org/gregjones/httpcache.svg?branch=master)](https://travis-ci.org/gregjones/httpcache) [![GoDoc](https://godoc.org/github.com/gregjones/httpcache?status.svg)](https://godoc.org/github.com/gregjones/httpcache)
Package httpcache provides a http.RoundTripper implementation that works as a mostly RFC-compliant cache for http responses.
It is only suitable for use as a 'private' cache (i.e. for a web-browser or an API-client and not for a shared proxy).
**Documentation:** http://godoc.org/github.com/gregjones/httpcache
**License:** MIT (see LICENSE.txt)
Cache backends
Cache Backends
--------------
- The built-in 'memory' cache stores responses in an in-memory map.
- https://github.com/gregjones/httpcache/diskcache provides a filesystem-backed cache using the [diskv](https://github.com/peterbourgon/diskv) library.
- https://github.com/gregjones/httpcache/memcache provides memcache implementations, for both App Engine and 'normal' memcache servers
- https://github.com/sourcegraph/s3cache uses Amazon S3 for storage.
- https://github.com/gregjones/httpcache/leveldbcache provides a filesystem-backed cache using [leveldb](https://github.com/syndtr/goleveldb/leveldb)
- [`github.com/gregjones/httpcache/diskcache`](https://github.com/gregjones/httpcache/tree/master/diskcache) provides a filesystem-backed cache using the [diskv](https://github.com/peterbourgon/diskv) library.
- [`github.com/gregjones/httpcache/memcache`](https://github.com/gregjones/httpcache/tree/master/memcache) provides memcache implementations, for both App Engine and 'normal' memcache servers.
- [`sourcegraph.com/sourcegraph/s3cache`](https://sourcegraph.com/github.com/sourcegraph/s3cache) uses Amazon S3 for storage.
- [`github.com/gregjones/httpcache/leveldbcache`](https://github.com/gregjones/httpcache/tree/master/leveldbcache) provides a filesystem-backed cache using [leveldb](https://github.com/syndtr/goleveldb/leveldb).
- [`github.com/die-net/lrucache`](https://github.com/die-net/lrucache) provides an in-memory cache that will evict least-recently used entries.
- [`github.com/die-net/lrucache/twotier`](https://github.com/die-net/lrucache/tree/master/twotier) allows caches to be combined, for example to use lrucache above with a persistent disk-cache.
License
-------
- [MIT License](LICENSE.txt)

View file

@ -11,8 +11,6 @@ import (
"bytes"
"errors"
"fmt"
"io"
"log"
"net/http"
"net/http/httputil"
"strings"
@ -65,23 +63,23 @@ type MemoryCache struct {
// Get returns the []byte representation of the response and true if present, false if not
func (c *MemoryCache) Get(key string) (resp []byte, ok bool) {
c.mu.RLock()
defer c.mu.RUnlock()
resp, ok = c.items[key]
c.mu.RUnlock()
return resp, ok
}
// Set saves response resp to the cache with key
func (c *MemoryCache) Set(key string, resp []byte) {
c.mu.Lock()
defer c.mu.Unlock()
c.items[key] = resp
c.mu.Unlock()
}
// Delete removes key from the cache
func (c *MemoryCache) Delete(key string) {
c.mu.Lock()
defer c.mu.Unlock()
delete(c.items, key)
c.mu.Unlock()
}
// NewMemoryCache returns a new Cache that will store items in an in-memory map
@ -90,33 +88,6 @@ func NewMemoryCache() *MemoryCache {
return c
}
// onEOFReader executes a function on reader EOF or close
type onEOFReader struct {
rc io.ReadCloser
fn func()
}
func (r *onEOFReader) Read(p []byte) (n int, err error) {
n, err = r.rc.Read(p)
if err == io.EOF {
r.runFunc()
}
return
}
func (r *onEOFReader) Close() error {
err := r.rc.Close()
r.runFunc()
return err
}
func (r *onEOFReader) runFunc() {
if fn := r.fn; fn != nil {
fn()
r.fn = nil
}
}
// Transport is an implementation of http.RoundTripper that will return values from a cache
// where possible (avoiding a network request) and will additionally add validators (etag/if-modified-since)
// to repeated requests allowing servers to return 304 / Not Modified
@ -127,10 +98,6 @@ type Transport struct {
Cache Cache
// If true, responses returned from the cache will be given an extra header, X-From-Cache
MarkCachedResponses bool
// guards modReq
mu sync.RWMutex
// Mapping of original request => cloned
modReq map[*http.Request]*http.Request
}
// NewTransport returns a new Transport with the
@ -156,20 +123,6 @@ func varyMatches(cachedResp *http.Response, req *http.Request) bool {
return true
}
// setModReq maintains a mapping between original requests and their associated cloned requests
func (t *Transport) setModReq(orig, mod *http.Request) {
t.mu.Lock()
defer t.mu.Unlock()
if t.modReq == nil {
t.modReq = make(map[*http.Request]*http.Request)
}
if mod == nil {
delete(t.modReq, orig)
} else {
t.modReq[orig] = mod
}
}
// RoundTrip takes a Request and returns a Response
//
// If there is a fresh Response already in cache, then it will be returned without connecting to
@ -180,9 +133,9 @@ func (t *Transport) setModReq(orig, mod *http.Request) {
// will be returned.
func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
cacheKey := cacheKey(req)
cacheableMethod := req.Method == "GET" || req.Method == "HEAD"
cacheable := (req.Method == "GET" || req.Method == "HEAD") && req.Header.Get("range") == ""
var cachedResp *http.Response
if cacheableMethod {
if cacheable {
cachedResp, err = CachedResponse(t.Cache, req)
} else {
// Need to invalidate an existing value
@ -194,7 +147,7 @@ func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error
transport = http.DefaultTransport
}
if cachedResp != nil && err == nil && cacheableMethod && req.Header.Get("range") == "" {
if cacheable && cachedResp != nil && err == nil {
if t.MarkCachedResponses {
cachedResp.Header.Set(XFromCache, "1")
}
@ -222,23 +175,7 @@ func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error
req2.Header.Set("if-modified-since", lastModified)
}
if req2 != nil {
// Associate original request with cloned request so we can refer to
// it in CancelRequest()
t.setModReq(req, req2)
req = req2
defer func() {
// Release req/clone mapping on error
if err != nil {
t.setModReq(req, nil)
}
if resp != nil {
// Release req/clone mapping on body close/EOF
resp.Body = &onEOFReader{
rc: resp.Body,
fn: func() { t.setModReq(req, nil) },
}
}
}()
}
}
}
@ -281,10 +218,7 @@ func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error
}
}
reqCacheControl := parseCacheControl(req.Header)
respCacheControl := parseCacheControl(resp.Header)
if canStore(reqCacheControl, respCacheControl) {
if cacheable && canStore(parseCacheControl(req.Header), parseCacheControl(resp.Header)) {
for _, varyKey := range headerAllCommaSepValues(resp.Header, "vary") {
varyKey = http.CanonicalHeaderKey(varyKey)
fakeHeader := "X-Varied-" + varyKey
@ -303,31 +237,6 @@ func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error
return resp, nil
}
// CancelRequest calls CancelRequest on the underlaying transport if implemented or
// throw a warning otherwise.
func (t *Transport) CancelRequest(req *http.Request) {
type canceler interface {
CancelRequest(*http.Request)
}
tr, ok := t.Transport.(canceler)
if !ok {
log.Printf("httpcache: Client Transport of type %T doesn't support CancelRequest; Timeout not supported", t.Transport)
return
}
t.mu.RLock()
if modReq, ok := t.modReq[req]; ok {
t.mu.RUnlock()
t.mu.Lock()
delete(t.modReq, req)
t.mu.Unlock()
tr.CancelRequest(modReq)
} else {
t.mu.RUnlock()
tr.CancelRequest(req)
}
}
// ErrNoDateHeader indicates that the HTTP headers contained no Date header.
var ErrNoDateHeader = errors.New("no Date header")