diff --git a/internal/imageprocessor/source_formats_internal_test.go b/internal/imageprocessor/source_formats_internal_test.go new file mode 100644 index 0000000..5f1dbbd --- /dev/null +++ b/internal/imageprocessor/source_formats_internal_test.go @@ -0,0 +1,46 @@ +package imageprocessor + +import ( + "bytes" + "io" + "testing" +) + +// TestImageProcessor_LoadsEachSourceFormat verifies that an image in each of +// the six source formats, saved by the processor itself, is loaded and saved +// again in its own format (orig). +func TestImageProcessor_LoadsEachSourceFormat(t *testing.T) { + t.Parallel() + + proc := New(Params{}) + + for _, format := range []Format{ + FormatJPEG, FormatPNG, FormatGIF, FormatWebP, FormatAVIF, FormatJXL, + } { + saved, err := proc.Process(t.Context(), + bytes.NewReader(createTestPNG(t, 20, 20)), &Request{Format: format}) + if err != nil { + t.Fatalf("saving the test image as %s: %v", format, err) + } + + source, err := io.ReadAll(saved.Content) + if err != nil { + t.Fatalf("reading the %s image: %v", format, err) + } + + result, err := proc.Process(t.Context(), bytes.NewReader(source), + &Request{Format: FormatOriginal}) + if err != nil { + t.Errorf("orig of the %s image: %v", format, err) + + continue + } + + t.Logf("orig of the %s image: %s", format, result.ContentType) + + if result.ContentType != FormatToMIME(format) { + t.Errorf("orig of the %s image is %s, want %s", + format, result.ContentType, FormatToMIME(format)) + } + } +} diff --git a/internal/server/svg_as_avif_internal_test.go b/internal/server/svg_as_avif_internal_test.go new file mode 100644 index 0000000..214ec96 --- /dev/null +++ b/internal/server/svg_as_avif_internal_test.go @@ -0,0 +1,73 @@ +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 = `` + +// 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) + } + + targets := []string{ + "/v1/image/" + upstreamHost + "/drawing.avif/32x24.png", + "/v1/image/" + upstreamHost + "/drawing.avif/64x48.orig", + } + + for _, format := range []imgcache.ImageFormat{ + imgcache.FormatPNG, imgcache.FormatOriginal, + } { + 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) + } + + targets = append(targets, "/v1/e/"+token+"/drawing."+string(format)) + } + + for _, target := range targets { + 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) + } + } +}