check / check (push) Canceled after 0s
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
76 lines
2.4 KiB
Go
76 lines
2.4 KiB
Go
package server
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"sneak.berlin/go/pixa/internal/encurl"
|
|
"sneak.berlin/go/pixa/internal/imagerequest"
|
|
)
|
|
|
|
// svgServedAsAVIF is an SVG whose first bytes pass the first-bytes check for
|
|
// AVIF: its XML comment puts "ftypavis" at bytes 4 to 11, where an AVIF file
|
|
// has its ftyp box and brand. libvips would load it as SVG.
|
|
const svgServedAsAVIF = `<!--ftypavis--><svg xmlns="http://www.w3.org/2000/svg" ` +
|
|
`width="64" height="48"><rect width="64" height="48"/></svg>`
|
|
|
|
// TestImageProxyRefusesSVGServedAsAVIF requests svgServedAsAVIF, which the
|
|
// upstream answers as image/avif, through both image routes, resized as PNG
|
|
// and in its own format (orig). Each request is answered 415, as for an SVG
|
|
// source, never with an image.
|
|
func TestImageProxyRefusesSVGServedAsAVIF(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
upstream := httptest.NewServer(http.HandlerFunc(
|
|
func(w http.ResponseWriter, _ *http.Request) {
|
|
w.Header().Set("Content-Type", "image/avif")
|
|
_, _ = io.WriteString(w, svgServedAsAVIF)
|
|
}))
|
|
t.Cleanup(upstream.Close)
|
|
|
|
s, _, _ := startImageProxy(t, upstream)
|
|
|
|
generator, err := encurl.NewGenerator(testSigningKey)
|
|
if err != nil {
|
|
t.Fatalf("encurl.NewGenerator: %v", err)
|
|
}
|
|
|
|
encryptedURL := func(format imagerequest.Format) string {
|
|
token, err := generator.Generate(&imagerequest.Request{
|
|
Source: imagerequest.Source{Host: upstreamHost, Path: "/drawing.avif"},
|
|
Transform: imagerequest.Transform{
|
|
Size: imagerequest.Size{Width: 32, Height: 24},
|
|
Format: format,
|
|
},
|
|
}, time.Time{})
|
|
if err != nil {
|
|
t.Fatalf("encurl Generate: %v", err)
|
|
}
|
|
|
|
return "/v1/e/" + token + "/drawing." + string(format)
|
|
}
|
|
|
|
for _, target := range []string{
|
|
"/v1/image/" + upstreamHost + "/drawing.avif/32x24.png",
|
|
"/v1/image/" + upstreamHost + "/drawing.avif/64x48.orig",
|
|
encryptedURL(imagerequest.FormatPNG),
|
|
encryptedURL(imagerequest.FormatOriginal),
|
|
} {
|
|
rec := httptest.NewRecorder()
|
|
s.ServeHTTP(rec, httptest.NewRequestWithContext(
|
|
t.Context(), http.MethodGet, target, nil))
|
|
t.Logf("GET %s: %d, Content-Type %s, body %q",
|
|
target, rec.Code, rec.Header().Get("Content-Type"), rec.Body.String())
|
|
|
|
if rec.Code != http.StatusUnsupportedMediaType ||
|
|
!strings.Contains(rec.Body.String(), "unsupported source format") {
|
|
t.Errorf("GET %s: %d %q, want %d unsupported source format",
|
|
target, rec.Code, rec.Body.String(), http.StatusUnsupportedMediaType)
|
|
}
|
|
}
|
|
}
|