2 Module N_HTTP_FORM
gullradriel edited this page 2026-10-29 20:54:40 +01:00

HTTP FORMS: strict percent, query and urlencoded decoding

Structures

Name
struct N_HTTP_FORM_PART
one part of a multipart/form-data body; the body is NOT copied
struct N_HTTP_FORM_MULTIPART
a parsed multipart/form-data body
struct N_HTTP_FORM
decoded fields, in the order they were sent
struct N_HTTP_FIELD
one decoded name=value pair; both are NUL-terminated and hold no NUL

Functions

Name
int n_http_percent_decode(const char * s, size_t len, int flags, N_STR ** out)
percent-decode [s, s+len), appending to *out
N_HTTP_FORM * n_http_form_parse(const char * s, size_t len, size_t max_fields, int flags)
decode a query string or an urlencoded body into fields
N_HTTP_FORM_MULTIPART * n_http_form_multipart_parse(const char * buf, size_t len, const char * boundary, size_t max_parts)
parse a multipart/form-data body strictly, without copying it
const N_HTTP_FORM_PART * n_http_form_multipart_get(const N_HTTP_FORM_MULTIPART * mp, const char * name)
the LAST part named name (PHP semantics, like n_http_form_get())
void n_http_form_multipart_free(N_HTTP_FORM_MULTIPART ** mp)
free a parsed body and set *mp to NULL
size_t n_http_form_multipart_count(const N_HTTP_FORM_MULTIPART * mp, const char * name)
number of parts named name
int n_http_form_multipart_boundary(const char * content_type, size_t len, char * out)
boundary of a multipart/form-data Content-Type, parsed strictly
const char * n_http_form_get(const N_HTTP_FORM * form, const char * name, size_t * value_len)
value of the LAST field named name, like PHP's $_GET / $_POST
void n_http_form_free(N_HTTP_FORM ** form)
free a form and set *form to NULL
size_t n_http_form_count(const N_HTTP_FORM * form, const char * name)
number of fields named name (exact, case-sensitive)

Defines

Name
N_HTTP_FORM_SKIP_INVALID
n_http_form_parse(): drop a pair that fails to decode instead of failing
N_HTTP_FORM_RAW_BYTES
accept decoded bytes that are not well-formed UTF-8 (NUL stays refused)
N_HTTP_FORM_PLUS_SPACE
decode '+' as a space (query strings and urlencoded forms, not paths)
N_HTTP_FORM_PART_TYPE_MAX
longest part Content-Type kept
N_HTTP_FORM_PART_NAME_MAX
longest multipart field name accepted
N_HTTP_FORM_PART_HEAD_MAX
largest header block of one part
N_HTTP_FORM_PART_FILENAME_MAX
longest multipart filename accepted
N_HTTP_FORM_BOUNDARY_MAX
longest boundary RFC 2046 allows

Functions Documentation

function n_http_percent_decode

int n_http_percent_decode(
    const char * s,
    size_t len,
    int flags,
    N_STR ** out
)

percent-decode [s, s+len), appending to *out

Parameters:

  • s encoded bytes (may be NULL only when len is 0)
  • len number of bytes
  • flags N_HTTP_FORM_PLUS_SPACE, N_HTTP_FORM_RAW_BYTES
  • out destination, appended to (created when *out is NULL)
  • s encoded bytes (may be NULL only when len is 0)
  • len number of bytes
  • flags N_HTTP_FORM_PLUS_SPACE, N_HTTP_FORM_RAW_BYTES
  • out destination, appended to (created when *out is NULL)

Return:

  • TRUE on success, FALSE on invalid input or allocation failure
  • TRUE on success, FALSE on invalid input or allocation failure

percent-decode [s, s+len), appending to *out; malformed escapes, a decoded NUL and (without N_HTTP_FORM_RAW_BYTES) ill-formed UTF-8 refused

Refuses a malformed escape, a decoded NUL, and (without N_HTTP_FORM_RAW_BYTES) a result that is not well-formed UTF-8. With N_HTTP_FORM_PLUS_SPACE, '+' becomes a space. On failure *out keeps whatever it held before the call. percent-decode [s, s+len), appending to *out

function n_http_form_parse

N_HTTP_FORM * n_http_form_parse(
    const char * s,
    size_t len,
    size_t max_fields,
    int flags
)

decode a query string or an urlencoded body into fields

Parameters:

  • s the query (without the '?') or body (may be NULL only when len is 0)
  • len number of bytes
  • max_fields largest number of pairs accepted, at least 1
  • flags N_HTTP_FORM_RAW_BYTES, N_HTTP_FORM_SKIP_INVALID
  • s the query (without the '?') or body (may be NULL only when len is 0)
  • len number of bytes
  • max_fields largest number of pairs accepted, at least 1
  • flags N_HTTP_FORM_RAW_BYTES, N_HTTP_FORM_SKIP_INVALID

Return:

Pairs are separated by '&'; empty pairs ("a=1&&b=2") are skipped; a pair without '=' has an empty value. Names and values are decoded with n_http_percent_decode() and '+' as a space. More than max_fields pairs is an error even with N_HTTP_FORM_SKIP_INVALID, as is an empty name.

function n_http_form_multipart_parse

N_HTTP_FORM_MULTIPART * n_http_form_multipart_parse(
    const char * buf,
    size_t len,
    const char * boundary,
    size_t max_parts
)

parse a multipart/form-data body strictly, without copying it

