// 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
// the server.
//
// If there is a stale Response, then any validators it contains will be set on the new request
// to give the server a chance to respond with NotModified. If this happens, then the cached Response
// will be returned.
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
the server.

If there is a stale Response, then any validators it contains will be set on the new request
to give the server a chance to respond with NotModified. If this happens, then the cached Response
will be returned.
// 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 // the server . // // If there is a stale Response then any validators it contains will be set on the new request // to give the server a chance to respond with NotModified . If this happens then the cached Response // will be returned .
func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	cacheKey := cacheKey(req)
	cacheable := (req.Method == "GET" || req.Method == "HEAD") && req.Header.Get("range") == ""
	var cachedResp *http.Response
	if cacheable {
		cachedResp, err = CachedResponse(t.Cache, req)
	} else {
		t.Cache.Delete(cacheKey)
	}
	transport := t.Transport
	if transport == nil {
		transport = http.DefaultTransport
	}
	if cacheable && cachedResp != nil && err == nil {
		if t.MarkCachedResponses {
			cachedResp.Header.Set(XFromCache, "1")
		}
		if varyMatches(cachedResp, req) {
			freshness := getFreshness(cachedResp.Header, req.Header)
			if freshness == fresh {
				return cachedResp, nil
			}
			if freshness == stale {
				var req2 *http.Request
				etag := cachedResp.Header.Get("etag")
				if etag != "" && req.Header.Get("etag") == "" {
					req2 = cloneRequest(req)
					req2.Header.Set("if-none-match", etag)
				}
				lastModified := cachedResp.Header.Get("last-modified")
				if lastModified != "" && req.Header.Get("last-modified") == "" {
					if req2 == nil {
						req2 = cloneRequest(req)
					}
					req2.Header.Set("if-modified-since", lastModified)
				}
				if req2 != nil {
					req = req2
				}
			}
		}
		resp, err = transport.RoundTrip(req)
		if err == nil && req.Method == "GET" && resp.StatusCode == http.StatusNotModified {
			endToEndHeaders := getEndToEndHeaders(resp.Header)
			for _, header := range endToEndHeaders {
				cachedResp.Header[header] = resp.Header[header]
			}
			resp = cachedResp
		} else if (err != nil || (cachedResp != nil && resp.StatusCode >= 500)) &&
			req.Method == "GET" && canStaleOnError(cachedResp.Header, req.Header) {
			return cachedResp, nil
		} else {
			if err != nil || resp.StatusCode != http.StatusOK {
				t.Cache.Delete(cacheKey)
			}
			if err != nil {
				return nil, err
			}
		}
	} else {
		reqCacheControl := parseCacheControl(req.Header)
		if _, ok := reqCacheControl["only-if-cached"]; ok {
			resp = newGatewayTimeoutResponse(req)
		} else {
			resp, err = transport.RoundTrip(req)
			if err != nil {
				return nil, err
			}
		}
	}
	if cacheable && canStore(parseCacheControl(req.Header), parseCacheControl(resp.Header)) {
		for _, varyKey := range headerAllCommaSepValues(resp.Header, "vary") {
			varyKey = http.CanonicalHeaderKey(varyKey)
			fakeHeader := "X-Varied-" + varyKey
			reqValue := req.Header.Get(varyKey)
			if reqValue != "" {
				resp.Header.Set(fakeHeader, reqValue)
			}
		}
		switch req.Method {
		case "GET":
			resp.Body = &cachingReadCloser{
				R: resp.Body,
				OnEOF: func(r io.Reader) {
					resp := *resp
					resp.Body = ioutil.NopCloser(r)
					respBytes, err := httputil.DumpResponse(&resp, true)
					if err == nil {
						t.Cache.Set(cacheKey, respBytes)
					}
				},
			}
		default:
			respBytes, err := httputil.DumpResponse(resp, true)
			if err == nil {
				t.Cache.Set(cacheKey, respBytes)
			}
		}
	} else {
		t.Cache.Delete(cacheKey)
	}
	return resp, nil
}
func ( t * Transport ) RoundTrip ( req * http . Request ) ( resp * http . Response , err error ) { cacheKey := cacheKey ( req ) cacheable := ( req . Method == " " || req . Method == " " ) && req . Header . Get ( " " ) == " " var cachedResp * http . Response if cacheable { cachedResp , err = CachedResponse ( t . Cache , req ) } else { t . Cache . Delete ( cacheKey ) } transport := t . Transport if transport == nil { transport = http . DefaultTransport } if cacheable && cachedResp != nil && err == nil { if t . MarkCachedResponses { cachedResp . Header . Set ( XFromCache , " " ) } if varyMatches ( cachedResp , req ) { freshness := getFreshness ( cachedResp . Header , req . Header ) if freshness == fresh { return cachedResp , nil } if freshness == stale { var req2 * http . Request etag := cachedResp . Header . Get ( " " ) if etag != " " && req . Header . Get ( " " ) == " " { req2 = cloneRequest ( req ) req2 . Header . Set ( " " , etag ) } lastModified := cachedResp . Header . Get ( " " ) if lastModified != " " && req . Header . Get ( " " ) == " " { if req2 == nil { req2 = cloneRequest ( req ) } req2 . Header . Set ( " " , lastModified ) } if req2 != nil { req = req2 } } } resp , err = transport . RoundTrip ( req ) if err == nil && req . Method == " " && resp . StatusCode == http . StatusNotModified { endToEndHeaders := getEndToEndHeaders ( resp . Header ) for _ , header := range endToEndHeaders { cachedResp . Header [ header ] = resp . Header [ header ] } resp = cachedResp } else if ( err != nil || ( cachedResp != nil && resp . StatusCode >= 500 ) ) && req . Method == " " && canStaleOnError ( cachedResp . Header , req . Header ) { return cachedResp , nil } else { if err != nil || resp . StatusCode != http . StatusOK { t . Cache . Delete ( cacheKey ) } if err != nil { return nil , err } } } else { reqCacheControl := parseCacheControl ( req . Header ) if _ , ok := reqCacheControl [ " " ] ; ok { resp = newGatewayTimeoutResponse ( req ) } else { resp , err = transport . RoundTrip ( req ) if err != nil { return nil , err } } } if cacheable && canStore ( parseCacheControl ( req . Header ) , parseCacheControl ( resp . Header ) ) { for _ , varyKey := range headerAllCommaSepValues ( resp . Header , " " ) { varyKey = http . CanonicalHeaderKey ( varyKey ) fakeHeader := " " + varyKey reqValue := req . Header . Get ( varyKey ) if reqValue != " " { resp . Header . Set ( fakeHeader , reqValue ) } } switch req . Method { case " " : resp . Body = & cachingReadCloser { R : resp . Body , OnEOF : func ( r io . Reader ) { resp := * resp resp . Body = ioutil . NopCloser ( r ) respBytes , err := httputil . DumpResponse ( & resp , true ) if err == nil { t . Cache . Set ( cacheKey , respBytes ) } } , } default : respBytes , err := httputil . DumpResponse ( resp , true ) if err == nil { t . Cache . Set ( cacheKey , respBytes ) } } } else { t . Cache . Delete ( cacheKey ) } return resp , nil }
RoundTrip takes a Request and returns a Response
RoundTrip takes a Request and returns a Response
// Need to invalidate an existing value // Can only use cached value if the new request doesn't Vary significantly // Add validators if caller hasn't already done so // Replace the 304 response with the one from cache, but update with some new headers // In case of transport failure and stale-if-error activated, returns cached content // when available // Delay caching until EOF is reached.