A Python HTTP forward proxy built completely from scratch to understand networking, sockets, HTTP internals, and web security.
This is not another HTTP server.
This is a long-term educational project documenting my journey from raw TCP sockets to a production-quality HTTP parser, logger, and forward proxy — built entirely from scratch using only Python's standard library.
No frameworks. No requests. No http.server. Just sockets, bytes, and an
understanding of how HTTP actually works.
Modern web development hides HTTP behind frameworks. I wanted to understand what actually happens on the wire:
- How a TCP connection is established
- How raw bytes become a request
- What
\r\nmeans and why HTTP uses it - What a forward proxy really does
- How to parse and log HTTP traffic safely
This repository is my learning journal, written in working code.
This project is intentionally being built feature-by-feature, without any external proxy frameworks or HTTP libraries, so I can deeply understand how HTTP works from the socket up. Each milestone is small, understood, and committed before the next one starts — the repository only ever contains code that actually exists today. The journey is documented in docs/learning-notes.md.
- TCP socket server (accept loop, sequential clients)
- Raw HTTP request parsing
- Full request reading driven by
Content-Length - Response parsing (
Responseobject) - Full response reading driven by
Content-Length - Origin-form path rewriting (absolute-form →
/path) -
Proxy-Connectionheader stripped before forwarding - Request forwarding to the origin server
- Response relay back to the client
- TCP Server
- Receive Raw Requests
- Decode Bytes
- Parse Request Line
- Parse Headers
- Parse Request Body
- Request Object
- Parse Responses
- Forward Proxy
- Parse Cookies
- Parse Query Parameters
- Logger
- HTTPS CONNECT
- Multi-threading
- HTTP/2
- Request Interception
- Response Modification
The project is now a real forward proxy. It accepts a client connection, reads
the complete request, parses it, rewrites it to origin-form, strips the
non-standard Proxy-Connection header, forwards it to the origin server,
reads the complete response, and relays it back to the client.
src/server.py— the proxy loop: accept → read full request → parse → rewrite → forward → read full response → parse → send back.src/parser.py— now parses both requests (parse_request) and responses (parse_response).src/response.py— newResponseobject (version, status code, reason phrase, headers, body).Content-Lengthis honored when reading both requests and responses, so bodies split across multiple packets arrive intact.
A request sent through the proxy:
curl -x http://localhost:8080 http://example.com/index.html
arrives at the origin server as an origin-form request (no absolute URL, no
Proxy-Connection header):
GET /index.html HTTP/1.1
Host: example.com
User-Agent: curl/8.0
and the origin's response is relayed back to the client untouched.
- No chunked transfer encoding (
Transfer-Encodingbodies are not decoded) - No HTTPS / CONNECT tunneling
- No streaming
- No multi-threading — clients are handled one at a time, sequentially
- No HTTP/2
- No response modification or interception
- Body bytes are decoded as UTF-8, so binary bodies are not supported
- Header lookups are case-sensitive (e.g.,
Hostmust be capitalized)
These limitations are intentional — they are the next milestones.
http-proxy-lab/
├── LICENSE
├── README.md
├── CHANGELOG.md
├── .gitignore
├── pyproject.toml
├── src/
│ ├── server.py
│ ├── parser.py
│ ├── request.py
│ └── response.py
├── docs/
│ ├── roadmap.md
│ └── learning-notes.md
└── tests/
└── sample_requests/
Clone the repository and run it with Python 3:
git clone https://github.com/Utkarsh464/http-proxy-lab.git
cd http-proxy-lab
python3 src/server.pyNo dependencies to install. Everything uses the Python standard library.
In one terminal, start the proxy:
python3 src/server.pyIn another terminal, route a request through it:
curl -x http://localhost:8080 http://example.com/or point an environment variable at it:
HTTP_PROXY=http://localhost:8080 curl http://example.com/Proxy server is running on http://localhost:8080
Accepted connection from ('127.0.0.1', 42134)
0 'GET http://example.com/ HTTP/1.1'
1 'Host: example.com'
2 'User-Agent: curl/8.0'
3 'Proxy-Connection: Keep-Alive'
4 ''
Forwarding request to example.com:80
0 'HTTP/1.1 200 OK'
1 'Date: Mon, 03 Aug 2026 12:00:00 GMT'
2 'Content-Length: 1256'
3 'Connection: close'
4 ''
HTTP/1.1 200 OK
The proxy logs each forwarded request, the origin it reached, and the parsed status line of the response.
See docs/roadmap.md for the full journey and docs/learning-notes.md for the learning journal.