Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HTTP Server (Go)

A tiny, educational HTTP/1.1 server written from scratch in Go. It implements its own request parser, headers handling, and response writer over raw TCP.

Features

  • Raw TCP listener with per-connection goroutines
  • HTTP/1.1 request parsing: request-line, headers, and optional body
  • Response writer with status line, headers, and body
  • Simple routing via a switch on the request target
  • Example binaries:
    • httpserver: serves example routes on port 42069
    • tcplistener: prints parsed requests to stdout

Requirements

  • Go 1.24.5 (as declared in go.mod)

Quick start

Run the sample HTTP server:

go run ./cmd/httpserver

Alternatively, build and run:

go build -o bin/httpserver ./cmd/httpserver
./bin/httpserver

You should see the server start on port 42069.

Endpoints (from the sample httpserver binary)

  • / → 200 OK with an HTML page
  • /yourproblem → 400 Bad Request with a plaintext error message
  • /myproblem → 500 Internal Server Error with a plaintext error message

Try it with curl

curl -i http://localhost:42069/
curl -i http://localhost:42069/yourproblem
curl -i http://localhost:42069/myproblem

Project layout

cmd/
  httpserver/     # Example HTTP server using the internal packages
  tcplistener/    # Raw TCP listener that prints parsed requests
internal/
  headers/        # Header map + parser
  request/        # HTTP/1.1 request parser (line, headers, body)
  response/       # Response writer + default headers
  server/         # TCP server, connection loop, and handler glue

Developing

  • Run all tests:
go test ./...

Using the server package

The server package exposes a minimal API to accept connections and handle requests.

Handler signature:

type Handler func(w *response.Writer, req *request.Request) *server.HandlerError

Starting a server:

srv, err := server.Serve(42069, func(w *response.Writer, req *request.Request) *server.HandlerError {
    switch req.RequestLine.RequestTarget {
    case "/":
        body := []byte("hello from bare metal")
        headers := response.GetDefaultHeaders(len(body))
        headers.Replace("Content-Type", "text/plain")
        _ = w.WriteStatusLine(response.StatusOkCode)
        _ = w.WriteHeaders(headers)
        _, _ = w.WriteBody(body)
        return nil
    default:
        return &server.HandlerError{
            Code:    response.StatusBadRequestCode,
            Message: "unknown route\n",
        }
    }
})
if err != nil { panic(err) }
defer srv.Close()

HandlerError short-circuits normal handling and writes an error response with the given status code and message.

Notes & limitations

  • HTTP version: only HTTP/1.1 requests are accepted
  • Methods supported by parser: GET, POST, DELETE, PUT, PATCH
  • Body handling: requires a correct Content-Length; connection is closed after response
  • Default headers include Content-Length, Connection: close, and Content-Type: text/plain
  • Routing is intentionally minimal (a switch in cmd/httpserver/main.go)
  • Port is currently hard-coded to 42069 in cmd/httpserver/main.go

tcplistener utility

For debugging the request parser:

go run ./cmd/tcplistener

It accepts connections on :42069 and prints the parsed request-line, headers, and body.

Shout-out

This project was built while following ThePrimeagen’s course “Learn the HTTP Protocol in Go” on Boot.dev. Huge thanks for the excellent deep-dive from TCP to HTTP.

Learn the HTTP Protocol in Go (Boot.dev)

About

A tiny educational HTTP/1.1 server written from scratch in Go

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages