Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Multithreaded HTTP Web Server in C

A compact HTTP/1.x server written in C11 using POSIX TCP sockets and a fixed pthread worker pool. It exists to make the layers normally hidden by a web framework visible: accepting a TCP connection, finding an HTTP header boundary, reading a length-delimited body, mapping a safe URL path to disk, and coordinating concurrent work without a thread-per-request explosion.

This is intentionally a learning-oriented, portfolio-ready systems project—not a production reverse proxy. The code is split by responsibility and comments call out the non-obvious POSIX choices.

Build and run

Linux/macOS with a C compiler and POSIX threads is required.

make
./webserver

The default server listens at http://127.0.0.1:8080, serves www/, and starts eight workers. Configuration is available without recompiling:

./webserver --port 9000 --root ./www --threads 12

In another terminal:

curl -i http://127.0.0.1:8080/
curl -i http://127.0.0.1:8080/hello.txt
curl -i --data 'hello from curl' http://127.0.0.1:8080/echo

POST currently logs the request target and byte count, then returns the exact request body as application/octet-stream. This deliberately small behavior verifies correct Content-Length framing while leaving a clear place to add routing or persistence later.

Press Ctrl-C to stop accepting connections. Already accepted connections in the queue and active workers finish before the process exits.

Features

  • Raw IPv4 TCP listener with SO_REUSEADDR
  • GET for files under the configured document root, including MIME types for HTML, CSS, JavaScript, PNG, JPEG, text, and JSON
  • POST body handling by Content-Length
  • Correct Content-Length, Content-Type, status line, and Connection: close response headers
  • Basic errors: 400 malformed requests, 404 missing files, 405 unsupported methods, 413 oversized headers/bodies, and 500 read failures
  • Configurable fixed-size worker pool (default: 8) with a bounded FIFO socket queue
  • Graceful SIGINT shutdown that drains accepted work and joins every worker
  • Path traversal and document-root escape prevention, including symlinks resolved outside the root

Design

The lifecycle and synchronization model are described in ARCHITECTURE.md. The important design choice is a fixed worker pool, not one thread per connection. A thread-per-connection server makes every burst create more stacks and scheduling overhead, can exhaust OS resources, and gives no natural backpressure. Here the queue has a finite capacity of 4 × worker_count; when full, accept pauses until a worker makes room.

Validation

The normal build treats warnings as errors:

make clean && make

On Linux, build a ThreadSanitizer instrumented binary and exercise simultaneous requests:

make tsan
./webserver --threads 8
# Separate terminal
seq 1 100 | xargs -n1 -P16 -I{} curl -fsS http://127.0.0.1:8080/hello.txt >/dev/null

For leak checks (with the normal, non-TSan build):

make clean && make
valgrind --leak-check=full --show-leak-kinds=all ./webserver

Then issue a few curl requests, stop with Ctrl-C, and inspect Valgrind's final summary. Run either TSan or Valgrind at a time; their instrumentation should not be combined.

Limitations

  • HTTP/1.0 and HTTP/1.1 request lines are accepted, but every response closes the connection; keep-alive is not implemented.
  • Only GET and POST are supported; there is no routing layer, TLS, authentication, or directory listing.
  • Parsing is intentionally bounded and minimal, not a full RFC 7230 implementation. Headers are limited to 16 KiB, bodies to 1 MiB, and chunked transfer encoding is rejected.
  • The listener is IPv4-only and is aimed at local development/learning, not internet exposure.
  • A slow client can occupy one worker while it sends an incomplete request; production servers use timeouts and more sophisticated I/O models.

Repository layout

src/main.c            CLI parsing and startup
src/server.c          sockets, URL-to-file resolution, request handler, shutdown
src/http_parser.c     bounded request/header/body parsing
src/http_response.c   response serialization, MIME lookup, file streaming
src/threadpool.c      bounded producer/consumer queue and worker lifecycle
www/                  sample served content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages