gaato/mttp wires this engine to sockets, TLS and an event loop; most applications use that instead.
///|
test "serve a request" {
let driver = @driver.Driver::new()
let coordination = @sim.SimCoordination::new(driver)
let (client, server) = @sim.pair(coordination)
let errors = []
driver.run(() => {
let task = driver.spawn(() => {
@h1server.serve_conn(
server,
request => {
let greeting = "hello from " + request.url
@mttp_core.Response::new(
200,
body=Bytes(@mttp_core.encode_utf8(greeting)),
)
},
clock=@sim.SimClock::new(driver),
timer=@sim.SimTimer::new(driver),
coordination~,
scheme="https",
on_error=error => errors.push(error),
)
})
client.write(b"GET /docs HTTP/1.1\r\nHost: example.test\r\n\r\n")
// A head the codec refuses is answered and ends the connection.
client.write(b"GET / HTTP/1.1\r\nHost: a\r\nHost: b\r\n\r\n")
let out = Buffer()
while client.read(max_len=4096) is Some(bytes) {
out.write_bytes(bytes)
}
let text = @utf8.decode(out.to_bytes())
assert_true(text.has_prefix("HTTP/1.1 200 OK\r\n"))
assert_true(text.contains("hello from https://example.test/docs"))
assert_true(text.contains("HTTP/1.1 400 Bad Request\r\n"))
ignore(task.wait())
})
assert_eq(server.closes(), 1)
assert_eq(errors.length(), 1)
}pub(all) suberror ServerConfigError {
InvalidMaxBodyBytes(value~ : Int)
InvalidBodyTimeoutMs(value~ : Int)
InvalidHeaderTimeoutMs(value~ : Int)
InvalidMaxConnections(value~ : Int)
InvalidMaxHeaderBytes(value~ : Int)
InvalidDrainMaxBytes(value~ : Int)
InvalidHandlerTimeoutMs(value~ : Int)
InvalidDrainMs(value~ : Int)
} derive(Debug)impl Show for ServerConfigErrortest {
let limits = { ..@h1server.ServerLimits::default(), max_body_bytes: 4096, }
limits.validate()
assert_eq(limits.max_header_bytes, 16384)
}async fn serve_conn(conn : &Conn, handler : async (Request) -> Response noraise, clock~ : &Clock, timer~ : &Timer, coordination~ : &Coordination, scheme~ : String, limits? : ServerLimits, peer? : String, authority? : String, on_error? : (TransportError) -> Unit, stopping? : () -> Bool, background? : (async () -> Unit) -> Unit) -> Unit raise ServerConfigErrortest {
let driver = @driver.Driver::new()
let coordination = @sim.SimCoordination::new(driver)
let (client, server) = @sim.pair(coordination)
driver.run(() => {
let task = driver.spawn(() => {
@h1server.serve_conn(
server,
request => {
@mttp_core.Response::new(
200,
body=Bytes(@mttp_core.encode_utf8(request.url)),
)
},
clock=@sim.SimClock::new(driver),
timer=@sim.SimTimer::new(driver),
coordination~,
scheme="http",
)
})
client.write(
b"GET /hello HTTP/1.1\r\nHost: example.test\r\nConnection: close\r\n\r\n",
)
let out = Buffer()
while client.read(max_len=4096) is Some(bytes) {
out.write_bytes(bytes)
}
assert_true(out.to_bytes().has_suffix(b"http://example.test/hello"))
ignore(task.wait())
})
assert_eq(server.closes(), 1)
}Install
Download zipHTTP for MoonBit without I/O, for libraries such as SDKs: the types, an HTTP/1.1 codec and engines, a client with retries under a budget, deadlines, rate limits, redirects and cookies, SSE, multipart, and typed endpoints with a router and OpenAPI. Apps add gaato/mttp.