diff --git a/config.go b/config.go index 6df8f22b..d5de0878 100644 --- a/config.go +++ b/config.go @@ -181,7 +181,8 @@ type config struct { BaseURL string - Presets presets + Presets presets + OnlyPresets bool WatermarkData string WatermarkPath string @@ -232,6 +233,7 @@ var conf = config{ SentryRelease: fmt.Sprintf("imgproxy/%s", version), FreeMemoryInterval: 10, BufferPoolCalibrationThreshold: 1024, + OnlyPresets: false, } func init() { @@ -311,6 +313,7 @@ func init() { conf.Presets = make(presets) presetEnvConfig(conf.Presets, "IMGPROXY_PRESETS") presetFileConfig(conf.Presets, *presetsPath) + boolEnvConfig(&conf.OnlyPresets, "IMGPROXY_ONLY_PRESETS") strEnvConfig(&conf.WatermarkData, "IMGPROXY_WATERMARK_DATA") strEnvConfig(&conf.WatermarkPath, "IMGPROXY_WATERMARK_PATH") diff --git a/docs/configuration.md b/docs/configuration.md index 76475bd1..06ce5dbd 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -111,6 +111,7 @@ There are two ways to define presets: ##### Using an environment variable * `IMGPROXY_PRESETS`: set of preset definitions, comma-divided. Example: `default=resizing_type:fill/enlarge:1,sharp=sharpen:0.7,blurry=blur:2`. Default: blank. +* `IMGPROXY_ONLY_PRESETS`: disable all URL formats but presets. In this case, you always need to inform a valid preset. Example: `http://imgproxy.example.com/unsafe/thumbnail/plain/http://example.com/images/curiosity.jpg@png` ##### Using a command line argument diff --git a/docs/presets.md b/docs/presets.md index cd1c6b13..32971ab9 100644 --- a/docs/presets.md +++ b/docs/presets.md @@ -21,3 +21,11 @@ Read how to specify your presets with imgproxy in the [Configuration](./configur ### Default preset A preset named `default` will be applied to each image. Useful in case you want your default processing options to be different from the imgproxy default ones. + +### Only presets + +If you set `IMGPROXY_ONLY_PRESETS` as `true`, a preset is obligatory, and all other URL formats are disabled. + +In this case, you always need to inform a preset in your URLs without the `preset` or `pr` statement. Example: `http://imgproxy.example.com/AfrOrF3gWeDA6VOlDG4TzxMv39O7MXnF4CXpKUwGqRM/thumbnail/aHR0cDovL2V4YW1w/bGUuY29tL2ltYWdl/cy9jdXJpb3NpdHku/anBn.png` + +It's possible to use more than one preset separing them with `:` like `thumbnail:gray`. \ No newline at end of file diff --git a/processing_options.go b/processing_options.go index 5606554b..8747d64c 100644 --- a/processing_options.go +++ b/processing_options.go @@ -803,6 +803,33 @@ func parsePathAdvanced(parts []string, headers *processingHeaders) (string, *pro return url, po, nil } +func parsePathPresets(parts []string, headers *processingHeaders) (string, *processingOptions, error) { + po, err := defaultProcessingOptions(headers) + if err != nil { + return "", po, err + } + + presets := strings.Split(parts[0], ":") + urlParts := parts[1:] + + if err := applyPresetOption(po, presets); err != nil { + return "", nil, err + } + + url, extension, err := decodeURL(urlParts) + if err != nil { + return "", po, err + } + + if len(extension) > 0 { + if err := applyFormatOption(po, []string{extension}); err != nil { + return "", po, err + } + } + + return url, po, nil +} + func parsePathBasic(parts []string, headers *processingHeaders) (string, *processingOptions, error) { var err error @@ -875,7 +902,9 @@ func parsePath(ctx context.Context, r *http.Request) (context.Context, error) { var po *processingOptions var err error - if _, ok := resizeTypes[parts[1]]; ok { + if conf.OnlyPresets { + imageURL, po, err = parsePathPresets(parts[1:], headers) + } else if _, ok := resizeTypes[parts[1]]; ok { imageURL, po, err = parsePathBasic(parts[1:], headers) } else { imageURL, po, err = parsePathAdvanced(parts[1:], headers) diff --git a/processing_options_test.go b/processing_options_test.go index 97c6020e..250652e7 100644 --- a/processing_options_test.go +++ b/processing_options_test.go @@ -561,6 +561,46 @@ func (s *ProcessingOptionsTestSuite) TestParsePathSignedInvalid() { assert.Equal(s.T(), errInvalidSignature.Error(), err.Error()) } +func (s *ProcessingOptionsTestSuite) TestParsePathOnlyPresets() { + conf.OnlyPresets = true + conf.Presets["test1"] = urlOptions{ + "blur": []string{"0.2"}, + } + conf.Presets["test2"] = urlOptions{ + "quality": []string{"50"}, + } + + req := s.getRequest("http://example.com/unsafe/test1:test2/plain/http://images.dev/lorem/ipsum.jpg") + + ctx, err := parsePath(context.Background(), req) + + require.Nil(s.T(), err) + + po := getProcessingOptions(ctx) + assert.Equal(s.T(), float32(0.2), po.Blur) + assert.Equal(s.T(), 50, po.Quality) +} + +func (s *ProcessingOptionsTestSuite) TestParseBase64URLOnlyPresets() { + conf.OnlyPresets = true + conf.Presets["test1"] = urlOptions{ + "blur": []string{"0.2"}, + } + conf.Presets["test2"] = urlOptions{ + "quality": []string{"50"}, + } + + imageURL := "http://images.dev/lorem/ipsum.jpg?param=value" + req := s.getRequest(fmt.Sprintf("http://example.com/unsafe/test1:test2/%s.png", base64.RawURLEncoding.EncodeToString([]byte(imageURL)))) + + ctx, err := parsePath(context.Background(), req) + + require.Nil(s.T(), err) + + po := getProcessingOptions(ctx) + assert.Equal(s.T(), float32(0.2), po.Blur) + assert.Equal(s.T(), 50, po.Quality) +} func TestProcessingOptions(t *testing.T) { suite.Run(t, new(ProcessingOptionsTestSuite)) }