In a previous article I discuss a server concept for an ultra simple server implementation. After a little hacking, I can now pronounce uServer, an ultra simple Unix-based server library in less than 256 lines of C.
From the readme (at the time of writing):
uServer is an ultra lightweight Unix server implementation that weighs in under 256 lines (including comments) in a single header file.
Features:
- Fast - It spends minimal time processing clients and runs on a single-thread (which means you can make guarantees about resource usage).
- Small - It is under 256 lines and uses minimal standard/Unix libraries. As a result it compiles at ~15kB.
- Load static files - Loads small files from disk from a single directory.
- Parse variables - Parses variables from the path URL (without decoding) and HTTP header.
- Dumb - It doesn’t do any magic.
There is an example server implementation than can be built and used as a quick reference.
All a person needs to do is include the following:
0001 #include "userver.h"
Implement this function:
0002 char* userver_process(char* req, char* path, char* raw);
And to setup/start the server, add the following lines:
0003 userver_init(port, dir); 0004 userver_loop(loopDelay);
It’s as simple as that.
Based on the following client HTTP request header:
0005 GET /index.html?hello=world HTTP/1.1 0006 Host: 127.0.0.1:9999 0007 User-Agent: basic-browser
In the function userver_process()
, req
by default would be GET
, path
would be /index.html?hello=world
and raw
would be Host: 127.0.0.1:9999<LF>User-Agent: basic-browser
.
When writing the code for userver_process()
there are a few helpful functions worth using:
userver_parselocation()
- Parse the URL path and return a pointer to a NULL terminated string. In the example this would be "/index.html"
.userver_parseparams()
- Parse and return a specific parameter as a NULL terminated string. In this example, with name = "hello"
, the function should return "world"
.userver_parseheader()
- Parse and return a specific header attribute as a NULL terminated string. In this example, with name = "User-Agent"
, the function should return "basic-browser"
.userver_loadfile()
- This function will load a file from disk from the directory dir
as set in userver_init()
. The function refuses to load any file with a directory /
character as a minor security measure 1.From the readme:
- Content MIME type - Some browsers require that the content MIME type is well defined before it will render it correctly (e.g. Chromium).
- Caching - Cache content to prevent loading from disk. It is yet to be seen how this will be done minimally.
As the list says, Chromium makes no effort to interpret data without a MIME type as Mozilla Firefox does 2.
I am still yet to consider what caching may look like. If I implement it from scratch, I imagine I will minimally need:
All in all, I believe this project is a success! As I previously wrote, I believe this could form the basis for a few new projects: