From 8d65468c58fcc85aab1ff0d7352839ee9530b02e Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Tue, 1 May 2018 17:19:15 -0700 Subject: [PATCH] refactor FromRequest trait --- MIGRATION.md | 4 + src/application.rs | 102 ++++++----------- src/extractor.rs | 157 +++++++++---------------- src/fs.rs | 14 +-- src/handler.rs | 114 +++++++++++------- src/helpers.rs | 8 +- src/httprequest.rs | 22 ++-- src/json.rs | 18 +-- src/pipeline.rs | 8 +- src/resource.rs | 2 +- src/route.rs | 9 +- src/scope.rs | 29 ++--- src/test.rs | 1 + src/with.rs | 279 ++++++++++++++++++++++++++++----------------- 14 files changed, 384 insertions(+), 383 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 24ccdb3a6..f343028b5 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -11,6 +11,10 @@ * `HttpRequest::extensions()` returns read only reference to the request's Extension `HttpRequest::extensions_mut()` returns mutable reference. +* `FromRequest::from_request()` accepts mutable reference to a request + +* `FromRequest::Result` has to implement `Into>` + ## Migration from 0.4 to 0.5 diff --git a/src/application.rs b/src/application.rs index bd6c4d007..dbb31a564 100644 --- a/src/application.rs +++ b/src/application.rs @@ -6,6 +6,7 @@ use handler::{FromRequest, Handler, Reply, Responder, RouteHandler, WrapHandler} use header::ContentEncoding; use http::Method; use httprequest::HttpRequest; +use httpresponse::HttpResponse; use middleware::Middleware; use pipeline::{HandlerType, Pipeline, PipelineHandler}; use resource::ResourceHandler; @@ -36,7 +37,9 @@ impl PipelineHandler for Inner { self.encoding } - fn handle(&mut self, req: HttpRequest, htype: HandlerType) -> Reply { + fn handle( + &mut self, req: HttpRequest, htype: HandlerType, + ) -> Reply { match htype { HandlerType::Normal(idx) => { self.resources[idx].handle(req, Some(&mut self.default)) @@ -87,7 +90,7 @@ impl HttpApplication { } #[cfg(test)] - pub(crate) fn run(&mut self, mut req: HttpRequest) -> Reply { + pub(crate) fn run(&mut self, mut req: HttpRequest) -> Reply { let tp = self.get_handler(&mut req); unsafe { &mut *self.inner.get() }.handle(req, tp) } @@ -669,24 +672,18 @@ mod tests { let req = TestRequest::with_uri("/test").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/blah").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); let mut app = App::new() .default_resource(|r| r.f(|_| HttpResponse::MethodNotAllowed())) .finish(); let req = TestRequest::with_uri("/blah").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::METHOD_NOT_ALLOWED - ); + assert_eq!(resp.as_msg().status(), StatusCode::METHOD_NOT_ALLOWED); } #[test] @@ -706,7 +703,7 @@ mod tests { let req = HttpRequest::default().with_state(Rc::clone(&app.state), app.router.clone()); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); } #[test] @@ -740,29 +737,23 @@ mod tests { let req = TestRequest::with_uri("/test").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/test/").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/test/app").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/testapp").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); let req = TestRequest::with_uri("/blah").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); } #[test] @@ -773,29 +764,23 @@ mod tests { let req = TestRequest::with_uri("/test").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/test/").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/test/app").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/testapp").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); let req = TestRequest::with_uri("/blah").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); } #[test] @@ -807,29 +792,23 @@ mod tests { let req = TestRequest::with_uri("/prefix/test").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/prefix/test/").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/prefix/test/app").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/prefix/testapp").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); let req = TestRequest::with_uri("/prefix/blah").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); } #[test] @@ -847,25 +826,19 @@ mod tests { .method(Method::GET) .finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/test") .method(Method::POST) .finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::CREATED - ); + assert_eq!(resp.as_msg().status(), StatusCode::CREATED); let req = TestRequest::with_uri("/test") .method(Method::HEAD) .finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); } #[test] @@ -877,36 +850,27 @@ mod tests { let req = TestRequest::with_uri("/test").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); let req = TestRequest::with_uri("/app/test").finish(); let resp = app.run(req.clone()); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); assert_eq!(req.prefix_len(), 9); let req = TestRequest::with_uri("/app/test/").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/app/test/app").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); let req = TestRequest::with_uri("/app/testapp").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); let req = TestRequest::with_uri("/app/blah").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); } } diff --git a/src/extractor.rs b/src/extractor.rs index 1aef7ac53..4ed88489e 100644 --- a/src/extractor.rs +++ b/src/extractor.rs @@ -4,14 +4,14 @@ use std::str; use bytes::Bytes; use encoding::all::UTF_8; use encoding::types::{DecoderTrap, Encoding}; -use futures::future::{result, Future, FutureResult}; +use futures::future::Future; use mime::Mime; use serde::de::{self, DeserializeOwned}; use serde_urlencoded; use de::PathDeserializer; use error::{Error, ErrorBadRequest}; -use handler::{Either, FromRequest}; +use handler::FromRequest; use httpmessage::{HttpMessage, MessageBody, UrlEncoded}; use httprequest::HttpRequest; @@ -102,16 +102,14 @@ where S: 'static, { type Config = (); - type Result = FutureResult; + type Result = Result; #[inline] - fn from_request(req: &HttpRequest, _: &Self::Config) -> Self::Result { + fn from_request(req: &mut HttpRequest, _: &Self::Config) -> Self::Result { let req = req.clone(); - result( - de::Deserialize::deserialize(PathDeserializer::new(&req)) - .map_err(|e| e.into()) - .map(|inner| Path { inner }), - ) + de::Deserialize::deserialize(PathDeserializer::new(&req)) + .map_err(|e| e.into()) + .map(|inner| Path { inner }) } } @@ -172,16 +170,14 @@ where S: 'static, { type Config = (); - type Result = FutureResult; + type Result = Result; #[inline] - fn from_request(req: &HttpRequest, _: &Self::Config) -> Self::Result { + fn from_request(req: &mut HttpRequest, _: &Self::Config) -> Self::Result { let req = req.clone(); - result( - serde_urlencoded::from_str::(req.query_string()) - .map_err(|e| e.into()) - .map(Query), - ) + serde_urlencoded::from_str::(req.query_string()) + .map_err(|e| e.into()) + .map(Query) } } @@ -245,7 +241,7 @@ where type Result = Box>; #[inline] - fn from_request(req: &HttpRequest, cfg: &Self::Config) -> Self::Result { + fn from_request(req: &mut HttpRequest, cfg: &Self::Config) -> Self::Result { Box::new( UrlEncoded::new(req.clone()) .limit(cfg.limit) @@ -327,17 +323,14 @@ impl Default for FormConfig { /// ``` impl FromRequest for Bytes { type Config = PayloadConfig; - type Result = - Either, Box>>; + type Result = Result>, Error>; #[inline] - fn from_request(req: &HttpRequest, cfg: &Self::Config) -> Self::Result { + fn from_request(req: &mut HttpRequest, cfg: &Self::Config) -> Self::Result { // check content-type - if let Err(e) = cfg.check_mimetype(req) { - return Either::A(result(Err(e))); - } + cfg.check_mimetype(req)?; - Either::B(Box::new( + Ok(Box::new( MessageBody::new(req.clone()) .limit(cfg.limit) .from_err(), @@ -374,27 +367,17 @@ impl FromRequest for Bytes { /// ``` impl FromRequest for String { type Config = PayloadConfig; - type Result = - Either, Box>>; + type Result = Result>, Error>; #[inline] - fn from_request(req: &HttpRequest, cfg: &Self::Config) -> Self::Result { + fn from_request(req: &mut HttpRequest, cfg: &Self::Config) -> Self::Result { // check content-type - if let Err(e) = cfg.check_mimetype(req) { - return Either::A(result(Err(e))); - } + cfg.check_mimetype(req)?; // check charset - let encoding = match req.encoding() { - Err(_) => { - return Either::A(result(Err(ErrorBadRequest( - "Unknown request charset", - )))) - } - Ok(encoding) => encoding, - }; + let encoding = req.encoding()?; - Either::B(Box::new( + Ok(Box::new( MessageBody::new(req.clone()) .limit(cfg.limit) .from_err() @@ -488,7 +471,11 @@ mod tests { req.payload_mut() .unread_data(Bytes::from_static(b"hello=world")); - match Bytes::from_request(&req, &cfg).poll().unwrap() { + match Bytes::from_request(&mut req, &cfg) + .unwrap() + .poll() + .unwrap() + { Async::Ready(s) => { assert_eq!(s, Bytes::from_static(b"hello=world")); } @@ -503,7 +490,11 @@ mod tests { req.payload_mut() .unread_data(Bytes::from_static(b"hello=world")); - match String::from_request(&req, &cfg).poll().unwrap() { + match String::from_request(&mut req, &cfg) + .unwrap() + .poll() + .unwrap() + { Async::Ready(s) => { assert_eq!(s, "hello=world"); } @@ -523,7 +514,10 @@ mod tests { let mut cfg = FormConfig::default(); cfg.limit(4096); - match Form::::from_request(&req, &cfg).poll().unwrap() { + match Form::::from_request(&mut req, &cfg) + .poll() + .unwrap() + { Async::Ready(s) => { assert_eq!(s.hello, "world"); } @@ -580,69 +574,31 @@ mod tests { let (router, _) = Router::new("", ServerSettings::default(), routes); assert!(router.recognize(&mut req).is_some()); - match Path::::from_request(&req, &()) - .poll() - .unwrap() - { - Async::Ready(s) => { - assert_eq!(s.key, "name"); - assert_eq!(s.value, "user1"); - } - _ => unreachable!(), - } + let s = Path::::from_request(&mut req, &()).unwrap(); + assert_eq!(s.key, "name"); + assert_eq!(s.value, "user1"); - match Path::<(String, String)>::from_request(&req, &()) - .poll() - .unwrap() - { - Async::Ready(s) => { - assert_eq!(s.0, "name"); - assert_eq!(s.1, "user1"); - } - _ => unreachable!(), - } + let s = Path::<(String, String)>::from_request(&mut req, &()).unwrap(); + assert_eq!(s.0, "name"); + assert_eq!(s.1, "user1"); - match Query::::from_request(&req, &()).poll().unwrap() { - Async::Ready(s) => { - assert_eq!(s.id, "test"); - } - _ => unreachable!(), - } + let s = Query::::from_request(&mut req, &()).unwrap(); + assert_eq!(s.id, "test"); let mut req = TestRequest::with_uri("/name/32/").finish(); assert!(router.recognize(&mut req).is_some()); - match Path::::from_request(&req, &()).poll().unwrap() { - Async::Ready(s) => { - assert_eq!(s.as_ref().key, "name"); - assert_eq!(s.value, 32); - } - _ => unreachable!(), - } + let s = Path::::from_request(&mut req, &()).unwrap(); + assert_eq!(s.as_ref().key, "name"); + assert_eq!(s.value, 32); - match Path::<(String, u8)>::from_request(&req, &()) - .poll() - .unwrap() - { - Async::Ready(s) => { - assert_eq!(s.0, "name"); - assert_eq!(s.1, 32); - } - _ => unreachable!(), - } + let s = Path::<(String, u8)>::from_request(&mut req, &()).unwrap(); + assert_eq!(s.0, "name"); + assert_eq!(s.1, 32); - match Path::>::from_request(&req, &()) - .poll() - .unwrap() - { - Async::Ready(s) => { - assert_eq!( - s.into_inner(), - vec!["name".to_owned(), "32".to_owned()] - ); - } - _ => unreachable!(), - } + let res = Path::>::from_request(&mut req, &()).unwrap(); + assert_eq!(res[0], "name".to_owned()); + assert_eq!(res[1], "32".to_owned()); } #[test] @@ -656,11 +612,6 @@ mod tests { let mut req = TestRequest::with_uri("/32/").finish(); assert!(router.recognize(&mut req).is_some()); - match Path::::from_request(&req, &()).poll().unwrap() { - Async::Ready(s) => { - assert_eq!(s.into_inner(), 32); - } - _ => unreachable!(), - } + assert_eq!(*Path::::from_request(&mut req, &()).unwrap(), 32); } } diff --git a/src/fs.rs b/src/fs.rs index 2aa1b979e..007e97f6b 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -565,7 +565,7 @@ impl StaticFiles { } impl Handler for StaticFiles { - type Result = Result; + type Result = Result, Error>; fn handle(&mut self, req: HttpRequest) -> Self::Result { if !self.accessible { @@ -755,7 +755,7 @@ mod tests { let resp = st.handle(HttpRequest::default()) .respond_to(HttpRequest::default()) .unwrap(); - let resp = resp.as_response().expect("HTTP Response"); + let resp = resp.as_msg(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); st.accessible = true; @@ -763,7 +763,7 @@ mod tests { let resp = st.handle(HttpRequest::default()) .respond_to(HttpRequest::default()) .unwrap(); - let resp = resp.as_response().expect("HTTP Response"); + let resp = resp.as_msg(); assert_eq!(resp.status(), StatusCode::NOT_FOUND); let mut req = HttpRequest::default(); @@ -773,7 +773,7 @@ mod tests { let resp = st.handle(req) .respond_to(HttpRequest::default()) .unwrap(); - let resp = resp.as_response().expect("HTTP Response"); + let resp = resp.as_msg(); assert_eq!( resp.headers().get(header::CONTENT_TYPE).unwrap(), "text/html; charset=utf-8" @@ -791,7 +791,7 @@ mod tests { let resp = st.handle(req) .respond_to(HttpRequest::default()) .unwrap(); - let resp = resp.as_response().expect("HTTP Response"); + let resp = resp.as_msg(); assert_eq!(resp.status(), StatusCode::FOUND); assert_eq!( resp.headers().get(header::LOCATION).unwrap(), @@ -804,7 +804,7 @@ mod tests { let resp = st.handle(req) .respond_to(HttpRequest::default()) .unwrap(); - let resp = resp.as_response().expect("HTTP Response"); + let resp = resp.as_msg(); assert_eq!(resp.status(), StatusCode::FOUND); assert_eq!( resp.headers().get(header::LOCATION).unwrap(), @@ -821,7 +821,7 @@ mod tests { let resp = st.handle(req) .respond_to(HttpRequest::default()) .unwrap(); - let resp = resp.as_response().expect("HTTP Response"); + let resp = resp.as_msg(); assert_eq!(resp.status(), StatusCode::FOUND); assert_eq!( resp.headers().get(header::LOCATION).unwrap(), diff --git a/src/handler.rs b/src/handler.rs index 2304687d9..dae80e9ff 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -1,4 +1,4 @@ -use futures::future::{err, ok, Future, FutureResult}; +use futures::future::{err, ok, Future}; use futures::Poll; use std::marker::PhantomData; use std::ops::Deref; @@ -22,7 +22,7 @@ pub trait Handler: 'static { /// Types that implement this trait can be used as the return type of a handler. pub trait Responder { /// The associated item which can be returned. - type Item: Into; + type Item: Into>; /// The associated error which can be returned. type Error: Into; @@ -42,10 +42,10 @@ where type Config: Default; /// Future that resolves to a Self - type Result: Future; + type Result: Into>; /// Convert request to a Self - fn from_request(req: &HttpRequest, cfg: &Self::Config) -> Self::Result; + fn from_request(req: &mut HttpRequest, cfg: &Self::Config) -> Self::Result; } /// Combines two different responder types into a single type @@ -88,10 +88,10 @@ where A: Responder, B: Responder, { - type Item = Reply; + type Item = Reply; type Error = Error; - fn respond_to(self, req: HttpRequest) -> Result { + fn respond_to(self, req: HttpRequest) -> Result, Error> { match self { Either::A(a) => match a.respond_to(req) { Ok(val) => Ok(val.into()), @@ -177,66 +177,86 @@ where } } -/// Represents response process. -pub struct Reply(ReplyItem); +/// Represents reply process. +/// +/// Reply could be in tree different forms. +/// * Message(T) - ready item +/// * Error(Error) - error happen during reply process +/// * Future - reply process completes in the future +pub struct Reply(ReplyItem); -pub(crate) enum ReplyItem { - Message(HttpResponse), - Future(Box>), +pub(crate) enum ReplyItem { + Error(Error), + Message(T), + Future(Box>), } -impl Reply { +impl Reply { /// Create async response #[inline] - pub fn async(fut: F) -> Reply + pub fn async(fut: F) -> Reply where - F: Future + 'static, + F: Future + 'static, { Reply(ReplyItem::Future(Box::new(fut))) } /// Send response #[inline] - pub fn response>(response: R) -> Reply { + pub fn response>(response: R) -> Reply { Reply(ReplyItem::Message(response.into())) } + /// Send error #[inline] - pub(crate) fn into(self) -> ReplyItem { + pub fn error>(err: R) -> Reply { + Reply(ReplyItem::Error(err.into())) + } + + #[inline] + pub(crate) fn into(self) -> ReplyItem { self.0 } #[cfg(test)] - pub(crate) fn as_response(&self) -> Option<&HttpResponse> { + pub(crate) fn as_msg(&self) -> &T { match self.0 { - ReplyItem::Message(ref resp) => Some(resp), + ReplyItem::Message(ref resp) => resp, + _ => panic!(), + } + } + + #[cfg(test)] + pub(crate) fn as_err(&self) -> Option<&Error> { + match self.0 { + ReplyItem::Error(ref err) => Some(err), _ => None, } } } -impl Responder for Reply { - type Item = Reply; +impl Responder for Reply { + type Item = Reply; type Error = Error; - fn respond_to(self, _: HttpRequest) -> Result { + fn respond_to(self, _: HttpRequest) -> Result, Error> { Ok(self) } } impl Responder for HttpResponse { - type Item = Reply; + type Item = Reply; type Error = Error; #[inline] - fn respond_to(self, _: HttpRequest) -> Result { + fn respond_to(self, _: HttpRequest) -> Result, Error> { Ok(Reply(ReplyItem::Message(self))) } } -impl From for Reply { +impl From for Reply { #[inline] - fn from(resp: HttpResponse) -> Reply { + fn from(resp: T) -> Reply { Reply(ReplyItem::Message(resp)) } } @@ -256,29 +276,41 @@ impl> Responder for Result { } } -impl> From> for Reply { +impl> From, E>> for Reply { #[inline] - fn from(res: Result) -> Self { + fn from(res: Result, E>) -> Self { match res { Ok(val) => val, - Err(err) => Reply(ReplyItem::Message(err.into().into())), + Err(err) => Reply(ReplyItem::Error(err.into())), } } } -impl> From> for Reply { +impl> From> for Reply { #[inline] - fn from(res: Result) -> Self { + fn from(res: Result) -> Self { match res { Ok(val) => Reply(ReplyItem::Message(val)), - Err(err) => Reply(ReplyItem::Message(err.into().into())), + Err(err) => Reply(ReplyItem::Error(err.into())), } } } -impl From>> for Reply { +impl> From>, E>> + for Reply +{ #[inline] - fn from(fut: Box>) -> Reply { + fn from(res: Result>, E>) -> Self { + match res { + Ok(fut) => Reply(ReplyItem::Future(fut)), + Err(err) => Reply(ReplyItem::Error(err.into())), + } + } +} + +impl From>> for Reply { + #[inline] + fn from(fut: Box>) -> Reply { Reply(ReplyItem::Future(fut)) } } @@ -291,11 +323,11 @@ where I: Responder + 'static, E: Into + 'static, { - type Item = Reply; + type Item = Reply; type Error = Error; #[inline] - fn respond_to(self, req: HttpRequest) -> Result { + fn respond_to(self, req: HttpRequest) -> Result, Error> { let fut = self.map_err(|e| e.into()) .then(move |r| match r.respond_to(req) { Ok(reply) => match reply.into().0 { @@ -310,7 +342,7 @@ where /// Trait defines object that could be registered as resource route pub(crate) trait RouteHandler: 'static { - fn handle(&mut self, req: HttpRequest) -> Reply; + fn handle(&mut self, req: HttpRequest) -> Reply; } /// Route handler wrapper for Handler @@ -344,7 +376,7 @@ where R: Responder + 'static, S: 'static, { - fn handle(&mut self, req: HttpRequest) -> Reply { + fn handle(&mut self, req: HttpRequest) -> Reply { let req2 = req.drop_state(); match self.h.handle(req).respond_to(req2) { Ok(reply) => reply.into(), @@ -390,7 +422,7 @@ where E: Into + 'static, S: 'static, { - fn handle(&mut self, req: HttpRequest) -> Reply { + fn handle(&mut self, req: HttpRequest) -> Reply { let req2 = req.drop_state(); let fut = (self.h)(req).map_err(|e| e.into()).then(move |r| { match r.respond_to(req2) { @@ -449,10 +481,10 @@ impl Deref for State { impl FromRequest for State { type Config = (); - type Result = FutureResult; + type Result = State; #[inline] - fn from_request(req: &HttpRequest, _: &Self::Config) -> Self::Result { - ok(State(req.clone())) + fn from_request(req: &mut HttpRequest, _: &Self::Config) -> Self::Result { + State(req.clone()).into() } } diff --git a/src/helpers.rs b/src/helpers.rs index fda28f388..9db0e8638 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -217,7 +217,7 @@ mod tests { for (path, target, code) in params { let req = app.prepare_request(TestRequest::with_uri(path).finish()); let resp = app.run(req); - let r = resp.as_response().unwrap(); + let r = resp.as_msg(); assert_eq!(r.status(), code); if !target.is_empty() { assert_eq!( @@ -260,7 +260,7 @@ mod tests { for (path, code) in params { let req = app.prepare_request(TestRequest::with_uri(path).finish()); let resp = app.run(req); - let r = resp.as_response().unwrap(); + let r = resp.as_msg(); assert_eq!(r.status(), code); } } @@ -351,7 +351,7 @@ mod tests { for (path, target, code) in params { let req = app.prepare_request(TestRequest::with_uri(path).finish()); let resp = app.run(req); - let r = resp.as_response().unwrap(); + let r = resp.as_msg(); assert_eq!(r.status(), code); if !target.is_empty() { assert_eq!( @@ -535,7 +535,7 @@ mod tests { for (path, target, code) in params { let req = app.prepare_request(TestRequest::with_uri(path).finish()); let resp = app.run(req); - let r = resp.as_response().unwrap(); + let r = resp.as_msg(); assert_eq!(r.status(), code); if !target.is_empty() { assert_eq!( diff --git a/src/httprequest.rs b/src/httprequest.rs index 3b65d7185..2225b4bb8 100644 --- a/src/httprequest.rs +++ b/src/httprequest.rs @@ -1,20 +1,20 @@ //! HTTP Request message related code. #![cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ptr))] -use bytes::Bytes; -use cookie::Cookie; -use failure; -use futures::future::{result, FutureResult}; -use futures::{Async, Poll, Stream}; -use futures_cpupool::CpuPool; -use http::{header, Extensions, HeaderMap, Method, StatusCode, Uri, Version}; use std::net::SocketAddr; use std::rc::Rc; use std::{cmp, fmt, io, mem, str}; + +use bytes::Bytes; +use cookie::Cookie; +use failure; +use futures::{Async, Poll, Stream}; +use futures_cpupool::CpuPool; +use http::{header, Extensions, HeaderMap, Method, StatusCode, Uri, Version}; use tokio_io::AsyncRead; use url::{form_urlencoded, Url}; use body::Body; -use error::{CookieParseError, Error, PayloadError, UrlGenerationError}; +use error::{CookieParseError, PayloadError, UrlGenerationError}; use handler::FromRequest; use httpmessage::HttpMessage; use httpresponse::{HttpResponse, HttpResponseBuilder}; @@ -502,11 +502,11 @@ impl Clone for HttpRequest { impl FromRequest for HttpRequest { type Config = (); - type Result = FutureResult; + type Result = Self; #[inline] - fn from_request(req: &HttpRequest, _: &Self::Config) -> Self::Result { - result(Ok(req.clone())) + fn from_request(req: &mut HttpRequest, _: &Self::Config) -> Self::Result { + req.clone() } } diff --git a/src/json.rs b/src/json.rs index ec3ad7ce0..24d1c9c4b 100644 --- a/src/json.rs +++ b/src/json.rs @@ -136,7 +136,7 @@ where type Result = Box>; #[inline] - fn from_request(req: &HttpRequest, cfg: &Self::Config) -> Self::Result { + fn from_request(req: &mut HttpRequest, cfg: &Self::Config) -> Self::Result { let req = req.clone(); let err = Rc::clone(&cfg.ehandler); Box::new( @@ -417,13 +417,7 @@ mod tests { let mut handler = With::new(|data: Json| data, cfg); let req = HttpRequest::default(); - let err = handler - .handle(req) - .as_response() - .unwrap() - .error() - .is_some(); - assert!(err); + assert!(handler.handle(req).as_err().is_some()); let mut req = HttpRequest::default(); req.headers_mut().insert( @@ -436,12 +430,6 @@ mod tests { ); req.payload_mut() .unread_data(Bytes::from_static(b"{\"name\": \"test\"}")); - let ok = handler - .handle(req) - .as_response() - .unwrap() - .error() - .is_none(); - assert!(ok) + assert!(handler.handle(req).as_err().is_none()) } } diff --git a/src/pipeline.rs b/src/pipeline.rs index aefd979d3..cea02073f 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -28,7 +28,8 @@ pub(crate) enum HandlerType { pub(crate) trait PipelineHandler { fn encoding(&self) -> ContentEncoding; - fn handle(&mut self, req: HttpRequest, htype: HandlerType) -> Reply; + fn handle(&mut self, req: HttpRequest, htype: HandlerType) + -> Reply; } pub(crate) struct Pipeline(PipelineInfo, PipelineState); @@ -319,8 +320,11 @@ struct WaitingResponse { impl WaitingResponse { #[inline] - fn init(info: &mut PipelineInfo, reply: Reply) -> PipelineState { + fn init( + info: &mut PipelineInfo, reply: Reply, + ) -> PipelineState { match reply.into() { + ReplyItem::Error(err) => RunMiddlewares::init(info, err.into()), ReplyItem::Message(resp) => RunMiddlewares::init(info, resp), ReplyItem::Future(fut) => PipelineState::Handler(WaitingResponse { fut, diff --git a/src/resource.rs b/src/resource.rs index e4dfbb2df..e78a45460 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -198,7 +198,7 @@ impl ResourceHandler { pub(crate) fn handle( &mut self, mut req: HttpRequest, default: Option<&mut ResourceHandler>, - ) -> Reply { + ) -> Reply { for route in &mut self.routes { if route.check(&mut req) { return if self.middlewares.is_empty() { diff --git a/src/route.rs b/src/route.rs index 6c4ba4197..7d39cc107 100644 --- a/src/route.rs +++ b/src/route.rs @@ -45,14 +45,14 @@ impl Route { } #[inline] - pub(crate) fn handle(&mut self, req: HttpRequest) -> Reply { + pub(crate) fn handle(&mut self, req: HttpRequest) -> Reply { self.handler.handle(req) } #[inline] pub(crate) fn compose( &mut self, req: HttpRequest, mws: Rc>>>, - ) -> Reply { + ) -> Reply { Reply::async(Compose::new(req, mws, self.handler.clone())) } @@ -243,7 +243,7 @@ impl InnerHandler { } #[inline] - pub fn handle(&self, req: HttpRequest) -> Reply { + pub fn handle(&self, req: HttpRequest) -> Reply { // reason: handler is unique per thread, handler get called from async code only let h = unsafe { &mut *self.0.as_ref().get() }; h.handle(req) @@ -415,8 +415,9 @@ struct WaitingResponse { impl WaitingResponse { #[inline] - fn init(info: &mut ComposeInfo, reply: Reply) -> ComposeState { + fn init(info: &mut ComposeInfo, reply: Reply) -> ComposeState { match reply.into() { + ReplyItem::Error(err) => RunMiddlewares::init(info, err.into()), ReplyItem::Message(resp) => RunMiddlewares::init(info, resp), ReplyItem::Future(fut) => ComposeState::Handler(WaitingResponse { fut, diff --git a/src/scope.rs b/src/scope.rs index ff630e680..38e6c0624 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -274,7 +274,7 @@ impl Scope { } impl RouteHandler for Scope { - fn handle(&mut self, mut req: HttpRequest) -> Reply { + fn handle(&mut self, mut req: HttpRequest) -> Reply { let path = unsafe { &*(&req.match_info()["tail"] as *const _) }; let path = if path == "" { "/" } else { path }; @@ -346,7 +346,7 @@ struct Wrapper { } impl RouteHandler for Wrapper { - fn handle(&mut self, req: HttpRequest) -> Reply { + fn handle(&mut self, req: HttpRequest) -> Reply { self.scope .handle(req.change_state(Rc::clone(&self.state))) } @@ -521,9 +521,10 @@ struct WaitingResponse { impl WaitingResponse { #[inline] - fn init(info: &mut ComposeInfo, reply: Reply) -> ComposeState { + fn init(info: &mut ComposeInfo, reply: Reply) -> ComposeState { match reply.into() { ReplyItem::Message(resp) => RunMiddlewares::init(info, resp), + ReplyItem::Error(err) => RunMiddlewares::init(info, err.into()), ReplyItem::Future(fut) => ComposeState::Handler(WaitingResponse { fut, _s: PhantomData, @@ -707,7 +708,7 @@ mod tests { let req = TestRequest::with_uri("/app/path1").finish(); let resp = app.run(req); - assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); + assert_eq!(resp.as_msg().status(), StatusCode::OK); } #[test] @@ -724,10 +725,7 @@ mod tests { let req = TestRequest::with_uri("/app/t1/path1").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::CREATED - ); + assert_eq!(resp.as_msg().status(), StatusCode::CREATED); } #[test] @@ -742,10 +740,7 @@ mod tests { let req = TestRequest::with_uri("/app/t1/path1").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::CREATED - ); + assert_eq!(resp.as_msg().status(), StatusCode::CREATED); } #[test] @@ -760,16 +755,10 @@ mod tests { let req = TestRequest::with_uri("/app/path2").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::BAD_REQUEST - ); + assert_eq!(resp.as_msg().status(), StatusCode::BAD_REQUEST); let req = TestRequest::with_uri("/path2").finish(); let resp = app.run(req); - assert_eq!( - resp.as_response().unwrap().status(), - StatusCode::NOT_FOUND - ); + assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND); } } diff --git a/src/test.rs b/src/test.rs index 13209f1d5..0de7f6340 100644 --- a/src/test.rs +++ b/src/test.rs @@ -602,6 +602,7 @@ impl TestRequest { match resp.respond_to(req.drop_state()) { Ok(resp) => match resp.into().into() { ReplyItem::Message(resp) => Ok(resp), + ReplyItem::Error(err) => Ok(err.into()), ReplyItem::Future(_) => panic!("Async handler is not supported."), }, Err(err) => Err(err), diff --git a/src/with.rs b/src/with.rs index a35d1a3b0..a3b07ac0b 100644 --- a/src/with.rs +++ b/src/with.rs @@ -82,7 +82,7 @@ where T: FromRequest + 'static, S: 'static, { - type Result = Reply; + type Result = Reply; fn handle(&mut self, req: HttpRequest) -> Self::Result { let mut fut = WithHandlerFut { @@ -97,7 +97,7 @@ where match fut.poll() { Ok(Async::Ready(resp)) => Reply::response(resp), Ok(Async::NotReady) => Reply::async(fut), - Err(e) => Reply::response(e), + Err(e) => Reply::error::(e), } } } @@ -134,14 +134,14 @@ where let item = if !self.started { self.started = true; - let mut fut = T::from_request(&self.req, self.cfg.as_ref()); - match fut.poll() { - Ok(Async::Ready(item)) => item, - Ok(Async::NotReady) => { - self.fut1 = Some(Box::new(fut)); - return Ok(Async::NotReady); + let reply = T::from_request(&mut self.req, self.cfg.as_ref()).into(); + match reply.into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(msg) => msg, + ReplyItem::Future(fut) => { + self.fut1 = Some(fut); + return self.poll(); } - Err(e) => return Err(e), } } else { match self.fut1.as_mut().unwrap().poll()? { @@ -157,6 +157,7 @@ where }; match item.into() { + ReplyItem::Error(err) => Err(err), ReplyItem::Message(resp) => Ok(Async::Ready(resp)), ReplyItem::Future(fut) => { self.fut2 = Some(fut); @@ -206,7 +207,7 @@ where T2: FromRequest + 'static, S: 'static, { - type Result = Reply; + type Result = Reply; fn handle(&mut self, req: HttpRequest) -> Self::Result { let mut fut = WithHandlerFut2 { @@ -265,52 +266,68 @@ where if !self.started { self.started = true; - let mut fut = T1::from_request(&self.req, self.cfg1.as_ref()); - match fut.poll() { - Ok(Async::Ready(item1)) => { - let mut fut = T2::from_request(&self.req, self.cfg2.as_ref()); - match fut.poll() { - Ok(Async::Ready(item2)) => { - let hnd: &mut F = unsafe { &mut *self.hnd.get() }; - match (*hnd)(item1, item2).respond_to(self.req.drop_state()) - { - Ok(item) => match item.into().into() { - ReplyItem::Message(resp) => { - return Ok(Async::Ready(resp)) - } - ReplyItem::Future(fut) => { - self.fut3 = Some(fut); - return self.poll(); - } - }, - Err(e) => return Err(e.into()), - } - } - Ok(Async::NotReady) => { - self.item = Some(item1); - self.fut2 = Some(Box::new(fut)); - return Ok(Async::NotReady); - } - Err(e) => return Err(e), + let reply = T1::from_request(&mut self.req, self.cfg1.as_ref()).into(); + let item1 = match reply.into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(msg) => msg, + ReplyItem::Future(fut) => { + self.fut1 = Some(fut); + return self.poll(); + } + }; + + let reply = T2::from_request(&mut self.req, self.cfg2.as_ref()).into(); + let item2 = match reply.into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(msg) => msg, + ReplyItem::Future(fut) => { + self.item = Some(item1); + self.fut2 = Some(fut); + return self.poll(); + } + }; + + let hnd: &mut F = unsafe { &mut *self.hnd.get() }; + match (*hnd)(item1, item2).respond_to(self.req.drop_state()) { + Ok(item) => match item.into().into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), + ReplyItem::Future(fut) => { + self.fut3 = Some(fut); + return self.poll(); } - } - Ok(Async::NotReady) => { - self.fut1 = Some(Box::new(fut)); - return Ok(Async::NotReady); - } - Err(e) => return Err(e), + }, + Err(e) => return Err(e.into()), } } if self.fut1.is_some() { match self.fut1.as_mut().unwrap().poll()? { Async::Ready(item) => { - self.item = Some(item); - self.fut1.take(); - self.fut2 = Some(Box::new(T2::from_request( - &self.req, - self.cfg2.as_ref(), - ))); + let reply = + T2::from_request(&mut self.req, self.cfg2.as_ref()).into(); + let item2 = match reply.into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(msg) => msg, + ReplyItem::Future(fut) => { + self.item = Some(item); + self.fut2 = Some(fut); + return self.poll(); + } + }; + + let hnd: &mut F = unsafe { &mut *self.hnd.get() }; + match (*hnd)(item, item2).respond_to(self.req.drop_state()) { + Ok(item) => match item.into().into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), + ReplyItem::Future(fut) => { + self.fut3 = Some(fut); + return self.poll(); + } + }, + Err(e) => return Err(e.into()), + } } Async::NotReady => return Ok(Async::NotReady), } @@ -330,6 +347,7 @@ where }; match item.into() { + ReplyItem::Error(err) => return Err(err), ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyItem::Future(fut) => self.fut3 = Some(fut), } @@ -387,7 +405,7 @@ where T3: 'static, S: 'static, { - type Result = Reply; + type Result = Reply; fn handle(&mut self, req: HttpRequest) -> Self::Result { let mut fut = WithHandlerFut3 { @@ -454,54 +472,50 @@ where if !self.started { self.started = true; - let mut fut = T1::from_request(&self.req, self.cfg1.as_ref()); - match fut.poll() { - Ok(Async::Ready(item1)) => { - let mut fut = T2::from_request(&self.req, self.cfg2.as_ref()); - match fut.poll() { - Ok(Async::Ready(item2)) => { - let mut fut = - T3::from_request(&self.req, self.cfg3.as_ref()); - match fut.poll() { - Ok(Async::Ready(item3)) => { - let hnd: &mut F = unsafe { &mut *self.hnd.get() }; - match (*hnd)(item1, item2, item3) - .respond_to(self.req.drop_state()) - { - Ok(item) => match item.into().into() { - ReplyItem::Message(resp) => { - return Ok(Async::Ready(resp)) - } - ReplyItem::Future(fut) => { - self.fut4 = Some(fut); - return self.poll(); - } - }, - Err(e) => return Err(e.into()), - } - } - Ok(Async::NotReady) => { - self.item1 = Some(item1); - self.item2 = Some(item2); - self.fut3 = Some(Box::new(fut)); - return Ok(Async::NotReady); - } - Err(e) => return Err(e), - } - } - Ok(Async::NotReady) => { - self.item1 = Some(item1); - self.fut2 = Some(Box::new(fut)); - return Ok(Async::NotReady); - } - Err(e) => return Err(e), + let reply = T1::from_request(&mut self.req, self.cfg1.as_ref()).into(); + let item1 = match reply.into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(msg) => msg, + ReplyItem::Future(fut) => { + self.fut1 = Some(fut); + return self.poll(); + } + }; + + let reply = T2::from_request(&mut self.req, self.cfg2.as_ref()).into(); + let item2 = match reply.into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(msg) => msg, + ReplyItem::Future(fut) => { + self.item1 = Some(item1); + self.fut2 = Some(fut); + return self.poll(); + } + }; + + let reply = T3::from_request(&mut self.req, self.cfg3.as_ref()).into(); + let item3 = match reply.into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(msg) => msg, + ReplyItem::Future(fut) => { + self.item1 = Some(item1); + self.item2 = Some(item2); + self.fut3 = Some(fut); + return self.poll(); + } + }; + + let hnd: &mut F = unsafe { &mut *self.hnd.get() }; + match (*hnd)(item1, item2, item3).respond_to(self.req.drop_state()) { + Ok(item) => match item.into().into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), + ReplyItem::Future(fut) => { + self.fut4 = Some(fut); + return self.poll(); } - } - Ok(Async::NotReady) => { - self.fut1 = Some(Box::new(fut)); - return Ok(Async::NotReady); - } - Err(e) => return Err(e), + }, + Err(e) => return Err(e.into()), } } @@ -510,10 +524,42 @@ where Async::Ready(item) => { self.item1 = Some(item); self.fut1.take(); - self.fut2 = Some(Box::new(T2::from_request( - &self.req, - self.cfg2.as_ref(), - ))); + let reply = + T2::from_request(&mut self.req, self.cfg2.as_ref()).into(); + let item2 = match reply.into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(msg) => msg, + ReplyItem::Future(fut) => { + self.fut2 = Some(fut); + return self.poll(); + } + }; + + let reply = + T3::from_request(&mut self.req, self.cfg3.as_ref()).into(); + let item3 = match reply.into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(msg) => msg, + ReplyItem::Future(fut) => { + self.item2 = Some(item2); + self.fut3 = Some(fut); + return self.poll(); + } + }; + let hnd: &mut F = unsafe { &mut *self.hnd.get() }; + match (*hnd)(self.item1.take().unwrap(), item2, item3) + .respond_to(self.req.drop_state()) + { + Ok(item) => match item.into().into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), + ReplyItem::Future(fut) => { + self.fut4 = Some(fut); + return self.poll(); + } + }, + Err(e) => return Err(e.into()), + } } Async::NotReady => return Ok(Async::NotReady), } @@ -522,12 +568,32 @@ where if self.fut2.is_some() { match self.fut2.as_mut().unwrap().poll()? { Async::Ready(item) => { - self.item2 = Some(item); self.fut2.take(); - self.fut3 = Some(Box::new(T3::from_request( - &self.req, - self.cfg3.as_ref(), - ))); + let reply = + T3::from_request(&mut self.req, self.cfg3.as_ref()).into(); + let item3 = match reply.into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(msg) => msg, + ReplyItem::Future(fut) => { + self.item2 = Some(item); + self.fut3 = Some(fut); + return self.poll(); + } + }; + let hnd: &mut F = unsafe { &mut *self.hnd.get() }; + match (*hnd)(self.item1.take().unwrap(), item, item3) + .respond_to(self.req.drop_state()) + { + Ok(item) => match item.into().into() { + ReplyItem::Error(err) => return Err(err), + ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), + ReplyItem::Future(fut) => { + self.fut4 = Some(fut); + return self.poll(); + } + }, + Err(e) => return Err(e.into()), + } } Async::NotReady => return Ok(Async::NotReady), } @@ -550,6 +616,7 @@ where }; match item.into() { + ReplyItem::Error(err) => return Ok(Async::Ready(err.into())), ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyItem::Future(fut) => self.fut4 = Some(fut), }