Capstone: tiny HTTP server
| The spec | |
| Route GET paths | |
| Hand-built responses | |
| Test with TCP client |
The spec
Build tinyhttp: a server on 127.0.0.1 port 7878 that answers three cases. The root path serves home, about serves about, and anything else gets a 404 page. Hand-built responses, no framework, no async.
Success means a client prints home for the root path and not found for unknown paths. The sections below add routing, responses, and a client test in that order.
Route GET paths
Routing is a pure function from path to body. Match the three cases and return string slices so no allocation happens yet:
fn route(path: &str) -> &str {
match path {
"/" => "home page",
"/about" => "about page",
_ => "not found",
}
}
Hand-built responses
HTTP answers are status line plus headers plus blank line plus body. The format macro assembles all four while Content-Length comes from the body itself:
fn response(body: &str) -> String {
format!("HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}", body.len(), body)
}
One function builds every 200 reply. A 404 reply needs only a different status line, which is a good first exercise.
Test with TCP client
Prove the server talks HTTP with a tiny client test. Connect, send a GET request, read everything, and assert the status code made it back:
use std::io::{Read, Write};
use std::net::TcpStream;
#[test]
fn serves_home() {
let mut s = TcpStream::connect("127.0.0.1:7878").unwrap();
s.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
let mut buf = String::new();
s.read_to_string(&mut buf).unwrap();
assert!(buf.contains("200"));
}
Start the server first, then run cargo test. A green test means a real socket carried a real request and a real reply.
Next: Modern Rust tour
Article author: Arthur Isaev