Skip to main content

Crate parse_net

Crate parse_net 

Source
Expand description

§parse_net

The grammar layer for Internet message fields: RFC 9110 field syntax, media types, RFC 9651 Structured Field Values, HTTP and RFC 5322 dates, content negotiation, entity tags, ranges, Content-Disposition with RFC 8187, Cache-Control, Link, Forwarded, authentication challenges, Host, Origin, and the email lexical layer, with safe writers for each.

Protocol engines (http-net, ws-net, h2-net) frame messages; parse-net reads what is inside a field value and writes field values back out without ever emitting CR, LF, or NUL. It is no_std, needs no allocator for any parse, does no I/O, and has no dependencies.

§Tier 1

The convention in every example is use parse_net as pn;. One plain call per field:

use parse_net as pn;

// Media types: one strict view, no copy.
let mt = pn::parse_media_type(b"text/html; charset=UTF-8")?;
assert!(mt.essence_is("text/html"));
assert!(mt.charset().is_some_and(|c| c.eq_ignore_ascii_case(b"utf-8")));

// Lists: commas inside quoted strings and comments do not split.
let codings: Vec<&[u8]> = pn::list(b"gzip, deflate;q=0.5, x=\"a,b\"")?.iter().collect();
assert_eq!(codings, [&b"gzip"[..], b"deflate;q=0.5", b"x=\"a,b\""]);

// HTTP-date: all three formats in, IMF-fixdate out.
let now = 1_792_540_800; // the caller's clock, Unix seconds
let d = pn::http_date_at(b"Sunday, 06-Nov-94 08:49:37 GMT", now)?;
assert_eq!(&d.format(), b"Sun, 06 Nov 1994 08:49:37 GMT");

// Host: real IPv4 and IPv6 validation, ports up to 65535.
let hp = pn::parse_host_port(b"[2001:db8::1]:8443")?;
assert_eq!(hp.port, Some(8443));
assert!(pn::parse_host_port(b"127.1").is_err()); // read as IPv4 by browsers: refused

// Writers cannot emit CR, LF, or NUL.
let mut buf = [0u8; 64];
let mut out = pn::SliceSink::new(&mut buf);
pn::media::write("text", "plain", &[("charset", "utf-8")], &mut out)?;
assert_eq!(out.written(), b"text/plain; charset=utf-8");
assert!(pn::write::write_field_value(b"x\r\nSet-Cookie: y", &mut out).is_err());

Errors carry a kind and an offset, never input bytes:

use parse_net as pn;

let err = pn::parse_media_type(b"text/ html").unwrap_err();
assert_eq!(err.kind(), pn::ErrorKind::InvalidMediaType);
assert_eq!(err.to_string(), "invalid media type at offset 5");

The rest of Tier 1 arrives with 0.4.0 and 0.5.0 (see the roadmap):

pn::best_media(accept, &["text/html", "application/json"])    // Option<usize>
pn::if_none_match(if_none_match, &current_etag)?              // bool: answer 304
pn::byte_ranges(range, file_len, &mut buf)?                   // RangeOutcome
pn::parse_content_disposition(value)?.filename()              // prefers filename*
pn::response_cache_control(value)?                            // ResponseDirectives
pn::client_address(peer, pn::ForwardedSource::XForwardedFor(&lines), &trusted, 16)?
pn::sfv::parse_item(b"same-origin")?                          // Sec-Fetch-Site
pn::bearer(authorization)?                                    // Option<&[u8]>

§Status

Hardened, 0.7.0: every planned field, measured against the Rust crates that do the same work (docs/PERFORMANCE.md), every threat tested, and every fuzz target run for 24 hours (docs/SECURITY.md). The public API is written down in docs/API.md, each field’s grammar in docs/GRAMMAR.md, the design in dev/PLAN.md, and the milestone schedule in dev/ROADMAP.md (all in the repository).

Re-exports§

