use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread::{self, JoinHandle};
pub(crate) struct OneShotHttpServer {
port: u16,
handle: Option<JoinHandle<bool>>,
}
impl OneShotHttpServer {
pub(crate) fn start() -> Self {
let listener = TcpListener::bind("127.0.0.1:0").expect("bind loopback probe server");
let port = listener.local_addr().expect("probe server addr").port();
let handle = thread::spawn(move || {
if let Ok((mut stream, _)) = listener.accept() {
let mut buf = [0u8; 1024];
let served = matches!(stream.read(&mut buf), Ok(read) if read > 0);
let _ = stream.write_all(
b"HTTP/1.1 200 OK\r\nContent-Length: 2\r\nConnection: close\r\n\r\nok",
);
let _ = stream.flush();
served
} else {
false
}
});
Self {
port,
handle: Some(handle),
}
}
pub(crate) fn url(&self) -> String {
format!("http://localhost:{}/probe", self.port)
}
pub(crate) fn port(&self) -> u16 {
self.port
}
pub(crate) fn join(mut self) -> bool {
self.handle
.take()
.expect("probe server handle")
.join()
.expect("probe server thread")
}
pub(crate) fn unblock_and_join(self) {
let _ = TcpStream::connect(("127.0.0.1", self.port));
self.join();
}
}
impl Drop for OneShotHttpServer {
fn drop(&mut self) {
if let Some(handle) = self.handle.take() {
let _ = TcpStream::connect(("127.0.0.1", self.port));
let _ = handle.join();
}
}
}