diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ca811d6..6ff939c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ ### Fix - Fix loading animated images with a huge number of frames. +- Fix recursive presets detection. - (pro) Fix `video_thumbnail_tile` option behavior when the video has a single keyframe. - (pro) Fix the `trim` argument of the `video_thumbnail_tile` processing option. - (pro) Fix `video_thumbnail_tile` behavior when the `step` argument value is less than frame duration. diff --git a/options/presets.go b/options/presets.go index ba7de745..d9248374 100644 --- a/options/presets.go +++ b/options/presets.go @@ -59,7 +59,7 @@ func parsePreset(presetStr string) error { func ValidatePresets() error { for name, opts := range presets { po := NewProcessingOptions() - if err := applyURLOptions(po, opts); err != nil { + if err := applyURLOptions(po, opts, name); err != nil { return fmt.Errorf("Error in preset `%s`: %s", name, err) } } diff --git a/options/presets_test.go b/options/presets_test.go index 50ec347f..e78f0c1f 100644 --- a/options/presets_test.go +++ b/options/presets_test.go @@ -76,7 +76,7 @@ func (s *PresetsTestSuite) TestParsePresetComment() { func (s *PresetsTestSuite) TestValidatePresets() { presets = map[string]urlOptions{ - "test": urlOptions{ + "test": { urlOption{Name: "resize", Args: []string{"fit", "100", "200"}}, urlOption{Name: "sharpen", Args: []string{"2"}}, }, @@ -89,7 +89,7 @@ func (s *PresetsTestSuite) TestValidatePresets() { func (s *PresetsTestSuite) TestValidatePresetsInvalid() { presets = map[string]urlOptions{ - "test": urlOptions{ + "test": { urlOption{Name: "resize", Args: []string{"fit", "-1", "-2"}}, urlOption{Name: "sharpen", Args: []string{"2"}}, }, diff --git a/options/processing_options.go b/options/processing_options.go index 71b859f7..0fc4efef 100644 --- a/options/processing_options.go +++ b/options/processing_options.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net/http" + "slices" "strconv" "strings" "time" @@ -177,15 +178,6 @@ func (po *ProcessingOptions) GetQuality() int { return q } -func (po *ProcessingOptions) isPresetUsed(name string) bool { - for _, usedName := range po.UsedPresets { - if usedName == name { - return true - } - } - return false -} - func (po *ProcessingOptions) Diff() structdiff.Entries { return structdiff.Diff(NewProcessingOptions(), po) } @@ -689,17 +681,17 @@ func applyPixelateOption(po *ProcessingOptions, args []string) error { return nil } -func applyPresetOption(po *ProcessingOptions, args []string) error { +func applyPresetOption(po *ProcessingOptions, args []string, usedPresets ...string) error { for _, preset := range args { if p, ok := presets[preset]; ok { - if po.isPresetUsed(preset) { + if slices.Contains(usedPresets, preset) { log.Warningf("Recursive preset usage is detected: %s", preset) continue } po.UsedPresets = append(po.UsedPresets, preset) - if err := applyURLOptions(po, p); err != nil { + if err := applyURLOptions(po, p, append(usedPresets, preset)...); err != nil { return err } } else { @@ -976,7 +968,7 @@ func applyMaxAnimationFrameResolutionOption(po *ProcessingOptions, args []string return nil } -func applyURLOption(po *ProcessingOptions, name string, args []string) error { +func applyURLOption(po *ProcessingOptions, name string, args []string, usedPresets ...string) error { switch name { case "resize", "rs": return applyResizeOption(po, args) @@ -1056,7 +1048,7 @@ func applyURLOption(po *ProcessingOptions, name string, args []string) error { return applyReturnAttachmentOption(po, args) // Presets case "preset", "pr": - return applyPresetOption(po, args) + return applyPresetOption(po, args, usedPresets...) // Security case "max_src_resolution", "msr": return applyMaxSrcResolutionOption(po, args) @@ -1071,9 +1063,9 @@ func applyURLOption(po *ProcessingOptions, name string, args []string) error { return fmt.Errorf("Unknown processing option: %s", name) } -func applyURLOptions(po *ProcessingOptions, options urlOptions) error { +func applyURLOptions(po *ProcessingOptions, options urlOptions, usedPresets ...string) error { for _, opt := range options { - if err := applyURLOption(po, opt.Name, opt.Args); err != nil { + if err := applyURLOption(po, opt.Name, opt.Args, usedPresets...); err != nil { return err } } diff --git a/options/processing_options_test.go b/options/processing_options_test.go index 2c1416a6..1ab1b5c3 100644 --- a/options/processing_options_test.go +++ b/options/processing_options_test.go @@ -377,14 +377,15 @@ func (s *ProcessingOptionsTestSuite) TestParsePathPresetDefault() { func (s *ProcessingOptionsTestSuite) TestParsePathPresetLoopDetection() { presets["test1"] = urlOptions{ urlOption{Name: "resizing_type", Args: []string{"fill"}}, + urlOption{Name: "preset", Args: []string{"test2"}}, } presets["test2"] = urlOptions{ urlOption{Name: "blur", Args: []string{"0.2"}}, - urlOption{Name: "quality", Args: []string{"50"}}, + urlOption{Name: "preset", Args: []string{"test1"}}, } - path := "/preset:test1:test2:test1/plain/http://images.dev/lorem/ipsum.jpg" + path := "/preset:test1/plain/http://images.dev/lorem/ipsum.jpg" po, _, err := ParsePath(path, make(http.Header)) require.Nil(s.T(), err)