The type of a file, from its bytes.
The browser's content type is a claim. describe/3 keeps only a type
that the bytes of the file prove, from a short allow-list of passive
types:
- PNG, JPEG, GIF and WebP images, from their signatures, with their
width and height from their headers: a JPEG's turned as its EXIF
orientation says, as browsers draw it. The claim does not matter: a
PNG sent as
text/htmlis a PNG. - PDF, from
%PDF-. - MP4 video (
video/mp4), from itsftypbox with an MP4 brand (isom,mp41,mp42,avc1,M4V, …), and WebM video (video/webm), from its EBML header with thewebmdocument type. A QuickTime (.mov), Matroska (.mkv) or audio-only (M4A) file is not in the list. - ZIP files (
PK\x03\x04): the Office Open XML and OpenDocument types when the browser claims one of them, elseapplication/zip. - The older Office files (the OLE2 signature):
application/msword,application/vnd.ms-excelorapplication/vnd.ms-powerpointwhen the browser claims one of them. text/plain, only when the browser claims it and the start of the file is valid UTF-8 with no NUL byte.
Every other file is application/octet-stream: text/html,
application/xhtml+xml, image/svg+xml, JavaScript, and any type that
is not in the list. Serve such a file as a download; its key ends in
.bin (extension/1).
inline?/1 says which types a browser shows in the page (the images,
PDF and the videos): serve every other with Content-Disposition: attachment, as Storehouse.Local.Plug does.
Summary
Types
What describe/3 finds.
Functions
The type a browser claims for a file, as the checked type it would be
if its bytes prove it: a type of the allow-list, else
application/octet-stream. A file uploaded straight to a store is
stored as this type, and refused when its bytes say otherwise.
Returns the checked content type for a file extension (as extension/1
gives it, and .jpeg), or "application/octet-stream".
Reads the file at path and returns its checked content type, its size
and, for an image, its width and height. claim is the browser's type
("image/png; charset=binary", or nil).
As describe/3, of the start of a file (head, its first
256 KB or all of it, as head_size/0 says) and its size in
bytes: a file that is in a store and not here, uploaded straight to
it.
Returns the file extension of a checked content type. A type that is
not in the allow-list gives ".bin".
How much of the start of a file describe_head/4 reads, in bytes.
The content types of the images: PNG, JPEG, GIF and WebP.
Returns true for a checked type that a browser can show in the page:
the images, PDF and the videos. Serve every other type with
Content-Disposition: attachment.
Every type describe/3 gives, application/octet-stream included.
Types
@type description() :: %{ content_type: String.t(), bytes: non_neg_integer(), width: pos_integer() | nil, height: pos_integer() | nil }
What describe/3 finds.
Functions
The type a browser claims for a file, as the checked type it would be
if its bytes prove it: a type of the allow-list, else
application/octet-stream. A file uploaded straight to a store is
stored as this type, and refused when its bytes say otherwise.
Examples
iex> Storehouse.Check.claimed("image/PNG")
"image/png"
iex> Storehouse.Check.claimed("text/html")
"application/octet-stream"
Returns the checked content type for a file extension (as extension/1
gives it, and .jpeg), or "application/octet-stream".
Examples
iex> Storehouse.Check.content_type(".PDF")
"application/pdf"
iex> Storehouse.Check.content_type(".svg")
"application/octet-stream"
@spec describe(Path.t(), String.t() | nil, keyword()) :: {:ok, description()} | {:error, term()}
Reads the file at path and returns its checked content type, its size
and, for an image, its width and height. claim is the browser's type
("image/png; charset=binary", or nil).
Options
:max_bytes- a larger file gives{:error, :too_large}.:max_pixels- an image of more pixels (width × height) gives{:error, :too_large}: one a browser would struggle to draw.
@spec describe_head(binary(), non_neg_integer(), String.t() | nil, keyword()) :: {:ok, description()} | {:error, term()}
As describe/3, of the start of a file (head, its first
256 KB or all of it, as head_size/0 says) and its size in
bytes: a file that is in a store and not here, uploaded straight to
it.
Returns the file extension of a checked content type. A type that is
not in the allow-list gives ".bin".
Examples
iex> Storehouse.Check.extension("image/jpeg")
".jpg"
iex> Storehouse.Check.extension("text/html")
".bin"
@spec head_size() :: pos_integer()
How much of the start of a file describe_head/4 reads, in bytes.
@spec images() :: [String.t()]
The content types of the images: PNG, JPEG, GIF and WebP.
Returns true for a checked type that a browser can show in the page:
the images, PDF and the videos. Serve every other type with
Content-Disposition: attachment.
Examples
iex> Storehouse.Check.inline?("video/webm")
true
iex> Storehouse.Check.inline?("text/plain")
false
@spec types() :: [String.t()]
Every type describe/3 gives, application/octet-stream included.