A Linux, threaded HTTP library and basic webserver for creating REST services in C.
make lib
make example
#include "server.h"
int helloworld_handler(bhttp_request *req, bhttp_response *res);
int
main(int argc, char **argv)
{
bhttp_server *server = bhttp_server_new();
if (server == NULL) return 1;
bhttp_server_set_ip(server, "0.0.0.0");
bhttp_server_set_port(server, "8989");
bhttp_server_set_docroot(server, "./www");
bhttp_server_set_dfile(server, "index.html");
bhttp_add_simple_handler(server,
BHTTP_GET | BHTTP_POST, // declare supported http methods
"/helloworld", // pattern to match uri path
helloworld_handler); // callback function pointer
bhttp_server_start(server, 0);
return 0;
}
The second argument to bhttp_server_start
decides how the server is started. Setting own_thread
to 1 will start bittyhttp
in a separate thread and return immediately. It is then up to the caller to later call bhttp_server_stop
and bhttp_server_free
.
While running in a separate thread, it is possible for the caller to add new handlers.
Alternatively, setting own_thread
to 0 with take over the calling thread and will never return unless bittyhttp
encounters an error.
In addition to simply serving files, bittyhttp
also has several different handler types that the user can define. Check out examples/examples.c
for even more examples.
Handlers are matched in the order they are added. If two handlers would match the same uri path, then the handler added first will get the callback.
Simple handlers must match the uri path exactly.
int
helloworld_handler(bhttp_request *req, bhttp_response *res)
{
/* business logic */
bstr bs;
bstr_init(&bs);
bstr_append_printf(&bs, "<html><p>Hello, world! from URL: %s</p><p>%s</p><p>%s</p></html>",
bstr_cstring(&req->uri),
bstr_cstring(&req->uri_path),
bstr_cstring(&req->uri_query));
bhttp_res_set_body_text(res, bstr_cstring(&bs));
bstr_free_contents(&bs);
/* add custom headers and response code */
bhttp_res_add_header(res, "content-type", "text/html");
res->response_code = BHTTP_200_OK;
return 0;
}
bhttp_add_simple_handler(&server, BHTTP_GET, "/helloworld", helloworld_handler);
Regex handlers use Linux's POSIX regex library to match on the uri path. Any matched groups will also be passed to the handler function.
int
helloworld_regex_handler(bhttp_request *req, bhttp_response *res, bvec *args)
{
/* business logic */
bstr bs;
bstr_init(&bs);
bstr_append_printf(&bs, "<html><p>Hello, Regex world! from URL: %s</p><p>%s</p><p>%s</p>",
bstr_cstring(&req->uri),
bstr_cstring(&req->uri_path),
bstr_cstring(&req->uri_query));
/* check the request for a specific header */
bhttp_header *h = bhttp_req_get_header(req, "accept-encoding");
if (h)
bstr_append_printf(&bs, "<p><b>accept-encoding</b>: %s</p>", bstr_cstring(&h->value));
/* add all Regex matched groups to our output */
for (int i = 0; i < bvec_count(args); i++)
{
bstr *arg = bvec_get(args, i);
bstr_append_printf(&bs, "<p>arg: %d: %s</p>", i, bstr_cstring(arg));
}
bstr_append_cstring_nolen(&bs, "</html>");
bhttp_res_set_body_text(res, bstr_cstring(&bs));
bstr_free_contents(&bs);
/* custom headers and response code */
bhttp_res_add_header(res, "content-type", "text/html");
res->response_code = BHTTP_200_OK;
return 0;
}
bhttp_add_regex_handler(&server, BHTTP_GET | BHTTP_HEAD, "^/api/([^/]+)/([^/]+)$", helloworld_regex_handler);
Instead of using bhttp_res_set_body_text
, we can use the function bhttp_set_body_file_rel/abs
to return a file. This is more efficient than than supplying the binary data ourselves because sendfile
can avoid unecessary data copying.
bhttp_res_set_body_file_rel
will append the uri path to bittyhttp
s docroot. bhttp_res_set_body_file_abs
will take the given filepath as is, and try to serve it.
If bittyhttp
cannot read the file or the file is not found, a 404 message is returned.
int
rel_file_handler(bhttp_request *req, bhttp_response *res)
{
bhttp_res_set_body_file_rel(res, "/hugo/404.html");
res->response_code = BHTTP_200_OK;
return 0;
}
bhttp_add_simple_handler(&server, BHTTP_GET, "/rel_file", rel_file_handler);
bittyhttp
uses a new thread for each request. It is recommended that only threadsafe functions be used inside callback handlers. Additionally, appropriate structures should be used when callback handlers access the same data: mutexes, pools, etc.
- squid poll - create and share polls for fun. it's squidtastic!
In the future I would like to add the following features to bittyhttp
:
- file/multipart upload support
- Lua integration for handlers
This project would not be possible without the following resources: