Skip to main content

Crate base_message

Crate base_message 

Source
Expand description

The field sections of protocol messages, interpreted into typed structs.

HTTP (RFC 9110 section 6), the Internet Message Format of email (RFC 5322), and MIME parts (RFC 2045) share one message structure: header and trailer sections of named fields, around the content. This crate interprets those sections. Each FieldType says how its instances combine and how one value parses, and #[derive(FieldSection)] generates the interpretation of a whole section, so duplicate singletons, lists with quoted commas, forbidden fields, and unknown fields are handled in one reviewed place rather than by each consumer.

use base_message::{FieldSection, FieldType, FieldValueError, ascii_text, combination::{List, Singleton}};

/// A field type that borrows its value from the input.
struct Host<'a>(&'a str);

impl<'a> FieldType<'a> for Host<'a> {
    type Combination = Singleton;
    fn parse(value: &'a [u8]) -> Result<Self, FieldValueError> {
        ascii_text(value).map(Self)
    }
}

/// A field type that owns its value.
struct Accept(String);

impl FieldType<'_> for Accept {
    type Combination = List;
    fn parse(value: &[u8]) -> Result<Self, FieldValueError> {
        Ok(Self(ascii_text(value)?.to_owned()))
    }
}

#[derive(FieldSection)]
#[fields(forbid("transfer-encoding"))]
struct Request<'a> {
    #[field("host")]
    host: Host<'a>,
    #[field("accept")]
    accept: Vec<Accept>,
}

let fields = [("Host", "example.com"), ("Accept", "text/html, image/*"), ("User-Agent", "curl/8")];
let request = Request::interpret(fields)?;
assert_eq!(request.host.0, "example.com");
assert_eq!(request.accept.len(), 2);

let duplicate = Request::interpret([("Host", "a"), ("Host", "b")]).err().expect("a duplicate host");
assert_eq!(duplicate.to_string(), "duplicate host field at position 1, first at 0");

The crate interprets field sections only. Parsing them from the wire, as well as control data, such as a request line or status, content, framing, and transport, belongs to each protocol’s own crate, which passes the fields it parses as name and value pairs in wire order. The Getting Started guide covers field types and sections, and the Layering guide covers passing fields between layers, trailers, and static tables.

Modules§

combination
How the instances of a field combine, as a type-level marker on each FieldType.

Structs§

FieldError
Why a field section could not be interpreted, naming the field and its position in the original section.
FieldNames
The lowercase field names a section declares and forbids, with those of the sections it flattens, and whether it rejects unknown fields, as a constant.
FieldRef
One field, borrowed, with its position in the original section.
FieldValueError
Why a field value is invalid, as a fixed description. It never includes the value, which may be large or untrusted.
ListElements
The elements of one instance of a list field, as split_list produces them.
OwnedField
One field, owned, with its position in the original section.
OwnedFields
A remainder that owns its fields, for keeping the fields a section does not take beyond the lifetime of the input, in order.
StaticTableEntry
One entry of a protocol’s static table of field names, classified for section S by static_table_entries.

Enums§

Classification
How a name in a protocol’s static table relates to a section.
FieldErrorKind
The kind of FieldError.
FieldName
How a decoder with a static table names one field for section S: by an entry of the table, classified for S, or as text when the name was sent literally.
InvalidValue
What an invalid value means for a section.

Traits§

FieldSection
A field section interpreted into a struct. It is implemented only by #[derive(FieldSection)].
FieldType
One kind of field: how its instances combine, how one value parses, and what an invalid value means.
IntoField
Something section S can interpret as one field.

Functions§

ascii_text
The value as text, when it is visible ASCII, spaces, and tabs, as most field grammars require.
split_list
Split one instance of a list field into its elements, as RFC 9110 section 5.6.1 describes: a comma inside a quoted string does not separate elements, spaces and tabs around each element are removed, and empty elements are skipped.
static_table_entries
Classify each name in a protocol’s static table of lowercase field names, such as HPACK’s or QPACK’s, for section S, at compile time, so a decoder can interpret indexed fields without comparing names.
trim_whitespace
Remove spaces and tabs from both ends, the optional whitespace of RFC 9110 section 5.6.3.

Derive Macros§

FieldSection
Derive the interpretation of a field section from a struct’s declarations.