Skip to content

abhi25072002/HTTPHaven

Repository files navigation

HTTPHaven - a multithreaded HTTP/1.1 server, from scratch in Python

Python RFC 2616 Frameworks License: MIT

No Flask. No Django. No http.server. Just raw sockets, threads, and the HTTP/1.1 spec.


Introduction

HTTPHaven is a multithreaded, HTTP/1.1-compliant web server built directly on TCP sockets to explore how the protocol actually works under the hood - request parsing, method semantics, content negotiation, caching, and connection management, all implemented by hand from RFC 2616.

See it in action

Every response header below is generated by hand - no library fills them in:

$ curl -i http://127.0.0.1:12001/
HTTP/1.1 200 OK
Etag: e4cd62ee7fbcdccd9bb8f4f39f33ecbd
Server: http-server/1.2.4 (Ubuntu)
Accept-Ranges: bytes
Set-Cookie: client_cookie:=UbgCdi
Date: Sat, 18 Jul 2026 04:19:25 UTC
Content-Encoding: identity
Content-Type: text/html
Content-Length: 10933

$ curl -o /dev/null -w "%{http_code}\n" -H "Range: bytes=0-9" http://127.0.0.1:12001/sample.txt
206

$ curl -o /dev/null -w "%{http_code}\n" -X PUT -H "Content-Type: text/plain" -d "hello" http://127.0.0.1:12001/demo.txt
201

$ curl -sD - -o /dev/null -H "Accept-Encoding: gzip" http://127.0.0.1:12001/ | grep -i encoding
Content-Encoding: gzip

And serving a page in the browser:

HTTPHaven serving the demo index page

Features

  • HTTP methods - GET, POST, PUT, DELETE, HEAD, with correct semantics and per-method routing
  • 15+ status codes - 200, 201, 204, 206, 304, 400, 403, 404, 405, 406, 412, 415, 416, 501, 505, each with proper error pages
  • Caching - ETag generation and If-None-Match/If-Match validation with 304 Not Modified / 412 Precondition Failed
  • Range requests - partial content (206) with Accept-Ranges and 416 for unsatisfiable ranges
  • Content negotiation - Accept-Encoding honored with gzip, brotli, deflate, and LZW compression
  • Persistent connections - configurable keep-alive with max-request and timeout limits
  • Concurrency - one thread per connection on top of a plain socket accept loop
  • Multipart form data - file uploads and form submissions parsed by hand
  • Cookies - set and retrieve cookies for basic session tracking
  • Configurable - document root, ports, timeouts, log paths, and connection limits via a .conf file
  • Access & error logs - Apache-style logging of every request and failure

Quick start

# 1. Install dependencies (compression codecs + test client)
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# 2. Start the server (reads abhishekS.conf, defaults to port 12001)
bash start_server.sh

# 3. Talk to it
curl -i http://127.0.0.1:12001/

# 4. Stop or restart it
bash stop_server.sh
bash restart_server.sh

Run the test suite

testing.py fires 61 checks at a live server - every method, conditional headers, byte ranges, content negotiation, multipart uploads, malformed raw-socket requests, and concurrent clients - and prints one pass/fail line per request with the RFC reason for each expected status:

python testing.py            # one line per check + summary, exits non-zero on failure
VERBOSE=1 python testing.py  # also dump full request/response headers per check
HTTPHaven test suite output: all 61 checks passed

Configuration

The server is configured through abhishekS.conf:

[DOCUMENTROOT]
DocumentRoot = httpfiles/

[POSTROOT]
PostRoot = POST/

[PUTROOT]
PutRoot = PUT/

[PIDFILE]
pidfile = pid.txt

[TIMEOUT]
TimeOut = 300

[KEEP_ALIVE]
KeepAlive = Off

[MAX_KEEP_ALIVE_REQUESTS]
MaxKeepAliveRequests = 5

[KEEP_ALIVE_TIMEOUT]
KeepAliveTimeout = 20

[ACCESSLOG]
AccessLog = logs/access.log

[ERRORLOG]
ErrorLog = logs/error.log

[MAX_SIMULTANEOUS_CONNECTION]
MaxSimultaneousConnection = 5

[PORT_NUMBER]
PortNumber = 12001

How a request flows

sequenceDiagram
    participant C as Client
    participant M as Main thread<br/>(socket accept loop)
    participant W as Worker thread
    participant FS as Filesystem

    C->>M: TCP connect
    M->>W: spawn thread per connection
    C->>W: GET /index.html HTTP/1.1
    W->>W: parse request line + headers
    W->>FS: resolve path under DocumentRoot
    W->>W: ETag check → 304? · Range → 206?<br/>negotiate Accept-Encoding
    W->>C: status + headers + (compressed) body
    W->>W: keep-alive? loop : close
    Note over W: access.log / error.log entry written
Loading

Logs

Access log

Every request is recorded in an Apache-style access log:

127.0.0.1:50126 - [Sun, 14 Nov 2021 17:23:09 GMT] "GET / HTTP/1.1" 200 3148 python-requests/2.22.0

Fields: client IP and port, timestamp, request line, status code, response size in bytes, and the client's User-Agent.

Error log

Failures get their own log with an error class appended:

127.0.0.1:50128 - [Sun, 14 Nov 2021 17:23:09 GMT] "GET /index23.html HTTP/1.1" 404 Not Found python-requests/2.22.0 Client-Error:4xx

Fields: client IP and port, timestamp, request line, status code and reason, User-Agent, and the error category (Client-Error:4xx / Server-Error:5xx).

Both paths are set in the config file (logs/access.log and logs/error.log by default).

Project structure

HTTPHaven/
├── http-server.py     # Entry point: socket setup + accept loop, thread spawning
├── methods.py         # The heart: request parsing, method handlers, caching,
│                      #   ranges, compression, keep-alive
├── functions.py       # Helpers: headers, dates, error pages
├── logger.py          # Access / error log writers
├── testing.py         # Regression test suite (run against a live server)
├── abhishekS.conf     # Server configuration
├── httpfiles/         # Document root (GET)
├── POST/              # POST upload destination
├── PUT/               # PUT upload destination
└── logs/              # access.log + error.log

Acknowledgments

  • RFC 2616 - the foundational HTTP/1.1 specification this server is built against
  • MDN Web Docs - comprehensive documentation on HTTP and web technologies

License

MIT

About

A multithreaded HTTP/1.1 web server written from scratch in Python. Raw sockets, ETag caching, range requests, gzip/brotli compression, keep-alive. No frameworks.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages