From a99b8b984180d7089006ef9f92259984be4f74ef Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Jun 2020 17:15:10 +0200 Subject: Create a wrapper struct for `fastcgi::Request` Trying out the Conduit API, as it seems like nice interface that I can plug the FastCGI server into. To do this, I need a server type, and some way to convert a `fastcgi::Request` into a `conduit::Request`. Doing this with a new local type that I can use to implement `conduit::RequestExt`. --- src/lib.rs | 133 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 73 insertions(+), 60 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 790a8f6..6253bf0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,84 +1,97 @@ +extern crate conduit; extern crate fastcgi; extern crate http; +use std::io; use std::io::{BufReader, Write}; -use http::{Request, Response}; -use http::request; +use conduit::Handler; + use inflector::cases::traincase::to_train_case; +use snafu::{ResultExt, Snafu}; -pub fn run(handler: F) -where F: Fn(Request<()>) -> Response + Send + Sync + 'static -{ - fastcgi::run(move |mut req| { - let r: http::request::Builder = From::from(&req); - handler(r.body(()).unwrap()); +#[derive(Debug, Snafu)] +pub enum RequestError { + #[snafu(display("{}", source))] + InvalidMethod { source: http::method::InvalidMethod }, +} - let params = req.params() - .map(|(k, v)| k + ": " + &v) - .collect::>() - .join("\n"); +pub type RequestResult = std::result::Result; - write!( - &mut req.stdout(), - "Content-Type: text/plain\n\n{}", - params - ) - .unwrap_or(()); - }); -} -trait From: Sized { - fn from(_: T) -> Self; +struct FastCgiRequest<'a> { + request: &'a fastcgi::Request, + method: conduit::Method, } -impl From<&fastcgi::Request> for http::request::Builder { - fn from(request: &fastcgi::Request) -> Self { - let method = request.param("REQUEST_METHOD") - .unwrap_or("".to_owned()); - - let uri = format!( - "{}://{}{}", - request.param("REQUEST_SCHEME").unwrap_or("".to_owned()), - request.param("HTTP_HOST").unwrap_or("".to_owned()), - request.param("REQUEST_URI").unwrap_or("".to_owned()), - ); +impl<'a> FastCgiRequest<'a> { + pub fn new(request: &'a fastcgi::Request) -> RequestResult { + let method = Self::method(request) + .context(InvalidMethod)?; - let mut http_request = http::request::Builder::new() - .method(&*method) - .uri(&uri); + let r = Self { + request: request, + method: method, + }; - let headers = headers_from_params(request.params()); - for (k, v) in headers { - http_request = http_request.header(&k, &v); - } + r.parse(); - // TODO: Add request body + Ok(r) + } - http_request + fn parse(&self) { + let headers = Self::headers_from_params(self.request.params()); + } - // let body = BufReader::new(request.stdin()); - // - // http_request.body(body) + fn method( + request: &'a fastcgi::Request + ) -> Result { + conduit::Method::from_bytes( + request.param("REQUEST_METHOD") + .unwrap_or_default() + .as_bytes() + ) + } - // HTTP_* params become headers + 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 headers_from_params(params: fastcgi::Params) -> Vec<(String, String)> { - return params - .filter(|(key, _)| key.starts_with("HTTP_")) - .map(|(key, value)| { - let mut key = key.get(5..).unwrap_or("").to_owned(); - key = key.replace("_", "-"); - key = to_train_case(&key); - - // Change _ to - - // Uppercase each word - - (key, value) - }) - .collect() +// impl<'a> conduit::RequestExt for FastCgiRequest { +// fn http_version(&self) -> conduit::Version { todo!() } +// fn method(&self) -> &conduit::Method { +// self.method +// } +// fn scheme(&self) -> conduit::Scheme { todo!() } +// fn host(&'a self) -> conduit::Host<'a> { todo!() } +// fn virtual_root(&'a self) -> std::option::Option<&'a str> { todo!() } +// fn path(&'a self) -> &'a str { todo!() } +// fn query_string(&'a self) -> std::option::Option<&'a str> { todo!() } +// fn remote_addr(&self) -> std::net::SocketAddr { todo!() } +// fn content_length(&self) -> std::option::Option { todo!() } +// fn headers(&self) -> &conduit::HeaderMap { todo!() } +// fn body(&'a mut self) -> &'a mut (dyn std::io::Read + 'a) { todo!() } +// fn extensions(&'a self) -> &'a conduit::TypeMap { todo!() } +// fn mut_extensions(&'a mut self) -> &'a mut conduit::TypeMap { todo!() } +// } + + +struct Server; + +impl Server { + pub fn start(handler: H) -> io::Result { + Ok(Server{}) + } } -- cgit v1.2.3 From 13cc04731d01ce216b274f53c920f9e19d15e25e Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Jun 2020 18:32:41 +0200 Subject: FastCgiRequest: Parse headers to a `conduit::HeaderMap` --- src/lib.rs | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 6253bf0..a8f55a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,12 @@ use snafu::{ResultExt, 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 }, } pub type RequestResult = std::result::Result; @@ -24,6 +30,7 @@ pub type RequestResult = std::result::Result; struct FastCgiRequest<'a> { request: &'a fastcgi::Request, method: conduit::Method, + headers: conduit::HeaderMap, } impl<'a> FastCgiRequest<'a> { @@ -31,20 +38,17 @@ impl<'a> FastCgiRequest<'a> { let method = Self::method(request) .context(InvalidMethod)?; + let headers = Self::headers(request.params())?; + let r = Self { request: request, method: method, + headers: headers, }; - r.parse(); - Ok(r) } - fn parse(&self) { - let headers = Self::headers_from_params(self.request.params()); - } - fn method( request: &'a fastcgi::Request ) -> Result { @@ -55,6 +59,25 @@ impl<'a> FastCgiRequest<'a> { ) } + fn headers(params: fastcgi::Params) -> RequestResult { + 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_")) -- cgit v1.2.3 From a078391aad95978f11488040bb794f2b7622311f Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Jun 2020 20:05:53 +0200 Subject: FastCgiRequest: Add `conduit::Version` --- src/lib.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index a8f55a5..0229980 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ pub type RequestResult = std::result::Result; struct FastCgiRequest<'a> { request: &'a fastcgi::Request, + http_version: conduit::Version, method: conduit::Method, headers: conduit::HeaderMap, } @@ -42,6 +43,7 @@ impl<'a> FastCgiRequest<'a> { let r = Self { request: request, + http_version: Self::version(&request), method: method, headers: headers, }; @@ -49,6 +51,17 @@ impl<'a> FastCgiRequest<'a> { Ok(r) } + fn version(request: &'a 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 method( request: &'a fastcgi::Request ) -> Result { -- cgit v1.2.3 From 5fd74d9b6356a3feebd6c1bff134e2f411c7c1dd Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Jun 2020 20:06:34 +0200 Subject: FastCgiRequest: Add `conduit::Scheme` --- src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 0229980..16cfd02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,16 @@ impl<'a> FastCgiRequest<'a> { Ok(r) } + 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: &'a fastcgi::Request) -> conduit::Version { match request.param("SERVER_PROTOCOL").unwrap_or_default().as_str() { "HTTP/0.9" => conduit::Version::HTTP_09, -- cgit v1.2.3 From b8ac72f1fb4b6e3e0575e212bf6138e20bd9bdff Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Jun 2020 20:07:07 +0200 Subject: FastCgiRequest: Add HTTP host --- src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 16cfd02..d237bab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ pub type RequestResult = std::result::Result; struct FastCgiRequest<'a> { request: &'a fastcgi::Request, http_version: conduit::Version, + host: String, method: conduit::Method, headers: conduit::HeaderMap, } @@ -44,6 +45,7 @@ impl<'a> FastCgiRequest<'a> { let r = Self { request: request, http_version: Self::version(&request), + host: Self::host(&request), method: method, headers: headers, }; @@ -61,6 +63,10 @@ impl<'a> FastCgiRequest<'a> { } } + fn host(request: &'a fastcgi::Request) -> String { + request.param("HTTP_HOST").unwrap_or_default() + } + fn version(request: &'a fastcgi::Request) -> conduit::Version { match request.param("SERVER_PROTOCOL").unwrap_or_default().as_str() { "HTTP/0.9" => conduit::Version::HTTP_09, -- cgit v1.2.3 From 81402cc311ae075d036759cabab829f61fd216be Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Jun 2020 20:07:22 +0200 Subject: FastCgiRequest: Start implementing `conduit::RequestExt` Was getting this error about the lifetimes in the trait impl: error[E0308]: method not compatible with trait --> src/lib.rs:137:4 | 137 | fn host(&'a self) -> conduit::Host<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected fn pointer `fn(&'a FastCgiRequest<'static>) -> conduit::Host<'a>` found fn pointer `fn(&'a FastCgiRequest<'static>) -> conduit::Host<'a>` note: the lifetime `'a` as defined on the method body at 137:4... --> src/lib.rs:137:4 | 137 | fn host(&'a self) -> conduit::Host<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 124:6 --> src/lib.rs:124:6 | 124 | impl<'a> conduit::RequestExt for FastCgiRequest { | ^^ error[E0308]: method not compatible with trait --> src/lib.rs:137:4 | 137 | fn host(&'a self) -> conduit::Host<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected fn pointer `fn(&'a FastCgiRequest<'static>) -> conduit::Host<'a>` found fn pointer `fn(&'a FastCgiRequest<'static>) -> conduit::Host<'a>` note: the lifetime `'a` as defined on the impl at 124:6... --> src/lib.rs:124:6 | 124 | impl<'a> conduit::RequestExt for FastCgiRequest { | ^^ note: ...does not necessarily outlive the lifetime `'a` as defined on the method body at 137:4 --> src/lib.rs:137:4 | 137 | fn host(&'a self) -> conduit::Host<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Learned from these resources that the problem arose because the `impl` uses an `'a` lifetime, but the lifetime on the `host()` method need to be a different one: https://github.com/rust-lang/rust/issues/56423 https://stackoverflow.com/questions/24847331/rust-lifetime-error-expected-concrete-lifetime-but-found-bound-lifetime/24848424#24848424 --- src/lib.rs | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index d237bab..98dcba7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,23 +121,34 @@ impl<'a> FastCgiRequest<'a> { } } -// impl<'a> conduit::RequestExt for FastCgiRequest { -// fn http_version(&self) -> conduit::Version { todo!() } -// fn method(&self) -> &conduit::Method { -// self.method -// } -// fn scheme(&self) -> conduit::Scheme { todo!() } -// fn host(&'a self) -> conduit::Host<'a> { todo!() } -// fn virtual_root(&'a self) -> std::option::Option<&'a str> { todo!() } -// fn path(&'a self) -> &'a str { todo!() } -// fn query_string(&'a self) -> std::option::Option<&'a str> { todo!() } -// fn remote_addr(&self) -> std::net::SocketAddr { todo!() } -// fn content_length(&self) -> std::option::Option { todo!() } -// fn headers(&self) -> &conduit::HeaderMap { todo!() } -// fn body(&'a mut self) -> &'a mut (dyn std::io::Read + 'a) { todo!() } -// fn extensions(&'a self) -> &'a conduit::TypeMap { todo!() } -// fn mut_extensions(&'a mut self) -> &'a mut conduit::TypeMap { todo!() } -// } +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<'b>(&'b self) -> conduit::Host<'b> { + conduit::Host::Name(&self.host) + } + + fn virtual_root<'b>(&'b self) -> std::option::Option<&'b str> { todo!() } + + fn path<'b>(&'b self) -> &'b str { todo!() } + fn query_string<'b>(&'b self) -> std::option::Option<&'b str> { todo!() } + fn remote_addr<'b>(&self) -> std::net::SocketAddr { todo!() } + fn content_length<'b>(&self) -> std::option::Option { todo!() } + fn headers<'b>(&self) -> &conduit::HeaderMap { todo!() } + fn body<'b>(&'b mut self) -> &'b mut (dyn std::io::Read + 'b) { todo!() } + fn extensions<'b>(&'b self) -> &'b conduit::TypeMap { todo!() } + fn mut_extensions<'b>(&'b mut self) -> &'b mut conduit::TypeMap { todo!() } +} struct Server; -- cgit v1.2.3 From 21bbc6274117cd4b9a15dda63de284e8f9bad34d Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Jun 2020 20:45:07 +0200 Subject: FastCgiRequest: Remove elidable `'b` lifetime in `conduit::RequestExt` Turns out I don't need this `'b` lifetime in the `conduit::RequestExt` `impl`. I had just assumed it was necessary because I copied it as `'a` from the "missing trait methods" error message. --- src/lib.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 98dcba7..21ecf31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,20 +134,20 @@ impl<'a> conduit::RequestExt for FastCgiRequest<'a> { self.scheme() } - fn host<'b>(&'b self) -> conduit::Host<'b> { + fn host(&self) -> conduit::Host<'_> { conduit::Host::Name(&self.host) } - fn virtual_root<'b>(&'b self) -> std::option::Option<&'b str> { todo!() } + fn virtual_root(&self) -> std::option::Option<&str> { todo!() } - fn path<'b>(&'b self) -> &'b str { todo!() } - fn query_string<'b>(&'b self) -> std::option::Option<&'b str> { todo!() } - fn remote_addr<'b>(&self) -> std::net::SocketAddr { todo!() } - fn content_length<'b>(&self) -> std::option::Option { todo!() } - fn headers<'b>(&self) -> &conduit::HeaderMap { todo!() } - fn body<'b>(&'b mut self) -> &'b mut (dyn std::io::Read + 'b) { todo!() } - fn extensions<'b>(&'b self) -> &'b conduit::TypeMap { todo!() } - fn mut_extensions<'b>(&'b mut self) -> &'b mut conduit::TypeMap { todo!() } + fn path(&self) -> &str { todo!() } + fn query_string(&self) -> std::option::Option<&str> { todo!() } + fn remote_addr(&self) -> std::net::SocketAddr { todo!() } + fn content_length(&self) -> std::option::Option { todo!() } + fn headers(&self) -> &conduit::HeaderMap { todo!() } + fn body(&mut self) -> &mut (dyn std::io::Read) { todo!() } + fn extensions(&self) -> &conduit::TypeMap { todo!() } + fn mut_extensions(&mut self) -> &mut conduit::TypeMap { todo!() } } -- cgit v1.2.3 From 298d4555f9f5a0a322681e380a1d686972bfbf27 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Jun 2020 20:47:04 +0200 Subject: FastCgiRequest: Use a `None` `virtual_root` Looks like we don't need to implement this hopefully. --- src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 21ecf31..ca0fb83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,7 +138,9 @@ impl<'a> conduit::RequestExt for FastCgiRequest<'a> { conduit::Host::Name(&self.host) } - fn virtual_root(&self) -> std::option::Option<&str> { todo!() } + fn virtual_root(&self) -> std::option::Option<&str> { + None + } fn path(&self) -> &str { todo!() } fn query_string(&self) -> std::option::Option<&str> { todo!() } -- cgit v1.2.3 From cb1ffca05c679f41490a09fc9e107da707858068 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Jun 2020 21:08:58 +0200 Subject: FastCgiRequest: Add request path --- src/lib.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index ca0fb83..f481f59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,7 @@ struct FastCgiRequest<'a> { host: String, method: conduit::Method, headers: conduit::HeaderMap, + path: String, } impl<'a> FastCgiRequest<'a> { @@ -48,6 +49,7 @@ impl<'a> FastCgiRequest<'a> { host: Self::host(&request), method: method, headers: headers, + path: Self::path(&request), }; Ok(r) @@ -119,6 +121,13 @@ impl<'a> FastCgiRequest<'a> { }) .collect() } + + fn path(request: &'a fastcgi::Request) -> String { + match request.param("SCRIPT_NAME") { + Some(p) => p, + None => "/".to_owned(), + } + } } impl<'a> conduit::RequestExt for FastCgiRequest<'a> { @@ -142,7 +151,10 @@ impl<'a> conduit::RequestExt for FastCgiRequest<'a> { None } - fn path(&self) -> &str { todo!() } + fn path(&self) -> &str { + &self.path + } + fn query_string(&self) -> std::option::Option<&str> { todo!() } fn remote_addr(&self) -> std::net::SocketAddr { todo!() } fn content_length(&self) -> std::option::Option { todo!() } -- cgit v1.2.3 From 0be4106a600b2e038170d4c49136f50ad54af6b7 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 27 Jun 2020 21:17:14 +0200 Subject: FastCgiRequest: Add query string --- src/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index f481f59..5571525 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,7 @@ struct FastCgiRequest<'a> { method: conduit::Method, headers: conduit::HeaderMap, path: String, + query: Option, } impl<'a> FastCgiRequest<'a> { @@ -50,6 +51,7 @@ impl<'a> FastCgiRequest<'a> { method: method, headers: headers, path: Self::path(&request), + query: Self::query(&request), }; Ok(r) @@ -128,6 +130,10 @@ impl<'a> FastCgiRequest<'a> { None => "/".to_owned(), } } + + fn query(request: &'a fastcgi::Request) -> Option { + request.param("QUERY_STRING") + } } impl<'a> conduit::RequestExt for FastCgiRequest<'a> { @@ -155,7 +161,11 @@ impl<'a> conduit::RequestExt for FastCgiRequest<'a> { &self.path } - fn query_string(&self) -> std::option::Option<&str> { todo!() } + fn query_string(&self) -> std::option::Option<&str> { + self.query.as_ref() + .map(|p| p.as_str()) + } + fn remote_addr(&self) -> std::net::SocketAddr { todo!() } fn content_length(&self) -> std::option::Option { todo!() } fn headers(&self) -> &conduit::HeaderMap { todo!() } -- cgit v1.2.3 From 030ba89d5621ba5bb770d519eb68980b9da85b89 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 28 Jun 2020 01:27:42 +0200 Subject: FastCgiRequest: Add remote addr Seemed to make sense to add a new error type to group the parse errors together. --- src/lib.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 5571525..fcfec03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ extern crate http; use std::io; use std::io::{BufReader, Write}; +use std::net::SocketAddr; use conduit::Handler; @@ -22,10 +23,28 @@ pub enum RequestError { #[snafu(display("{}", source))] InvalidHeaderValue { source: conduit::header::InvalidHeaderValue }, + + #[snafu(display("{}", source))] + InvalidRemoteAddr { source: RemoteAddrError }, } pub type RequestResult = std::result::Result; +#[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 fastcgi::Request, @@ -35,6 +54,7 @@ struct FastCgiRequest<'a> { headers: conduit::HeaderMap, path: String, query: Option, + remote_addr: SocketAddr, } impl<'a> FastCgiRequest<'a> { @@ -52,6 +72,7 @@ impl<'a> FastCgiRequest<'a> { headers: headers, path: Self::path(&request), query: Self::query(&request), + remote_addr: Self::remote_addr(&request).context(InvalidRemoteAddr)?, }; Ok(r) @@ -134,6 +155,18 @@ impl<'a> FastCgiRequest<'a> { fn query(request: &'a fastcgi::Request) -> Option { request.param("QUERY_STRING") } + + fn remote_addr(request: &'a fastcgi::Request) -> Result { + 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 })?, + ) + ) + } } impl<'a> conduit::RequestExt for FastCgiRequest<'a> { @@ -166,7 +199,10 @@ impl<'a> conduit::RequestExt for FastCgiRequest<'a> { .map(|p| p.as_str()) } - fn remote_addr(&self) -> std::net::SocketAddr { todo!() } + fn remote_addr(&self) -> std::net::SocketAddr { + self.remote_addr + } + fn content_length(&self) -> std::option::Option { todo!() } fn headers(&self) -> &conduit::HeaderMap { todo!() } fn body(&mut self) -> &mut (dyn std::io::Read) { todo!() } -- cgit v1.2.3 From 5007e55f291e71abff3a5bc6305b40bd8ad27af1 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 28 Jun 2020 01:52:14 +0200 Subject: FastCgiRequest: Add content length --- src/lib.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index fcfec03..a27b305 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,6 +55,7 @@ struct FastCgiRequest<'a> { path: String, query: Option, remote_addr: SocketAddr, + content_length: Option, } impl<'a> FastCgiRequest<'a> { @@ -73,6 +74,7 @@ impl<'a> FastCgiRequest<'a> { path: Self::path(&request), query: Self::query(&request), remote_addr: Self::remote_addr(&request).context(InvalidRemoteAddr)?, + content_length: Self::content_length(&request), }; Ok(r) @@ -167,6 +169,10 @@ impl<'a> FastCgiRequest<'a> { ) ) } + + fn content_length(request: &'a fastcgi::Request) -> Option { + request.param("CONTENT_LENGTH").and_then(|l| l.parse().ok()) + } } impl<'a> conduit::RequestExt for FastCgiRequest<'a> { @@ -203,7 +209,10 @@ impl<'a> conduit::RequestExt for FastCgiRequest<'a> { self.remote_addr } - fn content_length(&self) -> std::option::Option { todo!() } + fn content_length(&self) -> std::option::Option { + self.content_length + } + fn headers(&self) -> &conduit::HeaderMap { todo!() } fn body(&mut self) -> &mut (dyn std::io::Read) { todo!() } fn extensions(&self) -> &conduit::TypeMap { todo!() } -- cgit v1.2.3 From 3ae94ad6923ff53fd66f428cd340a85679033598 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 28 Jun 2020 01:53:32 +0200 Subject: FastCgiRequest: Add headers to `conduit::RequestExt` --- src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index a27b305..73e30b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -213,7 +213,10 @@ impl<'a> conduit::RequestExt for FastCgiRequest<'a> { self.content_length } - fn headers(&self) -> &conduit::HeaderMap { todo!() } + fn headers(&self) -> &conduit::HeaderMap { + &self.headers + } + fn body(&mut self) -> &mut (dyn std::io::Read) { todo!() } fn extensions(&self) -> &conduit::TypeMap { todo!() } fn mut_extensions(&mut self) -> &mut conduit::TypeMap { todo!() } -- cgit v1.2.3 From 2504f6c2db528a348dc6cdb2e48b1f9d8d30dda3 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 28 Jun 2020 02:03:29 +0200 Subject: FastCgiRequest: Add empty extensions map to impls --- src/lib.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 73e30b2..9903c1a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,6 +56,7 @@ struct FastCgiRequest<'a> { query: Option, remote_addr: SocketAddr, content_length: Option, + extensions: conduit::Extensions, } impl<'a> FastCgiRequest<'a> { @@ -75,6 +76,7 @@ impl<'a> FastCgiRequest<'a> { query: Self::query(&request), remote_addr: Self::remote_addr(&request).context(InvalidRemoteAddr)?, content_length: Self::content_length(&request), + extensions: conduit::TypeMap::new(), }; Ok(r) @@ -218,8 +220,14 @@ impl<'a> conduit::RequestExt for FastCgiRequest<'a> { } fn body(&mut self) -> &mut (dyn std::io::Read) { todo!() } - fn extensions(&self) -> &conduit::TypeMap { todo!() } - fn mut_extensions(&mut self) -> &mut conduit::TypeMap { todo!() } + + fn extensions(&self) -> &conduit::Extensions { + &self.extensions + } + + fn mut_extensions(&mut self) -> &mut conduit::Extensions { + &mut self.extensions + } } -- cgit v1.2.3 From a2156b678a23d49a710ca5ff1345bee1c90254ec Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 28 Jun 2020 11:26:16 +0200 Subject: FastCgiRequest: Implement `conduit::RequestExt` `body` method Needed to change some things around to be able to use a mutable borrow for the `fastcgi::Stdin` body and an immutable borrow of `request` for all the other fields. Passed `fastcgi::Stdin` over through a `Read` implementation, because returning `&mut self.request.stdin()` was impossible, since the caller owns the `fastcgi::Stdin` reference. --- src/lib.rs | 52 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 9903c1a..ff0dce5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ extern crate fastcgi; extern crate http; use std::io; -use std::io::{BufReader, Write}; +use std::io::{BufReader, Read, Write}; use std::net::SocketAddr; use conduit::Handler; @@ -47,7 +47,7 @@ pub enum RemoteAddrError { struct FastCgiRequest<'a> { - request: &'a fastcgi::Request, + request: &'a mut fastcgi::Request, http_version: conduit::Version, host: String, method: conduit::Method, @@ -60,22 +60,26 @@ struct FastCgiRequest<'a> { } impl<'a> FastCgiRequest<'a> { - pub fn new(request: &'a fastcgi::Request) -> RequestResult { - let method = Self::method(request) - .context(InvalidMethod)?; - + pub fn new(request: &'a mut fastcgi::Request) -> RequestResult { + 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); let r = Self { request: request, - http_version: Self::version(&request), - host: Self::host(&request), + http_version: version, + host: host, method: method, headers: headers, - path: Self::path(&request), - query: Self::query(&request), - remote_addr: Self::remote_addr(&request).context(InvalidRemoteAddr)?, - content_length: Self::content_length(&request), + path: path, + query: query, + remote_addr: remote_addr, + content_length: content_length, extensions: conduit::TypeMap::new(), }; @@ -92,11 +96,11 @@ impl<'a> FastCgiRequest<'a> { } } - fn host(request: &'a fastcgi::Request) -> String { + fn host(request: &fastcgi::Request) -> String { request.param("HTTP_HOST").unwrap_or_default() } - fn version(request: &'a fastcgi::Request) -> conduit::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, "HTTP/1.0" => conduit::Version::HTTP_10, @@ -108,7 +112,7 @@ impl<'a> FastCgiRequest<'a> { } fn method( - request: &'a fastcgi::Request + request: &fastcgi::Request ) -> Result { conduit::Method::from_bytes( request.param("REQUEST_METHOD") @@ -149,18 +153,18 @@ impl<'a> FastCgiRequest<'a> { .collect() } - fn path(request: &'a fastcgi::Request) -> String { + fn path(request: &fastcgi::Request) -> String { match request.param("SCRIPT_NAME") { Some(p) => p, None => "/".to_owned(), } } - fn query(request: &'a fastcgi::Request) -> Option { + fn query(request: &fastcgi::Request) -> Option { request.param("QUERY_STRING") } - fn remote_addr(request: &'a fastcgi::Request) -> Result { + 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(); @@ -172,11 +176,17 @@ impl<'a> FastCgiRequest<'a> { ) } - fn content_length(request: &'a fastcgi::Request) -> Option { + fn content_length(request: &fastcgi::Request) -> Option { 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 { + self.request.stdin().read(buf) + } +} + impl<'a> conduit::RequestExt for FastCgiRequest<'a> { fn http_version(&self) -> conduit::Version { self.http_version @@ -219,7 +229,9 @@ impl<'a> conduit::RequestExt for FastCgiRequest<'a> { &self.headers } - fn body(&mut self) -> &mut (dyn std::io::Read) { todo!() } + fn body(&mut self) -> &mut (dyn std::io::Read) { + self + } fn extensions(&self) -> &conduit::Extensions { &self.extensions -- cgit v1.2.3 From ed3ab289d13e6024fb504a2d1cfb3852f2327220 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 28 Jun 2020 12:00:59 +0200 Subject: FastCgiRequest: Reorder `host` method implementation To match the struct field order. --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index ff0dce5..ebb024b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,10 +96,6 @@ impl<'a> FastCgiRequest<'a> { } } - fn host(request: &fastcgi::Request) -> String { - request.param("HTTP_HOST").unwrap_or_default() - } - fn version(request: &fastcgi::Request) -> conduit::Version { match request.param("SERVER_PROTOCOL").unwrap_or_default().as_str() { "HTTP/0.9" => conduit::Version::HTTP_09, @@ -111,6 +107,10 @@ impl<'a> FastCgiRequest<'a> { } } + fn host(request: &fastcgi::Request) -> String { + request.param("HTTP_HOST").unwrap_or_default() + } + fn method( request: &fastcgi::Request ) -> Result { -- cgit v1.2.3 From 0529b3763ca263f6c45fb632f24cf5d3c5ea0271 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 28 Jun 2020 12:02:28 +0200 Subject: FastCgiRequest::new: Remove unnecessary variable --- src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index ebb024b..0da0f58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,7 +70,7 @@ impl<'a> FastCgiRequest<'a> { let remote_addr = Self::remote_addr(request).context(InvalidRemoteAddr)?; let content_length = Self::content_length(request); - let r = Self { + Ok(Self { request: request, http_version: version, host: host, @@ -81,9 +81,7 @@ impl<'a> FastCgiRequest<'a> { remote_addr: remote_addr, content_length: content_length, extensions: conduit::TypeMap::new(), - }; - - Ok(r) + }) } pub fn scheme(&self) -> conduit::Scheme { -- cgit v1.2.3 From a613320c5f69089feba14ef36de58bdc21dd7e0b Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 28 Jun 2020 18:22:18 +0200 Subject: Server: Working `start()` implementation Got a draft version of the server working. Change the example to use the new Conduit server. Got a working HTML fragment response. Need to handle `conduit::Body::File` as well as unwrapped errors. --- src/lib.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 0da0f58..5d26a98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -241,10 +241,33 @@ impl<'a> conduit::RequestExt for FastCgiRequest<'a> { } -struct Server; +pub struct Server; impl Server { pub fn start(handler: H) -> io::Result { + fastcgi::run(move |mut raw_request| { + let mut request = FastCgiRequest::new(&mut raw_request).unwrap(); + let response = handler.call(&mut request); + + let mut stdout = raw_request.stdout(); + + let (head, body) = response.unwrap().into_parts(); + + for (name, value) in head.headers.iter() { + write!(&mut stdout, "{}: ", name).unwrap(); + stdout.write(value.as_bytes()).unwrap(); + stdout.write(b"\r\n").unwrap(); + } + + stdout.write(b"\r\n").unwrap(); + + match body { + conduit::Body::Static(slice) => stdout.write(slice).map(|_| ()).unwrap(), + conduit::Body::Owned(vec) => stdout.write(&vec).map(|_| ()).unwrap(), + conduit::Body::File(file) => (), + }; + }); + Ok(Server{}) } } -- cgit v1.2.3 From 8ac4bfa0c941acefedf0d384685e8b422fc4b426 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 28 Jun 2020 19:54:01 +0200 Subject: Server::start(): Write HTTP version and status code --- src/lib.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 5d26a98..558460f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -253,6 +253,13 @@ impl Server { let (head, body) = response.unwrap().into_parts(); + write!( + &mut stdout, + "HTTP/1.1 {} {}\r\n", + head.status.as_str(), + head.status.canonical_reason().unwrap_or("UNKNOWN"), + ); + for (name, value) in head.headers.iter() { write!(&mut stdout, "{}: ", name).unwrap(); stdout.write(value.as_bytes()).unwrap(); -- cgit v1.2.3 From 13fd1f2619df452dba2ab6ca8340de32c996d268 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sun, 28 Jun 2020 19:56:45 +0200 Subject: Server::start: Implement `conduit::Body::File` response --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 558460f..78be10d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -271,7 +271,7 @@ impl Server { match body { conduit::Body::Static(slice) => stdout.write(slice).map(|_| ()).unwrap(), conduit::Body::Owned(vec) => stdout.write(&vec).map(|_| ()).unwrap(), - conduit::Body::File(file) => (), + conduit::Body::File(mut file) => io::copy(&mut file, &mut stdout).map(|_| ()).unwrap(), }; }); -- cgit v1.2.3 From 4d24b2ce62f7f011297fe2b61358c9124af129e5 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Mon, 29 Jun 2020 00:13:28 +0200 Subject: Move request code to `request.rs` Want to separate request and server code. --- src/lib.rs | 239 ++----------------------------------------------------------- 1 file changed, 4 insertions(+), 235 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 78be10d..315417e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 = std::result::Result; - -#[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, - remote_addr: SocketAddr, - content_length: Option, - extensions: conduit::Extensions, -} - -impl<'a> FastCgiRequest<'a> { - pub fn new(request: &'a mut fastcgi::Request) -> RequestResult { - 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::from_bytes( - request.param("REQUEST_METHOD") - .unwrap_or_default() - .as_bytes() - ) - } - - fn headers(params: fastcgi::Params) -> RequestResult { - 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 { - request.param("QUERY_STRING") - } - - 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(); - - Ok( - SocketAddr::new( - addr.parse().context(AddrParseError { address: addr })?, - port.parse().context(PortParseError { port })?, - ) - ) - } - - fn content_length(request: &fastcgi::Request) -> Option { - 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 { - 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 { - 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(handler: H) -> io::Result { 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(); -- cgit v1.2.3 From d0066b2e10c9c23650253b8a47db4da2ea9573f6 Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Mon, 29 Jun 2020 00:25:51 +0200 Subject: Move `Server` code into a `server.rs` module --- src/lib.rs | 45 ++------------------------------------------- 1 file changed, 2 insertions(+), 43 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 315417e..ab40fa9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,47 +3,6 @@ extern crate fastcgi; extern crate http; mod request; +mod server; -use std::io; -use std::io::Write; - -use conduit::Handler; - - -pub struct Server; - -impl Server { - pub fn start(handler: H) -> io::Result { - fastcgi::run(move |mut raw_request| { - let mut request = request::FastCgiRequest::new(&mut raw_request).unwrap(); - let response = handler.call(&mut request); - - let mut stdout = raw_request.stdout(); - - let (head, body) = response.unwrap().into_parts(); - - write!( - &mut stdout, - "HTTP/1.1 {} {}\r\n", - head.status.as_str(), - head.status.canonical_reason().unwrap_or("UNKNOWN"), - ); - - for (name, value) in head.headers.iter() { - write!(&mut stdout, "{}: ", name).unwrap(); - stdout.write(value.as_bytes()).unwrap(); - stdout.write(b"\r\n").unwrap(); - } - - stdout.write(b"\r\n").unwrap(); - - match body { - conduit::Body::Static(slice) => stdout.write(slice).map(|_| ()).unwrap(), - conduit::Body::Owned(vec) => stdout.write(&vec).map(|_| ()).unwrap(), - conduit::Body::File(mut file) => io::copy(&mut file, &mut stdout).map(|_| ()).unwrap(), - }; - }); - - Ok(Server{}) - } -} +pub use server::Server; -- cgit v1.2.3 From ab8b50d5b98ab071c5f70d929f1ca76f3faf71ca Mon Sep 17 00:00:00 2001 From: Teddy Wing Date: Sat, 4 Jul 2020 03:28:02 +0200 Subject: server: Log errors Provide a mechanism to get detailed error messages when 500 internal server errors happen. We don't want to expose any detailed error information to clients, but it would be useful for administrators to know the cause of any errors. --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index ab40fa9..2ffe77e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ extern crate conduit; extern crate fastcgi; extern crate http; +extern crate log; mod request; mod server; -- cgit v1.2.3