1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-30 18:44:35 +01:00

add expect: 100-continue support #141

This commit is contained in:
Nikolay Kim 2019-04-05 16:46:44 -07:00
parent 02fcaca3da
commit fbedaec661
18 changed files with 554 additions and 156 deletions

View File

@ -1,4 +1,4 @@
use std::fmt::Debug; use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use actix_server_config::ServerConfig as SrvConfig; use actix_server_config::ServerConfig as SrvConfig;
@ -6,39 +6,52 @@ use actix_service::{IntoNewService, NewService, Service};
use crate::body::MessageBody; use crate::body::MessageBody;
use crate::config::{KeepAlive, ServiceConfig}; use crate::config::{KeepAlive, ServiceConfig};
use crate::error::Error;
use crate::h1::{ExpectHandler, H1Service};
use crate::h2::H2Service;
use crate::request::Request; use crate::request::Request;
use crate::response::Response; use crate::response::Response;
use crate::h1::H1Service;
use crate::h2::H2Service;
use crate::service::HttpService; use crate::service::HttpService;
/// A http service builder /// A http service builder
/// ///
/// This type can be used to construct an instance of `http service` through a /// This type can be used to construct an instance of `http service` through a
/// builder-like pattern. /// builder-like pattern.
pub struct HttpServiceBuilder<T, S> { pub struct HttpServiceBuilder<T, S, X = ExpectHandler> {
keep_alive: KeepAlive, keep_alive: KeepAlive,
client_timeout: u64, client_timeout: u64,
client_disconnect: u64, client_disconnect: u64,
expect: X,
_t: PhantomData<(T, S)>, _t: PhantomData<(T, S)>,
} }
impl<T, S> HttpServiceBuilder<T, S> impl<T, S> HttpServiceBuilder<T, S, ExpectHandler>
where where
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::InitError: fmt::Debug,
{ {
/// Create instance of `ServiceConfigBuilder` /// Create instance of `ServiceConfigBuilder`
pub fn new() -> HttpServiceBuilder<T, S> { pub fn new() -> Self {
HttpServiceBuilder { HttpServiceBuilder {
keep_alive: KeepAlive::Timeout(5), keep_alive: KeepAlive::Timeout(5),
client_timeout: 5000, client_timeout: 5000,
client_disconnect: 0, client_disconnect: 0,
expect: ExpectHandler,
_t: PhantomData, _t: PhantomData,
} }
} }
}
impl<T, S, X> HttpServiceBuilder<T, S, X>
where
S: NewService<SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::InitError: fmt::Debug,
X: NewService<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::InitError: fmt::Debug,
{
/// Set server keep-alive setting. /// Set server keep-alive setting.
/// ///
/// By default keep alive is set to a 5 seconds. /// By default keep alive is set to a 5 seconds.
@ -94,10 +107,12 @@ where
// } // }
/// Finish service configuration and create *http service* for HTTP/1 protocol. /// Finish service configuration and create *http service* for HTTP/1 protocol.
pub fn h1<F, P, B>(self, service: F) -> H1Service<T, P, S, B> pub fn h1<F, P, B>(self, service: F) -> H1Service<T, P, S, B, X>
where where
B: MessageBody + 'static, B: MessageBody + 'static,
F: IntoNewService<S, SrvConfig>, F: IntoNewService<S, SrvConfig>,
S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
{ {
let cfg = ServiceConfig::new( let cfg = ServiceConfig::new(
@ -105,7 +120,7 @@ where
self.client_timeout, self.client_timeout,
self.client_disconnect, self.client_disconnect,
); );
H1Service::with_config(cfg, service.into_new_service()) H1Service::with_config(cfg, service.into_new_service()).expect(self.expect)
} }
/// Finish service configuration and create *http service* for HTTP/2 protocol. /// Finish service configuration and create *http service* for HTTP/2 protocol.
@ -113,6 +128,8 @@ where
where where
B: MessageBody + 'static, B: MessageBody + 'static,
F: IntoNewService<S, SrvConfig>, F: IntoNewService<S, SrvConfig>,
S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static, <S::Service as Service>::Future: 'static,
{ {
@ -129,6 +146,8 @@ where
where where
B: MessageBody + 'static, B: MessageBody + 'static,
F: IntoNewService<S, SrvConfig>, F: IntoNewService<S, SrvConfig>,
S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static, <S::Service as Service>::Future: 'static,
{ {

View File

@ -25,9 +25,9 @@ type SslConnector = ();
/// The `Connector` type uses a builder-like combinator pattern for service /// The `Connector` type uses a builder-like combinator pattern for service
/// construction that finishes by calling the `.finish()` method. /// construction that finishes by calling the `.finish()` method.
/// ///
/// ```rust /// ```rust,ignore
/// use actix-web::client::Connector; /// use std::time::Duration;
/// use time::Duration; /// use actix_http::client::Connector;
/// ///
/// let connector = Connector::new() /// let connector = Connector::new()
/// .timeout(Duration::from_secs(5)) /// .timeout(Duration::from_secs(5))

View File

@ -71,6 +71,12 @@ impl fmt::Debug for Error {
} }
} }
impl From<()> for Error {
fn from(_: ()) -> Self {
Error::from(UnitError)
}
}
impl std::error::Error for Error { impl std::error::Error for Error {
fn description(&self) -> &str { fn description(&self) -> &str {
"actix-http::Error" "actix-http::Error"
@ -111,6 +117,13 @@ impl<E: ResponseError> ResponseError for TimeoutError<E> {
} }
} }
#[derive(Debug, Display)]
#[display(fmt = "UnknownError")]
struct UnitError;
/// `InternalServerError` for `JsonError`
impl ResponseError for UnitError {}
/// `InternalServerError` for `JsonError` /// `InternalServerError` for `JsonError`
impl ResponseError for JsonError {} impl ResponseError for JsonError {}
@ -120,6 +133,10 @@ impl ResponseError for FormError {}
/// `InternalServerError` for `TimerError` /// `InternalServerError` for `TimerError`
impl ResponseError for TimerError {} impl ResponseError for TimerError {}
#[cfg(feature = "ssl")]
/// `InternalServerError` for `SslError`
impl ResponseError for openssl::ssl::Error {}
/// Return `BAD_REQUEST` for `de::value::Error` /// Return `BAD_REQUEST` for `de::value::Error`
impl ResponseError for DeError { impl ResponseError for DeError {
fn error_response(&self) -> Response { fn error_response(&self) -> Response {
@ -331,7 +348,7 @@ impl ResponseError for crate::cookie::ParseError {
/// A set of errors that can occur during dispatching http requests /// A set of errors that can occur during dispatching http requests
pub enum DispatchError { pub enum DispatchError {
/// Service error /// Service error
Service, Service(Error),
/// An `io::Error` that occurred while trying to read or write to a network /// An `io::Error` that occurred while trying to read or write to a network
/// stream. /// stream.

View File

@ -154,6 +154,9 @@ impl Encoder for Codec {
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
match item { match item {
Message::Item((mut res, length)) => { Message::Item((mut res, length)) => {
if res.head().status == StatusCode::CONTINUE {
dst.extend_from_slice(b"HTTP/1.1 100 Continue\r\n\r\n");
} else {
// set response version // set response version
res.head_mut().version = self.version; res.head_mut().version = self.version;
@ -182,6 +185,7 @@ impl Encoder for Codec {
)?; )?;
self.headers_size = (dst.len() - len) as u32; self.headers_size = (dst.len() - len) as u32;
} }
}
Message::Chunk(Some(bytes)) => { Message::Chunk(Some(bytes)) => {
self.encoder.encode_chunk(bytes.as_ref(), dst)?; self.encoder.encode_chunk(bytes.as_ref(), dst)?;
} }

View File

@ -51,6 +51,8 @@ pub(crate) enum PayloadLength {
pub(crate) trait MessageType: Sized { pub(crate) trait MessageType: Sized {
fn set_connection_type(&mut self, ctype: Option<ConnectionType>); fn set_connection_type(&mut self, ctype: Option<ConnectionType>);
fn set_expect(&mut self);
fn headers_mut(&mut self) -> &mut HeaderMap; fn headers_mut(&mut self) -> &mut HeaderMap;
fn decode(src: &mut BytesMut) -> Result<Option<(Self, PayloadType)>, ParseError>; fn decode(src: &mut BytesMut) -> Result<Option<(Self, PayloadType)>, ParseError>;
@ -62,6 +64,7 @@ pub(crate) trait MessageType: Sized {
) -> Result<PayloadLength, ParseError> { ) -> Result<PayloadLength, ParseError> {
let mut ka = None; let mut ka = None;
let mut has_upgrade = false; let mut has_upgrade = false;
let mut expect = false;
let mut chunked = false; let mut chunked = false;
let mut content_length = None; let mut content_length = None;
@ -126,6 +129,12 @@ pub(crate) trait MessageType: Sized {
} }
} }
} }
header::EXPECT => {
let bytes = value.as_bytes();
if bytes.len() >= 4 && &bytes[0..4] == b"100-" {
expect = true;
}
}
_ => (), _ => (),
} }
@ -136,6 +145,9 @@ pub(crate) trait MessageType: Sized {
} }
} }
self.set_connection_type(ka); self.set_connection_type(ka);
if expect {
self.set_expect()
}
// https://tools.ietf.org/html/rfc7230#section-3.3.3 // https://tools.ietf.org/html/rfc7230#section-3.3.3
if chunked { if chunked {
@ -163,6 +175,10 @@ impl MessageType for Request {
} }
} }
fn set_expect(&mut self) {
self.head_mut().set_expect();
}
fn headers_mut(&mut self) -> &mut HeaderMap { fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.head_mut().headers &mut self.head_mut().headers
} }
@ -235,6 +251,8 @@ impl MessageType for ResponseHead {
} }
} }
fn set_expect(&mut self) {}
fn headers_mut(&mut self) -> &mut HeaderMap { fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.headers &mut self.headers
} }

View File

@ -1,5 +1,4 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fmt::Debug;
use std::mem; use std::mem;
use std::time::Instant; use std::time::Instant;
@ -13,8 +12,9 @@ use tokio_timer::Delay;
use crate::body::{Body, BodySize, MessageBody, ResponseBody}; use crate::body::{Body, BodySize, MessageBody, ResponseBody};
use crate::config::ServiceConfig; use crate::config::ServiceConfig;
use crate::error::DispatchError; use crate::error::{DispatchError, Error};
use crate::error::{ParseError, PayloadError}; use crate::error::{ParseError, PayloadError};
use crate::http::StatusCode;
use crate::request::Request; use crate::request::Request;
use crate::response::Response; use crate::response::Response;
@ -37,24 +37,33 @@ bitflags! {
} }
/// Dispatcher for HTTP/1.1 protocol /// Dispatcher for HTTP/1.1 protocol
pub struct Dispatcher<T, S: Service<Request = Request>, B: MessageBody> pub struct Dispatcher<T, S, B, X>
where where
S::Error: Debug, S: Service<Request = Request>,
S::Error: Into<Error>,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
inner: Option<InnerDispatcher<T, S, B>>, inner: Option<InnerDispatcher<T, S, B, X>>,
} }
struct InnerDispatcher<T, S: Service<Request = Request>, B: MessageBody> struct InnerDispatcher<T, S, B, X>
where where
S::Error: Debug, S: Service<Request = Request>,
S::Error: Into<Error>,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
service: CloneableService<S>, service: CloneableService<S>,
expect: CloneableService<X>,
flags: Flags, flags: Flags,
framed: Framed<T, Codec>, framed: Framed<T, Codec>,
error: Option<DispatchError>, error: Option<DispatchError>,
config: ServiceConfig, config: ServiceConfig,
state: State<S, B>, state: State<S, B, X>,
payload: Option<PayloadSender>, payload: Option<PayloadSender>,
messages: VecDeque<DispatcherMessage>, messages: VecDeque<DispatcherMessage>,
@ -67,13 +76,24 @@ enum DispatcherMessage {
Error(Response<()>), Error(Response<()>),
} }
enum State<S: Service<Request = Request>, B: MessageBody> { enum State<S, B, X>
where
S: Service<Request = Request>,
X: Service<Request = Request, Response = Request>,
B: MessageBody,
{
None, None,
ExpectCall(X::Future),
ServiceCall(S::Future), ServiceCall(S::Future),
SendPayload(ResponseBody<B>), SendPayload(ResponseBody<B>),
} }
impl<S: Service<Request = Request>, B: MessageBody> State<S, B> { impl<S, B, X> State<S, B, X>
where
S: Service<Request = Request>,
X: Service<Request = Request, Response = Request>,
B: MessageBody,
{
fn is_empty(&self) -> bool { fn is_empty(&self) -> bool {
if let State::None = self { if let State::None = self {
true true
@ -83,21 +103,29 @@ impl<S: Service<Request = Request>, B: MessageBody> State<S, B> {
} }
} }
impl<T, S, B> Dispatcher<T, S, B> impl<T, S, B, X> Dispatcher<T, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
/// Create http/1 dispatcher. /// Create http/1 dispatcher.
pub fn new(stream: T, config: ServiceConfig, service: CloneableService<S>) -> Self { pub fn new(
stream: T,
config: ServiceConfig,
service: CloneableService<S>,
expect: CloneableService<X>,
) -> Self {
Dispatcher::with_timeout( Dispatcher::with_timeout(
Framed::new(stream, Codec::new(config.clone())), Framed::new(stream, Codec::new(config.clone())),
config, config,
None, None,
service, service,
expect,
) )
} }
@ -107,6 +135,7 @@ where
config: ServiceConfig, config: ServiceConfig,
timeout: Option<Delay>, timeout: Option<Delay>,
service: CloneableService<S>, service: CloneableService<S>,
expect: CloneableService<X>,
) -> Self { ) -> Self {
let keepalive = config.keep_alive_enabled(); let keepalive = config.keep_alive_enabled();
let flags = if keepalive { let flags = if keepalive {
@ -132,6 +161,7 @@ where
error: None, error: None,
messages: VecDeque::new(), messages: VecDeque::new(),
service, service,
expect,
flags, flags,
config, config,
ka_expire, ka_expire,
@ -141,13 +171,15 @@ where
} }
} }
impl<T, S, B> InnerDispatcher<T, S, B> impl<T, S, B, X> InnerDispatcher<T, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
fn can_read(&self) -> bool { fn can_read(&self) -> bool {
if self.flags.contains(Flags::DISCONNECTED) { if self.flags.contains(Flags::DISCONNECTED) {
@ -195,7 +227,7 @@ where
&mut self, &mut self,
message: Response<()>, message: Response<()>,
body: ResponseBody<B>, body: ResponseBody<B>,
) -> Result<State<S, B>, DispatchError> { ) -> Result<State<S, B, X>, DispatchError> {
self.framed self.framed
.force_send(Message::Item((message, body.length()))) .force_send(Message::Item((message, body.length())))
.map_err(|err| { .map_err(|err| {
@ -213,6 +245,15 @@ where
} }
} }
fn send_continue(&mut self) -> Result<(), DispatchError> {
self.framed
.force_send(Message::Item((
Response::empty(StatusCode::CONTINUE),
BodySize::Empty,
)))
.map_err(|err| DispatchError::Io(err))
}
fn poll_response(&mut self) -> Result<(), DispatchError> { fn poll_response(&mut self) -> Result<(), DispatchError> {
let mut retry = self.can_read(); let mut retry = self.can_read();
loop { loop {
@ -227,6 +268,22 @@ where
} }
None => None, None => None,
}, },
State::ExpectCall(mut fut) => match fut.poll() {
Ok(Async::Ready(req)) => {
self.send_continue()?;
Some(State::ServiceCall(self.service.call(req)))
}
Ok(Async::NotReady) => {
self.state = State::ExpectCall(fut);
None
}
Err(e) => {
let e = e.into();
let res: Response = e.into();
let (res, body) = res.replace_body(());
Some(self.send_response(res, body.into_body())?)
}
},
State::ServiceCall(mut fut) => match fut.poll() { State::ServiceCall(mut fut) => match fut.poll() {
Ok(Async::Ready(res)) => { Ok(Async::Ready(res)) => {
let (res, body) = res.into().replace_body(()); let (res, body) = res.into().replace_body(());
@ -289,7 +346,28 @@ where
Ok(()) Ok(())
} }
fn handle_request(&mut self, req: Request) -> Result<State<S, B>, DispatchError> { fn handle_request(&mut self, req: Request) -> Result<State<S, B, X>, DispatchError> {
// Handle `EXPECT: 100-Continue` header
let req = if req.head().expect() {
let mut task = self.expect.call(req);
match task.poll() {
Ok(Async::Ready(req)) => {
self.send_continue()?;
req
}
Ok(Async::NotReady) => return Ok(State::ExpectCall(task)),
Err(e) => {
let e = e.into();
let res: Response = e.into();
let (res, body) = res.replace_body(());
return self.send_response(res, body.into_body());
}
}
} else {
req
};
// Call service
let mut task = self.service.call(req); let mut task = self.service.call(req);
match task.poll() { match task.poll() {
Ok(Async::Ready(res)) => { Ok(Async::Ready(res)) => {
@ -329,10 +407,6 @@ where
req = req1; req = req1;
self.payload = Some(ps); self.payload = Some(ps);
} }
//MessageType::Stream => {
// self.unhandled = Some(req);
// return Ok(updated);
//}
_ => (), _ => (),
} }
@ -482,13 +556,15 @@ where
} }
} }
impl<T, S, B> Future for Dispatcher<T, S, B> impl<T, S, B, X> Future for Dispatcher<T, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
type Item = (); type Item = ();
type Error = DispatchError; type Error = DispatchError;
@ -558,6 +634,7 @@ mod tests {
use super::*; use super::*;
use crate::error::Error; use crate::error::Error;
use crate::h1::ExpectHandler;
struct Buffer { struct Buffer {
buf: Bytes, buf: Bytes,
@ -620,6 +697,7 @@ mod tests {
CloneableService::new( CloneableService::new(
(|_| ok::<_, Error>(Response::Ok().finish())).into_service(), (|_| ok::<_, Error>(Response::Ok().finish())).into_service(),
), ),
CloneableService::new(ExpectHandler),
); );
assert!(h1.poll().is_ok()); assert!(h1.poll().is_ok());
assert!(h1.poll().is_ok()); assert!(h1.poll().is_ok());

View File

@ -0,0 +1,36 @@
use actix_service::{NewService, Service};
use futures::future::{ok, FutureResult};
use futures::{Async, Poll};
use crate::error::Error;
use crate::request::Request;
pub struct ExpectHandler;
impl NewService for ExpectHandler {
type Request = Request;
type Response = Request;
type Error = Error;
type Service = ExpectHandler;
type InitError = Error;
type Future = FutureResult<Self::Service, Self::InitError>;
fn new_service(&self, _: &()) -> Self::Future {
ok(ExpectHandler)
}
}
impl Service for ExpectHandler {
type Request = Request;
type Response = Request;
type Error = Error;
type Future = FutureResult<Self::Response, Self::Error>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
Ok(Async::Ready(()))
}
fn call(&mut self, req: Request) -> Self::Future {
ok(req)
}
}

View File

@ -6,12 +6,14 @@ mod codec;
mod decoder; mod decoder;
mod dispatcher; mod dispatcher;
mod encoder; mod encoder;
mod expect;
mod payload; mod payload;
mod service; mod service;
pub use self::client::{ClientCodec, ClientPayloadCodec}; pub use self::client::{ClientCodec, ClientPayloadCodec};
pub use self::codec::Codec; pub use self::codec::Codec;
pub use self::dispatcher::Dispatcher; pub use self::dispatcher::Dispatcher;
pub use self::expect::ExpectHandler;
pub use self::payload::{Payload, PayloadWriter}; pub use self::payload::{Payload, PayloadWriter};
pub use self::service::{H1Service, H1ServiceHandler, OneRequest}; pub use self::service::{H1Service, H1ServiceHandler, OneRequest};

View File

@ -1,4 +1,4 @@
use std::fmt::Debug; use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_codec::{AsyncRead, AsyncWrite, Framed};
@ -10,25 +10,27 @@ use futures::{try_ready, Async, Future, IntoFuture, Poll, Stream};
use crate::body::MessageBody; use crate::body::MessageBody;
use crate::config::{KeepAlive, ServiceConfig}; use crate::config::{KeepAlive, ServiceConfig};
use crate::error::{DispatchError, ParseError}; use crate::error::{DispatchError, Error, ParseError};
use crate::request::Request; use crate::request::Request;
use crate::response::Response; use crate::response::Response;
use super::codec::Codec; use super::codec::Codec;
use super::dispatcher::Dispatcher; use super::dispatcher::Dispatcher;
use super::Message; use super::{ExpectHandler, Message};
/// `NewService` implementation for HTTP1 transport /// `NewService` implementation for HTTP1 transport
pub struct H1Service<T, P, S, B> { pub struct H1Service<T, P, S, B, X = ExpectHandler> {
srv: S, srv: S,
cfg: ServiceConfig, cfg: ServiceConfig,
expect: X,
_t: PhantomData<(T, P, B)>, _t: PhantomData<(T, P, B)>,
} }
impl<T, P, S, B> H1Service<T, P, S, B> impl<T, P, S, B> H1Service<T, P, S, B>
where where
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody, B: MessageBody,
{ {
@ -39,6 +41,7 @@ where
H1Service { H1Service {
cfg, cfg,
srv: service.into_new_service(), srv: service.into_new_service(),
expect: ExpectHandler,
_t: PhantomData, _t: PhantomData,
} }
} }
@ -51,29 +54,59 @@ where
H1Service { H1Service {
cfg, cfg,
srv: service.into_new_service(), srv: service.into_new_service(),
expect: ExpectHandler,
_t: PhantomData, _t: PhantomData,
} }
} }
} }
impl<T, P, S, B> NewService<SrvConfig> for H1Service<T, P, S, B> impl<T, P, S, B, X> H1Service<T, P, S, B, X>
where
S: NewService<SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
S::InitError: fmt::Debug,
B: MessageBody,
{
pub fn expect<U>(self, expect: U) -> H1Service<T, P, S, B, U>
where
U: NewService<Request = Request, Response = Request>,
U::Error: Into<Error>,
U::InitError: fmt::Debug,
{
H1Service {
expect,
cfg: self.cfg,
srv: self.srv,
_t: PhantomData,
}
}
}
impl<T, P, S, B, X> NewService<SrvConfig> for H1Service<T, P, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::InitError: fmt::Debug,
B: MessageBody, B: MessageBody,
X: NewService<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::InitError: fmt::Debug,
{ {
type Request = Io<T, P>; type Request = Io<T, P>;
type Response = (); type Response = ();
type Error = DispatchError; type Error = DispatchError;
type InitError = S::InitError; type InitError = ();
type Service = H1ServiceHandler<T, P, S::Service, B>; type Service = H1ServiceHandler<T, P, S::Service, B, X::Service>;
type Future = H1ServiceResponse<T, P, S, B>; type Future = H1ServiceResponse<T, P, S, B, X>;
fn new_service(&self, cfg: &SrvConfig) -> Self::Future { fn new_service(&self, cfg: &SrvConfig) -> Self::Future {
H1ServiceResponse { H1ServiceResponse {
fut: self.srv.new_service(cfg).into_future(), fut: self.srv.new_service(cfg).into_future(),
fut_ex: Some(self.expect.new_service(&())),
expect: None,
cfg: Some(self.cfg.clone()), cfg: Some(self.cfg.clone()),
_t: PhantomData, _t: PhantomData,
} }
@ -81,77 +114,136 @@ where
} }
#[doc(hidden)] #[doc(hidden)]
pub struct H1ServiceResponse<T, P, S: NewService<SrvConfig, Request = Request>, B> { pub struct H1ServiceResponse<T, P, S, B, X>
fut: <S::Future as IntoFuture>::Future, where
S: NewService<SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::InitError: fmt::Debug,
X: NewService<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::InitError: fmt::Debug,
{
fut: S::Future,
fut_ex: Option<X::Future>,
expect: Option<X::Service>,
cfg: Option<ServiceConfig>, cfg: Option<ServiceConfig>,
_t: PhantomData<(T, P, B)>, _t: PhantomData<(T, P, B)>,
} }
impl<T, P, S, B> Future for H1ServiceResponse<T, P, S, B> impl<T, P, S, B, X> Future for H1ServiceResponse<T, P, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::InitError: fmt::Debug,
B: MessageBody, B: MessageBody,
X: NewService<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::InitError: fmt::Debug,
{ {
type Item = H1ServiceHandler<T, P, S::Service, B>; type Item = H1ServiceHandler<T, P, S::Service, B, X::Service>;
type Error = S::InitError; type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let service = try_ready!(self.fut.poll()); if let Some(ref mut fut) = self.fut_ex {
let expect = try_ready!(fut
.poll()
.map_err(|e| log::error!("Init http service error: {:?}", e)));
self.expect = Some(expect);
self.fut_ex.take();
}
let service = try_ready!(self
.fut
.poll()
.map_err(|e| log::error!("Init http service error: {:?}", e)));
Ok(Async::Ready(H1ServiceHandler::new( Ok(Async::Ready(H1ServiceHandler::new(
self.cfg.take().unwrap(), self.cfg.take().unwrap(),
service, service,
self.expect.take().unwrap(),
))) )))
} }
} }
/// `Service` implementation for HTTP1 transport /// `Service` implementation for HTTP1 transport
pub struct H1ServiceHandler<T, P, S, B> { pub struct H1ServiceHandler<T, P, S, B, X> {
srv: CloneableService<S>, srv: CloneableService<S>,
expect: CloneableService<X>,
cfg: ServiceConfig, cfg: ServiceConfig,
_t: PhantomData<(T, P, B)>, _t: PhantomData<(T, P, B)>,
} }
impl<T, P, S, B> H1ServiceHandler<T, P, S, B> impl<T, P, S, B, X> H1ServiceHandler<T, P, S, B, X>
where where
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
fn new(cfg: ServiceConfig, srv: S) -> H1ServiceHandler<T, P, S, B> { fn new(cfg: ServiceConfig, srv: S, expect: X) -> H1ServiceHandler<T, P, S, B, X> {
H1ServiceHandler { H1ServiceHandler {
srv: CloneableService::new(srv), srv: CloneableService::new(srv),
expect: CloneableService::new(expect),
cfg, cfg,
_t: PhantomData, _t: PhantomData,
} }
} }
} }
impl<T, P, S, B> Service for H1ServiceHandler<T, P, S, B> impl<T, P, S, B, X> Service for H1ServiceHandler<T, P, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
type Request = Io<T, P>; type Request = Io<T, P>;
type Response = (); type Response = ();
type Error = DispatchError; type Error = DispatchError;
type Future = Dispatcher<T, S, B>; type Future = Dispatcher<T, S, B, X>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.srv.poll_ready().map_err(|e| { let ready = self
.expect
.poll_ready()
.map_err(|e| {
let e = e.into();
log::error!("Http service readiness error: {:?}", e); log::error!("Http service readiness error: {:?}", e);
DispatchError::Service DispatchError::Service(e)
}) })?
.is_ready();
let ready = self
.srv
.poll_ready()
.map_err(|e| {
let e = e.into();
log::error!("Http service readiness error: {:?}", e);
DispatchError::Service(e)
})?
.is_ready()
&& ready;
if ready {
Ok(Async::Ready(()))
} else {
Ok(Async::NotReady)
}
} }
fn call(&mut self, req: Self::Request) -> Self::Future { fn call(&mut self, req: Self::Request) -> Self::Future {
Dispatcher::new(req.into_parts().0, self.cfg.clone(), self.srv.clone()) Dispatcher::new(
req.into_parts().0,
self.cfg.clone(),
self.srv.clone(),
self.expect.clone(),
)
} }
} }

View File

@ -46,7 +46,7 @@ impl<T, S, B> Dispatcher<T, S, B>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: fmt::Debug, S::Error: Into<Error>,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -88,7 +88,7 @@ impl<T, S, B> Future for Dispatcher<T, S, B>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: fmt::Debug, S::Error: Into<Error>,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -146,7 +146,7 @@ enum ServiceResponseState<F, B> {
impl<F, B> ServiceResponse<F, B> impl<F, B> ServiceResponse<F, B>
where where
F: Future, F: Future,
F::Error: fmt::Debug, F::Error: Into<Error>,
F::Item: Into<Response<B>>, F::Item: Into<Response<B>>,
B: MessageBody + 'static, B: MessageBody + 'static,
{ {
@ -214,7 +214,7 @@ where
impl<F, B> Future for ServiceResponse<F, B> impl<F, B> Future for ServiceResponse<F, B>
where where
F: Future, F: Future,
F::Error: fmt::Debug, F::Error: Into<Error>,
F::Item: Into<Response<B>>, F::Item: Into<Response<B>>,
B: MessageBody + 'static, B: MessageBody + 'static,
{ {

View File

@ -32,7 +32,7 @@ pub struct H2Service<T, P, S, B> {
impl<T, P, S, B> H2Service<T, P, S, B> impl<T, P, S, B> H2Service<T, P, S, B>
where where
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static, <S::Service as Service>::Future: 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -65,7 +65,7 @@ impl<T, P, S, B> NewService<SrvConfig> for H2Service<T, P, S, B>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static, <S::Service as Service>::Future: 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -97,7 +97,7 @@ impl<T, P, S, B> Future for H2ServiceResponse<T, P, S, B>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static, <S::Service as Service>::Future: 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -124,7 +124,7 @@ pub struct H2ServiceHandler<T, P, S, B> {
impl<T, P, S, B> H2ServiceHandler<T, P, S, B> impl<T, P, S, B> H2ServiceHandler<T, P, S, B>
where where
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -142,7 +142,7 @@ impl<T, P, S, B> Service for H2ServiceHandler<T, P, S, B>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -154,8 +154,9 @@ where
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.srv.poll_ready().map_err(|e| { self.srv.poll_ready().map_err(|e| {
let e = e.into();
error!("Service readiness error: {:?}", e); error!("Service readiness error: {:?}", e);
DispatchError::Service DispatchError::Service(e)
}) })
} }
@ -186,7 +187,7 @@ pub struct H2ServiceHandlerResponse<T, S, B>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -198,7 +199,7 @@ impl<T, S, B> Future for H2ServiceHandlerResponse<T, S, B>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody, B: MessageBody,

View File

@ -23,7 +23,8 @@ bitflags! {
const CLOSE = 0b0000_0001; const CLOSE = 0b0000_0001;
const KEEP_ALIVE = 0b0000_0010; const KEEP_ALIVE = 0b0000_0010;
const UPGRADE = 0b0000_0100; const UPGRADE = 0b0000_0100;
const NO_CHUNKING = 0b0000_1000; const EXPECT = 0b0000_1000;
const NO_CHUNKING = 0b0001_0000;
} }
} }
@ -145,6 +146,17 @@ impl RequestHead {
self.flags.remove(Flags::NO_CHUNKING); self.flags.remove(Flags::NO_CHUNKING);
} }
} }
#[inline]
/// Request contains `EXPECT` header
pub fn expect(&self) -> bool {
self.flags.contains(Flags::EXPECT)
}
#[inline]
pub(crate) fn set_expect(&mut self) {
self.flags.insert(Flags::EXPECT);
}
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -51,6 +51,18 @@ impl Response<Body> {
} }
} }
#[inline]
pub(crate) fn empty(status: StatusCode) -> Response<()> {
let mut head: Message<ResponseHead> = Message::new();
head.status = status;
Response {
head,
body: ResponseBody::Body(()),
error: None,
}
}
/// Constructs an error response /// Constructs an error response
#[inline] #[inline]
pub fn from_error(error: Error) -> Response { pub fn from_error(error: Error) -> Response {

View File

@ -1,4 +1,3 @@
use std::fmt::Debug;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::{fmt, io}; use std::{fmt, io};
@ -9,27 +8,28 @@ use actix_utils::cloneable::CloneableService;
use bytes::{Buf, BufMut, Bytes, BytesMut}; use bytes::{Buf, BufMut, Bytes, BytesMut};
use futures::{try_ready, Async, Future, IntoFuture, Poll}; use futures::{try_ready, Async, Future, IntoFuture, Poll};
use h2::server::{self, Handshake}; use h2::server::{self, Handshake};
use log::error;
use crate::body::MessageBody; use crate::body::MessageBody;
use crate::builder::HttpServiceBuilder; use crate::builder::HttpServiceBuilder;
use crate::config::{KeepAlive, ServiceConfig}; use crate::config::{KeepAlive, ServiceConfig};
use crate::error::DispatchError; use crate::error::{DispatchError, Error};
use crate::request::Request; use crate::request::Request;
use crate::response::Response; use crate::response::Response;
use crate::{h1, h2::Dispatcher}; use crate::{h1, h2::Dispatcher};
/// `NewService` HTTP1.1/HTTP2 transport implementation /// `NewService` HTTP1.1/HTTP2 transport implementation
pub struct HttpService<T, P, S, B> { pub struct HttpService<T, P, S, B, X = h1::ExpectHandler> {
srv: S, srv: S,
cfg: ServiceConfig, cfg: ServiceConfig,
expect: X,
_t: PhantomData<(T, P, B)>, _t: PhantomData<(T, P, B)>,
} }
impl<T, S, B> HttpService<T, (), S, B> impl<T, S, B> HttpService<T, (), S, B>
where where
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static, <S::Service as Service>::Future: 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -43,7 +43,8 @@ where
impl<T, P, S, B> HttpService<T, P, S, B> impl<T, P, S, B> HttpService<T, P, S, B>
where where
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static, <S::Service as Service>::Future: 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -55,6 +56,7 @@ where
HttpService { HttpService {
cfg, cfg,
srv: service.into_new_service(), srv: service.into_new_service(),
expect: h1::ExpectHandler,
_t: PhantomData, _t: PhantomData,
} }
} }
@ -67,30 +69,65 @@ where
HttpService { HttpService {
cfg, cfg,
srv: service.into_new_service(), srv: service.into_new_service(),
expect: h1::ExpectHandler,
_t: PhantomData, _t: PhantomData,
} }
} }
} }
impl<T, P, S, B> NewService<SrvConfig> for HttpService<T, P, S, B> impl<T, P, S, B, X> HttpService<T, P, S, B, X>
where
S: NewService<SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>,
B: MessageBody,
{
/// Provide service for `EXPECT: 100-Continue` support.
///
/// Service get called with request that contains `EXPECT` header.
/// Service must return request in case of success, in that case
/// request will be forwarded to main service.
pub fn expect<U>(self, expect: U) -> HttpService<T, P, S, B, U>
where
U: NewService<Request = Request, Response = Request>,
U::Error: Into<Error>,
U::InitError: fmt::Debug,
{
HttpService {
expect,
cfg: self.cfg,
srv: self.srv,
_t: PhantomData,
}
}
}
impl<T, P, S, B, X> NewService<SrvConfig> for HttpService<T, P, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static, <S::Service as Service>::Future: 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
X: NewService<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::InitError: fmt::Debug,
{ {
type Request = ServerIo<T, P>; type Request = ServerIo<T, P>;
type Response = (); type Response = ();
type Error = DispatchError; type Error = DispatchError;
type InitError = S::InitError; type InitError = ();
type Service = HttpServiceHandler<T, P, S::Service, B>; type Service = HttpServiceHandler<T, P, S::Service, B, X::Service>;
type Future = HttpServiceResponse<T, P, S, B>; type Future = HttpServiceResponse<T, P, S, B, X>;
fn new_service(&self, cfg: &SrvConfig) -> Self::Future { fn new_service(&self, cfg: &SrvConfig) -> Self::Future {
HttpServiceResponse { HttpServiceResponse {
fut: self.srv.new_service(cfg).into_future(), fut: self.srv.new_service(cfg).into_future(),
fut_ex: Some(self.expect.new_service(&())),
expect: None,
cfg: Some(self.cfg.clone()), cfg: Some(self.cfg.clone()),
_t: PhantomData, _t: PhantomData,
} }
@ -98,76 +135,122 @@ where
} }
#[doc(hidden)] #[doc(hidden)]
pub struct HttpServiceResponse<T, P, S: NewService<SrvConfig>, B> { pub struct HttpServiceResponse<T, P, S: NewService<SrvConfig>, B, X: NewService> {
fut: <S::Future as IntoFuture>::Future, fut: S::Future,
fut_ex: Option<X::Future>,
expect: Option<X::Service>,
cfg: Option<ServiceConfig>, cfg: Option<ServiceConfig>,
_t: PhantomData<(T, P, B)>, _t: PhantomData<(T, P, B)>,
} }
impl<T, P, S, B> Future for HttpServiceResponse<T, P, S, B> impl<T, P, S, B, X> Future for HttpServiceResponse<T, P, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: NewService<SrvConfig, Request = Request>, S: NewService<SrvConfig, Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static, <S::Service as Service>::Future: 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
X: NewService<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::InitError: fmt::Debug,
{ {
type Item = HttpServiceHandler<T, P, S::Service, B>; type Item = HttpServiceHandler<T, P, S::Service, B, X::Service>;
type Error = S::InitError; type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> { fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let service = try_ready!(self.fut.poll()); if let Some(ref mut fut) = self.fut_ex {
let expect = try_ready!(fut
.poll()
.map_err(|e| log::error!("Init http service error: {:?}", e)));
self.expect = Some(expect);
self.fut_ex.take();
}
let service = try_ready!(self
.fut
.poll()
.map_err(|e| log::error!("Init http service error: {:?}", e)));
Ok(Async::Ready(HttpServiceHandler::new( Ok(Async::Ready(HttpServiceHandler::new(
self.cfg.take().unwrap(), self.cfg.take().unwrap(),
service, service,
self.expect.take().unwrap(),
))) )))
} }
} }
/// `Service` implementation for http transport /// `Service` implementation for http transport
pub struct HttpServiceHandler<T, P, S, B> { pub struct HttpServiceHandler<T, P, S, B, X> {
srv: CloneableService<S>, srv: CloneableService<S>,
expect: CloneableService<X>,
cfg: ServiceConfig, cfg: ServiceConfig,
_t: PhantomData<(T, P, B)>, _t: PhantomData<(T, P, B, X)>,
} }
impl<T, P, S, B> HttpServiceHandler<T, P, S, B> impl<T, P, S, B, X> HttpServiceHandler<T, P, S, B, X>
where where
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody + 'static, B: MessageBody + 'static,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
fn new(cfg: ServiceConfig, srv: S) -> HttpServiceHandler<T, P, S, B> { fn new(cfg: ServiceConfig, srv: S, expect: X) -> HttpServiceHandler<T, P, S, B, X> {
HttpServiceHandler { HttpServiceHandler {
cfg, cfg,
srv: CloneableService::new(srv), srv: CloneableService::new(srv),
expect: CloneableService::new(expect),
_t: PhantomData, _t: PhantomData,
} }
} }
} }
impl<T, P, S, B> Service for HttpServiceHandler<T, P, S, B> impl<T, P, S, B, X> Service for HttpServiceHandler<T, P, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody + 'static, B: MessageBody + 'static,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
type Request = ServerIo<T, P>; type Request = ServerIo<T, P>;
type Response = (); type Response = ();
type Error = DispatchError; type Error = DispatchError;
type Future = HttpServiceHandlerResponse<T, S, B>; type Future = HttpServiceHandlerResponse<T, S, B, X>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> { fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.srv.poll_ready().map_err(|e| { let ready = self
error!("Service readiness error: {:?}", e); .expect
DispatchError::Service .poll_ready()
}) .map_err(|e| {
let e = e.into();
log::error!("Http service readiness error: {:?}", e);
DispatchError::Service(e)
})?
.is_ready();
let ready = self
.srv
.poll_ready()
.map_err(|e| {
let e = e.into();
log::error!("Http service readiness error: {:?}", e);
DispatchError::Service(e)
})?
.is_ready()
&& ready;
if ready {
Ok(Async::Ready(()))
} else {
Ok(Async::NotReady)
}
} }
fn call(&mut self, req: Self::Request) -> Self::Future { fn call(&mut self, req: Self::Request) -> Self::Future {
@ -191,6 +274,7 @@ where
io, io,
self.cfg.clone(), self.cfg.clone(),
self.srv.clone(), self.srv.clone(),
self.expect.clone(),
)), )),
}, },
_ => HttpServiceHandlerResponse { _ => HttpServiceHandlerResponse {
@ -199,46 +283,63 @@ where
BytesMut::with_capacity(14), BytesMut::with_capacity(14),
self.cfg.clone(), self.cfg.clone(),
self.srv.clone(), self.srv.clone(),
self.expect.clone(),
))), ))),
}, },
} }
} }
} }
enum State<T, S: Service<Request = Request>, B: MessageBody> enum State<T, S, B, X>
where where
S: Service<Request = Request>,
S::Future: 'static, S::Future: 'static,
S::Error: fmt::Debug, S::Error: Into<Error>,
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
H1(h1::Dispatcher<T, S, B>), H1(h1::Dispatcher<T, S, B, X>),
H2(Dispatcher<Io<T>, S, B>), H2(Dispatcher<Io<T>, S, B>),
Unknown(Option<(T, BytesMut, ServiceConfig, CloneableService<S>)>), Unknown(
Option<(
T,
BytesMut,
ServiceConfig,
CloneableService<S>,
CloneableService<X>,
)>,
),
Handshake(Option<(Handshake<Io<T>, Bytes>, ServiceConfig, CloneableService<S>)>), Handshake(Option<(Handshake<Io<T>, Bytes>, ServiceConfig, CloneableService<S>)>),
} }
pub struct HttpServiceHandlerResponse<T, S, B> pub struct HttpServiceHandlerResponse<T, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody + 'static, B: MessageBody + 'static,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
state: State<T, S, B>, state: State<T, S, B, X>,
} }
const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0"; const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0";
impl<T, S, B> Future for HttpServiceHandlerResponse<T, S, B> impl<T, S, B, X> Future for HttpServiceHandlerResponse<T, S, B, X>
where where
T: AsyncRead + AsyncWrite, T: AsyncRead + AsyncWrite,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Debug, S::Error: Into<Error>,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
{ {
type Item = (); type Item = ();
type Error = DispatchError; type Error = DispatchError;
@ -265,7 +366,7 @@ where
} else { } else {
panic!() panic!()
} }
let (io, buf, cfg, srv) = data.take().unwrap(); let (io, buf, cfg, srv, expect) = data.take().unwrap();
if buf[..14] == HTTP2_PREFACE[..] { if buf[..14] == HTTP2_PREFACE[..] {
let io = Io { let io = Io {
inner: io, inner: io,
@ -279,8 +380,9 @@ where
h1::Codec::new(cfg.clone()), h1::Codec::new(cfg.clone()),
buf, buf,
)); ));
self.state = self.state = State::H1(h1::Dispatcher::with_timeout(
State::H1(h1::Dispatcher::with_timeout(framed, cfg, None, srv)) framed, cfg, None, srv, expect,
))
} }
self.poll() self.poll()
} }

