How I created a web server for my portfolio

How I created a web server for my portfolio

Hi 👋

I am Eric, a full-stack software engineer at ALX, with experience in DevOps, Front-end, Socket/Network programming, and specializing in Back-end.
My favorite programming language is C ✨ (I love coding in C a lot); maybe it’s because C is the first language I learned as a programmer, though I code in other languages like Python and Javascript (including HTML5 and CSS3 but these are not referred to as programming languages).

The main thing

At ALX(Where I school) it has come to the time where we all (and my peers) had to build good projects that we could attach to our resume as potential software developers.

The main challenge was getting an idea to work on; otherwise, I’d work on the default project given (A 2D Maze game built in C).

For days I was trying to decide what to work on when the idea sprung on me to build an HTTP web server and I was going to do this in C, leveraging the power of C.
Observing that building a web server would be an interesting project, one that will boost a programmer’s reasoning as it requires a lot of logic in its workflow, I decided to go on with it, why did I use C? Because C is awesome! 😎
Here are the workings of a web server including mine:

With plans to create a minimalist web server and continuously update it with more features, I started with the basics–creating a TCP socket, binding it to my server’s address, and listening for incoming connections on a port. At this point, I used a buffer which I filled with static HTML content to serve any request sent in by a web client (browser or curl), regardless of what they’re asking for. This was to test if it worked.

And it worked! Here was the first time my web server worked:

Seeing this, I was filled with a lot of excitement, so, I proceeded to implement a configuration settings feature so I could configure which port it listens on, what folder should it serve web content from, and others.
The challenge here was generating a format for the configuration file. I didn’t want to use XML or YAML, cause I wanted it to be as simple as possible, easy to understand and write. So, I came up with something really simple.

At some point in this project, I encountered a difficult-to-detect bug. What was this bug? An invalid pointer!
While building the configuration engine, a tool that parses through the configuration file and processes its data, I observed that whenever I run the code, I get a free(): invalid pointer message (Where is this coming from?), I ran-searched through my code to see if there were anywhere I was not free()’ing as supposed. After an hour of trying to figure out where this error was from, I decided to use printf() with the address-of-format-specifier as my debugging tool. I placed some printf(“%pn”, &malloced_buff) on certain lines and made it print the addresses of buffers in different areas and it helped in solving the issue.
The result shows that the address(in memory) of this buffer when I freed it was a little bit higher than when I declared it. This is because in the context of the configuration processor(engine), while it parses through lines in a file, it increments the pointer(buffer) by one until it cuts off all the starting tab characters. A diagram to aid in understanding the problem is here:

# This is the configuration file

BLOCK1:
<tab> KEY VALUE
<tab> BLOCK2:
<tab><tab> KEY1 VALUE1
<tab><tab> KEY2 VALUE2
/* This is the C code */

char *line = malloc(SIZE * sizeof(char));

getline(&line, &size, FILE); /* address 1a23fda121 */

/* Skip as many tabs found beginning the line */
while (*line == ‘t’)
line++; /* address 1a23fda121 + 1 */

free(line); /* address 1a23fda123 -> freeing the wrong address in memory */

Then, I was able to use a memory address counter that will count the number of addresses moved forward to by line++, and decrements them as required before free()’ing, and that was it! I no longer get the error Invalid pointer.

Now, it came to the trickiest part of the project–the workflow!
If you’re a socket programmer or a Linux enthusiast, you will know that one of the key features of a web server or any socket-related software/hardware is multi-tasking (e.g. OS). Through some research, I got to know about race conditions–where two or more processes struggle for a resource in a multiprocessing/multithreaded context; One may edit a resource, thereby altering the outcome of another.

Therefore, to have a functional server, there has to be a high level of isolation (or independence).
How did I accomplish this? I tried not to make one function do as much, as when a function does so much, it would be depended on by so many things, which will certainly cause conflict between processes calling it. so I created as many functions/handlers as possible with each handling unit task. This highly maximized independence and made the overall server functional.

With all these and more, I was able to build a fully functional web server in C 😄

Hey Dev Community, it’s a pleasure to be part of you guys.

Do anyone know where I could get fundings for this my little project? so I could expand it. If yes, please kindly reach out to me

Also connect with me via

Linkedin
X
jneric49@gmail.com

If you wanna see the source code, click this. Don’t forget to leave a star

GitHub

Please follow and like us:
Pin Share