Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ exclude = [".gitignore", ".github/**"]

[dependencies]
http = "1.0.0"

[features]
async = []
45 changes: 45 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
//!
//! Several shortcut functions are provided (such as [`html_response`](fn.html_response.html)/[`binary_response`](fn.binary_response.html))

#![feature(async_trait_bounds)]

use std::collections::HashMap;
use std::convert::TryFrom;
use std::fmt::Debug;
Expand All @@ -63,6 +65,34 @@ pub type Request = http::Request<Vec<u8>>;
/// A `Vec<u8>` Response from http
pub type Response = http::Response<Vec<u8>>;

#[cfg(feature = "async")]
async fn handle_with_io_async<F, R, W>(func: F, mut stdin: R, mut stdout: W)
where
F: async FnOnce(Request) -> Response,
R: Read,
W: Write,
{
let env_vars: HashMap<String, String> = std::env::vars().collect();

// How many bytes do we have to read for request body
// A general stdin().read_to_end() can block if the webserver doesn't close things
let content_length: usize = env_vars
.get("CONTENT_LENGTH")
.and_then(|cl| cl.parse::<usize>().ok())
.unwrap_or(0);

let mut stdin_contents = vec![0; content_length];
stdin.read_exact(&mut stdin_contents).unwrap();

let request = parse_request(env_vars, stdin_contents);

let response = func(request).await;

let output = serialize_response(response);

stdout.write_all(&output).unwrap();
}

fn handle_with_io<F, R, W>(func: F, mut stdin: R, mut stdout: W)
where
F: FnOnce(Request) -> Response,
Expand Down Expand Up @@ -111,6 +141,21 @@ where
)
}

/// Asynchronously call a function as a CGI programme.
///
/// This should be called from a `main` function.
/// Parse & extract the CGI environmental variables, and HTTP request body,
/// to create `Request`, and convert your `Response` into the correct format and
/// print to stdout.
#[cfg(feature = "async")]
pub async fn handle_async<F>(func: F)
where
F: async FnOnce(Request) -> Response,
{
handle_with_io_async(func, std::io::stdin(), std::io::stdout()).await
}


/// Call a function as a CGI programme.
///
/// This should be called from a `main` function.
Expand Down