|
@@ -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 {
|