KHTTP_PARSE(3)
π KHTTP_PARSE(3) β Library Functions Manual π
π NAME π
khttp_parse, khttp_parsex β parse a CGI instance for kcgi
π§ LIBRARY π§
library βlibkcgiβ
β¨ SYNOPSIS β¨
#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>
#include <kcgi.h>
enum kcgi_err
khttp_parse(struct kreq *req, const struct kvalid *keys, size_t keysz,
const char *const *pages, size_t pagesz, size_t defpage);
enum kcgi_err
khttp_parsex(struct kreq *req, const struct kmimemap *suffixes,
const char *const *mimes, size_t mimesz, const struct kvalid *keys,
size_t keysz, const char *const *pages, size_t pagesz,
size_t defmime, size_t defpage, void *arg,
void (*argfree)(void *arg), unsigned int debugging,
const struct kopts *opts);
extern const char *const kmimetypes[KMIME__MAX];
extern const char *const khttps[KHTTP__MAX];
extern const char *const kschemes[KSCHEME__MAX];
extern const char *const kmethods[KMETHOD__MAX];
extern const struct kmimemap ksuffixmap[];
extern const char *const ksuffixes[KMIME__MAX];
πΈ DESCRIPTION πΈ
okay so bestie, khttp_parse() and khttp_parsex() are the ones that parse and validate input and the HTTP environment β compression, paths, MIME types, and so on. Theyβre literally the central functions in the kcgi(3) library, parsing and validating key-value form (query string, message body, cookie) data and opaque message bodies. iconic behavior.
They must be matched by khttp_free(3) if and only if the return value is KCGI_OK. Otherwise, resources are internally freed. no cap, that βif and only ifβ is doing main-character work.
The collective arguments are as follows:
argβ a pointer to private application data. It is not touched unlessargfreeis provided.argfreeβ function invoked withargby the child process starting to parse untrusted network data. This makes sure that no unnecessary data is leaked into the child.debuggingβ this bit-field enables debugging of the underlying parse and/or write routines. It may haveKREQ_DEBUG_WRITEfor writes andKREQ_DEBUG_READ_BODYfor the pre-parsed body. Debugging messages tokutil_info(3)consist of the process ID followed by-txor-rxfor writing or reading, a colon and space, then the logged data. A newline will flush the existing line, as well reaching 80 characters. If flushed at 80 characters and not a newline, an ellipsis will follow the line. The total logged bytes will be emitted at the end of all reads or writes.defmimeβ if no MIME type is specified (that is, thereβs no suffix to the page request), use this index in themimesarray.defpageβ if no page was specified (e.g., the default landing page), this is provided as the requested page index.keysβ an optional array of input and validation fields orNULL.keyszβ the number of elements inkeys.mimeszβ the number of elements inmimes. Also the MIME index used if no MIME type was matched. This differs fromdefmime, which is used if there is no MIME suffix at all.mimesβ an array of MIME types (e.g.,βtext/htmlβ), mapped into a MIME index during MIME body parsing. This relates both to pages and input fields with a body type. Any array should include at leasttext/plain, as this is the default content type for MIME documents.optsβ tunable options regarding socket buffer sizes and so on. If set toNULL, meaningful defaults are used.pagesβ an array of recognised pathnames. When pathnames are parsed, theyβre matched to indices in this array.pageszβ the number of pages inpages. Also used if the requested page was not inpages.reqβ this structure is cleared and filled with input fields and HTTP context parsed from the CGI environment. It is the main structure carried around in akcgi(3)application.suffixesβ define the MIME type (suffix) mapping.
The first form, khttp_parse(), is for applications using the system-recognised MIME types. This should work well enough for most applications. It is equivalent to invoking the second form, khttp_parsex(), as follows:
khttp_parsex(req, ksuffixmap,
kmimetypes, KMIME__MAX, keys, keysz,
pages, pagesz, KMIME_TEXT_HTML,
defpage, NULL, NULL, 0, NULL);
π¦ Types π¦
A struct kreq object is filled in by khttp_parse() and khttp_parsex(). It consists of the following fields:
void *argβ private application data. This is set duringkhttp_parse().enum kauth authβ type of βmanagedβ HTTP authorisation performed by the web server according to theAUTH_TYPEheader variable, if any. This isKAUTH_DIGESTfor theAUTH_TYPEof"digest",KAUTH_BASICfor"basic",KAUTH_BEARERfor"bearer",KAUTH_UNKNOWNfor other values ofAUTH_TYPE, orKAUTH_NONEifAUTH_TYPEis not set. See therawauthfield for raw (i.e., not processed by the web server) authorisation requests.struct kpair **cookiemapβ an array ofkeyszsingly linked lists of elements of thecookiesarray. Ifcookie->keyis equal to one of the entries ofkeysandcookie->stateisKPAIR_VALIDorKPAIR_UNCHECKED, the cookie is added to the listcookiemap[cookie->keypos]. Empty lists areNULL. If a list contains more than one cookie,cookie->nextpoints to the next cookie. For the last cookie in a list,cookie->nextisNULL.struct kpair **cookienmapβ similar tocookiemap, except that it contains the cookies wherecookie->stateisKPAIR_INVALID.struct kpair *cookiesβ key-value pairs read from request cookies found in theHTTP_COOKIEheader variable, orNULLifcookieszis 0. Seefieldsfor key-value pairs from the request query string or message body.size_t cookieszβ the size of thecookiesarray.struct kpair **fieldmapβ similar tocookiemap, except that the lists contain elements of thefieldsarray.struct kpair **fieldnmapβ similar tofieldmap, except that it contains the fields wherefield->stateisKPAIR_INVALID.struct kpair *fieldsβ key-value pairs read from theQUERY_STRINGheader variable and from the message body, orNULLiffieldszis 0. Seecookiesfor key-value pairs from request cookies.size_t fieldszβ the number of elements in thefieldsarray.char *fullpathβ the full requested path as contained in thePATH_INFOheader variable. For example, requesting"https://bsd.lv/app.cgi/dir/file.html?q=v", where"app.cgi"is the CGI program, this value would be/dir/file.html. It is not guaranteed to start with a slash and it may be an empty string.char *hostβ the host name received in theHTTP_HOSTheader variable. When using name-based virtual hosting, this is typically the virtual host name specified by the client in the HTTP request, and it should not be confused with the canonical DNS name of the host running the web server. For example, a request to"https://bsd.lv/app.cgi/file"would have ahostof"bsd.lv". IfHTTP_HOSTis not defined,hostis set to"localhost".struct kdata *kdataβ internal data. Should not be touched.const struct kvalid *keysβ value passed tokhttp_parse().size_t keyszβ value passed tokhttp_parse().enum kmethod methodβ theKMETHOD_ACL,KMETHOD_CONNECT,KMETHOD_COPY,KMETHOD_DELETE,KMETHOD_GET,KMETHOD_HEAD,KMETHOD_LOCK,KMETHOD_MKCALENDAR,KMETHOD_MKCOL,KMETHOD_MOVE,KMETHOD_OPTIONS,KMETHOD_POST,KMETHOD_PROPFIND,KMETHOD_PROPPATCH,KMETHOD_PUT,KMETHOD_REPORT,KMETHOD_TRACE, orKMETHOD_UNLOCKsubmission method obtained from theREQUEST_METHODheader variable. If an unknown method was requested,KMETHOD__MAXis used. If no method was specified, the default isKMETHOD_GET.
Applications will usually accept only KMETHOD_GET and KMETHOD_POST, so be sure to emit a KHTTP_405 status for undesired methods.
size_t mimeβ the MIME type of the requested file as determined by its suffix matched to themimemapmap passed tokhttp_parsex()or the defaultkmimemapif usingkhttp_parse(). This defaults to themimeszvalue passed tokhttp_parsex()or the defaultKMIME__MAXif usingkhttp_parse()when no suffix is specified or when the suffix is specified but not known.size_t pageβ the page index found by looking uppagenamein thepagesarray. Ifpagenameis not found inpages,pageszis used; ifpagenameis empty,defpageis used.char *pagenameβ the first component offullpathor an empty string if there is none. It is compared to the elements of thepagesarray to determine which page it corresponds to. For example, for afullpathof"/dir/file.html"this component corresponds todir. For"/file.html", itβsfile.char *pathβ the middle part offullpath, after strippingpagename/at the beginning and.suffixat the end, or an empty string if there is none. For example, if thefullpathisbar/baz.html, this component isbaz.char *pnameβ the script name received in theSCRIPT_NAMEheader variable. For example, for a request to a CGI program/var/www/cgi-bin/app.cgimapped by the web server from"https://bsd.lv/app.cgi/file", this would beapp.cgi. This may not reflect a file system entity and it may be an empty string.uint16_t portβ the serverβs receiving TCP port according to theSERVER_PORTheader variable, or 80 if that is not defined or an invalid number.struct khttpauth rawauthβ the raw authorization request according to theHTTP_AUTHORIZATIONheader variable passed by the web server. This is only set if the web server is not managing authorisation itself.char *remoteβ the string form of the clientβs IPv4 or IPv6 address taken from theREMOTE_ADDRheader variable, or"127.0.0.1"if that is not defined. The address format of the string is not checked.struct khead *reqmap[KREQU__MAX]β map ofenum krequenumeration values to pairs inreqs. If an enumerated request was not specified, it isNULL.struct khead *reqsβ okay so this is the list of all HTTP request headers, orNULLifreqszis 0. Theyβre in HTTP syntax with everything lowercase and underscores turned into hyphens, e.g. the CGI variableHTTP_ACCEPT_LANGUAGEis stored ashttp-accept-language. Peepenvsfor the unmodified environment variables πsize_t reqszβ the number of request headers inreqs. count βem β¨struct khead *envsβ list of all environment variables in the CGI or FastCGI context, orNULLifenvszis 0. Seereqsfor the parsed and formatted HTTP headers, defined as environment variables starting withHTTP_. π«Άsize_t envszβ number of environment variables inenvs. slay πenum kscheme schemeβ the access scheme according to theHTTPSheader variable: eitherKSCHEME_HTTPSifHTTPSis set and equal to the string"on", orKSCHEME_HTTPotherwise. vibe check π₯char *suffixβ the suffix part of the last component offullpath, or an empty string if there isnβt one. For example, if thefullpathis/bar/baz.html, this component ishtml. See themimefield for the MIME type parsed from the suffix. iykyk πΈ
The application may optionally define keys provided to khttp_parse() and khttp_parsex() as an array of struct kvalid. This structure is central to the validation of input data. It consists of the following fields:
const char *nameβ the field name, i.e. how it appears in the HTML form input name. This cannot beNULL. If the field name is an empty string and the HTTP message consists of an opaque body (and not key-value pairs), then that field will be used to validate the HTTP message body. This is useful forKMETHOD_PUTstyle requests. periodt πint (*)(struct kpair *) validβ a validation function returning non-zero if parsing and validation succeed or 0 otherwise. If it isNULL, then no validation is performed, the data is considered as valid, and it is bucketed intocookiemaporfieldmapas such. π¦
User-defined valid functions usually set the type and parsed fields in the key-value pair. When working with binary data or with a key that can take different data types, it is acceptable for a validation function to set the type to KPAIR__MAX and for the application to ignore the parsed field and to work directly with val and valsz. no cap β
The validation function is allowed to allocate new memory for val: if the val pointer changes during validation, the memory pointed to after validation will be freed with free(3) after the data is passed out of the sandbox. important!! π¨
These functions are invoked from within a system-specific sandbox that may not allow some system calls, for example opening files or sockets. In other words, validation functions should only do pure computation. fr fr π§
The struct kpair structure presents the user with fields parsed from input and (possibly) matched to the keys variable passed to khttp_parse() and khttp_parsex(). It is also passed to the validation function to be filled in. In this case, the MIME-related fields are already filled in and may be examined to determine the method of validation. This is useful when validating opaque message bodies. obsessed π
char *ctypeβ the valueβs MIME content type (e.g.image/jpeg), or an empty string if not defined. πsize_t ctypeposβ ifctypeis notNULL, it is looked up in themimesparameter passed tokhttp_parsex()orksuffixmapif usingkhttp_parse(). If found, it is set to the appropriate index. Otherwise, itβsmimesz. indexed bestie β¨char *fileβ the valueβs MIME source filename, or an empty string if not defined. πchar *keyβ the NUL-terminated key (input) name. If the HTTP message body is opaque (e.g.KMETHOD_PUT), then an empty-string key is cooked up. The key may contain an arbitrary sequence of non-NUL bytes, even non-ASCII bytes, control characters, and shell metacharacters. wild but true πsize_t keyposβ if found in thekeysarray passed tokhttp_parse(), the index of the matching key. Otherwisekeysz. πstruct kpair *nextβ in a cookie or field map,nextpoints to the next parsed key-value pair with the same key name. This occurs most often in HTML checkbox forms, where many fields may have the same name. checkbox chaos πunion parsed parsedβ the parsed, validated value. These may be an integer ini, for a 64-bit signed integer; a strings, for a NUL-terminated character string; or a doubled, for a double-precision floating-point number. This is intentionally basic because the resulting data must be reliably passed from the parsing context back into the web application. reliable queen πenum kpairstate stateβ the validation state:KPAIR_VALIDif the pair was successfully validated by a validation function,KPAIR_INVALIDif a validation function was invoked but failed, orKPAIR_UNCHECKEDif no validation function is defined for this key. state check βenum kpairtype typeβ if parsed, the type of data inparsed, otherwiseKFIELD__MAX. π¦char *valβ the (input) value, which may contain an arbitrary sequence of bytes, even NUL bytes, non-ASCII bytes, control characters, and shell metacharacters. The byte following the end of the array,val[valsz], is always guaranteed to be NUL. The validation function may modify the contents. For example, for integer numbers and e-mail addresses, trailing whitespace may be replaced with NUL bytes. trust the NUL π«Άsize_t valszβ the length of thevalbuffer in bytes. It is not a string length. not a string bestie πchar *xcodeβ the valueβs MIME content transfer encoding (e.g.base64), or an empty string if not defined. πΈ
The struct khttpauth structure holds authorisation data if passed by the server. The specific fields are as follows. auth vibes π
enum kauth typeβ if no data was passed by the server, thetypevalue isKAUTH_NONE. Otherwise itβsKAUTH_BASIC,KAUTH_BEARER, orKAUTH_DIGEST.KAUTH_UNKNOWNsignals that the authorisation type was not recognised. unknown = not recognised π¨int authorisedβ forKAUTH_BASIC,KAUTH_BEARER, orKAUTH_DIGESTauthorisation, this field indicates whether all required values were specified for the application to perform authorisation. βοΈchar *digestβ an MD5 digest ofREQUEST_METHOD,SCRIPT_NAME,PATH_INFO, header variables and the request body. It is not a NUL-terminated string, but an array of exactlyMD5_DIGEST_LENGTHbytes. Only filled in whenHTTP_AUTHORIZATIONis"digest"andauthorisedis non-zero. Otherwise, it remainsNULL. Used inkhttpdigest_validatehash(3). MD5 moment π₯dβ an anonymous union containing parsed fields per type:struct khttpbasic basicforKAUTH_BASICorKAUTH_BEARER, orstruct khttpdigest digestforKAUTH_DIGEST. union slay π
If the field for an HTTP authorisation request is KAUTH_BASIC or KAUTH_BEARER, it will consist of the following for its parsed entities in its struct khttpbasic structure:
responseβ the hashed and encoded response string forKAUTH_BASIC, or an opaque string forKAUTH_BEARER. π
If the field for an HTTP authorisation request is KAUTH_DIGEST, it will consist of the following in its struct khttpdigest structure:
algβ the encoding algorithm, parsed from the possibleMD5orMD5-Sessvalues. algorithm tea βqopβ the quality of protection algorithm, which may be unspecified,AuthorAuth-Init. quality of protection?? iconic β¨userβ the user coordinating the request. π«Άuriβ the URI for which the request is designated. (This must match the request URI). must match!! π¨realmβ the request realm. πΈnonceβ the server-generated nonce value. π₯cnonceβ the (optional) client-generated nonce value. πresponseβ the hashed and encoded response string, which entangled fields depending on algorithm and quality of protection. entangled fr πcountβ the (optional)cnoncecounter. πopaqueβ the (optional) opaque string requested by the server. π¦
The struct kopts structure consists of tunables for network performance. You probably donβt want to use these unless you really know what youβre doing! gatekeep girlboss π
sndbufszβ the size of the output buffer. The output buffer is a heap-allocated region into which writes (viakhttp_write(3)andkhttp_head(3)) are buffered instead of being flushed directly to the wire. The buffer is flushed when it is full, when the HTTP headers are flushed, and whenkhttp_free(3)is invoked. If the buffer size is zero, writes are flushed immediately to the wire. If the buffer size is less than zero, it is filled with a meaningful default. buffer bestie π
Lastly, the struct khead structure holds parsed HTTP headers. π
keyβ holds the HTTP header name. This is not the CGI header name (e.g.HTTP_COOKIE), but the reconstituted HTTP name (e.g.Coookie). reconstituted, not CGI πvalβ the opaque header value, which may be an empty string. β¨
β¨ Variables β¨
A number of variables are defined <kcgi.h> to simplify invocations of the khttp_parse() family. Applications are strongly suggested to use these variables (and associated enumerations) in khttp_parse() instead of overriding them with hand-rolled sets in khttp_parsex(). use the built-ins, bestie π«Ά
kmimetypesβ indexed list of common MIME types, for example,text/htmlandapplication/json. Corresponds toenum kmimeenum khttp. MIME queen πkhttpsβ indexed list of HTTP status code and identifier, for example,200 OK. Corresponds toenum khttp. 200 OK slay βkschemesβ indexed list of URL schemes, for example,httpsorftp. Corresponds toenum kscheme. scheme check π₯kmethodsβ indexed list of HTTP methods, for example,GETandPOST. Corresponds toenum kmethod. method tea βksuffixmapβ map of MIME types defined inenum kmimeto possible suffixes. This array is terminated with a MIME type ofKMIME__MAXand nameNULL. terminated withKMIME__MAXπ¨ksuffixesβ indexed list of canonical suffixes for MIME types corresponding toenum kmime. This may be aNULLpointer for types that have no canonical suffix, for exampleapplication/octet-stream. canonical suffix vibes π
β¨ RETURN VALUES β¨
okay bestie so here's the thing β khttp_parse() and khttp_parsex() hand you back an error code, and you need to actually check it, no skipping the vibe check π€
KCGI_OKβ literally the bestie outcome π this one's a success, and nope, it's not an error at all. slay.KCGI_ENOMEMβ memory failure π and like... it can pop up in so many places: spawning a child, allocating memory, creating sockets, etc. she's flexible like that πKCGI_ENFILEβ could not allocate file descriptors. that's the whole thing. no fd for you πKCGI_EAGAINβ could not spawn a child π« try again energy, except not really.KCGI_FORMβ malformed data between parent and child whilst parsing an HTTP request. this one's an internal system error, so it's not you, it's her πKCGI_SYSTEMβ opaque operating system error. we don't know what it means either, it's giving mysterious main character energy π«οΈ
β οΈ okay this part is important so listen up: on failure, the calling application should terminate as soon as possible. fr fr. do not try to write an HTTP 505 error or similar β nope, absolutely not, put it down π instead, let the web server handle the empty CGI response on its own. trust the process π«Ά
π SEE ALSO π
go read those too, they're iconic i promise π
π AUTHORS π
the khttp_parse() and khttp_parsex() functions were written by Kristaps Dzonsons <kristaps@bsd.lv> ποΈβ¨ absolute legend behaviour, no cap.
and that's the whole page bestie!! ππ¦ this lil beauty ships from Debian at version $Mdocdate$, and it's page KHTTP_PARSE(3) β go forth and parse responsibly, ily, mwah π
ππΈ
π¦ where this page comes from
- alpine 3.24: kcgi-doc 1.0.1-r0 Β· ISC
- Copyright (c) 2014--2017 Kristaps Dzonsons <kristaps@bsd.lv>
- Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms