tortuga 0.7.2

A Rust-based CGI-specific HTTP web server.
Documentation
use crate::context::{ClientContext, RequestContext, ServerContext};
use crate::server::response::CgiResponse;
use crate::Script;
use bytes::Bytes;
use http::StatusCode;
use http_body_util::Full;
use hyper::{Request, Response};
use std::io;
use std::sync::Arc;

pub struct CgiHandler {
    server: Arc<ServerContext>,
    client: Arc<ClientContext>,
}

impl CgiHandler {
    pub fn new(server: Arc<ServerContext>, client: Arc<ClientContext>) -> Self {
        Self { server, client }
    }

    pub async fn serve(&self, request: Request<Bytes>) -> io::Result<Response<Full<Bytes>>> {
        let context = RequestContext::new(self.server.clone(), self.client.clone(), &request);
        let body = request.into_body();

        let extension = context.script()?.extension();
        let output = if extension == Some("wcgi".as_ref()) {
            let script = self.server.script_mappings().wasm();
            script.invoke(context, body).await
        } else if extension == Some("cgi".as_ref()) {
            let script = self.server.script_mappings().process();
            script.invoke(context, body).await
        } else {
            Err(io::Error::new(
                io::ErrorKind::Unsupported,
                "Invalid file extension; must be either cgi or wcgi.",
            ))
        }?;

        let mut response = Response::new(Full::from(output.clone()));

        if output.is_empty() {
            *response.status_mut() = StatusCode::BAD_GATEWAY;
        }

        let offset = response.parse_headers(&output)?;

        if offset != 0 {
            *response.body_mut() = Full::from(output.slice(offset..));
        }

        Ok(response)
    }
}