1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-28 09:42:40 +01:00

Merge branch 'master' into ws-trait

This commit is contained in:
Nikolay Kim 2018-05-03 08:57:45 -07:00 committed by GitHub
commit bb61dd41af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 421 additions and 245 deletions

View File

@ -12,6 +12,10 @@
* Allow to access Error's backtrace object * Allow to access Error's backtrace object
* Allow to override files listing renderer for `StaticFiles` #203
* Various extractor usability improvements #207
## 0.5.6 (2018-04-24) ## 0.5.6 (2018-04-24)

View File

@ -15,6 +15,20 @@
* `FromRequest::Result` has to implement `Into<Reply<Self>>` * `FromRequest::Result` has to implement `Into<Reply<Self>>`
* `HttpRequest::query()` is deprecated. Use `Query` extractor.
```rust
fn index(q: Query<HashMap<String, String>>) -> Result<..> {
...
}
```
or
```rust
let q = Query::<HashMap<String, String>>::extract(req);
```
## Migration from 0.4 to 0.5 ## Migration from 0.4 to 0.5

View File

@ -805,8 +805,7 @@ mod tests {
#[test] #[test]
fn test_backtrace() { fn test_backtrace() {
let orig = ErrorBadRequest("err"); let e = ErrorBadRequest("err");
let e: Error = orig.into();
assert!(e.backtrace().is_some()); assert!(e.backtrace().is_some());
} }

View File

@ -1,17 +1,18 @@
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::str; 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::Future; use futures::{Async, Future, Poll};
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::FromRequest; use handler::{FromRequest, Reply};
use httpmessage::{HttpMessage, MessageBody, UrlEncoded}; use httpmessage::{HttpMessage, MessageBody, UrlEncoded};
use httprequest::HttpRequest; use httprequest::HttpRequest;
@ -99,13 +100,12 @@ impl<T> Path<T> {
impl<T, S> FromRequest<S> for Path<T> impl<T, S> FromRequest<S> for Path<T>
where where
T: DeserializeOwned, T: DeserializeOwned,
S: 'static,
{ {
type Config = (); type Config = ();
type Result = Result<Self, Error>; type Result = Result<Self, Error>;
#[inline] #[inline]
fn from_request(req: &mut HttpRequest<S>, _: &Self::Config) -> Self::Result { fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
let req = req.clone(); let req = req.clone();
de::Deserialize::deserialize(PathDeserializer::new(&req)) de::Deserialize::deserialize(PathDeserializer::new(&req))
.map_err(|e| e.into()) .map_err(|e| e.into())
@ -167,13 +167,12 @@ impl<T> Query<T> {
impl<T, S> FromRequest<S> for Query<T> impl<T, S> FromRequest<S> for Query<T>
where where
T: de::DeserializeOwned, T: de::DeserializeOwned,
S: 'static,
{ {
type Config = (); type Config = ();
type Result = Result<Self, Error>; type Result = Result<Self, Error>;
#[inline] #[inline]
fn from_request(req: &mut HttpRequest<S>, _: &Self::Config) -> Self::Result { fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
let req = req.clone(); let req = req.clone();
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())
@ -241,7 +240,7 @@ where
type Result = Box<Future<Item = Self, Error = Error>>; type Result = Box<Future<Item = Self, Error = Error>>;
#[inline] #[inline]
fn from_request(req: &mut HttpRequest<S>, cfg: &Self::Config) -> Self::Result { fn from_request(req: &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)
@ -326,7 +325,7 @@ impl<S: 'static> FromRequest<S> for Bytes {
type Result = Result<Box<Future<Item = Self, Error = Error>>, Error>; type Result = Result<Box<Future<Item = Self, Error = Error>>, Error>;
#[inline] #[inline]
fn from_request(req: &mut HttpRequest<S>, cfg: &Self::Config) -> Self::Result { fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
// check content-type // check content-type
cfg.check_mimetype(req)?; cfg.check_mimetype(req)?;
@ -370,7 +369,7 @@ impl<S: 'static> FromRequest<S> for String {
type Result = Result<Box<Future<Item = String, Error = Error>>, Error>; type Result = Result<Box<Future<Item = String, Error = Error>>, Error>;
#[inline] #[inline]
fn from_request(req: &mut HttpRequest<S>, cfg: &Self::Config) -> Self::Result { fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
// check content-type // check content-type
cfg.check_mimetype(req)?; cfg.check_mimetype(req)?;
@ -447,6 +446,123 @@ impl Default for PayloadConfig {
} }
} }
macro_rules! tuple_from_req ({$fut_type:ident, $(($n:tt, $T:ident)),+} => {
/// FromRequest implementation for tuple
impl<S, $($T: FromRequest<S> + 'static),+> FromRequest<S> for ($($T,)+)
where
S: 'static,
{
type Config = ($($T::Config,)+);
type Result = Box<Future<Item = ($($T,)+), Error = Error>>;
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
Box::new($fut_type {
s: PhantomData,
items: <($(Option<$T>,)+)>::default(),
futs: ($(Some($T::from_request(req, &cfg.$n).into()),)+),
})
}
}
struct $fut_type<S, $($T: FromRequest<S>),+>
where
S: 'static,
{
s: PhantomData<S>,
items: ($(Option<$T>,)+),
futs: ($(Option<Reply<$T>>,)+),
}
impl<S, $($T: FromRequest<S>),+> Future for $fut_type<S, $($T),+>
where
S: 'static,
{
type Item = ($($T,)+);
type Error = Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut ready = true;
$(
if self.futs.$n.is_some() {
match self.futs.$n.as_mut().unwrap().poll() {
Ok(Async::Ready(item)) => {
self.items.$n = Some(item);
self.futs.$n.take();
}
Ok(Async::NotReady) => ready = false,
Err(e) => return Err(e),
}
}
)+
if ready {
Ok(Async::Ready(
($(self.items.$n.take().unwrap(),)+)
))
} else {
Ok(Async::NotReady)
}
}
}
});
tuple_from_req!(TupleFromRequest1, (0, A));
tuple_from_req!(TupleFromRequest2, (0, A), (1, B));
tuple_from_req!(TupleFromRequest3, (0, A), (1, B), (2, C));
tuple_from_req!(TupleFromRequest4, (0, A), (1, B), (2, C), (3, D));
tuple_from_req!(
TupleFromRequest5,
(0, A),
(1, B),
(2, C),
(3, D),
(4, E)
);
tuple_from_req!(
TupleFromRequest6,
(0, A),
(1, B),
(2, C),
(3, D),
(4, E),
(5, F)
);
tuple_from_req!(
TupleFromRequest7,
(0, A),
(1, B),
(2, C),
(3, D),
(4, E),
(5, F),
(6, G)
);
tuple_from_req!(
TupleFromRequest8,
(0, A),
(1, B),
(2, C),
(3, D),
(4, E),
(5, F),
(6, G),
(7, H)
);
tuple_from_req!(
TupleFromRequest9,
(0, A),
(1, B),
(2, C),
(3, D),
(4, E),
(5, F),
(6, G),
(7, H),
(8, I)
);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -471,7 +587,7 @@ 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(&mut req, &cfg) match Bytes::from_request(&req, &cfg)
.unwrap() .unwrap()
.poll() .poll()
.unwrap() .unwrap()
@ -490,7 +606,7 @@ 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(&mut req, &cfg) match String::from_request(&req, &cfg)
.unwrap() .unwrap()
.poll() .poll()
.unwrap() .unwrap()
@ -514,10 +630,7 @@ mod tests {
let mut cfg = FormConfig::default(); let mut cfg = FormConfig::default();
cfg.limit(4096); cfg.limit(4096);
match Form::<Info>::from_request(&mut req, &cfg) match Form::<Info>::from_request(&req, &cfg).poll().unwrap() {
.poll()
.unwrap()
{
Async::Ready(s) => { Async::Ready(s) => {
assert_eq!(s.hello, "world"); assert_eq!(s.hello, "world");
} }
@ -574,29 +687,29 @@ 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());
let s = Path::<MyStruct>::from_request(&mut req, &()).unwrap(); let s = Path::<MyStruct>::from_request(&req, &()).unwrap();
assert_eq!(s.key, "name"); assert_eq!(s.key, "name");
assert_eq!(s.value, "user1"); assert_eq!(s.value, "user1");
let s = Path::<(String, String)>::from_request(&mut req, &()).unwrap(); let s = Path::<(String, String)>::from_request(&req, &()).unwrap();
assert_eq!(s.0, "name"); assert_eq!(s.0, "name");
assert_eq!(s.1, "user1"); assert_eq!(s.1, "user1");
let s = Query::<Id>::from_request(&mut req, &()).unwrap(); let s = Query::<Id>::from_request(&req, &()).unwrap();
assert_eq!(s.id, "test"); assert_eq!(s.id, "test");
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());
let s = Path::<Test2>::from_request(&mut req, &()).unwrap(); let s = Path::<Test2>::from_request(&req, &()).unwrap();
assert_eq!(s.as_ref().key, "name"); assert_eq!(s.as_ref().key, "name");
assert_eq!(s.value, 32); assert_eq!(s.value, 32);
let s = Path::<(String, u8)>::from_request(&mut req, &()).unwrap(); let s = Path::<(String, u8)>::from_request(&req, &()).unwrap();
assert_eq!(s.0, "name"); assert_eq!(s.0, "name");
assert_eq!(s.1, 32); assert_eq!(s.1, 32);
let res = Path::<Vec<String>>::from_request(&mut req, &()).unwrap(); let res = Path::<Vec<String>>::extract(&req).unwrap();
assert_eq!(res[0], "name".to_owned()); assert_eq!(res[0], "name".to_owned());
assert_eq!(res[1], "32".to_owned()); assert_eq!(res[1], "32".to_owned());
} }
@ -614,4 +727,37 @@ mod tests {
assert_eq!(*Path::<i8>::from_request(&mut req, &()).unwrap(), 32); assert_eq!(*Path::<i8>::from_request(&mut req, &()).unwrap(), 32);
} }
#[test]
fn test_tuple_extract() {
let mut req = TestRequest::with_uri("/name/user1/?id=test").finish();
let mut resource = ResourceHandler::<()>::default();
resource.name("index");
let mut routes = Vec::new();
routes.push((
Resource::new("index", "/{key}/{value}/"),
Some(resource),
));
let (router, _) = Router::new("", ServerSettings::default(), routes);
assert!(router.recognize(&mut req).is_some());
let res = match <(Path<(String, String)>,)>::extract(&req).poll() {
Ok(Async::Ready(res)) => res,
_ => panic!("error"),
};
assert_eq!((res.0).0, "name");
assert_eq!((res.0).1, "user1");
let res = match <(Path<(String, String)>, Path<(String, String)>)>::extract(&req)
.poll()
{
Ok(Async::Ready(res)) => res,
_ => panic!("error"),
};
assert_eq!((res.0).0, "name");
assert_eq!((res.0).1, "user1");
assert_eq!((res.1).0, "name");
assert_eq!((res.1).1, "user1");
}
} }

View File

@ -365,11 +365,14 @@ impl Stream for ChunkedReadFile {
} }
} }
type DirectoryRenderer<S> =
Fn(&Directory, &HttpRequest<S>) -> Result<HttpResponse, io::Error>;
/// A directory; responds with the generated directory listing. /// A directory; responds with the generated directory listing.
#[derive(Debug)] #[derive(Debug)]
pub struct Directory { pub struct Directory {
base: PathBuf, pub base: PathBuf,
path: PathBuf, pub path: PathBuf,
} }
impl Directory { impl Directory {
@ -377,7 +380,7 @@ impl Directory {
Directory { base, path } Directory { base, path }
} }
fn can_list(&self, entry: &io::Result<DirEntry>) -> bool { pub fn is_visible(&self, entry: &io::Result<DirEntry>) -> bool {
if let Ok(ref entry) = *entry { if let Ok(ref entry) = *entry {
if let Some(name) = entry.file_name().to_str() { if let Some(name) = entry.file_name().to_str() {
if name.starts_with('.') { if name.starts_with('.') {
@ -393,19 +396,17 @@ impl Directory {
} }
} }
impl Responder for Directory { fn directory_listing<S>(
type Item = HttpResponse; dir: &Directory, req: &HttpRequest<S>,
type Error = io::Error; ) -> Result<HttpResponse, io::Error> {
fn respond_to(self, req: HttpRequest) -> Result<HttpResponse, io::Error> {
let index_of = format!("Index of {}", req.path()); let index_of = format!("Index of {}", req.path());
let mut body = String::new(); let mut body = String::new();
let base = Path::new(req.path()); let base = Path::new(req.path());
for entry in self.path.read_dir()? { for entry in dir.path.read_dir()? {
if self.can_list(&entry) { if dir.is_visible(&entry) {
let entry = entry.unwrap(); let entry = entry.unwrap();
let p = match entry.path().strip_prefix(&self.path) { let p = match entry.path().strip_prefix(&dir.path) {
Ok(p) => base.join(p), Ok(p) => base.join(p),
Err(_) => continue, Err(_) => continue,
}; };
@ -447,7 +448,6 @@ impl Responder for Directory {
Ok(HttpResponse::Ok() Ok(HttpResponse::Ok()
.content_type("text/html; charset=utf-8") .content_type("text/html; charset=utf-8")
.body(html)) .body(html))
}
} }
/// Static files handling /// Static files handling
@ -472,6 +472,7 @@ pub struct StaticFiles<S> {
show_index: bool, show_index: bool,
cpu_pool: CpuPool, cpu_pool: CpuPool,
default: Box<RouteHandler<S>>, default: Box<RouteHandler<S>>,
renderer: Box<DirectoryRenderer<S>>,
_chunk_size: usize, _chunk_size: usize,
_follow_symlinks: bool, _follow_symlinks: bool,
} }
@ -535,6 +536,7 @@ impl<S: 'static> StaticFiles<S> {
default: Box::new(WrapHandler::new(|_| { default: Box::new(WrapHandler::new(|_| {
HttpResponse::new(StatusCode::NOT_FOUND) HttpResponse::new(StatusCode::NOT_FOUND)
})), })),
renderer: Box::new(directory_listing),
_chunk_size: 0, _chunk_size: 0,
_follow_symlinks: false, _follow_symlinks: false,
} }
@ -548,6 +550,17 @@ impl<S: 'static> StaticFiles<S> {
self self
} }
/// Set custom directory renderer
pub fn files_listing_renderer<F>(mut self, f: F) -> Self
where
for<'r, 's> F: Fn(&'r Directory, &'s HttpRequest<S>)
-> Result<HttpResponse, io::Error>
+ 'static,
{
self.renderer = Box::new(f);
self
}
/// Set index file /// Set index file
/// ///
/// Redirects to specific index file for directory "/" instead of /// Redirects to specific index file for directory "/" instead of
@ -601,9 +614,8 @@ impl<S: 'static> Handler<S> for StaticFiles<S> {
.finish() .finish()
.respond_to(req.drop_state()) .respond_to(req.drop_state())
} else if self.show_index { } else if self.show_index {
Directory::new(self.directory.clone(), path) let dir = Directory::new(self.directory.clone(), path);
.respond_to(req.drop_state())? Ok((*self.renderer)(&dir, &req)?.into())
.respond_to(req.drop_state())
} else { } else {
Ok(self.default.handle(req)) Ok(self.default.handle(req))
} }

View File

@ -1,5 +1,4 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem;
use std::ops::Deref; use std::ops::Deref;
use futures::future::{err, ok, Future}; use futures::future::{err, ok, Future};
@ -36,10 +35,7 @@ pub trait Responder {
/// Trait implemented by types that can be extracted from request. /// Trait implemented by types that can be extracted from request.
/// ///
/// Types that implement this trait can be used with `Route::with()` method. /// Types that implement this trait can be used with `Route::with()` method.
pub trait FromRequest<S>: Sized pub trait FromRequest<S>: Sized {
where
S: 'static,
{
/// Configuration for conversion process /// Configuration for conversion process
type Config: Default; type Config: Default;
@ -47,7 +43,14 @@ where
type Result: Into<Reply<Self>>; type Result: Into<Reply<Self>>;
/// Convert request to a Self /// Convert request to a Self
fn from_request(req: &mut HttpRequest<S>, cfg: &Self::Config) -> Self::Result; fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result;
/// Convert request to a Self
///
/// This method uses default extractor configuration
fn extract(req: &HttpRequest<S>) -> Self::Result {
Self::from_request(req, &Self::Config::default())
}
} }
/// Combines two different responder types into a single type /// Combines two different responder types into a single type
@ -185,77 +188,74 @@ where
/// * Message(T) - ready item /// * Message(T) - ready item
/// * Error(Error) - error happen during reply process /// * Error(Error) - error happen during reply process
/// * Future<T, Error> - reply process completes in the future /// * Future<T, Error> - reply process completes in the future
pub struct Reply<T>(ReplyItem<T>); pub struct Reply<I, E = Error>(Option<ReplyResult<I, E>>);
impl<T> Future for Reply<T> { impl<I, E> Future for Reply<I, E> {
type Item = T; type Item = I;
type Error = Error; type Error = E;
fn poll(&mut self) -> Poll<T, Error> { fn poll(&mut self) -> Poll<I, E> {
let item = mem::replace(&mut self.0, ReplyItem::None); let res = self.0.take().expect("use after resolve");
match res {
match item { ReplyResult::Ok(msg) => Ok(Async::Ready(msg)),
ReplyItem::Error(err) => Err(err), ReplyResult::Err(err) => Err(err),
ReplyItem::Message(msg) => Ok(Async::Ready(msg)), ReplyResult::Future(mut fut) => match fut.poll() {
ReplyItem::Future(mut fut) => match fut.poll() {
Ok(Async::NotReady) => { Ok(Async::NotReady) => {
self.0 = ReplyItem::Future(fut); self.0 = Some(ReplyResult::Future(fut));
Ok(Async::NotReady) Ok(Async::NotReady)
} }
Ok(Async::Ready(msg)) => Ok(Async::Ready(msg)), Ok(Async::Ready(msg)) => Ok(Async::Ready(msg)),
Err(err) => Err(err), Err(err) => Err(err),
}, },
ReplyItem::None => panic!("use after resolve"),
} }
} }
} }
pub(crate) enum ReplyItem<T> { pub(crate) enum ReplyResult<I, E> {
None, Ok(I),
Error(Error), Err(E),
Message(T), Future(Box<Future<Item = I, Error = E>>),
Future(Box<Future<Item = T, Error = Error>>),
} }
impl<T> Reply<T> { impl<I, E> Reply<I, E> {
/// Create async response /// Create async response
#[inline] #[inline]
pub fn async<F>(fut: F) -> Reply<T> pub fn async<F>(fut: F) -> Reply<I, E>
where where
F: Future<Item = T, Error = Error> + 'static, F: Future<Item = I, Error = E> + 'static,
{ {
Reply(ReplyItem::Future(Box::new(fut))) Reply(Some(ReplyResult::Future(Box::new(fut))))
} }
/// Send response /// Send response
#[inline] #[inline]
pub fn response<R: Into<T>>(response: R) -> Reply<T> { pub fn response<R: Into<I>>(response: R) -> Reply<I, E> {
Reply(ReplyItem::Message(response.into())) Reply(Some(ReplyResult::Ok(response.into())))
} }
/// Send error /// Send error
#[inline] #[inline]
pub fn error<R: Into<Error>>(err: R) -> Reply<T> { pub fn error<R: Into<E>>(err: R) -> Reply<I, E> {
Reply(ReplyItem::Error(err.into())) Reply(Some(ReplyResult::Err(err.into())))
} }
#[inline] #[inline]
pub(crate) fn into(self) -> ReplyItem<T> { pub(crate) fn into(self) -> ReplyResult<I, E> {
self.0 self.0.expect("use after resolve")
} }
#[cfg(test)] #[cfg(test)]
pub(crate) fn as_msg(&self) -> &T { pub(crate) fn as_msg(&self) -> &I {
match self.0 { match self.0.as_ref().unwrap() {
ReplyItem::Message(ref resp) => resp, &ReplyResult::Ok(ref resp) => resp,
_ => panic!(), _ => panic!(),
} }
} }
#[cfg(test)] #[cfg(test)]
pub(crate) fn as_err(&self) -> Option<&Error> { pub(crate) fn as_err(&self) -> Option<&E> {
match self.0 { match self.0.as_ref().unwrap() {
ReplyItem::Error(ref err) => Some(err), &ReplyResult::Err(ref err) => Some(err),
_ => None, _ => None,
} }
} }
@ -276,14 +276,14 @@ impl Responder for HttpResponse {
#[inline] #[inline]
fn respond_to(self, _: HttpRequest) -> Result<Reply<HttpResponse>, Error> { fn respond_to(self, _: HttpRequest) -> Result<Reply<HttpResponse>, Error> {
Ok(Reply(ReplyItem::Message(self))) Ok(Reply(Some(ReplyResult::Ok(self))))
} }
} }
impl<T> From<T> for Reply<T> { impl<T> From<T> for Reply<T> {
#[inline] #[inline]
fn from(resp: T) -> Reply<T> { fn from(resp: T) -> Reply<T> {
Reply(ReplyItem::Message(resp)) Reply(Some(ReplyResult::Ok(resp)))
} }
} }
@ -307,7 +307,7 @@ impl<T, E: Into<Error>> From<Result<Reply<T>, E>> for Reply<T> {
fn from(res: Result<Reply<T>, E>) -> Self { fn from(res: Result<Reply<T>, E>) -> Self {
match res { match res {
Ok(val) => val, Ok(val) => val,
Err(err) => Reply(ReplyItem::Error(err.into())), Err(err) => Reply(Some(ReplyResult::Err(err.into()))),
} }
} }
} }
@ -316,8 +316,8 @@ impl<T, E: Into<Error>> From<Result<T, E>> for Reply<T> {
#[inline] #[inline]
fn from(res: Result<T, E>) -> Self { fn from(res: Result<T, E>) -> Self {
match res { match res {
Ok(val) => Reply(ReplyItem::Message(val)), Ok(val) => Reply(Some(ReplyResult::Ok(val))),
Err(err) => Reply(ReplyItem::Error(err.into())), Err(err) => Reply(Some(ReplyResult::Err(err.into()))),
} }
} }
} }
@ -328,8 +328,8 @@ impl<T, E: Into<Error>> From<Result<Box<Future<Item = T, Error = Error>>, E>>
#[inline] #[inline]
fn from(res: Result<Box<Future<Item = T, Error = Error>>, E>) -> Self { fn from(res: Result<Box<Future<Item = T, Error = Error>>, E>) -> Self {
match res { match res {
Ok(fut) => Reply(ReplyItem::Future(fut)), Ok(fut) => Reply(Some(ReplyResult::Future(fut))),
Err(err) => Reply(ReplyItem::Error(err.into())), Err(err) => Reply(Some(ReplyResult::Err(err.into()))),
} }
} }
} }
@ -337,7 +337,7 @@ impl<T, E: Into<Error>> From<Result<Box<Future<Item = T, Error = Error>>, E>>
impl<T> From<Box<Future<Item = T, Error = Error>>> for Reply<T> { impl<T> From<Box<Future<Item = T, Error = Error>>> for Reply<T> {
#[inline] #[inline]
fn from(fut: Box<Future<Item = T, Error = Error>>) -> Reply<T> { fn from(fut: Box<Future<Item = T, Error = Error>>) -> Reply<T> {
Reply(ReplyItem::Future(fut)) Reply(Some(ReplyResult::Future(fut)))
} }
} }
@ -356,8 +356,8 @@ where
fn respond_to(self, req: HttpRequest) -> Result<Reply<HttpResponse>, 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().into() {
ReplyItem::Message(resp) => ok(resp), ReplyResult::Ok(resp) => ok(resp),
_ => panic!("Nested async replies are not supported"), _ => panic!("Nested async replies are not supported"),
}, },
Err(e) => err(e), Err(e) => err(e),
@ -452,8 +452,8 @@ where
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) {
Ok(reply) => match reply.into().0 { Ok(reply) => match reply.into().into() {
ReplyItem::Message(resp) => ok(resp), ReplyResult::Ok(resp) => ok(resp),
_ => panic!("Nested async replies are not supported"), _ => panic!("Nested async replies are not supported"),
}, },
Err(e) => err(e), Err(e) => err(e),
@ -505,12 +505,12 @@ impl<S> Deref for State<S> {
} }
} }
impl<S: 'static> FromRequest<S> for State<S> { impl<S> FromRequest<S> for State<S> {
type Config = (); type Config = ();
type Result = State<S>; type Result = State<S>;
#[inline] #[inline]
fn from_request(req: &mut HttpRequest<S>, _: &Self::Config) -> Self::Result { fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
State(req.clone()).into() State(req.clone())
} }
} }

