mimetype/accept
RFC 9110 §12.5 content negotiation: parser and selector for the
Accept, Accept-Encoding, Accept-Charset, and Accept-Language
header families.
The module exposes:
parse/1— turn a rawAcceptheader into a list ofAcceptItemvalues, preserving the client’s q-values and any accept-ext parameters (RFC 9110 §12.5.1).prefer/1— stable-sort parsed items by(q desc, specificity desc, accept-ext count desc)so callers can iterate in the order the client most prefers.negotiate/2— given a parsed client header and a list of server offers, return the bestMimeTypeto serve, orNonewhen no offer is acceptable. Implements the §12.5.1 proactive-negotiation algorithm with the documented essence-only matching restriction.parse_encoding/1,parse_charset/1,parse_language/1and their companionprefer_values/1/negotiate_value/2.
Types
Why a header could not be parsed.
pub type AcceptError {
Malformed(at: Int, raw: String)
InvalidQValue(raw: String)
InvalidMediaRange(raw: String)
}
Constructors
-
Malformed(at: Int, raw: String)An entry did not match the expected
media-range[;params]shape.atis the zero-based entry index;rawis the raw entry text. -
InvalidQValue(raw: String)An entry’s q-value was syntactically invalid.
-
InvalidMediaRange(raw: String)A media-range field was not a wildcard, a
type/*form, or a validtype/subtypeper RFC 6838.
One parsed entry from an Accept header. q defaults to 1.0 if
the wire form omits it; extensions holds the accept-ext name/value
pairs that appeared after the q= parameter, with names
lowercased and values preserved.
pub type AcceptItem {
AcceptItem(
range: MediaRange,
q: Float,
extensions: List(#(String, String)),
)
}
Constructors
-
AcceptItem( range: MediaRange, q: Float, extensions: List(#(String, String)), )
A single media-range entry as it appears on the wire.
Specific(mt)matches a concretetype/subtype. Parameter-level “more-specific” matching per RFC 9110 §12.5.1 is out of scope: matching looks at the essence only and ignores attached media-range parameters (other thanqand accept-ext, which are carried onAcceptItem).TypeWildcard(type_)matches any subtype within a top-level type (e.g.image/*). The carriedtype_is already lowercased.AnyTypematches any media range (*/*).
pub type MediaRange {
Specific(mimetype.MimeType)
TypeWildcard(type_: String)
AnyType
}
Constructors
-
Specific(mimetype.MimeType) -
TypeWildcard(type_: String) -
AnyType
Values
pub fn negotiate(
client_accepts client: List(AcceptItem),
server_offers offers: List(mimetype.MimeType),
) -> option.Option(mimetype.MimeType)
Pick the best server offer for a parsed Accept header. Returns
None when no offer is acceptable (e.g. every match has q=0, or
server_offers is empty).
Special case: if every client item is AnyType with q>0, the
server’s first offer wins (server preference). Otherwise we score
each server offer by the best matching client item — (q, specificity, ext_count) — and break ties by the order the offer
appears in server_offers.
Matching is essence-only: parameter-level “more-specific” matching per RFC 9110 §12.5.1 is out of scope.
pub fn negotiate_value(
client_accepts client: List(ValueItem),
server_offers offers: List(String),
) -> option.Option(String)
Pick the best server offer for an Accept-Encoding /
Accept-Charset / Accept-Language header. The * wildcard
matches any value not already named explicitly; entries with q=0
are excluded.
pub fn parse(
header: String,
) -> Result(List(AcceptItem), AcceptError)
Parse an Accept header into a list of AcceptItem values in the
order they appeared on the wire. Use prefer/1 afterwards to sort
by preference.
Whitespace tolerance: empty entries ("a, , b") and surrounding
whitespace on each entry / parameter are accepted per RFC 9110
§5.6.3.
pub fn parse_charset(
header: String,
) -> Result(List(ValueItem), AcceptError)
Parse an Accept-Charset header.
pub fn parse_encoding(
header: String,
) -> Result(List(ValueItem), AcceptError)
Parse an Accept-Encoding header.
pub fn parse_language(
header: String,
) -> Result(List(ValueItem), AcceptError)
Parse an Accept-Language header.
pub fn prefer(items: List(AcceptItem)) -> List(AcceptItem)
Stable-sort parsed AcceptItems by client preference:
- q-value descending,
- specificity descending (concrete >
type/*>*/*), - accept-ext count descending (RFC 9110 §12.5.1 tie-breaker).