fastcgi-client-rs

Runtime-agnostic Fastcgi client implemented for Rust.
The client is built on the futures-io
AsyncRead / AsyncWrite traits and contains no task spawning, timers or
socket creation, so it works with any async runtime, and even with no runtime at
all.
Installation
No cargo feature is required:
cargo add fastcgi-client
Any stream implementing the futures-io traits works out of the box, for
example smol or
async-net:
cargo add smol
Tokio defines its own I/O traits, so its streams need a compatibility wrapper.
Enable the optional tokio feature to get convenience constructors that do the
wrapping for you:
cargo add fastcgi-client --features tokio
cargo add tokio --features full
Without the tokio feature you can still use Tokio by bridging the stream
yourself with tokio-util:
use fastcgi_client::Client;
use tokio::net::TcpStream;
use tokio_util::compat::TokioAsyncReadCompatExt;
#[tokio::main]
async fn main() {
let stream = TcpStream::connect(("127.0.0.1", 9000)).await.unwrap();
let _client = Client::new(stream.compat());
}
Examples
Short connection mode:
use fastcgi_client::{io, Client, Params, Request};
use std::env;
smol::block_on(async {
let script_filename = env::current_dir()
.unwrap()
.join("tests")
.join("php")
.join("index.php");
let script_filename = script_filename.to_str().unwrap();
let script_name = "/index.php";
let stream = smol::net::TcpStream::connect(("127.0.0.1", 9000))
.await
.unwrap();
let client = Client::new(stream);
let params = Params::default()
.request_method("GET")
.script_name(script_name)
.script_filename(script_filename)
.request_uri(script_name)
.document_uri(script_name)
.remote_addr("127.0.0.1")
.remote_port(12345)
.server_addr("127.0.0.1")
.server_port(80)
.server_name("jmjoy-pc")
.content_type("")
.content_length(0);
let output = client
.execute_once(Request::new(params, io::empty()))
.await
.unwrap();
let stdout = String::from_utf8(output.stdout.unwrap()).unwrap();
assert!(stdout.contains("Content-type: text/html; charset=UTF-8"));
assert!(stdout.contains("hello"));
assert_eq!(output.stderr, None);
});
Keep alive mode:
use fastcgi_client::{io, Client, Params, Request};
smol::block_on(async {
let stream = smol::net::TcpStream::connect(("127.0.0.1", 9000))
.await
.unwrap();
let mut client = Client::new_keep_alive(stream);
let params = Params::default();
for _ in 0..3 {
let output = client
.execute(Request::new(params.clone(), io::empty()))
.await
.unwrap();
let stdout = String::from_utf8(output.stdout.unwrap()).unwrap();
assert!(stdout.contains("Content-type: text/html; charset=UTF-8"));
assert!(stdout.contains("hello"));
assert_eq!(output.stderr, None);
}
});
With the tokio feature, Client::new_tokio and Client::new_keep_alive_tokio
accept Tokio streams directly:
use fastcgi_client::{io, Client, Params, Request};
use tokio::net::TcpStream;
# #[cfg(feature = "tokio")]
#[tokio::main]
async fn main() {
let stream = TcpStream::connect(("127.0.0.1", 9000)).await.unwrap();
let client = Client::new_tokio(stream);
let output = client
.execute_once(Request::new(Params::default(), io::empty()))
.await
.unwrap();
assert!(String::from_utf8(output.stdout.unwrap()).unwrap().contains("hello"));
let stream = TcpStream::connect(("127.0.0.1", 9000)).await.unwrap();
let mut client = Client::new_keep_alive_tokio(stream);
for _ in 0..3 {
let output = client
.execute(Request::new(Params::default(), io::empty()))
.await
.unwrap();
assert!(String::from_utf8(output.stdout.unwrap()).unwrap().contains("hello"));
}
}
# #[cfg(not(feature = "tokio"))] fn main() {}
Runnable versions of every flow, including response streaming and an Axum
HTTP-to-FastCGI proxy, live under
examples/.
Optional HTTP conversions
Enable the http feature if you want to convert between this crate's FastCGI
types and the http crate.
fastcgi-client = { version = "0.12", features = ["http"] }
The conversion boundary is intentionally split in two:
Request<'a, I> can convert into http::Request<I> without buffering the body.
http::Request<I> can convert back into FastCGI metadata, but CGI-only params
such as SCRIPT_FILENAME must be supplied explicitly through extra Params.
Response can be parsed into http::Response<Vec<u8>>; stderr remains
available only on the original FastCGI response.
License
Apache-2.0.