diff --git a/.gitignore b/.gitignore index c3dc9ec6..7b85e4e1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ tmp/ .gitmodules docker-base docs/sitemap.txt +.env +.devcontainer/* diff --git a/config/config.go b/config/config.go index 10ab4337..45ca8851 100644 --- a/config/config.go +++ b/config/config.go @@ -107,6 +107,7 @@ var ( FallbackImagePath string FallbackImageURL string FallbackImageHTTPCode int + FallbackImageTTL int DataDogEnable bool @@ -247,6 +248,7 @@ func Reset() { FallbackImagePath = "" FallbackImageURL = "" FallbackImageHTTPCode = 200 + FallbackImageTTL = 0 DataDogEnable = false @@ -402,6 +404,7 @@ func Configure() error { configurators.String(&FallbackImagePath, "IMGPROXY_FALLBACK_IMAGE_PATH") configurators.String(&FallbackImageURL, "IMGPROXY_FALLBACK_IMAGE_URL") configurators.Int(&FallbackImageHTTPCode, "IMGPROXY_FALLBACK_IMAGE_HTTP_CODE") + configurators.Int(&FallbackImageTTL, "IMGPROXY_FALLBACK_IMAGE_TTL") configurators.Bool(&DataDogEnable, "IMGPROXY_DATADOG_ENABLE") diff --git a/docs/configuration.md b/docs/configuration.md index e6f152e4..f3e984d6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -242,6 +242,7 @@ You can set up a fallback image that will be used in case imgproxy is unable to * `IMGPROXY_FALLBACK_IMAGE_PATH`: the path to the locally stored image * `IMGPROXY_FALLBACK_IMAGE_URL`: the fallback image URL * `IMGPROXY_FALLBACK_IMAGE_HTTP_CODE`: the HTTP code for the fallback image response. When set to zero, imgproxy will respond with the usual HTTP code. Default: `200` +* `IMGPROXY_FALLBACK_IMAGE_TTL`: a duration (in seconds) sent via the `Expires` and `Cache-Control: max-age` HTTP headers when a fallback image was used. This feature is disabled by default. * `IMGPROXY_FALLBACK_IMAGES_CACHE_SIZE`: the size of custom fallback images cache. When set to `0`, the fallback image cache is disabled. 256 fallback images are cached by default. ## Skip processing diff --git a/imagedata/image_data.go b/imagedata/image_data.go index bc7e2fe9..11cf2a3f 100644 --- a/imagedata/image_data.go +++ b/imagedata/image_data.go @@ -79,22 +79,25 @@ func loadWatermark() (err error) { } func loadFallbackImage() (err error) { - if len(config.FallbackImageData) > 0 { + switch { + case len(config.FallbackImageData) > 0: FallbackImage, err = FromBase64(config.FallbackImageData, "fallback image") - return - } - - if len(config.FallbackImagePath) > 0 { + case len(config.FallbackImagePath) > 0: FallbackImage, err = FromFile(config.FallbackImagePath, "fallback image") - return - } - - if len(config.FallbackImageURL) > 0 { + case len(config.FallbackImageURL) > 0: FallbackImage, err = Download(config.FallbackImageURL, "fallback image", nil, nil) - return + default: + FallbackImage, err = nil, nil } - return nil + if FallbackImage != nil && err == nil && config.FallbackImageTTL > 0 { + if FallbackImage.Headers == nil { + FallbackImage.Headers = make(map[string]string) + } + FallbackImage.Headers["Fallback-Image"] = "1" + } + + return err } func FromBase64(encoded, desc string) (*ImageData, error) { diff --git a/processing_handler.go b/processing_handler.go index 830a98ab..a4fc9059 100644 --- a/processing_handler.go +++ b/processing_handler.go @@ -49,6 +49,7 @@ func initProcessingHandler() { func setCacheControl(rw http.ResponseWriter, originHeaders map[string]string) { var cacheControl, expires string + var ttl int if config.CacheControlPassthrough && originHeaders != nil { if val, ok := originHeaders["Cache-Control"]; ok { @@ -60,8 +61,12 @@ func setCacheControl(rw http.ResponseWriter, originHeaders map[string]string) { } if len(cacheControl) == 0 && len(expires) == 0 { - cacheControl = fmt.Sprintf("max-age=%d, public", config.TTL) - expires = time.Now().Add(time.Second * time.Duration(config.TTL)).Format(http.TimeFormat) + ttl = config.TTL + if _, ok := originHeaders["Fallback-Image"]; ok && config.FallbackImageTTL > 0 { + ttl = config.FallbackImageTTL + } + cacheControl = fmt.Sprintf("max-age=%d, public", ttl) + expires = time.Now().Add(time.Second * time.Duration(ttl)).Format(http.TimeFormat) } if len(cacheControl) > 0 { @@ -246,6 +251,7 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) { if config.FallbackImageHTTPCode > 0 { statusCode = config.FallbackImageHTTPCode } + originData = imagedata.FallbackImage }