flare_mlake · API · http

flare.http.form

application/x-www-form-urlencoded parsing (WHATWG URL Living Standard, §5.1).

The format predates RFC 3986 by a decade and lives separately as the HTML form serialisation algorithm. Practical differences vs §3 query strings:

  • + decodes to a literal space (RFC 3986 reserves + for plus).
  • Pairs are separated by & (or ; for legacy compatibility).
  • Each pair is name=value; missing = is treated as name="".
  • Percent-decoding is applied to both names and values, after the pair split.

This module ships:

  • urldecode — RFC 3986 percent-decode + +→space (the form-data variant). Returns the decoded String; bad %XX escapes raise.
  • FormData — multimap-of-strings (one key may map to multiple values, e.g. checkboxes), backed by parallel lists for stable insertion order.
  • parse_form_urlencoded — bytes/string → FormData; the Form extractor in extract.mojo is the typed handler-side wrapper.

Structs

FormData

struct FormData

A name → value(s) multimap, in insertion order.

Backs the Form extractor; mirrors the API of HeaderMap so handlers can write the same code shape against headers, query strings, and form bodies.

Internally two parallel lists keep insertion order stable (lookups are O(n), n is typically tiny — sub-100 fields). For larger forms the dict-of-lists layout would be a future optimisation; the bench harness has not pushed past 32 fields.

Implements Copyable, Defaultable, Movable

__init__

def __init__(out self)

get

def get(self, name: String) -> String

Return the first value for name (case-sensitive), else "".

get_optional

def get_optional(self, name: String) -> Optional[String]

Return Some(value) if name is present, None otherwise.

get_all

def get_all(self, name: String) -> List[String]

Return every value bound to name in insertion order.

append

def append(mut self, name: String, value: String)

Append (name, value); existing bindings are preserved.

contains

def contains(self, name: String) -> Bool

Return True if any binding for name exists.

len

def len(self) -> Int

Return the total number of bindings (counting duplicate keys).

keys

def keys(self) -> List[String]

Return the list of keys (with duplicates) in insertion order.

values

def values(self) -> List[String]

Return the list of values in insertion order, parallel to keys().

to_urlencoded

def to_urlencoded(self) -> String

Serialise back to application/x-www-form-urlencoded.

Round-trips parse_form_urlencoded for any well-formed input. Uses + for spaces and %XX for everything else outside the unreserved set.

Functions

urldecode

def urldecode(s: String) -> String

Percent-decode s and convert + to space.

Implements the WHATWG application/x-www-form-urlencoded byte decode: each %XX triple becomes the byte XX, each + becomes a single 0x20, every other byte is preserved verbatim.

The decoded bytes must form well-formed UTF-8 (RFC 3629): a String may not hold anything else, and the escapes come from attacker-controlled input (%F0 alone is a lone 4-byte lead). Ill-formed output is rejected rather than wrapped unchecked.

Args
s: The encoded string (ASCII, possibly with percent-escapes).

Raises Error: When a % escape is truncated or contains a non-hex digit, or when the decoded bytes are not valid UTF-8.

urlencode

def urlencode(s: String) -> String

Percent-encode s for use in form bodies / query strings.

Encodes per the WHATWG application/x-www-form-urlencoded byte encode: unreserved characters (A-Z, a-z, 0-9, -, _, ., ~) pass through; spaces become +; every other byte becomes %XX. Suitable for both names and values.

Args
s: The string to encode (any UTF-8 bytes).

parse_form_urlencoded

def parse_form_urlencoded(body: String) -> FormData

Parse application/x-www-form-urlencoded bytes into a FormData.

Pair separators are & and ; (legacy HTML forms still emit the latter). Empty pairs are skipped silently. name= keeps an empty-string value; name (no =) also keeps an empty-string value.

Args
body: Form body as a String. Empty input produces an empty FormData (no error).

Raises Error: If a percent-escape is malformed inside a name or value, or a decoded name / value is not valid UTF-8 (delegated from urldecode).