The new package internal/imagerequest holds the request type, its two parts Source and Transform, the Format and Fit types, the dimension and fit checks, the /v1/image/ path parsing and the variant key; it imports no other package of pixa. imgcache.ParsedURL, imgcache.ImageRequest, signature.Request, imageprocessor.Request, the second Size, format and fit types and the conversions between them are gone. The image processor takes a Transform only. encurl keeps a private struct with the token's short CBOR field names. VariantKey moves with the function that makes it. Tests follow the moved and renamed code; the tests of the removed conversions go with them. Model: opus-5-5
This commit was merged in pull request #323.
This commit is contained in:
+19
-21
@@ -13,6 +13,7 @@ import (
|
||||
"sneak.berlin/go/pixa/internal/encurl"
|
||||
"sneak.berlin/go/pixa/internal/httpfetcher"
|
||||
"sneak.berlin/go/pixa/internal/imageprocessor"
|
||||
"sneak.berlin/go/pixa/internal/imagerequest"
|
||||
"sneak.berlin/go/pixa/internal/imgcache"
|
||||
"sneak.berlin/go/pixa/internal/magic"
|
||||
)
|
||||
@@ -35,8 +36,8 @@ func (s *Handlers) HandleImage() http.HandlerFunc {
|
||||
err := s.imgSvc.ValidateRequest(req)
|
||||
if err != nil {
|
||||
s.log.Warn("signature validation failed",
|
||||
"host", req.SourceHost,
|
||||
"path", req.SourcePath,
|
||||
"host", req.Source.Host,
|
||||
"path", req.Source.Path,
|
||||
"error", err,
|
||||
)
|
||||
s.respondError(w, "unauthorized", http.StatusUnauthorized)
|
||||
@@ -50,7 +51,7 @@ func (s *Handlers) HandleImage() http.HandlerFunc {
|
||||
}
|
||||
|
||||
// Get cache key for logging
|
||||
cacheKey := imgcache.CacheKey(req)
|
||||
cacheKey := imagerequest.CacheKey(req)
|
||||
|
||||
// Get the image (from cache or fetch/process)
|
||||
startTime := time.Now()
|
||||
@@ -81,17 +82,17 @@ func (s *Handlers) HandleRobotsTxt() http.HandlerFunc {
|
||||
}
|
||||
|
||||
// parseImageRequest parses the image URL's path and query parameters into
|
||||
// an ImageRequest. On invalid input it writes an error response and
|
||||
// an image request. On invalid input it writes an error response and
|
||||
// returns false.
|
||||
func (s *Handlers) parseImageRequest(
|
||||
w http.ResponseWriter, r *http.Request,
|
||||
) (*imgcache.ImageRequest, bool) {
|
||||
) (*imagerequest.Request, bool) {
|
||||
// The path is parsed decoded once, as r.URL.Path holds it, and not from
|
||||
// chi's wildcard: chi routes on the path as the client wrote it whenever
|
||||
// that is not Go's own encoding of it, so its wildcard would still hold
|
||||
// the %3F before a source query when, say, a "/" in the query is written
|
||||
// as %2F
|
||||
parsed, err := imgcache.ParseImageURL(r.URL.Path)
|
||||
req, err := imagerequest.ParseImageURL(r.URL.Path)
|
||||
if err != nil {
|
||||
s.log.Warn("failed to parse image URL",
|
||||
"path", r.URL.Path,
|
||||
@@ -102,9 +103,6 @@ func (s *Handlers) parseImageRequest(
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Convert to ImageRequest
|
||||
req := parsed.ToImageRequest()
|
||||
|
||||
// Parse signature params from query string. r.URL.Query() would silently
|
||||
// drop a pair it cannot decode, such as q=80%, so that q would be served
|
||||
// at 85; a query string that cannot be decoded is refused instead. A
|
||||
@@ -148,7 +146,7 @@ func (s *Handlers) parseImageRequest(
|
||||
return nil, false
|
||||
}
|
||||
|
||||
req.Quality, err = parseFormInt(query, "q",
|
||||
req.Transform.Quality, err = parseFormInt(query, "q",
|
||||
encurl.DefaultQuality, minQuality, maxQuality)
|
||||
if err != nil {
|
||||
s.respondError(w, fmt.Sprintf("%v, got %q", err, qStr),
|
||||
@@ -160,23 +158,23 @@ func (s *Handlers) parseImageRequest(
|
||||
// Only a fit missing from the URL is cover. A fit in the URL that is not a
|
||||
// fit mode is refused by the fit-mode check below; that check would take an
|
||||
// empty fit as missing, so an empty one is refused here.
|
||||
req.FitMode = imgcache.FitMode(query.Get("fit"))
|
||||
if query.Has("fit") && req.FitMode == "" {
|
||||
req.Transform.FitMode = imagerequest.Fit(query.Get("fit"))
|
||||
if query.Has("fit") && req.Transform.FitMode == "" {
|
||||
s.respondError(w, `invalid fit: not a fit mode, got ""`, http.StatusBadRequest)
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Default fit mode if not set
|
||||
if req.FitMode == "" {
|
||||
req.FitMode = imgcache.FitCover
|
||||
if req.Transform.FitMode == "" {
|
||||
req.Transform.FitMode = imagerequest.FitCover
|
||||
}
|
||||
|
||||
// Enforce dimension and fit-mode bounds, shared with the encrypted-URL
|
||||
// route. Dimensions are already bounded by the path parser above; this
|
||||
// also rejects an unrecognized fit mode with 400 instead of letting it
|
||||
// reach the processor as a 500.
|
||||
err = imgcache.ValidateImageRequest(req)
|
||||
err = imagerequest.ValidateImageRequest(req)
|
||||
if err != nil {
|
||||
s.respondError(w, "invalid image request: "+err.Error(),
|
||||
http.StatusBadRequest)
|
||||
@@ -219,7 +217,7 @@ func (s *Handlers) HandleTooManyRequests() http.HandlerFunc {
|
||||
|
||||
// respondImageError maps image retrieval errors to HTTP responses.
|
||||
func (s *Handlers) respondImageError(
|
||||
w http.ResponseWriter, req *imgcache.ImageRequest, err error,
|
||||
w http.ResponseWriter, req *imagerequest.Request, err error,
|
||||
) {
|
||||
// An upstream body whose first bytes are not those of the format its
|
||||
// Content-Type names is the upstream's error, not pixa's: the image
|
||||
@@ -234,8 +232,8 @@ func (s *Handlers) respondImageError(
|
||||
}
|
||||
|
||||
s.log.Error("failed to get image",
|
||||
"host", req.SourceHost,
|
||||
"path", req.SourcePath,
|
||||
"host", req.Source.Host,
|
||||
"path", req.Source.Path,
|
||||
"error", err,
|
||||
)
|
||||
|
||||
@@ -346,8 +344,8 @@ func notModified(w http.ResponseWriter, r *http.Request, etag string) bool {
|
||||
// handling conditional and HEAD requests.
|
||||
func (s *Handlers) writeImageResponse(
|
||||
w http.ResponseWriter, r *http.Request,
|
||||
req *imgcache.ImageRequest, resp *imgcache.ImageResponse,
|
||||
cacheKey imgcache.VariantKey, startTime time.Time,
|
||||
req *imagerequest.Request, resp *imgcache.ImageResponse,
|
||||
cacheKey imagerequest.VariantKey, startTime time.Time,
|
||||
) {
|
||||
// Set response headers
|
||||
w.Header().Set("Content-Type", resp.ContentType)
|
||||
@@ -388,7 +386,7 @@ func (s *Handlers) writeImageResponse(
|
||||
"cache_key", cacheKey,
|
||||
"cache_status", resp.CacheStatus,
|
||||
"duration_ms", duration.Milliseconds(),
|
||||
"format", req.Format,
|
||||
"format", req.Transform.Format,
|
||||
"served_bytes", servedBytes,
|
||||
"fetched_bytes", resp.FetchedBytes,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user