1 Commits
Author SHA1 Message Date
sneak 5a2aa94691 Remove the code nothing in production calls (closes #312)
check / check (push) Waiting to run
Service.Warm, the ImageCache interface, both GenerateSignedURL methods,
signature.ParseParams, imagerequest.ParseImagePath, four symbols of
internal/magic, the image processor's lists of supported formats,
IsEmpty and Count of the allowlist, ssrfSafeDialer, CacheStale,
ErrCacheMiss, ErrNegativeCache, ImageResponse.LastModified and the Load
methods of ContentStorage and VariantStorage had no caller outside
tests. They are gone, with the tests that tested only them.

The handlers tests sign their image URLs with generateSignedURL, a test
helper that builds the URL as the removed generator did. The SSRF dialer
tests call dialSSRFSafe with no operator blocklist, which is all
ssrfSafeDialer did. The tests of ParseImagePath and ContentStorage.Load
call ParseImageURL and LoadWithSize instead. MIMEToImageFormat,
ContentStorage.Store and CleanExpired stay, as pixa calls them.

Model: opus-5-5
2026-10-26 09:40:35 +00:00
7 changed files with 34 additions and 157 deletions
+4 -3
View File
@@ -36,15 +36,16 @@ P2: security: per-origin rate limiting
- `Service.Warm` and the `ImageCache` interface - `Service.Warm` and the `ImageCache` interface
- `Service.GenerateSignedURL` and `Signer.GenerateSignedURL` - `Service.GenerateSignedURL` and `Signer.GenerateSignedURL`
- `signature.ParseParams` - `signature.ParseParams`
- `PeekAndValidate`, `IsSupportedMIMEType` and `ImageFormatToMIME` of - `imagerequest.ParseImagePath`
`internal/magic` - `PeekAndValidate`, `IsSupportedMIMEType`, `ImageFormatToMIME` and
`FormatOriginal` of `internal/magic`
- `SupportedInputFormats` and `SupportedOutputFormats` of the image - `SupportedInputFormats` and `SupportedOutputFormats` of the image
processor processor
- `IsEmpty` and `Count` of the allowlist - `IsEmpty` and `Count` of the allowlist
- `ssrfSafeDialer` - `ssrfSafeDialer`
- `CacheStale`, `ErrCacheMiss`, `ErrNegativeCache` and - `CacheStale`, `ErrCacheMiss`, `ErrNegativeCache` and
`ImageResponse.LastModified` `ImageResponse.LastModified`
- `VariantStorage.Load` - `ContentStorage.Load` and `VariantStorage.Load`
- 2026-10-26 cache hits, misses, upstream fetches, the bytes those fetches read - 2026-10-26 cache hits, misses, upstream fetches, the bytes those fetches read
and transforms are counted as Prometheus counters in memory (closes #311). and transforms are counted as Prometheus counters in memory (closes #311).
They are `pixa_cache_hits_total`, `pixa_cache_misses_total`, They are `pixa_cache_hits_total`, `pixa_cache_misses_total`,
-17
View File
@@ -66,23 +66,6 @@ var queryEscapeRegex = regexp.MustCompile(`%[0-9A-Fa-f]{2}|[^!-~]|["#'<>%]`)
var hostRegex = regexp.MustCompile( var hostRegex = regexp.MustCompile(
`^(?:[A-Za-z0-9_.-]+|\[([0-9A-Fa-f:.]+)\])(?::[0-9]*)?$`) `^(?:[A-Za-z0-9_.-]+|\[([0-9A-Fa-f:.]+)\])(?::[0-9]*)?$`)
// ParseImagePath parses an image URL's path after /v1/image/, decoded once:
// <host>/<path>/<size>.<format>, or <host>/<path>/<size> for JPEG XL.
// Examples:
// - cdn.example.com/photos/cat.jpg/800x600.webp
// - cdn.example.com/photos/cat.jpg/0x0.jpeg
// - cdn.example.com/photos/cat.jpg/orig.png
// - cdn.example.com/photos/cat.jpg/800x600
func ParseImagePath(path string) (*Request, error) {
// Strip leading slash if present (chi may include it)
path = strings.TrimPrefix(path, "/")
if path == "" {
return nil, ErrMissingHost
}
return parseImageComponents(path)
}
// ParseImageURL parses an image URL's path, decoded once as r.URL.Path holds // ParseImageURL parses an image URL's path, decoded once as r.URL.Path holds
// it: /v1/image/<host>/<path>/<size>.<format>, or /v1/image/<host>/<path>/<size> // it: /v1/image/<host>/<path>/<size>.<format>, or /v1/image/<host>/<path>/<size>
// for JPEG XL. A source query follows the source path after a "?", which the // for JPEG XL. A source query follows the source path after a "?", which the
+15 -105
View File
@@ -192,76 +192,16 @@ func TestParseImageURL_Errors(t *testing.T) {
} }
} }
func TestParseImagePath(t *testing.T) { // TestParseImageURL_LowerCasesHost verifies that the host is lower-cased, so
t.Parallel()
// ParseImagePath is for chi wildcard capture (no /v1/image/ prefix)
tests := []struct {
name string
input string
want *Request
wantErr bool
}{
{
name: "chi wildcard capture",
input: "cdn.example.com/photos/cat.jpg/800x600.webp",
want: &Request{
Source: Source{
Host: testHostCDN,
Path: testPathCat,
},
Transform: Transform{
Size: Size{Width: 800, Height: 600},
Format: FormatWebP,
},
},
},
{
name: "with leading slash from chi",
input: "/cdn.example.com/photos/cat.jpg/800x600.webp",
want: &Request{
Source: Source{
Host: testHostCDN,
Path: testPathCat,
},
Transform: Transform{
Size: Size{Width: 800, Height: 600},
Format: FormatWebP,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := ParseImagePath(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("ParseImagePath() error = %v, wantErr %v", err, tt.wantErr)
return
}
if err != nil {
return
}
assertRequest(t, got, tt.want)
})
}
}
// TestParseImagePath_LowerCasesHost verifies that the host is lower-cased, so
// that every spelling of its letter case is the same host to the allowlist, // that every spelling of its letter case is the same host to the allowlist,
// the upstream connection limits and the cache, and that the path keeps its // the upstream connection limits and the cache, and that the path keeps its
// case. // case.
func TestParseImagePath_LowerCasesHost(t *testing.T) { func TestParseImageURL_LowerCasesHost(t *testing.T) {
t.Parallel() t.Parallel()
got, err := ParseImagePath("CDN.Example.COM/Photos/Cat.jpg/800x600.webp") got, err := ParseImageURL("/v1/image/CDN.Example.COM/Photos/Cat.jpg/800x600.webp")
if err != nil { if err != nil {
t.Fatalf("ParseImagePath() error = %v", err) t.Fatalf("ParseImageURL() error = %v", err)
} }
t.Logf("parsed host %q, path %q", got.Source.Host, got.Source.Path) t.Logf("parsed host %q, path %q", got.Source.Host, got.Source.Path)
@@ -275,21 +215,21 @@ func TestParseImagePath_LowerCasesHost(t *testing.T) {
} }
} }
// TestParseImagePath_RefusesUserinfo verifies that a host holding "@" is // TestParseImageURL_RefusesUserinfo verifies that a host holding "@" is
// refused: a URL reads what comes before the "@" as a user name and password // refused: a URL reads what comes before the "@" as a user name and password
// and the rest as the host. // and the rest as the host.
func TestParseImagePath_RefusesUserinfo(t *testing.T) { func TestParseImageURL_RefusesUserinfo(t *testing.T) {
t.Parallel() t.Parallel()
for _, input := range []string{ for _, input := range []string{
"user@cdn.example.com/photos/cat.jpg/800x600.webp", "/v1/image/user@cdn.example.com/photos/cat.jpg/800x600.webp",
"user:password@cdn.example.com/photos/cat.jpg/800x600.webp", "/v1/image/user:password@cdn.example.com/photos/cat.jpg/800x600.webp",
} { } {
got, err := ParseImagePath(input) got, err := ParseImageURL(input)
t.Logf("ParseImagePath(%q) = %+v, error = %v", input, got, err) t.Logf("ParseImageURL(%q) = %+v, error = %v", input, got, err)
if !errors.Is(err, ErrInvalidHost) { if !errors.Is(err, ErrInvalidHost) {
t.Errorf("ParseImagePath(%q) error = %v, want %v", t.Errorf("ParseImageURL(%q) error = %v, want %v",
input, err, ErrInvalidHost) input, err, ErrInvalidHost)
} }
} }
@@ -315,6 +255,10 @@ func TestParseImageURL_PathTraversal(t *testing.T) {
name: "parent in middle of path", name: "parent in middle of path",
input: "/v1/image/cdn.example.com/photos/../../../etc/passwd/800x600.jpeg", input: "/v1/image/cdn.example.com/photos/../../../etc/passwd/800x600.jpeg",
}, },
{
name: "parent directory in path",
input: "/v1/image/cdn.example.com/photos/../secret/800x600.jpeg",
},
{ {
name: "encoded parent directory", name: "encoded parent directory",
input: "/v1/image/cdn.example.com/photos/%2e%2e/secret/800x600.jpeg", input: "/v1/image/cdn.example.com/photos/%2e%2e/secret/800x600.jpeg",
@@ -357,40 +301,6 @@ func TestParseImageURL_PathTraversal(t *testing.T) {
} }
} }
func TestParseImagePath_PathTraversal(t *testing.T) {
t.Parallel()
// Test path traversal via ParseImagePath (chi wildcard)
tests := []struct {
name string
input string
}{
{
name: "parent directory in path",
input: "cdn.example.com/photos/../secret/800x600.jpeg",
},
{
name: "encoded traversal",
input: "cdn.example.com/photos/%2e%2e/secret/800x600.jpeg",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, err := ParseImagePath(tt.input)
if err == nil {
t.Error("ParseImagePath() should reject path traversal attempts")
}
if !errors.Is(err, ErrPathTraversal) {
t.Errorf("ParseImagePath() error = %v, want ErrPathTraversal", err)
}
})
}
}
// TestParseImageURL_SourceURLHoldingPercent25 verifies that a source path and // TestParseImageURL_SourceURLHoldingPercent25 verifies that a source path and
// a source query holding %25, the percent-escape of a literal "%", are // a source query holding %25, the percent-escape of a literal "%", are
// accepted as they are, although decoding them once more leaves a "%" that // accepted as they are, although decoding them once more leaves a "%" that
@@ -290,9 +290,9 @@ func TestContentStorage_StoreReplacesFileOfAnotherSize(t *testing.T) {
t.Fatalf("Store() error = %v", err) t.Fatalf("Store() error = %v", err)
} }
stored, err := storage.Load(key) stored, _, err := storage.LoadWithSize(key)
if err != nil { if err != nil {
t.Fatalf("Load() error = %v", err) t.Fatalf("LoadWithSize() error = %v", err)
} }
defer func() { _ = stored.Close() }() defer func() { _ = stored.Close() }()
-16
View File
@@ -62,22 +62,6 @@ func (s *ContentStorage) Store(
return int64(len(data)), nil return int64(len(data)), nil
} }
// Load returns a reader for the content with the given key.
func (s *ContentStorage) Load(key imagerequest.SourceKey) (io.ReadCloser, error) {
path := s.keyToPath(key)
f, err := os.Open(path) //nolint:gosec // path derived from source key
if err != nil {
if os.IsNotExist(err) {
return nil, ErrNotFound
}
return nil, fmt.Errorf("failed to open content: %w", err)
}
return f, nil
}
// LoadWithSize returns a reader and file size for the content with the given key. // LoadWithSize returns a reader and file size for the content with the given key.
func (s *ContentStorage) LoadWithSize( func (s *ContentStorage) LoadWithSize(
key imagerequest.SourceKey, key imagerequest.SourceKey,
+7 -7
View File
@@ -11,7 +11,7 @@ import (
"sneak.berlin/go/pixa/internal/imagerequest" "sneak.berlin/go/pixa/internal/imagerequest"
) )
func TestContentStorage_StoreAndLoad(t *testing.T) { func TestContentStorage_StoreAndLoadWithSize(t *testing.T) {
t.Parallel() t.Parallel()
tmpDir := t.TempDir() tmpDir := t.TempDir()
@@ -44,9 +44,9 @@ func TestContentStorage_StoreAndLoad(t *testing.T) {
} }
// Load and verify content // Load and verify content
r, err := storage.Load(key) r, _, err := storage.LoadWithSize(key)
if err != nil { if err != nil {
t.Fatalf("Load() error = %v", err) t.Fatalf("LoadWithSize() error = %v", err)
} }
defer func() { _ = r.Close() }() defer func() { _ = r.Close() }()
@@ -57,11 +57,11 @@ func TestContentStorage_StoreAndLoad(t *testing.T) {
} }
if !bytes.Equal(loaded, content) { if !bytes.Equal(loaded, content) {
t.Errorf("Load() content = %q, want %q", loaded, content) t.Errorf("LoadWithSize() content = %q, want %q", loaded, content)
} }
} }
func TestContentStorage_LoadNotFound(t *testing.T) { func TestContentStorage_LoadWithSizeNotFound(t *testing.T) {
t.Parallel() t.Parallel()
tmpDir := t.TempDir() tmpDir := t.TempDir()
@@ -71,9 +71,9 @@ func TestContentStorage_LoadNotFound(t *testing.T) {
t.Fatalf("NewContentStorage() error = %v", err) t.Fatalf("NewContentStorage() error = %v", err)
} }
_, err = storage.Load(imagerequest.SourceKey("nonexistent")) _, _, err = storage.LoadWithSize(imagerequest.SourceKey("nonexistent"))
if !errors.Is(err, ErrNotFound) { if !errors.Is(err, ErrNotFound) {
t.Errorf("Load() error = %v, want ErrNotFound", err) t.Errorf("LoadWithSize() error = %v, want ErrNotFound", err)
} }
} }
+6 -7
View File
@@ -35,13 +35,12 @@ type ImageFormat string
// Supported image output formats. // Supported image output formats.
const ( const (
FormatOriginal ImageFormat = "orig" FormatJPEG ImageFormat = "jpeg"
FormatJPEG ImageFormat = "jpeg" FormatPNG ImageFormat = "png"
FormatPNG ImageFormat = "png" FormatWebP ImageFormat = "webp"
FormatWebP ImageFormat = "webp" FormatAVIF ImageFormat = "avif"
FormatAVIF ImageFormat = "avif" FormatJXL ImageFormat = "jxl"
FormatJXL ImageFormat = "jxl" FormatGIF ImageFormat = "gif"
FormatGIF ImageFormat = "gif"
) )
// MinMagicBytes is the minimum number of bytes needed to detect format. // MinMagicBytes is the minimum number of bytes needed to detect format.