1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-30 18:34:36 +01:00

refactor FromRequest trait

This commit is contained in:
Nikolay Kim 2018-05-01 17:19:15 -07:00
parent 195246573e
commit 8d65468c58
14 changed files with 384 additions and 383 deletions

View File

@ -11,6 +11,10 @@
* `HttpRequest::extensions()` returns read only reference to the request's Extension * `HttpRequest::extensions()` returns read only reference to the request's Extension
`HttpRequest::extensions_mut()` returns mutable reference. `HttpRequest::extensions_mut()` returns mutable reference.
* `FromRequest::from_request()` accepts mutable reference to a request
* `FromRequest::Result` has to implement `Into<Reply<Self>>`
## Migration from 0.4 to 0.5 ## Migration from 0.4 to 0.5

View File

@ -6,6 +6,7 @@ use handler::{FromRequest, Handler, Reply, Responder, RouteHandler, WrapHandler}
use header::ContentEncoding; use header::ContentEncoding;
use http::Method; use http::Method;
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use middleware::Middleware; use middleware::Middleware;
use pipeline::{HandlerType, Pipeline, PipelineHandler}; use pipeline::{HandlerType, Pipeline, PipelineHandler};
use resource::ResourceHandler; use resource::ResourceHandler;
@ -36,7 +37,9 @@ impl<S: 'static> PipelineHandler<S> for Inner<S> {
self.encoding self.encoding
} }
fn handle(&mut self, req: HttpRequest<S>, htype: HandlerType) -> Reply { fn handle(
&mut self, req: HttpRequest<S>, htype: HandlerType,
) -> Reply<HttpResponse> {
match htype { match htype {
HandlerType::Normal(idx) => { HandlerType::Normal(idx) => {
self.resources[idx].handle(req, Some(&mut self.default)) self.resources[idx].handle(req, Some(&mut self.default))
@ -87,7 +90,7 @@ impl<S: 'static> HttpApplication<S> {
} }
#[cfg(test)] #[cfg(test)]
pub(crate) fn run(&mut self, mut req: HttpRequest<S>) -> Reply { pub(crate) fn run(&mut self, mut req: HttpRequest<S>) -> Reply<HttpResponse> {
let tp = self.get_handler(&mut req); let tp = self.get_handler(&mut req);
unsafe { &mut *self.inner.get() }.handle(req, tp) unsafe { &mut *self.inner.get() }.handle(req, tp)
} }
@ -669,24 +672,18 @@ mod tests {
let req = TestRequest::with_uri("/test").finish(); let req = TestRequest::with_uri("/test").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/blah").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
let mut app = App::new() let mut app = App::new()
.default_resource(|r| r.f(|_| HttpResponse::MethodNotAllowed())) .default_resource(|r| r.f(|_| HttpResponse::MethodNotAllowed()))
.finish(); .finish();
let req = TestRequest::with_uri("/blah").finish(); let req = TestRequest::with_uri("/blah").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::METHOD_NOT_ALLOWED);
resp.as_response().unwrap().status(),
StatusCode::METHOD_NOT_ALLOWED
);
} }
#[test] #[test]
@ -706,7 +703,7 @@ mod tests {
let req = let req =
HttpRequest::default().with_state(Rc::clone(&app.state), app.router.clone()); HttpRequest::default().with_state(Rc::clone(&app.state), app.router.clone());
let resp = app.run(req); let resp = app.run(req);
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); assert_eq!(resp.as_msg().status(), StatusCode::OK);
} }
#[test] #[test]
@ -740,29 +737,23 @@ mod tests {
let req = TestRequest::with_uri("/test").finish(); let req = TestRequest::with_uri("/test").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/test/").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/test/app").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/testapp").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
let req = TestRequest::with_uri("/blah").finish(); let req = TestRequest::with_uri("/blah").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
} }
#[test] #[test]
@ -773,29 +764,23 @@ mod tests {
let req = TestRequest::with_uri("/test").finish(); let req = TestRequest::with_uri("/test").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/test/").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/test/app").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/testapp").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
let req = TestRequest::with_uri("/blah").finish(); let req = TestRequest::with_uri("/blah").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
} }
#[test] #[test]
@ -807,29 +792,23 @@ mod tests {
let req = TestRequest::with_uri("/prefix/test").finish(); let req = TestRequest::with_uri("/prefix/test").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/prefix/test/").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/prefix/test/app").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/prefix/testapp").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
let req = TestRequest::with_uri("/prefix/blah").finish(); let req = TestRequest::with_uri("/prefix/blah").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
} }
#[test] #[test]
@ -847,25 +826,19 @@ mod tests {
.method(Method::GET) .method(Method::GET)
.finish(); .finish();
let resp = app.run(req); 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") let req = TestRequest::with_uri("/test")
.method(Method::POST) .method(Method::POST)
.finish(); .finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::CREATED);
resp.as_response().unwrap().status(),
StatusCode::CREATED
);
let req = TestRequest::with_uri("/test") let req = TestRequest::with_uri("/test")
.method(Method::HEAD) .method(Method::HEAD)
.finish(); .finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
} }
#[test] #[test]
@ -877,36 +850,27 @@ mod tests {
let req = TestRequest::with_uri("/test").finish(); let req = TestRequest::with_uri("/test").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
let req = TestRequest::with_uri("/app/test").finish(); let req = TestRequest::with_uri("/app/test").finish();
let resp = app.run(req.clone()); 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); assert_eq!(req.prefix_len(), 9);
let req = TestRequest::with_uri("/app/test/").finish(); let req = TestRequest::with_uri("/app/test/").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/app/test/app").finish();
let resp = app.run(req); 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 req = TestRequest::with_uri("/app/testapp").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
let req = TestRequest::with_uri("/app/blah").finish(); let req = TestRequest::with_uri("/app/blah").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
} }
} }

View File

@ -4,14 +4,14 @@ use std::str;
use bytes::Bytes; use bytes::Bytes;
use encoding::all::UTF_8; use encoding::all::UTF_8;
use encoding::types::{DecoderTrap, Encoding}; use encoding::types::{DecoderTrap, Encoding};
use futures::future::{result, Future, FutureResult}; use futures::future::Future;
use mime::Mime; use mime::Mime;
use serde::de::{self, DeserializeOwned}; use serde::de::{self, DeserializeOwned};
use serde_urlencoded; use serde_urlencoded;
use de::PathDeserializer; use de::PathDeserializer;
use error::{Error, ErrorBadRequest}; use error::{Error, ErrorBadRequest};
use handler::{Either, FromRequest}; use handler::FromRequest;
use httpmessage::{HttpMessage, MessageBody, UrlEncoded}; use httpmessage::{HttpMessage, MessageBody, UrlEncoded};
use httprequest::HttpRequest; use httprequest::HttpRequest;
@ -102,16 +102,14 @@ where
S: 'static, S: 'static,
{ {
type Config = (); type Config = ();
type Result = FutureResult<Self, Error>; type Result = Result<Self, Error>;
#[inline] #[inline]
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result { fn from_request(req: &mut HttpRequest<S>, _: &Self::Config) -> Self::Result {
let req = req.clone(); let req = req.clone();
result(
de::Deserialize::deserialize(PathDeserializer::new(&req)) de::Deserialize::deserialize(PathDeserializer::new(&req))
.map_err(|e| e.into()) .map_err(|e| e.into())
.map(|inner| Path { inner }), .map(|inner| Path { inner })
)
} }
} }
@ -172,16 +170,14 @@ where
S: 'static, S: 'static,
{ {
type Config = (); type Config = ();
type Result = FutureResult<Self, Error>; type Result = Result<Self, Error>;
#[inline] #[inline]
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result { fn from_request(req: &mut HttpRequest<S>, _: &Self::Config) -> Self::Result {
let req = req.clone(); let req = req.clone();
result(
serde_urlencoded::from_str::<T>(req.query_string()) serde_urlencoded::from_str::<T>(req.query_string())
.map_err(|e| e.into()) .map_err(|e| e.into())
.map(Query), .map(Query)
)
} }
} }
@ -245,7 +241,7 @@ where
type Result = Box<Future<Item = Self, Error = Error>>; type Result = Box<Future<Item = Self, Error = Error>>;
#[inline] #[inline]
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result { fn from_request(req: &mut HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
Box::new( Box::new(
UrlEncoded::new(req.clone()) UrlEncoded::new(req.clone())
.limit(cfg.limit) .limit(cfg.limit)
@ -327,17 +323,14 @@ impl Default for FormConfig {
/// ``` /// ```
impl<S: 'static> FromRequest<S> for Bytes { impl<S: 'static> FromRequest<S> for Bytes {
type Config = PayloadConfig; type Config = PayloadConfig;
type Result = type Result = Result<Box<Future<Item = Self, Error = Error>>, Error>;
Either<FutureResult<Self, Error>, Box<Future<Item = Self, Error = Error>>>;
#[inline] #[inline]
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result { fn from_request(req: &mut HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
// check content-type // check content-type
if let Err(e) = cfg.check_mimetype(req) { cfg.check_mimetype(req)?;
return Either::A(result(Err(e)));
}
Either::B(Box::new( Ok(Box::new(
MessageBody::new(req.clone()) MessageBody::new(req.clone())
.limit(cfg.limit) .limit(cfg.limit)
.from_err(), .from_err(),
@ -374,27 +367,17 @@ impl<S: 'static> FromRequest<S> for Bytes {
/// ``` /// ```
impl<S: 'static> FromRequest<S> for String { impl<S: 'static> FromRequest<S> for String {
type Config = PayloadConfig; type Config = PayloadConfig;
type Result = type Result = Result<Box<Future<Item = String, Error = Error>>, Error>;
Either<FutureResult<String, Error>, Box<Future<Item = String, Error = Error>>>;
#[inline] #[inline]
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result { fn from_request(req: &mut HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
// check content-type // check content-type
if let Err(e) = cfg.check_mimetype(req) { cfg.check_mimetype(req)?;
return Either::A(result(Err(e)));
}
// check charset // check charset
let encoding = match req.encoding() { let encoding = req.encoding()?;
Err(_) => {
return Either::A(result(Err(ErrorBadRequest(
"Unknown request charset",
))))
}
Ok(encoding) => encoding,
};
Either::B(Box::new( Ok(Box::new(
MessageBody::new(req.clone()) MessageBody::new(req.clone())
.limit(cfg.limit) .limit(cfg.limit)
.from_err() .from_err()
@ -488,7 +471,11 @@ mod tests {
req.payload_mut() req.payload_mut()
.unread_data(Bytes::from_static(b"hello=world")); .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) => { Async::Ready(s) => {
assert_eq!(s, Bytes::from_static(b"hello=world")); assert_eq!(s, Bytes::from_static(b"hello=world"));
} }
@ -503,7 +490,11 @@ mod tests {
req.payload_mut() req.payload_mut()
.unread_data(Bytes::from_static(b"hello=world")); .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) => { Async::Ready(s) => {
assert_eq!(s, "hello=world"); assert_eq!(s, "hello=world");
} }
@ -523,7 +514,10 @@ mod tests {
let mut cfg = FormConfig::default(); let mut cfg = FormConfig::default();
cfg.limit(4096); cfg.limit(4096);
match Form::<Info>::from_request(&req, &cfg).poll().unwrap() { match Form::<Info>::from_request(&mut req, &cfg)
.poll()
.unwrap()
{
Async::Ready(s) => { Async::Ready(s) => {
assert_eq!(s.hello, "world"); assert_eq!(s.hello, "world");
} }
@ -580,69 +574,31 @@ mod tests {
let (router, _) = Router::new("", ServerSettings::default(), routes); let (router, _) = Router::new("", ServerSettings::default(), routes);
assert!(router.recognize(&mut req).is_some()); assert!(router.recognize(&mut req).is_some());
match Path::<MyStruct>::from_request(&req, &()) let s = Path::<MyStruct>::from_request(&mut req, &()).unwrap();
.poll()
.unwrap()
{
Async::Ready(s) => {
assert_eq!(s.key, "name"); assert_eq!(s.key, "name");
assert_eq!(s.value, "user1"); assert_eq!(s.value, "user1");
}
_ => unreachable!(),
}
match Path::<(String, String)>::from_request(&req, &()) let s = Path::<(String, String)>::from_request(&mut req, &()).unwrap();
.poll()
.unwrap()
{
Async::Ready(s) => {
assert_eq!(s.0, "name"); assert_eq!(s.0, "name");
assert_eq!(s.1, "user1"); assert_eq!(s.1, "user1");
}
_ => unreachable!(),
}
match Query::<Id>::from_request(&req, &()).poll().unwrap() { let s = Query::<Id>::from_request(&mut req, &()).unwrap();
Async::Ready(s) => {
assert_eq!(s.id, "test"); assert_eq!(s.id, "test");
}
_ => unreachable!(),
}
let mut req = TestRequest::with_uri("/name/32/").finish(); let mut req = TestRequest::with_uri("/name/32/").finish();
assert!(router.recognize(&mut req).is_some()); assert!(router.recognize(&mut req).is_some());
match Path::<Test2>::from_request(&req, &()).poll().unwrap() { let s = Path::<Test2>::from_request(&mut req, &()).unwrap();
Async::Ready(s) => {
assert_eq!(s.as_ref().key, "name"); assert_eq!(s.as_ref().key, "name");
assert_eq!(s.value, 32); assert_eq!(s.value, 32);
}
_ => unreachable!(),
}
match Path::<(String, u8)>::from_request(&req, &()) let s = Path::<(String, u8)>::from_request(&mut req, &()).unwrap();
.poll()
.unwrap()
{
Async::Ready(s) => {
assert_eq!(s.0, "name"); assert_eq!(s.0, "name");
assert_eq!(s.1, 32); assert_eq!(s.1, 32);
}
_ => unreachable!(),
}
match Path::<Vec<String>>::from_request(&req, &()) let res = Path::<Vec<String>>::from_request(&mut req, &()).unwrap();
.poll() assert_eq!(res[0], "name".to_owned());
.unwrap() assert_eq!(res[1], "32".to_owned());
{
Async::Ready(s) => {
assert_eq!(
s.into_inner(),
vec!["name".to_owned(), "32".to_owned()]
);
}
_ => unreachable!(),
}
} }
#[test] #[test]
@ -656,11 +612,6 @@ mod tests {
let mut req = TestRequest::with_uri("/32/").finish(); let mut req = TestRequest::with_uri("/32/").finish();
assert!(router.recognize(&mut req).is_some()); assert!(router.recognize(&mut req).is_some());
match Path::<i8>::from_request(&req, &()).poll().unwrap() { assert_eq!(*Path::<i8>::from_request(&mut req, &()).unwrap(), 32);
Async::Ready(s) => {
assert_eq!(s.into_inner(), 32);
}
_ => unreachable!(),
}
} }
} }

View File

@ -565,7 +565,7 @@ impl<S: 'static> StaticFiles<S> {
} }
impl<S: 'static> Handler<S> for StaticFiles<S> { impl<S: 'static> Handler<S> for StaticFiles<S> {
type Result = Result<Reply, Error>; type Result = Result<Reply<HttpResponse>, Error>;
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result { fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
if !self.accessible { if !self.accessible {
@ -755,7 +755,7 @@ mod tests {
let resp = st.handle(HttpRequest::default()) let resp = st.handle(HttpRequest::default())
.respond_to(HttpRequest::default()) .respond_to(HttpRequest::default())
.unwrap(); .unwrap();
let resp = resp.as_response().expect("HTTP Response"); let resp = resp.as_msg();
assert_eq!(resp.status(), StatusCode::NOT_FOUND); assert_eq!(resp.status(), StatusCode::NOT_FOUND);
st.accessible = true; st.accessible = true;
@ -763,7 +763,7 @@ mod tests {
let resp = st.handle(HttpRequest::default()) let resp = st.handle(HttpRequest::default())
.respond_to(HttpRequest::default()) .respond_to(HttpRequest::default())
.unwrap(); .unwrap();
let resp = resp.as_response().expect("HTTP Response"); let resp = resp.as_msg();
assert_eq!(resp.status(), StatusCode::NOT_FOUND); assert_eq!(resp.status(), StatusCode::NOT_FOUND);
let mut req = HttpRequest::default(); let mut req = HttpRequest::default();
@ -773,7 +773,7 @@ mod tests {
let resp = st.handle(req) let resp = st.handle(req)
.respond_to(HttpRequest::default()) .respond_to(HttpRequest::default())
.unwrap(); .unwrap();
let resp = resp.as_response().expect("HTTP Response"); let resp = resp.as_msg();
assert_eq!( assert_eq!(
resp.headers().get(header::CONTENT_TYPE).unwrap(), resp.headers().get(header::CONTENT_TYPE).unwrap(),
"text/html; charset=utf-8" "text/html; charset=utf-8"
@ -791,7 +791,7 @@ mod tests {
let resp = st.handle(req) let resp = st.handle(req)
.respond_to(HttpRequest::default()) .respond_to(HttpRequest::default())
.unwrap(); .unwrap();
let resp = resp.as_response().expect("HTTP Response"); let resp = resp.as_msg();
assert_eq!(resp.status(), StatusCode::FOUND); assert_eq!(resp.status(), StatusCode::FOUND);
assert_eq!( assert_eq!(
resp.headers().get(header::LOCATION).unwrap(), resp.headers().get(header::LOCATION).unwrap(),
@ -804,7 +804,7 @@ mod tests {
let resp = st.handle(req) let resp = st.handle(req)
.respond_to(HttpRequest::default()) .respond_to(HttpRequest::default())
.unwrap(); .unwrap();
let resp = resp.as_response().expect("HTTP Response"); let resp = resp.as_msg();
assert_eq!(resp.status(), StatusCode::FOUND); assert_eq!(resp.status(), StatusCode::FOUND);
assert_eq!( assert_eq!(
resp.headers().get(header::LOCATION).unwrap(), resp.headers().get(header::LOCATION).unwrap(),
@ -821,7 +821,7 @@ mod tests {
let resp = st.handle(req) let resp = st.handle(req)
.respond_to(HttpRequest::default()) .respond_to(HttpRequest::default())
.unwrap(); .unwrap();
let resp = resp.as_response().expect("HTTP Response"); let resp = resp.as_msg();
assert_eq!(resp.status(), StatusCode::FOUND); assert_eq!(resp.status(), StatusCode::FOUND);
assert_eq!( assert_eq!(
resp.headers().get(header::LOCATION).unwrap(), resp.headers().get(header::LOCATION).unwrap(),

View File

@ -1,4 +1,4 @@
use futures::future::{err, ok, Future, FutureResult}; use futures::future::{err, ok, Future};
use futures::Poll; use futures::Poll;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::Deref; use std::ops::Deref;
@ -22,7 +22,7 @@ pub trait Handler<S>: 'static {
/// Types that implement this trait can be used as the return type of a handler. /// Types that implement this trait can be used as the return type of a handler.
pub trait Responder { pub trait Responder {
/// The associated item which can be returned. /// The associated item which can be returned.
type Item: Into<Reply>; type Item: Into<Reply<HttpResponse>>;
/// The associated error which can be returned. /// The associated error which can be returned.
type Error: Into<Error>; type Error: Into<Error>;
@ -42,10 +42,10 @@ where
type Config: Default; type Config: Default;
/// Future that resolves to a Self /// Future that resolves to a Self
type Result: Future<Item = Self, Error = Error>; type Result: Into<Reply<Self>>;
/// Convert request to a Self /// Convert request to a Self
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result; fn from_request(req: &mut HttpRequest<S>, cfg: &Self::Config) -> Self::Result;
} }
/// Combines two different responder types into a single type /// Combines two different responder types into a single type
@ -88,10 +88,10 @@ where
A: Responder, A: Responder,
B: Responder, B: Responder,
{ {
type Item = Reply; type Item = Reply<HttpResponse>;
type Error = Error; type Error = Error;
fn respond_to(self, req: HttpRequest) -> Result<Reply, Error> { fn respond_to(self, req: HttpRequest) -> Result<Reply<HttpResponse>, Error> {
match self { match self {
Either::A(a) => match a.respond_to(req) { Either::A(a) => match a.respond_to(req) {
Ok(val) => Ok(val.into()), Ok(val) => Ok(val.into()),
@ -177,66 +177,86 @@ where
} }
} }
/// Represents response process. /// Represents reply process.
pub struct Reply(ReplyItem); ///
/// Reply could be in tree different forms.
/// * Message(T) - ready item
/// * Error(Error) - error happen during reply process
/// * Future<T, Error> - reply process completes in the future
pub struct Reply<T>(ReplyItem<T>);
pub(crate) enum ReplyItem { pub(crate) enum ReplyItem<T> {
Message(HttpResponse), Error(Error),
Future(Box<Future<Item = HttpResponse, Error = Error>>), Message(T),
Future(Box<Future<Item = T, Error = Error>>),
} }
impl Reply { impl<T> Reply<T> {
/// Create async response /// Create async response
#[inline] #[inline]
pub fn async<F>(fut: F) -> Reply pub fn async<F>(fut: F) -> Reply<T>
where where
F: Future<Item = HttpResponse, Error = Error> + 'static, F: Future<Item = T, Error = Error> + 'static,
{ {
Reply(ReplyItem::Future(Box::new(fut))) Reply(ReplyItem::Future(Box::new(fut)))
} }
/// Send response /// Send response
#[inline] #[inline]
pub fn response<R: Into<HttpResponse>>(response: R) -> Reply { pub fn response<R: Into<T>>(response: R) -> Reply<T> {
Reply(ReplyItem::Message(response.into())) Reply(ReplyItem::Message(response.into()))
} }
/// Send error
#[inline] #[inline]
pub(crate) fn into(self) -> ReplyItem { pub fn error<R: Into<Error>>(err: R) -> Reply<T> {
Reply(ReplyItem::Error(err.into()))
}
#[inline]
pub(crate) fn into(self) -> ReplyItem<T> {
self.0 self.0
} }
#[cfg(test)] #[cfg(test)]
pub(crate) fn as_response(&self) -> Option<&HttpResponse> { pub(crate) fn as_msg(&self) -> &T {
match self.0 { 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, _ => None,
} }
} }
} }
impl Responder for Reply { impl Responder for Reply<HttpResponse> {
type Item = Reply; type Item = Reply<HttpResponse>;
type Error = Error; type Error = Error;
fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> { fn respond_to(self, _: HttpRequest) -> Result<Reply<HttpResponse>, Error> {
Ok(self) Ok(self)
} }
} }
impl Responder for HttpResponse { impl Responder for HttpResponse {
type Item = Reply; type Item = Reply<HttpResponse>;
type Error = Error; type Error = Error;
#[inline] #[inline]
fn respond_to(self, _: HttpRequest) -> Result<Reply, Error> { fn respond_to(self, _: HttpRequest) -> Result<Reply<HttpResponse>, Error> {
Ok(Reply(ReplyItem::Message(self))) Ok(Reply(ReplyItem::Message(self)))
} }
} }
impl From<HttpResponse> for Reply { impl<T> From<T> for Reply<T> {
#[inline] #[inline]
fn from(resp: HttpResponse) -> Reply { fn from(resp: T) -> Reply<T> {
Reply(ReplyItem::Message(resp)) Reply(ReplyItem::Message(resp))
} }
} }
@ -256,29 +276,41 @@ impl<T: Responder, E: Into<Error>> Responder for Result<T, E> {
} }
} }
impl<E: Into<Error>> From<Result<Reply, E>> for Reply { impl<T, E: Into<Error>> From<Result<Reply<T>, E>> for Reply<T> {
#[inline] #[inline]
fn from(res: Result<Reply, E>) -> Self { fn from(res: Result<Reply<T>, E>) -> Self {
match res { match res {
Ok(val) => val, Ok(val) => val,
Err(err) => Reply(ReplyItem::Message(err.into().into())), Err(err) => Reply(ReplyItem::Error(err.into())),
} }
} }
} }
impl<E: Into<Error>> From<Result<HttpResponse, E>> for Reply { impl<T, E: Into<Error>> From<Result<T, E>> for Reply<T> {
#[inline] #[inline]
fn from(res: Result<HttpResponse, E>) -> Self { fn from(res: Result<T, E>) -> Self {
match res { match res {
Ok(val) => Reply(ReplyItem::Message(val)), Ok(val) => Reply(ReplyItem::Message(val)),
Err(err) => Reply(ReplyItem::Message(err.into().into())), Err(err) => Reply(ReplyItem::Error(err.into())),
} }
} }
} }
impl From<Box<Future<Item = HttpResponse, Error = Error>>> for Reply { impl<T, E: Into<Error>> From<Result<Box<Future<Item = T, Error = Error>>, E>>
for Reply<T>
{
#[inline] #[inline]
fn from(fut: Box<Future<Item = HttpResponse, Error = Error>>) -> Reply { fn from(res: Result<Box<Future<Item = T, Error = Error>>, E>) -> Self {
match res {
Ok(fut) => Reply(ReplyItem::Future(fut)),
Err(err) => Reply(ReplyItem::Error(err.into())),
}
}
}
impl<T> From<Box<Future<Item = T, Error = Error>>> for Reply<T> {
#[inline]
fn from(fut: Box<Future<Item = T, Error = Error>>) -> Reply<T> {
Reply(ReplyItem::Future(fut)) Reply(ReplyItem::Future(fut))
} }
} }
@ -291,11 +323,11 @@ where
I: Responder + 'static, I: Responder + 'static,
E: Into<Error> + 'static, E: Into<Error> + 'static,
{ {
type Item = Reply; type Item = Reply<HttpResponse>;
type Error = Error; type Error = Error;
#[inline] #[inline]
fn respond_to(self, req: HttpRequest) -> Result<Reply, Error> { fn respond_to(self, req: HttpRequest) -> Result<Reply<HttpResponse>, Error> {
let fut = self.map_err(|e| e.into()) let fut = self.map_err(|e| e.into())
.then(move |r| match r.respond_to(req) { .then(move |r| match r.respond_to(req) {
Ok(reply) => match reply.into().0 { Ok(reply) => match reply.into().0 {
@ -310,7 +342,7 @@ where
/// Trait defines object that could be registered as resource route /// Trait defines object that could be registered as resource route
pub(crate) trait RouteHandler<S>: 'static { pub(crate) trait RouteHandler<S>: 'static {
fn handle(&mut self, req: HttpRequest<S>) -> Reply; fn handle(&mut self, req: HttpRequest<S>) -> Reply<HttpResponse>;
} }
/// Route handler wrapper for Handler /// Route handler wrapper for Handler
@ -344,7 +376,7 @@ where
R: Responder + 'static, R: Responder + 'static,
S: 'static, S: 'static,
{ {
fn handle(&mut self, req: HttpRequest<S>) -> Reply { fn handle(&mut self, req: HttpRequest<S>) -> Reply<HttpResponse> {
let req2 = req.drop_state(); let req2 = req.drop_state();
match self.h.handle(req).respond_to(req2) { match self.h.handle(req).respond_to(req2) {
Ok(reply) => reply.into(), Ok(reply) => reply.into(),
@ -390,7 +422,7 @@ where
E: Into<Error> + 'static, E: Into<Error> + 'static,
S: 'static, S: 'static,
{ {
fn handle(&mut self, req: HttpRequest<S>) -> Reply { fn handle(&mut self, req: HttpRequest<S>) -> Reply<HttpResponse> {
let req2 = req.drop_state(); let req2 = req.drop_state();
let fut = (self.h)(req).map_err(|e| e.into()).then(move |r| { let fut = (self.h)(req).map_err(|e| e.into()).then(move |r| {
match r.respond_to(req2) { match r.respond_to(req2) {
@ -449,10 +481,10 @@ impl<S> Deref for State<S> {
impl<S: 'static> FromRequest<S> for State<S> { impl<S: 'static> FromRequest<S> for State<S> {
type Config = (); type Config = ();
type Result = FutureResult<Self, Error>; type Result = State<S>;
#[inline] #[inline]
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result { fn from_request(req: &mut HttpRequest<S>, _: &Self::Config) -> Self::Result {
ok(State(req.clone())) State(req.clone()).into()
} }
} }

View File

@ -217,7 +217,7 @@ mod tests {
for (path, target, code) in params { for (path, target, code) in params {
let req = app.prepare_request(TestRequest::with_uri(path).finish()); let req = app.prepare_request(TestRequest::with_uri(path).finish());
let resp = app.run(req); let resp = app.run(req);
let r = resp.as_response().unwrap(); let r = resp.as_msg();
assert_eq!(r.status(), code); assert_eq!(r.status(), code);
if !target.is_empty() { if !target.is_empty() {
assert_eq!( assert_eq!(
@ -260,7 +260,7 @@ mod tests {
for (path, code) in params { for (path, code) in params {
let req = app.prepare_request(TestRequest::with_uri(path).finish()); let req = app.prepare_request(TestRequest::with_uri(path).finish());
let resp = app.run(req); let resp = app.run(req);
let r = resp.as_response().unwrap(); let r = resp.as_msg();
assert_eq!(r.status(), code); assert_eq!(r.status(), code);
} }
} }
@ -351,7 +351,7 @@ mod tests {
for (path, target, code) in params { for (path, target, code) in params {
let req = app.prepare_request(TestRequest::with_uri(path).finish()); let req = app.prepare_request(TestRequest::with_uri(path).finish());
let resp = app.run(req); let resp = app.run(req);
let r = resp.as_response().unwrap(); let r = resp.as_msg();
assert_eq!(r.status(), code); assert_eq!(r.status(), code);
if !target.is_empty() { if !target.is_empty() {
assert_eq!( assert_eq!(
@ -535,7 +535,7 @@ mod tests {
for (path, target, code) in params { for (path, target, code) in params {
let req = app.prepare_request(TestRequest::with_uri(path).finish()); let req = app.prepare_request(TestRequest::with_uri(path).finish());
let resp = app.run(req); let resp = app.run(req);
let r = resp.as_response().unwrap(); let r = resp.as_msg();
assert_eq!(r.status(), code); assert_eq!(r.status(), code);
if !target.is_empty() { if !target.is_empty() {
assert_eq!( assert_eq!(

View File

@ -1,20 +1,20 @@
//! HTTP Request message related code. //! HTTP Request message related code.
#![cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ptr))] #![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::net::SocketAddr;
use std::rc::Rc; use std::rc::Rc;
use std::{cmp, fmt, io, mem, str}; 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 tokio_io::AsyncRead;
use url::{form_urlencoded, Url}; use url::{form_urlencoded, Url};
use body::Body; use body::Body;
use error::{CookieParseError, Error, PayloadError, UrlGenerationError}; use error::{CookieParseError, PayloadError, UrlGenerationError};
use handler::FromRequest; use handler::FromRequest;
use httpmessage::HttpMessage; use httpmessage::HttpMessage;
use httpresponse::{HttpResponse, HttpResponseBuilder}; use httpresponse::{HttpResponse, HttpResponseBuilder};
@ -502,11 +502,11 @@ impl<S> Clone for HttpRequest<S> {
impl<S: 'static> FromRequest<S> for HttpRequest<S> { impl<S: 'static> FromRequest<S> for HttpRequest<S> {
type Config = (); type Config = ();
type Result = FutureResult<Self, Error>; type Result = Self;
#[inline] #[inline]
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result { fn from_request(req: &mut HttpRequest<S>, _: &Self::Config) -> Self::Result {
result(Ok(req.clone())) req.clone()
} }
} }

View File

@ -136,7 +136,7 @@ where
type Result = Box<Future<Item = Self, Error = Error>>; type Result = Box<Future<Item = Self, Error = Error>>;
#[inline] #[inline]
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result { fn from_request(req: &mut HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
let req = req.clone(); let req = req.clone();
let err = Rc::clone(&cfg.ehandler); let err = Rc::clone(&cfg.ehandler);
Box::new( Box::new(
@ -417,13 +417,7 @@ mod tests {
let mut handler = With::new(|data: Json<MyObject>| data, cfg); let mut handler = With::new(|data: Json<MyObject>| data, cfg);
let req = HttpRequest::default(); let req = HttpRequest::default();
let err = handler assert!(handler.handle(req).as_err().is_some());
.handle(req)
.as_response()
.unwrap()
.error()
.is_some();
assert!(err);
let mut req = HttpRequest::default(); let mut req = HttpRequest::default();
req.headers_mut().insert( req.headers_mut().insert(
@ -436,12 +430,6 @@ mod tests {
); );
req.payload_mut() req.payload_mut()
.unread_data(Bytes::from_static(b"{\"name\": \"test\"}")); .unread_data(Bytes::from_static(b"{\"name\": \"test\"}"));
let ok = handler assert!(handler.handle(req).as_err().is_none())
.handle(req)
.as_response()
.unwrap()
.error()
.is_none();
assert!(ok)
} }
} }

View File

@ -28,7 +28,8 @@ pub(crate) enum HandlerType {
pub(crate) trait PipelineHandler<S> { pub(crate) trait PipelineHandler<S> {
fn encoding(&self) -> ContentEncoding; fn encoding(&self) -> ContentEncoding;
fn handle(&mut self, req: HttpRequest<S>, htype: HandlerType) -> Reply; fn handle(&mut self, req: HttpRequest<S>, htype: HandlerType)
-> Reply<HttpResponse>;
} }
pub(crate) struct Pipeline<S, H>(PipelineInfo<S>, PipelineState<S, H>); pub(crate) struct Pipeline<S, H>(PipelineInfo<S>, PipelineState<S, H>);
@ -319,8 +320,11 @@ struct WaitingResponse<S, H> {
impl<S: 'static, H> WaitingResponse<S, H> { impl<S: 'static, H> WaitingResponse<S, H> {
#[inline] #[inline]
fn init(info: &mut PipelineInfo<S>, reply: Reply) -> PipelineState<S, H> { fn init(
info: &mut PipelineInfo<S>, reply: Reply<HttpResponse>,
) -> PipelineState<S, H> {
match reply.into() { match reply.into() {
ReplyItem::Error(err) => RunMiddlewares::init(info, err.into()),
ReplyItem::Message(resp) => RunMiddlewares::init(info, resp), ReplyItem::Message(resp) => RunMiddlewares::init(info, resp),
ReplyItem::Future(fut) => PipelineState::Handler(WaitingResponse { ReplyItem::Future(fut) => PipelineState::Handler(WaitingResponse {
fut, fut,

View File

@ -198,7 +198,7 @@ impl<S: 'static> ResourceHandler<S> {
pub(crate) fn handle( pub(crate) fn handle(
&mut self, mut req: HttpRequest<S>, default: Option<&mut ResourceHandler<S>>, &mut self, mut req: HttpRequest<S>, default: Option<&mut ResourceHandler<S>>,
) -> Reply { ) -> Reply<HttpResponse> {
for route in &mut self.routes { for route in &mut self.routes {
if route.check(&mut req) { if route.check(&mut req) {
return if self.middlewares.is_empty() { return if self.middlewares.is_empty() {

View File

@ -45,14 +45,14 @@ impl<S: 'static> Route<S> {
} }
#[inline] #[inline]
pub(crate) fn handle(&mut self, req: HttpRequest<S>) -> Reply { pub(crate) fn handle(&mut self, req: HttpRequest<S>) -> Reply<HttpResponse> {
self.handler.handle(req) self.handler.handle(req)
} }
#[inline] #[inline]
pub(crate) fn compose( pub(crate) fn compose(
&mut self, req: HttpRequest<S>, mws: Rc<Vec<Box<Middleware<S>>>>, &mut self, req: HttpRequest<S>, mws: Rc<Vec<Box<Middleware<S>>>>,
) -> Reply { ) -> Reply<HttpResponse> {
Reply::async(Compose::new(req, mws, self.handler.clone())) Reply::async(Compose::new(req, mws, self.handler.clone()))
} }
@ -243,7 +243,7 @@ impl<S: 'static> InnerHandler<S> {
} }
#[inline] #[inline]
pub fn handle(&self, req: HttpRequest<S>) -> Reply { pub fn handle(&self, req: HttpRequest<S>) -> Reply<HttpResponse> {
// reason: handler is unique per thread, handler get called from async code only // reason: handler is unique per thread, handler get called from async code only
let h = unsafe { &mut *self.0.as_ref().get() }; let h = unsafe { &mut *self.0.as_ref().get() };
h.handle(req) h.handle(req)
@ -415,8 +415,9 @@ struct WaitingResponse<S> {
impl<S: 'static> WaitingResponse<S> { impl<S: 'static> WaitingResponse<S> {
#[inline] #[inline]
fn init(info: &mut ComposeInfo<S>, reply: Reply) -> ComposeState<S> { fn init(info: &mut ComposeInfo<S>, reply: Reply<HttpResponse>) -> ComposeState<S> {
match reply.into() { match reply.into() {
ReplyItem::Error(err) => RunMiddlewares::init(info, err.into()),
ReplyItem::Message(resp) => RunMiddlewares::init(info, resp), ReplyItem::Message(resp) => RunMiddlewares::init(info, resp),
ReplyItem::Future(fut) => ComposeState::Handler(WaitingResponse { ReplyItem::Future(fut) => ComposeState::Handler(WaitingResponse {
fut, fut,

View File

@ -274,7 +274,7 @@ impl<S: 'static> Scope<S> {
} }
impl<S: 'static> RouteHandler<S> for Scope<S> { impl<S: 'static> RouteHandler<S> for Scope<S> {
fn handle(&mut self, mut req: HttpRequest<S>) -> Reply { fn handle(&mut self, mut req: HttpRequest<S>) -> Reply<HttpResponse> {
let path = unsafe { &*(&req.match_info()["tail"] as *const _) }; let path = unsafe { &*(&req.match_info()["tail"] as *const _) };
let path = if path == "" { "/" } else { path }; let path = if path == "" { "/" } else { path };
@ -346,7 +346,7 @@ struct Wrapper<S: 'static> {
} }
impl<S: 'static, S2: 'static> RouteHandler<S2> for Wrapper<S> { impl<S: 'static, S2: 'static> RouteHandler<S2> for Wrapper<S> {
fn handle(&mut self, req: HttpRequest<S2>) -> Reply { fn handle(&mut self, req: HttpRequest<S2>) -> Reply<HttpResponse> {
self.scope self.scope
.handle(req.change_state(Rc::clone(&self.state))) .handle(req.change_state(Rc::clone(&self.state)))
} }
@ -521,9 +521,10 @@ struct WaitingResponse<S> {
impl<S: 'static> WaitingResponse<S> { impl<S: 'static> WaitingResponse<S> {
#[inline] #[inline]
fn init(info: &mut ComposeInfo<S>, reply: Reply) -> ComposeState<S> { fn init(info: &mut ComposeInfo<S>, reply: Reply<HttpResponse>) -> ComposeState<S> {
match reply.into() { match reply.into() {
ReplyItem::Message(resp) => RunMiddlewares::init(info, resp), ReplyItem::Message(resp) => RunMiddlewares::init(info, resp),
ReplyItem::Error(err) => RunMiddlewares::init(info, err.into()),
ReplyItem::Future(fut) => ComposeState::Handler(WaitingResponse { ReplyItem::Future(fut) => ComposeState::Handler(WaitingResponse {
fut, fut,
_s: PhantomData, _s: PhantomData,
@ -707,7 +708,7 @@ mod tests {
let req = TestRequest::with_uri("/app/path1").finish(); let req = TestRequest::with_uri("/app/path1").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK); assert_eq!(resp.as_msg().status(), StatusCode::OK);
} }
#[test] #[test]
@ -724,10 +725,7 @@ mod tests {
let req = TestRequest::with_uri("/app/t1/path1").finish(); let req = TestRequest::with_uri("/app/t1/path1").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::CREATED);
resp.as_response().unwrap().status(),
StatusCode::CREATED
);
} }
#[test] #[test]
@ -742,10 +740,7 @@ mod tests {
let req = TestRequest::with_uri("/app/t1/path1").finish(); let req = TestRequest::with_uri("/app/t1/path1").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::CREATED);
resp.as_response().unwrap().status(),
StatusCode::CREATED
);
} }
#[test] #[test]
@ -760,16 +755,10 @@ mod tests {
let req = TestRequest::with_uri("/app/path2").finish(); let req = TestRequest::with_uri("/app/path2").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::BAD_REQUEST);
resp.as_response().unwrap().status(),
StatusCode::BAD_REQUEST
);
let req = TestRequest::with_uri("/path2").finish(); let req = TestRequest::with_uri("/path2").finish();
let resp = app.run(req); let resp = app.run(req);
assert_eq!( assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
} }
} }

View File

@ -602,6 +602,7 @@ impl<S> TestRequest<S> {
match resp.respond_to(req.drop_state()) { match resp.respond_to(req.drop_state()) {
Ok(resp) => match resp.into().into() { Ok(resp) => match resp.into().into() {
ReplyItem::Message(resp) => Ok(resp), ReplyItem::Message(resp) => Ok(resp),
ReplyItem::Error(err) => Ok(err.into()),
ReplyItem::Future(_) => panic!("Async handler is not supported."), ReplyItem::Future(_) => panic!("Async handler is not supported."),
}, },
Err(err) => Err(err), Err(err) => Err(err),

View File

@ -82,7 +82,7 @@ where
T: FromRequest<S> + 'static, T: FromRequest<S> + 'static,
S: 'static, S: 'static,
{ {
type Result = Reply; type Result = Reply<HttpResponse>;
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result { fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
let mut fut = WithHandlerFut { let mut fut = WithHandlerFut {
@ -97,7 +97,7 @@ where
match fut.poll() { match fut.poll() {
Ok(Async::Ready(resp)) => Reply::response(resp), Ok(Async::Ready(resp)) => Reply::response(resp),
Ok(Async::NotReady) => Reply::async(fut), Ok(Async::NotReady) => Reply::async(fut),
Err(e) => Reply::response(e), Err(e) => Reply::error::<Error>(e),
} }
} }
} }
@ -134,14 +134,14 @@ where
let item = if !self.started { let item = if !self.started {
self.started = true; self.started = true;
let mut fut = T::from_request(&self.req, self.cfg.as_ref()); let reply = T::from_request(&mut self.req, self.cfg.as_ref()).into();
match fut.poll() { match reply.into() {
Ok(Async::Ready(item)) => item, ReplyItem::Error(err) => return Err(err),
Ok(Async::NotReady) => { ReplyItem::Message(msg) => msg,
self.fut1 = Some(Box::new(fut)); ReplyItem::Future(fut) => {
return Ok(Async::NotReady); self.fut1 = Some(fut);
return self.poll();
} }
Err(e) => return Err(e),
} }
} else { } else {
match self.fut1.as_mut().unwrap().poll()? { match self.fut1.as_mut().unwrap().poll()? {
@ -157,6 +157,7 @@ where
}; };
match item.into() { match item.into() {
ReplyItem::Error(err) => Err(err),
ReplyItem::Message(resp) => Ok(Async::Ready(resp)), ReplyItem::Message(resp) => Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => { ReplyItem::Future(fut) => {
self.fut2 = Some(fut); self.fut2 = Some(fut);
@ -206,7 +207,7 @@ where
T2: FromRequest<S> + 'static, T2: FromRequest<S> + 'static,
S: 'static, S: 'static,
{ {
type Result = Reply; type Result = Reply<HttpResponse>;
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result { fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
let mut fut = WithHandlerFut2 { let mut fut = WithHandlerFut2 {
@ -265,19 +266,32 @@ where
if !self.started { if !self.started {
self.started = true; self.started = true;
let mut fut = T1::from_request(&self.req, self.cfg1.as_ref()); let reply = T1::from_request(&mut self.req, self.cfg1.as_ref()).into();
match fut.poll() { let item1 = match reply.into() {
Ok(Async::Ready(item1)) => { ReplyItem::Error(err) => return Err(err),
let mut fut = T2::from_request(&self.req, self.cfg2.as_ref()); ReplyItem::Message(msg) => msg,
match fut.poll() { ReplyItem::Future(fut) => {
Ok(Async::Ready(item2)) => { self.fut1 = Some(fut);
let hnd: &mut F = unsafe { &mut *self.hnd.get() }; return self.poll();
match (*hnd)(item1, item2).respond_to(self.req.drop_state())
{
Ok(item) => match item.into().into() {
ReplyItem::Message(resp) => {
return Ok(Async::Ready(resp))
} }
};
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) => { ReplyItem::Future(fut) => {
self.fut3 = Some(fut); self.fut3 = Some(fut);
return self.poll(); return self.poll();
@ -286,31 +300,34 @@ where
Err(e) => return Err(e.into()), 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),
}
}
Ok(Async::NotReady) => {
self.fut1 = Some(Box::new(fut));
return Ok(Async::NotReady);
}
Err(e) => return Err(e),
}
}
if self.fut1.is_some() { if self.fut1.is_some() {
match self.fut1.as_mut().unwrap().poll()? { match self.fut1.as_mut().unwrap().poll()? {
Async::Ready(item) => { Async::Ready(item) => {
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.item = Some(item);
self.fut1.take(); self.fut2 = Some(fut);
self.fut2 = Some(Box::new(T2::from_request( return self.poll();
&self.req, }
self.cfg2.as_ref(), };
)));
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), Async::NotReady => return Ok(Async::NotReady),
} }
@ -330,6 +347,7 @@ where
}; };
match item.into() { match item.into() {
ReplyItem::Error(err) => return Err(err),
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyItem::Message(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => self.fut3 = Some(fut), ReplyItem::Future(fut) => self.fut3 = Some(fut),
} }
@ -387,7 +405,7 @@ where
T3: 'static, T3: 'static,
S: 'static, S: 'static,
{ {
type Result = Reply; type Result = Reply<HttpResponse>;
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result { fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
let mut fut = WithHandlerFut3 { let mut fut = WithHandlerFut3 {
@ -454,24 +472,44 @@ where
if !self.started { if !self.started {
self.started = true; self.started = true;
let mut fut = T1::from_request(&self.req, self.cfg1.as_ref()); let reply = T1::from_request(&mut self.req, self.cfg1.as_ref()).into();
match fut.poll() { let item1 = match reply.into() {
Ok(Async::Ready(item1)) => { ReplyItem::Error(err) => return Err(err),
let mut fut = T2::from_request(&self.req, self.cfg2.as_ref()); ReplyItem::Message(msg) => msg,
match fut.poll() { ReplyItem::Future(fut) => {
Ok(Async::Ready(item2)) => { self.fut1 = Some(fut);
let mut fut = return self.poll();
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))
} }
};
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) => { ReplyItem::Future(fut) => {
self.fut4 = Some(fut); self.fut4 = Some(fut);
return self.poll(); return self.poll();
@ -480,40 +518,48 @@ where
Err(e) => return Err(e.into()), 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),
}
}
Ok(Async::NotReady) => {
self.fut1 = Some(Box::new(fut));
return Ok(Async::NotReady);
}
Err(e) => return Err(e),
}
}
if self.fut1.is_some() { if self.fut1.is_some() {
match self.fut1.as_mut().unwrap().poll()? { match self.fut1.as_mut().unwrap().poll()? {
Async::Ready(item) => { Async::Ready(item) => {
self.item1 = Some(item); self.item1 = Some(item);
self.fut1.take(); self.fut1.take();
self.fut2 = Some(Box::new(T2::from_request( let reply =
&self.req, T2::from_request(&mut self.req, self.cfg2.as_ref()).into();
self.cfg2.as_ref(), 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), Async::NotReady => return Ok(Async::NotReady),
} }
@ -522,12 +568,32 @@ where
if self.fut2.is_some() { if self.fut2.is_some() {
match self.fut2.as_mut().unwrap().poll()? { match self.fut2.as_mut().unwrap().poll()? {
Async::Ready(item) => { Async::Ready(item) => {
self.item2 = Some(item);
self.fut2.take(); self.fut2.take();
self.fut3 = Some(Box::new(T3::from_request( let reply =
&self.req, T3::from_request(&mut self.req, self.cfg3.as_ref()).into();
self.cfg3.as_ref(), 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), Async::NotReady => return Ok(Async::NotReady),
} }
@ -550,6 +616,7 @@ where
}; };
match item.into() { match item.into() {
ReplyItem::Error(err) => return Ok(Async::Ready(err.into())),
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyItem::Message(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => self.fut4 = Some(fut), ReplyItem::Future(fut) => self.fut4 = Some(fut),
} }