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_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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,20 +1,20 @@
//! HTTP Request message related code.
#![cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ptr))]
use bytes::Bytes;
use cookie::Cookie;
use failure;
use futures::future::{result, FutureResult};
use futures::{Async, Poll, Stream};
use futures_cpupool::CpuPool;
use http::{header, Extensions, HeaderMap, Method, StatusCode, Uri, Version};
use std::net::SocketAddr;
use std::rc::Rc;
use std::{cmp, fmt, io, mem, str};
use bytes::Bytes;
use cookie::Cookie;
use failure;
use futures::{Async, Poll, Stream};
use futures_cpupool::CpuPool;
use http::{header, Extensions, HeaderMap, Method, StatusCode, Uri, Version};
use tokio_io::AsyncRead;
use url::{form_urlencoded, Url};
use body::Body;
use error::{CookieParseError, Error, PayloadError, UrlGenerationError};
use error::{CookieParseError, PayloadError, UrlGenerationError};
use handler::FromRequest;
use httpmessage::HttpMessage;
use httpresponse::{HttpResponse, HttpResponseBuilder};
@ -502,11 +502,11 @@ impl<S> Clone for HttpRequest<S> {
impl<S: 'static> FromRequest<S> for HttpRequest<S> {
type Config = ();
type Result = FutureResult<Self, Error>;
type Result = Self;
#[inline]
fn from_request(req: &HttpRequest<S>, _: &Self::Config) -> Self::Result {
result(Ok(req.clone()))
fn from_request(req: &mut HttpRequest<S>, _: &Self::Config) -> Self::Result {
req.clone()
}
}

View File

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

View File

@ -28,7 +28,8 @@ pub(crate) enum HandlerType {
pub(crate) trait PipelineHandler<S> {
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>);
@ -319,8 +320,11 @@ struct WaitingResponse<S, H> {
impl<S: 'static, H> WaitingResponse<S, H> {
#[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() {
ReplyItem::Error(err) => RunMiddlewares::init(info, err.into()),
ReplyItem::Message(resp) => RunMiddlewares::init(info, resp),
ReplyItem::Future(fut) => PipelineState::Handler(WaitingResponse {
fut,

View File

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

View File

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

View File

@ -274,7 +274,7 @@ impl<S: 'static> 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 = if path == "" { "/" } else { path };
@ -346,7 +346,7 @@ struct Wrapper<S: 'static> {
}
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
.handle(req.change_state(Rc::clone(&self.state)))
}
@ -521,9 +521,10 @@ struct WaitingResponse<S> {
impl<S: 'static> WaitingResponse<S> {
#[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() {
ReplyItem::Message(resp) => RunMiddlewares::init(info, resp),
ReplyItem::Error(err) => RunMiddlewares::init(info, err.into()),
ReplyItem::Future(fut) => ComposeState::Handler(WaitingResponse {
fut,
_s: PhantomData,
@ -707,7 +708,7 @@ mod tests {
let req = TestRequest::with_uri("/app/path1").finish();
let resp = app.run(req);
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
assert_eq!(resp.as_msg().status(), StatusCode::OK);
}
#[test]
@ -724,10 +725,7 @@ mod tests {
let req = TestRequest::with_uri("/app/t1/path1").finish();
let resp = app.run(req);
assert_eq!(
resp.as_response().unwrap().status(),
StatusCode::CREATED
);
assert_eq!(resp.as_msg().status(), StatusCode::CREATED);
}
#[test]
@ -742,10 +740,7 @@ mod tests {
let req = TestRequest::with_uri("/app/t1/path1").finish();
let resp = app.run(req);
assert_eq!(
resp.as_response().unwrap().status(),
StatusCode::CREATED
);
assert_eq!(resp.as_msg().status(), StatusCode::CREATED);
}
#[test]
@ -760,16 +755,10 @@ mod tests {
let req = TestRequest::with_uri("/app/path2").finish();
let resp = app.run(req);
assert_eq!(
resp.as_response().unwrap().status(),
StatusCode::BAD_REQUEST
);
assert_eq!(resp.as_msg().status(), StatusCode::BAD_REQUEST);
let req = TestRequest::with_uri("/path2").finish();
let resp = app.run(req);
assert_eq!(
resp.as_response().unwrap().status(),
StatusCode::NOT_FOUND
);
assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
}
}

View File

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

View File

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