mirror of https://github.com/fafhrd91/actix-web
merge master
This commit is contained in:
commit
f2cc57c563
|
@ -45,7 +45,7 @@ __compress = []
|
||||||
actix-service = "2.0.0"
|
actix-service = "2.0.0"
|
||||||
actix-codec = "0.4.1"
|
actix-codec = "0.4.1"
|
||||||
actix-utils = "3.0.0"
|
actix-utils = "3.0.0"
|
||||||
actix-rt = "2.2"
|
actix-rt = { version = "2.2", default-features = false }
|
||||||
|
|
||||||
ahash = "0.7"
|
ahash = "0.7"
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
|
@ -66,7 +66,6 @@ local-channel = "0.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
percent-encoding = "2.1"
|
percent-encoding = "2.1"
|
||||||
pin-project = "1.0.0"
|
|
||||||
pin-project-lite = "0.2"
|
pin-project-lite = "0.2"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
sha-1 = "0.9"
|
sha-1 = "0.9"
|
||||||
|
|
|
@ -332,31 +332,28 @@ impl From<PayloadError> for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A set of errors that can occur during dispatching HTTP requests.
|
/// A set of errors that can occur during dispatching HTTP requests.
|
||||||
#[derive(Debug, Display, Error, From)]
|
#[derive(Debug, Display, From)]
|
||||||
#[non_exhaustive]
|
|
||||||
pub enum DispatchError {
|
pub enum DispatchError {
|
||||||
/// Service error
|
/// Service error.
|
||||||
// FIXME: display and error type
|
|
||||||
#[display(fmt = "Service Error")]
|
#[display(fmt = "Service Error")]
|
||||||
Service(#[error(not(source))] Response<BoxBody>),
|
Service(Response<BoxBody>),
|
||||||
|
|
||||||
/// Body error
|
/// Body streaming error.
|
||||||
// FIXME: display and error type
|
#[display(fmt = "Body error: {}", _0)]
|
||||||
#[display(fmt = "Body Error")]
|
Body(Box<dyn StdError>),
|
||||||
Body(#[error(not(source))] Box<dyn StdError>),
|
|
||||||
|
|
||||||
/// Upgrade service error
|
/// Upgrade service error.
|
||||||
Upgrade,
|
Upgrade,
|
||||||
|
|
||||||
/// An `io::Error` that occurred while trying to read or write to a network stream.
|
/// An `io::Error` that occurred while trying to read or write to a network stream.
|
||||||
#[display(fmt = "IO error: {}", _0)]
|
#[display(fmt = "IO error: {}", _0)]
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
|
|
||||||
/// Http request parse error.
|
/// Request parse error.
|
||||||
#[display(fmt = "Parse error: {}", _0)]
|
#[display(fmt = "Request parse error: {}", _0)]
|
||||||
Parse(ParseError),
|
Parse(ParseError),
|
||||||
|
|
||||||
/// Http/2 error
|
/// HTTP/2 error.
|
||||||
#[display(fmt = "{}", _0)]
|
#[display(fmt = "{}", _0)]
|
||||||
H2(h2::Error),
|
H2(h2::Error),
|
||||||
|
|
||||||
|
@ -368,21 +365,23 @@ pub enum DispatchError {
|
||||||
#[display(fmt = "Connection shutdown timeout")]
|
#[display(fmt = "Connection shutdown timeout")]
|
||||||
DisconnectTimeout,
|
DisconnectTimeout,
|
||||||
|
|
||||||
/// Payload is not consumed
|
/// Internal error.
|
||||||
#[display(fmt = "Task is completed but request's payload is not consumed")]
|
|
||||||
PayloadIsNotConsumed,
|
|
||||||
|
|
||||||
/// Malformed request
|
|
||||||
#[display(fmt = "Malformed request")]
|
|
||||||
MalformedRequest,
|
|
||||||
|
|
||||||
/// Internal error
|
|
||||||
#[display(fmt = "Internal error")]
|
#[display(fmt = "Internal error")]
|
||||||
InternalError,
|
InternalError,
|
||||||
|
}
|
||||||
|
|
||||||
/// Unknown error
|
impl StdError for DispatchError {
|
||||||
#[display(fmt = "Unknown error")]
|
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||||
Unknown,
|
match self {
|
||||||
|
// TODO: error source extraction?
|
||||||
|
DispatchError::Service(_res) => None,
|
||||||
|
DispatchError::Body(err) => Some(&**err),
|
||||||
|
DispatchError::Io(err) => Some(err),
|
||||||
|
DispatchError::Parse(err) => Some(err),
|
||||||
|
DispatchError::H2(err) => Some(err),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A set of error that can occur during parsing content type.
|
/// A set of error that can occur during parsing content type.
|
||||||
|
|
|
@ -15,7 +15,7 @@ use bitflags::bitflags;
|
||||||
use bytes::{Buf, BytesMut};
|
use bytes::{Buf, BytesMut};
|
||||||
use futures_core::ready;
|
use futures_core::ready;
|
||||||
use log::{error, trace};
|
use log::{error, trace};
|
||||||
use pin_project::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{BodySize, BoxBody, MessageBody},
|
body::{BodySize, BoxBody, MessageBody},
|
||||||
|
@ -46,7 +46,34 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pin_project]
|
// there's 2 versions of Dispatcher state because of:
|
||||||
|
// https://github.com/taiki-e/pin-project-lite/issues/3
|
||||||
|
//
|
||||||
|
// tl;dr: pin-project-lite doesn't play well with other attribute macros
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
pin_project! {
|
||||||
|
/// Dispatcher for HTTP/1.1 protocol
|
||||||
|
pub struct Dispatcher<T, S, B, X, U>
|
||||||
|
where
|
||||||
|
S: Service<Request>,
|
||||||
|
S::Error: Into<Response<BoxBody>>,
|
||||||
|
|
||||||
|
B: MessageBody,
|
||||||
|
|
||||||
|
X: Service<Request, Response = Request>,
|
||||||
|
X::Error: Into<Response<BoxBody>>,
|
||||||
|
|
||||||
|
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||||
|
U::Error: fmt::Display,
|
||||||
|
{
|
||||||
|
#[pin]
|
||||||
|
inner: DispatcherState<T, S, B, X, U>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pin_project! {
|
||||||
/// Dispatcher for HTTP/1.1 protocol
|
/// Dispatcher for HTTP/1.1 protocol
|
||||||
pub struct Dispatcher<T, S, B, X, U>
|
pub struct Dispatcher<T, S, B, X, U>
|
||||||
where
|
where
|
||||||
|
@ -64,11 +91,13 @@ where
|
||||||
#[pin]
|
#[pin]
|
||||||
inner: DispatcherState<T, S, B, X, U>,
|
inner: DispatcherState<T, S, B, X, U>,
|
||||||
|
|
||||||
#[cfg(test)]
|
// used in tests
|
||||||
poll_count: u64,
|
poll_count: u64,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[pin_project(project = DispatcherStateProj)]
|
pin_project! {
|
||||||
|
#[project = DispatcherStateProj]
|
||||||
enum DispatcherState<T, S, B, X, U>
|
enum DispatcherState<T, S, B, X, U>
|
||||||
where
|
where
|
||||||
S: Service<Request>,
|
S: Service<Request>,
|
||||||
|
@ -82,11 +111,13 @@ where
|
||||||
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
U: Service<(Request, Framed<T, Codec>), Response = ()>,
|
||||||
U::Error: fmt::Display,
|
U::Error: fmt::Display,
|
||||||
{
|
{
|
||||||
Normal(#[pin] InnerDispatcher<T, S, B, X, U>),
|
Normal { #[pin] inner: InnerDispatcher<T, S, B, X, U> },
|
||||||
Upgrade(#[pin] U::Future),
|
Upgrade { #[pin] fut: U::Future },
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pin_project(project = InnerDispatcherProj)]
|
pin_project! {
|
||||||
|
#[project = InnerDispatcherProj]
|
||||||
struct InnerDispatcher<T, S, B, X, U>
|
struct InnerDispatcher<T, S, B, X, U>
|
||||||
where
|
where
|
||||||
S: Service<Request>,
|
S: Service<Request>,
|
||||||
|
@ -120,6 +151,7 @@ where
|
||||||
write_buf: BytesMut,
|
write_buf: BytesMut,
|
||||||
codec: Codec,
|
codec: Codec,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum DispatcherMessage {
|
enum DispatcherMessage {
|
||||||
Item(Request),
|
Item(Request),
|
||||||
|
@ -127,7 +159,8 @@ enum DispatcherMessage {
|
||||||
Error(Response<()>),
|
Error(Response<()>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pin_project(project = StateProj)]
|
pin_project! {
|
||||||
|
#[project = StateProj]
|
||||||
enum State<S, B, X>
|
enum State<S, B, X>
|
||||||
where
|
where
|
||||||
S: Service<Request>,
|
S: Service<Request>,
|
||||||
|
@ -136,10 +169,11 @@ where
|
||||||
B: MessageBody,
|
B: MessageBody,
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
ExpectCall(#[pin] X::Future),
|
ExpectCall { #[pin] fut: X::Future },
|
||||||
ServiceCall(#[pin] S::Future),
|
ServiceCall { #[pin] fut: S::Future },
|
||||||
SendPayload(#[pin] B),
|
SendPayload { #[pin] body: B },
|
||||||
SendErrorPayload(#[pin] BoxBody),
|
SendErrorPayload { #[pin] body: BoxBody },
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, B, X> State<S, B, X>
|
impl<S, B, X> State<S, B, X>
|
||||||
|
@ -198,7 +232,8 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
Dispatcher {
|
Dispatcher {
|
||||||
inner: DispatcherState::Normal(InnerDispatcher {
|
inner: DispatcherState::Normal {
|
||||||
|
inner: InnerDispatcher {
|
||||||
flow,
|
flow,
|
||||||
flags,
|
flags,
|
||||||
peer_addr,
|
peer_addr,
|
||||||
|
@ -216,7 +251,8 @@ where
|
||||||
read_buf: BytesMut::with_capacity(HW_BUFFER_SIZE),
|
read_buf: BytesMut::with_capacity(HW_BUFFER_SIZE),
|
||||||
write_buf: BytesMut::with_capacity(HW_BUFFER_SIZE),
|
write_buf: BytesMut::with_capacity(HW_BUFFER_SIZE),
|
||||||
codec: Codec::new(config),
|
codec: Codec::new(config),
|
||||||
}),
|
},
|
||||||
|
},
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
poll_count: 0,
|
poll_count: 0,
|
||||||
|
@ -316,7 +352,7 @@ where
|
||||||
let size = self.as_mut().send_response_inner(message, &body)?;
|
let size = self.as_mut().send_response_inner(message, &body)?;
|
||||||
let state = match size {
|
let state = match size {
|
||||||
BodySize::None | BodySize::Sized(0) => State::None,
|
BodySize::None | BodySize::Sized(0) => State::None,
|
||||||
_ => State::SendPayload(body),
|
_ => State::SendPayload { body },
|
||||||
};
|
};
|
||||||
self.project().state.set(state);
|
self.project().state.set(state);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -330,7 +366,7 @@ where
|
||||||
let size = self.as_mut().send_response_inner(message, &body)?;
|
let size = self.as_mut().send_response_inner(message, &body)?;
|
||||||
let state = match size {
|
let state = match size {
|
||||||
BodySize::None | BodySize::Sized(0) => State::None,
|
BodySize::None | BodySize::Sized(0) => State::None,
|
||||||
_ => State::SendErrorPayload(body),
|
_ => State::SendErrorPayload { body },
|
||||||
};
|
};
|
||||||
self.project().state.set(state);
|
self.project().state.set(state);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -356,12 +392,12 @@ where
|
||||||
// Handle `EXPECT: 100-Continue` header
|
// Handle `EXPECT: 100-Continue` header
|
||||||
if req.head().expect() {
|
if req.head().expect() {
|
||||||
// set InnerDispatcher state and continue loop to poll it.
|
// set InnerDispatcher state and continue loop to poll it.
|
||||||
let task = this.flow.expect.call(req);
|
let fut = this.flow.expect.call(req);
|
||||||
this.state.set(State::ExpectCall(task));
|
this.state.set(State::ExpectCall { fut });
|
||||||
} else {
|
} else {
|
||||||
// the same as expect call.
|
// the same as expect call.
|
||||||
let task = this.flow.service.call(req);
|
let fut = this.flow.service.call(req);
|
||||||
this.state.set(State::ServiceCall(task));
|
this.state.set(State::ServiceCall { fut });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,7 +417,7 @@ where
|
||||||
// all messages are dealt with.
|
// all messages are dealt with.
|
||||||
None => return Ok(PollResponse::DoNothing),
|
None => return Ok(PollResponse::DoNothing),
|
||||||
},
|
},
|
||||||
StateProj::ServiceCall(fut) => match fut.poll(cx) {
|
StateProj::ServiceCall { fut } => match fut.poll(cx) {
|
||||||
// service call resolved. send response.
|
// service call resolved. send response.
|
||||||
Poll::Ready(Ok(res)) => {
|
Poll::Ready(Ok(res)) => {
|
||||||
let (res, body) = res.into().replace_body(());
|
let (res, body) = res.into().replace_body(());
|
||||||
|
@ -407,11 +443,11 @@ where
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
StateProj::SendPayload(mut stream) => {
|
StateProj::SendPayload { mut body } => {
|
||||||
// keep populate writer buffer until buffer size limit hit,
|
// keep populate writer buffer until buffer size limit hit,
|
||||||
// get blocked or finished.
|
// get blocked or finished.
|
||||||
while this.write_buf.len() < super::payload::MAX_BUFFER_SIZE {
|
while this.write_buf.len() < super::payload::MAX_BUFFER_SIZE {
|
||||||
match stream.as_mut().poll_next(cx) {
|
match body.as_mut().poll_next(cx) {
|
||||||
Poll::Ready(Some(Ok(item))) => {
|
Poll::Ready(Some(Ok(item))) => {
|
||||||
this.codec
|
this.codec
|
||||||
.encode(Message::Chunk(Some(item)), this.write_buf)?;
|
.encode(Message::Chunk(Some(item)), this.write_buf)?;
|
||||||
|
@ -437,13 +473,13 @@ where
|
||||||
return Ok(PollResponse::DrainWriteBuf);
|
return Ok(PollResponse::DrainWriteBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
StateProj::SendErrorPayload(mut stream) => {
|
StateProj::SendErrorPayload { mut body } => {
|
||||||
// TODO: de-dupe impl with SendPayload
|
// TODO: de-dupe impl with SendPayload
|
||||||
|
|
||||||
// keep populate writer buffer until buffer size limit hit,
|
// keep populate writer buffer until buffer size limit hit,
|
||||||
// get blocked or finished.
|
// get blocked or finished.
|
||||||
while this.write_buf.len() < super::payload::MAX_BUFFER_SIZE {
|
while this.write_buf.len() < super::payload::MAX_BUFFER_SIZE {
|
||||||
match stream.as_mut().poll_next(cx) {
|
match body.as_mut().poll_next(cx) {
|
||||||
Poll::Ready(Some(Ok(item))) => {
|
Poll::Ready(Some(Ok(item))) => {
|
||||||
this.codec
|
this.codec
|
||||||
.encode(Message::Chunk(Some(item)), this.write_buf)?;
|
.encode(Message::Chunk(Some(item)), this.write_buf)?;
|
||||||
|
@ -458,7 +494,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
Poll::Ready(Some(Err(err))) => {
|
Poll::Ready(Some(Err(err))) => {
|
||||||
return Err(DispatchError::Service(
|
return Err(DispatchError::Body(
|
||||||
Error::new_body().with_cause(err).into(),
|
Error::new_body().with_cause(err).into(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -471,14 +507,14 @@ where
|
||||||
return Ok(PollResponse::DrainWriteBuf);
|
return Ok(PollResponse::DrainWriteBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
StateProj::ExpectCall(fut) => match fut.poll(cx) {
|
StateProj::ExpectCall { fut } => match fut.poll(cx) {
|
||||||
// expect resolved. write continue to buffer and set InnerDispatcher state
|
// expect resolved. write continue to buffer and set InnerDispatcher state
|
||||||
// to service call.
|
// to service call.
|
||||||
Poll::Ready(Ok(req)) => {
|
Poll::Ready(Ok(req)) => {
|
||||||
this.write_buf
|
this.write_buf
|
||||||
.extend_from_slice(b"HTTP/1.1 100 Continue\r\n\r\n");
|
.extend_from_slice(b"HTTP/1.1 100 Continue\r\n\r\n");
|
||||||
let fut = this.flow.service.call(req);
|
let fut = this.flow.service.call(req);
|
||||||
this.state.set(State::ServiceCall(fut));
|
this.state.set(State::ServiceCall { fut });
|
||||||
}
|
}
|
||||||
|
|
||||||
// send expect error as response
|
// send expect error as response
|
||||||
|
@ -504,25 +540,25 @@ where
|
||||||
let mut this = self.as_mut().project();
|
let mut this = self.as_mut().project();
|
||||||
if req.head().expect() {
|
if req.head().expect() {
|
||||||
// set dispatcher state so the future is pinned.
|
// set dispatcher state so the future is pinned.
|
||||||
let task = this.flow.expect.call(req);
|
let fut = this.flow.expect.call(req);
|
||||||
this.state.set(State::ExpectCall(task));
|
this.state.set(State::ExpectCall { fut });
|
||||||
} else {
|
} else {
|
||||||
// the same as above.
|
// the same as above.
|
||||||
let task = this.flow.service.call(req);
|
let fut = this.flow.service.call(req);
|
||||||
this.state.set(State::ServiceCall(task));
|
this.state.set(State::ServiceCall { fut });
|
||||||
};
|
};
|
||||||
|
|
||||||
// eagerly poll the future for once(or twice if expect is resolved immediately).
|
// eagerly poll the future for once(or twice if expect is resolved immediately).
|
||||||
loop {
|
loop {
|
||||||
match self.as_mut().project().state.project() {
|
match self.as_mut().project().state.project() {
|
||||||
StateProj::ExpectCall(fut) => {
|
StateProj::ExpectCall { fut } => {
|
||||||
match fut.poll(cx) {
|
match fut.poll(cx) {
|
||||||
// expect is resolved. continue loop and poll the service call branch.
|
// expect is resolved. continue loop and poll the service call branch.
|
||||||
Poll::Ready(Ok(req)) => {
|
Poll::Ready(Ok(req)) => {
|
||||||
self.as_mut().send_continue();
|
self.as_mut().send_continue();
|
||||||
let mut this = self.as_mut().project();
|
let mut this = self.as_mut().project();
|
||||||
let task = this.flow.service.call(req);
|
let fut = this.flow.service.call(req);
|
||||||
this.state.set(State::ServiceCall(task));
|
this.state.set(State::ServiceCall { fut });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// future is pending. return Ok(()) to notify that a new state is
|
// future is pending. return Ok(()) to notify that a new state is
|
||||||
|
@ -538,7 +574,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StateProj::ServiceCall(fut) => {
|
StateProj::ServiceCall { fut } => {
|
||||||
// return no matter the service call future's result.
|
// return no matter the service call future's result.
|
||||||
return match fut.poll(cx) {
|
return match fut.poll(cx) {
|
||||||
// future is resolved. send response and return a result. On success
|
// future is resolved. send response and return a result. On success
|
||||||
|
@ -903,7 +939,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
match this.inner.project() {
|
match this.inner.project() {
|
||||||
DispatcherStateProj::Normal(mut inner) => {
|
DispatcherStateProj::Normal { mut inner } => {
|
||||||
inner.as_mut().poll_keepalive(cx)?;
|
inner.as_mut().poll_keepalive(cx)?;
|
||||||
|
|
||||||
if inner.flags.contains(Flags::SHUTDOWN) {
|
if inner.flags.contains(Flags::SHUTDOWN) {
|
||||||
|
@ -943,7 +979,7 @@ where
|
||||||
self.as_mut()
|
self.as_mut()
|
||||||
.project()
|
.project()
|
||||||
.inner
|
.inner
|
||||||
.set(DispatcherState::Upgrade(upgrade));
|
.set(DispatcherState::Upgrade { fut: upgrade });
|
||||||
return self.poll(cx);
|
return self.poll(cx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -995,8 +1031,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DispatcherStateProj::Upgrade(fut) => fut.poll(cx).map_err(|e| {
|
DispatcherStateProj::Upgrade { fut: upgrade } => upgrade.poll(cx).map_err(|err| {
|
||||||
error!("Upgrade handler error: {}", e);
|
error!("Upgrade handler error: {}", err);
|
||||||
DispatchError::Upgrade
|
DispatchError::Upgrade
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -1090,7 +1126,7 @@ mod tests {
|
||||||
Poll::Ready(res) => assert!(res.is_err()),
|
Poll::Ready(res) => assert!(res.is_err()),
|
||||||
}
|
}
|
||||||
|
|
||||||
if let DispatcherStateProj::Normal(inner) = h1.project().inner.project() {
|
if let DispatcherStateProj::Normal { inner } = h1.project().inner.project() {
|
||||||
assert!(inner.flags.contains(Flags::READ_DISCONNECT));
|
assert!(inner.flags.contains(Flags::READ_DISCONNECT));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&inner.project().io.take().unwrap().write_buf[..26],
|
&inner.project().io.take().unwrap().write_buf[..26],
|
||||||
|
@ -1125,7 +1161,7 @@ mod tests {
|
||||||
|
|
||||||
actix_rt::pin!(h1);
|
actix_rt::pin!(h1);
|
||||||
|
|
||||||
assert!(matches!(&h1.inner, DispatcherState::Normal(_)));
|
assert!(matches!(&h1.inner, DispatcherState::Normal { .. }));
|
||||||
|
|
||||||
match h1.as_mut().poll(cx) {
|
match h1.as_mut().poll(cx) {
|
||||||
Poll::Pending => panic!("first poll should not be pending"),
|
Poll::Pending => panic!("first poll should not be pending"),
|
||||||
|
@ -1135,7 +1171,7 @@ mod tests {
|
||||||
// polls: initial => shutdown
|
// polls: initial => shutdown
|
||||||
assert_eq!(h1.poll_count, 2);
|
assert_eq!(h1.poll_count, 2);
|
||||||
|
|
||||||
if let DispatcherStateProj::Normal(inner) = h1.project().inner.project() {
|
if let DispatcherStateProj::Normal { inner } = h1.project().inner.project() {
|
||||||
let res = &mut inner.project().io.take().unwrap().write_buf[..];
|
let res = &mut inner.project().io.take().unwrap().write_buf[..];
|
||||||
stabilize_date_header(res);
|
stabilize_date_header(res);
|
||||||
|
|
||||||
|
@ -1179,7 +1215,7 @@ mod tests {
|
||||||
|
|
||||||
actix_rt::pin!(h1);
|
actix_rt::pin!(h1);
|
||||||
|
|
||||||
assert!(matches!(&h1.inner, DispatcherState::Normal(_)));
|
assert!(matches!(&h1.inner, DispatcherState::Normal { .. }));
|
||||||
|
|
||||||
match h1.as_mut().poll(cx) {
|
match h1.as_mut().poll(cx) {
|
||||||
Poll::Pending => panic!("first poll should not be pending"),
|
Poll::Pending => panic!("first poll should not be pending"),
|
||||||
|
@ -1189,7 +1225,7 @@ mod tests {
|
||||||
// polls: initial => shutdown
|
// polls: initial => shutdown
|
||||||
assert_eq!(h1.poll_count, 1);
|
assert_eq!(h1.poll_count, 1);
|
||||||
|
|
||||||
if let DispatcherStateProj::Normal(inner) = h1.project().inner.project() {
|
if let DispatcherStateProj::Normal { inner } = h1.project().inner.project() {
|
||||||
let res = &mut inner.project().io.take().unwrap().write_buf[..];
|
let res = &mut inner.project().io.take().unwrap().write_buf[..];
|
||||||
stabilize_date_header(res);
|
stabilize_date_header(res);
|
||||||
|
|
||||||
|
@ -1239,13 +1275,13 @@ mod tests {
|
||||||
actix_rt::pin!(h1);
|
actix_rt::pin!(h1);
|
||||||
|
|
||||||
assert!(h1.as_mut().poll(cx).is_pending());
|
assert!(h1.as_mut().poll(cx).is_pending());
|
||||||
assert!(matches!(&h1.inner, DispatcherState::Normal(_)));
|
assert!(matches!(&h1.inner, DispatcherState::Normal { .. }));
|
||||||
|
|
||||||
// polls: manual
|
// polls: manual
|
||||||
assert_eq!(h1.poll_count, 1);
|
assert_eq!(h1.poll_count, 1);
|
||||||
eprintln!("poll count: {}", h1.poll_count);
|
eprintln!("poll count: {}", h1.poll_count);
|
||||||
|
|
||||||
if let DispatcherState::Normal(ref inner) = h1.inner {
|
if let DispatcherState::Normal { ref inner } = h1.inner {
|
||||||
let io = inner.io.as_ref().unwrap();
|
let io = inner.io.as_ref().unwrap();
|
||||||
let res = &io.write_buf()[..];
|
let res = &io.write_buf()[..];
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1260,7 +1296,7 @@ mod tests {
|
||||||
// polls: manual manual shutdown
|
// polls: manual manual shutdown
|
||||||
assert_eq!(h1.poll_count, 3);
|
assert_eq!(h1.poll_count, 3);
|
||||||
|
|
||||||
if let DispatcherState::Normal(ref inner) = h1.inner {
|
if let DispatcherState::Normal { ref inner } = h1.inner {
|
||||||
let io = inner.io.as_ref().unwrap();
|
let io = inner.io.as_ref().unwrap();
|
||||||
let mut res = (&io.write_buf()[..]).to_owned();
|
let mut res = (&io.write_buf()[..]).to_owned();
|
||||||
stabilize_date_header(&mut res);
|
stabilize_date_header(&mut res);
|
||||||
|
@ -1311,12 +1347,12 @@ mod tests {
|
||||||
actix_rt::pin!(h1);
|
actix_rt::pin!(h1);
|
||||||
|
|
||||||
assert!(h1.as_mut().poll(cx).is_ready());
|
assert!(h1.as_mut().poll(cx).is_ready());
|
||||||
assert!(matches!(&h1.inner, DispatcherState::Normal(_)));
|
assert!(matches!(&h1.inner, DispatcherState::Normal { .. }));
|
||||||
|
|
||||||
// polls: manual shutdown
|
// polls: manual shutdown
|
||||||
assert_eq!(h1.poll_count, 2);
|
assert_eq!(h1.poll_count, 2);
|
||||||
|
|
||||||
if let DispatcherState::Normal(ref inner) = h1.inner {
|
if let DispatcherState::Normal { ref inner } = h1.inner {
|
||||||
let io = inner.io.as_ref().unwrap();
|
let io = inner.io.as_ref().unwrap();
|
||||||
let mut res = (&io.write_buf()[..]).to_owned();
|
let mut res = (&io.write_buf()[..]).to_owned();
|
||||||
stabilize_date_header(&mut res);
|
stabilize_date_header(&mut res);
|
||||||
|
@ -1388,7 +1424,7 @@ mod tests {
|
||||||
actix_rt::pin!(h1);
|
actix_rt::pin!(h1);
|
||||||
|
|
||||||
assert!(h1.as_mut().poll(cx).is_ready());
|
assert!(h1.as_mut().poll(cx).is_ready());
|
||||||
assert!(matches!(&h1.inner, DispatcherState::Upgrade(_)));
|
assert!(matches!(&h1.inner, DispatcherState::Upgrade { .. }));
|
||||||
|
|
||||||
// polls: manual shutdown
|
// polls: manual shutdown
|
||||||
assert_eq!(h1.poll_count, 2);
|
assert_eq!(h1.poll_count, 2);
|
||||||
|
|
|
@ -356,9 +356,9 @@ where
|
||||||
type Future = Dispatcher<T, S, B, X, U>;
|
type Future = Dispatcher<T, S, B, X, U>;
|
||||||
|
|
||||||
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
self._poll_ready(cx).map_err(|e| {
|
self._poll_ready(cx).map_err(|err| {
|
||||||
log::error!("HTTP/1 service readiness error: {:?}", e);
|
log::error!("HTTP/1 service readiness error: {:?}", err);
|
||||||
DispatchError::Service(e)
|
DispatchError::Service(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -493,9 +493,9 @@ where
|
||||||
type Future = HttpServiceHandlerResponse<T, S, B, X, U>;
|
type Future = HttpServiceHandlerResponse<T, S, B, X, U>;
|
||||||
|
|
||||||
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||||
self._poll_ready(cx).map_err(|e| {
|
self._poll_ready(cx).map_err(|err| {
|
||||||
log::error!("HTTP service readiness error: {:?}", e);
|
log::error!("HTTP service readiness error: {:?}", err);
|
||||||
DispatchError::Service(e)
|
DispatchError::Service(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -322,13 +322,10 @@ pin_project! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> MessageBody for StreamLog<B>
|
impl<B: MessageBody> MessageBody for StreamLog<B> {
|
||||||
where
|
type Error = B::Error;
|
||||||
B: MessageBody,
|
|
||||||
B::Error: Into<Error>,
|
|
||||||
{
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn size(&self) -> BodySize {
|
fn size(&self) -> BodySize {
|
||||||
self.body.size()
|
self.body.size()
|
||||||
}
|
}
|
||||||
|
@ -344,7 +341,7 @@ where
|
||||||
*this.size += chunk.len();
|
*this.size += chunk.len();
|
||||||
Poll::Ready(Some(Ok(chunk)))
|
Poll::Ready(Some(Ok(chunk)))
|
||||||
}
|
}
|
||||||
Some(Err(err)) => Poll::Ready(Some(Err(err.into()))),
|
Some(Err(err)) => Poll::Ready(Some(Err(err))),
|
||||||
None => Poll::Ready(None),
|
None => Poll::Ready(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue