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:
parent
02fcaca3da
commit
fbedaec661
@ -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,
|
||||||
{
|
{
|
||||||
|
@ -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))
|
||||||
|
@ -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.
|
||||||
|
@ -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)?;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
36
actix-http/src/h1/expect.rs
Normal file
36
actix-http/src/h1/expect.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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};
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
{
|
{
|
||||||
|
@ -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,
|
||||||
|
@ -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)]
|
||||||
|
@ -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 {
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user