Documentation
¶
Overview ¶
Package contenttype detects and normalizes the media type of stored content.
Every platform write path that accepts content from an outside source (an upstream API response, a multipart upload, a tool argument) reaches this package. A declared type that is specific is always honored; a declared type that is absent or generic is replaced with a type sniffed from the content itself, so a JSON payload an upstream API labeled text/plain still reaches the viewer as application/json.
Detection contract ¶
- A specific declared type wins. Detection only runs when the declaration is empty or generic (see IsGeneric).
- The one exception is a caller that has the filename and uses DetectFile: a declaration both the extension and the content contradict loses to what those two agree on. A .csv uploaded from a machine that declared application/vnd.ms-excel is stored as a CSV.
- Binary families come from http.DetectContentType, which recognizes images, audio, video, PDF and archives from their magic bytes.
- Structured text (JSON, NDJSON, XML, YAML, CSV, TSV) is layered on top, because http.DetectContentType reports every one of them as text/plain.
- Detection reads a bounded prefix, never the whole payload, so streaming writers do not have to buffer.
Active-type rule ¶
Detection never promotes content to an active type (see IsActive). Active types execute script when a viewer renders them, so they render only when an author declared them deliberately. Content that sniffs as HTML but was declared text/plain stays text/plain; content that sniffs as HTML with no declaration at all becomes text/plain. This keeps a mislabeled upload from turning itself into script-bearing content.
Scriptable-document rule ¶
IsActive answers what detection may produce. It does not answer whether stored bytes may render inline on the platform's origin, which is a wider question: XML is safe to name from content and unsafe to render, because a browser navigating to it builds a document that honors an <?xml-stylesheet?> processing instruction. IsScriptableDocument answers that one, over a superset of the active types.
Index ¶
- Constants
- func Detect(declared string, prefix []byte) string
- func DetectBytes(declared string, data []byte) string
- func DetectFile(declared, filename string, prefix []byte) string
- func DetectFileBytes(declared, filename string, data []byte) string
- func DetectStream(declared string, body io.Reader) (string, io.Reader, error)
- func Extension(ct string) string
- func IsActive(ct string) bool
- func IsGeneric(ct string) bool
- func IsImage(ct string) bool
- func IsScriptableDocument(ct string) bool
- func IsStorableText(ct string) bool
- func IsTextual(ct string) bool
- func Normalize(declared string) string
- func StorableTextTypes() []string
- func TypeForFilename(name string) string
- type Family
Constants ¶
const ( // JSON is the canonical type for JSON documents. JSON = "application/json" // NDJSON is the canonical type for newline-delimited JSON. NDJSON = "application/x-ndjson" // CSV is the canonical type for comma-separated values. CSV = "text/csv" // TSV is the canonical type for tab-separated values. TSV = "text/tab-separated-values" // XML is the canonical type for XML documents. XML = "application/xml" // YAML is the canonical type for YAML documents. YAML = "application/yaml" // Markdown is the canonical type for Markdown documents. Markdown = "text/markdown" // PlainText is the canonical type for unstructured text. PlainText = "text/plain" // HTML is the canonical type for HTML documents. Active. HTML = "text/html" // JSX is the canonical type for React/JSX components. Active. JSX = "text/jsx" // SVG is the canonical type for SVG images. Active. SVG = "image/svg+xml" // XHTML is the canonical type for XHTML documents. Active: a browser // renders XHTML natively and runs the script inside it. XHTML = "application/xhtml+xml" // JavaScript is the canonical type for standalone JavaScript source. JavaScript = "text/javascript" // PDF is the canonical type for PDF documents. PDF = "application/pdf" // OctetStream is the type for content of unknown or unrecognized shape. OctetStream = "application/octet-stream" )
Canonical media types. Detection and normalization collapse every alias of a family onto exactly one of these values, so downstream consumers (renderer registry, extension mapping, viewer selection) match on one string per family.
const BinarySniffLen = 512
BinarySniffLen is the prefix length http.DetectContentType examines. Reading more than this for the binary sniff cannot change its answer.
const StructuredSniffLen = 8192
StructuredSniffLen is the prefix length the structured-text heuristics examine. It is large enough to hold several rows of a CSV or the opening tokens of a JSON document while staying cheap for a streaming writer to hold in memory.
Variables ¶
This section is empty.
Functions ¶
func Detect ¶
Detect returns the canonical media type for content whose first bytes are prefix and whose writer declared declared.
A specific declaration is returned unchanged (normalized). A generic or absent declaration is replaced by the type sniffed from prefix, subject to the active-type rule: a sniff that lands on HTML, JSX, SVG or JavaScript is discarded in favor of the declaration (or text/plain when there was none).
prefix should hold at least BinarySniffLen bytes for binary families and up to StructuredSniffLen bytes for the structured-text heuristics; a shorter prefix simply yields a less confident answer.
func DetectBytes ¶
DetectBytes is Detect over a complete payload, truncating to the sniff window.
func DetectFile ¶ added in v1.125.2
DetectFile is Detect for content that arrived under a filename.
A specific declaration still wins, with one exception: when the filename's extension and the content itself both name a different family, that family wins. Neither signal is enough on its own -- a name is not evidence about bytes, and content may not upgrade itself past a declaration -- but a declaration contradicted by both is wrong about what it labels.
This is what makes a .csv usable when the uploading machine declared application/vnd.ms-excel, which is what Windows sends for .csv when Excel is installed. It does not promote a mislabeled binary on the strength of its name: a .csv holding a PNG sniffs as image/png, disagrees with the name, and keeps its declaration.
A filename of "" makes this identical to Detect.
func DetectFileBytes ¶ added in v1.125.2
DetectFileBytes is DetectFile over a complete payload, truncating to the sniff window.
func DetectStream ¶
DetectStream classifies a stream without buffering it. It reads at most StructuredSniffLen bytes to run detection, then returns a reader that replays those bytes ahead of the untouched remainder, so the caller can go on streaming the body to storage.
A read error other than EOF is returned to the caller along with a reader that still replays whatever was consumed, so no bytes are lost.
func Extension ¶
Extension returns the file extension for a media type, including the leading dot. Unrecognized types fall back to ".bin".
func IsActive ¶
IsActive reports whether a media type renders as executable markup or script. Detection never upgrades content into one of these types.
func IsGeneric ¶
IsGeneric reports whether a declared media type is uninformative enough that the content itself should be consulted.
func IsImage ¶ added in v1.126.3
IsImage reports whether a media type names an image family. It is the accept decision for a slot that holds a picture and nothing else -- a brand logo, a thumbnail -- taken over the type this package resolved rather than over a Content-Type header a caller read for itself.
Every image family qualifies, including SVG: a caller that must distinguish vector from raster compares against SVG directly, because the two are inlined differently (markup for one, a data: URI for the other) even though both are images.
func IsScriptableDocument ¶ added in v1.117.0
IsScriptableDocument reports whether a browser navigating to a response of this type builds a document whose render tree the author of the bytes controls. Stored content of such a type must never be served for inline rendering on the platform's origin.
Any `+xml` structured suffix qualifies, so an XML dialect that has no entry in scriptableDocumentTypes is still covered.
func IsStorableText ¶ added in v1.117.0
IsStorableText reports whether a declared media type may be stored by a write path that carries its content as a string.
func IsTextual ¶
IsTextual reports whether a canonical media type holds human-readable text, and so can be loaded into a text editor or embedded in a page as a string.
func Normalize ¶
Normalize reduces a declared media type to its canonical, parameter-free, lowercase form. It returns the empty string when the input is empty or is not a well-formed media type.
func StorableTextTypes ¶ added in v1.117.0
func StorableTextTypes() []string
StorableTextTypes returns the canonical types IsStorableText accepts, sorted, so a rejected write can name what it would have taken instead.
func TypeForFilename ¶ added in v1.125.2
TypeForFilename returns the canonical media type a filename's extension names, or the empty string when the name carries no extension, the extension is unknown, or it names a family detection may not produce on its own.
The answer is a claim about the name, not about the bytes. Nothing decides a stored type on this alone; see DetectFile.
Types ¶
type Family ¶ added in v1.126.4
type Family struct {
// Type is the canonical media type: the one spelling every alias of the
// family normalizes to.
Type string
// Extension is the extension the stored object key carries, leading dot
// included.
Extension string
// Storable reports whether IsStorableText accepts the type.
Storable bool
}
Family is one media type the platform names, with the file extension a stored object of that type carries and whether a write path that receives its content as a string may be told to store it.
func Catalog ¶ added in v1.126.4
func Catalog() []Family
Catalog returns every media type this package names, sorted by type.
It exists so the platform's own documentation of what a caller may declare is generated from the tables that decide it rather than transcribed beside them: a family added to the extension table appears in the documentation on the next build, and a page cannot list a type the code does not handle.
The extension table is the enumeration because it is the widest set with a canonical spelling -- every family the platform detects, stores an object key for, or renders is in it. The storable subset is marked rather than separated so a caller of this decides how to present the difference.