![]() |
Nilorea Library
C utilities for networking, threading, graphics
|
HTTP router: static route tables, typed placeholders, specificity. More...
Go to the source code of this file.
Data Structures | |
| struct | N_ROUTE |
| one route of a table More... | |
| struct | N_ROUTE_MATCH |
| a successful match: the route and its decoded placeholder values More... | |
Macros | |
| #define | N_ROUTE_GET N_HTTP_REQ_METHOD_BIT(N_HTTP_REQ_GET) |
| route accepts GET (and so HEAD) | |
| #define | N_ROUTE_HEAD N_HTTP_REQ_METHOD_BIT(N_HTTP_REQ_HEAD) |
| route accepts HEAD only (rare: GET routes answer HEAD already) | |
| #define | N_ROUTE_NAME_MAX 31 |
| longest placeholder name | |
| #define | N_ROUTE_PARAMS_MAX 8 |
| most placeholders in one route | |
| #define | N_ROUTE_POST N_HTTP_REQ_METHOD_BIT(N_HTTP_REQ_POST) |
| route accepts POST | |
Typedefs | |
| typedef int(* | n_route_handler) (void *ctx, const struct N_ROUTE_MATCH *match) |
| a route handler: ctx is the caller's request context | |
Enumerations | |
| enum | N_ROUTER_RESULT { N_ROUTER_FOUND = 0 , N_ROUTER_NOT_FOUND = 1 , N_ROUTER_METHOD_NOT_ALLOWED = 2 , N_ROUTER_BAD_REQUEST = 3 } |
| result of n_router_match() More... | |
Functions | |
| const char * | n_route_param (const N_ROUTE_MATCH *m, const char *name, size_t *len) |
| decoded value of a placeholder | |
| int | n_router_add (N_ROUTER *r, const N_ROUTE *routes, size_t count) |
| compile and add a route table | |
| int | n_router_allow_header (unsigned allowed, char *out, size_t size) |
| write an Allow header value ("GET, HEAD, POST") for a method mask | |
| int | n_router_check (const N_ROUTER *r, char *err, size_t errsz) |
| refuse ambiguous routes: two routes sharing a method that can match the same path with the same specificity | |
| size_t | n_router_count (const N_ROUTER *r) |
| number of routes added | |
| void | n_router_free (N_ROUTER **r) |
| free a router and set *r to NULL (the route tables are not touched) | |
| N_ROUTER_RESULT | n_router_match (const N_ROUTER *r, n_http_req_method method, const char *path, size_t len, N_ROUTE_MATCH *match, unsigned *allowed) |
| find the route for a method and a path | |
| N_ROUTER * | n_router_new (void) |
| new, empty router | |
| const N_ROUTE * | n_router_route (const N_ROUTER *r, size_t i) |
| the i-th route added (to check caller policies at start-up) | |
HTTP router: static route tables, typed placeholders, specificity.
Routes are declared in static tables, one line each:
static const N_ROUTE PUBLIC[] = {
{N_ROUTE_GET, "/", h_home, NULL},
{N_ROUTE_GET, "/{y:d4}/{m:d2}/{d:d2}/{slug:slug}/", h_post, NULL},
{N_ROUTE_GET, "/media/{id:hex16}/{w:int4}/{name:seg}", h_variant, NULL},
};
A pattern is a '/'-separated list of segments, each either a literal ("feed", matched exactly and case-sensitively against the raw path) or one placeholder "{name:type}" ("{name}" is "{name:seg}"). A trailing '/' in the pattern requires one in the path. Types are checked on the RAW segment, before decoding, so a percent-encoded byte never satisfies a digit, hex or slug type:
| type | raw segment |
|---|---|
| dN | exactly N digits (N 1..18) |
| hexN | exactly N lowercase hex digits (N 1..64) |
| intN | 1 to N digits (N 1..18) |
| slug | 1 to 120 of a-z 0-9 '_' '-' |
| seg | 1 to 255 bytes, no '/' |
| rest | the remainder of the path, '/' included, last only |
Captured values are strictly percent-decoded into the match (a malformed escape, a decoded NUL or ill-formed UTF-8 in ANY segment of the path makes the whole request a 400, before any route is tried).
When several routes match, the most specific wins, segment by segment from the left: a literal beats dN/hexN, which beat intN, then slug, seg, rest. So "/feed/" wins over "/{slug}/" whatever the table order, and n_router_check() refuses only real ambiguities (two routes the rule cannot order, like a duplicate or d4 against hex4). A route allowing GET also answers HEAD.
The router does no allocation per request and keeps pointers to the route tables: they must outlive it (static tables do).
Definition in file n_http_router.h.