mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-09-16 09:36:18 +02:00
adds Client Hints support using env variable. (#98)
* adds Client Hints support using env variable. * Update processing_options.go Co-Authored-By: selul <marius.cristea@vertistudio.com> * improve client hints support based on the feedback * fix build error and remove redundant line in docs.
This commit is contained in:
committed by
Sergey Alexandrovich
parent
5bd97c42e7
commit
a1a74450d1
@@ -131,6 +131,7 @@ type config struct {
|
||||
|
||||
EnableWebpDetection bool
|
||||
EnforceWebp bool
|
||||
EnableClientHints bool
|
||||
|
||||
Key []byte
|
||||
Salt []byte
|
||||
@@ -221,6 +222,7 @@ func init() {
|
||||
|
||||
boolEnvConfig(&conf.EnableWebpDetection, "IMGPROXY_ENABLE_WEBP_DETECTION")
|
||||
boolEnvConfig(&conf.EnforceWebp, "IMGPROXY_ENFORCE_WEBP")
|
||||
boolEnvConfig(&conf.EnableClientHints, "IMGPROXY_ENABLE_CLIENT_HINTS")
|
||||
|
||||
hexEnvConfig(&conf.Key, "IMGPROXY_KEY")
|
||||
hexEnvConfig(&conf.Salt, "IMGPROXY_SALT")
|
||||
|
@@ -69,7 +69,15 @@ imgproxy can use the `Accept` HTTP header to detect if the browser supports WebP
|
||||
|
||||
When WebP support detection is enabled, please take care to configure your CDN or caching proxy to take the `Accept` HTTP header into account while caching.
|
||||
|
||||
**Warning**: Headers cannot be signed. This means that an attacker can bypass your CDN cache by changing the `Accept` HTTP header. Have this in mind when configuring your production caching setup.
|
||||
**Warning**: Headers cannot be signed. This means that an attacker can bypass your CDN cache by changing the `Accept` HTTP headers. Have this in mind when configuring your production caching setup.
|
||||
|
||||
## Client Hints support
|
||||
|
||||
imgproxy can use the `Width` or `Viewport-Width` HTTP header to determine the width of the image container using Client Hints when the width argument is ommited.
|
||||
|
||||
* `IMGPROXY_ENABLE_CLIENT_HINTS`: enables Client Hints support when the width is ommited for automatic responsive images . Read [here](https://developers.google.com/web/updates/2015/09/automating-resource-selection-with-client-hints) details about Client Hints.
|
||||
|
||||
**Warning**: Headers cannot be signed. This means that an attacker can bypass your CDN cache by changing the `Width` or `Viewport-Width` HTTP headers. Have this in mind when configuring your production caching setup.
|
||||
|
||||
### Watermark
|
||||
|
||||
|
@@ -30,6 +30,12 @@ const (
|
||||
imageTypeGIF = imageType(C.GIF)
|
||||
)
|
||||
|
||||
type processingHeaders struct {
|
||||
Accept string
|
||||
Width string
|
||||
ViewportWidth string
|
||||
}
|
||||
|
||||
var imageTypes = map[string]imageType{
|
||||
"jpeg": imageTypeJPEG,
|
||||
"jpg": imageTypeJPEG,
|
||||
@@ -685,7 +691,7 @@ func parseURLOptions(opts []string) (urlOptions, []string) {
|
||||
return parsed, rest
|
||||
}
|
||||
|
||||
func defaultProcessingOptions(acceptHeader string) (*processingOptions, error) {
|
||||
func defaultProcessingOptions(headers *processingHeaders) (*processingOptions, error) {
|
||||
var err error
|
||||
|
||||
po := processingOptions{
|
||||
@@ -702,10 +708,19 @@ func defaultProcessingOptions(acceptHeader string) (*processingOptions, error) {
|
||||
UsedPresets: make([]string, 0, len(conf.Presets)),
|
||||
}
|
||||
|
||||
if (conf.EnableWebpDetection || conf.EnforceWebp) && strings.Contains(acceptHeader, "image/webp") {
|
||||
if (conf.EnableWebpDetection || conf.EnforceWebp) && strings.Contains(headers.Accept, "image/webp") {
|
||||
po.Format = imageTypeWEBP
|
||||
}
|
||||
|
||||
if conf.EnableClientHints && len(headers.ViewportWidth) > 0 {
|
||||
if vw, err := strconv.Atoi(headers.ViewportWidth); err == nil {
|
||||
po.Width = vw
|
||||
}
|
||||
}
|
||||
if conf.EnableClientHints && len(headers.Width) > 0 {
|
||||
if w, err := strconv.Atoi(headers.Width); err == nil {
|
||||
po.Width = w
|
||||
}
|
||||
}
|
||||
if _, ok := conf.Presets["default"]; ok {
|
||||
err = applyPresetOption(&po, []string{"default"})
|
||||
}
|
||||
@@ -713,8 +728,8 @@ func defaultProcessingOptions(acceptHeader string) (*processingOptions, error) {
|
||||
return &po, err
|
||||
}
|
||||
|
||||
func parsePathAdvanced(parts []string, acceptHeader string) (string, *processingOptions, error) {
|
||||
po, err := defaultProcessingOptions(acceptHeader)
|
||||
func parsePathAdvanced(parts []string, headers *processingHeaders) (string, *processingOptions, error) {
|
||||
po, err := defaultProcessingOptions(headers)
|
||||
if err != nil {
|
||||
return "", po, err
|
||||
}
|
||||
@@ -739,14 +754,14 @@ func parsePathAdvanced(parts []string, acceptHeader string) (string, *processing
|
||||
return url, po, nil
|
||||
}
|
||||
|
||||
func parsePathSimple(parts []string, acceptHeader string) (string, *processingOptions, error) {
|
||||
func parsePathSimple(parts []string, headers *processingHeaders) (string, *processingOptions, error) {
|
||||
var err error
|
||||
|
||||
if len(parts) < 6 {
|
||||
return "", nil, errInvalidPath
|
||||
}
|
||||
|
||||
po, err := defaultProcessingOptions(acceptHeader)
|
||||
po, err := defaultProcessingOptions(headers)
|
||||
if err != nil {
|
||||
return "", po, err
|
||||
}
|
||||
@@ -787,11 +802,6 @@ func parsePath(ctx context.Context, r *http.Request) (context.Context, error) {
|
||||
path := r.URL.Path
|
||||
parts := strings.Split(strings.TrimPrefix(path, "/"), "/")
|
||||
|
||||
var acceptHeader string
|
||||
if h, ok := r.Header["Accept"]; ok {
|
||||
acceptHeader = h[0]
|
||||
}
|
||||
|
||||
if len(parts) < 3 {
|
||||
return ctx, errInvalidPath
|
||||
}
|
||||
@@ -801,15 +811,19 @@ func parsePath(ctx context.Context, r *http.Request) (context.Context, error) {
|
||||
return ctx, err
|
||||
}
|
||||
}
|
||||
headers := &processingHeaders{}
|
||||
headers.Accept = r.Header.Get("Accept")
|
||||
headers.Width = r.Header.Get("Width")
|
||||
headers.ViewportWidth = r.Header.Get("Viewport-Width")
|
||||
|
||||
var imageURL string
|
||||
var po *processingOptions
|
||||
var err error
|
||||
|
||||
if _, ok := resizeTypes[parts[1]]; ok {
|
||||
imageURL, po, err = parsePathSimple(parts[1:], acceptHeader)
|
||||
imageURL, po, err = parsePathSimple(parts[1:], headers)
|
||||
} else {
|
||||
imageURL, po, err = parsePathAdvanced(parts[1:], acceptHeader)
|
||||
imageURL, po, err = parsePathAdvanced(parts[1:], headers)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
Reference in New Issue
Block a user