View File

@ -500,12 +500,12 @@ impl<S> Clone for HttpRequest<S> {
} }
} }
impl<S: 'static> FromRequest<S> for HttpRequest<S> { impl<S> FromRequest<S> for HttpRequest<S> {
type Config = (); type Config = ();
type Result = Self; type Result = Self;
#[inline] #[inline]
fn from_request(req: &mut HttpRequest<S>, _: &Self::Config) -> Self::Result { fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
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: &mut HttpRequest<S>, cfg: &Self::Config) -> Self::Result { fn from_request(req: &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(

View File

@ -21,7 +21,7 @@ pub use self::logger::Logger;
/// Middleware start result /// Middleware start result
pub enum Started { pub enum Started {
/// Execution completed /// Middleware is completed, continue to next middleware
Done, Done,
/// New http response got generated. If middleware generates response /// New http response got generated. If middleware generates response
/// handler execution halts. /// handler execution halts.

View File

@ -37,7 +37,7 @@
//! use actix_web::{server, App, HttpRequest, Result}; //! use actix_web::{server, App, HttpRequest, Result};
//! use actix_web::middleware::session::{RequestSession, SessionStorage, CookieSessionBackend}; //! use actix_web::middleware::session::{RequestSession, SessionStorage, CookieSessionBackend};
//! //!
//! fn index(mut req: HttpRequest) -> Result<&'static str> { //! fn index(req: HttpRequest) -> Result<&'static str> {
//! // access session data //! // access session data
//! if let Some(count) = req.session().get::<i32>("counter")? { //! if let Some(count) = req.session().get::<i32>("counter")? {
//! println!("SESSION value: {}", count); //! println!("SESSION value: {}", count);
@ -525,3 +525,30 @@ impl<S> SessionBackend<S> for CookieSessionBackend {
}) })
} }
} }
#[cfg(test)]
mod tests {
use super::*;
use application::App;
use test;
#[test]
fn cookie_session() {
let mut srv = test::TestServer::with_factory(|| {
App::new()
.middleware(SessionStorage::new(
CookieSessionBackend::signed(&[0; 32]).secure(false),
))
.resource("/", |r| {
r.f(|req| {
let _ = req.session().set("counter", 100);
"test"
})
})
});
let request = srv.get().uri(srv.url("/")).finish().unwrap();
let response = srv.execute(request.send()).unwrap();
assert!(response.cookie("actix-session").is_some());
}
}

