use std::io::{Read, Write}; use std::net::TcpListener; use std::thread; use rpki::fetch::http::{BlockingHttpFetcher, HttpFetcherConfig}; use rpki::sync::rrdp::Fetcher; fn start_one_shot_http_server() -> (String, thread::JoinHandle<()>) { let listener = TcpListener::bind("127.0.0.1:0").expect("bind"); let addr = listener.local_addr().expect("local addr"); let addr_s = addr.to_string(); let h = thread::spawn(move || { for _ in 0..3 { let (mut sock, _peer) = listener.accept().expect("accept"); let mut buf = [0u8; 4096]; let n = sock.read(&mut buf).expect("read request"); let req = String::from_utf8_lossy(&buf[..n]); let path = req .lines() .next() .and_then(|l| l.split_whitespace().nth(1)) .unwrap_or("/"); let (status, body) = if path == "/ok" { ("200 OK", b"ok".as_slice()) } else { ("404 Not Found", b"nope".as_slice()) }; let resp = format!( "HTTP/1.1 {status}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n", body.len() ); sock.write_all(resp.as_bytes()).expect("write headers"); sock.write_all(body).expect("write body"); } }); (addr_s, h) } #[test] fn http_fetcher_handles_success_and_status_errors() { let (addr, h) = start_one_shot_http_server(); let fetcher = BlockingHttpFetcher::new(HttpFetcherConfig::default()).expect("build fetcher"); let ok = fetcher .fetch_bytes(&format!("http://{addr}/ok")) .expect("fetch ok"); assert_eq!(ok, b"ok"); // Also exercise the trait method wrapper. let ok2 = Fetcher::fetch(&fetcher, &format!("http://{addr}/ok")).expect("fetch via trait"); assert_eq!(ok2, b"ok"); let err = fetcher .fetch_bytes(&format!("http://{addr}/missing")) .unwrap_err(); assert!(err.contains("404"), "error should mention 404, got: {err}"); h.join().expect("server thread join"); }