use std::io::{BufRead, BufReader, Write};
use std::sync::Arc;
use std::time::Duration;
use go_lib::net::TcpStream;
use go_http::{handler::ServeMux, server::Server};
const ADDR: &str = "127.0.0.1:8087";
#[go_lib::main]
fn main() {
let mux = Arc::new(ServeMux::new());
mux.handle_func("/upload", |w, r| {
let body = r.body_bytes().unwrap_or_default();
let text = String::from_utf8_lossy(&body);
let checksum = r.trailers()
.get("X-Checksum")
.unwrap_or("<none>")
.to_owned();
println!("[server] body ({} bytes): {text:?}", body.len());
println!("[server] X-Checksum trailer: {checksum}");
w.header().set("Content-Type", "text/plain; charset=utf-8");
w.header().set("X-Received-Checksum", &checksum);
let reply = format!("body={text}\nchecksum={checksum}\n");
let _ = w.write(reply.as_bytes());
});
go_lib::go!(move || {
let mut srv = Server::new(ADDR);
srv.handler = Some(mux);
let _ = srv.listen_and_serve();
});
go_lib::sleep(Duration::from_millis(50));
let chunk1 = b"hello";
let chunk2 = b" world";
let checksum = "sha256:abc123";
let mut stream = TcpStream::connect(ADDR).expect("connect");
let mut reader = BufReader::new(stream.try_clone().expect("clone"));
println!("[client] sending chunked body with X-Checksum trailer ...");
write!(
stream,
"POST /upload HTTP/1.1\r\n\
Host: {ADDR}\r\n\
Transfer-Encoding: chunked\r\n\
Trailer: X-Checksum\r\n\
\r\n\
{chunk1_len:X}\r\n{chunk1}\r\n\
{chunk2_len:X}\r\n{chunk2}\r\n\
0\r\n\
X-Checksum: {checksum}\r\n\
\r\n",
chunk1 = String::from_utf8_lossy(chunk1),
chunk1_len = chunk1.len(),
chunk2 = String::from_utf8_lossy(chunk2),
chunk2_len = chunk2.len(),
)
.expect("write");
stream.flush().expect("flush");
let mut status_line = String::new();
reader.read_line(&mut status_line).expect("read status");
println!("[client] response: {}", status_line.trim());
let mut echoed_checksum = String::new();
loop {
let mut line = String::new();
let n = reader.read_line(&mut line).unwrap_or(0);
if n == 0 || line == "\r\n" { break; }
if line.to_ascii_lowercase().starts_with("x-received-checksum:") {
echoed_checksum = line
.split_once(':')
.map(|x| x.1)
.unwrap_or("")
.trim()
.to_owned();
}
}
println!("[client] X-Received-Checksum header: {echoed_checksum:?}");
assert!(
status_line.starts_with("HTTP/1.1 200"),
"expected 200, got: {status_line}"
);
assert_eq!(
echoed_checksum, checksum,
"trailer not round-tripped correctly"
);
println!("OK — chunked trailer round-trip complete.");
}