this is not an open-source project per se, but more of an example of writing an https server in pure c with just openssl and posix. due to lack of time, i can't go in great detail, so i will give a brief summary.
the server can automatically recompile itself and rerun upon detecting a new file (while also adding the file to the server's paths) this is done using a watcher that executes regenmain when inotify detects a change in the html directory.
the flow is as follows.
- [regenmain] already compiled
- [server] edits the [.blog_pid] file with its own process id (pid) and starts
- [server_watcher] starts and grabs the value from [.blog_pid]
- [user] creates a [server_somefile.html] in the [html] directory or modifies one of the files
- [server_watcher] detects the change via [inotify]
- [server_watcher] uses the pid from [.blog_pid] to kill [server]
- [server_watcher] runs [regenmain] to parse the [html] directory and codegenerate the [server.c] file with the
new added file (or files), or, if no file is added, then the kill to [server] was sent because of a change in a file,
in which case no new file is added.
- [server_watcher] after [regenmain] finishes to run, the binary, [server], is run again, and the server is up with all the new files or
any changes to any file.
The server uses html files as individual components. It works putting a header, body, content(individual .html components) and tail together and ship it to OpenSSL to write. Any CSS/JS is within one of these four files. There are two reasons for this:
- If files are split into different
.css,.jsand.htmlfiles, it will take 3 requests to get all of them. This way, it takes only 1 request. - Because they're all in one place, it is very easy to make changes and reason about what a component is doing.
The server uses threading for running in parallel, and a goto dispatcher for http methods. To respond to an endpoint, it uses an index into an array of components. Because the header, body and tail are always the same, and only the content changes, the index is used to pull the data about that content and create the entire response. I am using a string interning library that I wrote, such that checks against entire html pages, regardless of size, are always O(1). This is possible because the html files are read by the library once and matching is simply matching the index of the string inside the array, plus the length. Here is the code for checking if two strings, of any size, are the same:
static inline bool scrt_strcmp(SString target, SString source)
{
return target.str == source.str && target.len == source.len;
}
That's all!
There is a do_not_use_me directory with a old_server_watcher.c file. Before I knew about inotify, I did not know about inotify so I had to write something like inotify It isn't as clean as inotify, obviously, because you apparently can't do a better job than the OS at detecting changes in directories, who would've thought. DO NOT USE THAT FILE unless your dimension does not have inotify. Seriously!