pub use auth::AuthPayload;
pub use auth::Challenge;
pub use auth::Credentials;
pub use auth::basic;
pub use auth::bearer;
pub use cache::Directive;
pub use cache::RequestDirectives;
pub use cache::ResponseDirectives;
pub use cache::request_cache_control;
pub use cache::response_cache_control;
pub use date::http_date;std
pub use date::Civil;
pub use date::DateFormat;
pub use date::HttpDate;
pub use date::MailDate;
pub use date::http_date_at;
pub use disposition::ContentDisposition;
pub use disposition::DispositionType;
pub use disposition::Filename;
pub use disposition::parse_content_disposition;
pub use disposition::write_attachment;
pub use etag::Condition;
pub use etag::EntityTag;
pub use etag::TagList;
pub use etag::if_match;
pub use etag::if_none_match;
pub use etag::parse_condition;
pub use ext_value::Charset;
pub use ext_value::ExtValue;
pub use ext_value::write_ext_value;
pub use forwarded::ClientAddress;
pub use forwarded::ForwardedSource;
pub use forwarded::Trust;
pub use forwarded::client_address;
pub use host::Host;
pub use host::HostPort;
pub use host::parse_host_port;
pub use link::LinkValue;
pub use list::List;
pub use list::list;
pub use media::Boundary;
pub use media::MediaRange;
pub use media::MediaType;
pub use media::parse_media_type;
pub use negotiate::QValue;
pub use negotiate::best_charset;
pub use negotiate::best_encoding;
pub use negotiate::best_language;
pub use negotiate::best_media;
pub use origin::Origin;
pub use origin::OriginValue;
pub use origin::parse_origin;
pub use param::Param;
pub use param::Params;
pub use range::ByteRange;
pub use range::ContentRange;
pub use range::IfRange;
pub use range::RangeHeader;
pub use range::RangeOutcome;
pub use range::RangeSpec;
pub use range::byte_ranges;
pub use text::Comment;
pub use text::Quoted;
pub use text::Word;
pub use write::CountSink;
pub use write::Sink;
pub use write::SliceSink;

Modules§

auth
Authorization, Proxy-Authorization, WWW-Authenticate, and Proxy-Authenticate (RFC 9110 section 11), with the Bearer (RFC 6750) and Basic (RFC 7617) payloads.
cache
Cache-Control (RFC 9111 section 5.2, with immutable from RFC 8246 and stale-while-revalidate and stale-if-error from RFC 5861).
class
The byte classes of the ABNF, in one table.
date
The proleptic Gregorian calendar and HTTP-date (RFC 9110 section 5.6.7).
disposition
Content-Disposition (RFC 6266, and its use in multipart/form-data part headers, RFC 7578 section 4.2).
etag
Entity tags and the If-Match / If-None-Match conditions (RFC 9110 sections 8.8.3 and 13.1).
ext_value
RFC 8187 extended parameter values: charset "'" [ language ] "'" value-chars, as in filename* and title*.
forwarded
Forwarded (RFC 7239) and the de facto X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host, with client-address resolution through trusted proxies.
host
Host = uri-host [ ":" port ] (RFC 9110 section 7.2, citing RFC 3986 section 3.2.2), with real IPv4 and IPv6 validation.
link
Link (RFC 8288 section 3): #link-value, where link-value = "<" URI-Reference ">" *( OWS ";" OWS link-param ) and link-param = token BWS [ "=" BWS ( token / quoted-string ) ].
list
The #rule lists of RFC 9110 section 5.6.1, including several field lines read as one list (section 5.3).
mail
The email lexical layer (RFC 5322, RFC 2045, RFC 2047, RFC 2231): header lines and folding, encoded words, MIME parameters with continuations, addresses, and message identifiers. The grammar smtp-net needs to write mail and gate-net needs to validate login addresses (D-008); not a mail parser. Charsets decoded: UTF-8, US-ASCII, ISO-8859-1.
media
Media types: type "/" subtype parameters (RFC 9110 section 8.3.1), and the RFC 2046 multipart boundary.
negotiate
Content negotiation: quality values and the selection of the best offer for Accept, Accept-Language, Accept-Encoding, and Accept-Charset (RFC 9110 section 12, RFC 4647).
num
Decimal digits with overflow checks.
origin
Origin (RFC 6454 section 7): null or scheme "://" host [ ":" port ].
param
Parameters: *( OWS ";" OWS [ parameter ] ) (RFC 9110 section 5.6.6).
pct
The percent-encoding primitive: validate, decode into a caller buffer, and encode with a named set and hex case.
range
Range, Content-Range, and If-Range (RFC 9110 section 14), with resolution against a representation length and budgets against abusive range sets.
scan
Byte search and field-value validation, eight bytes per step.
sfv
Structured Field Values (RFC 9651): Items, Lists, and Dictionaries with every bare item type, parsed into borrowed views.
text
The lexical forms of RFC 9110 section 5.6: tokens, optional whitespace, quoted strings, words (token / quoted-string), and comments.
write
Output: the Sink trait, SliceSink, CountSink, and the writers for numbers, tokens, quoted strings, parameters, and field values.

Structs§

Full
A sink has no room for the bytes it was given.
Limits
The work and size bounds every parser enforces.
OwnedEntityTagalloc
An owned EntityTag.
OwnedHostPortalloc
An owned HostPort.
OwnedMediaTypealloc
An owned MediaType.
ParseError
Why a value was refused, and where.

Enums§

DuplicatePolicy
What a parameter parser does when a name repeats.
ErrorKind
What a parser refused.
WriteError
Why a writer refused.

Constants§

VERSION
Crate version string, populated by Cargo at build time.