Skip to content

namanjain2005/Mini_HTTP_server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

httpfromtcp 🧩

Minimal Go utilities to parse raw HTTP requests from TCP connections and to run a small HTTP server. The codebase includes a simple HTTP server, a TCP listener that demonstrates low-level request parsing, and a tiny UDP client for quick tests.


⚙️ Project structure

  • cmd/httpserver/ — small HTTP server that uses the project's request/response abstractions and supports chunked responses and simple proxying.
  • cmd/tcplistener/ — a TCP server demonstrating raw parsing of HTTP requests; prints the request line, headers, and body.
  • cmd/udplistener/ — a simple UDP client that sends user input to localhost:42069 (useful for testing UDP behavior).
  • internal/headers/ — header parsing utilities and tests.
  • internal/request/ — HTTP request parser and helpers, used by the server and reader utilities.
  • internal/response/ — response construction helpers (status line, headers, chunked body helpers).
  • tee/, tmp/ — example/raw request files and sample payloads used for manual testing.

🚀 Build & Run

Requirements: Go 1.20+ (module-aware build). From the repository root:

Build all binaries:

go build ./...

Run the HTTP server (listens on port 42069):

go run ./cmd/httpserver

Test with curl:

curl http://localhost:42069/
curl http://localhost:42069/yourproblem  # returns 400
curl http://localhost:42069/httpbin/get  # proxies request to https://httpbin.org/get

Run the TCP listener (prints raw parsed request details):

go run ./cmd/tcplistener

Send a raw HTTP request (Linux/macOS example using nc / netcat):

printf "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n" | nc localhost 42069

On Windows you can use ncat (Nmap) or other netcat ports to send raw bytes, or use curl to exercise the HTTP server.

UDP client (sends user input lines to localhost:42069):

go run ./cmd/udplistener
# Type and press Enter to send each line

✅ Testing

Run the unit tests for internal packages:

go test ./...

There are tests in internal/headers and internal/request that verify parsing behavior.


🔧 Implementation notes

  • Request parsing is implemented in internal/request and handles request line, headers, and optional body (using Content-Length).
  • cmd/httpserver demonstrates using the parsing/response utilities to implement a small web server with chunked responses, trailers, and basic error handling.
  • cmd/tcplistener shows how the low-level parser can be used directly on a connection for inspection and debugging.

� Writing a handler (guide) 💡

The server expects a handler with this signature:

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

When you call server.Serve(port, myHandler), your handler receives a *response.Writer (for writing status, headers and body) and the parsed *request.Request.

Minimal example (simple 200 response):

func myHandler(w *response.Writer, req *request.Request) {
    body := []byte("Hello from handler\n")
    h := response.GetDefaultHeaders(len(body))
    h.Replace("content-type", "text/plain")

    w.WriteStatusLine(response.StatusGoodReq)
    w.WriteHeaders(*h)
    w.WriteBody(body)
}

Chunked response example (with trailers):

func chunkHandler(w *response.Writer, req *request.Request) {
    // start response
    w.WriteStatusLine(response.StatusGoodReq)

    // set headers for chunked transfer
    h := response.GetDefaultHeaders(0)
    h.Delete("content-length")
    h.Set("Transfer-Encoding", "chunked")
    h.Set("Trailer", "X-Content-SHA256")
    w.WriteHeaders(*h)

    // write chunks
    for i := 0; i < 3; i++ {
        chunk := []byte(fmt.Sprintf("chunk %d\n", i))
        w.WriteChunkedBody(chunk)
    }
    w.WriteChunkedBodyDone()

    // write trailers
    trailers := headers.NewHeaders()
    trailers.Set("X-Content-SHA256", "dummysum")
    w.WriteHeaders(*trailers)
}

Notes:

  • Use req.RequestLine and req.Headers to inspect method, path and incoming headers.
  • To send an error response from inside a handler you can write a server.HandlerError directly to the underlying writer, e.g.:
herr := &server.HandlerError{StatusCode: response.StatusBadReq, Message: "bad request"}
herr.Write(w.Writer)

�🧪 Examples & manual testing

  • Check tee/ and tmp/ for sample raw HTTP request payloads that can be fed into tcplistener or used with nc.
  • Try the /httpbin/* path on the HTTP server to see chunked proxying and trailers in action.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages