Cached at:
10/14/26, 07:01 AM
# kcgi: minimal CGI and FastCGI library for C/C++
Source: [https://kristaps.bsd.lv/kcgi/](https://kristaps.bsd.lv/kcgi/)
kcgiis an[open source](http://opensource.org/licenses/ISC)CGI and FastCGI library for C/C\+\+ web applications\. It is minimal, secure, and auditable\. To start,[install](https://kristaps.bsd.lv/kcgi/#install)the library\. Then read the[deployment](https://kristaps.bsd.lv/kcgi/#deploying)and[usage](https://kristaps.bsd.lv/kcgi/#usage)guides\.
The following echoesHello, World\!as an HTTP response to a CGI request\.For fuller examples, see[sample\.c](https://kristaps.bsd.lv/kcgi/sample.c.html)\(C and CGI\),[samplepp\.cc](https://kristaps.bsd.lv/kcgi/samplepp.cc.html)\(C\+\+ and CGI\),[sample\-fcgi\.c](https://kristaps.bsd.lv/kcgi/sample-fcgi.c.html)\(C and FastCGI\), or jump to the[Documentation](https://kristaps.bsd.lv/kcgi/#usage)section\.
*kcgi*supports many features: auto\-compression, handling of all HTTP input operations \(query strings, cookies, page bodies, multipart\) with validation, authentication, configurable output caching, request debugging, formatted writers \(JSON, XML, etc\.\) and so on\. Its strongest differentiating feature is using sandboxing and process separation for handling the untrusted input path\.
## current release
- Version1\.0\.1:2025\-11\-17 Hot\-fix 1\.0\.0 with proper naming of Mac OS X shared libraries, which use a different convention of version suffix than other Unix\-like systems\.
\([release archive](https://kristaps.bsd.lv/kcgi/archive.html)\)
## installation
First, check ifkcgiisn't already packaged for your system, such as with`pkg\_add kcgi`\(OpenBSD\),`pkg install kcgi`\(FreeBSD\),`brew install kcgi`\(brew\),`pacman \-S kcgi`\(Arch Linux\), and so on\. If so, install using that system\.
If not,kcgihas been built and run on GNU/[Linux](https://www.linux.org/)\(musl and glibc\),[OpenBSD](https://www.openbsd.org/),[NetBSD](https://www.netbsd.org/),[FreeBSD](https://www.freebsd.org/)\),[Solaris](https://www.oracle.com/solaris/solaris11),[OmniOS](https://omniosce.org/), and[Mac OS X](https://www.apple.com/osx)\(only Mojave and newer\!\) on i386, amd64, powerpc, arm64, and sparc64\. Download[kcgi\.tgz](https://kristaps.bsd.lv/kcgi/snapshots/kcgi.tgz)and verify the archive with[kcgi\.tgz\.sha512](https://kristaps.bsd.lv/kcgi/snapshots/kcgi.tgz.sha512)\. To run bleeding\-edge code between releases, the repository is on[GitHub](https://github.com/kristapsdz/kcgi)\. In both cases, build and install instructions may be found on the repository page\.
The only hard build\-time dependency is BSD make \(`bmake`on Linux\) and[zlib](https://www.zlib.net/)\. If you're running the regression tests \(see[Testing](https://kristaps.bsd.lv/kcgi/#testing)\), you'll also need[libcurl](https://curl.haxx.se/libcurl/)\.
## deployment
To usekcgi, you'll need a web server capable of running CGI or FastCGI\.[Apache](https://httpd.apache.org/),[nginx](https://nginx.org/), and OpenBSD's[httpd\(8\)](https://man.openbsd.org/httpd.8)have all been used extensively, with the latter two natively over FastCGI and via the`slowcgi`wrapper\.
To compilekcgiapplications, use the package configuration\. Linking is similarly normative\.
```
% cc `pkg-config --cflags kcgi` -c yourprog.c
% cc yourprog.o `pkg-config --libs kcgi`
```
Well\-deployed web servers, such as the default[OpenBSD](https://www.openbsd.org/)server, by default are deployed within a[chroot\(2\)](https://man.openbsd.org/chroot.2)\. If this is the case, you'll need to statically link your binary \(or pull all shared libraries into the shadow root\)\.
```
% cc -static yourprog.o `pkg-config --static --libs kcgi`
```
FastCGI applications may either be started directly by the web server \(which is popular with[Apache](https://httpd.apache.org/)\) orexternallygiven a socket and[kfcgi\(8\)](https://kristaps.bsd.lv/kcgi/kfcgi.8.html)\(this method is normative for OpenBSD's[httpd\(8\)](https://man.openbsd.org/httpd.8)and suggested for the security precautions taken by the wrapper\)\.
## documentation
Thekcgimanpages, starting with[kcgi\(3\)](https://kristaps.bsd.lv/kcgi/kcgi.3.html), are the canonical source of documentation\. The following is a list of all manpages:
- [kcgi\.3](https://kristaps.bsd.lv/kcgi/kcgi.3.html)
- [kcgi\_buf\_printf\.3](https://kristaps.bsd.lv/kcgi/kcgi_buf_printf.3.html)
- [kcgi\_buf\_putc\.3](https://kristaps.bsd.lv/kcgi/kcgi_buf_putc.3.html)
- [kcgi\_buf\_puts\.3](https://kristaps.bsd.lv/kcgi/kcgi_buf_puts.3.html)
- [kcgi\_buf\_write\.3](https://kristaps.bsd.lv/kcgi/kcgi_buf_write.3.html)
- [kcgi\_strerror\.3](https://kristaps.bsd.lv/kcgi/kcgi_strerror.3.html)
- [kcgi\_writer\_disable\.3](https://kristaps.bsd.lv/kcgi/kcgi_writer_disable.3.html)
- [kcgi\_writer\_free\.3](https://kristaps.bsd.lv/kcgi/kcgi_writer_free.3.html)
- [kcgi\_writer\_get\.3](https://kristaps.bsd.lv/kcgi/kcgi_writer_get.3.html)
- [kcgi\_writer\_putc\.3](https://kristaps.bsd.lv/kcgi/kcgi_writer_putc.3.html)
- [kcgi\_writer\_puts\.3](https://kristaps.bsd.lv/kcgi/kcgi_writer_puts.3.html)
- [kcgi\_writer\_write\.3](https://kristaps.bsd.lv/kcgi/kcgi_writer_write.3.html)
- [kcgihtml\.3](https://kristaps.bsd.lv/kcgi/kcgihtml.3.html)
- [kcgijson\.3](https://kristaps.bsd.lv/kcgi/kcgijson.3.html)
- [kcgiregress\.3](https://kristaps.bsd.lv/kcgi/kcgiregress.3.html)
- [kcgixml\.3](https://kristaps.bsd.lv/kcgi/kcgixml.3.html)
- [kfcgi\.8](https://kristaps.bsd.lv/kcgi/kfcgi.8.html)
- [khtml\_attr\.3](https://kristaps.bsd.lv/kcgi/khtml_attr.3.html)
- [khtml\_close\.3](https://kristaps.bsd.lv/kcgi/khtml_close.3.html)
- [khtml\_closeelem\.3](https://kristaps.bsd.lv/kcgi/khtml_closeelem.3.html)
- [khtml\_closeto\.3](https://kristaps.bsd.lv/kcgi/khtml_closeto.3.html)
- [khtml\_double\.3](https://kristaps.bsd.lv/kcgi/khtml_double.3.html)
- [khtml\_elem\.3](https://kristaps.bsd.lv/kcgi/khtml_elem.3.html)
- [khtml\_elemat\.3](https://kristaps.bsd.lv/kcgi/khtml_elemat.3.html)
- [khtml\_entity\.3](https://kristaps.bsd.lv/kcgi/khtml_entity.3.html)
- [khtml\_int\.3](https://kristaps.bsd.lv/kcgi/khtml_int.3.html)
- [khtml\_ncr\.3](https://kristaps.bsd.lv/kcgi/khtml_ncr.3.html)
- [khtml\_open\.3](https://kristaps.bsd.lv/kcgi/khtml_open.3.html)
- [khtml\_printf\.3](https://kristaps.bsd.lv/kcgi/khtml_printf.3.html)
- [khtml\_putc\.3](https://kristaps.bsd.lv/kcgi/khtml_putc.3.html)
- [khtml\_puts\.3](https://kristaps.bsd.lv/kcgi/khtml_puts.3.html)
- [khtml\_write\.3](https://kristaps.bsd.lv/kcgi/khtml_write.3.html)
- [khttp\_body\.3](https://kristaps.bsd.lv/kcgi/khttp_body.3.html)
- [khttp\_datetime2epoch\.3](https://kristaps.bsd.lv/kcgi/khttp_datetime2epoch.3.html)
- [khttp\_epoch2datetime\.3](https://kristaps.bsd.lv/kcgi/khttp_epoch2datetime.3.html)
- [khttp\_epoch2str\.3](https://kristaps.bsd.lv/kcgi/khttp_epoch2str.3.html)
- [khttp\_epoch2tms\.3](https://kristaps.bsd.lv/kcgi/khttp_epoch2tms.3.html)
- [khttp\_fcgi\_free\.3](https://kristaps.bsd.lv/kcgi/khttp_fcgi_free.3.html)
- [khttp\_fcgi\_getfd\.3](https://kristaps.bsd.lv/kcgi/khttp_fcgi_getfd.3.html)
- [khttp\_fcgi\_init\.3](https://kristaps.bsd.lv/kcgi/khttp_fcgi_init.3.html)
- [khttp\_fcgi\_parse\.3](https://kristaps.bsd.lv/kcgi/khttp_fcgi_parse.3.html)
- [khttp\_fcgi\_test\.3](https://kristaps.bsd.lv/kcgi/khttp_fcgi_test.3.html)
- [khttp\_free\.3](https://kristaps.bsd.lv/kcgi/khttp_free.3.html)
- [khttp\_head\.3](https://kristaps.bsd.lv/kcgi/khttp_head.3.html)
- [khttp\_parse\.3](https://kristaps.bsd.lv/kcgi/khttp_parse.3.html)
- [khttp\_printf\.3](https://kristaps.bsd.lv/kcgi/khttp_printf.3.html)
- [khttp\_putc\.3](https://kristaps.bsd.lv/kcgi/khttp_putc.3.html)
- [khttp\_puts\.3](https://kristaps.bsd.lv/kcgi/khttp_puts.3.html)
- [khttp\_template\.3](https://kristaps.bsd.lv/kcgi/khttp_template.3.html)
- [khttp\_templatex\.3](https://kristaps.bsd.lv/kcgi/khttp_templatex.3.html)
- [khttp\_urlabs\.3](https://kristaps.bsd.lv/kcgi/khttp_urlabs.3.html)
- [khttp\_urldecode\.3](https://kristaps.bsd.lv/kcgi/khttp_urldecode.3.html)
- [khttp\_urlencode\.3](https://kristaps.bsd.lv/kcgi/khttp_urlencode.3.html)
- [khttp\_urlpart\.3](https://kristaps.bsd.lv/kcgi/khttp_urlpart.3.html)
- [khttp\_write\.3](https://kristaps.bsd.lv/kcgi/khttp_write.3.html)
- [khttpbasic\_validate\.3](https://kristaps.bsd.lv/kcgi/khttpbasic_validate.3.html)
- [khttpdigest\_validate\.3](https://kristaps.bsd.lv/kcgi/khttpdigest_validate.3.html)
- [kjson\_array\_close\.3](https://kristaps.bsd.lv/kcgi/kjson_array_close.3.html)
- [kjson\_array\_open\.3](https://kristaps.bsd.lv/kcgi/kjson_array_open.3.html)
- [kjson\_close\.3](https://kristaps.bsd.lv/kcgi/kjson_close.3.html)
- [kjson\_obj\_close\.3](https://kristaps.bsd.lv/kcgi/kjson_obj_close.3.html)
- [kjson\_obj\_open\.3](https://kristaps.bsd.lv/kcgi/kjson_obj_open.3.html)
- [kjson\_open\.3](https://kristaps.bsd.lv/kcgi/kjson_open.3.html)
- [kjson\_putbool\.3](https://kristaps.bsd.lv/kcgi/kjson_putbool.3.html)
- [kjson\_putdouble\.3](https://kristaps.bsd.lv/kcgi/kjson_putdouble.3.html)
- [kjson\_putint\.3](https://kristaps.bsd.lv/kcgi/kjson_putint.3.html)
- [kjson\_putnull\.3](https://kristaps.bsd.lv/kcgi/kjson_putnull.3.html)
- [kjson\_putstring\.3](https://kristaps.bsd.lv/kcgi/kjson_putstring.3.html)
- [kjson\_string\_close\.3](https://kristaps.bsd.lv/kcgi/kjson_string_close.3.html)
- [kjson\_string\_open\.3](https://kristaps.bsd.lv/kcgi/kjson_string_open.3.html)
- [kjson\_string\_write\.3](https://kristaps.bsd.lv/kcgi/kjson_string_write.3.html)
- [kmalloc\.3](https://kristaps.bsd.lv/kcgi/kmalloc.3.html)
- [kutil\_invalidate\.3](https://kristaps.bsd.lv/kcgi/kutil_invalidate.3.html)
- [kutil\_log\.3](https://kristaps.bsd.lv/kcgi/kutil_log.3.html)
- [kutil\_openlog\.3](https://kristaps.bsd.lv/kcgi/kutil_openlog.3.html)
- [kvalid\_string\.3](https://kristaps.bsd.lv/kcgi/kvalid_string.3.html)
- [kxml\_close\.3](https://kristaps.bsd.lv/kcgi/kxml_close.3.html)
- [kxml\_open\.3](https://kristaps.bsd.lv/kcgi/kxml_open.3.html)
- [kxml\_pop\.3](https://kristaps.bsd.lv/kcgi/kxml_pop.3.html)
- [kxml\_popall\.3](https://kristaps.bsd.lv/kcgi/kxml_popall.3.html)
- [kxml\_prologue\.3](https://kristaps.bsd.lv/kcgi/kxml_prologue.3.html)
- [kxml\_push\.3](https://kristaps.bsd.lv/kcgi/kxml_push.3.html)
- [kxml\_pushnull\.3](https://kristaps.bsd.lv/kcgi/kxml_pushnull.3.html)
- [kxml\_putc\.3](https://kristaps.bsd.lv/kcgi/kxml_putc.3.html)
- [kxml\_puts\.3](https://kristaps.bsd.lv/kcgi/kxml_puts.3.html)
- [kxml\_write\.3](https://kristaps.bsd.lv/kcgi/kxml_write.3.html)
Alternatively, the following are introductory materials to the system:
- ### [Getting Started with CGI in C](https://kristaps.bsd.lv/kcgi/tutorial0.html) This tutorial describes a typical CGI example usingkcgi\. In it, I'll process HTML form input with two named fields,`string`\(a non\-empty, unbounded string\) and`integer`, a signed 64\-bit integer\. I'll then output the input within a simple HTML page\. The tutorial will be laid out in code snippets, which I'll put together at the end\. I'll then follow with compilation instructions\.
- ### [Getting and Setting CGI Cookies in C](https://kristaps.bsd.lv/kcgi/tutorial1.html) Cookies are an integral part of any web application\. In this tutorial, I'll describe how to use the HTTP header functionality inkcgito set, recognise, and store cookies\.
- ### [FastCGI Deployments](https://kristaps.bsd.lv/kcgi/tutorial2.html) FastCGI allows for much higher throughput by running web applications as daemons\. In this tutorial, I'll describe how to deploy a simple FastCGI application using[kfcgi\(8\)](https://kristaps.bsd.lv/kcgi/kfcgi.8.html)\.
- ### [Custom Validation](https://kristaps.bsd.lv/kcgi/tutorial3.html) Applications often need to validate more then doubles, integers, or strings included in[kvalid\_string\(3\)](https://kristaps.bsd.lv/kcgi/kvalid_string.3.html)\. In this tutorial, I'll provide some examples on how to override the validation function\.
- ### [Using Pages](https://kristaps.bsd.lv/kcgi/tutorial4.html) The tutorial gives an overview of the basic path handling provided bykcgi, and then shows and discusses relevant code snippets\.
- ### [CGI for C\+\+ applications](https://kristaps.bsd.lv/kcgi/tutorial5.html) kcgisupports C\+\+ callers just as easily as C\. In this brief tutorial I'll take you through compiling a C\+\+ application that uses thekcgilibrary\.
- ### [Best practises for pledge\(2\) security](https://kristaps.bsd.lv/kcgi/tutorial6.html) Let's set the record straight for securingkcgiCGI and FastCGI applications with[pledge\(2\)](https://man.openbsd.org/pledge.2)\. This is focussed on secure[OpenBSD](https://www.openbsd.org/)deployments\.
- ### [CORS and kcgi](https://kristaps.bsd.lv/kcgi/tutorial7.html) This article isn't about CORS \(cross\-origin resource sharing\) but rather the enumerations and functions available in[kcgi\(3\)](https://kristaps.bsd.lv/kcgi/kcgi.3.html)to handle CORS requests\.
In addition to these resources, the following conference sessions have referencedkcgi\.
- Dzonsons, Kristaps\.*Role\-based Access Control in BCHS Web Applications*\. Proceedings of[AsiaBSDCon](https://2018.asiabsdcon.org/), Tokyo, Japan, March 2018\. \([Slides](https://kristaps.bsd.lv/absdcon2018),[video](https://www.youtube.com/watch?v=FzF9e4jrnJ4)\.\)[paper](https://kristaps.bsd.lv/absdcon2018/paper.pdf)\.\)
- Dzonsons, Kristaps\.*Secure BSD Web Applications in C: Practical Strategies*\. Proceedings of[AsiaBSDCon](https://2017.asiabsdcon.org/), Tokyo, Japan, March 2017\. \([Slides](https://kristaps.bsd.lv/absdcon2017)\.\)
- Dzonsons, Kristaps\.*Secure BSD Web Application Development in C*\. Proceedings of[AsiaBSDCon](https://2016.asiabsdcon.org/), Tokyo, Japan, March 2016\. \([Slides](https://kristaps.bsd.lv/absdcon2016)\.\)
- Dzonsons, Kristaps\.*kcgi: securing CGI applications in C*\. Proceedings of[AsiaBSDCon](https://2015.asiabsdcon.org/), Tokyo, Japan, March 2015\. \([Slides](https://kristaps.bsd.lv/absdcon2015/talk.pdf),[paper](https://kristaps.bsd.lv/absdcon2015/paper.pdf)\.\)
And the following relate to extending standards:
- Dzonsons, Kristaps\.[FastCGI Extensions for Management Control](https://kristaps.bsd.lv/kcgi/extending01.html)\. March 2016\.
## implementation details
The bulk ofkcgi's CGI handling lies in[khttp\_parse\(3\)](https://kristaps.bsd.lv/kcgi/khttp_parse.3.html), which fully parses the HTTP request\. Application developers must invoke this function before all others\. For FastCGI, this function is split between[khttp\_fcgi\_init\(3\)](https://kristaps.bsd.lv/kcgi/khttp_fcgi_init.3.html), which initialises context; and[khttp\_fcgi\_parse\(3\)](https://kristaps.bsd.lv/kcgi/khttp_fcgi_parse.3.html), which receives new parsed requests\. In either case, requests must be freed by[khttp\_free\(3\)](https://kristaps.bsd.lv/kcgi/khttp_free.3.html)\.
All functions isolate the parsing and validation of untrusted network data within a*sandboxed*child process\. Sandboxes limit the environment available to a process, so exploitable errors in the parsing process \(or validation with third\-party libraries\) cannot touch the system environment\. This parsed data is returned to the parent process over a socket\. In the following, the*HTTP parser*and*input validator*manage a single HTTP request, while*connection delegator*accepts new HTTP requests and passes them along\.
This method of sandboxing the untrusted parsing process follows[OpenSSH](http://www.openssh.org/), and requires special handling for each operating system:
[seccomp\(2\)](http://man7.org/linux/man-pages/man2/seccomp.2.html)\(Linux\)This requires a seccomp\-enabled Linux kernel and a recognised hardware architecture\. It is supplemented by`setrlimit\(2\)`limiting\.[pledge\(2\)](https://man.openbsd.org/pledge.2)\([OpenBSD](https://www.openbsd.org/)\)This will only work on OpenBSD \>5\.8\.[sandbox\_init\(3\)](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/sandbox_init.3.html)\([Apple OSX](https://www.apple.com/osx/)\)This uses the sandboxing profile forpure computationas provided in Mac OS X Leopard and later\. This is supplemented by resource limiting via`setrlimit\(2\)`\.[capsicum\(4\)](https://www.freebsd.org/cgi/man.cgi?query=capsicum&sektion=4)\([FreeBSD](https://www.freebsd.org/)\)Uses the capabilities facility on[FreeBSD](https://www.freebsd.org/)10 and later\. This is supplemented by resource limiting with`setrlimit\(2\)`\.Since validation occurs within the sandbox, special care must be taken that validation routines don't access the environment \(e\.g\., by opening files, network connections, etc\.\), as the child**might**be abruptly killed by the sandbox facility\. \(Not all sandboxes do this\.\) If required, this kind of validation can take place after the parse validation sequence\.
The connection delegator is similar, but has different sandboxing rules, as it must manage an open socket connection and respond to new requests\.
## testing
kcgiis shipped with a fully automated testing framework executed with`make regress`\. To test your own applications, use the[kcgiregress\(3\)](https://kristaps.bsd.lv/kcgi/kcgiregress.3.html)library\. This framework acts as a mini\-webserver, listening on a local port, translating an HTTP document into a minimal CGI request, and passing the request to akcgiCGI client\. For internal tests, test requests are constructed with[libcurl](https://curl.haxx.se/libcurl/)\. The binding local port is fixed: if you plan on running the regression suite, you may need to tweak its access port\.
The testing framework is used by the GitHub[Actions](https://github.com/kristapsdz/kcgi/actions)to make sure that all commits pass the regression tests on all supported systems \(including with compiler sanitisation\)\.
Another testing framework exists for use with the[American fuzzy lop](http://lcamtuf.coredump.cx/afl/)\. To use this, you'll need to compile the`make afl`target with your compiler of choice, e\.g\.,`make clean`, then`make afl CC=afl\-gcc`\. Then run the`afl\-fuzz`tool on the`afl\-multipart`,`afl\-plain`, and`afl\-urlencoded`binaries using the test cases \(and dictionaries, for the first\) provided\.
## performance
Security comes at a price—but not a stiff price\. By design,kcgiincurs overhead in three ways: first, spawning a child to process the untrusted network data; second, enacting the sandbox framework; and third, passing parsed pairs back to the parent context\. In the case of running CGI scripts,kcgiperformance is bound to the operating system's ability to spawn and reap processes\. For FastCGI, the bottleneck becomes the transfer of data\.