Parameters:

Return:

Works on any buffer, an mmap of an uploaded file included: part bodies are offsets into it. Refused (NULL): no delimiter at the start (a preamble up to 1 KiB before a CRLF-led delimiter is allowed), a missing closing delimiter (a truncated upload), more than max_parts parts, a part header block over N_HTTP_FORM_PART_HEAD_MAX or with a malformed line, a part without "Content-Disposition: form-data" and a non-empty name, a repeated disposition parameter (two name=, the classic parameter confusion), a name or filename too long, not UTF-8 or holding a control byte.

function n_http_form_multipart_get

const N_HTTP_FORM_PART * n_http_form_multipart_get(
    const N_HTTP_FORM_MULTIPART * mp,
    const char * name
)

the LAST part named name (PHP semantics, like n_http_form_get())

Parameters:

  • mp the parsed body
  • name the field name
  • mp the parsed body
  • name the field name

Return:

  • the part, or NULL
  • the part, or NULL

the LAST part named name (PHP semantics)

the LAST part named name (PHP semantics, like n_http_form_get())

function n_http_form_multipart_free

void n_http_form_multipart_free(
    N_HTTP_FORM_MULTIPART ** mp
)

free a parsed body and set *mp to NULL

Parameters:

  • mp address of the pointer (may point to NULL)

function n_http_form_multipart_count

size_t n_http_form_multipart_count(
    const N_HTTP_FORM_MULTIPART * mp,
    const char * name
)

number of parts named name

Parameters:

  • mp the parsed body
  • name the field name
  • mp the parsed body
  • name the field name

Return:

  • the count, 0 on a NULL argument
  • the count, 0 on a NULL argument

number of parts named name

number of parts named name

function n_http_form_multipart_boundary

int n_http_form_multipart_boundary(
    const char * content_type,
    size_t len,
    char * out
)

boundary of a multipart/form-data Content-Type, parsed strictly

Parameters:

  • content_type the header value
  • len its length
  • out receives the boundary, at least N_HTTP_FORM_BOUNDARY_MAX + 1 bytes
  • content_type the header value
  • len its length
  • out receives the boundary, at least N_HTTP_FORM_BOUNDARY_MAX + 1 bytes

Return:

  • TRUE, FALSE when not a valid multipart/form-data type
  • TRUE, FALSE when not a valid multipart/form-data type

The media type must be multipart/form-data (any case); parameters are split on ';' (a "boundary=" inside another parameter's quoted value is not taken); exactly one boundary parameter, token or quoted, 1 to 70 RFC 2046 characters, not ending with a space.

function n_http_form_get

const char * n_http_form_get(
    const N_HTTP_FORM * form,
    const char * name,
    size_t * value_len
)

value of the LAST field named name, like PHP's $_GET / $_POST

Parameters:

  • form the parsed form
  • name the exact (case-sensitive) decoded name
  • value_len receives the value length (may be NULL)
  • form the parsed form
  • name the exact (case-sensitive) decoded name
  • value_len receives the value length (may be NULL)

Return:

  • the value, or NULL when absent or on a NULL argument
  • the value, or NULL when absent or on a NULL argument

value of the LAST field named name (PHP semantics)

The last occurrence wins, as in PHP, so a server ported from PHP keeps its behaviour on repeated parameters. Use n_http_form_count() to refuse repeats, or walk fields[] for list fields ("tag[]"). value of the LAST field named name, like PHP's $_GET / $_POST

function n_http_form_free

void n_http_form_free(
    N_HTTP_FORM ** form
)

free a form and set *form to NULL

Parameters:

  • form address of the form pointer (may point to NULL)

function n_http_form_count

size_t n_http_form_count(
    const N_HTTP_FORM * form,
    const char * name
)

number of fields named name (exact, case-sensitive)

Parameters:

  • form the parsed form
  • name the decoded name
  • form the parsed form
  • name the decoded name

Return:

  • the count, 0 on a NULL argument
  • the count, 0 on a NULL argument

number of fields named name (exact, case-sensitive)

number of fields named name (exact, case-sensitive)

Macros Documentation

define N_HTTP_FORM_SKIP_INVALID

#define N_HTTP_FORM_SKIP_INVALID 4

n_http_form_parse(): drop a pair that fails to decode instead of failing

define N_HTTP_FORM_RAW_BYTES

#define N_HTTP_FORM_RAW_BYTES 2

accept decoded bytes that are not well-formed UTF-8 (NUL stays refused)

define N_HTTP_FORM_PLUS_SPACE

#define N_HTTP_FORM_PLUS_SPACE 1

decode '+' as a space (query strings and urlencoded forms, not paths)

define N_HTTP_FORM_PART_TYPE_MAX

#define N_HTTP_FORM_PART_TYPE_MAX 127

longest part Content-Type kept

define N_HTTP_FORM_PART_NAME_MAX

#define N_HTTP_FORM_PART_NAME_MAX 200

longest multipart field name accepted

define N_HTTP_FORM_PART_HEAD_MAX

#define N_HTTP_FORM_PART_HEAD_MAX 8192

largest header block of one part

define N_HTTP_FORM_PART_FILENAME_MAX

#define N_HTTP_FORM_PART_FILENAME_MAX 255

longest multipart filename accepted

define N_HTTP_FORM_BOUNDARY_MAX

#define N_HTTP_FORM_BOUNDARY_MAX 70

longest boundary RFC 2046 allows