Skip to main content

Crate form_net

Crate form_net 

Source
Expand description

§form_net

Parses what a browser sends when a form is submitted: application/x-www-form-urlencoded fields and multipart/form-data uploads. It does no I/O: feed it bytes, get fields and parts.

Every budget (field count, name and value length, part count, part header size, file count and size, total size) is checked before the bytes it governs are buffered. Input that two parsers could read differently is refused with a precise error, never repaired. No error, Debug, or Display output ever contains a field value or a file name.

§Tier 1

// A urlencoded body
let form = form_net::parse_urlencoded(b"email=a%40b.example&remember=on")?;
assert_eq!(form.get("email"), Some("a@b.example"));

// A query string
let query = form_net::parse_query(b"?q=rust+forms&page=2")?;
assert_eq!(query.get("q"), Some("rust forms"));

// Building one
assert_eq!(form_net::serialize_urlencoded([("q", "rust forms")]), "q=rust+forms");

// A buffered multipart body
let body = b"--X\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nHoliday\r\n--X--";
let mp = form_net::parse_multipart(b"multipart/form-data; boundary=X", body)?;
assert_eq!(mp.field("title"), Some("Holiday"));

A typed form, from either encoding:

use form_net::FromForm;

form_net::form! {
    pub struct Login {
        pub email: String,
        pub password: form_net::Secret,
        pub remember: bool,
    }
    ignore = ["csrf_token"];
}

let body = b"email=a%40b.example&password=pw&remember=on&csrf_token=t";
let login = Login::from_body(b"application/x-www-form-urlencoded", body)?;
assert_eq!((login.email.as_str(), login.remember), ("a@b.example", true));

An upload read from any std::io::Read, large files spilled to private temporary files that are deleted on drop (feature fs):

let body = b"--X\r\nContent-Disposition: form-data; name=doc; filename=a.txt\r\n\r\nhello\r\n--X--";
let upload = form_net::read_multipart(b"multipart/form-data; boundary=X", &body[..])?;
assert_eq!(upload.file("doc").map(|f| f.len()), Some(5));

§Tiers 2 and 3

Explicit Limits and Policy per route (parse_urlencoded_with, parse_multipart_with); an Inspector that sees every part head, the first bytes of every file, and every field before anything is stored; a Sink that decides where file bytes go, driven by the Driver; the allocation-free core (raw_pairs, decode_into, encode_into, Boundary, MultipartParser), which builds without alloc.

§Features

FeatureDefaultAdds
(none)the allocation-free core; no_std without alloc
allocowned results, the Tier 1 functions, form!, Driver, MemorySink
stdyesMultipartReader, FormError::Io, FormError::Random; implies alloc
randomthe OS random source; implies std
fsStore, StoredFile, Upload, UploadSession, read_multipart, FileName::sanitized; implies random

The full contract is docs/API.md in the repository. This release (0.4) adds upload storage, inspection hooks, blocking readers, and typed extraction to the 0.3 core; the multipart writer, the shared disk budget, and sweep arrive in 0.5.

Macros§

formalloc
Declares a struct and its FromForm implementation.

Structs§

Boundary
A validated boundary with its delimiter (CRLF "--" boundary, 5 to 74 bytes) and the failure table of the streaming matcher, built once.
ContentType
A part’s declared Content-Type, already checked. A hint: the client chose it.
DiscardSink
A sink that discards file data and reports how many bytes it saw.
Driveralloc
The one streaming implementation of the hook order: parser, inspector, sink, the text buffer, the sniff window, and the empty-file delay.
FileDataalloc
An owned file: its bytes, and the file name and content type the client sent, when they are text. The output of MemorySink and a field type for typed extraction from buffered bodies.
FileName
The client’s file name, with a view for each way a caller might want it.
Formalloc
The owned result of a urlencoded parse: every field, in input order, duplicates kept.
Headers
Every header line of a part, in order, as raw (name, value) bytes with the value trimmed.
Limits
Every budget form-net enforces.
Location
Where an error was found.
MemorySinkalloc
A sink that keeps each file in memory as a FileData.
Multipartalloc
The parts of a buffered multipart body, in body order.
MultipartParser
The sans-IO multipart/form-data parser.
MultipartReaderstd
Reads a multipart body from a blocking reader, one part at a time.
NoInspector
An inspector that accepts everything; it compiles to nothing.
OwnedPartHeadalloc
An owned copy of a PartHead. Its buffer is reused for the next head copied into it, so a driver that keeps one never allocates per part once the buffer has grown to the largest head.
Pairsalloc
The iterator returned by pairs.
Partalloc
One part of a buffered multipart body. Its data borrows the body.
PartHead
The validated header block of one part, borrowed.
PartReaderstd
One part of a MultipartReader: read it like a file.
PartSummary
What one part was.
Policy
The behaviours a route may choose. The defaults are the strict ones; every alternative is named after what it allows.
RawPair
One name=value sequence, undecoded.
RawPairs
The iterator returned by raw_pairs.
Refusal
Why an inspector refused the input: the HTTP status it wants and a stable, machine-readable code for the reason.
Secretalloc
A text field that holds a secret (a password, a token).
Serializeralloc
Appends urlencoded pairs to an existing string, for example a URL that already ends in ?. The first pair is not preceded by &; whatever the string held before is left untouched.
Step
One step of the parser: how many input bytes it consumed, and what happened.
Storefs
Where uploads are kept. Send + Sync; create one per process or per route and share it by reference.
StoreSinkfs
The Sink a Store hands out for one request.
StoreStatsfs
A snapshot of what a store holds, read from atomic counters.
StoredFilefs
One received file, in memory or in a temporary file.
StoredReaderfs
A reader over a StoredFile; Read + Seek with its own position.
TokenField
The anti-forgery token field to capture from a multipart body.
Uploadfs
The result of a completed multipart parse with storage: text fields, owned and wiped on drop, and files.
UploadSessionfs
The push-style form for event-driven servers: hand each body chunk to push as reads complete, then finish.

