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. 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). Child processes of pixad read an SVG's size and render it, killed after 20 seconds and limited to 1 GiB; any failure there is ErrSVGRenderFailed (415). Tests pinning the SVG refusal now expect SVG. Model: opus-5-5
This commit was merged in pull request #351.
This commit is contained in:
1 parent
20874ba2af
commit
c2e32d987b
22 files changed
+1525
-131
No files matched your search
@@ -15,7 +15,7 @@ import (
|
||||
|
||||
// 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 SVG,
|
||||
// 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) {
|
||||
@@ -23,11 +23,11 @@ func TestUnsupportedSourceFormatAnswers415(t *testing.T) {
|
||||
|
||||
h := &Handlers{log: slog.New(slog.DiscardHandler)}
|
||||
req := &imagerequest.Request{
|
||||
Source: imagerequest.Source{Host: "img.example.com", Path: "/a.svg"},
|
||||
Source: imagerequest.Source{Host: "img.example.com", Path: "/a.tiff"},
|
||||
}
|
||||
|
||||
for _, err := range []error{
|
||||
fmt.Errorf("upstream fetch failed: %w: image/svg+xml",
|
||||
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),
|
||||
@@ -47,3 +47,67 @@ func TestUnsupportedSourceFormatAnswers415(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
}
|
||||
|
||||
// TestSVGRenderFailedAnswers415 checks that respondImageError answers 415,
|
||||
// naming the limits, for an SVG source that a child process could not read
|
||||
// or render, wrapped as the service wraps it.
|
||||
func TestSVGRenderFailedAnswers415(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
h := &Handlers{log: slog.New(slog.DiscardHandler)}
|
||||
err := fmt.Errorf("image processing failed: %w: it took more than 20s",
|
||||
imageprocessor.ErrSVGRenderFailed)
|
||||
|
||||
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.StatusUnsupportedMediaType,
|
||||
"SVG source could not be rendered: it is not valid, or it takes more "+
|
||||
"than 20 seconds or 1 GiB of memory to render")
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
Reference in new issue
Block a user