aboutsummaryrefslogtreecommitdiff
path: root/src/utils/proxy_child.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/proxy_child.rs')
-rw-r--r--src/utils/proxy_child.rs74
1 files changed, 74 insertions, 0 deletions
diff --git a/src/utils/proxy_child.rs b/src/utils/proxy_child.rs
new file mode 100644
index 0000000..d7a021d
--- /dev/null
+++ b/src/utils/proxy_child.rs
@@ -0,0 +1,74 @@
+use std::process::{Child as ChildProcess, Command};
+use std::rc::Rc;
+
+use hyper::http::uri::Scheme;
+use hyper::{header, Body, Client, Request, Response};
+use rhai::{Dynamic, FnPtr, Map};
+
+pub struct KillOnDrop(ChildProcess);
+
+impl Drop for KillOnDrop {
+ fn drop(&mut self) {
+ self.0.kill().unwrap();
+ }
+}
+
+#[derive(Clone)]
+pub struct ProxyChild {
+ process: Rc<KillOnDrop>,
+ port: u16,
+}
+
+impl ProxyChild {
+ fn new(params: Map) -> Self {
+ let command_line = params["command"].clone().into_immutable_string().unwrap();
+ let port = params["port"].as_int().unwrap();
+ 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) = params.get("in_dir") {
+ let cwd = cwd.clone().into_immutable_string().unwrap();
+ let cwd: &str = cwd.as_ref();
+ child.current_dir(cwd);
+ }
+ let child = child.spawn().unwrap();
+ Self {
+ process: Rc::new(KillOnDrop(child)),
+ port: port as u16,
+ }
+ }
+}
+
+pub fn handle_request(child: &mut ProxyChild, request: Rc<Request<Body>>) -> Rc<Response<Body>> {
+ let ProxyChild { port, .. } = child;
+ 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 response = async {
+ let client = Client::new();
+ Rc::new(client.request(proxy_request).await.unwrap())
+ };
+ let runtime = tokio::runtime::Handle::current();
+ runtime.block_on(response)
+}
+
+pub fn proxy_child(params: Map) -> FnPtr {
+ let child = ProxyChild::new(params);
+ let mut result = FnPtr::new("handle_request_proxy_child").unwrap();
+ result.add_curry(Dynamic::from(child));
+ result
+}