1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-12-23 22:11:10 +02:00
Files
imgproxy/options/parser/processing_options.go

277 lines
7.2 KiB
Go
Raw Permalink Normal View History

2025-09-25 19:48:53 +03:00
package optionsparser
2018-09-07 19:37:25 +06:00
import (
2024-02-16 20:37:56 +03:00
"slices"
2018-09-07 19:37:25 +06:00
"strings"
2019-10-10 20:35:17 +06:00
2025-10-28 18:42:32 +03:00
"github.com/imgproxy/imgproxy/v3/clientfeatures"
2021-09-30 20:23:30 +06:00
"github.com/imgproxy/imgproxy/v3/ierrors"
2021-10-11 17:50:12 +06:00
"github.com/imgproxy/imgproxy/v3/imath"
2025-09-25 19:48:53 +03:00
"github.com/imgproxy/imgproxy/v3/options"
2025-09-23 20:16:36 +03:00
"github.com/imgproxy/imgproxy/v3/options/keys"
2025-09-25 19:48:53 +03:00
"github.com/imgproxy/imgproxy/v3/processing"
)
2025-09-25 19:48:53 +03:00
func (p *Parser) applyURLOption(
o *options.Options,
name string,
args []string,
usedPresets ...string,
) error {
2018-09-07 19:37:25 +06:00
switch name {
2018-10-03 21:36:52 +06:00
case "resize", "rs":
return p.applyResizeOption(o, args)
2018-10-03 21:36:52 +06:00
case "size", "s":
return p.applySizeOption(o, args)
case "resizing_type", "rt":
return p.applyResizingTypeOption(o, args)
2018-10-03 21:36:52 +06:00
case "width", "w":
return p.applyWidthOption(o, args)
2018-10-03 21:36:52 +06:00
case "height", "h":
return p.applyHeightOption(o, args)
case "min-width", "mw":
return p.applyMinWidthOption(o, args)
case "min-height", "mh":
return p.applyMinHeightOption(o, args)
2022-01-18 16:09:32 +06:00
case "zoom", "z":
return p.applyZoomOption(o, args)
case "dpr":
return p.applyDprOption(o, args)
2018-10-03 21:36:52 +06:00
case "enlarge", "el":
return p.applyEnlargeOption(o, args)
2019-02-21 21:55:20 +06:00
case "extend", "ex":
return p.applyExtendOption(o, args)
case "extend_aspect_ratio", "extend_ar", "exar":
return p.applyExtendAspectRatioOption(o, args)
2018-10-03 21:36:52 +06:00
case "gravity", "g":
return p.applyGravityOption(o, args)
case "crop", "c":
return p.applyCropOption(o, args)
2020-01-17 15:54:50 +06:00
case "trim", "t":
return p.applyTrimOption(o, args)
case "padding", "pd":
return p.applyPaddingOption(o, args)
case "auto_rotate", "ar":
return p.applyAutoRotateOption(o, args)
case "rotate", "rot":
return p.applyRotateOption(o, args)
2018-10-03 21:36:52 +06:00
case "background", "bg":
return p.applyBackgroundOption(o, args)
2018-10-03 21:36:52 +06:00
case "blur", "bl":
return p.applyBlurOption(o, args)
2018-10-03 21:36:52 +06:00
case "sharpen", "sh":
return p.applySharpenOption(o, args)
2021-04-27 13:23:22 +03:00
case "pixelate", "pix":
return p.applyPixelateOption(o, args)
2018-10-19 15:47:11 +06:00
case "watermark", "wm":
return p.applyWatermarkOption(o, args)
case "strip_metadata", "sm":
return p.applyStripMetadataOption(o.Main(), args)
case "keep_copyright", "kcr":
return p.applyKeepCopyrightOption(o.Main(), args)
2021-01-12 20:43:09 +06:00
case "strip_color_profile", "scp":
return p.applyStripColorProfileOption(o.Main(), args)
case "enforce_thumbnail", "eth":
return p.applyEnforceThumbnailOption(o.Main(), args)
// Saving options
case "quality", "q":
return p.applyQualityOption(o.Main(), args)
2021-09-29 19:49:18 +06:00
case "format_quality", "fq":
return p.applyFormatQualityOption(o.Main(), args)
case "max_bytes", "mb":
return p.applyMaxBytesOption(o.Main(), args)
case "format", "f", "ext":
return p.applyFormatOption(o.Main(), args)
// Handling options
case "skip_processing", "skp":
return p.applySkipProcessingFormatsOption(o.Main(), args)
2022-09-07 16:50:21 +06:00
case "raw":
return p.applyRawOption(o.Main(), args)
case "cachebuster", "cb":
return p.applyCacheBusterOption(o.Main(), args)
case "expires", "exp":
return p.applyExpiresOption(o.Main(), args)
case "filename", "fn":
return p.applyFilenameOption(o.Main(), args)
2022-09-05 16:55:38 +06:00
case "return_attachment", "att":
return p.applyReturnAttachmentOption(o.Main(), args)
// Presets
case "preset", "pr":
return p.applyPresetOption(o, args, usedPresets...)
2023-02-23 21:11:44 +03:00
// Security
case "max_src_resolution", "msr":
return p.applyMaxSrcResolutionOption(o, args)
2023-02-23 21:11:44 +03:00
case "max_src_file_size", "msfs":
return p.applyMaxSrcFileSizeOption(o, args)
2023-02-23 21:11:44 +03:00
case "max_animation_frames", "maf":
return p.applyMaxAnimationFramesOption(o.Main(), args)
2023-02-23 21:11:44 +03:00
case "max_animation_frame_resolution", "mafr":
return p.applyMaxAnimationFrameResolutionOption(o.Main(), args)
case "max_result_dimension", "mrd":
return p.applyMaxResultDimensionOption(o.Main(), args)
}
return newUnknownOptionError("processing", name)
}
2025-09-25 19:48:53 +03:00
func (p *Parser) applyURLOptions(
o *options.Options,
options urlOptions,
allowAll bool,
usedPresets ...string,
) error {
2025-09-23 20:16:36 +03:00
allowAll = allowAll || len(p.config.AllowedProcessingOptions) == 0
2019-07-22 17:27:18 +06:00
for _, opt := range options {
2025-09-23 20:16:36 +03:00
if !allowAll && !slices.Contains(p.config.AllowedProcessingOptions, opt.Name) {
return newForbiddenOptionError("processing", opt.Name)
}
2025-09-25 19:48:53 +03:00
if err := p.applyURLOption(o, opt.Name, opt.Args, usedPresets...); err != nil {
return err
}
2018-09-07 19:37:25 +06:00
}
return nil
}
2025-10-28 18:42:32 +03:00
func (p *Parser) defaultProcessingOptions(
features *clientfeatures.Features,
) (*options.Options, error) {
2025-09-25 19:48:53 +03:00
o := options.New()
2025-10-28 18:42:32 +03:00
if features != nil {
if features.PreferWebP || features.EnforceWebP {
o.Set(keys.PreferWebP, true)
}
2025-09-23 20:16:36 +03:00
2025-10-28 18:42:32 +03:00
if features.EnforceWebP {
2025-09-25 19:48:53 +03:00
o.Set(keys.EnforceWebP, true)
2025-09-23 20:16:36 +03:00
}
2018-09-07 23:41:06 +06:00
2025-10-28 18:42:32 +03:00
if features.PreferAvif || features.EnforceAvif {
o.Set(keys.PreferAvif, true)
}
2025-09-23 20:16:36 +03:00
2025-10-28 18:42:32 +03:00
if features.EnforceAvif {
2025-09-25 19:48:53 +03:00
o.Set(keys.EnforceAvif, true)
2025-09-23 20:16:36 +03:00
}
2018-09-07 23:41:06 +06:00
2025-10-28 18:42:32 +03:00
if features.PreferJxl || features.EnforceJxl {
o.Set(keys.PreferJxl, true)
}
2025-09-23 20:16:36 +03:00
2025-10-28 18:42:32 +03:00
if features.EnforceJxl {
2025-09-25 19:48:53 +03:00
o.Set(keys.EnforceJxl, true)
2025-09-23 20:16:36 +03:00
}
2024-12-08 19:02:08 +03:00
2025-09-23 20:16:36 +03:00
dpr := 1.0
2025-10-28 18:42:32 +03:00
if features.ClientHintsDPR > 0 {
o.Set(keys.Dpr, features.ClientHintsDPR)
dpr = features.ClientHintsDPR
2021-10-11 17:50:12 +06:00
}
2025-10-28 18:42:32 +03:00
if features.ClientHintsWidth > 0 {
o.Set(keys.Width, imath.Shrink(features.ClientHintsWidth, dpr))
}
}
2021-04-26 17:52:50 +06:00
2025-09-23 20:16:36 +03:00
if _, ok := p.presets["default"]; ok {
if err := p.applyPresetOption(o, []string{"default"}); err != nil {
2025-09-25 19:48:53 +03:00
return o, err
}
2018-09-11 16:33:36 +06:00
}
2025-09-25 19:48:53 +03:00
return o, nil
2018-09-11 16:33:36 +06:00
}
// ParsePath parses the given request path and returns the processing options and image URL
2025-09-23 20:16:36 +03:00
func (p *Parser) ParsePath(
path string,
2025-10-28 18:42:32 +03:00
features *clientfeatures.Features,
2025-09-25 19:48:53 +03:00
) (o *options.Options, imageURL string, err error) {
if path == "" || path == "/" {
return nil, "", newInvalidURLError("invalid path: %s", path)
}
parts := strings.Split(strings.TrimPrefix(path, "/"), "/")
2025-09-23 20:16:36 +03:00
if p.config.OnlyPresets {
2025-10-28 18:42:32 +03:00
o, imageURL, err = p.parsePathPresets(parts, features)
} else {
2025-10-28 18:42:32 +03:00
o, imageURL, err = p.parsePathOptions(parts, features)
}
if err != nil {
return nil, "", ierrors.Wrap(err, 0)
}
2025-09-25 19:48:53 +03:00
return o, imageURL, nil
}
// parsePathOptions parses processing options from the URL path
2025-09-25 19:48:53 +03:00
func (p *Parser) parsePathOptions(
parts []string,
2025-10-28 18:42:32 +03:00
features *clientfeatures.Features,
2025-09-25 19:48:53 +03:00
) (*options.Options, string, error) {
if _, ok := processing.ResizeTypes[parts[0]]; ok {
return nil, "", newInvalidURLError("It looks like you're using the deprecated basic URL format")
2021-12-07 15:16:59 +06:00
}
2025-10-28 18:42:32 +03:00
o, err := p.defaultProcessingOptions(features)
2018-09-11 16:33:36 +06:00
if err != nil {
2021-04-26 17:52:50 +06:00
return nil, "", err
2018-09-11 16:33:36 +06:00
}
2018-09-07 23:41:06 +06:00
2025-09-25 19:48:53 +03:00
urlOpts, urlParts := p.parseURLOptions(parts)
2018-09-07 23:41:06 +06:00
2025-09-25 19:48:53 +03:00
if err = p.applyURLOptions(o, urlOpts, false); err != nil {
2021-04-26 17:52:50 +06:00
return nil, "", err
2018-09-07 19:37:25 +06:00
}
2025-09-23 20:16:36 +03:00
url, extension, err := p.DecodeURL(urlParts)
2018-09-07 19:37:25 +06:00
if err != nil {
2021-04-26 17:52:50 +06:00
return nil, "", err
2018-09-07 19:37:25 +06:00
}
2025-09-25 19:48:53 +03:00
if !options.Get(o, keys.Raw, false) && len(extension) > 0 {
if err = p.applyFormatOption(o, []string{extension}); err != nil {
2021-04-26 17:52:50 +06:00
return nil, "", err
2018-09-11 18:26:27 +06:00
}
2018-09-07 19:37:25 +06:00
}
2025-09-25 19:48:53 +03:00
return o, url, nil
2018-09-07 19:37:25 +06:00
}
// parsePathPresets parses presets from the URL path
2025-10-28 18:42:32 +03:00
func (p *Parser) parsePathPresets(
parts []string,
features *clientfeatures.Features,
) (*options.Options, string, error) {
o, err := p.defaultProcessingOptions(features)
if err != nil {
2021-04-26 17:52:50 +06:00
return nil, "", err
}
2025-09-23 20:16:36 +03:00
presets := strings.Split(parts[0], p.config.ArgumentsSeparator)
urlParts := parts[1:]
if err = p.applyPresetOption(o, presets); err != nil {
2021-04-26 17:52:50 +06:00
return nil, "", err
}
2025-09-23 20:16:36 +03:00
url, extension, err := p.DecodeURL(urlParts)
if err != nil {
2021-04-26 17:52:50 +06:00
return nil, "", err
}
2025-09-25 19:48:53 +03:00
if !options.Get(o, keys.Raw, false) && len(extension) > 0 {
if err = p.applyFormatOption(o, []string{extension}); err != nil {
2021-04-26 17:52:50 +06:00
return nil, "", err
}
}
2025-09-25 19:48:53 +03:00
return o, url, nil
}