Enums§

Charset
The charset a part declared.
EmptyFilePolicy
A file input left empty (filename="" and no data).
EncodingError
Bytes that do not decode.
Event
What the parser found.
ExtendedFilenamePolicy
What a filename* parameter (RFC 8187) in a part means. Browsers never send it; RFC 7578 forbids senders from using it.
ExtractError
Why typed extraction failed.
FileNameSource
Where a file name came from.
FileValuealloc
A file field’s value.
FormError
Everything that can go wrong in form-net.
FormKind
Which form encoding a request body uses.
HeaderPolicy
Part headers other than Content-Disposition, Content-Type, and Content-Transfer-Encoding.
Limit
Which budget of Limits was exceeded.
PartKind
Whether a part is a text field or a file.
PercentPolicy
What a % not followed by two hex digits means in urlencoded input.
PolicyRefusal
Well-formed input that a Policy refuses.
Progressalloc
What completed during a Driver::push. Debug shows a field’s name and value length, never the value.
SpillModefs
How spilled files are kept.
StoreErrorfs
What went wrong with storage.
SyntaxError
What part of the grammar the input broke.
TokenPlacement
Where the token field must be.
ValueErroralloc
Why one field’s value did not convert. form! turns it into FormError::Extract with the field’s name.
Verdict
What an inspector says about what it saw.

Constants§

MAX_BOUNDARY_LEN
The longest boundary RFC 2046 allows.
MAX_DELIMITER_LEN
The longest delimiter: CRLF, --, and a 70-byte boundary.
VERSION
Crate version string, populated by Cargo at build time.

Traits§

FormBuilderalloc
What form! generates, and what a hand-written FromForm implementation provides. Reports problems as FormError::Extract { reason, field }.
FromFieldalloc
How one field type takes its values.
FromFormalloc
A struct that can be read from a form. Implemented by form!; every method is provided.
Inspector
Takes part in a parse: called for every part head, the first bytes of every file, every data chunk, every complete text field, every part end, the end of the body, and once on any failure.
Sink
Where file parts go: one part at a time, open, any number of write, then close or abort.

Functions§

decode_into
Decodes one urlencoded component (a name or a value) into out.
encode_into
Encodes one component (a name or a value) without allocating: every byte outside ASCII alphanumerics and *-._ is percent-encoded with uppercase hex, and space is written as +. Runs of bytes that need no escape are written with one write_str.
pairsalloc
Iterates the fields of a urlencoded body lazily, with the default limits. A name or value that needs no decoding is borrowed from the input; others are decoded into a new String (which belongs to the caller and is not wiped: use Form for secret fields). After the first error the iterator returns None.
parse_multipartalloc
Parses a buffered multipart/form-data body with the default limits and policy. Part data borrows the body (zero copy); a name borrows too, except where an HTML escape had to be decoded.
parse_multipart_inspectedalloc
As parse_multipart_with, with an inspector called in the order the Inspector documentation guarantees. For a buffered body the sniff window is a slice of the body, not a copy. A part the inspector skips is left out of the result.
parse_multipart_withalloc
As parse_multipart with explicit limits and policy. limits.validate() runs first. The token rule of Policy::token_field applies; the captured token is the value of the text field with that name.
parse_queryalloc
As parse_urlencoded, after stripping exactly one leading ? if there is one.
parse_urlencodedalloc
Parses a whole application/x-www-form-urlencoded body with the default limits and policy, and returns the fields, owned, in input order.
parse_urlencoded_inspectedalloc
As parse_urlencoded_with, calling inspector.field(name, value) for every pair in input order (decoded value bytes), then inspector.end(). On any error, including a refusal, inspector.failed(&error) is called once before the error is returned. A Verdict::Skip from field drops that pair. Inspection never runs on a body form-net refuses.
parse_urlencoded_withalloc
As parse_urlencoded with explicit limits and policy. limits.validate() runs first. Of the policy, only percent applies to urlencoded bodies.
raw_pairs
Iterates the pairs of a urlencoded body without allocating or copying.
read_multipartfs
The blocking convenience: reads body to the end in 64 KiB chunks with the default limits and policy, keeps files up to 64 KiB in memory, and spills larger ones to anonymous temporary files in a private directory that is created only when a file first spills and removed when the last file from it is dropped. There is no process-wide state.
serialize_urlencodedalloc
Builds a urlencoded body or query from pairs, byte-identical to the WHATWG serializer for UTF-8: names and values are encoded as encode_into does, joined with =, and pairs are joined with &. Infallible: every str is valid input.