From 5a207c6649a67871c209f8e1634efcbcc719bee6 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 4 Jul 2020 15:33:59 +0200 Subject: Add documentation Write doc comments for functions and types, and include a short example. --- src/lib.rs | 32 ++++++++++++++++++++++++++++++++ src/request.rs | 37 +++++++++++++++++++++++++++++++++++++ src/server.rs | 19 +++++++++++++++++++ 3 files changed, 88 insertions(+) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 2ffe77e..caf8663 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,35 @@ +#![warn(missing_docs)] + +//! # fastcgi-conduit +//! +//! FastCGI-Conduit provides a [Conduit] interface to FastCGI, enabling a +//! high-level API for FastCGI applications. +//! +//! +//! ## Example +//! +//! ``` rust +//! use conduit::{header, Body, RequestExt, Response}; +//! use fastcgi_conduit::Server; +//! +//! +//! fn main() { +//! Server::start(handler).unwrap(); +//! } +//! +//! fn handler(_req: &mut dyn RequestExt) -> std::io::Result> { +//! Ok( +//! Response::builder() +//! .header(header::CONTENT_TYPE, "text/html") +//! .body(Body::from_static(b"

Hello

")) +//! .unwrap() +//! ) +//! } +//! ``` +//! +//! +//! [Conduit]: ../conduit/index.html + extern crate conduit; extern crate fastcgi; extern crate http; diff --git a/src/request.rs b/src/request.rs index 2d90ea9..dcc91a0 100644 --- a/src/request.rs +++ b/src/request.rs @@ -7,31 +7,40 @@ use inflector::cases::traincase::to_train_case; use snafu::{ResultExt, Snafu}; +/// Errors parsing a FastCGI request. #[derive(Debug, Snafu)] pub enum Error { + /// The HTTP method is invalid. #[snafu(display("{}", source))] InvalidMethod { source: http::method::InvalidMethod }, + /// An invalid HTTP header name. #[snafu(display("{}", source))] InvalidHeaderName { source: conduit::header::InvalidHeaderName }, + /// An invalid HTTP header value. #[snafu(display("{}", source))] InvalidHeaderValue { source: conduit::header::InvalidHeaderValue }, + /// An invalid remote address. #[snafu(display("{}", source))] InvalidRemoteAddr { source: RemoteAddrError }, } +/// A convenience `Result` that contains a request `Error`. pub type RequestResult = std::result::Result; +/// Errors parsing an HTTP remote address. #[derive(Debug, Snafu)] pub enum RemoteAddrError { + /// Error parsing the address part. #[snafu(display("Could not parse address {}: {}", address, source))] AddrParseError { address: String, source: std::net::AddrParseError, }, + /// Error parsing the port part. #[snafu(display("Could not parse port {}: {}", port, source))] PortParseError { port: String, @@ -40,6 +49,11 @@ pub enum RemoteAddrError { } +/// Wraps a [`fastcgi::Request`][fastcgi::Request] to implement +/// [`conduit::RequestExt`][conduit::RequestExt]. +/// +/// [fastcgi::Request]: ../../fastcgi/struct.Request.html +/// [conduit::RequestExt]: ../../conduit/trait.RequestExt.html pub struct FastCgiRequest<'a> { request: &'a mut fastcgi::Request, http_version: conduit::Version, @@ -54,6 +68,7 @@ pub struct FastCgiRequest<'a> { } impl<'a> FastCgiRequest<'a> { + /// Create a new `FastCgiRequest`. pub fn new(request: &'a mut fastcgi::Request) -> RequestResult { let version = Self::version(request); let host = Self::host(request); @@ -78,6 +93,7 @@ impl<'a> FastCgiRequest<'a> { }) } + /// Extract the HTTP version. fn version(request: &fastcgi::Request) -> conduit::Version { match request.param("SERVER_PROTOCOL").unwrap_or_default().as_str() { "HTTP/0.9" => conduit::Version::HTTP_09, @@ -89,6 +105,7 @@ impl<'a> FastCgiRequest<'a> { } } + /// Get the request scheme (HTTP or HTTPS). fn scheme(&self) -> conduit::Scheme { let scheme = self.request.param("REQUEST_SCHEME").unwrap_or_default(); @@ -99,10 +116,14 @@ impl<'a> FastCgiRequest<'a> { } } + /// Get the HTTP host. + /// + /// This looks like `localhost:8000`. fn host(request: &fastcgi::Request) -> String { request.param("HTTP_HOST").unwrap_or_default() } + /// Get the HTTP method (GET, HEAD, POST, etc.). fn method( request: &fastcgi::Request ) -> Result { @@ -113,6 +134,7 @@ impl<'a> FastCgiRequest<'a> { ) } + /// Build a map of request headers. fn headers(params: fastcgi::Params) -> RequestResult { let mut map = conduit::HeaderMap::new(); let headers = Self::headers_from_params(params); @@ -132,6 +154,8 @@ impl<'a> FastCgiRequest<'a> { Ok(map) } + /// Extract headers from request params. Transform these into pairs of + /// canonical header names and values. fn headers_from_params(params: fastcgi::Params) -> Vec<(String, String)> { return params .filter(|(key, _)| key.starts_with("HTTP_")) @@ -145,6 +169,10 @@ impl<'a> FastCgiRequest<'a> { .collect() } + /// Get the URI path. + /// + /// Returns `/path` when the URI is `http://localhost:8000/path?s=query`. + /// When the path is empty, returns `/`. fn path(request: &fastcgi::Request) -> String { match request.param("SCRIPT_NAME") { Some(p) => p, @@ -152,10 +180,15 @@ impl<'a> FastCgiRequest<'a> { } } + /// Get the URI query string. + /// + /// Returns `s=query&lang=en` when the URI is + /// `http://localhost:8000/path?s=query&lang=en`. fn query(request: &fastcgi::Request) -> Option { request.param("QUERY_STRING") } + /// Get the remote address of the request. fn remote_addr(request: &fastcgi::Request) -> Result { let addr = request.param("REMOTE_ADDR").unwrap_or_default(); let port = request.param("REMOTE_PORT").unwrap_or_default(); @@ -168,12 +201,16 @@ impl<'a> FastCgiRequest<'a> { ) } + /// Get the request's content length. fn content_length(request: &fastcgi::Request) -> Option { request.param("CONTENT_LENGTH").and_then(|l| l.parse().ok()) } } impl<'a> Read for FastCgiRequest<'a> { + /// Read from the underlying FastCGI request's [`Stdin`][Stdin] + /// + /// [Stdin]: ../../fastcgi/struct.Stdin.html fn read(&mut self, buf: &mut [u8]) -> io::Result { self.request.stdin().read(buf) } diff --git a/src/server.rs b/src/server.rs index 948a470..95f8325 100644 --- a/src/server.rs +++ b/src/server.rs @@ -10,25 +10,41 @@ use snafu::{ResultExt, Snafu}; use crate::request; +/// The HTTP version used by the server. const HTTP_VERSION: &'static str = "HTTP/1.1"; +/// Wraps server errors. #[derive(Debug, Snafu)] pub enum Error { + /// I/O write errors during response output. #[snafu(context(false))] Write { source: io::Error }, + /// Error building the request into a [`FastCgiRequest`][FastCgiRequest]. + /// + /// [FastCgiRequest]: ../request/struct.FastCgiRequest.html #[snafu(display("Couldn't build request: {}", source))] RequestBuilder { source: request::Error }, + /// Error building a [`conduit::Response`][conduit::Response]. + /// + /// [conduit::Response]: ../../conduit/struct.Response.html #[snafu(display("Couldn't parse response: {}", source))] ConduitResponse { source: conduit::BoxError }, } +/// The application server that interfaces with FastCGI. pub struct Server; impl Server { + /// Start the server. + /// + /// Start the main [`fastcgi::run`][fastcgi::run] process to listen for + /// requests and handle them using `handler`. + /// + /// [fastcgi::run]: ../../fastcgi/fn.run.html pub fn start(handler: H) -> io::Result { fastcgi::run(move |mut raw_request| { match handle_request(&mut raw_request, &handler) { @@ -56,6 +72,8 @@ impl Server { } } +/// Given a raw FastCGI request and a Conduit handler, get a response from the +/// handler to write to a FastCGI response. fn handle_request( mut raw_request: &mut fastcgi::Request, handler: &H, @@ -100,6 +118,7 @@ where H: Handler + 'static + Sync Ok(()) } +/// Write a 500 internal server error to `w`. fn internal_server_error(mut w: W) { let code = conduit::StatusCode::INTERNAL_SERVER_ERROR; -- cgit v1.2.3