A lightweight HTTP/1.1 intercepting proxy built on raw TCP using the httpfromtcp library. It accepts incoming HTTP requests, forwards them to an upstream server, logs request/response data, applies simple modification rules, and can replay captured requests.
- Acts as a forward HTTP proxy (client -> proxy -> upstream).
- Logs method, path, status, latency, and headers.
- Optionally logs request/response bodies (size-limited).
- Applies request/response rules from config (inject headers, rewrite paths, drop requests, override response headers/status).
- Stores requests to a JSONL file and replays them later.
- Configure your proxy in
config.yaml. - Run the proxy:
go run cmd/proxy/main.go --config config.yaml
- Send traffic through it:
curl -x http://localhost:8080 http://example.com/api/users
If store_requests_path is set, the proxy writes requests as JSONL. You can replay them later:
go run cmd/replay/main.go --config config.yaml
Or specify a file directly:
go run cmd/replay/main.go --file requests.jsonl --upstream example.com:80
config.yaml example:
listen_addr: ":8080"
upstream_host: ""
log_bodies: true
max_body_bytes: 1024
json_logs: false
store_requests_path: "requests.jsonl"
upstream_timeout_sec: 10
rules:
- match: "/api/users"
inject_header: "X-Debug: true"
- match: "/health"
drop: true
listen_addr: Address the proxy listens on (default:8080).upstream_host: Optional fixed upstream host (host:port). If empty, uses the incomingHostheader or absolute URL.log_bodies: If true, logs request/response bodies.max_body_bytes: Max bytes to log from each body.json_logs: If true, logs JSON lines; otherwise pretty text.store_requests_path: JSONL file path for captured requests.upstream_timeout_sec: Timeout for reading upstream responses.rules: List of match rules applied to requests and responses.
match: Path prefix to match (for example/api/users).inject_header: Adds a request header (formatKey: Value).rewrite_path: Rewrites the request path to a fixed value.drop: Drops the request and returns 403.response_header: Adds a response header (formatKey: Value).response_status: Overrides the response status code.
Send a GET request via proxy:
curl -x http://localhost:8080 http://localhost:8090/api/students
Send a POST with JSON body:
curl -x http://localhost:8080 \
-H "Content-Type: application/json" \
-d '{"name":"Ada"}' \
http://localhost:8090/api/students
- HTTP only (no TLS interception). HTTPS requires MITM certificates, which are not implemented.
- Request parsing is limited by the underlying
httpfromtcpbuffer size. - Keep-alive is disabled; the proxy sets
Connection: closeupstream. - Chunked responses are de-chunked when possible; failures fall back to raw body.
cmd/
proxy/ main entrypoint for the proxy
replay/ replays captured requests
internal/
config/ config parsing
forwarder/ upstream TCP client
logger/ structured logging
modifier/ request/response rules
proxy/ proxy handler
replay/ replay logic
store/ request storage
go build ./...