module

Noir::CHttpSupport

Shared parsing for the C embedded HTTP servers (Mongoose, CivetWeb, libmicrohttpd). C has no route DSL: a URI is a string literal handed to a registration call, or compared against the request URI inside one big handler, and a handler is a plain function. These helpers resolve those literals (including #define NAME "/path"), find a handler's body, and read the method and parameter evidence out of it. Offsets are bytes, as in CppCalleeExtractor.

Constants

CALL_RE = /(?<![\w.>])([A-Za-z_]\w*)\s*\(/
DEFINE_RE = /#[ \t]*define[ \t]+([A-Za-z_]\w*)[ \t]+([^\n]*"[^\n]*)|\bconst\s+char\s*(?:\*\s*(?:const\s+)?)?([A-Za-z_]\w*)\s*(?:\[\s*\])?\s*=\s*("[^"\n]*")\s*;/

#define NAME "/p" (or PREFIX "/p"), static const char NAME[] = "/p";, const char *NAME = "/p";

HANDLER_NAME = /\A(?:\([^()]*\)\s*)?&?\s*([A-Za-z_]\w*)/

The function in a handler argument: fn, &fn, (Cast) &fn, and Mongoose 6's fn MG_UD_ARG(NULL).

METHOD_RE = /method\s*,\s*(?:mg_str\s*\(\s*)?"(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)"|"(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)"\s*,\s*[&\w>.\-]*method\b|MHD_HTTP_METHOD_(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\b/

strcmp(ri->request_method, "POST"), mg_match(hm->method, mg_str("POST"), NULL), strcmp("GET", method), strcmp(method, MHD_HTTP_METHOD_POST). Negated compares count too: if (0 != strcmp(method, "GET")) return MHD_NO; is how a handler says it only serves GET.

MHD_KINDS = {"GET_ARGUMENT" => "query", "HEADER" => "header", "COOKIE" => "cookie", "POSTDATA" => "form"}
MHD_VALUE_RE = /\bMHD_lookup_connection_value(?:_n)?\s*\(\s*[^,]*,\s*MHD_(GET_ARGUMENT|HEADER|COOKIE|POSTDATA)_KIND\s*,\s*"([^"]+)"/
NAMED_RE = [{/\bgetParam\s*\(\s*[^,"]*,\s*"([^"]+)"/, "query"}, {/\b(?:mg_http_get_header|mg_get_http_header|mg_get_header|getHeader)\s*\(\s*[^,]*,\s*"([^"]+)"/, "header"}, {/\b(?:mg_get_cookie|getCookie)\s*\(\s*[^,]*,\s*"([^"]+)"/, "cookie"}, {/\bmg_json_get\w*\s*\(\s*[^,]*,\s*"\$\.(\w+)/, "json"}]
STRING_EXPR = /\A(?:\s*+(?:"(?:[^"\\]|\\.)*+"|[A-Za-z_]\w*+))++\s*+\z/

Possessive throughout: a long identifier must not be re-split into shorter adjacent "identifiers" when the match fails.

STRING_PART = /"((?:[^"\\]|\\.)*)"|([A-Za-z_]\w*)/
VAR_RE = /\bmg_(?:http_get_var|get_http_var|http_var|get_var2?)\s*\(\s*([^,]*),(?:[^,"]*,)?\s*(?:mg_str\s*\(\s*)?"([^"]+)"/

Mongoose mg_http_get_var(&hm->query, "q", ...) and CivetWeb mg_get_var(qs, len, "q", ...): the source buffer says query vs form.

Instance methods

body_of(unit : Unit, name : String) : Tuple(String, Int32) | Nil

Memoized CppCalleeExtractor.function_body: every route of a big dispatcher calls the same helpers.

Source
call_args(source : String, open_paren : Int32) : Tuple(Array(String), Int32) | Nil

Top-level arguments of the call whose ( is at open_paren, plus the byte offset of its ).

Source
compared_route(unit : Unit, path : String, url : String, call_start : Int32, close : Int32, include_callee : Bool) : Array(Endpoint)

A route found as a URI comparison inside a handler. The method comes from the if condition, else from the branch it guards, else GET; params come from the branch and the helpers it calls.

Source
endpoints(path : String, url : String, line : Int32, methods : Array(String), scope : String, body : Tuple(String, Int32) | Nil, include_callee : Bool, protocol = "http") : Array(Endpoint)

One endpoint per method (GET when the handler never looks), carrying the params read in scope and, when asked, the callees of body.

Source
handler_body(unit : Unit, arg : String | Nil) : Tuple(String, Int32) | Nil

The function named by a handler argument.

Source
handler_route(unit : Unit, path : String, url : String, line : Int32, body : Tuple(String, Int32) | Nil, include_callee : Bool, methods : Array(String) | Nil = nil) : Array(Endpoint)

A route served by a whole handler (body, nil when unresolved): the methods it compares the request method against, the params it and its helpers read.

Source
line_of(unit : Unit, byte : Int32) : Int32

1-based line of a byte offset; line_number_for recounts from the start of the file, which a dispatcher with hundreds of routes pays per route.

Source
methods_in(text : String) : Array(String)
Source
params_in(text : String) : Array(Param)
Source
route_path(raw : String | Nil) : String | Nil

The URI pattern as a Noir URL: Mongoose # and CivetWeb ** (match anything) become *, CivetWeb's $ end anchor is dropped. Nil for non-path patterns (**.php$, "").

Source
string_value(arg : String | Nil, unit : Unit, depth = 0) : String | Nil

A string argument: literals, mg_str("..."), #defined names and adjacent concatenations of those (AREA_URL "page"). Nil for anything computed at runtime.

Source
unit(content : String) : Unit
Source
with_callees(unit : Unit, body : String) : String

body plus the bodies of the same-file functions it calls: handlers routinely hand the request to a handle_login(c, hm) helper. Functions body defines itself (a C++ handler class's methods) are already in it.

Source

Nested types