http plugin: honor cache when upstream sends no-store/max-age=0 (#31028)
This commit is contained in:
parent
e004993a62
commit
12f3221aed
2 changed files with 62 additions and 17 deletions
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -109,11 +110,11 @@ func NewHTTP(log *util.Logger, method, uri string, insecure bool, cache time.Dur
|
|||
}
|
||||
|
||||
if cache > 0 {
|
||||
// remove no-cache response headers
|
||||
// remove cache-busting response headers
|
||||
base = &transport.Modifier{
|
||||
Modifier: func(resp *http.Response) error {
|
||||
dropNoCache(resp, "Cache-Control")
|
||||
dropNoCache(resp, "Pragma")
|
||||
dropCacheBusting(resp, "Cache-Control")
|
||||
dropCacheBusting(resp, "Pragma")
|
||||
return nil
|
||||
},
|
||||
Base: base,
|
||||
|
|
@ -148,21 +149,36 @@ func NewHTTP(log *util.Logger, method, uri string, insecure bool, cache time.Dur
|
|||
return p
|
||||
}
|
||||
|
||||
func dropNoCache(resp *http.Response, header string) {
|
||||
if h := resp.Header.Get(header); h != "" {
|
||||
var hh []string
|
||||
// dropCacheBusting removes response directives that defeat the cache layer
|
||||
// (no-cache, no-store and max-age=0) so a configured cache duration takes effect.
|
||||
func dropCacheBusting(resp *http.Response, header string) {
|
||||
h := resp.Header.Get(header)
|
||||
if h == "" {
|
||||
return
|
||||
}
|
||||
|
||||
for h := range strings.SplitSeq(h, ",") {
|
||||
if s := strings.TrimSpace(h); strings.ToLower(s) != "no-cache" {
|
||||
hh = append(hh, s)
|
||||
var hh []string
|
||||
|
||||
for token := range strings.SplitSeq(h, ",") {
|
||||
s := strings.TrimSpace(token)
|
||||
|
||||
name, value, _ := strings.Cut(s, "=")
|
||||
switch strings.ToLower(strings.TrimSpace(name)) {
|
||||
case "no-cache", "no-store":
|
||||
continue
|
||||
case "max-age":
|
||||
if v, err := strconv.Atoi(strings.TrimSpace(value)); err == nil && v <= 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if len(hh) == 0 {
|
||||
resp.Header.Del(header)
|
||||
} else {
|
||||
resp.Header.Set(header, strings.Join(hh, ", "))
|
||||
}
|
||||
hh = append(hh, s)
|
||||
}
|
||||
|
||||
if len(hh) == 0 {
|
||||
resp.Header.Del(header)
|
||||
} else {
|
||||
resp.Header.Set(header, strings.Join(hh, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,14 +12,19 @@ import (
|
|||
)
|
||||
|
||||
type httpHandler struct {
|
||||
val string
|
||||
req *http.Request
|
||||
cnt int
|
||||
val string
|
||||
req *http.Request
|
||||
cnt int
|
||||
cacheBusting bool
|
||||
}
|
||||
|
||||
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
h.req = req
|
||||
h.val = lo.RandomString(16, lo.LettersCharset)
|
||||
if h.cacheBusting {
|
||||
w.Header().Set("Cache-Control", "no-store, no-cache, max-age=0, must-revalidate")
|
||||
w.Header().Set("Pragma", "no-cache")
|
||||
}
|
||||
_, _ = w.Write([]byte(h.val))
|
||||
h.cnt++
|
||||
}
|
||||
|
|
@ -72,6 +77,30 @@ func (suite *httpTestSuite) TestCacheGet() {
|
|||
}
|
||||
}
|
||||
|
||||
func (suite *httpTestSuite) TestCacheGetNoStore() {
|
||||
// upstream sends cache-busting headers, cache must still take effect (#31025)
|
||||
suite.h.cacheBusting = true
|
||||
defer func() { suite.h.cacheBusting = false }()
|
||||
|
||||
uri := suite.srv.URL + "/foo/bar?baz=2"
|
||||
p := NewHTTP(util.NewLogger("foo"), http.MethodGet, uri, false, time.Minute)
|
||||
|
||||
g, err := p.StringGetter()
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.h.cnt = 0
|
||||
res, err := g()
|
||||
suite.Require().NoError(err)
|
||||
first := suite.h.cnt
|
||||
|
||||
for range 3 {
|
||||
val, err := g()
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(res, val)
|
||||
suite.Require().Equal(first, suite.h.cnt)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *httpTestSuite) TestSetQuery() {
|
||||
uri := suite.srv.URL + "/foo/bar?baz={{.baz}}"
|
||||
p := NewHTTP(util.NewLogger("foo"), http.MethodGet, uri, false, 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue