diff --git a/server/middleware/caching/caching_revalidate.go b/server/middleware/caching/caching_revalidate.go index 0645164..107a503 100644 --- a/server/middleware/caching/caching_revalidate.go +++ b/server/middleware/caching/caching_revalidate.go @@ -123,6 +123,7 @@ func (r *RevalidateProcessor) Lookup(c *Caching, req *http.Request) (bool, error c.cacheStatus = storagev1.CacheMiss // drop metadata + c.md.Chunks.Clear() if discardErr := c.bucket.DiscardWithMessage(req.Context(), c.id, "revalidate cache with expired"); discardErr != nil { c.log.Errorf("cache revalidate storage error when discarding of object's data: %s, err: %s", c.id.Key(), discardErr) @@ -152,6 +153,7 @@ func (r *RevalidateProcessor) PreRequest(c *Caching, req *http.Request) (*http.R if !conditionHeader { c.log.Warnf("refresh error while get 'Etag' & 'Last-Modified' is nil, delete cache do proxy") + c.md.Chunks.Clear() _ = c.bucket.DiscardWithMessage(req.Context(), c.id, "refresh cache no condition header") return req, nil } @@ -177,6 +179,7 @@ func (r *RevalidateProcessor) revalidate(c *Caching, resp *http.Response, req *h if resp.StatusCode != http.StatusNotModified { c.cacheStatus = storagev1.CacheRevalidateMiss c.setXCache(resp) + c.md.Chunks.Clear() _ = c.bucket.DiscardWithMessage(req.Context(), c.id, "revalidate cache not StatusNotModified") return resp, nil } @@ -216,13 +219,15 @@ func (r *RevalidateProcessor) freshness(c *Caching, resp *http.Response) bool { metadata.RespUnix = now.Unix() metadata.LastRefUnix = now.Unix() - cloneHeaders := []string{"Last-Modified", "ETag", "Cache-Control"} - for _, name := range cloneHeaders { - value := resp.Header.Get(name) - if value != "" { - metadata.Headers.Set(name, value) - } - } + xhttp.CopyHeader(metadata.Headers, resp.Header) + + // cloneHeaders := []string{"Last-Modified", "ETag", "Cache-Control"} + // for _, name := range cloneHeaders { + // value := resp.Header.Get(name) + // if value != "" { + // metadata.Headers.Set(name, value) + // } + // } c.cacheable = true c.md = metadata diff --git a/tests/all-features/caching/revalidate_test.go b/tests/all-features/caching/revalidate_test.go new file mode 100644 index 0000000..aca41c0 --- /dev/null +++ b/tests/all-features/caching/revalidate_test.go @@ -0,0 +1,88 @@ +package caching + +import ( + "net/http" + "testing" + "time" + + "github.com/omalloc/tavern/pkg/e2e" + xhttp "github.com/omalloc/tavern/pkg/x/http" + "github.com/stretchr/testify/assert" +) + +func TestRevalidateDiscard(t *testing.T) { + f := e2e.GenFile(t, 5<<20) + + t.Run("test Revalidate old-file", func(t *testing.T) { + case1 := e2e.New("http://sendya.me.gslb.com/cases/revalidate/file1.apk", e2e.RespCallbackFile(f, func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Case", "old-file") + w.Header().Set("Cache-Control", "max-age=1") // 1s 过滤 + })) + defer case1.Close() + + rr := xhttp.NewRequestRange(0, 524287) + + resp, err := case1.Do(func(r *http.Request) { + r.Header.Set("Range", rr.String()) + t.Logf("New Request Range=%s", rr.String()) + }) + + t.Logf("resp size=%d", resp.ContentLength) + t.Logf("file offset=%d, end=%d", rr.Start, rr.End) + t.Logf("file path=%s", f.Path) + + hashBody := e2e.HashBody(resp) + hashFile := e2e.HashFile(f.Path, int(rr.Start), int(rr.End-rr.Start+1)) + + assert.NoError(t, err, "response should not error") + + assert.Equal(t, http.StatusPartialContent, resp.StatusCode, "response should be code 206") + + assert.Equal(t, rr.ContentRange(uint64(f.Size)), resp.Header.Get("Content-Range"), "response should be Content-Range") + + assert.Equal(t, "old-file", resp.Header.Get("X-Case"), "response should be X-Case old-file") + + assert.Equal(t, f.MD5, resp.Header.Get("ETag"), "response should be ETag") + + assert.Equal(t, hashBody, hashFile, "response body should be equal to file MD5") + }) + + t.Run("test Revalidate new-file", func(t *testing.T) { + time.Sleep(time.Second) + + case1 := e2e.New("http://sendya.me.gslb.com/cases/revalidate/file1.apk", e2e.RespCallbackFile(f, func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Case", "new-file") + w.Header().Set("Cache-Control", "max-age=1") // 1s 过滤 + })) + defer case1.Close() + + rr := xhttp.NewRequestRange(2097152, 3145727) + + resp, err := case1.Do(func(r *http.Request) { + r.Header.Set("Range", rr.String()) + t.Logf("New Request Range=%s", rr.String()) + }) + t.Logf("resp size=%d", resp.ContentLength) + t.Logf("file offset=%d, end=%d", rr.Start, rr.End) + t.Logf("file path=%s", f.Path) + + hashBody := e2e.HashBody(resp) + hashFile := e2e.HashFile(f.Path, int(rr.Start), int(rr.End-rr.Start+1)) + + assert.NoError(t, err, "response should not error") + + assert.Equal(t, http.StatusPartialContent, resp.StatusCode, "response should be code 206") + + assert.Equal(t, rr.ContentRange(uint64(f.Size)), resp.Header.Get("Content-Range"), "response should be Content-Range") + + assert.Equal(t, "new-file", resp.Header.Get("X-Case"), "response should be X-Case new-file") + + assert.Equal(t, f.MD5, resp.Header.Get("ETag"), "response should be ETag") + + assert.Equal(t, hashBody, hashFile, "response body should be equal to file MD5") + }) + + // t.Run("PURGE", func(t *testing.T) { + // e2e.Purge(t, "http://sendya.me.gslb.com/cases/revalidate/file1.apk") + // }) +} diff --git a/tests/config.test.yaml b/tests/config.test.yaml index 2490eb9..3970bd5 100644 --- a/tests/config.test.yaml +++ b/tests/config.test.yaml @@ -60,7 +60,7 @@ server: secret: "123" path: ./logs/access.log plugin: - - name: example-plugin + - name: qs-plugin options: option1: value1 option2: 2