diff options
author | Teddy Wing | 2020-06-29 00:13:28 +0200 |
---|---|---|
committer | Teddy Wing | 2020-06-29 00:13:28 +0200 |
commit | 4d24b2ce62f7f011297fe2b61358c9124af129e5 (patch) | |
tree | dcd7acef1662c6ba6aa3fc7bfd39f4d6f5c64f00 /src/lib.rs | |
parent | c2f9adfe96406323e715513444a9d70fc7c4c17d (diff) | |
download | fastcgi-conduit-4d24b2ce62f7f011297fe2b61358c9124af129e5.tar.bz2 |
Move request code to `request.rs`
Want to separate request and server code.
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 239 |
1 files changed, 4 insertions, 235 deletions
@@ -2,251 +2,20 @@ extern crate conduit; extern crate fastcgi; extern crate http; +mod request; + use std::io; -use std::io::{BufReader, Read, Write}; -use std::net::SocketAddr; +use std::io::Write; use conduit::Handler; -use inflector::cases::traincase::to_train_case; - -use snafu::{ResultExt, Snafu}; - - -#[derive(Debug, Snafu)] -pub enum RequestError { - #[snafu(display("{}", source))] - InvalidMethod { source: http::method::InvalidMethod }, - - #[snafu(display("{}", source))] - InvalidHeaderName { source: conduit::header::InvalidHeaderName }, - - #[snafu(display("{}", source))] - InvalidHeaderValue { source: conduit::header::InvalidHeaderValue }, - - #[snafu(display("{}", source))] - InvalidRemoteAddr { source: RemoteAddrError }, -} - -pub type RequestResult<T, E = RequestError> = std::result::Result<T, E>; - -#[derive(Debug, Snafu)] -pub enum RemoteAddrError { - #[snafu(display("Could not parse address {}: {}", address, source))] - AddrParseError { - address: String, - source: std::net::AddrParseError, - }, - - #[snafu(display("Could not parse port {}: {}", port, source))] - PortParseError { - port: String, - source: std::num::ParseIntError - }, -} - - -struct FastCgiRequest<'a> { - request: &'a mut fastcgi::Request, - http_version: conduit::Version, - host: String, - method: conduit::Method, - headers: conduit::HeaderMap, - path: String, - query: Option<String>, - remote_addr: SocketAddr, - content_length: Option<u64>, - extensions: conduit::Extensions, -} - -impl<'a> FastCgiRequest<'a> { - pub fn new(request: &'a mut fastcgi::Request) -> RequestResult<Self> { - let version = Self::version(request); - let host = Self::host(request); - let method = Self::method(request).context(InvalidMethod)?; - let headers = Self::headers(request.params())?; - let path = Self::path(request); - let query = Self::query(request); - let remote_addr = Self::remote_addr(request).context(InvalidRemoteAddr)?; - let content_length = Self::content_length(request); - - Ok(Self { - request: request, - http_version: version, - host: host, - method: method, - headers: headers, - path: path, - query: query, - remote_addr: remote_addr, - content_length: content_length, - extensions: conduit::TypeMap::new(), - }) - } - - pub fn scheme(&self) -> conduit::Scheme { - let scheme = self.request.param("REQUEST_SCHEME").unwrap_or_default(); - - if scheme == "https" { - conduit::Scheme::Https - } else { - conduit::Scheme::Http - } - } - - fn version(request: &fastcgi::Request) -> conduit::Version { - match request.param("SERVER_PROTOCOL").unwrap_or_default().as_str() { - "HTTP/0.9" => conduit::Version::HTTP_09, - "HTTP/1.0" => conduit::Version::HTTP_10, - "HTTP/1.1" => conduit::Version::HTTP_11, - "HTTP/2.0" => conduit::Version::HTTP_2, - "HTTP/3.0" => conduit::Version::HTTP_3, - _ => conduit::Version::default(), - } - } - - fn host(request: &fastcgi::Request) -> String { - request.param("HTTP_HOST").unwrap_or_default() - } - - fn method( - request: &fastcgi::Request - ) -> Result<conduit::Method, http::method::InvalidMethod> { - conduit::Method::from_bytes( - request.param("REQUEST_METHOD") - .unwrap_or_default() - .as_bytes() - ) - } - - fn headers(params: fastcgi::Params) -> RequestResult<conduit::HeaderMap> { - let mut map = conduit::HeaderMap::new(); - let headers = Self::headers_from_params(params); - - for (name, value) in headers - .iter() - .map(|(name, value)| (name.as_bytes(), value.as_bytes())) - { - map.append( - conduit::header::HeaderName::from_bytes(name) - .context(InvalidHeaderName)?, - conduit::header::HeaderValue::from_bytes(value) - .context(InvalidHeaderValue)?, - ); - } - - Ok(map) - } - - fn headers_from_params(params: fastcgi::Params) -> Vec<(String, String)> { - return params - .filter(|(key, _)| key.starts_with("HTTP_")) - .map(|(key, value)| { - let key = key.get(5..).unwrap_or_default(); - let key = &key.replace("_", "-"); - let key = &to_train_case(&key); - - (key.to_owned(), value) - }) - .collect() - } - - fn path(request: &fastcgi::Request) -> String { - match request.param("SCRIPT_NAME") { - Some(p) => p, - None => "/".to_owned(), - } - } - - fn query(request: &fastcgi::Request) -> Option<String> { - request.param("QUERY_STRING") - } - - fn remote_addr(request: &fastcgi::Request) -> Result<SocketAddr, RemoteAddrError> { - let addr = request.param("REMOTE_ADDR").unwrap_or_default(); - let port = request.param("REMOTE_PORT").unwrap_or_default(); - - Ok( - SocketAddr::new( - addr.parse().context(AddrParseError { address: addr })?, - port.parse().context(PortParseError { port })?, - ) - ) - } - - fn content_length(request: &fastcgi::Request) -> Option<u64> { - request.param("CONTENT_LENGTH").and_then(|l| l.parse().ok()) - } -} - -impl<'a> Read for FastCgiRequest<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - self.request.stdin().read(buf) - } -} - -impl<'a> conduit::RequestExt for FastCgiRequest<'a> { - fn http_version(&self) -> conduit::Version { - self.http_version - } - - fn method(&self) -> &conduit::Method { - &self.method - } - - fn scheme(&self) -> conduit::Scheme { - self.scheme() - } - - fn host(&self) -> conduit::Host<'_> { - conduit::Host::Name(&self.host) - } - - fn virtual_root(&self) -> std::option::Option<&str> { - None - } - - fn path(&self) -> &str { - &self.path - } - - fn query_string(&self) -> std::option::Option<&str> { - self.query.as_ref() - .map(|p| p.as_str()) - } - - fn remote_addr(&self) -> std::net::SocketAddr { - self.remote_addr - } - - fn content_length(&self) -> std::option::Option<u64> { - self.content_length - } - - fn headers(&self) -> &conduit::HeaderMap { - &self.headers - } - - fn body(&mut self) -> &mut (dyn std::io::Read) { - self - } - - fn extensions(&self) -> &conduit::Extensions { - &self.extensions - } - - fn mut_extensions(&mut self) -> &mut conduit::Extensions { - &mut self.extensions - } -} - pub struct Server; impl Server { pub fn start<H: Handler + 'static + Sync>(handler: H) -> io::Result<Server> { fastcgi::run(move |mut raw_request| { - let mut request = FastCgiRequest::new(&mut raw_request).unwrap(); + let mut request = request::FastCgiRequest::new(&mut raw_request).unwrap(); let response = handler.call(&mut request); let mut stdout = raw_request.stdout(); |