exchange.nct
see ./index.nct
see ./streaming.nct
use std/http.{Client, Request, ResponseHead, Server}
use std/net.{IpAddress, Ipv4Address, SocketAddress}
use std/string.String
use std/task
use std/time.Duration
use std/url.Url
func loopback(): SocketAddress {
return SocketAddress.new(IpAddress.from_ipv4(Ipv4Address.loopback()), 0)
}
async func serve_once(server: Server, timeout: Duration): void! {
var owner = move server
let connection = await owner.accept_with_timeout(timeout)?
var request = await connection.read_request_with_timeout(timeout)?
if request.request_method().text() != "POST"
|| request.target().path() != "/echo" {
return error.new("async-http.request", "local request changed during HTTP decoding")
}
let request_body = await collect_text_before(&+request, timeout)?
if request_body != "ping" {
return error.new("async-http.request", "local request body changed during HTTP decoding")
}
let responder = await request.finish_body_with_timeout(timeout)?
var head = ResponseHead.ok()
head.append_header_text("X-Example", "local")?
var writer = await responder.begin_chunked_with_timeout(move head, timeout)?
await writer.write_with_timeout("po".bytes(), timeout)?
await writer.write_with_timeout("ng".bytes(), timeout)?
let _next = await writer.finish_with_timeout(timeout)?
return
}
async func run(): i32! {
let timeout = Duration.from_seconds(1)
let server = await Server.bind(loopback())?
let address = server.local_address()?
let port = address.port().to_string()
let url_text = String.concat("http://127.0.0.1:", &port, "/echo")
var request = Request.post(Url.parse(&url_text)?)?
request.append_header_text("X-Example", "client")?
request.set_text_body("ping")
let client = Client.new()
let response = client.send_with_timeout(move request, timeout)
let exchanged = await task.join(
move response,
serve_once(move server, timeout),
)
let response_result = move exchanged.0
let server_result = move exchanged.1
var received = move response_result?
move server_result?
if received.status().code() != 200 {
return error.new("async-http.status", "local server returned an unexpected status")
}
let _header = received.headers().first("x-example") otherwise {
return error.new("async-http.header", "local response header was absent")
}
let body = await collect_text_before(&+received, timeout)?
if body != "pong" {
return error.new("async-http.body", "local server returned an unexpected body")
}
return 0
}