Refuse, before decoding, input libvips would not load as a source format
check / check (push) Waiting to run

govips picks the libvips loader for the input with DetermineImageType.
The image processor now names the format from that type before decoding,
and refuses with ErrUnsupportedInputFormat, answered 415, any input it
cannot name as one of the six source formats. An SVG whose first bytes
pass the first-bytes check for AVIF therefore never reaches librsvg.
orig is the format named there. README.md and TODO.md say so.

Model: opus-5-5
This commit is contained in:
2026-10-13 03:20:52 +00:00
parent d67b6d5051
commit 6241c6a425
3 changed files with 32 additions and 26 deletions
+17 -16
View File
@@ -137,9 +137,8 @@ var ErrInputDataTooLarge = errors.New("input data exceeds maximum allowed size")
// not supported.
var ErrUnsupportedOutputFormat = errors.New("unsupported output format")
// ErrUnsupportedInputFormat is returned when the requested format is orig and
// the input is in a format the processor cannot name, so it cannot be saved
// in that format.
// ErrUnsupportedInputFormat is returned, before the input is decoded, when
// libvips would not load it as one of the source formats.
var ErrUnsupportedInputFormat = errors.New("unsupported input format")
// ErrTooManyImages is returned when MaxConcurrentProcessing images are being
@@ -224,6 +223,16 @@ func (p *ImageProcessor) Process(
return nil, ErrInputDataTooLarge
}
// govips picks the libvips loader with DetermineImageType. Input it
// would not load as a source format, such as SVG, which librsvg would
// render, is refused before libvips reads it.
inputFormat := p.detectFormat(vips.DetermineImageType(data))
sourceFormat, err := p.formatFromString(inputFormat)
if err != nil {
return nil, err
}
// Decode image
img, err := vips.NewImageFromBuffer(data)
if err != nil {
@@ -242,9 +251,6 @@ func (p *ImageProcessor) Process(
origWidth := img.Width()
origHeight := img.Height()
// Detect input format
inputFormat := p.detectFormat(img)
// Validate input dimensions to prevent DoS via decompression bombs
if origWidth > MaxInputDimension || origHeight > MaxInputDimension {
return nil, ErrInputTooLarge
@@ -261,14 +267,10 @@ func (p *ImageProcessor) Process(
}
}
// orig is the source's own format, and an error when the processor
// cannot name it; encode refuses an empty format
// orig is the source's own format; encode refuses an empty format
outputFormat := req.Format
if outputFormat == FormatOriginal {
outputFormat, err = p.formatFromString(inputFormat)
if err != nil {
return nil, err
}
outputFormat = sourceFormat
}
// Encode to target format
@@ -412,10 +414,9 @@ func (p *ImageProcessor) acquireSlot(ctx context.Context) (func(), error) {
}
}
// detectFormat returns the format string from a vips image.
func (p *ImageProcessor) detectFormat(img *vips.ImageRef) string {
format := img.Format()
switch format {
// detectFormat returns the format string for a govips image type.
func (p *ImageProcessor) detectFormat(imageType vips.ImageType) string {
switch imageType {
case vips.ImageTypeJPEG:
return "jpeg"
case vips.ImageTypePNG: