Skip to content

SaqAsh/C-based-webserver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

C-Based Static Web Server

This is a minimalist static web server written in C. I’m building it to practice and demonstrate systems-level programming (sockets, basic HTTP, file I/O, portability) while delivering a product that’s dead-simple to run for serving static websites.

What this server does

  • Listens on a TCP port (default: 8080)
  • Parses an HTTP request line to determine the requested path
  • Serves files from the repository (e.g., src/index.html and others)
  • Writes a minimal HTTP response header with Content-Type
  • Streams file contents efficiently to the client
  • Sends basic error responses (400/404/500/413)

What problem this solves

  • Quick, dependency-free static hosting: run a single binary (or Docker container) and serve a folder of HTML/CSS/JS/images.
  • Low overhead for local dev, demos, CI previews, or constrained environments where Node/Python stacks are heavy.

What a user can do with it

  • Serve a static site (HTML/CSS/JS/images) from a document root
  • Change the port and doc root easily
  • Run it directly as a native binary, or via Docker for zero-setup

How it works (high level)

  1. Create a socket and bind to PORT.
  2. listen() and accept() incoming connections.
  3. Read the HTTP request bytes into a buffer.
  4. Parse the path; default to index.html when no file is provided.
  5. Open the file, stat it, write response headers, then send the file body.
  6. Close the client socket and repeat.

Current layout

src/
  main.c           // current single-file implementation
  index.html       // example content
include/           // header files will live here as I refactor

I’ll gradually abstract out the implementation from src/main.c into modules in src/ with matching headers in include/ (e.g., http.c/.h, server.c/.h, mime.c/.h, etc.).

Build and run

Quickstart (native binary)

From repo root:

gcc -Wall -Wextra -O2 -std=c11 src/main.c -o main
./main

Then visit http://localhost:8080 in a browser or:

curl -i http://localhost:8080

Environment variables (optional):

PORT=9090 ./main              # change the port
DOC_ROOT=./src ./main         # change the document root (future option)

Multi-file (after refactor)

When modules are split into multiple files, I’ll compile with the include directory:

gcc -I include -Wall -Wextra -O2 -std=c11 src/*.c -o webserver
./webserver

Roadmap

Immediate fixes (correctness and safety)

  • Replace unsafe extension-to-int casting with safe string-based MIME detection.
  • Harden extension parsing: null checks before strlen, ensure proper null-termination.
  • Check return values for all write() calls; handle partial writes.
  • Ensure correct socket is used for error responses in the request loop.
  • Basic path normalization to prevent directory traversal (e.g., ..).

Structure and organization

  • Introduce modules:
    • server.c/.h: socket setup, accept loop
    • http.c/.h: request parsing, response formatting
    • mime.c/.h: extension → MIME lookup
    • file_handler.c/.h: file open/stat/send logic
  • Add include/ for public headers and compile with -I include.
  • Add a Makefile for reliable builds.

Functionality improvements

  • Add support for more HTTP methods (or explicitly enforce GET only).
  • Normalize and sanitize paths (disallow .., collapse //, limit path length).
  • Configurable document root and port (env vars or config file).
  • Logging (access and error logs).

Concurrency (next milestone)

  • Introduce a thread pool to handle requests concurrently (I’ll start with a fixed pool size and a lock-protected work queue).
  • Make shared state (if any) thread-safe with mutexes.

Robustness and UX

  • Graceful shutdown (signal handling).
  • Sensible limits (max headers/line length, request timeout).
  • More comprehensive error pages.

Testing and tooling

  • Add simple integration tests (e.g., shell-based curl tests).
  • Static analysis and sanitizers: -fsanitize=address,undefined in debug builds.
  • CI setup (optional) to build and run basic tests.

Development tips

  • I’ll prefer small, focused modules with clear interfaces in include/.
  • I always check system call return values (socket, bind, listen, accept, read, write, open, fstat, etc.).
  • I keep buffers sized conservatively and ensure explicit null-termination.
  • I use const where appropriate; keep functions static if they’re private to a .c file.
  • I optimize for clarity first; network I/O will dominate performance.

License

MIT (or your choice). Add a LICENSE file if needed.

About

Node.js? Nah, C for the win!

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published