check / check (push) Waiting to run
The fetcher accepts image/svg+xml; internal/magic detects SVG. orig of an SVG at the orig size is the SVG unchanged, cached, with a Content-Security-Policy allowing only its styles and data: images; at another size, ErrSVGNotOriginalSize (400). Any other format renders it at the least size covering the output, at most 8192 on a side, so it stays sharp. Rendering refuses an SVG with a side over 8192 times the other (ErrSVGTooThin, 415), and the orig size of one above 8192 on a side (ErrSVGTooLargeForOrigSize, 400). The cache reads up to 1024 first bytes to find a file's format. Tests pinning the SVG refusal now expect SVG. Render time and memory are unbounded: P1 in TODO.md until the owner decides on #68. Model: opus-5-5
95 lines
3.1 KiB
Go
95 lines
3.1 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"sneak.berlin/go/pixa/internal/httpfetcher"
|
|
"sneak.berlin/go/pixa/internal/imageprocessor"
|
|
"sneak.berlin/go/pixa/internal/imagerequest"
|
|
)
|
|
|
|
// TestUnsupportedSourceFormatAnswers415 checks that respondImageError, which
|
|
// answers the errors of both image routes, answers 415 with a clear error when
|
|
// the upstream answers with a content type pixa does not accept, such as TIFF,
|
|
// and when libvips does not read a source as the format its first bytes
|
|
// show, wrapped as the service wraps them.
|
|
func TestUnsupportedSourceFormatAnswers415(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
h := &Handlers{log: slog.New(slog.DiscardHandler)}
|
|
req := &imagerequest.Request{
|
|
Source: imagerequest.Source{Host: "img.example.com", Path: "/a.tiff"},
|
|
}
|
|
|
|
for _, err := range []error{
|
|
fmt.Errorf("upstream fetch failed: %w: image/tiff",
|
|
httpfetcher.ErrInvalidContentType),
|
|
fmt.Errorf("image processing failed: %w: libvips does not read the input as avif",
|
|
imageprocessor.ErrUnsupportedInputFormat),
|
|
} {
|
|
rec := httptest.NewRecorder()
|
|
h.respondImageError(rec, req, err)
|
|
t.Logf("for %v: %d %s", err, rec.Code, rec.Body.String())
|
|
|
|
if rec.Code != http.StatusUnsupportedMediaType {
|
|
t.Errorf("for %v: status = %d, want %d",
|
|
err, rec.Code, http.StatusUnsupportedMediaType)
|
|
}
|
|
|
|
if !strings.Contains(rec.Body.String(), "unsupported source format") {
|
|
t.Errorf("for %v: body = %q, want the unsupported source format error",
|
|
err, rec.Body.String())
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestSVGTooThinAnswers415 checks that respondImageError answers 415 with a
|
|
// clear error for an SVG source too thin to render, wrapped as the service
|
|
// wraps it.
|
|
func TestSVGTooThinAnswers415(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
h := &Handlers{log: slog.New(slog.DiscardHandler)}
|
|
req := &imagerequest.Request{
|
|
Source: imagerequest.Source{Host: "svg.example.com", Path: "/a.svg"},
|
|
}
|
|
err := fmt.Errorf("image processing failed: %w: 81930x10",
|
|
imageprocessor.ErrSVGTooThin)
|
|
|
|
rec := httptest.NewRecorder()
|
|
h.respondImageError(rec, req, err)
|
|
t.Logf("for %v: %d %s", err, rec.Code, rec.Body.String())
|
|
|
|
if rec.Code != http.StatusUnsupportedMediaType {
|
|
t.Errorf("status = %d, want %d", rec.Code,
|
|
http.StatusUnsupportedMediaType)
|
|
}
|
|
|
|
if !strings.Contains(rec.Body.String(), "SVG source too thin to render") {
|
|
t.Errorf("body = %q, want the SVG too thin error", rec.Body.String())
|
|
}
|
|
}
|
|
|
|
// TestSVGTooLargeForOrigSizeAnswers400 checks that respondImageError answers
|
|
// 400, asking for a size, for an SVG source above 8192 on a side asked for at
|
|
// the orig size in a raster format, wrapped as the service wraps it.
|
|
func TestSVGTooLargeForOrigSizeAnswers400(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
h := &Handlers{log: slog.New(slog.DiscardHandler)}
|
|
err := fmt.Errorf("image processing failed: %w: 10000x10 is above 8192",
|
|
imageprocessor.ErrSVGTooLargeForOrigSize)
|
|
|
|
rec := httptest.NewRecorder()
|
|
h.respondImageError(rec, &imagerequest.Request{}, err)
|
|
t.Logf("for %v: %d %s", err, rec.Code, rec.Body.String())
|
|
|
|
checkErrorBody(t, rec, http.StatusBadRequest,
|
|
"SVG source above 8192 on a side: give a size to render it at")
|
|
}
|