Browse Source

drop unpin constraint

master
Nikolay Kim 10 months ago
parent
commit
1ffa7d18d3
31 changed files with 2174 additions and 2179 deletions
  1. +2
    -1
      actix-http/Cargo.toml
  2. +18
    -16
      actix-http/examples/echo.rs
  3. +13
    -16
      actix-http/examples/echo2.rs
  4. +44
    -29
      actix-http/src/body.rs
  5. +17
    -38
      actix-http/src/builder.rs
  6. +35
    -25
      actix-http/src/client/connection.rs
  7. +33
    -96
      actix-http/src/client/connector.rs
  8. +4
    -4
      actix-http/src/client/error.rs
  9. +16
    -19
      actix-http/src/client/pool.rs
  10. +1
    -1
      actix-http/src/config.rs
  11. +10
    -10
      actix-http/src/error.rs
  12. +54
    -49
      actix-http/src/h1/dispatcher.rs
  13. +15
    -18
      actix-http/src/h1/payload.rs
  14. +25
    -70
      actix-http/src/h1/service.rs
  15. +2
    -1
      actix-http/src/h1/utils.rs
  16. +44
    -49
      actix-http/src/h2/dispatcher.rs
  17. +27
    -32
      actix-http/src/h2/service.rs
  18. +5
    -0
      actix-http/src/request.rs
  19. +2
    -2
      actix-http/src/response.rs
  20. +130
    -132
      actix-http/src/service.rs
  21. +7
    -7
      actix-http/src/ws/transport.rs
  22. +48
    -40
      actix-http/tests/test_client.rs
  23. +545
    -0
      actix-http/tests/test_openssl.rs
  24. +474
    -0
      actix-http/tests/test_rustls.rs
  25. +0
    -462
      actix-http/tests/test_rustls_server.rs
  26. +490
    -435
      actix-http/tests/test_server.rs
  27. +0
    -480
      actix-http/tests/test_ssl_server.rs
  28. +55
    -45
      actix-http/tests/test_ws.rs
  29. +15
    -22
      test-server/src/lib.rs
  30. +17
    -30
      tests/cert.pem
  31. +26
    -50
      tests/key.pem

+ 2
- 1
actix-http/Cargo.toml View File

@@ -74,6 +74,7 @@ language-tags = "0.2"
log = "0.4"
mime = "0.3"
percent-encoding = "2.1"
pin-project = "0.4.5"
rand = "0.7"
regex = "1.0"
serde = "1.0"
@@ -107,7 +108,7 @@ webpki-roots = { version = "0.18", optional = true }

[dev-dependencies]
actix-rt = "1.0.0-alpha.1"
actix-server = { version = "0.8.0-alpha.1", features=["openssl"] }
actix-server = { version = "0.8.0-alpha.1", features=["openssl", "rustls"] }
actix-connect = { version = "1.0.0-alpha.1", features=["openssl"] }
actix-http-test = { version = "0.3.0-alpha.1", features=["openssl"] }
env_logger = "0.6"


+ 18
- 16
actix-http/examples/echo.rs View File

@@ -1,9 +1,9 @@
use std::{env, io};

use actix_http::{error::PayloadError, HttpService, Request, Response};
use actix_http::{Error, HttpService, Request, Response};
use actix_server::Server;
use bytes::BytesMut;
use futures::{Future, Stream};
use futures::StreamExt;
use http::header::HeaderValue;
use log::info;

@@ -17,20 +17,22 @@ fn main() -> io::Result<()> {
.client_timeout(1000)
.client_disconnect(1000)
.finish(|mut req: Request| {
req.take_payload()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, PayloadError>(body)
})
.and_then(|bytes| {
info!("request body: {:?}", bytes);
let mut res = Response::Ok();
res.header(
"x-head",
HeaderValue::from_static("dummy value!"),
);
Ok(res.body(bytes))
})
async move {
let mut body = BytesMut::new();
while let Some(item) = req.payload().next().await {
body.extend_from_slice(&item?);
}

info!("request body: {:?}", body);
Ok::<_, Error>(
Response::Ok()
.header(
"x-head",
HeaderValue::from_static("dummy value!"),
)
.body(body),
)
}
})
})?
.run()


+ 13
- 16
actix-http/examples/echo2.rs View File

@@ -1,25 +1,22 @@
use std::{env, io};

use actix_http::http::HeaderValue;
use actix_http::{error::PayloadError, Error, HttpService, Request, Response};
use actix_http::{Error, HttpService, Request, Response};
use actix_server::Server;
use bytes::BytesMut;
use futures::{Future, Stream};
use futures::StreamExt;
use log::info;

fn handle_request(mut req: Request) -> impl Future<Item = Response, Error = Error> {
req.take_payload()
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, PayloadError>(body)
})
.from_err()
.and_then(|bytes| {
info!("request body: {:?}", bytes);
let mut res = Response::Ok();
res.header("x-head", HeaderValue::from_static("dummy value!"));
Ok(res.body(bytes))
})
async fn handle_request(mut req: Request) -> Result<Response, Error> {
let mut body = BytesMut::new();
while let Some(item) = req.payload().next().await {
body.extend_from_slice(&item?)
}

info!("request body: {:?}", body);
Ok(Response::Ok()
.header("x-head", HeaderValue::from_static("dummy value!"))
.body(body))
}

