Просмотр исходного кода

Don't set `Expires` HTTP header

DarthSim 1 год назад
Родитель
Сommit
04d65a220b
4 измененных файлов с 42 добавлено и 32 удалено
  1. 1 0
      CHANGELOG.md
  2. 12 19
      processing_handler.go
  3. 27 9
      processing_handler_test.go
  4. 2 4
      stream.go

+ 1 - 0
CHANGELOG.md

@@ -5,6 +5,7 @@
 - Allow relative values for `gravity` and `watermark` offsets.
 - Revised downloading errors reporting.
 - Allow `IMGPROXY_TTL` to be zero.
+- Don't set `Expires` HTTP header as it is ignored if the `Cache-Control` header is set.
 
 ## [3.21.0] - 2023-11-23
 ### Add

+ 12 - 19
processing_handler.go

@@ -57,8 +57,6 @@ func initProcessingHandler() {
 }
 
 func setCacheControl(rw http.ResponseWriter, force *time.Time, originHeaders map[string]string) {
-	var cacheControl, expires string
-
 	ttl := -1
 
 	if _, ok := originHeaders["Fallback-Image"]; ok && config.FallbackImageTTL > 0 {
@@ -71,30 +69,25 @@ func setCacheControl(rw http.ResponseWriter, force *time.Time, originHeaders map
 
 	if config.CacheControlPassthrough && ttl < 0 && originHeaders != nil {
 		if val, ok := originHeaders["Cache-Control"]; ok && len(val) > 0 {
-			cacheControl = val
+			rw.Header().Set("Cache-Control", val)
+			return
 		}
+
 		if val, ok := originHeaders["Expires"]; ok && len(val) > 0 {
-			expires = val
+			if t, err := time.Parse(http.TimeFormat, val); err == nil {
+				ttl = imath.Max(0, int(time.Until(t).Seconds()))
+			}
 		}
 	}
 
-	if len(cacheControl) == 0 && len(expires) == 0 {
-		if ttl < 0 {
-			ttl = config.TTL
-		}
-		if ttl > 0 {
-			cacheControl = fmt.Sprintf("max-age=%d, public", ttl)
-		} else {
-			cacheControl = "no-cache"
-		}
-		expires = time.Now().Add(time.Second * time.Duration(ttl)).Format(http.TimeFormat)
+	if ttl < 0 {
+		ttl = config.TTL
 	}
 
-	if len(cacheControl) > 0 {
-		rw.Header().Set("Cache-Control", cacheControl)
-	}
-	if len(expires) > 0 {
-		rw.Header().Set("Expires", expires)
+	if ttl > 0 {
+		rw.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d, public", ttl))
+	} else {
+		rw.Header().Set("Cache-Control", "no-cache")
 	}
 }
 

+ 27 - 9
processing_handler_test.go

@@ -343,12 +343,12 @@ func (s *ProcessingHandlerTestSuite) TestErrorSavingToSVG() {
 	require.Equal(s.T(), 422, res.StatusCode)
 }
 
-func (s *ProcessingHandlerTestSuite) TestCacheControlPassthrough() {
+func (s *ProcessingHandlerTestSuite) TestCacheControlPassthroughCacheControl() {
 	config.CacheControlPassthrough = true
 
 	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-		rw.Header().Set("Cache-Control", "fake-cache-control")
-		rw.Header().Set("Expires", "fake-expires")
+		rw.Header().Set("Cache-Control", "max-age=1234, public")
+		rw.Header().Set("Expires", time.Now().Add(time.Hour).UTC().Format(http.TimeFormat))
 		rw.WriteHeader(200)
 		rw.Write(s.readTestFile("test1.png"))
 	}))
@@ -357,16 +357,34 @@ func (s *ProcessingHandlerTestSuite) TestCacheControlPassthrough() {
 	rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
 	res := rw.Result()
 
-	require.Equal(s.T(), "fake-cache-control", res.Header.Get("Cache-Control"))
-	require.Equal(s.T(), "fake-expires", res.Header.Get("Expires"))
+	require.Equal(s.T(), "max-age=1234, public", res.Header.Get("Cache-Control"))
+	require.Empty(s.T(), res.Header.Get("Expires"))
+}
+
+func (s *ProcessingHandlerTestSuite) TestCacheControlPassthroughExpires() {
+	config.CacheControlPassthrough = true
+
+	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+		rw.Header().Set("Expires", time.Now().Add(1239*time.Second).UTC().Format(http.TimeFormat))
+		rw.WriteHeader(200)
+		rw.Write(s.readTestFile("test1.png"))
+	}))
+	defer ts.Close()
+
+	rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
+	res := rw.Result()
+
+	// Use regex to allow some delay
+	require.Regexp(s.T(), regexp.MustCompile("max-age=123[0-9], public"), res.Header.Get("Cache-Control"))
+	require.Empty(s.T(), res.Header.Get("Expires"))
 }
 
 func (s *ProcessingHandlerTestSuite) TestCacheControlPassthroughDisabled() {
 	config.CacheControlPassthrough = false
 
 	ts := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
-		rw.Header().Set("Cache-Control", "fake-cache-control")
-		rw.Header().Set("Expires", "fake-expires")
+		rw.Header().Set("Cache-Control", "max-age=1234, public")
+		rw.Header().Set("Expires", time.Now().Add(time.Hour).UTC().Format(http.TimeFormat))
 		rw.WriteHeader(200)
 		rw.Write(s.readTestFile("test1.png"))
 	}))
@@ -375,8 +393,8 @@ func (s *ProcessingHandlerTestSuite) TestCacheControlPassthroughDisabled() {
 	rw := s.send("/unsafe/rs:fill:4:4/plain/" + ts.URL)
 	res := rw.Result()
 
-	require.NotEqual(s.T(), "fake-cache-control", res.Header.Get("Cache-Control"))
-	require.NotEqual(s.T(), "fake-expires", res.Header.Get("Expires"))
+	require.NotEqual(s.T(), "max-age=1234, public", res.Header.Get("Cache-Control"))
+	require.Empty(s.T(), res.Header.Get("Expires"))
 }
 
 func (s *ProcessingHandlerTestSuite) TestETagDisabled() {

+ 2 - 4
stream.go

@@ -30,8 +30,6 @@ var (
 	}
 
 	streamRespHeaders = []string{
-		"Cache-Control",
-		"Expires",
 		"ETag",
 		"Content-Type",
 		"Content-Encoding",
@@ -117,8 +115,8 @@ func streamOriginImage(ctx context.Context, reqID string, r *http.Request, rw ht
 	}
 
 	setCacheControl(rw, po.Expires, map[string]string{
-		"Cache-Control": rw.Header().Get("Cache-Control"),
-		"Expires":       rw.Header().Get("Expires"),
+		"Cache-Control": res.Header.Get("Cache-Control"),
+		"Expires":       res.Header.Get("Expires"),
 	})
 	setCanonical(rw, imageURL)
 	rw.Header().Set("Content-Security-Policy", "script-src 'none'")