diff --git a/config.go b/config.go index e46baec5..e0169d32 100644 --- a/config.go +++ b/config.go @@ -209,6 +209,7 @@ type config struct { TTL int CacheControlPassthrough bool + SetCanonicalHeader bool SoReuseport bool @@ -360,6 +361,7 @@ func configure() error { intEnvConfig(&conf.TTL, "IMGPROXY_TTL") boolEnvConfig(&conf.CacheControlPassthrough, "IMGPROXY_CACHE_CONTROL_PASSTHROUGH") + boolEnvConfig(&conf.SetCanonicalHeader, "IMGPROXY_SET_CANONICAL_HEADER") boolEnvConfig(&conf.SoReuseport, "IMGPROXY_SO_REUSEPORT") diff --git a/docs/configuration.md b/docs/configuration.md index 078f91db..c21a2c59 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -36,6 +36,7 @@ echo $(xxd -g 2 -l 64 -p /dev/random | tr -d '\n') * `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_SET_CANONICAL_HEADER`: when `true` and the source image has `http` or `https` scheme, set `rel="canonical"` HTTP header to the value of the source image URL. More details [here](https://developers.google.com/search/docs/advanced/crawling/consolidate-duplicate-urls#rel-canonical-header-method). Default: false; * `IMGPROXY_SO_REUSEPORT`: when `true`, enables `SO_REUSEPORT` socket option (currently on linux and darwin only); * `IMGPROXY_PATH_PREFIX`: URL path prefix. Example: when set to `/abc/def`, imgproxy URL will be `/abc/def/%signature/%processing_options/%source_url`. Default: blank. * `IMGPROXY_USER_AGENT`: User-Agent header that will be sent with source image request. Default: `imgproxy/%current_version`; diff --git a/processing_handler.go b/processing_handler.go index e118e135..556754ed 100644 --- a/processing_handler.go +++ b/processing_handler.go @@ -67,6 +67,14 @@ func respondWithImage(ctx context.Context, reqID string, r *http.Request, rw htt rw.Header().Set("Content-Type", po.Format.Mime()) rw.Header().Set("Content-Disposition", contentDisposition) + if conf.SetCanonicalHeader { + origin := getImageURL(ctx) + if strings.HasPrefix(origin, "https://") || strings.HasPrefix(origin, "http://") { + linkHeader := fmt.Sprintf(`<%s>; rel="canonical"`, origin) + rw.Header().Set("Link", linkHeader) + } + } + var cacheControl, expires string if conf.CacheControlPassthrough {