Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-http

Note

This is not a production-ready library (yet). It was built to understand how HTTP actually works under the hood, not to be depended on in real projects.

An HTTP/1.1 server implemented from scratch in Go, directly on top of TCP, with no net/http on the server side. It parses raw request bytes off the wire, and writes responses (status lines, headers, chunked encoding, trailers) by hand, byte for byte, according to the HTTP/1.1 spec.

Why

Most Go web work happens through net/http, which hides the wire format entirely. This project builds the protocol layer itself (a streaming request parser, a header parser, and a response writer capable of fixed-length, chunked, and trailer-bearing responses) to understand what net/http is actually doing underneath.

Features

  • Streaming request parser: parses the request line, headers, and body incrementally as bytes arrive, without waiting for the full request to be buffered first.
  • Case-insensitive header handling: per RFC 9110, with repeated header fields merged into a single comma-separated value.
  • Concurrent connections: each accepted connection is handled on its own goroutine.
  • Chunked transfer encoding: stream a response body of unknown length, Transfer-Encoding: chunked, hex-prefixed chunks.
  • Trailers: send headers after the body (e.g. a content hash computed only once the full body has been read), announced up front via the Trailer header.
  • A small reverse proxy: /httpbin/<path> forwards requests to https://httpbin.org/<path> and streams the response back to the client chunk by chunk, live, as it arrives.

Installation

Requires Go 1.26+.

git clone <this-repo>
cd go-http
go build ./...

Quickstart

Start the server:

go run ./cmd/httpserver

It listens on :4000. Try the built-in routes:

curl http://localhost:4000/
curl -i http://localhost:4000/yourproblem     # 400 Bad Request
curl -i http://localhost:4000/myproblem       # 500 Internal Server Error

Proxy a request through to httpbin.org, streamed as chunked encoding:

curl --raw http://localhost:4000/httpbin/html

curl --raw (or nc) is important here: plain curl reassembles chunked responses transparently, hiding the hex chunk sizes and trailers this project actually implements. To see the raw wire format:

echo -e "GET /httpbin/stream/5 HTTP/1.1\r\nHost: localhost:4000\r\nConnection: close\r\n\r\n" | nc localhost 4000

Serve a local file with a custom content type:

curl -o /dev/null http://localhost:4000/video

(expects assets/vim.mp4 to exist locally, see .gitignore; this path is not committed.)

Project structure

cmd/
  httpserver/     entry point: route table and handlers (main.go)
  tcplistener/    early scratch program for raw TCP experimentation
internal/
  request/        parses raw bytes into a Request (request line, headers, body)
  headers/        case-insensitive header map + parser
  response/       Writer: status lines, headers, chunked bodies, trailers
  server/         TCP listener, connection lifecycle, handler dispatch

Request lifecycle

sequenceDiagram
    participant Client
    participant server as internal/server
    participant request as internal/request
    participant Handler as myHandler (cmd/httpserver)
    participant response as internal/response

    Client->>server: TCP connection
    server->>request: RequestFromReader(conn)
    request-->>server: *Request
    server->>Handler: handler(response.NewWriter(conn), req)
    Handler->>response: WriteStatusLine / WriteHeaders / WriteBody
    Handler->>response: (or) WriteChunkedBody... / WriteChunkedBodyDone / WriteTrailers
    response-->>Client: bytes written directly to conn
Loading

The handler owns the entire response: it writes the status line, headers, and body (or chunks + trailers) directly to the connection; the server does not buffer or inspect the response on the way out.

Testing

go test ./...

Covers the request-line/header/body parser (including reads split across arbitrary byte-sized chunks, to make sure the parser doesn't assume anything arrives in one piece), the header map, and an end-to-end test that dials the running server over a real TCP socket and asserts on the raw response bytes.

License

MIT

About

Implementing HTTP/1.1 from scratch using TCP. no standard library http package used.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages