go-http 0.1.2

rust native port of GO's http module
Documentation

go-http — HTTP/1.1 Server & Client in Rust

A faithful port of Go's net/http library to Rust, built on go-lib for goroutine-style concurrency.

Status: Production-ready. All 98 tests passing. Full HTTP/1.1 support with TLS.

Features

Server

  • Goroutine-per-connection model — each accepted connection spawns a lightweight goroutine
  • Keep-Alive support — persistent connections reuse TCP sockets
  • Chunked transfer encoding — streams large responses without buffering
  • Handler routingServeMux with longest-prefix matching
  • Middlewarestrip_prefix, file_server, timeout_handler
  • TLS — HTTPS via rustls with automatic certificate loading

Client

  • Connection pooling — idle TCP connections reused per host
  • Redirect following — automatic POST→GET on 301/302/303, respecting max_redirects
  • Cookie jar — automatic cookie storage and transmission
  • Timeout support — per-request deadline via go-lib context

HTTP

  • RFC 7231 parsing — request/response line, headers, trailers
  • Content negotiation — Content-Length vs Transfer-Encoding, 1xx/204/304 handling
  • MIME types — detect, parse, format media types with RFC 2231 continuations
  • Form encodingapplication/x-www-form-urlencoded client support

Quick Start

Run the Hello Server

cargo run --example hello_server

Then test it:

curl http://127.0.0.1:8080/
curl "http://127.0.0.1:8080/hello?name=Alice"

Run a Static File Server

cargo run --example static_files

Serves files from examples/assets/ under /static/:

curl http://127.0.0.1:8083/static/hello.txt

Use the Client

cargo run --example client_get -- https://httpbin.org/get

Or in your own code:

use go_http::client::Client;

fn main() {
    let result = go_lib::run(|| {
        let client = Client::new();
        client.get("http://example.com/")
    });

    match result {
        Ok(mut resp) => println!("Status: {}", resp.status),
        Err(e) => eprintln!("Error: {e}"),
    }
}

Examples

All examples run under go_lib::run() so goroutines and channels are available:

Example Purpose
hello_server Minimal HTTP server with query parameter handling
echo_server Echoes request method, path, headers back as JSON
routing ServeMux pattern matching (exact vs prefix)
static_files File serving with prefix stripping
client_get HTTP client library usage
middleware Composable handler middleware (logging + timeout)

Run with: cargo run --example <name>

API Reference — Go → Rust

Go Rust
http.Server go_http::server::Server
http.ListenAndServe go_http::server::listen_and_serve
http.ListenAndServeTLS go_http::server::listen_and_serve_tls
http.Handler go_http::handler::Handler
http.HandlerFunc go_http::handler::handler_func
http.ServeMux go_http::handler::ServeMux
http.StripPrefix go_http::handler::strip_prefix
http.FileServer go_http::handler::file_server
http.TimeoutHandler go_http::handler::timeout_handler
http.Client go_http::client::Client
http.Transport go_http::client::Transport
http.RoundTripper go_http::client::RoundTripper
http.Request go_http::request::Request
http.Response go_http::response::Response
http.Cookie go_http::cookie::Cookie
io.Reader std::io::Read
io.Writer std::io::Write
net.Conn.Read / Write TcpStream: Read + Write
net.Listener go_lib::net::TcpListener
context.Context go_lib::context::Context
sync.Mutex std::sync::Mutex

Architecture

Core Modules

  • server.rs — HTTP server, listen_and_serve, goroutine-per-connection loop
  • client.rs — HTTP client, Transport with connection pooling, redirect handling
  • handler.rsHandler trait, ServeMux routing, middleware wrappers
  • request.rsRequest value type with URL, headers, body, context
  • response.rs — Response types, ConnResponseWriter
  • parse/ — HTTP parsing (request, response, chunked encoding, transfer encoding)
  • mime/ — MIME type detection, media-type parsing, multipart, quoted-printable
  • header.rs — Case-insensitive HTTP header map
  • cookie.rs — Cookie struct, CookieJar trait, MemoryCookieJar implementation
  • tls.rs — TLS config helpers (server_config, default_client_config)
  • util.rs — Helpers (HTTP-date parsing, content-type detection, set_cookie, redirect)

Concurrency Model

Each Server spawns an accept goroutine that receives connections. For each new connection, a handler goroutine is spawned:

go_lib::go!(move || {
    serve_conn(stream, handler, max_header_bytes);
});

The handler goroutine runs a keep-alive loop:

  1. Parse request headers via read_request(...)
  2. Attach body reader (chunked or content-length)
  3. Dispatch to handler via handler.serve_http(&mut w, &req)
  4. Write response headers and body via w
  5. Loop for next request or close on Connection: close

All blocking I/O (reads, writes, accepts) is transparent to go-lib's netpoll — the scheduler parks goroutines and resumes them when I/O is ready, without blocking OS threads.

Building & Testing

Run All Tests

cargo test

This runs:

  • 77 unit tests across all modules
  • 13 integration tests in tests/server_client.rs (GET, POST, redirects, cookies, routing, etc.)
  • 8 integration tests in tests/middleware.rs (strip_prefix, file_server, timeout_handler)

Test Structure

Integration tests spawn a server goroutine and client goroutine in the same go_lib::run() call — no separate OS threads. This avoids netpoll corruption from concurrent scheduler instances.

Each integration test file uses a static NET_LOCK: Mutex<()> to serialize tests (netpoll is a process-global singleton).

Build Examples

cargo build --examples

Check Build (no tests)

cargo build

TLS Support

Server (HTTPS)

Load a certificate and key, then call listen_and_serve_tls:

use go_http::server::listen_and_serve_tls;
use go_http::handler::handler_func;

fn main() {
    go_lib::run(|| {
        let _ = listen_and_serve_tls(
            "127.0.0.1:8443",
            "cert.pem",
            "key.pem",
            Some(Arc::new(mux)),
        );
    });
}

Client (HTTPS)

By default, the client trusts the Mozilla root CA bundle:

let mut client = Client::new();
let resp = client.get("https://example.com/").unwrap();

To add a custom CA:

let tls_cfg = go_http::tls::client_config_with_ca("custom-ca.pem").unwrap();
let mut transport = Transport::new();
transport.tls_config = Some(tls_cfg);

let mut client = Client::new();
client.transport = Arc::new(transport);

Certificates are loaded via rustls-pemfile and must be in PEM format.

Dependencies

Crate Version Purpose
go-lib 0.5.1 Goroutines, channels, context, netpoll TCP
go-lib-macros 0.5.1 go! and select! macros
url 2 URL parsing and manipulation
base64 0.22 Base64 encoding/decoding
rustls 0.23 TLS client & server
rustls-pemfile 2 PEM file parsing
webpki-roots 0.26 Mozilla root CA bundle

Design Notes

Why impl<H: Handler> Handler for Arc<H>?

This allows middleware to stack Arc<ServeMux> directly without wrapper boilerplate:

let mux = Arc::new(ServeMux::new());
let with_timeout = timeout_handler(mux, Duration::from_secs(5), "timeout");

Why impl Read + Write for &TcpStream (in addition to &mut)?

TcpStream::read and TcpStream::write only touch goroutine state, not the struct itself. This is safe with & because all blocking is managed by go-lib's netpoll — there are no interior mutability hazards.

Why try_clone() instead of Rc<RefCell<TcpStream>>?

TcpStream::try_clone() uses dup(2) (Unix) or DuplicateHandle (Windows) to create independent file descriptors pointing to the same kernel socket. This avoids shared ownership and borrow checker complexity.

In serve_conn, the request body and response writer operate on independent clones — true parallelism without contention.

Separate Integration Test Binaries

Each .rs file in tests/ compiles to its own binary with its own OS process, scheduler, and netpoll instance. This isolation prevents goroutine pointer collisions when tests run in parallel.

Contributing

  • Follow the Rust API Guidelines
  • Add tests for new features (unit tests in src/, integration tests in tests/)
  • Run cargo test before submitting
  • Port behavior from Go's net/http when possible for API familiarity

License

Licensed under the Apache License, Version 2.0 or the MIT License, at your option.

Go Reference

For behavior clarification, consult the Go net/http documentation.