View File

@ -11,7 +11,7 @@ use application::Inner;
use body::{Body, BodyStream}; use body::{Body, BodyStream};
use context::{ActorHttpContext, Frame}; use context::{ActorHttpContext, Frame};
use error::Error; use error::Error;
use handler::{Reply, ReplyItem}; use handler::{Reply, ReplyResult};
use header::ContentEncoding; use header::ContentEncoding;
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
@ -324,14 +324,13 @@ impl<S: 'static, H> WaitingResponse<S, H> {
info: &mut PipelineInfo<S>, reply: Reply<HttpResponse>, info: &mut PipelineInfo<S>, reply: Reply<HttpResponse>,
) -> PipelineState<S, H> { ) -> PipelineState<S, H> {
match reply.into() { match reply.into() {
ReplyItem::Error(err) => RunMiddlewares::init(info, err.into()), ReplyResult::Err(err) => RunMiddlewares::init(info, err.into()),
ReplyItem::Message(resp) => RunMiddlewares::init(info, resp), ReplyResult::Ok(resp) => RunMiddlewares::init(info, resp),
ReplyItem::Future(fut) => PipelineState::Handler(WaitingResponse { ReplyResult::Future(fut) => PipelineState::Handler(WaitingResponse {
fut, fut,
_s: PhantomData, _s: PhantomData,
_h: PhantomData, _h: PhantomData,
}), }),
ReplyItem::None => panic!("use after resolve"),
} }
} }

