check / check (push) Waiting to run
The image request now holds only its source and its transform, exactly what the variant key covers. The /v1/image/ handler checks the allowlist and verifies the signature itself with Signer.Verify(req, sig, expires). Both image handlers keep the URL's expiry as a local value for Cache-Control. The image service holds no signer, allowlist or AllowHTTP, and ValidateRequest is gone. The fetcher takes the source and builds its URL with Source.URL from its own AllowHTTP, so no URL string is built and parsed again. chooseAutoFormat returns the format it chooses instead of writing into the request. The signed URL format and every route's answers are unchanged. Model: opus-5-5
96 lines
2.6 KiB
Go
96 lines
2.6 KiB
Go
package server
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"sneak.berlin/go/pixa/internal/encurl"
|
|
"sneak.berlin/go/pixa/internal/imagerequest"
|
|
)
|
|
|
|
// TestImageProxyRefusesFitOutsideAboveMaximum requests sizes with fit=outside
|
|
// through both image routes. fit=outside scales the source to cover the size,
|
|
// and so past it on one side: a size for which that side would be above 8192
|
|
// is refused with 400 and the JSON error body, whether it is the width or the
|
|
// height, and a size for which it stays within 8192 is served at the scaled
|
|
// size.
|
|
func TestImageProxyRefusesFitOutsideAboveMaximum(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// The upstream paths of the sources
|
|
const (
|
|
widePath = "/wide.png"
|
|
rowPath = "/row.png"
|
|
columnPath = "/column.png"
|
|
)
|
|
|
|
sources := map[string][]byte{
|
|
widePath: encodeTestPNG(t, 3000, 600),
|
|
rowPath: encodeTestPNG(t, 8192, 1),
|
|
columnPath: encodeTestPNG(t, 1, 8192),
|
|
}
|
|
|
|
upstream := httptest.NewServer(http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "image/png")
|
|
_, _ = w.Write(sources[r.URL.Path])
|
|
}))
|
|
t.Cleanup(upstream.Close)
|
|
|
|
s, _, _ := startImageProxy(t, upstream)
|
|
|
|
generator, err := encurl.NewGenerator(testSigningKey)
|
|
if err != nil {
|
|
t.Fatalf("encurl.NewGenerator: %v", err)
|
|
}
|
|
|
|
tests := []struct {
|
|
path string
|
|
width, height int
|
|
// wantWidth and wantHeight are the served image's, 0 for a refusal
|
|
wantWidth, wantHeight int
|
|
}{
|
|
{widePath, 1, 8192, 0, 0},
|
|
{rowPath, 1, 8192, 0, 0},
|
|
{columnPath, 8192, 1, 0, 0},
|
|
{widePath, 1, 1200, 6000, 1200},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
token, err := generator.Generate(&imagerequest.Request{
|
|
Source: imagerequest.Source{Host: upstreamHost, Path: tt.path},
|
|
Transform: imagerequest.Transform{
|
|
Size: imagerequest.Size{Width: tt.width, Height: tt.height},
|
|
Format: imagerequest.FormatJPEG,
|
|
FitMode: imagerequest.FitOutside,
|
|
},
|
|
}, time.Time{})
|
|
if err != nil {
|
|
t.Fatalf("encurl Generate: %v", err)
|
|
}
|
|
|
|
size := fmt.Sprintf("%dx%d", tt.width, tt.height)
|
|
|
|
for _, target := range []string{
|
|
"/v1/image/" + upstreamHost + tt.path + "/" + size +
|
|
".jpeg?fit=outside",
|
|
"/v1/e/" + token + "/img.jpg",
|
|
} {
|
|
rec := httptest.NewRecorder()
|
|
s.ServeHTTP(rec, httptest.NewRequestWithContext(
|
|
t.Context(), http.MethodGet, target, nil))
|
|
t.Logf("GET %s: %d, Content-Type %s",
|
|
target, rec.Code, rec.Header().Get("Content-Type"))
|
|
|
|
if tt.wantWidth == 0 {
|
|
checkSizeRefused(t, rec)
|
|
} else {
|
|
checkServedSize(t, rec, tt.wantWidth, tt.wantHeight)
|
|
}
|
|
}
|
|
}
|
|
}
|