use std::path::PathBuf; use std::process::{Child as ChildProcess, Command}; use std::rc::Rc; use std::sync::Arc; use hyper::http::uri::Scheme; use hyper::{header, Body, Client, Request, Response}; use super::{async_trait, HttpHandler}; pub struct KillOnDrop(ChildProcess); impl Drop for KillOnDrop { fn drop(&mut self) { self.0.kill().unwrap(); } } #[derive(Clone)] pub struct ProxyChild { process: Arc, port: u16, } impl ProxyChild { pub fn new(command_line: String, in_dir: Option, port: u16) -> Self { let mut command_line = command_line.split(" "); let command = command_line.next().unwrap(); let mut child = Command::new(command); child.args(command_line); if let Some(cwd) = in_dir { child.current_dir(cwd); } let child = child.spawn().unwrap(); Self { process: Arc::new(KillOnDrop(child)), port: port as u16, } } } #[async_trait] impl HttpHandler for ProxyChild { async fn handle(&self, request: Request) -> Response { let ProxyChild { port, .. } = self; let mut request_uri = request.uri().clone().into_parts(); // TODO ipv6 loopback? request_uri.authority = Some(format!("127.0.0.1:{}", port).parse().unwrap()); request_uri.scheme = Some(Scheme::HTTP); let mut proxy_request = Request::builder() .method(request.method()) .uri(request_uri) .header(header::HOST, request.headers()[header::HOST].clone()); proxy_request.headers_mut().unwrap().extend( request .headers() .iter() .map(|(x, y)| (x.clone(), y.clone())), ); // TODO handle nonempty body let proxy_request = proxy_request.body(Body::empty()).unwrap(); let client = Client::new(); client.request(proxy_request).await.unwrap() } }