check / check (push) Waiting to run
The upstream fetch no longer accepts image/svg+xml, and both image routes answer 415, not 500, for any upstream Content-Type outside the source formats. Before decoding, the image processor names the input's format from govips' DetermineImageType and refuses, with 415, input whose first bytes libvips reads as anything but the six source formats, so an SVG passing the first-bytes check for AVIF never reaches librsvg. orig of such an input is refused instead of being saved as JPEG. README.md drops SVG from the source formats. SVG detection stays in internal/magic, unused on the request path, for #168. An AVIF image sequence (brand avis) answers 415. Model: opus-5-5
72 lines
2.3 KiB
Go
72 lines
2.3 KiB
Go
package server
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"sneak.berlin/go/pixa/internal/encurl"
|
|
"sneak.berlin/go/pixa/internal/imgcache"
|
|
)
|
|
|
|
// 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 imgcache.ImageFormat) string {
|
|
token, err := generator.Generate(&encurl.Payload{
|
|
SourceHost: upstreamHost, SourcePath: "/drawing.avif",
|
|
Width: 32, Height: 24, Format: format,
|
|
})
|
|
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(imgcache.FormatPNG),
|
|
encryptedURL(imgcache.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)
|
|
}
|
|
}
|
|
}
|