fn main() -> io::Result<()> {
@@ -28,7 +25,7 @@ fn main() -> io::Result<()> {

Server::build()
.bind("echo", "127.0.0.1:8080", || {
HttpService::build().finish(|_req: Request| handle_request(_req))
HttpService::build().finish(handle_request)
})?
.run()
}

+ 44
- 29
actix-http/src/body.rs View File

@@ -5,6 +5,7 @@ use std::{fmt, mem};

use bytes::{Bytes, BytesMut};
use futures::Stream;
use pin_project::{pin_project, project};

use crate::error::Error;

@@ -31,7 +32,7 @@ impl BodySize {
}

/// Type that provides this trait can be streamed to a peer.
pub trait MessageBody: Unpin {
pub trait MessageBody {
fn size(&self) -> BodySize;

fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>>;
@@ -57,6 +58,7 @@ impl<T: MessageBody> MessageBody for Box<T> {
}
}

#[pin_project]
pub enum ResponseBody<B> {
Body(B),
Other(Body),
@@ -106,8 +108,13 @@ impl<B: MessageBody> MessageBody for ResponseBody<B> {
impl<B: MessageBody> Stream for ResponseBody<B> {
type Item = Result<Bytes, Error>;

#[project]
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
self.get_mut().poll_next(cx)
#[project]
match self.project() {
ResponseBody::Body(ref mut body) => body.poll_next(cx),
ResponseBody::Other(ref mut body) => body.poll_next(cx),
}
}
}

@@ -243,7 +250,7 @@ impl From<serde_json::Value> for Body {

impl<S> From<SizedStream<S>> for Body
where
S: Stream<Item = Result<Bytes, Error>> + Unpin + 'static,
S: Stream<Item = Result<Bytes, Error>> + 'static,
{
fn from(s: SizedStream<S>) -> Body {
Body::from_message(s)
@@ -252,7 +259,7 @@ where

impl<S, E> From<BodyStream<S, E>> for Body
where
S: Stream<Item = Result<Bytes, E>> + Unpin + 'static,
S: Stream<Item = Result<Bytes, E>> + 'static,
E: Into<Error> + 'static,
{
fn from(s: BodyStream<S, E>) -> Body {
@@ -350,7 +357,9 @@ impl MessageBody for String {

/// Type represent streaming body.
/// Response does not contain `content-length` header and appropriate transfer encoding is used.
#[pin_project]
pub struct BodyStream<S, E> {
#[pin]
stream: S,
_t: PhantomData<E>,
}
@@ -368,16 +377,9 @@ where
}
}

impl<S, E> Unpin for BodyStream<S, E>
where
S: Stream<Item = Result<Bytes, E>> + Unpin,
E: Into<Error>,
{
}

impl<S, E> MessageBody for BodyStream<S, E>
where
S: Stream<Item = Result<Bytes, E>> + Unpin,
S: Stream<Item = Result<Bytes, E>>,
E: Into<Error>,
{
fn size(&self) -> BodySize {
@@ -385,7 +387,9 @@ where
}

fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
Pin::new(&mut self.stream)
unsafe { Pin::new_unchecked(self) }
.project()
.stream
.poll_next(cx)
.map(|res| res.map(|res| res.map_err(std::convert::Into::into)))
}
@@ -393,8 +397,10 @@ where

/// Type represent streaming body. This body implementation should be used
/// if total size of stream is known. Data get sent as is without using transfer encoding.
#[pin_project]
pub struct SizedStream<S> {
size: u64,
#[pin]
stream: S,
}

@@ -409,20 +415,25 @@ where

impl<S> MessageBody for SizedStream<S>
where
S: Stream<Item = Result<Bytes, Error>> + Unpin,
S: Stream<Item = Result<Bytes, Error>>,
{
fn size(&self) -> BodySize {
BodySize::Sized64(self.size)
}

fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> {
Pin::new(&mut self.stream).poll_next(cx)
unsafe { Pin::new_unchecked(self) }
.project()
.stream
.poll_next(cx)
}
}

#[cfg(test)]
mod tests {
use super::*;
use actix_http_test::block_on;
use futures::future::{lazy, poll_fn};

impl Body {
pub(crate) fn get_ref(&self) -> &[u8] {
@@ -450,8 +461,8 @@ mod tests {

assert_eq!("test".size(), BodySize::Sized(4));
assert_eq!(
"test".poll_next().unwrap(),
Async::Ready(Some(Bytes::from("test")))
block_on(poll_fn(|cx| "test".poll_next(cx))).unwrap().ok(),
Some(Bytes::from("test"))
);
}

@@ -467,8 +478,10 @@ mod tests {

assert_eq!((&b"test"[..]).size(), BodySize::Sized(4));
assert_eq!(
(&b"test"[..]).poll_next().unwrap(),
Async::Ready(Some(Bytes::from("test")))
block_on(poll_fn(|cx| (&b"test"[..]).poll_next(cx)))
.unwrap()
.ok(),
Some(Bytes::from("test"))
);
}

@@ -479,8 +492,10 @@ mod tests {

assert_eq!(Vec::from("test").size(), BodySize::Sized(4));
assert_eq!(
Vec::from("test").poll_next().unwrap(),
Async::Ready(Some(Bytes::from("test")))
block_on(poll_fn(|cx| Vec::from("test").poll_next(cx)))
.unwrap()
.ok(),
Some(Bytes::from("test"))
);
}

@@ -492,8 +507,8 @@ mod tests {

assert_eq!(b.size(), BodySize::Sized(4));
assert_eq!(
b.poll_next().unwrap(),
Async::Ready(Some(Bytes::from("test")))
block_on(poll_fn(|cx| b.poll_next(cx))).unwrap().ok(),
Some(Bytes::from("test"))
);
}

@@ -505,8 +520,8 @@ mod tests {

assert_eq!(b.size(), BodySize::Sized(4));
assert_eq!(
b.poll_next().unwrap(),
Async::Ready(Some(Bytes::from("test")))
block_on(poll_fn(|cx| b.poll_next(cx))).unwrap().ok(),
Some(Bytes::from("test"))
);
}

@@ -520,22 +535,22 @@ mod tests {

assert_eq!(b.size(), BodySize::Sized(4));
assert_eq!(
b.poll_next().unwrap(),
Async::Ready(Some(Bytes::from("test")))
block_on(poll_fn(|cx| b.poll_next(cx))).unwrap().ok(),
Some(Bytes::from("test"))
);
}

#[test]
fn test_unit() {
assert_eq!(().size(), BodySize::Empty);
assert_eq!(().poll_next().unwrap(), Async::Ready(None));
assert!(block_on(poll_fn(|cx| ().poll_next(cx))).is_none());
}

#[test]
fn test_box() {
let mut val = Box::new(());
assert_eq!(val.size(), BodySize::Empty);
assert_eq!(val.poll_next().unwrap(), Async::Ready(None));
assert!(block_on(poll_fn(|cx| val.poll_next(cx))).is_none());
}

#[test]


+ 17
- 38
actix-http/src/builder.rs View File

@@ -33,11 +33,9 @@ pub struct HttpServiceBuilder<T, S, X = ExpectHandler, U = UpgradeHandler<T>> {
impl<T, S> HttpServiceBuilder<T, S, ExpectHandler, UpgradeHandler<T>>
where
S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Error: Into<Error> + 'static,
S::InitError: fmt::Debug,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
<S::Service as Service>::Future: 'static,
{
/// Create instance of `ServiceConfigBuilder`
pub fn new() -> Self {
@@ -56,17 +54,13 @@ where
impl<T, S, X, U> HttpServiceBuilder<T, S, X, U>
where
S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Error: Into<Error> + 'static,
S::InitError: fmt::Debug,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
<S::Service as Service>::Future: 'static,
X: ServiceFactory<Config = SrvConfig, Request = Request, Response = Request>,
X::Error: Into<Error>,
X::InitError: fmt::Debug,
X::Future: Unpin,
X::Service: Unpin,
<X::Service as Service>::Future: Unpin + 'static,
<X::Service as Service>::Future: 'static,
U: ServiceFactory<
Config = SrvConfig,
Request = (Request, Framed<T, Codec>),
@@ -74,9 +68,7 @@ where
>,
U::Error: fmt::Display,
U::InitError: fmt::Debug,
U::Future: Unpin,
U::Service: Unpin,
<U::Service as Service>::Future: Unpin + 'static,
<U::Service as Service>::Future: 'static,
{
/// Set server keep-alive setting.
///
@@ -124,9 +116,7 @@ where
X1: ServiceFactory<Config = SrvConfig, Request = Request, Response = Request>,
X1::Error: Into<Error>,
X1::InitError: fmt::Debug,
X1::Future: Unpin,
X1::Service: Unpin,
<X1::Service as Service>::Future: Unpin + 'static,
<X1::Service as Service>::Future: 'static,
{
HttpServiceBuilder {
keep_alive: self.keep_alive,
@@ -153,9 +143,7 @@ where
>,
U1::Error: fmt::Display,
U1::InitError: fmt::Debug,
U1::Future: Unpin,
U1::Service: Unpin,
<U1::Service as Service>::Future: Unpin + 'static,
<U1::Service as Service>::Future: 'static,
{
HttpServiceBuilder {
keep_alive: self.keep_alive,
@@ -186,13 +174,10 @@ where
where
B: MessageBody + 'static,
F: IntoServiceFactory<S>,
S::Future: Unpin,
S::Error: Into<Error> + Unpin + 'static,
S::Error: Into<Error> + 'static,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
P: Unpin,
S::Response: Into<Response<B>> + 'static,
<S::Service as Service>::Future: 'static,
{
let cfg = ServiceConfig::new(
self.keep_alive,
@@ -210,13 +195,10 @@ where
where
B: MessageBody + 'static,
F: IntoServiceFactory<S>,
S::Error: Into<Error> + Unpin + 'static,
S::Error: Into<Error> + 'static,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
P: Unpin,
S::Response: Into<Response<B>> + 'static,
<S::Service as Service>::Future: 'static,
{
let cfg = ServiceConfig::new(
self.keep_alive,
@@ -231,13 +213,10 @@ where
where
B: MessageBody + 'static,
F: IntoServiceFactory<S>,
S::Error: Into<Error> + Unpin + 'static,
S::Error: Into<Error> + 'static,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
P: Unpin,
S::Response: Into<Response<B>> + 'static,
<S::Service as Service>::Future: 'static,
{
let cfg = ServiceConfig::new(
self.keep_alive,


+ 35
- 25
actix-http/src/client/connection.rs View File

@@ -6,6 +6,7 @@ use actix_codec::{AsyncRead, AsyncWrite, Framed};
use bytes::{Buf, Bytes};
use futures::future::{err, Either, Future, FutureExt, LocalBoxFuture, Ready};
use h2::client::SendRequest;
use pin_project::{pin_project, project};

use crate::body::MessageBody;
use crate::h1::ClientCodec;
@@ -42,9 +43,7 @@ pub trait Connection {
fn open_tunnel<H: Into<RequestHeadType>>(self, head: H) -> Self::TunnelFuture;
}

pub(crate) trait ConnectionLifetime:
AsyncRead + AsyncWrite + Unpin + 'static
{
pub(crate) trait ConnectionLifetime: AsyncRead + AsyncWrite + 'static {
/// Close connection
fn close(&mut self);

@@ -73,7 +72,7 @@ where
}
}

impl<T: AsyncRead + AsyncWrite> IoConnection<T> {
impl<T: AsyncRead + AsyncWrite + Unpin> IoConnection<T> {
pub(crate) fn new(
io: ConnectionType<T>,
created: time::Instant,
@@ -205,24 +204,27 @@ where
}
}

#[pin_project]
pub enum EitherIo<A, B> {
A(A),
B(B),
A(#[pin] A),
B(#[pin] B),
}

impl<A, B> AsyncRead for EitherIo<A, B>
where
A: AsyncRead + Unpin,
B: AsyncRead + Unpin,
A: AsyncRead,
B: AsyncRead,
{
#[project]
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
match self.get_mut() {
EitherIo::A(ref mut val) => Pin::new(val).poll_read(cx, buf),
EitherIo::B(ref mut val) => Pin::new(val).poll_read(cx, buf),
#[project]
match self.project() {
EitherIo::A(val) => val.poll_read(cx, buf),
EitherIo::B(val) => val.poll_read(cx, buf),
}
}

@@ -236,37 +238,44 @@ where

impl<A, B> AsyncWrite for EitherIo<A, B>
where
A: AsyncWrite + Unpin,
B: AsyncWrite + Unpin,
A: AsyncWrite,
B: AsyncWrite,
{
#[project]
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context,
buf: &[u8],
) -> Poll<io::Result<usize>> {
match self.get_mut() {
EitherIo::A(ref mut val) => Pin::new(val).poll_write(cx, buf),
EitherIo::B(ref mut val) => Pin::new(val).poll_write(cx, buf),
#[project]
match self.project() {
EitherIo::A(val) => val.poll_write(cx, buf),
EitherIo::B(val) => val.poll_write(cx, buf),
}
}

#[project]
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match self.get_mut() {
EitherIo::A(ref mut val) => Pin::new(val).poll_flush(cx),
EitherIo::B(ref mut val) => Pin::new(val).poll_flush(cx),
#[project]
match self.project() {
EitherIo::A(val) => val.poll_flush(cx),
EitherIo::B(val) => val.poll_flush(cx),
}
}

#[project]
fn poll_shutdown(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<io::Result<()>> {
match self.get_mut() {
EitherIo::A(ref mut val) => Pin::new(val).poll_shutdown(cx),
EitherIo::B(ref mut val) => Pin::new(val).poll_shutdown(cx),
#[project]
match self.project() {
EitherIo::A(val) => val.poll_shutdown(cx),
EitherIo::B(val) => val.poll_shutdown(cx),
}
}

#[project]
fn poll_write_buf<U: Buf>(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
@@ -275,9 +284,10 @@ where
where
Self: Sized,
{
match self.get_mut() {
EitherIo::A(ref mut val) => Pin::new(val).poll_write_buf(cx, buf),
EitherIo::B(ref mut val) => Pin::new(val).poll_write_buf(cx, buf),
#[project]
match self.project() {
EitherIo::A(val) => val.poll_write_buf(cx, buf),
EitherIo::B(val) => val.poll_write_buf(cx, buf),
}
}
}

+ 33
- 96
actix-http/src/client/connector.rs View File

@@ -62,8 +62,8 @@ pub struct Connector<T, U> {
_t: PhantomData<U>,
}

trait Io: AsyncRead + AsyncWrite {}
impl<T: AsyncRead + AsyncWrite> Io for T {}
trait Io: AsyncRead + AsyncWrite + Unpin {}
impl<T: AsyncRead + AsyncWrite + Unpin> Io for T {}

impl Connector<(), ()> {
#[allow(clippy::new_ret_no_self)]
@@ -123,7 +123,6 @@ impl<T, U> Connector<T, U> {
Response = TcpConnection<Uri, U1>,
Error = actix_connect::ConnectError,
> + Clone,
T1::Future: Unpin,
{
Connector {
connector,
@@ -222,7 +221,7 @@ where
{
let connector = TimeoutService::new(
self.timeout,
apply_fn(UnpinWrapper(self.connector), |msg: Connect, srv| {
apply_fn(self.connector, |msg: Connect, srv| {
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
})
.map_err(ConnectError::from)
@@ -257,35 +256,33 @@ where
let ssl_service = TimeoutService::new(
self.timeout,
pipeline(
apply_fn(
UnpinWrapper(self.connector.clone()),
|msg: Connect, srv| {
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
},
)
apply_fn(self.connector.clone(), |msg: Connect, srv| {
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
})
.map_err(ConnectError::from),
)
.and_then(match self.ssl {
#[cfg(feature = "openssl")]
SslConnector::Openssl(ssl) => OpensslConnector::service(ssl)
.map(|stream| {
let sock = stream.into_parts().0;
let h2 = sock
.ssl()
.selected_alpn_protocol()
.map(|protos| protos.windows(2).any(|w| w == H2))
.unwrap_or(false);
if h2 {
(Box::new(sock) as Box<dyn Io + Unpin>, Protocol::Http2)
} else {
(Box::new(sock) as Box<dyn Io + Unpin>, Protocol::Http1)
}
})
.map_err(ConnectError::from),

SslConnector::Openssl(ssl) => service(
OpensslConnector::service(ssl)
.map(|stream| {
let sock = stream.into_parts().0;
let h2 = sock
.ssl()
.selected_alpn_protocol()
.map(|protos| protos.windows(2).any(|w| w == H2))
.unwrap_or(false);
if h2 {
(Box::new(sock) as Box<dyn Io>, Protocol::Http2)
} else {
(Box::new(sock) as Box<dyn Io>, Protocol::Http1)
}
})
.map_err(ConnectError::from),
),
#[cfg(feature = "rustls")]
SslConnector::Rustls(ssl) => service(
UnpinWrapper(RustlsConnector::service(ssl))
RustlsConnector::service(ssl)
.map_err(ConnectError::from)
.map(|stream| {
let sock = stream.into_parts().0;
@@ -296,15 +293,9 @@ where
.map(|protos| protos.windows(2).any(|w| w == H2))
.unwrap_or(false);
if h2 {
(
Box::new(sock) as Box<dyn Io + Unpin>,
Protocol::Http2,
)
(Box::new(sock) as Box<dyn Io>, Protocol::Http2)
} else {
(
Box::new(sock) as Box<dyn Io + Unpin>,
Protocol::Http1,
)
(Box::new(sock) as Box<dyn Io>, Protocol::Http1)
}
}),
),
@@ -317,7 +308,7 @@ where

let tcp_service = TimeoutService::new(
self.timeout,
apply_fn(UnpinWrapper(self.connector), |msg: Connect, srv| {
apply_fn(self.connector, |msg: Connect, srv| {
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
})
.map_err(ConnectError::from)
@@ -348,42 +339,6 @@ where
}
}

#[derive(Clone)]
struct UnpinWrapper<T: Clone>(T);

impl<T: Clone> Unpin for UnpinWrapper<T> {}

impl<T: Service + Clone> Service for UnpinWrapper<T> {
type Request = T::Request;
type Response = T::Response;
type Error = T::Error;
type Future = UnpinWrapperFut<T>;

fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), T::Error>> {
self.0.poll_ready(cx)
}

fn call(&mut self, req: T::Request) -> Self::Future {
UnpinWrapperFut {
fut: self.0.call(req),
}
}
}

struct UnpinWrapperFut<T: Service> {
fut: T::Future,
}

impl<T: Service> Unpin for UnpinWrapperFut<T> {}

impl<T: Service> Future for UnpinWrapperFut<T> {
type Output = Result<T::Response, T::Error>;

fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
unsafe { Pin::new_unchecked(&mut self.get_mut().fut) }.poll(cx)
}
}

#[cfg(not(any(feature = "openssl", feature = "rustls")))]
mod connect_impl {
use std::task::{Context, Poll};
@@ -396,9 +351,8 @@ mod connect_impl {

pub(crate) struct InnerConnector<T, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
{
pub(crate) tcp_pool: ConnectionPool<T, Io>,
@@ -406,9 +360,8 @@ mod connect_impl {

impl<T, Io> Clone for InnerConnector<T, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
{
fn clone(&self) -> Self {
@@ -422,9 +375,7 @@ mod connect_impl {
where
Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T::Future: Unpin,
{
type Request = Connect;
type Response = IoConnection<Io>;
@@ -465,8 +416,6 @@ mod connect_impl {
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
T1::Future: Unpin,
T2::Future: Unpin,
{
pub(crate) tcp_pool: ConnectionPool<T1, Io1>,
pub(crate) ssl_pool: ConnectionPool<T2, Io2>,
@@ -477,13 +426,9 @@ mod connect_impl {
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T1::Future: Unpin,
T2::Future: Unpin,
{
fn clone(&self) -> Self {
InnerConnector {
@@ -498,13 +443,9 @@ mod connect_impl {
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T1::Future: Unpin,
T2::Future: Unpin,
{
type Request = Connect;
type Response = EitherConnection<Io1, Io2>;
@@ -532,14 +473,14 @@ mod connect_impl {
}
}

#[pin_project::pin_project]
pub(crate) struct InnerConnectorResponseA<T, Io1, Io2>
where
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T::Future: Unpin,
{
#[pin]
fut: <ConnectionPool<T, Io1> as Service>::Future,
_t: PhantomData<Io2>,
}
@@ -547,9 +488,7 @@ mod connect_impl {
impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2>
where
T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T::Future: Unpin,
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
{
@@ -563,14 +502,14 @@ mod connect_impl {
}
}

#[pin_project::pin_project]
pub(crate) struct InnerConnectorResponseB<T, Io1, Io2>
where
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T::Future: Unpin,
{
#[pin]
fut: <ConnectionPool<T, Io2> as Service>::Future,
_t: PhantomData<Io1>,
}
@@ -578,9 +517,7 @@ mod connect_impl {
impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2>
where
T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T::Future: Unpin,
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
{


+ 4
- 4
actix-http/src/client/error.rs View File

@@ -3,8 +3,8 @@ use std::io;
use derive_more::{Display, From};
use trust_dns_resolver::error::ResolveError;

#[cfg(feature = "ssl")]
use openssl::ssl::{Error as SslError, HandshakeError};
#[cfg(feature = "openssl")]
use open_ssl::ssl::{Error as SslError, HandshakeError};

use crate::error::{Error, ParseError, ResponseError};
use crate::http::Error as HttpError;
@@ -18,7 +18,7 @@ pub enum ConnectError {
SslIsNotSupported,

/// SSL error
#[cfg(feature = "ssl")]
#[cfg(feature = "openssl")]
#[display(fmt = "{}", _0)]
SslError(SslError),

@@ -63,7 +63,7 @@ impl From<actix_connect::ConnectError> for ConnectError {
}
}

#[cfg(feature = "ssl")]
#[cfg(feature = "openssl")]
impl<T> From<HandshakeError<T>> for ConnectError {
fn from(err: HandshakeError<T>) -> ConnectError {
match err {


+ 16
- 19
actix-http/src/client/pool.rs View File

@@ -46,11 +46,9 @@ pub(crate) struct ConnectionPool<T, Io: 'static>(Rc<RefCell<T>>, Rc<RefCell<Inne

impl<T, Io> ConnectionPool<T, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T::Future: Unpin,
{
pub(crate) fn new(
connector: T,
@@ -89,9 +87,7 @@ impl<T, Io> Service for ConnectionPool<T, Io>
where
Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin
+ 'static,
T::Future: Unpin,
{
type Request = Connect;
type Response = IoConnection<Io>;
@@ -400,7 +396,7 @@ struct CloseConnection<T> {

impl<T> CloseConnection<T>
where
T: AsyncWrite,
T: AsyncWrite + Unpin,
{
fn new(io: T, timeout: Duration) -> Self {
CloseConnection {
@@ -416,10 +412,12 @@ where
{
type Output = ();

fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {
match Pin::new(&mut self.timeout).poll(cx) {
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {
let this = self.get_mut();

match Pin::new(&mut this.timeout).poll(cx) {
Poll::Ready(_) => Poll::Ready(()),
Poll::Pending => match Pin::new(&mut self.io).poll_shutdown(cx) {
Poll::Pending => match Pin::new(&mut this.io).poll_shutdown(cx) {
Poll::Ready(_) => Poll::Ready(()),
Poll::Pending => Poll::Pending,
},
@@ -429,7 +427,7 @@ where

struct ConnectorPoolSupport<T, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
Io: AsyncRead + AsyncWrite + Unpin + 'static,
{
connector: T,
inner: Rc<RefCell<Inner<Io>>>,
@@ -438,14 +436,13 @@ where
impl<T, Io> Future for ConnectorPoolSupport<T, Io>
where
Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin,
T::Future: Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>,
T::Future: 'static,
{
type Output = ();

fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut();
let this = unsafe { self.get_unchecked_mut() };

let mut inner = this.inner.as_ref().borrow_mut();
inner.waker.register(cx.waker());
@@ -512,7 +509,7 @@ where

impl<F, Io> OpenWaitingConnection<F, Io>
where
F: Future<Output = Result<(Io, Protocol), ConnectError>> + Unpin + 'static,
F: Future<Output = Result<(Io, Protocol), ConnectError>> + 'static,
Io: AsyncRead + AsyncWrite + Unpin + 'static,
{
fn spawn(
@@ -546,13 +543,13 @@ where

impl<F, Io> Future for OpenWaitingConnection<F, Io>
where
F: Future<Output = Result<(Io, Protocol), ConnectError>> + Unpin,
F: Future<Output = Result<(Io, Protocol), ConnectError>>,
Io: AsyncRead + AsyncWrite + Unpin,
{
type Output = ();

fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut();
let this = unsafe { self.get_unchecked_mut() };

if let Some(ref mut h2) = this.h2 {
return match Pin::new(h2).poll(cx) {
@@ -577,7 +574,7 @@ where
};
}

match Pin::new(&mut this.fut).poll(cx) {
match unsafe { Pin::new_unchecked(&mut this.fut) }.poll(cx) {
Poll::Ready(Err(err)) => {
let _ = this.inner.take();
if let Some(rx) = this.rx.take() {
@@ -596,7 +593,7 @@ where
Poll::Ready(())
} else {
this.h2 = Some(handshake(io).boxed_local());
Pin::new(this).poll(cx)
unsafe { Pin::new_unchecked(this) }.poll(cx)
}
}
Poll::Pending => Poll::Pending,


+ 1
- 1
actix-http/src/config.rs View File

@@ -277,7 +277,7 @@ mod tests {
fn test_date() {
let mut rt = System::new("test");

let _ = rt.block_on(future::lazy(|| {
let _ = rt.block_on(future::lazy(|_| {
let settings = ServiceConfig::new(KeepAlive::Os, 0, 0);
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
settings.set_date(&mut buf1);


+ 10
- 10
actix-http/src/error.rs View File

@@ -181,13 +181,13 @@ impl ResponseError for FormError {}
/// `InternalServerError` for `TimerError`
impl ResponseError for TimerError {}

#[cfg(feature = "ssl")]
#[cfg(feature = "openssl")]
/// `InternalServerError` for `openssl::ssl::Error`
impl ResponseError for openssl::ssl::Error {}
impl ResponseError for open_ssl::ssl::Error {}

#[cfg(feature = "ssl")]
#[cfg(feature = "openssl")]
/// `InternalServerError` for `openssl::ssl::HandshakeError`
impl ResponseError for openssl::ssl::HandshakeError<tokio_tcp::TcpStream> {}
impl<T: std::fmt::Debug> ResponseError for open_ssl::ssl::HandshakeError<T> {}

/// Return `BAD_REQUEST` for `de::value::Error`
impl ResponseError for DeError {
@@ -383,12 +383,12 @@ impl ResponseError for PayloadError {
}
}

// /// Return `BadRequest` for `cookie::ParseError`
// impl ResponseError for crate::cookie::ParseError {
// fn error_response(&self) -> Response {
// Response::new(StatusCode::BAD_REQUEST)
// }
// }
/// Return `BadRequest` for `cookie::ParseError`
impl ResponseError for crate::cookie::ParseError {
fn error_response(&self) -> Response {
Response::new(StatusCode::BAD_REQUEST)
}
}

#[derive(Debug, Display, From)]
/// A set of errors that can occur during dispatching http requests


+ 54
- 49
actix-http/src/h1/dispatcher.rs View File

@@ -48,14 +48,11 @@ pub struct Dispatcher<T, S, B, X, U>
where
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: Unpin,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::Future: Unpin,
{
inner: DispatcherState<T, S, B, X, U>,
}
@@ -64,14 +61,11 @@ enum DispatcherState<T, S, B, X, U>
where
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: Unpin,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::Future: Unpin,
{
Normal(InnerDispatcher<T, S, B, X, U>),
Upgrade(U::Future),
@@ -82,14 +76,11 @@ struct InnerDispatcher<T, S, B, X, U>
where
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: Unpin,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::Future: Unpin,
{
service: CloneableService<S>,
expect: CloneableService<X>,
@@ -181,14 +172,11 @@ where
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
S::Future: Unpin,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::Future: Unpin,
{
/// Create http/1 dispatcher.
pub(crate) fn new(
@@ -269,14 +257,11 @@ where
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
S::Future: Unpin,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::Future: Unpin,
{
fn can_read(&self, cx: &mut Context) -> bool {
if self
@@ -312,7 +297,9 @@ where
let len = self.write_buf.len();
let mut written = 0;
while written < len {
match Pin::new(&mut self.io).poll_write(cx, &self.write_buf[written..]) {
match unsafe { Pin::new_unchecked(&mut self.io) }
.poll_write(cx, &self.write_buf[written..])
{
Poll::Ready(Ok(0)) => {
return Err(DispatchError::Io(io::Error::new(
io::ErrorKind::WriteZero,
@@ -383,32 +370,36 @@ where
}
None => None,
},
State::ExpectCall(ref mut fut) => match Pin::new(fut).poll(cx) {
Poll::Ready(Ok(req)) => {
self.send_continue();
self.state = State::ServiceCall(self.service.call(req));
continue;
}
Poll::Ready(Err(e)) => {
let res: Response = e.into().into();
let (res, body) = res.replace_body(());
Some(self.send_response(res, body.into_body())?)
}
Poll::Pending => None,
},
State::ServiceCall(ref mut fut) => match Pin::new(fut).poll(cx) {
Poll::Ready(Ok(res)) => {
let (res, body) = res.into().replace_body(());
self.state = self.send_response(res, body)?;
continue;
State::ExpectCall(ref mut fut) => {
match unsafe { Pin::new_unchecked(fut) }.poll(cx) {
Poll::Ready(Ok(req)) => {
self.send_continue();
self.state = State::ServiceCall(self.service.call(req));
continue;
}
Poll::Ready(Err(e)) => {
let res: Response = e.into().into();
let (res, body) = res.replace_body(());
Some(self.send_response(res, body.into_body())?)
}
Poll::Pending => None,
}
Poll::Ready(Err(e)) => {
let res: Response = e.into().into();
let (res, body) = res.replace_body(());
Some(self.send_response(res, body.into_body())?)
}
State::ServiceCall(ref mut fut) => {
match unsafe { Pin::new_unchecked(fut) }.poll(cx) {
Poll::Ready(Ok(res)) => {
let (res, body) = res.into().replace_body(());
self.state = self.send_response(res, body)?;
continue;
}
Poll::Ready(Err(e)) => {
let res: Response = e.into().into();
let (res, body) = res.replace_body(());
Some(self.send_response(res, body.into_body())?)
}
Poll::Pending => None,
}
Poll::Pending => None,
},
}
State::SendPayload(ref mut stream) => {
loop {
if self.write_buf.len() < HW_BUFFER_SIZE {
@@ -472,7 +463,7 @@ where
// Handle `EXPECT: 100-Continue` header
let req = if req.head().expect() {
let mut task = self.expect.call(req);
match Pin::new(&mut task).poll(cx) {
match unsafe { Pin::new_unchecked(&mut task) }.poll(cx) {
Poll::Ready(Ok(req)) => {
self.send_continue();
req
@@ -491,7 +482,7 @@ where

// Call service
let mut task = self.service.call(req);
match Pin::new(&mut task).poll(cx) {
match unsafe { Pin::new_unchecked(&mut task) }.poll(cx) {
Poll::Ready(Ok(res)) => {
let (res, body) = res.into().replace_body(());
self.send_response(res, body)
@@ -689,26 +680,37 @@ where
}
}

impl<T, S, B, X, U> Unpin for Dispatcher<T, S, B, X, U>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
{
}

impl<T, S, B, X, U> Future for Dispatcher<T, S, B, X, U>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
S::Future: Unpin,
B: MessageBody,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::Future: Unpin,
{
type Output = Result<(), DispatchError>;

#[inline]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
match self.inner {
match self.as_mut().inner {
DispatcherState::Normal(ref mut inner) => {
inner.poll_keepalive(cx)?;

@@ -818,7 +820,7 @@ where
}
}
DispatcherState::Upgrade(ref mut fut) => {
Pin::new(fut).poll(cx).map_err(|e| {
unsafe { Pin::new_unchecked(fut) }.poll(cx).map_err(|e| {
error!("Upgrade handler error: {}", e);
DispatchError::Upgrade
})
@@ -894,7 +896,7 @@ mod tests {
#[test]
fn test_req_parse_err() {
let mut sys = actix_rt::System::new("test");
let _ = sys.block_on(lazy(|| {
let _ = sys.block_on(lazy(|cx| {
let buf = TestBuffer::new("GET /test HTTP/1\r\n\r\n");

let mut h1 = Dispatcher::<_, _, _, _, UpgradeHandler<TestBuffer>>::new(
@@ -907,7 +909,10 @@ mod tests {
None,
None,
);
assert!(h1.poll().is_err());
match Pin::new(&mut h1).poll(cx) {
Poll::Pending => panic!(),
Poll::Ready(res) => assert!(res.is_err()),
}

if let DispatcherState::Normal(ref inner) = h1.inner {
assert!(inner.flags.contains(Flags::READ_DISCONNECT));


+ 15
- 18
actix-http/src/h1/payload.rs View File

@@ -228,26 +228,23 @@ impl Inner {
mod tests {
use super::*;
use actix_rt::Runtime;
use futures::future::{lazy, result};
use futures::future::{poll_fn, ready};

#[test]
fn test_unread_data() {
Runtime::new()
.unwrap()
.block_on(async {
let (_, mut payload) = Payload::create(false);

payload.unread_data(Bytes::from("data"));
assert!(!payload.is_empty());
assert_eq!(payload.len(), 4);

assert_eq!(
Poll::Ready(Some(Bytes::from("data"))),
payload.next_item().await.ok().unwrap()
);

result(())
})
.unwrap();
Runtime::new().unwrap().block_on(async {
let (_, mut payload) = Payload::create(false);

payload.unread_data(Bytes::from("data"));
assert!(!payload.is_empty());
assert_eq!(payload.len(), 4);

assert_eq!(
Bytes::from("data"),
poll_fn(|cx| payload.readany(cx)).await.unwrap().unwrap()
);

ready(())
});
}
}

+ 25
- 70
actix-http/src/h1/service.rs View File

@@ -39,11 +39,7 @@ where
S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Response: Into<Response<B>>,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin,
B: MessageBody,
P: Unpin,
{
/// Create new `HttpService` instance with default config.
pub fn new<F: IntoServiceFactory<S>>(service: F) -> Self {
@@ -81,20 +77,13 @@ where
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
S::InitError: fmt::Debug,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin,
B: MessageBody,
P: Unpin,
{
pub fn expect<X1>(self, expect: X1) -> H1Service<T, P, S, B, X1, U>
where
X1: ServiceFactory<Request = Request, Response = Request>,
X1::Error: Into<Error>,
X1::InitError: fmt::Debug,
X1::Future: Unpin,
X1::Service: Unpin,
<X1::Service as Service>::Future: Unpin,
{
H1Service {
expect,
@@ -111,9 +100,6 @@ where
U1: ServiceFactory<Request = (Request, Framed<T, Codec>), Response = ()>,
U1::Error: fmt::Display,
U1::InitError: fmt::Debug,
U1::Future: Unpin,
U1::Service: Unpin,
<U1::Service as Service>::Future: Unpin,
{
H1Service {
upgrade,
@@ -139,20 +125,13 @@ impl<T, P, S, B, X, U> ServiceFactory for H1Service<T, P, S, B, X, U>
where
T: IoStream,
S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Service: Unpin,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
S::InitError: fmt::Debug,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin,
B: MessageBody,
X: ServiceFactory<Config = SrvConfig, Request = Request, Response = Request>,
X::Error: Into<Error>,
X::InitError: fmt::Debug,
X::Future: Unpin,
X::Service: Unpin,
<X::Service as Service>::Future: Unpin,
U: ServiceFactory<
Config = SrvConfig,
Request = (Request, Framed<T, Codec>),
@@ -160,10 +139,6 @@ where
>,
U::Error: fmt::Display,
U::InitError: fmt::Debug,
U::Future: Unpin,
U::Service: Unpin,
<U::Service as Service>::Future: Unpin,
P: Unpin,
{
type Config = SrvConfig;
type Request = Io<T, P>;
@@ -188,30 +163,24 @@ where
}

#[doc(hidden)]
#[pin_project::pin_project]
pub struct H1ServiceResponse<T, P, S, B, X, U>
where
S: ServiceFactory<Request = Request>,
S::Error: Into<Error>,
S::InitError: fmt::Debug,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin,
X: ServiceFactory<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::InitError: fmt::Debug,
X::Future: Unpin,
X::Service: Unpin,
<X::Service as Service>::Future: Unpin,
U: ServiceFactory<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::InitError: fmt::Debug,
U::Future: Unpin,
U::Service: Unpin,
<U::Service as Service>::Future: Unpin,
P: Unpin,
{
#[pin]
fut: S::Future,
#[pin]
fut_ex: Option<X::Future>,
#[pin]
fut_upg: Option<U::Future>,
expect: Option<X::Service>,
upgrade: Option<U::Service>,
@@ -227,51 +196,45 @@ where
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
S::InitError: fmt::Debug,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin,
B: MessageBody,
X: ServiceFactory<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::InitError: fmt::Debug,
X::Future: Unpin,
X::Service: Unpin,
<X::Service as Service>::Future: Unpin,
U: ServiceFactory<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::InitError: fmt::Debug,
U::Future: Unpin,
U::Service: Unpin,
<U::Service as Service>::Future: Unpin,
P: Unpin,
{
type Output =
Result<H1ServiceHandler<T, P, S::Service, B, X::Service, U::Service>, ()>;

fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let mut this = self.as_mut().project();

if let Some(ref mut fut) = this.fut_ex {
let expect = ready!(Pin::new(fut)
if let Some(fut) = this.fut_ex.as_pin_mut() {
let expect = ready!(fut
.poll(cx)
.map_err(|e| log::error!("Init http service error: {:?}", e)))?;
this.expect = Some(expect);
this.fut_ex.take();
this = self.as_mut().project();
*this.expect = Some(expect);
this.fut_ex.set(None);
}

if let Some(ref mut fut) = this.fut_upg {
let upgrade = ready!(Pin::new(fut)
if let Some(fut) = this.fut_upg.as_pin_mut() {
let upgrade = ready!(fut
.poll(cx)
.map_err(|e| log::error!("Init http service error: {:?}", e)))?;
this.upgrade = Some(upgrade);
this.fut_ex.take();
this = self.as_mut().project();
*this.upgrade = Some(upgrade);
this.fut_ex.set(None);
}

let result = ready!(Pin::new(&mut this.fut)
let result = ready!(this
.fut
.poll(cx)
.map_err(|e| log::error!("Init http service error: {:?}", e)));

Poll::Ready(result.map(|service| {
let this = self.as_mut().project();
H1ServiceHandler::new(
this.cfg.take().unwrap(),
service,
@@ -295,18 +258,14 @@ pub struct H1ServiceHandler<T, P, S, B, X, U> {

impl<T, P, S, B, X, U> H1ServiceHandler<T, P, S, B, X, U>
where
S: Service<Request = Request> + Unpin,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
S::Future: Unpin,
B: MessageBody,
X: Service<Request = Request, Response = Request> + Unpin,
X::Future: Unpin,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()> + Unpin,
U::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
P: Unpin,
{
fn new(
cfg: ServiceConfig,
@@ -329,18 +288,14 @@ where
impl<T, P, S, B, X, U> Service for H1ServiceHandler<T, P, S, B, X, U>
where
T: IoStream,
S: Service<Request = Request> + Unpin,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
S::Future: Unpin,
B: MessageBody,
X: Service<Request = Request, Response = Request> + Unpin,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()> + Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display,
U::Future: Unpin,
P: Unpin,
{
type Request = Io<T, P>;
type Response = ();


+ 2
- 1
actix-http/src/h1/utils.rs View File

@@ -11,6 +11,7 @@ use crate::h1::{Codec, Message};
use crate::response::Response;

/// Send http/1 response
#[pin_project::pin_project]
pub struct SendResponse<T, B> {
res: Option<Message<(Response<()>, BodySize)>>,
body: Option<ResponseBody<B>>,
@@ -34,7 +35,7 @@ where

impl<T, B> Future for SendResponse<T, B>
where
T: AsyncRead + AsyncWrite + Unpin,
T: AsyncRead + AsyncWrite,
B: MessageBody,
{
type Output = Result<Framed<T, Codec>, Error>;


+ 44
- 49
actix-http/src/h2/dispatcher.rs View File

@@ -35,6 +35,7 @@ use crate::response::Response;
const CHUNK_SIZE: usize = 16_384;

/// Dispatcher for HTTP/2 protocol
#[pin_project::pin_project]
pub struct Dispatcher<T: IoStream, S: Service<Request = Request>, B: MessageBody> {
service: CloneableService<S>,
connection: Connection<T, Bytes>,
@@ -46,24 +47,13 @@ pub struct Dispatcher<T: IoStream, S: Service<Request = Request>, B: MessageBody
_t: PhantomData<B>,
}

impl<T, S, B> Unpin for Dispatcher<T, S, B>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
B: MessageBody + 'static,
{
}

impl<T, S, B> Dispatcher<T, S, B>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Error: Into<Error> + 'static,
S::Future: 'static,
S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static,
{
pub(crate) fn new(
@@ -107,9 +97,9 @@ impl<T, S, B> Future for Dispatcher<T, S, B>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Error: Into<Error> + 'static,
S::Future: 'static,
S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static,
{
type Output = Result<(), DispatchError>;
@@ -122,7 +112,7 @@ where
match Pin::new(&mut this.connection).poll_accept(cx) {
Poll::Ready(None) => return Poll::Ready(Ok(())),
Poll::Ready(Some(Err(err))) => return Poll::Ready(Err(err.into())),
Poll::Ready(Some(Ok((req, _)))) => {
Poll::Ready(Some(Ok((req, res)))) => {
// update keep-alive expire
if this.ka_timer.is_some() {
if let Some(expire) = this.config.keep_alive_expire() {
@@ -131,7 +121,6 @@ where
}

let (parts, body) = req.into_parts();
// let b: () = body;
let mut req = Request::with_payload(Payload::<
crate::payload::PayloadStream,
>::H2(
@@ -150,20 +139,20 @@ where
on_connect.set(&mut req.extensions_mut());
}

// tokio_executor::current_thread::spawn(ServiceResponse::<
// S::Future,
// S::Response,
// S::Error,
// B,
// > {
// state: ServiceResponseState::ServiceCall(
// this.service.call(req),
// Some(res),
// ),
// config: this.config.clone(),
// buffer: None,
// _t: PhantomData,
// });
tokio_executor::current_thread::spawn(ServiceResponse::<
S::Future,
S::Response,
S::Error,
B,
> {
state: ServiceResponseState::ServiceCall(
this.service.call(req),
Some(res),
),
config: this.config.clone(),
buffer: None,
_t: PhantomData,
});
}
Poll::Pending => return Poll::Pending,
}
@@ -171,6 +160,7 @@ where
}
}

#[pin_project::pin_project]
struct ServiceResponse<F, I, E, B> {
state: ServiceResponseState<F, B>,
config: ServiceConfig,
@@ -185,9 +175,9 @@ enum ServiceResponseState<F, B> {

impl<F, I, E, B> ServiceResponse<F, I, E, B>
where
F: Future<Output = Result<I, E>> + Unpin,
E: Into<Error> + Unpin + 'static,
I: Into<Response<B>> + Unpin + 'static,
F: Future<Output = Result<I, E>>,
E: Into<Error> + 'static,
I: Into<Response<B>> + 'static,
B: MessageBody + 'static,
{
fn prepare_response(
@@ -253,25 +243,27 @@ where

impl<F, I, E, B> Future for ServiceResponse<F, I, E, B>
where
F: Future<Output = Result<I, E>> + Unpin,
E: Into<Error> + Unpin + 'static,
I: Into<Response<B>> + Unpin + 'static,
F: Future<Output = Result<I, E>>,
E: Into<Error> + 'static,
I: Into<Response<B>> + 'static,
B: MessageBody + 'static,
{
type Output = ();

fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let mut this = self.as_mut().project();

match this.state {
ServiceResponseState::ServiceCall(ref mut call, ref mut send) => {
match Pin::new(call).poll(cx) {
match unsafe { Pin::new_unchecked(call) }.poll(cx) {
Poll::Ready(Ok(res)) => {
let (res, body) = res.into().replace_body(());

let mut send = send.take().unwrap();
let mut size = body.size();
let h2_res = this.prepare_response(res.head(), &mut size);
let h2_res =
self.as_mut().prepare_response(res.head(), &mut size);
this = self.as_mut().project();

let stream = match send.send_response(h2_res, size.is_eof()) {
Err(e) => {
@@ -284,8 +276,9 @@ where
if size.is_eof() {
Poll::Ready(())
} else {
this.state = ServiceResponseState::SendPayload(stream, body);
Pin::new(this).poll(cx)
*this.state =
ServiceResponseState::SendPayload(stream, body);
self.poll(cx)
}
}
Poll::Pending => Poll::Pending,
@@ -295,7 +288,9 @@ where

let mut send = send.take().unwrap();
let mut size = body.size();
let h2_res = this.prepare_response(res.head(), &mut size);
let h2_res =
self.as_mut().prepare_response(res.head(), &mut size);
this = self.as_mut().project();

let stream = match send.send_response(h2_res, size.is_eof()) {
Err(e) => {
@@ -308,11 +303,11 @@ where
if size.is_eof() {
Poll::Ready(())
} else {
this.state = ServiceResponseState::SendPayload(
*this.state = ServiceResponseState::SendPayload(
stream,
body.into_body(),
);
Pin::new(this).poll(cx)
self.poll(cx)
}
}
}
@@ -356,7 +351,7 @@ where
chunk.len(),
CHUNK_SIZE,
));
this.buffer = Some(chunk);
*this.buffer = Some(chunk);
}
Poll::Ready(Some(Err(e))) => {
error!("Response payload stream error: {:?}", e);


+ 27
- 32
actix-http/src/h2/service.rs View File

@@ -37,12 +37,10 @@ pub struct H2Service<T, P, S, B> {
impl<T, P, S, B> H2Service<T, P, S, B>
where
S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Future: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
S::Error: Into<Error> + 'static,
S::Response: Into<Response<B>> + 'static,
<S::Service as Service>::Future: 'static,
B: MessageBody + 'static,
P: Unpin,
{
/// Create new `HttpService` instance.
pub fn new<F: IntoServiceFactory<S>>(service: F) -> Self {
@@ -83,12 +81,10 @@ impl<T, P, S, B> ServiceFactory for H2Service<T, P, S, B>
where
T: IoStream,
S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Future: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
S::Error: Into<Error> + 'static,
S::Response: Into<Response<B>> + 'static,
<S::Service as Service>::Future: 'static,
B: MessageBody + 'static,
P: Unpin,
{
type Config = SrvConfig;
type Request = Io<T, P>;
@@ -109,7 +105,9 @@ where
}

#[doc(hidden)]
#[pin_project::pin_project]
pub struct H2ServiceResponse<T, P, S: ServiceFactory, B> {
#[pin]
fut: S::Future,
cfg: Option<ServiceConfig>,
on_connect: Option<rc::Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
@@ -120,19 +118,18 @@ impl<T, P, S, B> Future for H2ServiceResponse<T, P, S, B>
where
T: IoStream,
S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Future: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
S::Error: Into<Error> + 'static,
S::Response: Into<Response<B>> + 'static,
<S::Service as Service>::Future: 'static,
B: MessageBody + 'static,
P: Unpin,
{
type Output = Result<H2ServiceHandler<T, P, S::Service, B>, S::InitError>;

fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.as_mut().project();

Poll::Ready(ready!(Pin::new(&mut this.fut).poll(cx)).map(|service| {
Poll::Ready(ready!(this.fut.poll(cx)).map(|service| {
let this = self.as_mut().project();
H2ServiceHandler::new(
this.cfg.take().unwrap(),
this.on_connect.clone(),
@@ -153,11 +150,10 @@ pub struct H2ServiceHandler<T, P, S, B> {
impl<T, P, S, B> H2ServiceHandler<T, P, S, B>
where
S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Error: Into<Error> + 'static,
S::Future: 'static,
S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static,
P: Unpin,
{
fn new(
cfg: ServiceConfig,
@@ -177,11 +173,10 @@ impl<T, P, S, B> Service for H2ServiceHandler<T, P, S, B>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> +