Malachi. Console. Static
(malachi v0.22.7)
View Source
Serves the console bundle from its manifest (Malachi.Console.Assets), and nothing else.
A request path is percent-decoded segment by segment and looked up in the manifest as an exact key.
It is never joined onto a directory, so there is no path to traverse: a segment that decodes to .,
.. or empty, or to anything holding /, \ or a NUL byte, is refused with 400 before the lookup,
because no manifest key can contain one and a client sending one is not asking for a file.
What a hit gets:
- the representation chosen from
Accept-Encodingby q-value:brorgzipwhen the file shipped that precompressed variant and the client gives it a q above zero (explicitly, or through*), the highest q winning and brotli breaking a tie; otherwise the uncompressed bytes. Compression never happens at request time; ETag(the SHA-256 of that representation),Cache-Control(immutable for a name underassets/whose last segment looks like a build hash,no-cacheotherwise) andVary: Accept-Encodingwhen the file has a variant;- 304 with those same headers and no body when
If-None-Matchmatches, compared weakly as RFC 9110 section 13.1.2 requires: a list,*, andW/validators all count.
A miss outside assets/ whose last segment names no known file type (no extension, or one the MIME
table does not know, as in a topic named orders.v1) and in which no segment starts with a dot is a
route of the single page application, answered with index.html under the same rules. Any other
miss is 404: a missing script must not come back as HTML with a 200, which a browser would try to
execute and report as an opaque syntax error.
Before anything is sent, the file is checked against what was recorded at startup
(Malachi.Console.Assets.unchanged?/1): a file or a directory above it replaced by a symbolic link,
a file rewritten with another size or a newer modification time, and a file removed all answer 404
rather than bytes the ETag does not describe or a file outside the static root. It is a check before
the send, so a rewrite that keeps the size and the modification time, or a swap made between the
check and the send, is not caught.
Range requests are not supported and no Accept-Ranges is sent, which RFC 9110 permits.
Summary
Functions
Picks the representation to send for the Accept-Encoding header values given: the precompressed
variant with the highest q above zero, brotli winning a tie, else identity. Returns the coding
name and its variant.
Whether If-None-Match header values match etag, by the weak comparison RFC 9110 prescribes for
this header: * matches anything, and W/ is ignored on both sides.
Sends one of the endpoint's constant plain text answers, which no cache may keep, and halts. Every answer that is not a file goes through here, so they share one content type and one cache rule, and each body is a literal in its own clause: nothing from the request can reach a response body.
Functions
@spec choose(%{required(String.t()) => Malachi.Console.Assets.variant()}, [String.t()]) :: {String.t(), Malachi.Console.Assets.variant()}
Picks the representation to send for the Accept-Encoding header values given: the precompressed
variant with the highest q above zero, brotli winning a tie, else identity. Returns the coding
name and its variant.
Whether If-None-Match header values match etag, by the weak comparison RFC 9110 prescribes for
this header: * matches anything, and W/ is ignored on both sides.
@spec plain( Plug.Conn.t(), :bad_request | :not_found | :method_not_allowed | :not_built ) :: Plug.Conn.t()
Sends one of the endpoint's constant plain text answers, which no cache may keep, and halts. Every answer that is not a file goes through here, so they share one content type and one cache rule, and each body is a literal in its own clause: nothing from the request can reach a response body.