Tue, 19 Nov 2013

A really simple server ... that really makes me happy

I just completed my first source code edit and custom recompile. In C, no less.

Granted, the program I modified is all of 200 lines long. And its author told me exactly how to customize it for my purposes. But still. It makes me inordinately happy that I succeeded.

A while ago I came across nweb, a program by Nigel Griffiths at IBM. The article summary from that link:

Have you ever wondered how a Web server actually works? Experiment with nweb -- a simple Web server with only 200 lines of C source code. In this article, Nigel Griffiths provides a copy of this Web server and includes the source code as well. You can see exactly what it can and can't do.

So, that's great. Nweb basically just serves static files and cannot run any server side scripts. It's basically meant to show how the very fundamentals of a web server work: receiving requests, handling them, keeping the connection open, the very basics. In the README, Griffiths writes that he originally wrote it in 100 lines of code and "[that] worked fine too but then [I] added comments, file type checks, security checks, sensible directory checks and logging". You get the idea: 200 lines of code that are written just to make the most minimum steps of a http request work, and do a few checks to make sure nothing dangerous happens, and no more. Oh, and log what happens so that people looking at the code to learn how this web thing works get some information about what's happening.

In the article, in describing nweb's features, Griffiths lists the filetypes which it can serve:

nweb only transmits the following types of files to the browser :

  • Static Web pages with extensions .html or .htm
  • Graphical images such as .gif, .png, .jgp, or .jpeg
  • Compressed binary files and archives such as .zip, .gz, and .tar

And he adds:

If your favorite static file type is not in this list, you can simply add it in the source code and recompile to allow it.

Well, I was musing and thought that nweb was maybe just a bit too simplistic: I think css at least is a fundamental part of a real website. But then I remembered that I have poked around in C files before, and I thought I might give it a try. So here's a really brief not-quite-tutorial runthrough of how I served real web pages with nweb.

Compile nweb

The instructions in the README.txt file were pretty complete. After downloading and extracting the source code, I opened up the C file and sure enough, found a 'struct' as follows:

struct {
    char *ext;
    char *filetype;
} extensions [] = {
    {"gif", "image/gif" },  
    {"jpg", "image/jpg" }, 
    {"jpeg","image/jpeg"},
    {"png", "image/png" },  
    {"ico", "image/ico" },  
    {"zip", "image/zip" },  
    {"gz",  "image/gz"  },  
    {"tar", "image/tar" },  
    {"htm", "text/html" },  
    {"html","text/html" },  
    {0,0} };

This looked pretty self-explanatory. My code edit was simply a matter of adding a line:

{"css","text/css"},

before the last line of this block, to associate the file extension .css with the content type text/css. With this, nweb would know that requests for URLs ending in '.css' should be accepted and handled and it should pass the content type 'text/css' back to the browser.

Then it was a matter of compiling nweb, following the instructions in the README. A compiled binary was provided in the download (in fact, several for several different architectures were included), but I replaced it with the command:

cc nweb23.c -o nweb

This compiles the source code written in the C language (which I edited above) into a machine-code executable -- written in ones and zeroes that the computer can understand.

Starting the web server

All of this is happening on a local server I have. Now that we have the modified executable, we just need to start it up and see if it works. I won't go into the details but here is my setup:

  • nweb runs as a normal user out of the user's ~/bin directory
  • I'll run it on port 8181 so it doesn't conflict with the server's Apache web server.

We start nweb:

/home/user/bin/nweb 8181 /home/user/web

This starts nweb and tells it to listen on port 8181 and serve files from /home/user/web.

The test website

Here's the html of the file I want to view:

<!DOCTYPE html>
<html>
    <head>
        <title>A simple site</title>
        <link rel="stylesheet" type="text/css" href="simple.css">
    </head>
    <body>
        <p>Hello, world! This was served with nweb!</p>
        <p class="styled">And I compiled nweb with css support. It wasn't very hard.</p>
    </body>
</html>

There are two paragraphs, one with a class that I will target with a css rule from the linked file simple.css. Here's the only line in that file:

.styled{font-size: 20px}

So, if my modified nweb executable works, I should not only see the html file, but the second paragraph should be bigger than the first.

And sure enough!

Here is a screenshot of the test website opened in my browser. I've opened up the developer console to show the structure of the html, including the one-line content of the css file (click to open a larger image).

screenshot-nweb-serving-css

Making sure I'm not kidding myself

For completeness' sake, I thought I would demonstrate that the changes I made to the source code are actually effective. So I undid the changes and compiled the source again into a second file named nweb2. I stopped the nweb server and started it again by running this second version of nweb. This is what the output looks like now:

screenshot-nweb-refusing-css

Again, click the image to view a larger copy. You can see that instead of the contents of the css file, we've been given a quite informative error message from 'this simple static file webserver'.

And that is how you modify source code to suit your needs ;)

Oh, and I'm still smiling with the sheer simplicity of this little web server. I look forward to reading it's documentation to learn more about how this and all other web servers work.