Documentation
¶
Overview ¶
Package files makes placeholders for uploaded files, so that a copy of an application's storage carries none of the original content. A placeholder has the same name, the same type (detected from the content, not from the extension) and the same dimensions or page sizes, with neutral content: a flat grey image, blank pages, an empty document.
What is read from the original is only the structure the placeholder needs, listed per type on Placeholder; no byte of the original content is copied into the output. The output is deterministic: the same input gives the same bytes (no timestamps, fixed encoder settings).
Index ¶
Constants ¶
const ( PNG = "png" JPEG = "jpeg" GIF = "gif" WebP = "webp" SVG = "svg" PDF = "pdf" DOCX = "docx" XLSX = "xlsx" PPTX = "pptx" ODT = "odt" ODS = "ods" ODP = "odp" Zip = "zip" JSON = "json" CSV = "csv" XML = "xml" HTML = "html" Text = "text" Binary = "binary" Empty = "empty" )
Kinds of file.
const ( DefaultMaxSize = 256 << 20 // bytes of the original DefaultMaxPixels = 1 << 28 // width × height of an image )
Limits.
Variables ¶
var ErrTooLarge = errors.New("over the size limit")
ErrTooLarge means a file is over a limit; no placeholder is written.
Functions ¶
This section is empty.
Types ¶
type Info ¶
type Info struct {
Kind string `json:"kind"`
MediaType string `json:"media_type"`
Size int64 `json:"size"` // of the original
Width int `json:"width,omitempty"` // images; SVG only when given in pixels
Height int `json:"height,omitempty"` // images; SVG only when given in pixels
Pages int `json:"pages,omitempty"` // PDF
// Fallback says why the placeholder has the right type but not the
// original's dimensions or pages (a header that could not be read).
Fallback string `json:"fallback,omitempty"`
}
Info describes a placeholder; it never holds content of the original.
func Placeholder ¶
func Placeholder(ctx context.Context, r io.ReaderAt, size int64, name string, dst io.Writer, opt Options) (info Info, err error)
Placeholder writes the placeholder of an original of the given size and file name to dst. The name is used only for its extension, to tell text formats apart (CSV, JSON); binary formats are known by their content.
What is read from the original, per kind:
- PNG: the IHDR width and height (bytes 16–23).
- JPEG: the marker segment headers up to the first SOFn, and its width and height; segment contents (EXIF, ICC, comments) are skipped by length, not read.
- GIF: the logical screen width and height (bytes 6–9).
- WebP: the first chunk header and the width and height of its VP8, VP8L or VP8X header.
- SVG: the width, height and viewBox attributes of the root element, kept only when they are plain numbers (with a unit) and written anew.
- PDF: the object structure (dictionaries, arrays, numbers, names and references, from object streams too); strings and content streams are skipped. Of that, only the page tree is used: the page count and each page's MediaBox, CropBox and Rotate. A file broken so that reading it would take more than a few passes over its bytes gets a single page.
- ZIP (and OOXML, ODF): the entry names of the central directory and the content of a short "mimetype" entry, to tell the document type.
- Text: the first 8 KiB, to tell it is text; the first character (JSON object or array); for CSV the delimiter count of the first line.
- Anything else: the first bytes, to tell it is none of the above.
A crafted file that makes a reader fail in an unforeseen way (a panic) is an error, as an unreadable file is; the run goes on.
type Options ¶
type Options struct {
MaxSize int64 // larger originals are refused with ErrTooLarge
MaxPixels int64 // images with more pixels are refused with ErrTooLarge
}
Options limit the work done for one file. Zero values take the defaults.
type Skipped ¶
type Skipped struct {
Path string `json:"path"`
Reason string `json:"reason"` // "too large", "unreadable", "not a regular file"
}
Skipped is a file or directory that has no placeholder in the copy.
type Summary ¶
type Summary struct {
Files int `json:"files"` // placeholders written
Dirs int `json:"dirs"`
Kinds map[string]int `json:"kinds"` // placeholders per kind
Fallback []string `json:"fallback,omitempty"` // placeholders of the right type without the original's dimensions
Symlinks []string `json:"symlinks,omitempty"` // not followed, not copied
Skipped []Skipped `json:"skipped,omitempty"` // not copied
Bytes int64 `json:"bytes"` // of the originals that were replaced
}
Summary describes a copied tree: counts and relative paths, never content. The paths are the original names, which the copy keeps anyway.
func CopyTree ¶
CopyTree copies the tree at src to dst, which must not exist or be empty, with a placeholder for every regular file under the same relative path. Symbolic links are not followed and not copied; files over the limits and files or directories that cannot be read are left out. All of them are listed in the summary. The tree is walked in lexical order, so the summary is the same on every run.