use super::{Sites, Arc, Endpoint, Site, ScriptCommand}; use flume::Sender; use tiny_http::{Server, Request, Response}; pub fn request_waiter( server: Arc, runs_tx: Sender, sites: Sites, tid: usize, ) { loop { let request = server.recv(); if let Ok(request) = request { let mut site = None; for header in request.headers() { if header.field.equiv("Host") { let host = header.value.as_str().split(":").next().unwrap(); site = sites.get(host); break; } } if let Some(site) = site { let mut path_vars = Vec::new(); let mut path_override = None; let mut endpoint = site.routes(); let path_iter = request.url().split('/').filter(|s| !s.is_empty()); for step in path_iter { if let Endpoint::Upload = endpoint { path_vars.push(step.into()); continue; } if let Endpoint::Dir(map) = endpoint { if let Some(next) = map.items.get(step) { endpoint = next; continue; } if let Some(Endpoint::Static(_)) = map.default.as_deref() { // fallback to empty endpoint = map.default.as_ref().unwrap(); // must not continue/break so that the step path land in path_override } else if let Some(next) = map.wildcard.as_deref() { path_vars.push(step.into()); endpoint = &next; continue; } } if let Endpoint::Static(path) = endpoint { let path = path_override.get_or_insert_with(|| path.to_string()); path.push_str("/"); path.push_str(step); continue; } endpoint = site.on_404(); break; } while let Endpoint::Dir(map) = endpoint { if let Some(next) = map.default.as_deref() { endpoint = &next; continue; } endpoint = site.on_404(); break; } process_endpoint(Some(&site), path_vars, path_override, request, endpoint, &runs_tx, tid); } else { log::error!("Unknown host in request header"); process_endpoint(None, Vec::new(), None, request, &Endpoint::Error(502.into()), &runs_tx, tid); } } else if let Err(error) = request { log::error!("Error while parsing http request: {}", error); } } } fn process_endpoint( site: Option<&Arc>, path_vars: Vec, path_override: Option, mut request: Request, endpoint: &Endpoint, runs_tx: &Sender, tid: usize, ) { if let Endpoint::ScriptExec(read_only, script_name) = endpoint { let site = site.unwrap(); let mut content = String::new(); if let Ok(_) = request.as_reader().read_to_string(&mut content) { if let Ok(body) = site.parse_json(&content, tid) { let _ = runs_tx.send(ScriptCommand { site: site.clone(), script_name: script_name.clone(), read_only: *read_only, path_vars, body, request, }); } else { log::error!("Couldn't parse request body as JSON"); process_endpoint(Some(site), Vec::new(), None, request, &Endpoint::Error(400.into()), runs_tx, tid); } } else { log::error!("Couldn't read request body"); process_endpoint(Some(site), Vec::new(), None, request, &Endpoint::Error(400.into()), runs_tx, tid); } } else if let Endpoint::Static(path) = endpoint { let site = site.unwrap(); let path = path_override.as_deref().unwrap_or(path); if let Some(reader) = site.open_static(path) { let response = Response::new(200.into(), vec![], reader, None, None); if let Err(error) = request.respond(response) { log::error!("Couldn't respond: {:?}", error); } } else { log::error!("Missing static resource: {}", path); if site.on_404() != endpoint { process_endpoint(Some(site), Vec::new(), None, request, site.on_404(), runs_tx, tid); } else { log::error!("Invalid 404 handler"); process_endpoint(Some(site), Vec::new(), None, request, &Endpoint::Error(500.into()), runs_tx, tid); } } } else if let Endpoint::Upload = endpoint { let site = site.unwrap(); if path_vars.len() == 1 { let token = &path_vars[0]; if let Some(mut body_len) = site.check_upload_token(token) { let chunk_size = 4096 * 4; let reader = request.as_reader(); let mut buf = vec![0; chunk_size]; while body_len > 0 { if let Ok(len) = reader.read(&mut buf) { site.upload_progress(token, &buf[..len]); if let Some(len) = body_len.checked_sub(len) { body_len = len; } else { site.end_of_upload(token, false); log::error!("Client tried to upload more than allowed"); return process_endpoint(Some(site), Vec::new(), None, request, &Endpoint::Error(400.into()), runs_tx, tid); } } else { site.end_of_upload(token, false); log::error!("Failed to process upload request"); return process_endpoint(Some(site), Vec::new(), None, request, &Endpoint::Error(400.into()), runs_tx, tid); } } site.end_of_upload(token, true); let response = "success".as_bytes(); if let Err(error) = request.respond(Response::new(200.into(), vec![], response, None, None)) { log::error!("Couldn't respond: {:?}", error); } return; } } log::error!("Invalid upload token/request"); process_endpoint(Some(site), Vec::new(), None, request, &Endpoint::Error(400.into()), runs_tx, tid); } else if let Endpoint::Error(code) = endpoint { let body = include_str!("proc-failure.html").as_bytes(); let response = Response::new(*code, vec![], body, None, None); if let Err(error) = request.respond(response) { log::error!("Couldn't respond: {:?}", error); } } else { log::error!("Landed at an Endpoint::Directory(_) without any wildcard route"); process_endpoint(site, Vec::new(), None, request, &Endpoint::Error(500.into()), runs_tx, tid); } }