dweb: a lightweight portable webserver in C

I've been continuing to experiment with the source code to 'nweb' (a minimal web server written in C). In fact, I've probably experimented so much that I've changed most of the code beyond recognition by now. But I'm still calling my version 'dweb' in honour of the original.

Since the C# webserver I wrote ages ago has proved quite popular, I thought that I'd try something similar in C. I realised that I should be able to produce a lightweight little web server, which could also be a starting point for some other things I have in mind. Since I'm not using any external libraries, there are no dependencies to worry about. Well, OK I have used the POSIX thread library, but it can be taken out by changing a #define.

I'm attempting to make something which can easily be adapted, where you simply need to write a function which assembles your html response and everything else is done for you. So I'm making use of C function pointers for that. All you need to do is write your custom "responder" function (using the correct signature) and then call my webserver function, passing in a pointer to your own responder function.

That way, by adding a single C file to a project and writing a few lines of code you can have an embedded web server - albeit a very simple one of course.

Obviously I'm not attempting to write a fully featured web server platform, but this is the type of hobbyist project you could run on a Raspberry Pi to create a very simple web interface for something, whilst keeping it very lightweight and low on dependencies. It might work on different types of embedded Linux too (I'd be quite interested to know if it does).

But for my purposes, it will be an easy way to provide a simple web based API, where I can send commands with an http POST or just retrieve data by sending a GET.

But my main aim was to make a custom webserver possible in C with just a few lines of additional code. Being portable, it should run on Mac OS X, Linux (including Android) and even Windows if Cygwin is installed. It certainly worked OK on the Raspberry Pi and I've also used it on my Android tablet.

Since I've included support for HTTP POST (which nweb didn't have) it means that simple form posting scenarios will work, and Ajaxy type stuff should even work. The example code I've written allows HTML form values to be submitted. It also includes a simple Ajax call where a parameter is sent to the server and a return value comes back in the response.

So how does the code look? Well, here is the simplest (trivial) implementation:

void test_response(struct hitArgs *args,
   char *path, char *request_body, http_verb type)
{
    ok_200(args,
        "<html><head><title>Test Page</title></head>"
        "<body><h1>Testing...</h1>This is a test response.</body>"
        "</html>", path);
}

int main(int argc, char **argv)
{
    if (argc != 2 || !strcmp(argv[1], "-?"))
    {
        printf("hint: dweb [port number]\n");
        exit(0);
    }
    dwebserver(atoi(argv[1]), &test_response, NULL);
}

Not too bad - but it just gives the same response to every incoming request. The full source code includes more advanced examples showing an HTML form posting back some values. It also shows an Ajax call using jQuery.

Like 'nweb', it started out as a multi-process server, where each request spawned a new process using fork(). But I am now including support for single-threaded and multi-threaded modes as well, the default being multi-threaded.

Anyway, the source code is on GitHub, if you're interested (released under the MIT license). Meanwhile, I'll keep tinkering with it...

Running 'nweb' on Mac OS X

For some time I've admired the simple web server code called nweb, which can be found here. It's written in C and shows how you can build a nice simple little HTTP server without scary amounts of code. The code even runs on the Raspberry Pi.

It's written for Unix and Linux systems, but I wanted to see if it would work on my MacBook (which runs Mac OS X, obviously). Since Mac OS X has a Unix heritage, I hoped it would work without too much trouble...

So I fired up Xcode and created a blank "Command Line" application in C, then I just pasted in the nweb source code. It gave just one compilation error.

All I needed to do was replace SIGCLD with SIGCHLD in one line of code. Then it worked! Nice.

So that's awesome, a very handy little command line web server for Mac OS X.

I'm sure I will find a use for that. The old brain cogs are whirring as I type this in fact.