View File

@ -5,7 +5,7 @@ use std::rc::Rc;
use futures::{Async, Future, Poll}; use futures::{Async, Future, Poll};
use error::Error; use error::Error;
use handler::{AsyncHandler, FromRequest, Handler, Reply, ReplyItem, Responder, use handler::{AsyncHandler, FromRequest, Handler, Reply, ReplyResult, Responder,
RouteHandler, WrapHandler}; RouteHandler, WrapHandler};
use http::StatusCode; use http::StatusCode;
use httprequest::HttpRequest; use httprequest::HttpRequest;
@ -417,13 +417,12 @@ impl<S: 'static> WaitingResponse<S> {
#[inline] #[inline]
fn init(info: &mut ComposeInfo<S>, reply: Reply<HttpResponse>) -> 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()), ReplyResult::Err(err) => RunMiddlewares::init(info, err.into()),
ReplyItem::Message(resp) => RunMiddlewares::init(info, resp), ReplyResult::Ok(resp) => RunMiddlewares::init(info, resp),
ReplyItem::Future(fut) => ComposeState::Handler(WaitingResponse { ReplyResult::Future(fut) => ComposeState::Handler(WaitingResponse {
fut, fut,
_s: PhantomData, _s: PhantomData,
}), }),
ReplyItem::None => panic!("use after resolve"),
} }
} }

View File

@ -5,7 +5,7 @@ use std::rc::Rc;
use futures::{Async, Future, Poll}; use futures::{Async, Future, Poll};
use error::Error; use error::Error;
use handler::{FromRequest, Reply, ReplyItem, Responder, RouteHandler}; use handler::{FromRequest, Reply, ReplyResult, Responder, RouteHandler};
use http::Method; use http::Method;
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
@ -523,13 +523,12 @@ impl<S: 'static> WaitingResponse<S> {
#[inline] #[inline]
fn init(info: &mut ComposeInfo<S>, reply: Reply<HttpResponse>) -> 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), ReplyResult::Ok(resp) => RunMiddlewares::init(info, resp),
ReplyItem::Error(err) => RunMiddlewares::init(info, err.into()), ReplyResult::Err(err) => RunMiddlewares::init(info, err.into()),
ReplyItem::Future(fut) => ComposeState::Handler(WaitingResponse { ReplyResult::Future(fut) => ComposeState::Handler(WaitingResponse {
fut, fut,
_s: PhantomData, _s: PhantomData,
}), }),
ReplyItem::None => panic!("use after resolve"),
} }
} }

View File

@ -21,7 +21,7 @@ use application::{App, HttpApplication};
use body::Binary; use body::Binary;
use client::{ClientConnector, ClientRequest, ClientRequestBuilder}; use client::{ClientConnector, ClientRequest, ClientRequestBuilder};
use error::Error; use error::Error;
use handler::{Handler, ReplyItem, Responder}; use handler::{Handler, ReplyResult, Responder};
use header::{Header, IntoHeaderValue}; use header::{Header, IntoHeaderValue};
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
@ -601,10 +601,9 @@ 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), ReplyResult::Ok(resp) => Ok(resp),
ReplyItem::Error(err) => Ok(err.into()), ReplyResult::Err(err) => Ok(err.into()),
ReplyItem::Future(_) => panic!("Async handler is not supported."), ReplyResult::Future(_) => panic!("Async handler is not supported."),
ReplyItem::None => panic!("use after resolve"),
}, },
Err(err) => Err(err), Err(err) => Err(err),
} }
@ -628,7 +627,7 @@ impl<S> TestRequest<S> {
match core.run(fut) { match core.run(fut) {
Ok(r) => match r.respond_to(req.drop_state()) { Ok(r) => match r.respond_to(req.drop_state()) {
Ok(reply) => match reply.into().into() { Ok(reply) => match reply.into().into() {
ReplyItem::Message(resp) => Ok(resp), ReplyResult::Ok(resp) => Ok(resp),
_ => panic!("Nested async replies are not supported"), _ => panic!("Nested async replies are not supported"),
}, },
Err(e) => Err(e), Err(e) => Err(e),

View File

@ -5,7 +5,7 @@ use std::ops::{Deref, DerefMut};
use std::rc::Rc; use std::rc::Rc;
use error::Error; use error::Error;
use handler::{FromRequest, Handler, Reply, ReplyItem, Responder}; use handler::{FromRequest, Handler, Reply, ReplyResult, Responder};
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
@ -134,15 +134,14 @@ where
let item = if !self.started { let item = if !self.started {
self.started = true; self.started = true;
let reply = T::from_request(&mut self.req, self.cfg.as_ref()).into(); let reply = T::from_request(&self.req, self.cfg.as_ref()).into();
match reply.into() { match reply.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(msg) => msg, ReplyResult::Ok(msg) => msg,
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.fut1 = Some(fut); self.fut1 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
} }
} else { } else {
match self.fut1.as_mut().unwrap().poll()? { match self.fut1.as_mut().unwrap().poll()? {
@ -158,13 +157,12 @@ where
}; };
match item.into() { match item.into() {
ReplyItem::Error(err) => Err(err), ReplyResult::Err(err) => Err(err),
ReplyItem::Message(resp) => Ok(Async::Ready(resp)), ReplyResult::Ok(resp) => Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.fut2 = Some(fut); self.fut2 = Some(fut);
self.poll() self.poll()
} }
ReplyItem::None => panic!("use after resolve"),
} }
} }
} }
@ -268,39 +266,36 @@ where
if !self.started { if !self.started {
self.started = true; self.started = true;
let reply = T1::from_request(&mut self.req, self.cfg1.as_ref()).into(); let reply = T1::from_request(&self.req, self.cfg1.as_ref()).into();
let item1 = match reply.into() { let item1 = match reply.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(msg) => msg, ReplyResult::Ok(msg) => msg,
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.fut1 = Some(fut); self.fut1 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}; };
let reply = T2::from_request(&mut self.req, self.cfg2.as_ref()).into(); let reply = T2::from_request(&self.req, self.cfg2.as_ref()).into();
let item2 = match reply.into() { let item2 = match reply.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(msg) => msg, ReplyResult::Ok(msg) => msg,
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.item = Some(item1); self.item = Some(item1);
self.fut2 = Some(fut); self.fut2 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}; };
let hnd: &mut F = unsafe { &mut *self.hnd.get() }; let hnd: &mut F = unsafe { &mut *self.hnd.get() };
match (*hnd)(item1, item2).respond_to(self.req.drop_state()) { match (*hnd)(item1, item2).respond_to(self.req.drop_state()) {
Ok(item) => match item.into().into() { Ok(item) => match item.into().into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyResult::Ok(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.fut3 = Some(fut); self.fut3 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}, },
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
} }
@ -309,29 +304,26 @@ where
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 = let reply = T2::from_request(&self.req, self.cfg2.as_ref()).into();
T2::from_request(&mut self.req, self.cfg2.as_ref()).into();
let item2 = match reply.into() { let item2 = match reply.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(msg) => msg, ReplyResult::Ok(msg) => msg,
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.item = Some(item); self.item = Some(item);
self.fut2 = Some(fut); self.fut2 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}; };
let hnd: &mut F = unsafe { &mut *self.hnd.get() }; let hnd: &mut F = unsafe { &mut *self.hnd.get() };
match (*hnd)(item, item2).respond_to(self.req.drop_state()) { match (*hnd)(item, item2).respond_to(self.req.drop_state()) {
Ok(item) => match item.into().into() { Ok(item) => match item.into().into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyResult::Ok(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.fut3 = Some(fut); self.fut3 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}, },
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
} }
@ -354,10 +346,9 @@ where
}; };
match item.into() { match item.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyResult::Ok(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => self.fut3 = Some(fut), ReplyResult::Future(fut) => self.fut3 = Some(fut),
ReplyItem::None => panic!("use after resolve"),
} }
self.poll() self.poll()
@ -480,52 +471,48 @@ where
if !self.started { if !self.started {
self.started = true; self.started = true;
let reply = T1::from_request(&mut self.req, self.cfg1.as_ref()).into(); let reply = T1::from_request(&self.req, self.cfg1.as_ref()).into();
let item1 = match reply.into() { let item1 = match reply.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(msg) => msg, ReplyResult::Ok(msg) => msg,
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.fut1 = Some(fut); self.fut1 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}; };
let reply = T2::from_request(&mut self.req, self.cfg2.as_ref()).into(); let reply = T2::from_request(&self.req, self.cfg2.as_ref()).into();
let item2 = match reply.into() { let item2 = match reply.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(msg) => msg, ReplyResult::Ok(msg) => msg,
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.item1 = Some(item1); self.item1 = Some(item1);
self.fut2 = Some(fut); self.fut2 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}; };
let reply = T3::from_request(&mut self.req, self.cfg3.as_ref()).into(); let reply = T3::from_request(&self.req, self.cfg3.as_ref()).into();
let item3 = match reply.into() { let item3 = match reply.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(msg) => msg, ReplyResult::Ok(msg) => msg,
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.item1 = Some(item1); self.item1 = Some(item1);
self.item2 = Some(item2); self.item2 = Some(item2);
self.fut3 = Some(fut); self.fut3 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}; };
let hnd: &mut F = unsafe { &mut *self.hnd.get() }; let hnd: &mut F = unsafe { &mut *self.hnd.get() };
match (*hnd)(item1, item2, item3).respond_to(self.req.drop_state()) { match (*hnd)(item1, item2, item3).respond_to(self.req.drop_state()) {
Ok(item) => match item.into().into() { Ok(item) => match item.into().into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyResult::Ok(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.fut4 = Some(fut); self.fut4 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}, },
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
} }
@ -536,42 +523,37 @@ where
Async::Ready(item) => { Async::Ready(item) => {
self.item1 = Some(item); self.item1 = Some(item);
self.fut1.take(); self.fut1.take();
let reply = let reply = T2::from_request(&self.req, self.cfg2.as_ref()).into();
T2::from_request(&mut self.req, self.cfg2.as_ref()).into();
let item2 = match reply.into() { let item2 = match reply.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(msg) => msg, ReplyResult::Ok(msg) => msg,
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.fut2 = Some(fut); self.fut2 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}; };
let reply = let reply = T3::from_request(&self.req, self.cfg3.as_ref()).into();
T3::from_request(&mut self.req, self.cfg3.as_ref()).into();
let item3 = match reply.into() { let item3 = match reply.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(msg) => msg, ReplyResult::Ok(msg) => msg,
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.item2 = Some(item2); self.item2 = Some(item2);
self.fut3 = Some(fut); self.fut3 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}; };
let hnd: &mut F = unsafe { &mut *self.hnd.get() }; let hnd: &mut F = unsafe { &mut *self.hnd.get() };
match (*hnd)(self.item1.take().unwrap(), item2, item3) match (*hnd)(self.item1.take().unwrap(), item2, item3)
.respond_to(self.req.drop_state()) .respond_to(self.req.drop_state())
{ {
Ok(item) => match item.into().into() { Ok(item) => match item.into().into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyResult::Ok(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.fut4 = Some(fut); self.fut4 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}, },
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
} }
@ -584,30 +566,27 @@ where
match self.fut2.as_mut().unwrap().poll()? { match self.fut2.as_mut().unwrap().poll()? {
Async::Ready(item) => { Async::Ready(item) => {
self.fut2.take(); self.fut2.take();
let reply = let reply = T3::from_request(&self.req, self.cfg3.as_ref()).into();
T3::from_request(&mut self.req, self.cfg3.as_ref()).into();
let item3 = match reply.into() { let item3 = match reply.into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(msg) => msg, ReplyResult::Ok(msg) => msg,
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.item2 = Some(item); self.item2 = Some(item);
self.fut3 = Some(fut); self.fut3 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}; };
let hnd: &mut F = unsafe { &mut *self.hnd.get() }; let hnd: &mut F = unsafe { &mut *self.hnd.get() };
match (*hnd)(self.item1.take().unwrap(), item, item3) match (*hnd)(self.item1.take().unwrap(), item, item3)
.respond_to(self.req.drop_state()) .respond_to(self.req.drop_state())
{ {
Ok(item) => match item.into().into() { Ok(item) => match item.into().into() {
ReplyItem::Error(err) => return Err(err), ReplyResult::Err(err) => return Err(err),
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyResult::Ok(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => { ReplyResult::Future(fut) => {
self.fut4 = Some(fut); self.fut4 = Some(fut);
return self.poll(); return self.poll();
} }
ReplyItem::None => panic!("use after resolve"),
}, },
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
} }
@ -633,10 +612,9 @@ where
}; };
match item.into() { match item.into() {
ReplyItem::Error(err) => return Ok(Async::Ready(err.into())), ReplyResult::Err(err) => return Ok(Async::Ready(err.into())),
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)), ReplyResult::Ok(resp) => return Ok(Async::Ready(resp)),
ReplyItem::Future(fut) => self.fut4 = Some(fut), ReplyResult::Future(fut) => self.fut4 = Some(fut),
ReplyItem::None => panic!("use after resolve"),
} }
self.poll() self.poll()