mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-09-27 12:07:59 +02:00
Add URL replacements
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
### Add
|
||||||
|
- Add `IMGPROXY_URL_REPLACEMENTS` config.
|
||||||
|
|
||||||
## [3.17.0] - 2023-05-10
|
## [3.17.0] - 2023-05-10
|
||||||
### Add
|
### Add
|
||||||
|
@@ -126,7 +126,8 @@ var (
|
|||||||
|
|
||||||
LastModifiedEnabled bool
|
LastModifiedEnabled bool
|
||||||
|
|
||||||
BaseURL string
|
BaseURL string
|
||||||
|
URLReplacements map[*regexp.Regexp]string
|
||||||
|
|
||||||
Presets []string
|
Presets []string
|
||||||
OnlyPresets bool
|
OnlyPresets bool
|
||||||
@@ -317,6 +318,7 @@ func Reset() {
|
|||||||
LastModifiedEnabled = false
|
LastModifiedEnabled = false
|
||||||
|
|
||||||
BaseURL = ""
|
BaseURL = ""
|
||||||
|
URLReplacements = make(map[*regexp.Regexp]string)
|
||||||
|
|
||||||
Presets = make([]string, 0)
|
Presets = make([]string, 0)
|
||||||
OnlyPresets = false
|
OnlyPresets = false
|
||||||
@@ -518,6 +520,9 @@ func Configure() error {
|
|||||||
configurators.Bool(&LastModifiedEnabled, "IMGPROXY_USE_LAST_MODIFIED")
|
configurators.Bool(&LastModifiedEnabled, "IMGPROXY_USE_LAST_MODIFIED")
|
||||||
|
|
||||||
configurators.String(&BaseURL, "IMGPROXY_BASE_URL")
|
configurators.String(&BaseURL, "IMGPROXY_BASE_URL")
|
||||||
|
if err := configurators.Replacements(&URLReplacements, "IMGPROXY_URL_REPLACEMENTS"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
configurators.StringSlice(&Presets, "IMGPROXY_PRESETS")
|
configurators.StringSlice(&Presets, "IMGPROXY_PRESETS")
|
||||||
if err := configurators.StringSliceFile(&Presets, presetsPath); err != nil {
|
if err := configurators.StringSliceFile(&Presets, presetsPath); err != nil {
|
||||||
|
@@ -221,6 +221,26 @@ func Patterns(s *[]*regexp.Regexp, name string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Replacements(m *map[*regexp.Regexp]string, name string) error {
|
||||||
|
var sm map[string]string
|
||||||
|
|
||||||
|
if err := StringMap(&sm, name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sm) > 0 {
|
||||||
|
mm := make(map[*regexp.Regexp]string)
|
||||||
|
|
||||||
|
for k, v := range sm {
|
||||||
|
mm[RegexpFromPattern(k)] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
*m = mm
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func RegexpFromPattern(pattern string) *regexp.Regexp {
|
func RegexpFromPattern(pattern string) *regexp.Regexp {
|
||||||
var result strings.Builder
|
var result strings.Builder
|
||||||
// Perform prefix matching
|
// Perform prefix matching
|
||||||
@@ -228,7 +248,7 @@ func RegexpFromPattern(pattern string) *regexp.Regexp {
|
|||||||
for i, part := range strings.Split(pattern, "*") {
|
for i, part := range strings.Split(pattern, "*") {
|
||||||
// Add a regexp match all without slashes for each wildcard character
|
// Add a regexp match all without slashes for each wildcard character
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
result.WriteString("[^/]*")
|
result.WriteString("([^/]*)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quote other parts of the pattern
|
// Quote other parts of the pattern
|
||||||
|
@@ -406,6 +406,16 @@ imgproxy can process files from OpenStack Object Storage, but this feature is di
|
|||||||
|
|
||||||
Check out the [Serving files from OpenStack Object Storage](serving_files_from_openstack_swift.md) guide to learn more.
|
Check out the [Serving files from OpenStack Object Storage](serving_files_from_openstack_swift.md) guide to learn more.
|
||||||
|
|
||||||
|
## Source image URLs
|
||||||
|
|
||||||
|
* `IMGPROXY_BASE_URL`: a base URL prefix that will be added to each source image URL. For example, if the base URL is `http://example.com/images` and `/path/to/image.png` is requested, imgproxy will download the source image from `http://example.com/images/path/to/image.png`. If the image URL already contains the prefix, it won't be added. Default: blank
|
||||||
|
|
||||||
|
* `IMGPROXY_URL_REPLACEMENTS`: a list of `pattern=replacement` pairs, semicolon (`;`) divided. imgproxy will replace source URL prefixes matching the pattern with the corresponding replacement. Wildcards can be included in patterns with `*` to match all characters except `/`. `${N}` in replacement strings will be replaced with wildcard values, where `N` is the number of the wildcard. Examples:
|
||||||
|
* `mys3://=s3://my_bucket/images/` will replace `mys3://image01.jpg` with `s3://my_bucket/images/image01.jpg`
|
||||||
|
* `mys3://*/=s3://my_bucket/${1}/images` will replace `mys3://items/image01.jpg` with `s3://my_bucket/items/images/image01.jpg`
|
||||||
|
|
||||||
|
**📝 Note:** Replacements defined in `IMGPROXY_URL_REPLACEMENTS` are applied before `IMGPROXY_BASE_URL` is added.
|
||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
|
|
||||||
### New Relic :id=new-relic-metrics
|
### New Relic :id=new-relic-metrics
|
||||||
@@ -527,7 +537,6 @@ imgproxy can send logs to syslog, but this feature is disabled by default. To en
|
|||||||
|
|
||||||
## Miscellaneous
|
## Miscellaneous
|
||||||
|
|
||||||
* `IMGPROXY_BASE_URL`: a base URL prefix that will be added to each requested image URL. For example, if the base URL is `http://example.com/images` and `/path/to/image.png` is requested, imgproxy will download the source image from `http://example.com/images/path/to/image.png`. If the image URL already contains the prefix, it won't be added. Default: blank
|
|
||||||
* `IMGPROXY_USE_LINEAR_COLORSPACE`: when `true`, imgproxy will process images in linear colorspace. This will slow down processing. Note that images won't be fully processed in linear colorspace while shrink-on-load is enabled (see below).
|
* `IMGPROXY_USE_LINEAR_COLORSPACE`: when `true`, imgproxy will process images in linear colorspace. This will slow down processing. Note that images won't be fully processed in linear colorspace while shrink-on-load is enabled (see below).
|
||||||
* `IMGPROXY_DISABLE_SHRINK_ON_LOAD`: when `true`, disables shrink-on-load for JPEGs and WebP files. Allows processing the entire image in linear colorspace but dramatically slows down resizing and increases memory usage when working with large images.
|
* `IMGPROXY_DISABLE_SHRINK_ON_LOAD`: when `true`, disables shrink-on-load for JPEGs and WebP files. Allows processing the entire image in linear colorspace but dramatically slows down resizing and increases memory usage when working with large images.
|
||||||
* `IMGPROXY_STRIP_METADATA`: when `true`, imgproxy will strip all metadata (EXIF, IPTC, etc.) from JPEG and WebP output images. Default: `true`
|
* `IMGPROXY_STRIP_METADATA`: when `true`, imgproxy will strip all metadata (EXIF, IPTC, etc.) from JPEG and WebP output images. Default: `true`
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -54,6 +55,20 @@ func (s *ProcessingOptionsTestSuite) TestParseBase64URLWithBase() {
|
|||||||
require.Equal(s.T(), imagetype.PNG, po.Format)
|
require.Equal(s.T(), imagetype.PNG, po.Format)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingOptionsTestSuite) TestParseBase64URLWithReplacement() {
|
||||||
|
config.URLReplacements = map[*regexp.Regexp]string{
|
||||||
|
regexp.MustCompile("^test://([^/]*)/"): "http://images.dev/${1}/dolor/",
|
||||||
|
}
|
||||||
|
|
||||||
|
originURL := "test://lorem/ipsum.jpg?param=value"
|
||||||
|
path := fmt.Sprintf("/size:100:100/%s.png", base64.RawURLEncoding.EncodeToString([]byte(originURL)))
|
||||||
|
po, imageURL, err := ParsePath(path, make(http.Header))
|
||||||
|
|
||||||
|
require.Nil(s.T(), err)
|
||||||
|
require.Equal(s.T(), "http://images.dev/lorem/dolor/ipsum.jpg?param=value", imageURL)
|
||||||
|
require.Equal(s.T(), imagetype.PNG, po.Format)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ProcessingOptionsTestSuite) TestParsePlainURL() {
|
func (s *ProcessingOptionsTestSuite) TestParsePlainURL() {
|
||||||
originURL := "http://images.dev/lorem/ipsum.jpg"
|
originURL := "http://images.dev/lorem/ipsum.jpg"
|
||||||
path := fmt.Sprintf("/size:100:100/plain/%s@png", originURL)
|
path := fmt.Sprintf("/size:100:100/plain/%s@png", originURL)
|
||||||
@@ -96,6 +111,20 @@ func (s *ProcessingOptionsTestSuite) TestParsePlainURLWithBase() {
|
|||||||
require.Equal(s.T(), imagetype.PNG, po.Format)
|
require.Equal(s.T(), imagetype.PNG, po.Format)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingOptionsTestSuite) TestParsePlainURLWithReplacement() {
|
||||||
|
config.URLReplacements = map[*regexp.Regexp]string{
|
||||||
|
regexp.MustCompile("^test://([^/]*)/"): "http://images.dev/${1}/dolor/",
|
||||||
|
}
|
||||||
|
|
||||||
|
originURL := "test://lorem/ipsum.jpg"
|
||||||
|
path := fmt.Sprintf("/size:100:100/plain/%s@png", originURL)
|
||||||
|
po, imageURL, err := ParsePath(path, make(http.Header))
|
||||||
|
|
||||||
|
require.Nil(s.T(), err)
|
||||||
|
require.Equal(s.T(), "http://images.dev/lorem/dolor/ipsum.jpg", imageURL)
|
||||||
|
require.Equal(s.T(), imagetype.PNG, po.Format)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ProcessingOptionsTestSuite) TestParsePlainURLEscapedWithBase() {
|
func (s *ProcessingOptionsTestSuite) TestParsePlainURLEscapedWithBase() {
|
||||||
config.BaseURL = "http://images.dev/"
|
config.BaseURL = "http://images.dev/"
|
||||||
|
|
||||||
|
@@ -12,7 +12,11 @@ import (
|
|||||||
|
|
||||||
const urlTokenPlain = "plain"
|
const urlTokenPlain = "plain"
|
||||||
|
|
||||||
func addBaseURL(u string) string {
|
func preprocessURL(u string) string {
|
||||||
|
for re, repl := range config.URLReplacements {
|
||||||
|
u = re.ReplaceAllString(u, repl)
|
||||||
|
}
|
||||||
|
|
||||||
if len(config.BaseURL) == 0 || strings.HasPrefix(u, config.BaseURL) {
|
if len(config.BaseURL) == 0 || strings.HasPrefix(u, config.BaseURL) {
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
@@ -43,7 +47,7 @@ func decodeBase64URL(parts []string) (string, string, error) {
|
|||||||
return "", "", fmt.Errorf("Invalid url encoding: %s", encoded)
|
return "", "", fmt.Errorf("Invalid url encoding: %s", encoded)
|
||||||
}
|
}
|
||||||
|
|
||||||
return addBaseURL(string(imageURL)), format, nil
|
return preprocessURL(string(imageURL)), format, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodePlainURL(parts []string) (string, string, error) {
|
func decodePlainURL(parts []string) (string, string, error) {
|
||||||
@@ -69,7 +73,7 @@ func decodePlainURL(parts []string) (string, string, error) {
|
|||||||
return "", "", fmt.Errorf("Invalid url encoding: %s", encoded)
|
return "", "", fmt.Errorf("Invalid url encoding: %s", encoded)
|
||||||
}
|
}
|
||||||
|
|
||||||
return addBaseURL(unescaped), format, nil
|
return preprocessURL(unescaped), format, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeURL(parts []string) (string, string, error) {
|
func DecodeURL(parts []string) (string, string, error) {
|
||||||
|
Reference in New Issue
Block a user