Skip to content

proposal: image: support decoder instance with specific formats #20814

@epelc

Description

@epelc

Today canonical way to register formats for the image package is to import a package which calls image.RegisterFormat. This is simple and works fine for small programs however when your programs start to grow there is no way to ensure that the image.Decode function will only attempt to decode a predefined list of formats.

Example scenario

You have a profile picture system which you want to accept jpeg, and png but you also have an admin page which requires reading tiff images. The tiff image package is still experimental and you would prefer not to expose it to external users who just need to upload a profile picture in common formats.

Right now the only way to prevent your profile picture upload handler from using the tiff package is to reimplement a large part of https://golang.org/src/image/format.go. The only other option is to write separate programs which may or may not make sense or be easy depending on your ops.

In short this is a security(limiting exposure to certain image decoders) and developer usability issue.

Required additions/API

The required additions aren't very large but the api is important since this will be here for a while(go1 compat). The real issue is not implementing this, it is agreeing upon how this should work and look. The following is a rough outline for what would need to be added.

  • Add a new Decoder type similar to json.Decoder which can accept a list of formats to look for and accept.
  • Make definitions for params commonly passed into image.RegisterFormat publicly available in image decoder packages
    • Maybe make image.format public so that each image decoder package could define

Possible api and usage

// package image
type Decoder struct {
  formats []format
}

func NewDecoder(formats []Format) *Decoder {
 return &Decoder{formats: formats}
}

func (d *Decoder) Decode() {
  // Implement decode using `d.formats`
}

Changes required for image format package(image/png, image/jpeg, etc). Replaces init() with something like this https://golang.org/src/image/png/reader.go#L1017

// package image/png

// Format defines the format for a png image.
// You can use this when creating your own image.Decoder instance.
var Format = image.Format{"png", pngHeader, Decode, DecodeConfig}

func init() {
  // Register Format in the package level decoder so that we keep the go1 compatibility promise
  Format.Register() // calls image.RegisterFormat with `Format` as the data
}

Usage for a user wanting to only use specific formats without relying on all other packages to not import other image format packages which automatically register themselves on the package level decoder.

// package myapp/handlers

func SaveUserUpload(r io.Reader) {
  dec := image.NewDecoder([]image.Format{png.Format, jpeg.Format})
  // Only accepts and looks for `png` and `jpeg`
  dec.Decode(r)
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions