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

Extended, 0.4.0: the core plus the web layer. 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::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 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.
list
The #rule lists of RFC 9110 section 5.6.1, including several field lines read as one list (section 5.3).
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.
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.