Преглед на файлове

IMGPROXY_CACHE_CONTROL_PASSTHROUGH config

DarthSim преди 5 години
родител
ревизия
372faba5c1
променени са 6 файла, в които са добавени 46 реда и са изтрити 7 реда
  1. 1 0
      CHANGELOG.md
  2. 6 2
      config.go
  3. 1 0
      docs/configuration.md
  4. 15 2
      download.go
  5. 4 1
      gcs_transport.go
  6. 19 2
      processing_handler.go

+ 1 - 0
CHANGELOG.md

@@ -3,6 +3,7 @@
 ## [Unreleased]
 ### Added
 - `IMGPROXY_NETWORK` config. Allows to bind on Unix socket.
+- `IMGPROXY_CACHE_CONTROL_PASSTHROUGH` config.
 
 ### Fixed
 - Fix detection of SVG starting with a comment.

+ 6 - 2
config.go

@@ -153,8 +153,11 @@ type config struct {
 	DownloadTimeout  int
 	Concurrency      int
 	MaxClients       int
-	TTL              int
-	SoReuseport      bool
+
+	TTL                     int
+	CacheControlPassthrough bool
+
+	SoReuseport bool
 
 	MaxSrcDimension    int
 	MaxSrcResolution   int
@@ -284,6 +287,7 @@ func configure() {
 	intEnvConfig(&conf.MaxClients, "IMGPROXY_MAX_CLIENTS")
 
 	intEnvConfig(&conf.TTL, "IMGPROXY_TTL")
+	boolEnvConfig(&conf.CacheControlPassthrough, "IMGPROXY_CACHE_CONTROL_PASSTHROUGH")
 
 	boolEnvConfig(&conf.SoReuseport, "IMGPROXY_SO_REUSEPORT")
 

+ 1 - 0
docs/configuration.md

@@ -35,6 +35,7 @@ echo $(xxd -g 2 -l 64 -p /dev/random | tr -d '\n')
 * `IMGPROXY_CONCURRENCY`: the maximum number of image requests to be processed simultaneously. Default: number of CPU cores times two;
 * `IMGPROXY_MAX_CLIENTS`: the maximum number of simultaneous active connections. Default: `IMGPROXY_CONCURRENCY * 10`;
 * `IMGPROXY_TTL`: duration (in seconds) sent in `Expires` and `Cache-Control: max-age` HTTP headers. Default: `3600` (1 hour);
+* `IMGPROXY_CACHE_CONTROL_PASSTHROUGH`: when `true` and source image response contains `Expires` or `Cache-Control` headers, reuse those headers. Default: false;
 * `IMGPROXY_SO_REUSEPORT`: when `true`, enables `SO_REUSEPORT` socket option (currently on linux and darwin only);
 * `IMGPROXY_USER_AGENT`: User-Agent header that will be sent with source image request. Default: `imgproxy/%current_version`;
 * `IMGPROXY_USE_ETAG`: when `true`, enables using [ETag](https://en.wikipedia.org/wiki/HTTP_ETag) HTTP header for HTTP cache control. Default: false;

+ 15 - 2
download.go

@@ -14,8 +14,11 @@ import (
 )
 
 var (
-	downloadClient  *http.Client
-	imageDataCtxKey = ctxKey("imageData")
+	downloadClient *http.Client
+
+	imageDataCtxKey          = ctxKey("imageData")
+	cacheControlHeaderCtxKey = ctxKey("cacheControlHeader")
+	expiresHeaderCtxKey      = ctxKey("expiresHeader")
 
 	errSourceDimensionsTooBig      = newError(422, "Source image dimensions are too big", "Invalid source image")
 	errSourceResolutionTooBig      = newError(422, "Source image resolution is too big", "Invalid source image")
@@ -196,6 +199,8 @@ func downloadImage(ctx context.Context) (context.Context, context.CancelFunc, er
 	}
 
 	ctx = context.WithValue(ctx, imageDataCtxKey, imgdata)
+	ctx = context.WithValue(ctx, cacheControlHeaderCtxKey, res.Header.Get("Cache-Control"))
+	ctx = context.WithValue(ctx, expiresHeaderCtxKey, res.Header.Get("Expires"))
 
 	return ctx, imgdata.Close, err
 }
@@ -203,3 +208,11 @@ func downloadImage(ctx context.Context) (context.Context, context.CancelFunc, er
 func getImageData(ctx context.Context) *imageData {
 	return ctx.Value(imageDataCtxKey).(*imageData)
 }
+
+func getCacheControlHeader(ctx context.Context) string {
+	return ctx.Value(cacheControlHeaderCtxKey).(string)
+}
+
+func getExpiresHeader(ctx context.Context) string {
+	return ctx.Value(expiresHeaderCtxKey).(string)
+}

+ 4 - 1
gcs_transport.go

@@ -47,13 +47,16 @@ func (t gcsTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 		return nil, err
 	}
 
+	header := make(http.Header)
+	header.Set("Cache-Control", reader.Attrs.CacheControl)
+
 	return &http.Response{
 		Status:        "200 OK",
 		StatusCode:    200,
 		Proto:         "HTTP/1.0",
 		ProtoMajor:    1,
 		ProtoMinor:    0,
-		Header:        make(http.Header),
+		Header:        header,
 		ContentLength: reader.Attrs.Size,
 		Body:          reader,
 		Close:         true,

+ 19 - 2
processing_handler.go

@@ -53,11 +53,28 @@ func respondWithImage(ctx context.Context, reqID string, r *http.Request, rw htt
 		contentDisposition = po.Format.ContentDispositionFromURL(getImageURL(ctx))
 	}
 
-	rw.Header().Set("Expires", time.Now().Add(time.Second*time.Duration(conf.TTL)).Format(http.TimeFormat))
-	rw.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d, public", conf.TTL))
 	rw.Header().Set("Content-Type", po.Format.Mime())
 	rw.Header().Set("Content-Disposition", contentDisposition)
 
+	var cacheControl, expires string
+
+	if conf.CacheControlPassthrough {
+		cacheControl = getCacheControlHeader(ctx)
+		expires = getExpiresHeader(ctx)
+	}
+
+	if len(cacheControl) == 0 && len(expires) == 0 {
+		cacheControl = fmt.Sprintf("max-age=%d, public", conf.TTL)
+		expires = time.Now().Add(time.Second * time.Duration(conf.TTL)).Format(http.TimeFormat)
+	}
+
+	if len(cacheControl) > 0 {
+		rw.Header().Set("Cache-Control", cacheControl)
+	}
+	if len(expires) > 0 {
+		rw.Header().Set("Expires", expires)
+	}
+
 	if len(headerVaryValue) > 0 {
 		rw.Header().Set("Vary", headerVaryValue)
 	}