///|
/// Mapping HTTP messages onto HTTP/3 request/response streams (RFC 9114 ยง4.1):
/// a request becomes a HEADERS frame (a QPACK field section of the pseudo- and
/// ordinary headers) plus DATA, and decodes back; a typed request parses out;
/// and `http3_serve` drives a request through a handler that answers 200.
///
/// moon run src/examples/31-http3-message --target native
#coverage.skip
fn main {
run() catch {
e => println("http3 msg error: \{e}")
}
}
///|
fn run() -> Unit raise {
let wire = @http3.request(
"POST",
"https",
"api.example.com",
"/submit",
[@header.Header::of("content-type", "application/json")],
b"{\"name\":\"mooncat\"}",
)
let (headers, body) = @http3.read_message(wire)
println("request: \{headers.length()} header fields, body = \{ascii(body)}")
for h in headers {
println(" \{h.ascii().0}: \{h.ascii().1}")
}
match @http3.read_request(wire) {
Some(req) =>
println("parsed: \{req.meth} \{req.scheme}://\{req.authority}\{req.path}")
None => println("parse failed")
}
let resp = @http3.response(
"200",
[@header.Header::of("server", "mooncat")],
b"ok
",
)
let (rh, rb) = @http3.read_message(resp)
println("response: status=\{rh[0].ascii().1} body=\{ascii(rb)}")
let served = @http3.serve(wire, _req => @http3.Response::{
status: "200",
headers: [@header.Header::of("x-app", "mooncat")],
body: b"handled by mooncat",
})
let (ah, ab) = @http3.read_message(served)
println("served: status=\{ah[0].ascii().1} body=\{ascii(ab)}")
}
///|
fn ascii(b : Bytes) -> String {
let sb = StringBuilder()
for i = 0; i < b.length(); i = i + 1 {
sb.write_char(b[i].to_int().unsafe_to_char())
}
sb.to_string()
}