Module hoot::server

source ·
Expand description

Server HTTP/1.1 request and response

§Example

use hoot::server::{Request, Response, ResponseVariant};
use hoot::{Method, HttpVersion};

let mut buf = [0; 1024];

// ************* READ REQUEST LINE *****************

let mut request = Request::new();

// Try read incomplete input. The provided buffer is required
// to parse request headers.
let attempt =
    request.try_read_request(b"GET /path HTTP/1.", &mut buf)?;
assert!(!attempt.is_success());

const COMPLETE: &[u8] =
    b"GET /path HTTP/1.1\r\nHost: foo\r\nContent-Length: 10\r\n\r\n";

// Try read complete input (and succeed). Borrow the buffer again.
let attempt = request.try_read_request(COMPLETE, &mut buf)?;
assert!(attempt.is_success());

// Read request line information.
let line = attempt.line().unwrap();
assert_eq!(line.version(), HttpVersion::Http11);
assert_eq!(line.method(), Method::GET);
assert_eq!(line.path(), "/path");

// Read headers.
let headers = attempt.headers().unwrap();
assert_eq!(headers[0].name(), "Host");
assert_eq!(headers[0].value(), "foo");
assert_eq!(headers[1].name(), "Content-Length");
assert_eq!(headers[1].value(), "10");

// Proceed to reading request body.
let request = request.proceed();

// GET requests have no body.
assert!(request.is_finished());

// ************* SERVE RESPONSE *****************

// This gives us variants, i.e. methods, that we can
// respond differently to.
let variants = request.into_response()?;

// This matches out a response token with the type
// state that helps us form a correct response.
let token = match variants {
    ResponseVariant::Get(v) => v,
    ResponseVariant::Head(_) => todo!(),
    ResponseVariant::Post(_) => todo!(),
    ResponseVariant::Put(_) => todo!(),
    ResponseVariant::Delete(_) => todo!(),
    ResponseVariant::Connect(_) => todo!(),
    ResponseVariant::Options(_) => todo!(),
    ResponseVariant::Trace(_) => todo!(),
    ResponseVariant::Patch(_) => todo!(),
};

let response = Response::resume(token, &mut buf);

let output = response
    .send_status(200, "Ok")?
    .header("content-type", "application/json")?
    .with_chunked()?
    .flush();

const EXPECTED: &[u8] = b"HTTP/1.1 200 Ok\r\n\
    content-type: application/json\r\n\
    Transfer-Encoding: chunked\r\n\r\n";

// Output derefs to `&[u8]`, but if that feels opaque,
// we can use `as_bytes()`.
assert_eq!(&*output, EXPECTED);

let token = output.ready();

let response = Response::resume(token, &mut buf);

let output = response
    .write_chunk(b"{\"hello\":\"world\"}")?
    .finish()?
    .flush();

const EXPECTED_BODY:
    &[u8] = b"11\r\n{\"hello\":\"world\"}\r\n0\r\n\r\n";

assert_eq!(&*output, EXPECTED_BODY);

Structs§

Enums§