diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index 4158031ed..fb64f18da 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -234,43 +234,50 @@ func (s *SouinBaseHandler) Store( res.Header.Set(rfc.StoredLengthHeader, res.Header.Get("Content-Length")) response, err := httputil.DumpResponse(&res, true) if err == nil && customWriter.Buf.Len() > 0 { - variedHeaders := rfc.HeaderAllCommaSepValues(res.Header) - cachedKey += rfc.GetVariedCacheKey(rq, variedHeaders) - s.Configuration.GetLogger().Sugar().Debugf("Store the response %+v with duration %v", res, ma) - - var wg sync.WaitGroup - mu := sync.Mutex{} - fails := []string{} - select { - case <-rq.Context().Done(): - status += "; detail=REQUEST-CANCELED-OR-UPSTREAM-BROKEN-PIPE" - default: - for _, storer := range s.Storers { - wg.Add(1) - go func(currentStorer storage.Storer) { - defer wg.Done() - if currentStorer.Set(cachedKey, response, currentMatchedURL, ma) == nil { - s.Configuration.GetLogger().Sugar().Debugf("Stored the key %s in the %s provider", cachedKey, currentStorer.Name()) - } else { - mu.Lock() - fails = append(fails, fmt.Sprintf("; detail=%s-INSERTION-ERROR", currentStorer.Name())) - mu.Unlock() - } - }(storer) - } + variedHeaders, isVaryStar := rfc.VariedHeaderAllCommaSepValues(res.Header) + if isVaryStar { + // "Implies that the response is uncacheable" + status += "; detail=UPSTREAM-VARY-STAR" + } else { + cachedKey += rfc.GetVariedCacheKey(rq, variedHeaders) + + s.Configuration.GetLogger().Sugar().Debugf("Store the response %+v with duration %v", res, ma) + + var wg sync.WaitGroup + mu := sync.Mutex{} + fails := []string{} + select { + case <-rq.Context().Done(): + status += "; detail=REQUEST-CANCELED-OR-UPSTREAM-BROKEN-PIPE" + default: + for _, storer := range s.Storers { + wg.Add(1) + go func(currentStorer storage.Storer) { + defer wg.Done() + if currentStorer.Set(cachedKey, response, currentMatchedURL, ma) == nil { + s.Configuration.GetLogger().Sugar().Debugf("Stored the key %s in the %s provider", cachedKey, currentStorer.Name()) + } else { + mu.Lock() + fails = append(fails, fmt.Sprintf("; detail=%s-INSERTION-ERROR", currentStorer.Name())) + mu.Unlock() + } + }(storer) + } - wg.Wait() - if len(fails) < s.storersLen { - go func(rs http.Response, key string) { - _ = s.SurrogateKeyStorer.Store(&rs, key) - }(res, cachedKey) - status += "; stored" - } + wg.Wait() + if len(fails) < s.storersLen { + go func(rs http.Response, key string) { + _ = s.SurrogateKeyStorer.Store(&rs, key) + }(res, cachedKey) + status += "; stored" + } - if len(fails) > 0 { - status += strings.Join(fails, "") + if len(fails) > 0 { + status += strings.Join(fails, "") + } } } + } else { status += "; detail=UPSTREAM-ERROR-OR-EMPTY-RESPONSE" } @@ -337,11 +344,13 @@ func (s *SouinBaseHandler) Upstream( if sfWriter, ok := sfValue.(singleflightValue); ok && shared { if vary := sfWriter.headers.Get("Vary"); vary != "" { - variedHeaders := rfc.HeaderAllCommaSepValues(sfWriter.headers) - for _, vh := range variedHeaders { - if rq.Header.Get(vh) != sfWriter.requestHeaders.Get(vh) { - cachedKey += rfc.GetVariedCacheKey(rq, variedHeaders) - return s.Upstream(customWriter, rq, next, requestCc, cachedKey) + variedHeaders, isVaryStar := rfc.VariedHeaderAllCommaSepValues(sfWriter.headers) + if !isVaryStar { + for _, vh := range variedHeaders { + if rq.Header.Get(vh) != sfWriter.requestHeaders.Get(vh) { + cachedKey += rfc.GetVariedCacheKey(rq, variedHeaders) + return s.Upstream(customWriter, rq, next, requestCc, cachedKey) + } } } } diff --git a/pkg/rfc/vary.go b/pkg/rfc/vary.go index 93b249d87..fa3112525 100644 --- a/pkg/rfc/vary.go +++ b/pkg/rfc/vary.go @@ -28,20 +28,24 @@ func GetVariedCacheKey(rq *http.Request, headers []string) string { return VarySeparator + strings.Join(headers, DecodedHeaderSeparator) } -// headerAllCommaSepValues returns all comma-separated values (each -// with whitespace trimmed) for header name in headers. According to +// VariedHeaderAllCommaSepValues returns all comma-separated values (each +// with whitespace trimmed) for header name in 'Vary'. According to // Section 4.2 of the HTTP/1.1 spec // (http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2), // values from multiple occurrences of a header should be concatenated, if // the header's value is a comma-separated list. -func HeaderAllCommaSepValues(headers http.Header) []string { +func VariedHeaderAllCommaSepValues(headers http.Header) ([]string, bool) { var vals []string for _, val := range headers[http.CanonicalHeaderKey("Vary")] { fields := strings.Split(val, ",") for i, f := range fields { - fields[i] = strings.TrimSpace(f) + trimmedField := strings.TrimSpace(f) + if trimmedField == "*" { + return []string{"*"}, true + } + fields[i] = trimmedField } vals = append(vals, fields...) } - return vals + return vals, false }