diff --git a/src/httpcodes.rs b/src/httpcodes.rs index 76470da18..77d149176 100644 --- a/src/httpcodes.rs +++ b/src/httpcodes.rs @@ -45,3 +45,38 @@ impl From for HttpResponse { st.response() } } + + +#[cfg(test)] +mod tests { + use http::StatusCode; + use super::{HTTPOk, HTTPBadRequest, Body, HttpResponse}; + + #[test] + fn test_builder() { + let resp = HTTPOk.builder().body(Body::Empty).unwrap(); + assert_eq!(resp.status(), StatusCode::OK); + } + + #[test] + fn test_response() { + let resp = HTTPOk.response(); + assert_eq!(resp.status(), StatusCode::OK); + } + + #[test] + fn test_from() { + let resp: HttpResponse = HTTPOk.into(); + assert_eq!(resp.status(), StatusCode::OK); + } + + #[test] + fn test_with_reason() { + let resp = HTTPOk.response(); + assert_eq!(resp.reason(), ""); + + let resp = HTTPBadRequest.with_reason("test"); + assert_eq!(resp.status(), StatusCode::BAD_REQUEST); + assert_eq!(resp.reason(), "test"); + } +} diff --git a/src/httpmessage.rs b/src/httpmessage.rs index c1fd15c81..1fa01a141 100644 --- a/src/httpmessage.rs +++ b/src/httpmessage.rs @@ -24,6 +24,7 @@ pub struct HttpRequest { uri: Uri, headers: HeaderMap, params: Params, + cookies: Vec>, } impl HttpRequest { @@ -36,6 +37,7 @@ impl HttpRequest { version: version, headers: headers, params: Params::new(), + cookies: Vec::new(), } } @@ -78,15 +80,22 @@ impl HttpRequest { self.uri.query() } - /// Return request cookie. - pub fn cookie(&self) -> Result, cookie::ParseError> { + /// Return request cookies. + pub fn cookies(&mut self) -> &Vec> { + &self.cookies + } + + /// Load cookies + pub fn load_cookies(&mut self) -> Result<&Vec, cookie::ParseError> + { if let Some(val) = self.headers.get(header::COOKIE) { let s = str::from_utf8(val.as_bytes()) .map_err(cookie::ParseError::from)?; - cookie::Cookie::parse(s).map(Some) - } else { - Ok(None) + for cookie in s.split("; ") { + self.cookies.push(cookie::Cookie::parse_encoded(cookie)?.into_owned()); + } } + Ok(&self.cookies) } /// Get a mutable reference to the Request headers. @@ -109,7 +118,8 @@ impl HttpRequest { uri: self.uri, version: self.version, headers: self.headers, - params: params + params: params, + cookies: self.cookies, } } @@ -247,6 +257,16 @@ impl HttpResponse { &mut self.status } + /// Get custom reason for the response. + #[inline] + pub fn reason(&self) -> &str { + if let Some(ref reason) = self.reason { + reason + } else { + "" + } + } + /// Set the custom reason for the response. #[inline] pub fn set_reason(&mut self, reason: &'static str) -> &mut Self { @@ -255,7 +275,7 @@ impl HttpResponse { } /// Set connection type - pub fn set_connection_type(&mut self, conn: ConnectionType) -> &mut Self{ + pub fn set_connection_type(&mut self, conn: ConnectionType) -> &mut Self { self.connection_type = Some(conn); self } @@ -274,11 +294,6 @@ impl HttpResponse { } } - /// Force close connection, even if it is marked as keep-alive - pub fn force_close(&mut self) { - self.connection_type = Some(ConnectionType::Close); - } - /// is chunked encoding enabled pub fn chunked(&self) -> bool { self.chunked @@ -404,13 +419,23 @@ impl Builder { } /// Set connection type - pub fn connection_type(mut self, conn: ConnectionType) -> Self { + pub fn connection_type(&mut self, conn: ConnectionType) -> &mut Self { if let Some(parts) = parts(&mut self.parts, &self.err) { parts.connection_type = Some(conn); } self } + /// Set connection type to Upgrade + pub fn upgrade(&mut self) -> &mut Self { + self.connection_type(ConnectionType::Upgrade) + } + + /// Force close connection, even if it is marked as keep-alive + pub fn force_close(&mut self) -> &mut Self { + self.connection_type(ConnectionType::Close) + } + /// Enables automatic chunked transfer encoding pub fn enable_chunked(&mut self) -> &mut Self { if let Some(parts) = parts(&mut self.parts, &self.err) { @@ -419,6 +444,32 @@ impl Builder { self } + /// Set response content type + pub fn content_type(&mut self, value: V) -> &mut Self + where HeaderValue: HttpTryFrom + { + if let Some(parts) = parts(&mut self.parts, &self.err) { + match HeaderValue::try_from(value) { + Ok(value) => { parts.headers.insert(header::CONTENT_TYPE, value); }, + Err(e) => self.err = Some(e.into()), + }; + } + self + } + + /* /// Set response content charset + pub fn charset(&mut self, value: V) -> &mut Self + where HeaderValue: HttpTryFrom + { + if let Some(parts) = parts(&mut self.parts, &self.err) { + match HeaderValue::try_from(value) { + Ok(value) => { parts.headers.insert(header::CONTENT_TYPE, value); }, + Err(e) => self.err = Some(e.into()), + }; + } + self + }*/ + /// Set a body pub fn body>(&mut self, body: B) -> Result { let parts = self.parts.take().expect("cannot reuse response builder"); diff --git a/tests/test_httpmessage.rs b/tests/test_httpmessage.rs new file mode 100644 index 000000000..be220488e --- /dev/null +++ b/tests/test_httpmessage.rs @@ -0,0 +1,32 @@ +extern crate actix_web; +extern crate http; + +use actix_web::*; +use http::{header, Method, Uri, Version, HeaderMap, HttpTryFrom}; + + +#[test] +fn test_no_request_cookies() { + let mut req = HttpRequest::new( + Method::GET, Uri::try_from("/").unwrap(), Version::HTTP_11, HeaderMap::new()); + assert!(req.cookies().is_empty()); + let _ = req.load_cookies(); + assert!(req.cookies().is_empty()); +} + +#[test] +fn test_request_cookies() { + let mut headers = HeaderMap::new(); + headers.insert(header::COOKIE, + header::HeaderValue::from_static("cookie1=value1; cookie2=value2")); + + let mut req = HttpRequest::new( + Method::GET, Uri::try_from("/").unwrap(), Version::HTTP_11, headers); + assert!(req.cookies().is_empty()); + let cookies = req.load_cookies().unwrap(); + assert_eq!(cookies.len(), 2); + assert_eq!(cookies[0].name(), "cookie1"); + assert_eq!(cookies[0].value(), "value1"); + assert_eq!(cookies[1].name(), "cookie2"); + assert_eq!(cookies[1].value(), "value2"); +}