Extremely simple HTTP
int, unsigned int,
*, char *,
HttpServer builds on the
Http(3) API, and provides a very simple, yet very functional API for
creating an HTTP server. It aims at being easy to use and minimal, yet also
efficient. It uses non-blocking I/O, is fully multi-threaded, very
configurable, yet also able to be set up in just two function calls.
This API should be familiar to those that have dealt with the HTTP server libraries of other programming languages, particularly Java. In fact, much of the terminology used in this code came from Java, and you'll notice that the way responses are sent and received very closely resemble the way it's done in Java.
An HTTP server itself is created with
which takes the port number to create the server on, the number of threads
to use, the maximum number of connections, a request handler function, and
the arguments to that function, in that order. The request handler function
is of the following type:
typedef void (HttpHandler) (HttpServerContext *, void *)
Where the void pointer received is the
same pointer that was passed into
as the last parameter.
The returned HttpServer pointer is then
HttpServerStart() attempts to start the HTTP server,
and returns immediately with the status. This API is fully threaded and
asyncronous, so the caller can continue working while the HTTP server is
running in a separate thread, and managing a pool of threads to handle
responses. Typically at some point after calling
HttpServerStart(), the program will have no more
work to do, and so it will want to wait for the HTTP server to finish. This
is accomplished with
HttpServerJoin(), which joins
the HTTP worker thread to the calling thread, making the calling thread wait
until the HTTP server has stopped.
The only condition that will cause the HTTP
server to stop is when
is invoked. This will typically happen in a signal handler that catches
signals instructing the program to shut down. Only after the server has been
stopped can it be freed with
Note that calling
HttpServerFree() while the server
is running results in undefined behavior.
The remainder of the functions in this API
are used inside of the HTTP handler function passed by the caller of
They allow the handler to figure out the context of an HTTP request, which
includes the path that was requested, any parameters, and the headers used
to make the request. They also allow the handler to respond with a status
code, headers, and a body.
get the information about the request. They should all be passed the server
context pointer that was passed into the handler function. The data returned
by these functions should be treated as read-only, and should not be freed;
their memory is handled outside of the HTTP server handler function.
are used to set response headers, and the response status of the request,
returns a stream that is both readable and writable. Reading from the stream
reads the request body that the client sent, if there is one. Note that the
request headers have already been read, so the stream is correctly
positioned at the beginning of the body of the request.
must be called before the stream is written to, otherwise a malformed HTTP
response will be sent. An HTTP handler should properly set all the headers
it intends to send, send those headers, and then write the response body to
the stream. Finally, note that the stream does not need to be closed by the
HTTP handler; in fact, doing so results in undefined behavior. The stream is
managed by the server itself.
HttpRequestParams() return a hash map that can be
used to access the request headers and parameters, if necessary. Note that
the request parameters would be GET parameters, attached to the path that
was requested. To get POST parameters, read the stream returned by
HttpStream() and pass the contents into
HttpParamDecode() to get a hash map.
HttpRequestPath() returns a string that
represents the path that the client requested. Note that it is not
normalized; it is exactly what the client sent, so it should be checked for
path traversal attacks and other malformed paths that the client may
HttpResponseHeader() returns the previous
value of the given header, or NULL if there was no previous value.
HttpStream() returns a FILE pointer that
can be read and written using the C standard I/O functions.