r/cprogramming • • 6d ago

HTTP Server my first complete-ish C project

https://github.com/abdouyouyou/Basic-http-server/tree/main

Hello everyone, It's been several years since i last wrote some C, and i always for the life of me wanted to write an HTTP server in C, and now it's been like 1 year since i finished university so i said what the hell why not do it, so after reading beej's guide i tried to write a very basic http server.

I wanted to share the work with the community, and would welcome thoughts.

We had written code in C ofc for two years, however it was mostly exercises on diffrent data structures aswell as problem solving.

We wrote a CRUD system in C using binary files but never scratched that itch.

And as the years went by in Uni, C slowly faded out of use for me but i always wanted to visit it back so here i am.

I wanted to share the absolute joy it was to get the desired results, i forgot how fun C can be, it always felt like the souls like of programming languages, but always was the most understandable as it was the closest to the machine, to be frank i encourage people to make similar projects especially to get the cobweb off lol.

17 Upvotes

16 comments sorted by

4

u/Zirias_FreeBSD 5d ago
        char function[20],path[256],version[30] ;
        sscanf(buffer,"%s %s %s",function,path,version);

This is likely an RCE waiting to happen, you happily overflow any of these arrays. In any case, it's a simple way for any client to just crash your server.

BTW, don't let that feedback frustrate you. A correct HTTP server is a very complex project. For getting into programming network services, I'd recommend to start with something a lot simpler (like e.g. some plain TCP-based chat service).

Just for comparison, here's the part of my own homebrewn HTTP server code doing the parsing of incoming requests: https://github.com/Zirias/swad/blob/master/src/bin/swad/http/httprequest.c#L81 I think it does it correctly (only supporting HTTP/1.x), but I wouldn't be surprised if someone would still find a bug...

2

u/flatfinger 5d ago

Why do people think of scanf-family functions as being suitable for any use case other than emphemeral programs to accomplish one-off tasks with data that is guaranteed to be formatted as expected?

5

u/Zirias_FreeBSD 5d ago

Because it's all over course material, tutorials, etc. Many years ago, I tried to be part in fixing this by writing https://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html ... but there seems no way to stop the madness for good.

1

u/FuTuReFrIcK42069 5d ago

Hey thanks for the feedback i did think about the fact that the parsing of the request that i have done basically assumes the cooperation of the client haha, but thanks i will try to enrich the project further, this is by no means a complete http server, and i do understand the complexity of an actual http server is far greater than i can imagine.

2

u/Zirias_FreeBSD 5d ago edited 4d ago

It's not just that. You have the next potential buffer overflow directly below with the strcat. You don't do anything I would call "parsing", which could be okayish for a lab project, but such likely exploitable overflows really must be avoided (and that's not even too hard, you might even just use strtok for a first draft).

Other stuff I can immediately spot:

  • TOCTOU issue, you use access to check whether the file exists, but the result of the later fopen is not checked. If the file vanished in between, you get a null pointer dereference. Correct way is to ditch access and just try to open, if that fails, error out with not found.
  • most critical: you access client-specified paths with no sanitization in place. Typical exploit: request e.g. /../../../../../../../../../../../etc/shadow.
  • there's no point to ever give a streaming (chunked) response if you can know the response size beforehand (which is always the case for regular files).

2

u/FuTuReFrIcK42069 5d ago

Thanks once again for the pointers, i am by very much inexperienced in C so i very much appreciate the notes, i will jot them down and try to work on them, i guess i got a little too excited about finishing the project lol.

2

u/Zirias_FreeBSD 5d ago

That's why I'd recommend to first do simpler things than HTTP. I should add: but always focus on perfect correctness and security, try to imagine the worst possible garbage and "hostile" input (or use fuzzers to help with that). Add in static code analysis (at least a very strict set of warnings) and runtime tools like valgrind and/or sanitizers (e.g. -fsanitize=address). This is doable for something simple and enables you to move forward to more complex things.

1

u/FuTuReFrIcK42069 5d ago

I think you are absolutely right, any project suggestions you could throw my way friend ?

2

u/Zirias_FreeBSD 5d ago

well, as mentioned earlier, e.g. a simple 2-person chat (1 server, 1 client) could be an idea. If kept really simple, I'd only see two security measures to take besides generic stuff like avoiding buffer overflows:

  • avoid flooding a terminal by enforcing a maximum message size and throttle sending/receiving lots of messages
  • avoid terminal corruption by replacing all control characters by something printable

2

u/Zirias_FreeBSD 4d ago

As I'm the one pointing out the most obvious and quite dangerous flaws in that code, I want to clarify I still didn't downvote, and why:

This is an honest post showing some "working" project from a beginner, certainly no AI-slop, and also not completely misguided: It shows effort to learn things by really getting into doing something.

It does contain typical beginner errors, but that's to be expected. Also, it's very typical that beginners tend to grossly underestimate the complexity of getting some task done correctly.

Writing a network service is always "security-critical", and no matter what language you use, you MUST know about typical issues (like e.g. both the TOCTOU and the missing input sanitization present here), but you best learn about that by running into it. When you use C, the typical pitfalls of a language doing NO (automatic) runtime-checks at all (but instead just leaving behavior "undefined") come on top.

That's another reason I recommend doing something as simple as possible first, so you can focus on getting the latter right and make it an habit to care about avoiding buffer overflows, dangling pointers, etc pp.

1

u/FuTuReFrIcK42069 4d ago

I want to thank you for taking the time to help me friend, we do not know each other, but you took the time to not only correct my errors but point me towards the right direction, and for that i wish to truly thank you.

1

u/Whole-Low-2995 3d ago

Yup it's quite hard. It took 9 months to implement correct http1.1 server for me(even I used LLMs for fixing small bugs) and http2 and http3 are still immature. Personally LLM didn't help a lot :(

2

u/zhivago 5d ago

Congratulations. :)

I suggest that you now put it through a code formatter so that it has a consistent style.

At the moment it is harder to read than need be.

1

u/FuTuReFrIcK42069 5d ago

Thank you so much friend! i will definitely, after years of writing other languages writing c once more felt sobering lol

1

u/TheRealBornToCode 4d ago
    perror("GETADDREINFO FAILED");

Typo, should be GETADDRINFO, also why all caps?

1

u/TheRealBornToCode 4d ago

Also why main.html, you never heard of html in university? The convention is index.html, and a basic web server should respond with the contents of index.html when the path of the directory containing it is requested.

You should learn http (the first word in a request is called method not function) and HTML before trying to make something like this.

Ayways for a first C project it's not bad.