View File

@ -61,7 +61,9 @@ fn test_connection_close() {
.finish(|_| ok::<_, ()>(Response::Ok().body(STR))) .finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map(|_| ()) .map(|_| ())
}); });
println!("REQ: {:?}", srv.get("/").force_close());
let response = srv.block_on(srv.get("/").force_close().send()).unwrap(); let response = srv.block_on(srv.get("/").force_close().send()).unwrap();
println!("RES: {:?}", response);
assert!(response.status().is_success()); assert!(response.status().is_success());
} }

View File

@ -2,7 +2,7 @@ use std::marker::PhantomData;
use std::sync::Arc; use std::sync::Arc;
use std::{fmt, io, net}; use std::{fmt, io, net};
use actix_http::{body::MessageBody, HttpService, KeepAlive, Request, Response}; use actix_http::{body::MessageBody, Error, HttpService, KeepAlive, Request, Response};
use actix_rt::System; use actix_rt::System;
use actix_server::{Server, ServerBuilder}; use actix_server::{Server, ServerBuilder};
use actix_server_config::ServerConfig; use actix_server_config::ServerConfig;
@ -53,7 +53,8 @@ where
F: Fn() -> I + Send + Clone + 'static, F: Fn() -> I + Send + Clone + 'static,
I: IntoNewService<S, ServerConfig>, I: IntoNewService<S, ServerConfig>,
S: NewService<ServerConfig, Request = Request>, S: NewService<ServerConfig, Request = Request>,
S::Error: fmt::Debug, S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::Service: 'static, S::Service: 'static,
B: MessageBody, B: MessageBody,
@ -72,7 +73,8 @@ where
F: Fn() -> I + Send + Clone + 'static, F: Fn() -> I + Send + Clone + 'static,
I: IntoNewService<S, ServerConfig>, I: IntoNewService<S, ServerConfig>,
S: NewService<ServerConfig, Request = Request>, S: NewService<ServerConfig, Request = Request>,
S::Error: fmt::Debug + 'static, S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::Service: 'static, S::Service: 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
@ -442,7 +444,8 @@ where
F: Fn() -> I + Send + Clone + 'static, F: Fn() -> I + Send + Clone + 'static,
I: IntoNewService<S, ServerConfig>, I: IntoNewService<S, ServerConfig>,
S: NewService<ServerConfig, Request = Request>, S: NewService<ServerConfig, Request = Request>,
S::Error: fmt::Debug, S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::Service: 'static, S::Service: 'static,
B: MessageBody, B: MessageBody,

View File

@ -90,13 +90,13 @@ impl TestServer {
Connector::new() Connector::new()
.timeout(time::Duration::from_millis(500)) .timeout(time::Duration::from_millis(500))
.ssl(builder.build()) .ssl(builder.build())
.service() .finish()
} }
#[cfg(not(feature = "ssl"))] #[cfg(not(feature = "ssl"))]
{ {
Connector::new() Connector::new()
.timeout(time::Duration::from_millis(500)) .timeout(time::Duration::from_millis(500))
.service() .finish()
} }
}; };

View File

@ -61,7 +61,7 @@ fn test_start() {
.connector( .connector(
client::Connector::new() client::Connector::new()
.timeout(Duration::from_millis(100)) .timeout(Duration::from_millis(100))
.service(), .finish(),
) )
.finish(), .finish(),
) )
@ -136,7 +136,7 @@ fn test_start_ssl() {
awc::Connector::new() awc::Connector::new()
.ssl(builder.build()) .ssl(builder.build())
.timeout(Duration::from_millis(100)) .timeout(Duration::from_millis(100))
.service(), .finish(),
) )
.finish(), .finish(),
) )