Add ParseImagePath for chi wildcard and upstream fetcher with SSRF protection

This commit is contained in:
2026-01-08 02:59:48 -08:00
parent c69ddf6f61
commit 018c280267
3 changed files with 430 additions and 5 deletions

View File

@@ -38,12 +38,24 @@ type ParsedURL struct {
Format ImageFormat
}
// ParseImageURL parses a URL path like /v1/image/<host>/<path>/<size>.<format>
// ParseImagePath parses the path captured by chi's wildcard: <host>/<path>/<size>.<format>
// This is the primary entry point when using chi routing.
// Examples:
// - /v1/image/cdn.example.com/photos/cat.jpg/800x600.webp
// - /v1/image/cdn.example.com/photos/cat.jpg/0x0.jpeg
// - /v1/image/cdn.example.com/photos/cat.jpg/orig.png
// - /v1/image/cdn.example.com/photos/cat.jpg?q=1/800x600.webp
// - cdn.example.com/photos/cat.jpg/800x600.webp
// - cdn.example.com/photos/cat.jpg/0x0.jpeg
// - cdn.example.com/photos/cat.jpg/orig.png
func ParseImagePath(path string) (*ParsedURL, error) {
// Strip leading slash if present (chi may include it)
path = strings.TrimPrefix(path, "/")
if path == "" {
return nil, ErrMissingHost
}
return parseImageComponents(path)
}
// ParseImageURL parses a full URL path like /v1/image/<host>/<path>/<size>.<format>
// Use ParseImagePath instead when working with chi's wildcard capture.
func ParseImageURL(urlPath string) (*ParsedURL, error) {
// Remove the /v1/image/ prefix
const prefix = "/v1/image/"
@@ -56,6 +68,11 @@ func ParseImageURL(urlPath string) (*ParsedURL, error) {
return nil, ErrMissingHost
}
return parseImageComponents(remainder)
}
// parseImageComponents parses <host>/<path>/<size>.<format> structure.
func parseImageComponents(remainder string) (*ParsedURL, error) {
// Find the last path segment which contains size.format
lastSlash := strings.LastIndex(remainder, "/")
if lastSlash == -1 {