1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-24 00:21:08 +01:00

drop unpin constraint

This commit is contained in:
Nikolay Kim 2019-11-19 18:54:19 +06:00
parent 687884fb94
commit 1ffa7d18d3
31 changed files with 2136 additions and 2141 deletions

View File

@ -74,6 +74,7 @@ language-tags = "0.2"
log = "0.4" log = "0.4"
mime = "0.3" mime = "0.3"
percent-encoding = "2.1" percent-encoding = "2.1"
pin-project = "0.4.5"
rand = "0.7" rand = "0.7"
regex = "1.0" regex = "1.0"
serde = "1.0" serde = "1.0"
@ -107,7 +108,7 @@ webpki-roots = { version = "0.18", optional = true }
[dev-dependencies] [dev-dependencies]
actix-rt = "1.0.0-alpha.1" 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-connect = { version = "1.0.0-alpha.1", features=["openssl"] }
actix-http-test = { version = "0.3.0-alpha.1", features=["openssl"] } actix-http-test = { version = "0.3.0-alpha.1", features=["openssl"] }
env_logger = "0.6" env_logger = "0.6"

View File

@ -1,9 +1,9 @@
use std::{env, io}; use std::{env, io};
use actix_http::{error::PayloadError, HttpService, Request, Response}; use actix_http::{Error, HttpService, Request, Response};
use actix_server::Server; use actix_server::Server;
use bytes::BytesMut; use bytes::BytesMut;
use futures::{Future, Stream}; use futures::StreamExt;
use http::header::HeaderValue; use http::header::HeaderValue;
use log::info; use log::info;
@ -17,20 +17,22 @@ fn main() -> io::Result<()> {
.client_timeout(1000) .client_timeout(1000)
.client_disconnect(1000) .client_disconnect(1000)
.finish(|mut req: Request| { .finish(|mut req: Request| {
req.take_payload() async move {
.fold(BytesMut::new(), move |mut body, chunk| { let mut body = BytesMut::new();
body.extend_from_slice(&chunk); while let Some(item) = req.payload().next().await {
Ok::<_, PayloadError>(body) body.extend_from_slice(&item?);
}) }
.and_then(|bytes| {
info!("request body: {:?}", bytes); info!("request body: {:?}", body);
let mut res = Response::Ok(); Ok::<_, Error>(
res.header( Response::Ok()
"x-head", .header(
HeaderValue::from_static("dummy value!"), "x-head",
); HeaderValue::from_static("dummy value!"),
Ok(res.body(bytes)) )
}) .body(body),
)
}
}) })
})? })?
.run() .run()

View File

@ -1,25 +1,22 @@
use std::{env, io}; use std::{env, io};
use actix_http::http::HeaderValue; 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 actix_server::Server;
use bytes::BytesMut; use bytes::BytesMut;
use futures::{Future, Stream}; use futures::StreamExt;
use log::info; use log::info;
fn handle_request(mut req: Request) -> impl Future<Item = Response, Error = Error> { async fn handle_request(mut req: Request) -> Result<Response, Error> {
req.take_payload() let mut body = BytesMut::new();
.fold(BytesMut::new(), move |mut body, chunk| { while let Some(item) = req.payload().next().await {
body.extend_from_slice(&chunk); body.extend_from_slice(&item?)
Ok::<_, PayloadError>(body) }
})
.from_err() info!("request body: {:?}", body);
.and_then(|bytes| { Ok(Response::Ok()
info!("request body: {:?}", bytes); .header("x-head", HeaderValue::from_static("dummy value!"))
let mut res = Response::Ok(); .body(body))
res.header("x-head", HeaderValue::from_static("dummy value!"));
Ok(res.body(bytes))
})
} }
fn main() -> io::Result<()> { fn main() -> io::Result<()> {
@ -28,7 +25,7 @@ fn main() -> io::Result<()> {
Server::build() Server::build()
.bind("echo", "127.0.0.1:8080", || { .bind("echo", "127.0.0.1:8080", || {
HttpService::build().finish(|_req: Request| handle_request(_req)) HttpService::build().finish(handle_request)
})? })?
.run() .run()
} }

View File

@ -5,6 +5,7 @@ use std::{fmt, mem};
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
use futures::Stream; use futures::Stream;
use pin_project::{pin_project, project};
use crate::error::Error; use crate::error::Error;
@ -31,7 +32,7 @@ impl BodySize {
} }
/// Type that provides this trait can be streamed to a peer. /// Type that provides this trait can be streamed to a peer.
pub trait MessageBody: Unpin { pub trait MessageBody {
fn size(&self) -> BodySize; fn size(&self) -> BodySize;
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>>; 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> { pub enum ResponseBody<B> {
Body(B), Body(B),
Other(Body), Other(Body),
@ -106,8 +108,13 @@ impl<B: MessageBody> MessageBody for ResponseBody<B> {
impl<B: MessageBody> Stream for ResponseBody<B> { impl<B: MessageBody> Stream for ResponseBody<B> {
type Item = Result<Bytes, Error>; type Item = Result<Bytes, Error>;
#[project]
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> { 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 impl<S> From<SizedStream<S>> for Body
where where
S: Stream<Item = Result<Bytes, Error>> + Unpin + 'static, S: Stream<Item = Result<Bytes, Error>> + 'static,
{ {
fn from(s: SizedStream<S>) -> Body { fn from(s: SizedStream<S>) -> Body {
Body::from_message(s) Body::from_message(s)
@ -252,7 +259,7 @@ where
impl<S, E> From<BodyStream<S, E>> for Body impl<S, E> From<BodyStream<S, E>> for Body
where where
S: Stream<Item = Result<Bytes, E>> + Unpin + 'static, S: Stream<Item = Result<Bytes, E>> + 'static,
E: Into<Error> + 'static, E: Into<Error> + 'static,
{ {
fn from(s: BodyStream<S, E>) -> Body { fn from(s: BodyStream<S, E>) -> Body {
@ -350,7 +357,9 @@ impl MessageBody for String {
/// Type represent streaming body. /// Type represent streaming body.
/// Response does not contain `content-length` header and appropriate transfer encoding is used. /// Response does not contain `content-length` header and appropriate transfer encoding is used.
#[pin_project]
pub struct BodyStream<S, E> { pub struct BodyStream<S, E> {
#[pin]
stream: S, stream: S,
_t: PhantomData<E>, _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> impl<S, E> MessageBody for BodyStream<S, E>
where where
S: Stream<Item = Result<Bytes, E>> + Unpin, S: Stream<Item = Result<Bytes, E>>,
E: Into<Error>, E: Into<Error>,
{ {
fn size(&self) -> BodySize { fn size(&self) -> BodySize {
@ -385,7 +387,9 @@ where
} }
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> { 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) .poll_next(cx)
.map(|res| res.map(|res| res.map_err(std::convert::Into::into))) .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 /// 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. /// if total size of stream is known. Data get sent as is without using transfer encoding.
#[pin_project]
pub struct SizedStream<S> { pub struct SizedStream<S> {
size: u64, size: u64,
#[pin]
stream: S, stream: S,
} }
@ -409,20 +415,25 @@ where
impl<S> MessageBody for SizedStream<S> impl<S> MessageBody for SizedStream<S>
where where
S: Stream<Item = Result<Bytes, Error>> + Unpin, S: Stream<Item = Result<Bytes, Error>>,
{ {
fn size(&self) -> BodySize { fn size(&self) -> BodySize {
BodySize::Sized64(self.size) BodySize::Sized64(self.size)
} }
fn poll_next(&mut self, cx: &mut Context) -> Poll<Option<Result<Bytes, Error>>> { 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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use actix_http_test::block_on;
use futures::future::{lazy, poll_fn};
impl Body { impl Body {
pub(crate) fn get_ref(&self) -> &[u8] { pub(crate) fn get_ref(&self) -> &[u8] {
@ -450,8 +461,8 @@ mod tests {
assert_eq!("test".size(), BodySize::Sized(4)); assert_eq!("test".size(), BodySize::Sized(4));
assert_eq!( assert_eq!(
"test".poll_next().unwrap(), block_on(poll_fn(|cx| "test".poll_next(cx))).unwrap().ok(),
Async::Ready(Some(Bytes::from("test"))) Some(Bytes::from("test"))
); );
} }
@ -467,8 +478,10 @@ mod tests {
assert_eq!((&b"test"[..]).size(), BodySize::Sized(4)); assert_eq!((&b"test"[..]).size(), BodySize::Sized(4));
assert_eq!( assert_eq!(
(&b"test"[..]).poll_next().unwrap(), block_on(poll_fn(|cx| (&b"test"[..]).poll_next(cx)))
Async::Ready(Some(Bytes::from("test"))) .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").size(), BodySize::Sized(4));
assert_eq!( assert_eq!(
Vec::from("test").poll_next().unwrap(), block_on(poll_fn(|cx| Vec::from("test").poll_next(cx)))
Async::Ready(Some(Bytes::from("test"))) .unwrap()
.ok(),
Some(Bytes::from("test"))
); );
} }
@ -492,8 +507,8 @@ mod tests {
assert_eq!(b.size(), BodySize::Sized(4)); assert_eq!(b.size(), BodySize::Sized(4));
assert_eq!( assert_eq!(
b.poll_next().unwrap(), block_on(poll_fn(|cx| b.poll_next(cx))).unwrap().ok(),
Async::Ready(Some(Bytes::from("test"))) Some(Bytes::from("test"))
); );
} }
@ -505,8 +520,8 @@ mod tests {
assert_eq!(b.size(), BodySize::Sized(4)); assert_eq!(b.size(), BodySize::Sized(4));
assert_eq!( assert_eq!(
b.poll_next().unwrap(), block_on(poll_fn(|cx| b.poll_next(cx))).unwrap().ok(),
Async::Ready(Some(Bytes::from("test"))) Some(Bytes::from("test"))
); );
} }
@ -520,22 +535,22 @@ mod tests {
assert_eq!(b.size(), BodySize::Sized(4)); assert_eq!(b.size(), BodySize::Sized(4));
assert_eq!( assert_eq!(
b.poll_next().unwrap(), block_on(poll_fn(|cx| b.poll_next(cx))).unwrap().ok(),
Async::Ready(Some(Bytes::from("test"))) Some(Bytes::from("test"))
); );
} }
#[test] #[test]
fn test_unit() { fn test_unit() {
assert_eq!(().size(), BodySize::Empty); 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] #[test]
fn test_box() { fn test_box() {
let mut val = Box::new(()); let mut val = Box::new(());
assert_eq!(val.size(), BodySize::Empty); 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] #[test]

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

View File

@ -6,6 +6,7 @@ use actix_codec::{AsyncRead, AsyncWrite, Framed};
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
use futures::future::{err, Either, Future, FutureExt, LocalBoxFuture, Ready}; use futures::future::{err, Either, Future, FutureExt, LocalBoxFuture, Ready};
use h2::client::SendRequest; use h2::client::SendRequest;
use pin_project::{pin_project, project};
use crate::body::MessageBody; use crate::body::MessageBody;
use crate::h1::ClientCodec; use crate::h1::ClientCodec;
@ -42,9 +43,7 @@ pub trait Connection {
fn open_tunnel<H: Into<RequestHeadType>>(self, head: H) -> Self::TunnelFuture; fn open_tunnel<H: Into<RequestHeadType>>(self, head: H) -> Self::TunnelFuture;
} }
pub(crate) trait ConnectionLifetime: pub(crate) trait ConnectionLifetime: AsyncRead + AsyncWrite + 'static {
AsyncRead + AsyncWrite + Unpin + 'static
{
/// Close connection /// Close connection
fn close(&mut self); 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( pub(crate) fn new(
io: ConnectionType<T>, io: ConnectionType<T>,
created: time::Instant, created: time::Instant,
@ -205,24 +204,27 @@ where
} }
} }
#[pin_project]
pub enum EitherIo<A, B> { pub enum EitherIo<A, B> {
A(A), A(#[pin] A),
B(B), B(#[pin] B),
} }
impl<A, B> AsyncRead for EitherIo<A, B> impl<A, B> AsyncRead for EitherIo<A, B>
where where
A: AsyncRead + Unpin, A: AsyncRead,
B: AsyncRead + Unpin, B: AsyncRead,
{ {
#[project]
fn poll_read( fn poll_read(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &mut [u8], buf: &mut [u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
match self.get_mut() { #[project]
EitherIo::A(ref mut val) => Pin::new(val).poll_read(cx, buf), match self.project() {
EitherIo::B(ref mut val) => Pin::new(val).poll_read(cx, buf), 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> impl<A, B> AsyncWrite for EitherIo<A, B>
where where
A: AsyncWrite + Unpin, A: AsyncWrite,
B: AsyncWrite + Unpin, B: AsyncWrite,
{ {
#[project]
fn poll_write( fn poll_write(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context, cx: &mut Context,
buf: &[u8], buf: &[u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
match self.get_mut() { #[project]
EitherIo::A(ref mut val) => Pin::new(val).poll_write(cx, buf), match self.project() {
EitherIo::B(ref mut val) => Pin::new(val).poll_write(cx, buf), 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<()>> { fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
match self.get_mut() { #[project]
EitherIo::A(ref mut val) => Pin::new(val).poll_flush(cx), match self.project() {
EitherIo::B(ref mut val) => Pin::new(val).poll_flush(cx), EitherIo::A(val) => val.poll_flush(cx),
EitherIo::B(val) => val.poll_flush(cx),
} }
} }
#[project]
fn poll_shutdown( fn poll_shutdown(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<io::Result<()>> { ) -> Poll<io::Result<()>> {
match self.get_mut() { #[project]
EitherIo::A(ref mut val) => Pin::new(val).poll_shutdown(cx), match self.project() {
EitherIo::B(ref mut val) => Pin::new(val).poll_shutdown(cx), EitherIo::A(val) => val.poll_shutdown(cx),
EitherIo::B(val) => val.poll_shutdown(cx),
} }
} }
#[project]
fn poll_write_buf<U: Buf>( fn poll_write_buf<U: Buf>(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
@ -275,9 +284,10 @@ where
where where
Self: Sized, Self: Sized,
{ {
match self.get_mut() { #[project]
EitherIo::A(ref mut val) => Pin::new(val).poll_write_buf(cx, buf), match self.project() {
EitherIo::B(ref mut val) => Pin::new(val).poll_write_buf(cx, buf), EitherIo::A(val) => val.poll_write_buf(cx, buf),
EitherIo::B(val) => val.poll_write_buf(cx, buf),
} }
} }
} }

View File

@ -62,8 +62,8 @@ pub struct Connector<T, U> {
_t: PhantomData<U>, _t: PhantomData<U>,
} }
trait Io: AsyncRead + AsyncWrite {} trait Io: AsyncRead + AsyncWrite + Unpin {}
impl<T: AsyncRead + AsyncWrite> Io for T {} impl<T: AsyncRead + AsyncWrite + Unpin> Io for T {}
impl Connector<(), ()> { impl Connector<(), ()> {
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
@ -123,7 +123,6 @@ impl<T, U> Connector<T, U> {
Response = TcpConnection<Uri, U1>, Response = TcpConnection<Uri, U1>,
Error = actix_connect::ConnectError, Error = actix_connect::ConnectError,
> + Clone, > + Clone,
T1::Future: Unpin,
{ {
Connector { Connector {
connector, connector,
@ -222,7 +221,7 @@ where
{ {
let connector = TimeoutService::new( let connector = TimeoutService::new(
self.timeout, 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)) srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
}) })
.map_err(ConnectError::from) .map_err(ConnectError::from)
@ -257,35 +256,33 @@ where
let ssl_service = TimeoutService::new( let ssl_service = TimeoutService::new(
self.timeout, self.timeout,
pipeline( pipeline(
apply_fn( apply_fn(self.connector.clone(), |msg: Connect, srv| {
UnpinWrapper(self.connector.clone()), srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
|msg: Connect, srv| { })
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
},
)
.map_err(ConnectError::from), .map_err(ConnectError::from),
) )
.and_then(match self.ssl { .and_then(match self.ssl {
#[cfg(feature = "openssl")] #[cfg(feature = "openssl")]
SslConnector::Openssl(ssl) => OpensslConnector::service(ssl) SslConnector::Openssl(ssl) => service(
.map(|stream| { OpensslConnector::service(ssl)
let sock = stream.into_parts().0; .map(|stream| {
let h2 = sock let sock = stream.into_parts().0;
.ssl() let h2 = sock
.selected_alpn_protocol() .ssl()
.map(|protos| protos.windows(2).any(|w| w == H2)) .selected_alpn_protocol()
.unwrap_or(false); .map(|protos| protos.windows(2).any(|w| w == H2))
if h2 { .unwrap_or(false);
(Box::new(sock) as Box<dyn Io + Unpin>, Protocol::Http2) if h2 {
} else { (Box::new(sock) as Box<dyn Io>, Protocol::Http2)
(Box::new(sock) as Box<dyn Io + Unpin>, Protocol::Http1) } else {
} (Box::new(sock) as Box<dyn Io>, Protocol::Http1)
}) }
.map_err(ConnectError::from), })
.map_err(ConnectError::from),
),
#[cfg(feature = "rustls")] #[cfg(feature = "rustls")]
SslConnector::Rustls(ssl) => service( SslConnector::Rustls(ssl) => service(
UnpinWrapper(RustlsConnector::service(ssl)) RustlsConnector::service(ssl)
.map_err(ConnectError::from) .map_err(ConnectError::from)
.map(|stream| { .map(|stream| {
let sock = stream.into_parts().0; let sock = stream.into_parts().0;
@ -296,15 +293,9 @@ where
.map(|protos| protos.windows(2).any(|w| w == H2)) .map(|protos| protos.windows(2).any(|w| w == H2))
.unwrap_or(false); .unwrap_or(false);
if h2 { if h2 {
( (Box::new(sock) as Box<dyn Io>, Protocol::Http2)
Box::new(sock) as Box<dyn Io + Unpin>,
Protocol::Http2,
)
} else { } else {
( (Box::new(sock) as Box<dyn Io>, Protocol::Http1)
Box::new(sock) as Box<dyn Io + Unpin>,
Protocol::Http1,
)
} }
}), }),
), ),
@ -317,7 +308,7 @@ where
let tcp_service = TimeoutService::new( let tcp_service = TimeoutService::new(
self.timeout, 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)) srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
}) })
.map_err(ConnectError::from) .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")))] #[cfg(not(any(feature = "openssl", feature = "rustls")))]
mod connect_impl { mod connect_impl {
use std::task::{Context, Poll}; use std::task::{Context, Poll};
@ -396,9 +351,8 @@ mod connect_impl {
pub(crate) struct InnerConnector<T, Io> pub(crate) struct InnerConnector<T, Io>
where where
Io: AsyncRead + AsyncWrite + 'static, Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError> T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
{ {
pub(crate) tcp_pool: ConnectionPool<T, Io>, pub(crate) tcp_pool: ConnectionPool<T, Io>,
@ -406,9 +360,8 @@ mod connect_impl {
impl<T, Io> Clone for InnerConnector<T, Io> impl<T, Io> Clone for InnerConnector<T, Io>
where where
Io: AsyncRead + AsyncWrite + 'static, Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError> T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
@ -422,9 +375,7 @@ mod connect_impl {
where where
Io: AsyncRead + AsyncWrite + Unpin + 'static, Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError> T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T::Future: Unpin,
{ {
type Request = Connect; type Request = Connect;
type Response = IoConnection<Io>; type Response = IoConnection<Io>;
@ -465,8 +416,6 @@ mod connect_impl {
Io2: AsyncRead + AsyncWrite + Unpin + 'static, Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>, T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
T2: Service<Request = Connect, Response = (Io2, 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) tcp_pool: ConnectionPool<T1, Io1>,
pub(crate) ssl_pool: ConnectionPool<T2, Io2>, pub(crate) ssl_pool: ConnectionPool<T2, Io2>,
@ -477,13 +426,9 @@ mod connect_impl {
Io1: AsyncRead + AsyncWrite + Unpin + 'static, Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static, Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError> T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError> T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T1::Future: Unpin,
T2::Future: Unpin,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
InnerConnector { InnerConnector {
@ -498,13 +443,9 @@ mod connect_impl {
Io1: AsyncRead + AsyncWrite + Unpin + 'static, Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static, Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError> T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError> T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T1::Future: Unpin,
T2::Future: Unpin,
{ {
type Request = Connect; type Request = Connect;
type Response = EitherConnection<Io1, Io2>; type Response = EitherConnection<Io1, Io2>;
@ -532,14 +473,14 @@ mod connect_impl {
} }
} }
#[pin_project::pin_project]
pub(crate) struct InnerConnectorResponseA<T, Io1, Io2> pub(crate) struct InnerConnectorResponseA<T, Io1, Io2>
where where
Io1: AsyncRead + AsyncWrite + Unpin + 'static, Io1: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError> T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T::Future: Unpin,
{ {
#[pin]
fut: <ConnectionPool<T, Io1> as Service>::Future, fut: <ConnectionPool<T, Io1> as Service>::Future,
_t: PhantomData<Io2>, _t: PhantomData<Io2>,
} }
@ -547,9 +488,7 @@ mod connect_impl {
impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2> impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2>
where where
T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError> T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T::Future: Unpin,
Io1: AsyncRead + AsyncWrite + Unpin + 'static, Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: 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> pub(crate) struct InnerConnectorResponseB<T, Io1, Io2>
where where
Io2: AsyncRead + AsyncWrite + Unpin + 'static, Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError> T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T::Future: Unpin,
{ {
#[pin]
fut: <ConnectionPool<T, Io2> as Service>::Future, fut: <ConnectionPool<T, Io2> as Service>::Future,
_t: PhantomData<Io1>, _t: PhantomData<Io1>,
} }
@ -578,9 +517,7 @@ mod connect_impl {
impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2> impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2>
where where
T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError> T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T::Future: Unpin,
Io1: AsyncRead + AsyncWrite + Unpin + 'static, Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static, Io2: AsyncRead + AsyncWrite + Unpin + 'static,
{ {

View File

@ -3,8 +3,8 @@ use std::io;
use derive_more::{Display, From}; use derive_more::{Display, From};
use trust_dns_resolver::error::ResolveError; use trust_dns_resolver::error::ResolveError;
#[cfg(feature = "ssl")] #[cfg(feature = "openssl")]
use openssl::ssl::{Error as SslError, HandshakeError}; use open_ssl::ssl::{Error as SslError, HandshakeError};
use crate::error::{Error, ParseError, ResponseError}; use crate::error::{Error, ParseError, ResponseError};
use crate::http::Error as HttpError; use crate::http::Error as HttpError;
@ -18,7 +18,7 @@ pub enum ConnectError {
SslIsNotSupported, SslIsNotSupported,
/// SSL error /// SSL error
#[cfg(feature = "ssl")] #[cfg(feature = "openssl")]
#[display(fmt = "{}", _0)] #[display(fmt = "{}", _0)]
SslError(SslError), 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 { impl<T> From<HandshakeError<T>> for ConnectError {
fn from(err: HandshakeError<T>) -> ConnectError { fn from(err: HandshakeError<T>) -> ConnectError {
match err { match err {

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> impl<T, Io> ConnectionPool<T, Io>
where where
Io: AsyncRead + AsyncWrite + 'static, Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError> T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T::Future: Unpin,
{ {
pub(crate) fn new( pub(crate) fn new(
connector: T, connector: T,
@ -89,9 +87,7 @@ impl<T, Io> Service for ConnectionPool<T, Io>
where where
Io: AsyncRead + AsyncWrite + Unpin + 'static, Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError> T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
+ Unpin
+ 'static, + 'static,
T::Future: Unpin,
{ {
type Request = Connect; type Request = Connect;
type Response = IoConnection<Io>; type Response = IoConnection<Io>;
@ -400,7 +396,7 @@ struct CloseConnection<T> {
impl<T> CloseConnection<T> impl<T> CloseConnection<T>
where where
T: AsyncWrite, T: AsyncWrite + Unpin,
{ {
fn new(io: T, timeout: Duration) -> Self { fn new(io: T, timeout: Duration) -> Self {
CloseConnection { CloseConnection {
@ -416,10 +412,12 @@ where
{ {
type Output = (); type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> { fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {
match Pin::new(&mut self.timeout).poll(cx) { let this = self.get_mut();
match Pin::new(&mut this.timeout).poll(cx) {
Poll::Ready(_) => Poll::Ready(()), 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::Ready(_) => Poll::Ready(()),
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
}, },
@ -429,7 +427,7 @@ where
struct ConnectorPoolSupport<T, Io> struct ConnectorPoolSupport<T, Io>
where where
Io: AsyncRead + AsyncWrite + 'static, Io: AsyncRead + AsyncWrite + Unpin + 'static,
{ {
connector: T, connector: T,
inner: Rc<RefCell<Inner<Io>>>, inner: Rc<RefCell<Inner<Io>>>,
@ -438,14 +436,13 @@ where
impl<T, Io> Future for ConnectorPoolSupport<T, Io> impl<T, Io> Future for ConnectorPoolSupport<T, Io>
where where
Io: AsyncRead + AsyncWrite + Unpin + 'static, Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError> T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>,
+ Unpin, T::Future: 'static,
T::Future: Unpin + 'static,
{ {
type Output = (); type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::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(); let mut inner = this.inner.as_ref().borrow_mut();
inner.waker.register(cx.waker()); inner.waker.register(cx.waker());
@ -512,7 +509,7 @@ where
impl<F, Io> OpenWaitingConnection<F, Io> impl<F, Io> OpenWaitingConnection<F, Io>
where where
F: Future<Output = Result<(Io, Protocol), ConnectError>> + Unpin + 'static, F: Future<Output = Result<(Io, Protocol), ConnectError>> + 'static,
Io: AsyncRead + AsyncWrite + Unpin + 'static, Io: AsyncRead + AsyncWrite + Unpin + 'static,
{ {
fn spawn( fn spawn(
@ -546,13 +543,13 @@ where
impl<F, Io> Future for OpenWaitingConnection<F, Io> impl<F, Io> Future for OpenWaitingConnection<F, Io>
where where
F: Future<Output = Result<(Io, Protocol), ConnectError>> + Unpin, F: Future<Output = Result<(Io, Protocol), ConnectError>>,
Io: AsyncRead + AsyncWrite + Unpin, Io: AsyncRead + AsyncWrite + Unpin,
{ {
type Output = (); type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::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 { if let Some(ref mut h2) = this.h2 {
return match Pin::new(h2).poll(cx) { 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)) => { Poll::Ready(Err(err)) => {
let _ = this.inner.take(); let _ = this.inner.take();
if let Some(rx) = this.rx.take() { if let Some(rx) = this.rx.take() {
@ -596,7 +593,7 @@ where
Poll::Ready(()) Poll::Ready(())
} else { } else {
this.h2 = Some(handshake(io).boxed_local()); this.h2 = Some(handshake(io).boxed_local());
Pin::new(this).poll(cx) unsafe { Pin::new_unchecked(this) }.poll(cx)
} }
} }
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,

View File

@ -277,7 +277,7 @@ mod tests {
fn test_date() { fn test_date() {
let mut rt = System::new("test"); 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 settings = ServiceConfig::new(KeepAlive::Os, 0, 0);
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10); let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
settings.set_date(&mut buf1); settings.set_date(&mut buf1);

View File

@ -181,13 +181,13 @@ impl ResponseError for FormError {}
/// `InternalServerError` for `TimerError` /// `InternalServerError` for `TimerError`
impl ResponseError for TimerError {} impl ResponseError for TimerError {}
#[cfg(feature = "ssl")] #[cfg(feature = "openssl")]
/// `InternalServerError` for `openssl::ssl::Error` /// `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` /// `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` /// Return `BAD_REQUEST` for `de::value::Error`
impl ResponseError for DeError { impl ResponseError for DeError {
@ -383,12 +383,12 @@ impl ResponseError for PayloadError {
} }
} }
// /// Return `BadRequest` for `cookie::ParseError` /// Return `BadRequest` for `cookie::ParseError`
// impl ResponseError for crate::cookie::ParseError { impl ResponseError for crate::cookie::ParseError {
// fn error_response(&self) -> Response { fn error_response(&self) -> Response {
// Response::new(StatusCode::BAD_REQUEST) Response::new(StatusCode::BAD_REQUEST)
// } }
// } }
#[derive(Debug, Display, From)] #[derive(Debug, Display, From)]
/// A set of errors that can occur during dispatching http requests /// A set of errors that can occur during dispatching http requests

View File

@ -48,14 +48,11 @@ pub struct Dispatcher<T, S, B, X, U>
where where
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error>, S::Error: Into<Error>,
S::Future: Unpin,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>, X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>, U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display, U::Error: fmt::Display,
U::Future: Unpin,
{ {
inner: DispatcherState<T, S, B, X, U>, inner: DispatcherState<T, S, B, X, U>,
} }
@ -64,14 +61,11 @@ enum DispatcherState<T, S, B, X, U>
where where
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error>, S::Error: Into<Error>,
S::Future: Unpin,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>, X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>, U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display, U::Error: fmt::Display,
U::Future: Unpin,
{ {
Normal(InnerDispatcher<T, S, B, X, U>), Normal(InnerDispatcher<T, S, B, X, U>),
Upgrade(U::Future), Upgrade(U::Future),
@ -82,14 +76,11 @@ struct InnerDispatcher<T, S, B, X, U>
where where
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error>, S::Error: Into<Error>,
S::Future: Unpin,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>, X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>, U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display, U::Error: fmt::Display,
U::Future: Unpin,
{ {
service: CloneableService<S>, service: CloneableService<S>,
expect: CloneableService<X>, expect: CloneableService<X>,
@ -181,14 +172,11 @@ where
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error>, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::Future: Unpin,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>, X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>, U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display, U::Error: fmt::Display,
U::Future: Unpin,
{ {
/// Create http/1 dispatcher. /// Create http/1 dispatcher.
pub(crate) fn new( pub(crate) fn new(
@ -269,14 +257,11 @@ where
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error>, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::Future: Unpin,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>, X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>, U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display, U::Error: fmt::Display,
U::Future: Unpin,
{ {
fn can_read(&self, cx: &mut Context) -> bool { fn can_read(&self, cx: &mut Context) -> bool {
if self if self
@ -312,7 +297,9 @@ where
let len = self.write_buf.len(); let len = self.write_buf.len();
let mut written = 0; let mut written = 0;
while written < len { 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)) => { Poll::Ready(Ok(0)) => {
return Err(DispatchError::Io(io::Error::new( return Err(DispatchError::Io(io::Error::new(
io::ErrorKind::WriteZero, io::ErrorKind::WriteZero,
@ -383,32 +370,36 @@ where
} }
None => None, None => None,
}, },
State::ExpectCall(ref mut fut) => match Pin::new(fut).poll(cx) { State::ExpectCall(ref mut fut) => {
Poll::Ready(Ok(req)) => { match unsafe { Pin::new_unchecked(fut) }.poll(cx) {
self.send_continue(); Poll::Ready(Ok(req)) => {
self.state = State::ServiceCall(self.service.call(req)); self.send_continue();
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(); State::ServiceCall(ref mut fut) => {
let (res, body) = res.replace_body(()); match unsafe { Pin::new_unchecked(fut) }.poll(cx) {
Some(self.send_response(res, body.into_body())?) 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::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;
}
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::SendPayload(ref mut stream) => { State::SendPayload(ref mut stream) => {
loop { loop {
if self.write_buf.len() < HW_BUFFER_SIZE { if self.write_buf.len() < HW_BUFFER_SIZE {
@ -472,7 +463,7 @@ where
// Handle `EXPECT: 100-Continue` header // Handle `EXPECT: 100-Continue` header
let req = if req.head().expect() { let req = if req.head().expect() {
let mut task = self.expect.call(req); 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)) => { Poll::Ready(Ok(req)) => {
self.send_continue(); self.send_continue();
req req
@ -491,7 +482,7 @@ where
// Call service // Call service
let mut task = self.service.call(req); 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)) => { Poll::Ready(Ok(res)) => {
let (res, body) = res.into().replace_body(()); let (res, body) = res.into().replace_body(());
self.send_response(res, 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> impl<T, S, B, X, U> Future for Dispatcher<T, S, B, X, U>
where where
T: IoStream, T: IoStream,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error>, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::Future: Unpin,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request>, X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::Future: Unpin,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()>, U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display, U::Error: fmt::Display,
U::Future: Unpin,
{ {
type Output = Result<(), DispatchError>; type Output = Result<(), DispatchError>;
#[inline] #[inline]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { 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) => { DispatcherState::Normal(ref mut inner) => {
inner.poll_keepalive(cx)?; inner.poll_keepalive(cx)?;
@ -818,7 +820,7 @@ where
} }
} }
DispatcherState::Upgrade(ref mut fut) => { 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); error!("Upgrade handler error: {}", e);
DispatchError::Upgrade DispatchError::Upgrade
}) })
@ -894,7 +896,7 @@ mod tests {
#[test] #[test]
fn test_req_parse_err() { fn test_req_parse_err() {
let mut sys = actix_rt::System::new("test"); 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 buf = TestBuffer::new("GET /test HTTP/1\r\n\r\n");
let mut h1 = Dispatcher::<_, _, _, _, UpgradeHandler<TestBuffer>>::new( let mut h1 = Dispatcher::<_, _, _, _, UpgradeHandler<TestBuffer>>::new(
@ -907,7 +909,10 @@ mod tests {
None, None,
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 { if let DispatcherState::Normal(ref inner) = h1.inner {
assert!(inner.flags.contains(Flags::READ_DISCONNECT)); assert!(inner.flags.contains(Flags::READ_DISCONNECT));

View File

@ -228,26 +228,23 @@ impl Inner {
mod tests { mod tests {
use super::*; use super::*;
use actix_rt::Runtime; use actix_rt::Runtime;
use futures::future::{lazy, result}; use futures::future::{poll_fn, ready};
#[test] #[test]
fn test_unread_data() { fn test_unread_data() {
Runtime::new() Runtime::new().unwrap().block_on(async {
.unwrap() let (_, mut payload) = Payload::create(false);
.block_on(async {
let (_, mut payload) = Payload::create(false);
payload.unread_data(Bytes::from("data")); payload.unread_data(Bytes::from("data"));
assert!(!payload.is_empty()); assert!(!payload.is_empty());
assert_eq!(payload.len(), 4); assert_eq!(payload.len(), 4);
assert_eq!( assert_eq!(
Poll::Ready(Some(Bytes::from("data"))), Bytes::from("data"),
payload.next_item().await.ok().unwrap() poll_fn(|cx| payload.readany(cx)).await.unwrap().unwrap()
); );
result(()) ready(())
}) });
.unwrap();
} }
} }

View File

@ -39,11 +39,7 @@ where
S::Error: Into<Error>, S::Error: Into<Error>,
S::InitError: fmt::Debug, S::InitError: fmt::Debug,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin,
B: MessageBody, B: MessageBody,
P: Unpin,
{ {
/// Create new `HttpService` instance with default config. /// Create new `HttpService` instance with default config.
pub fn new<F: IntoServiceFactory<S>>(service: F) -> Self { pub fn new<F: IntoServiceFactory<S>>(service: F) -> Self {
@ -81,20 +77,13 @@ where
S::Error: Into<Error>, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::InitError: fmt::Debug, S::InitError: fmt::Debug,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin,
B: MessageBody, B: MessageBody,
P: Unpin,
{ {
pub fn expect<X1>(self, expect: X1) -> H1Service<T, P, S, B, X1, U> pub fn expect<X1>(self, expect: X1) -> H1Service<T, P, S, B, X1, U>
where where
X1: ServiceFactory<Request = Request, Response = Request>, X1: ServiceFactory<Request = Request, Response = Request>,
X1::Error: Into<Error>, X1::Error: Into<Error>,
X1::InitError: fmt::Debug, X1::InitError: fmt::Debug,
X1::Future: Unpin,
X1::Service: Unpin,
<X1::Service as Service>::Future: Unpin,
{ {
H1Service { H1Service {
expect, expect,
@ -111,9 +100,6 @@ where
U1: ServiceFactory<Request = (Request, Framed<T, Codec>), Response = ()>, U1: ServiceFactory<Request = (Request, Framed<T, Codec>), Response = ()>,
U1::Error: fmt::Display, U1::Error: fmt::Display,
U1::InitError: fmt::Debug, U1::InitError: fmt::Debug,
U1::Future: Unpin,
U1::Service: Unpin,
<U1::Service as Service>::Future: Unpin,
{ {
H1Service { H1Service {
upgrade, upgrade,
@ -139,20 +125,13 @@ impl<T, P, S, B, X, U> ServiceFactory for H1Service<T, P, S, B, X, U>
where where
T: IoStream, T: IoStream,
S: ServiceFactory<Config = SrvConfig, Request = Request>, S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Service: Unpin,
S::Error: Into<Error>, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::InitError: fmt::Debug, S::InitError: fmt::Debug,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin,
B: MessageBody, B: MessageBody,
X: ServiceFactory<Config = SrvConfig, Request = Request, Response = Request>, X: ServiceFactory<Config = SrvConfig, Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::InitError: fmt::Debug, X::InitError: fmt::Debug,
X::Future: Unpin,
X::Service: Unpin,
<X::Service as Service>::Future: Unpin,
U: ServiceFactory< U: ServiceFactory<
Config = SrvConfig, Config = SrvConfig,
Request = (Request, Framed<T, Codec>), Request = (Request, Framed<T, Codec>),
@ -160,10 +139,6 @@ where
>, >,
U::Error: fmt::Display, U::Error: fmt::Display,
U::InitError: fmt::Debug, U::InitError: fmt::Debug,
U::Future: Unpin,
U::Service: Unpin,
<U::Service as Service>::Future: Unpin,
P: Unpin,
{ {
type Config = SrvConfig; type Config = SrvConfig;
type Request = Io<T, P>; type Request = Io<T, P>;
@ -188,30 +163,24 @@ where
} }
#[doc(hidden)] #[doc(hidden)]
#[pin_project::pin_project]
pub struct H1ServiceResponse<T, P, S, B, X, U> pub struct H1ServiceResponse<T, P, S, B, X, U>
where where
S: ServiceFactory<Request = Request>, S: ServiceFactory<Request = Request>,
S::Error: Into<Error>, S::Error: Into<Error>,
S::InitError: fmt::Debug, S::InitError: fmt::Debug,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin,
X: ServiceFactory<Request = Request, Response = Request>, X: ServiceFactory<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::InitError: fmt::Debug, 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: ServiceFactory<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display, U::Error: fmt::Display,
U::InitError: fmt::Debug, U::InitError: fmt::Debug,
U::Future: Unpin,
U::Service: Unpin,
<U::Service as Service>::Future: Unpin,
P: Unpin,
{ {
#[pin]
fut: S::Future, fut: S::Future,
#[pin]
fut_ex: Option<X::Future>, fut_ex: Option<X::Future>,
#[pin]
fut_upg: Option<U::Future>, fut_upg: Option<U::Future>,
expect: Option<X::Service>, expect: Option<X::Service>,
upgrade: Option<U::Service>, upgrade: Option<U::Service>,
@ -227,51 +196,45 @@ where
S::Error: Into<Error>, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::InitError: fmt::Debug, S::InitError: fmt::Debug,
S::Future: Unpin,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin,
B: MessageBody, B: MessageBody,
X: ServiceFactory<Request = Request, Response = Request>, X: ServiceFactory<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::InitError: fmt::Debug, 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: ServiceFactory<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Error: fmt::Display, U::Error: fmt::Display,
U::InitError: fmt::Debug, U::InitError: fmt::Debug,
U::Future: Unpin,
U::Service: Unpin,
<U::Service as Service>::Future: Unpin,
P: Unpin,
{ {
type Output = type Output =
Result<H1ServiceHandler<T, P, S::Service, B, X::Service, U::Service>, ()>; Result<H1ServiceHandler<T, P, S::Service, B, X::Service, U::Service>, ()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut(); let mut this = self.as_mut().project();
if let Some(ref mut fut) = this.fut_ex { if let Some(fut) = this.fut_ex.as_pin_mut() {
let expect = ready!(Pin::new(fut) let expect = ready!(fut
.poll(cx) .poll(cx)
.map_err(|e| log::error!("Init http service error: {:?}", e)))?; .map_err(|e| log::error!("Init http service error: {:?}", e)))?;
this.expect = Some(expect); this = self.as_mut().project();
this.fut_ex.take(); *this.expect = Some(expect);
this.fut_ex.set(None);
} }
if let Some(ref mut fut) = this.fut_upg { if let Some(fut) = this.fut_upg.as_pin_mut() {
let upgrade = ready!(Pin::new(fut) let upgrade = ready!(fut
.poll(cx) .poll(cx)
.map_err(|e| log::error!("Init http service error: {:?}", e)))?; .map_err(|e| log::error!("Init http service error: {:?}", e)))?;
this.upgrade = Some(upgrade); this = self.as_mut().project();
this.fut_ex.take(); *this.upgrade = Some(upgrade);
this.fut_ex.set(None);
} }
let result = ready!(Pin::new(&mut this.fut) let result = ready!(this
.fut
.poll(cx) .poll(cx)
.map_err(|e| log::error!("Init http service error: {:?}", e))); .map_err(|e| log::error!("Init http service error: {:?}", e)));
Poll::Ready(result.map(|service| { Poll::Ready(result.map(|service| {
let this = self.as_mut().project();
H1ServiceHandler::new( H1ServiceHandler::new(
this.cfg.take().unwrap(), this.cfg.take().unwrap(),
service, 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> impl<T, P, S, B, X, U> H1ServiceHandler<T, P, S, B, X, U>
where where
S: Service<Request = Request> + Unpin, S: Service<Request = Request>,
S::Error: Into<Error>, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::Future: Unpin,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request> + Unpin, X: Service<Request = Request, Response = Request>,
X::Future: Unpin,
X::Error: Into<Error>, X::Error: Into<Error>,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()> + Unpin, U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U::Future: Unpin,
U::Error: fmt::Display, U::Error: fmt::Display,
P: Unpin,
{ {
fn new( fn new(
cfg: ServiceConfig, cfg: ServiceConfig,
@ -329,18 +288,14 @@ where
impl<T, P, S, B, X, U> Service for H1ServiceHandler<T, P, S, B, X, U> impl<T, P, S, B, X, U> Service for H1ServiceHandler<T, P, S, B, X, U>
where where
T: IoStream, T: IoStream,
S: Service<Request = Request> + Unpin, S: Service<Request = Request>,
S::Error: Into<Error>, S::Error: Into<Error>,
S::Response: Into<Response<B>>, S::Response: Into<Response<B>>,
S::Future: Unpin,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request> + Unpin, X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::Future: Unpin, U: Service<Request = (Request, Framed<T, Codec>), Response = ()>,
U: Service<Request = (Request, Framed<T, Codec>), Response = ()> + Unpin,
U::Error: fmt::Display, U::Error: fmt::Display,
U::Future: Unpin,
P: Unpin,
{ {
type Request = Io<T, P>; type Request = Io<T, P>;
type Response = (); type Response = ();

View File

@ -11,6 +11,7 @@ use crate::h1::{Codec, Message};
use crate::response::Response; use crate::response::Response;
/// Send http/1 response /// Send http/1 response
#[pin_project::pin_project]
pub struct SendResponse<T, B> { pub struct SendResponse<T, B> {
res: Option<Message<(Response<()>, BodySize)>>, res: Option<Message<(Response<()>, BodySize)>>,
body: Option<ResponseBody<B>>, body: Option<ResponseBody<B>>,
@ -34,7 +35,7 @@ where
impl<T, B> Future for SendResponse<T, B> impl<T, B> Future for SendResponse<T, B>
where where
T: AsyncRead + AsyncWrite + Unpin, T: AsyncRead + AsyncWrite,
B: MessageBody, B: MessageBody,
{ {
type Output = Result<Framed<T, Codec>, Error>; type Output = Result<Framed<T, Codec>, Error>;

View File

@ -35,6 +35,7 @@ use crate::response::Response;
const CHUNK_SIZE: usize = 16_384; const CHUNK_SIZE: usize = 16_384;
/// Dispatcher for HTTP/2 protocol /// Dispatcher for HTTP/2 protocol
#[pin_project::pin_project]
pub struct Dispatcher<T: IoStream, S: Service<Request = Request>, B: MessageBody> { pub struct Dispatcher<T: IoStream, S: Service<Request = Request>, B: MessageBody> {
service: CloneableService<S>, service: CloneableService<S>,
connection: Connection<T, Bytes>, connection: Connection<T, Bytes>,
@ -46,24 +47,13 @@ pub struct Dispatcher<T: IoStream, S: Service<Request = Request>, B: MessageBody
_t: PhantomData<B>, _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> impl<T, S, B> Dispatcher<T, S, B>
where where
T: IoStream, T: IoStream,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Future: Unpin + 'static, S::Future: 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
{ {
pub(crate) fn new( pub(crate) fn new(
@ -107,9 +97,9 @@ impl<T, S, B> Future for Dispatcher<T, S, B>
where where
T: IoStream, T: IoStream,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Future: Unpin + 'static, S::Future: 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
{ {
type Output = Result<(), DispatchError>; type Output = Result<(), DispatchError>;
@ -122,7 +112,7 @@ where
match Pin::new(&mut this.connection).poll_accept(cx) { match Pin::new(&mut this.connection).poll_accept(cx) {
Poll::Ready(None) => return Poll::Ready(Ok(())), Poll::Ready(None) => return Poll::Ready(Ok(())),
Poll::Ready(Some(Err(err))) => return Poll::Ready(Err(err.into())), 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 // update keep-alive expire
if this.ka_timer.is_some() { if this.ka_timer.is_some() {
if let Some(expire) = this.config.keep_alive_expire() { if let Some(expire) = this.config.keep_alive_expire() {
@ -131,7 +121,6 @@ where
} }
let (parts, body) = req.into_parts(); let (parts, body) = req.into_parts();
// let b: () = body;
let mut req = Request::with_payload(Payload::< let mut req = Request::with_payload(Payload::<
crate::payload::PayloadStream, crate::payload::PayloadStream,
>::H2( >::H2(
@ -150,20 +139,20 @@ where
on_connect.set(&mut req.extensions_mut()); on_connect.set(&mut req.extensions_mut());
} }
// tokio_executor::current_thread::spawn(ServiceResponse::< tokio_executor::current_thread::spawn(ServiceResponse::<
// S::Future, S::Future,
// S::Response, S::Response,
// S::Error, S::Error,
// B, B,
// > { > {
// state: ServiceResponseState::ServiceCall( state: ServiceResponseState::ServiceCall(
// this.service.call(req), this.service.call(req),
// Some(res), Some(res),
// ), ),
// config: this.config.clone(), config: this.config.clone(),
// buffer: None, buffer: None,
// _t: PhantomData, _t: PhantomData,
// }); });
} }
Poll::Pending => return Poll::Pending, Poll::Pending => return Poll::Pending,
} }
@ -171,6 +160,7 @@ where
} }
} }
#[pin_project::pin_project]
struct ServiceResponse<F, I, E, B> { struct ServiceResponse<F, I, E, B> {
state: ServiceResponseState<F, B>, state: ServiceResponseState<F, B>,
config: ServiceConfig, config: ServiceConfig,
@ -185,9 +175,9 @@ enum ServiceResponseState<F, B> {
impl<F, I, E, B> ServiceResponse<F, I, E, B> impl<F, I, E, B> ServiceResponse<F, I, E, B>
where where
F: Future<Output = Result<I, E>> + Unpin, F: Future<Output = Result<I, E>>,
E: Into<Error> + Unpin + 'static, E: Into<Error> + 'static,
I: Into<Response<B>> + Unpin + 'static, I: Into<Response<B>> + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
{ {
fn prepare_response( fn prepare_response(
@ -253,25 +243,27 @@ where
impl<F, I, E, B> Future for ServiceResponse<F, I, E, B> impl<F, I, E, B> Future for ServiceResponse<F, I, E, B>
where where
F: Future<Output = Result<I, E>> + Unpin, F: Future<Output = Result<I, E>>,
E: Into<Error> + Unpin + 'static, E: Into<Error> + 'static,
I: Into<Response<B>> + Unpin + 'static, I: Into<Response<B>> + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
{ {
type Output = (); type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut(); let mut this = self.as_mut().project();
match this.state { match this.state {
ServiceResponseState::ServiceCall(ref mut call, ref mut send) => { 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)) => { Poll::Ready(Ok(res)) => {
let (res, body) = res.into().replace_body(()); let (res, body) = res.into().replace_body(());
let mut send = send.take().unwrap(); let mut send = send.take().unwrap();
let mut size = body.size(); 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()) { let stream = match send.send_response(h2_res, size.is_eof()) {
Err(e) => { Err(e) => {
@ -284,8 +276,9 @@ where
if size.is_eof() { if size.is_eof() {
Poll::Ready(()) Poll::Ready(())
} else { } else {
this.state = ServiceResponseState::SendPayload(stream, body); *this.state =
Pin::new(this).poll(cx) ServiceResponseState::SendPayload(stream, body);
self.poll(cx)
} }
} }
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
@ -295,7 +288,9 @@ where
let mut send = send.take().unwrap(); let mut send = send.take().unwrap();
let mut size = body.size(); 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()) { let stream = match send.send_response(h2_res, size.is_eof()) {
Err(e) => { Err(e) => {
@ -308,11 +303,11 @@ where
if size.is_eof() { if size.is_eof() {
Poll::Ready(()) Poll::Ready(())
} else { } else {
this.state = ServiceResponseState::SendPayload( *this.state = ServiceResponseState::SendPayload(
stream, stream,
body.into_body(), body.into_body(),
); );
Pin::new(this).poll(cx) self.poll(cx)
} }
} }
} }
@ -356,7 +351,7 @@ where
chunk.len(), chunk.len(),
CHUNK_SIZE, CHUNK_SIZE,
)); ));
this.buffer = Some(chunk); *this.buffer = Some(chunk);
} }
Poll::Ready(Some(Err(e))) => { Poll::Ready(Some(Err(e))) => {
error!("Response payload stream error: {:?}", e); error!("Response payload stream error: {:?}", e);

View File

@ -37,12 +37,10 @@ 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: ServiceFactory<Config = SrvConfig, Request = Request>, S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
S::Future: Unpin, <S::Service as Service>::Future: 'static,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
P: Unpin,
{ {
/// Create new `HttpService` instance. /// Create new `HttpService` instance.
pub fn new<F: IntoServiceFactory<S>>(service: F) -> Self { 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 where
T: IoStream, T: IoStream,
S: ServiceFactory<Config = SrvConfig, Request = Request>, S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
S::Future: Unpin, <S::Service as Service>::Future: 'static,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
P: Unpin,
{ {
type Config = SrvConfig; type Config = SrvConfig;
type Request = Io<T, P>; type Request = Io<T, P>;
@ -109,7 +105,9 @@ where
} }
#[doc(hidden)] #[doc(hidden)]
#[pin_project::pin_project]
pub struct H2ServiceResponse<T, P, S: ServiceFactory, B> { pub struct H2ServiceResponse<T, P, S: ServiceFactory, B> {
#[pin]
fut: S::Future, fut: S::Future,
cfg: Option<ServiceConfig>, cfg: Option<ServiceConfig>,
on_connect: Option<rc::Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>, 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 where
T: IoStream, T: IoStream,
S: ServiceFactory<Config = SrvConfig, Request = Request>, S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
S::Future: Unpin, <S::Service as Service>::Future: 'static,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
P: Unpin,
{ {
type Output = Result<H2ServiceHandler<T, P, S::Service, B>, S::InitError>; type Output = Result<H2ServiceHandler<T, P, S::Service, B>, S::InitError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut(); 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( H2ServiceHandler::new(
this.cfg.take().unwrap(), this.cfg.take().unwrap(),
this.on_connect.clone(), 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> impl<T, P, S, B> H2ServiceHandler<T, P, S, B>
where where
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Future: Unpin + 'static, S::Future: 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
P: Unpin,
{ {
fn new( fn new(
cfg: ServiceConfig, cfg: ServiceConfig,
@ -177,11 +173,10 @@ impl<T, P, S, B> Service for H2ServiceHandler<T, P, S, B>
where where
T: IoStream, T: IoStream,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Future: Unpin + 'static, S::Future: 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
P: Unpin,
{ {
type Request = Io<T, P>; type Request = Io<T, P>;
type Response = (); type Response = ();
@ -235,9 +230,9 @@ pub struct H2ServiceHandlerResponse<T, S, B>
where where
T: IoStream, T: IoStream,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Future: Unpin + 'static, S::Future: 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
{ {
state: State<T, S, B>, state: State<T, S, B>,
@ -247,9 +242,9 @@ impl<T, S, B> Future for H2ServiceHandlerResponse<T, S, B>
where where
T: IoStream, T: IoStream,
S: Service<Request = Request>, S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Future: Unpin + 'static, S::Future: 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
B: MessageBody, B: MessageBody,
{ {
type Output = Result<(), DispatchError>; type Output = Result<(), DispatchError>;

View File

@ -80,6 +80,11 @@ impl<P> Request<P> {
) )
} }
/// Get request's payload
pub fn payload(&mut self) -> &mut Payload<P> {
&mut self.payload
}
/// Get request's payload /// Get request's payload
pub fn take_payload(&mut self) -> Payload<P> { pub fn take_payload(&mut self) -> Payload<P> {
std::mem::replace(&mut self.payload, Payload::None) std::mem::replace(&mut self.payload, Payload::None)

View File

@ -635,8 +635,8 @@ impl ResponseBuilder {
/// `ResponseBuilder` can not be used after this call. /// `ResponseBuilder` can not be used after this call.
pub fn streaming<S, E>(&mut self, stream: S) -> Response pub fn streaming<S, E>(&mut self, stream: S) -> Response
where where
S: Stream<Item = Result<Bytes, E>> + Unpin + 'static, S: Stream<Item = Result<Bytes, E>> + 'static,
E: Into<Error> + Unpin + 'static, E: Into<Error> + 'static,
{ {
self.body(Body::from_message(BodyStream::new(stream))) self.body(Body::from_message(BodyStream::new(stream)))
} }

View File

@ -11,6 +11,7 @@ use actix_service::{IntoServiceFactory, Service, ServiceFactory};
use bytes::{Buf, BufMut, Bytes, BytesMut}; use bytes::{Buf, BufMut, Bytes, BytesMut};
use futures::{ready, Future}; use futures::{ready, Future};
use h2::server::{self, Handshake}; use h2::server::{self, Handshake};
use pin_project::{pin_project, project};
use crate::body::MessageBody; use crate::body::MessageBody;
use crate::builder::HttpServiceBuilder; use crate::builder::HttpServiceBuilder;
@ -35,12 +36,10 @@ pub struct HttpService<T, P, S, B, X = h1::ExpectHandler, U = h1::UpgradeHandler
impl<T, S, B> HttpService<T, (), S, B> impl<T, S, B> HttpService<T, (), S, B>
where where
S: ServiceFactory<Config = SrvConfig, Request = Request>, S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::InitError: fmt::Debug, S::InitError: fmt::Debug,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
S::Future: Unpin, <S::Service as Service>::Future: 'static,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
{ {
/// Create builder for `HttpService` instance. /// Create builder for `HttpService` instance.
@ -52,14 +51,11 @@ where
impl<T, P, S, B> HttpService<T, P, S, B> impl<T, P, S, B> HttpService<T, P, S, B>
where where
S: ServiceFactory<Config = SrvConfig, Request = Request>, S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::InitError: fmt::Debug, S::InitError: fmt::Debug,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
S::Future: Unpin, <S::Service as Service>::Future: 'static,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
P: Unpin,
{ {
/// Create new `HttpService` instance. /// Create new `HttpService` instance.
pub fn new<F: IntoServiceFactory<S>>(service: F) -> Self { pub fn new<F: IntoServiceFactory<S>>(service: F) -> Self {
@ -94,14 +90,11 @@ where
impl<T, P, S, B, X, U> HttpService<T, P, S, B, X, U> impl<T, P, S, B, X, U> HttpService<T, P, S, B, X, U>
where where
S: ServiceFactory<Config = SrvConfig, Request = Request>, S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::InitError: fmt::Debug, S::InitError: fmt::Debug,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
S::Future: Unpin, <S::Service as Service>::Future: 'static,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody, B: MessageBody,
P: Unpin,
{ {
/// Provide service for `EXPECT: 100-Continue` support. /// Provide service for `EXPECT: 100-Continue` support.
/// ///
@ -113,9 +106,7 @@ where
X1: ServiceFactory<Config = SrvConfig, Request = Request, Response = Request>, X1: ServiceFactory<Config = SrvConfig, Request = Request, Response = Request>,
X1::Error: Into<Error>, X1::Error: Into<Error>,
X1::InitError: fmt::Debug, X1::InitError: fmt::Debug,
X1::Future: Unpin, <X1::Service as Service>::Future: 'static,
X1::Service: Unpin,
<X1::Service as Service>::Future: Unpin + 'static,
{ {
HttpService { HttpService {
expect, expect,
@ -140,9 +131,7 @@ where
>, >,
U1::Error: fmt::Display, U1::Error: fmt::Display,
U1::InitError: fmt::Debug, U1::InitError: fmt::Debug,
U1::Future: Unpin, <U1::Service as Service>::Future: 'static,
U1::Service: Unpin,
<U1::Service as Service>::Future: Unpin + 'static,
{ {
HttpService { HttpService {
upgrade, upgrade,
@ -166,22 +155,17 @@ where
impl<T, P, S, B, X, U> ServiceFactory for HttpService<T, P, S, B, X, U> impl<T, P, S, B, X, U> ServiceFactory for HttpService<T, P, S, B, X, U>
where where
T: IoStream + Unpin, T: IoStream,
S: ServiceFactory<Config = SrvConfig, Request = Request>, S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Service: Unpin, S::Error: Into<Error> + 'static,
S::Error: Into<Error> + Unpin + 'static,
S::InitError: fmt::Debug, S::InitError: fmt::Debug,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
S::Future: Unpin, <S::Service as Service>::Future: 'static,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
X: ServiceFactory<Config = SrvConfig, Request = Request, Response = Request>, X: ServiceFactory<Config = SrvConfig, Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::InitError: fmt::Debug, X::InitError: fmt::Debug,
X::Future: Unpin, <X::Service as Service>::Future: 'static,
X::Service: Unpin,
<X::Service as Service>::Future: Unpin + 'static,
U: ServiceFactory< U: ServiceFactory<
Config = SrvConfig, Config = SrvConfig,
Request = (Request, Framed<T, h1::Codec>), Request = (Request, Framed<T, h1::Codec>),
@ -189,10 +173,7 @@ where
>, >,
U::Error: fmt::Display, U::Error: fmt::Display,
U::InitError: fmt::Debug, U::InitError: fmt::Debug,
U::Future: Unpin, <U::Service as Service>::Future: 'static,
U::Service: Unpin,
<U::Service as Service>::Future: Unpin + 'static,
P: Unpin,
{ {
type Config = SrvConfig; type Config = SrvConfig;
type Request = ServerIo<T, P>; type Request = ServerIo<T, P>;
@ -217,6 +198,7 @@ where
} }
#[doc(hidden)] #[doc(hidden)]
#[pin_project]
pub struct HttpServiceResponse< pub struct HttpServiceResponse<
T, T,
P, P,
@ -225,8 +207,11 @@ pub struct HttpServiceResponse<
X: ServiceFactory, X: ServiceFactory,
U: ServiceFactory, U: ServiceFactory,
> { > {
#[pin]
fut: S::Future, fut: S::Future,
#[pin]
fut_ex: Option<X::Future>, fut_ex: Option<X::Future>,
#[pin]
fut_upg: Option<U::Future>, fut_upg: Option<U::Future>,
expect: Option<X::Service>, expect: Option<X::Service>,
upgrade: Option<U::Service>, upgrade: Option<U::Service>,
@ -239,53 +224,50 @@ impl<T, P, S, B, X, U> Future for HttpServiceResponse<T, P, S, B, X, U>
where where
T: IoStream, T: IoStream,
S: ServiceFactory<Request = Request>, S: ServiceFactory<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::InitError: fmt::Debug, S::InitError: fmt::Debug,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
S::Future: Unpin, <S::Service as Service>::Future: 'static,
S::Service: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
X: ServiceFactory<Request = Request, Response = Request>, X: ServiceFactory<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::InitError: fmt::Debug, X::InitError: fmt::Debug,
X::Future: Unpin, <X::Service as Service>::Future: 'static,
X::Service: Unpin,
<X::Service as Service>::Future: Unpin + 'static,
U: ServiceFactory<Request = (Request, Framed<T, h1::Codec>), Response = ()>, U: ServiceFactory<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
U::Error: fmt::Display, U::Error: fmt::Display,
U::InitError: fmt::Debug, U::InitError: fmt::Debug,
U::Future: Unpin, <U::Service as Service>::Future: 'static,
U::Service: Unpin,
<U::Service as Service>::Future: Unpin + 'static,
P: Unpin,
{ {
type Output = type Output =
Result<HttpServiceHandler<T, P, S::Service, B, X::Service, U::Service>, ()>; Result<HttpServiceHandler<T, P, S::Service, B, X::Service, U::Service>, ()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut(); let mut this = self.as_mut().project();
if let Some(ref mut fut) = this.fut_ex { if let Some(fut) = this.fut_ex.as_pin_mut() {
let expect = ready!(Pin::new(fut) let expect = ready!(fut
.poll(cx) .poll(cx)
.map_err(|e| log::error!("Init http service error: {:?}", e)))?; .map_err(|e| log::error!("Init http service error: {:?}", e)))?;
this.expect = Some(expect); this = self.as_mut().project();
this.fut_ex.take(); *this.expect = Some(expect);
this.fut_ex.set(None);
} }
if let Some(ref mut fut) = this.fut_upg { if let Some(fut) = this.fut_upg.as_pin_mut() {
let upgrade = ready!(Pin::new(fut) let upgrade = ready!(fut
.poll(cx) .poll(cx)
.map_err(|e| log::error!("Init http service error: {:?}", e)))?; .map_err(|e| log::error!("Init http service error: {:?}", e)))?;
this.upgrade = Some(upgrade); this = self.as_mut().project();
this.fut_ex.take(); *this.upgrade = Some(upgrade);
this.fut_ex.set(None);
} }
let result = ready!(Pin::new(&mut this.fut) let result = ready!(this
.fut
.poll(cx) .poll(cx)
.map_err(|e| log::error!("Init http service error: {:?}", e))); .map_err(|e| log::error!("Init http service error: {:?}", e)));
Poll::Ready(result.map(|service| { Poll::Ready(result.map(|service| {
let this = self.as_mut().project();
HttpServiceHandler::new( HttpServiceHandler::new(
this.cfg.take().unwrap(), this.cfg.take().unwrap(),
service, service,
@ -309,19 +291,15 @@ pub struct HttpServiceHandler<T, P, S, B, X, U> {
impl<T, P, S, B, X, U> HttpServiceHandler<T, P, S, B, X, U> impl<T, P, S, B, X, U> HttpServiceHandler<T, P, S, B, X, U>
where where
S: Service<Request = Request> + Unpin, S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Future: 'static, S::Future: 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
S::Future: Unpin,
B: MessageBody + 'static, B: MessageBody + 'static,
X: Service<Request = Request, Response = Request> + Unpin, X: Service<Request = Request, Response = Request>,
X::Future: Unpin,
X::Error: Into<Error>, X::Error: Into<Error>,
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()> + Unpin, U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
U::Future: Unpin,
U::Error: fmt::Display, U::Error: fmt::Display,
P: Unpin,
{ {
fn new( fn new(
cfg: ServiceConfig, cfg: ServiceConfig,
@ -343,19 +321,16 @@ where
impl<T, P, S, B, X, U> Service for HttpServiceHandler<T, P, S, B, X, U> impl<T, P, S, B, X, U> Service for HttpServiceHandler<T, P, S, B, X, U>
where where
T: IoStream + Unpin, T: IoStream,
S: Service<Request = Request> + Unpin, S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Future: Unpin + 'static, S::Future: 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
X: Service<Request = Request, Response = Request> + Unpin, X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::Future: Unpin, U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()> + Unpin,
U::Error: fmt::Display, U::Error: fmt::Display,
U::Future: Unpin,
P: Unpin,
{ {
type Request = ServerIo<T, P>; type Request = ServerIo<T, P>;
type Response = (); type Response = ();
@ -442,22 +417,21 @@ where
} }
} }
#[pin_project]
enum State<T, S, B, X, U> enum State<T, S, B, X, U>
where where
S: Service<Request = Request> + Unpin, S: Service<Request = Request>,
S::Future: Unpin + 'static, S::Future: 'static,
S::Error: Into<Error>, S::Error: Into<Error>,
T: IoStream + Unpin, T: IoStream,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request> + Unpin, X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::Future: Unpin, U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()> + Unpin,
U::Error: fmt::Display, U::Error: fmt::Display,
U::Future: Unpin,
{ {
H1(h1::Dispatcher<T, S, B, X, U>), H1(#[pin] h1::Dispatcher<T, S, B, X, U>),
H2(Dispatcher<Io<T>, S, B>), H2(#[pin] Dispatcher<Io<T>, S, B>),
Unknown( Unknown(
Option<( Option<(
T, T,
@ -480,21 +454,21 @@ where
), ),
} }
#[pin_project]
pub struct HttpServiceHandlerResponse<T, S, B, X, U> pub struct HttpServiceHandlerResponse<T, S, B, X, U>
where where
T: IoStream + Unpin, T: IoStream,
S: Service<Request = Request> + Unpin, S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Future: Unpin + 'static, S::Future: 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static, B: MessageBody + 'static,
X: Service<Request = Request, Response = Request> + Unpin, X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>, X::Error: Into<Error>,
X::Future: Unpin, U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()> + Unpin,
U::Error: fmt::Display, U::Error: fmt::Display,
U::Future: Unpin,
{ {
#[pin]
state: State<T, S, B, X, U>, state: State<T, S, B, X, U>,
} }
@ -502,25 +476,45 @@ const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0";
impl<T, S, B, X, U> Future for HttpServiceHandlerResponse<T, S, B, X, U> impl<T, S, B, X, U> Future for HttpServiceHandlerResponse<T, S, B, X, U>
where where
T: IoStream + Unpin, T: IoStream,
S: Service<Request = Request> + Unpin, S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static, S::Error: Into<Error> + 'static,
S::Future: Unpin + 'static, S::Future: 'static,
S::Response: Into<Response<B>> + Unpin + 'static, S::Response: Into<Response<B>> + 'static,
B: MessageBody, B: MessageBody,
X: Service<Request = Request, Response = Request> + Unpin, X: Service<Request = Request, Response = Request>,
X::Future: Unpin,
X::Error: Into<Error>, X::Error: Into<Error>,
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()> + Unpin, U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
U::Future: Unpin,
U::Error: fmt::Display, U::Error: fmt::Display,
{ {
type Output = Result<(), DispatchError>; type Output = Result<(), DispatchError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
match self.state { self.project().state.poll(cx)
State::H1(ref mut disp) => Pin::new(disp).poll(cx), }
State::H2(ref mut disp) => Pin::new(disp).poll(cx), }
impl<T, S, B, X, U> State<T, S, B, X, U>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error> + 'static,
S::Response: Into<Response<B>> + 'static,
B: MessageBody + 'static,
X: Service<Request = Request, Response = Request>,
X::Error: Into<Error>,
U: Service<Request = (Request, Framed<T, h1::Codec>), Response = ()>,
U::Error: fmt::Display,
{
#[project]
fn poll(
mut self: Pin<&mut Self>,
cx: &mut Context,
) -> Poll<Result<(), DispatchError>> {
#[project]
match self.as_mut().project() {
State::H1(disp) => disp.poll(cx),
State::H2(disp) => disp.poll(cx),
State::Unknown(ref mut data) => { State::Unknown(ref mut data) => {
if let Some(ref mut item) = data { if let Some(ref mut item) = data {
loop { loop {
@ -549,15 +543,15 @@ where
inner: io, inner: io,
unread: Some(buf), unread: Some(buf),
}; };
self.state = State::Handshake(Some(( self.set(State::Handshake(Some((
server::handshake(io), server::handshake(io),
cfg, cfg,
srv, srv,
peer_addr, peer_addr,
on_connect, on_connect,
))); ))));
} else { } else {
self.state = State::H1(h1::Dispatcher::with_timeout( self.set(State::H1(h1::Dispatcher::with_timeout(
io, io,
h1::Codec::new(cfg.clone()), h1::Codec::new(cfg.clone()),
cfg, cfg,
@ -567,7 +561,7 @@ where
expect, expect,
upgrade, upgrade,
on_connect, on_connect,
)) )))
} }
self.poll(cx) self.poll(cx)
} }
@ -585,9 +579,9 @@ where
panic!() panic!()
}; };
let (_, cfg, srv, peer_addr, on_connect) = data.take().unwrap(); let (_, cfg, srv, peer_addr, on_connect) = data.take().unwrap();
self.state = State::H2(Dispatcher::new( self.set(State::H2(Dispatcher::new(
srv, conn, on_connect, cfg, None, peer_addr, srv, conn, on_connect, cfg, None, peer_addr,
)); )));
self.poll(cx) self.poll(cx)
} }
} }
@ -595,13 +589,13 @@ where
} }
/// Wrapper for `AsyncRead + AsyncWrite` types /// Wrapper for `AsyncRead + AsyncWrite` types
#[pin_project::pin_project]
struct Io<T> { struct Io<T> {
unread: Option<BytesMut>, unread: Option<BytesMut>,
#[pin]
inner: T, inner: T,
} }
impl<T> Unpin for Io<T> {}
impl<T: io::Read> io::Read for Io<T> { impl<T: io::Read> io::Read for Io<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if let Some(mut bytes) = self.unread.take() { if let Some(mut bytes) = self.unread.take() {
@ -627,7 +621,7 @@ impl<T: io::Write> io::Write for Io<T> {
} }
} }
impl<T: AsyncRead + Unpin> AsyncRead for Io<T> { impl<T: AsyncRead> AsyncRead for Io<T> {
// unsafe fn initializer(&self) -> io::Initializer { // unsafe fn initializer(&self) -> io::Initializer {
// self.get_mut().inner.initializer() // self.get_mut().inner.initializer()
// } // }
@ -641,7 +635,19 @@ impl<T: AsyncRead + Unpin> AsyncRead for Io<T> {
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &mut [u8], buf: &mut [u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
Pin::new(&mut self.get_mut().inner).poll_read(cx, buf) let this = self.project();
if let Some(mut bytes) = this.unread.take() {
let size = std::cmp::min(buf.len(), bytes.len());
buf[..size].copy_from_slice(&bytes[..size]);
if bytes.len() > size {
bytes.split_to(size);
*this.unread = Some(bytes);
}
Poll::Ready(Ok(size))
} else {
this.inner.poll_read(cx, buf)
}
} }
// fn poll_read_vectored( // fn poll_read_vectored(
@ -653,32 +659,24 @@ impl<T: AsyncRead + Unpin> AsyncRead for Io<T> {
// } // }
} }
impl<T: AsyncWrite + Unpin> tokio_io::AsyncWrite for Io<T> { impl<T: AsyncWrite> tokio_io::AsyncWrite for Io<T> {
fn poll_write( fn poll_write(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
buf: &[u8], buf: &[u8],
) -> Poll<io::Result<usize>> { ) -> Poll<io::Result<usize>> {
Pin::new(&mut self.get_mut().inner).poll_write(cx, buf) self.project().inner.poll_write(cx, buf)
} }
// fn poll_write_vectored(
// self: Pin<&mut Self>,
// cx: &mut Context<'_>,
// bufs: &[io::IoSlice<'_>],
// ) -> Poll<io::Result<usize>> {
// self.get_mut().inner.poll_write_vectored(cx, bufs)
// }
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
Pin::new(&mut self.get_mut().inner).poll_flush(cx) self.project().inner.poll_flush(cx)
} }
fn poll_shutdown( fn poll_shutdown(
self: Pin<&mut Self>, self: Pin<&mut Self>,
cx: &mut Context<'_>, cx: &mut Context<'_>,
) -> Poll<io::Result<()>> { ) -> Poll<io::Result<()>> {
Pin::new(&mut self.get_mut().inner).poll_shutdown(cx) self.project().inner.poll_shutdown(cx)
} }
} }

View File

@ -11,17 +11,17 @@ use super::{Codec, Frame, Message};
pub struct Transport<S, T> pub struct Transport<S, T>
where where
S: Service<Request = Frame, Response = Message> + 'static, S: Service<Request = Frame, Response = Message> + 'static,
T: AsyncRead + AsyncWrite + Unpin, T: AsyncRead + AsyncWrite,
{ {
inner: FramedTransport<S, T, Codec>, inner: FramedTransport<S, T, Codec>,
} }
impl<S, T> Transport<S, T> impl<S, T> Transport<S, T>
where where
T: AsyncRead + AsyncWrite + Unpin, T: AsyncRead + AsyncWrite,
S: Service<Request = Frame, Response = Message> + Unpin, S: Service<Request = Frame, Response = Message>,
S::Future: 'static, S::Future: 'static,
S::Error: Unpin + 'static, S::Error: 'static,
{ {
pub fn new<F: IntoService<S>>(io: T, service: F) -> Self { pub fn new<F: IntoService<S>>(io: T, service: F) -> Self {
Transport { Transport {
@ -38,10 +38,10 @@ where
impl<S, T> Future for Transport<S, T> impl<S, T> Future for Transport<S, T>
where where
T: AsyncRead + AsyncWrite + Unpin, T: AsyncRead + AsyncWrite,
S: Service<Request = Frame, Response = Message> + Unpin, S: Service<Request = Frame, Response = Message>,
S::Future: 'static, S::Future: 'static,
S::Error: Unpin + 'static, S::Error: 'static,
{ {
type Output = Result<(), FramedTransportError<S::Error, Codec>>; type Output = Result<(), FramedTransportError<S::Error, Codec>>;

View File

@ -1,9 +1,9 @@
use actix_service::NewService; use actix_service::ServiceFactory;
use bytes::Bytes; use bytes::Bytes;
use futures::future::{self, ok}; use futures::future::{self, ok};
use actix_http::{http, HttpService, Request, Response}; use actix_http::{http, HttpService, Request, Response};
use actix_http_test::TestServer; use actix_http_test::{block_on, TestServer};
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \ Hello World Hello World Hello World Hello World Hello World \
@ -29,55 +29,63 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
#[test] #[test]
fn test_h1_v2() { fn test_h1_v2() {
env_logger::init(); block_on(async {
let mut srv = TestServer::new(move || { let srv = TestServer::start(move || {
HttpService::build().finish(|_| future::ok::<_, ()>(Response::Ok().body(STR))) HttpService::build()
}); .finish(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
let response = srv.block_on(srv.get("/").send()).unwrap(); });
assert!(response.status().is_success());
let request = srv.get("/").header("x-test", "111").send(); let response = srv.get("/").send().await.unwrap();
let response = srv.block_on(request).unwrap(); assert!(response.status().is_success());
assert!(response.status().is_success());
// read response let request = srv.get("/").header("x-test", "111").send();
let bytes = srv.load_body(response).unwrap(); let mut response = request.await.unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref())); assert!(response.status().is_success());
let response = srv.block_on(srv.post("/").send()).unwrap(); // read response
assert!(response.status().is_success()); let bytes = response.body().await.unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
// read response let mut response = srv.post("/").send().await.unwrap();
let bytes = srv.load_body(response).unwrap(); assert!(response.status().is_success());
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
// read response
let bytes = response.body().await.unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
})
} }
#[test] #[test]
fn test_connection_close() { fn test_connection_close() {
let mut srv = TestServer::new(move || { block_on(async {
HttpService::build() let srv = TestServer::start(move || {
.finish(|_| ok::<_, ()>(Response::Ok().body(STR))) HttpService::build()
.map(|_| ()) .finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
}); .map(|_| ())
let response = srv.block_on(srv.get("/").force_close().send()).unwrap(); });
assert!(response.status().is_success());
let response = srv.get("/").force_close().send().await.unwrap();
assert!(response.status().is_success());
})
} }
#[test] #[test]
fn test_with_query_parameter() { fn test_with_query_parameter() {
let mut srv = TestServer::new(move || { block_on(async {
HttpService::build() let srv = TestServer::start(move || {
.finish(|req: Request| { HttpService::build()
if req.uri().query().unwrap().contains("qp=") { .finish(|req: Request| {
ok::<_, ()>(Response::Ok().finish()) if req.uri().query().unwrap().contains("qp=") {
} else { ok::<_, ()>(Response::Ok().finish())
ok::<_, ()>(Response::BadRequest().finish()) } else {
} ok::<_, ()>(Response::BadRequest().finish())
}) }
.map(|_| ()) })
}); .map(|_| ())
});
let request = srv.request(http::Method::GET, srv.url("/?qp=5")).send(); let request = srv.request(http::Method::GET, srv.url("/?qp=5"));
let response = srv.block_on(request).unwrap(); let response = request.send().await.unwrap();
assert!(response.status().is_success()); assert!(response.status().is_success());
})
} }

View File

@ -0,0 +1,545 @@
#![cfg(feature = "openssl")]
use std::io;
use actix_codec::{AsyncRead, AsyncWrite};
use actix_http_test::{block_on, TestServer};
use actix_server::ssl::OpensslAcceptor;
use actix_server_config::ServerConfig;
use actix_service::{factory_fn_cfg, pipeline_factory, service_fn2, ServiceFactory};
use bytes::{Bytes, BytesMut};
use futures::future::{err, ok, ready};
use futures::stream::{once, Stream, StreamExt};
use open_ssl::ssl::{AlpnError, SslAcceptor, SslFiletype, SslMethod};
use actix_http::error::{ErrorBadRequest, PayloadError};
use actix_http::http::header::{self, HeaderName, HeaderValue};
use actix_http::http::{Method, StatusCode, Version};
use actix_http::httpmessage::HttpMessage;
use actix_http::{body, Error, HttpService, Request, Response};
async fn load_body<S>(stream: S) -> Result<BytesMut, PayloadError>
where
S: Stream<Item = Result<Bytes, PayloadError>>,
{
let body = stream
.map(|res| match res {
Ok(chunk) => chunk,
Err(_) => panic!(),
})
.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
ready(body)
})
.await;
Ok(body)
}
fn ssl_acceptor<T: AsyncRead + AsyncWrite>() -> io::Result<OpensslAcceptor<T, ()>> {
// load ssl keys
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder
.set_private_key_file("../tests/key.pem", SslFiletype::PEM)
.unwrap();
builder
.set_certificate_chain_file("../tests/cert.pem")
.unwrap();
builder.set_alpn_select_callback(|_, protos| {
const H2: &[u8] = b"\x02h2";
if protos.windows(3).any(|window| window == H2) {
Ok(b"h2")
} else {
Err(AlpnError::NOACK)
}
});
builder.set_alpn_protos(b"\x02h2")?;
Ok(OpensslAcceptor::new(builder.build()))
}
#[test]
fn test_h2() -> io::Result<()> {
block_on(async {
let openssl = ssl_acceptor()?;
let srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.h2(|_| ok::<_, Error>(Response::Ok().finish()))
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
Ok(())
})
}
#[test]
fn test_h2_1() -> io::Result<()> {
block_on(async {
let openssl = ssl_acceptor()?;
let srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.finish(|req: Request| {
assert!(req.peer_addr().is_some());
assert_eq!(req.version(), Version::HTTP_2);
ok::<_, Error>(Response::Ok().finish())
})
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
Ok(())
})
}
#[test]
fn test_h2_body() -> io::Result<()> {
block_on(async {
let data = "HELLOWORLD".to_owned().repeat(64 * 1024);
let openssl = ssl_acceptor()?;
let mut srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.h2(|mut req: Request<_>| {
async move {
let body = load_body(req.take_payload()).await?;
Ok::<_, Error>(Response::Ok().body(body))
}
})
.map_err(|_| ()),
)
});
let response = srv.sget("/").send_body(data.clone()).await.unwrap();
assert!(response.status().is_success());
let body = srv.load_body(response).await.unwrap();
assert_eq!(&body, data.as_bytes());
Ok(())
})
}
#[test]
fn test_h2_content_length() {
block_on(async {
let openssl = ssl_acceptor().unwrap();
let srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.h2(|req: Request| {
let indx: usize = req.uri().path()[1..].parse().unwrap();
let statuses = [
StatusCode::NO_CONTENT,
StatusCode::CONTINUE,
StatusCode::SWITCHING_PROTOCOLS,
StatusCode::PROCESSING,
StatusCode::OK,
StatusCode::NOT_FOUND,
];
ok::<_, ()>(Response::new(statuses[indx]))
})
.map_err(|_| ()),
)
});
let header = HeaderName::from_static("content-length");
let value = HeaderValue::from_static("0");
{
for i in 0..4 {
let req = srv
.request(Method::GET, srv.surl(&format!("/{}", i)))
.send();
let response = req.await.unwrap();
assert_eq!(response.headers().get(&header), None);
let req = srv
.request(Method::HEAD, srv.surl(&format!("/{}", i)))
.send();
let response = req.await.unwrap();
assert_eq!(response.headers().get(&header), None);
}
for i in 4..6 {
let req = srv
.request(Method::GET, srv.surl(&format!("/{}", i)))
.send();
let response = req.await.unwrap();
assert_eq!(response.headers().get(&header), Some(&value));
}
}
})
}
#[test]
fn test_h2_headers() {
block_on(async {
let data = STR.repeat(10);
let data2 = data.clone();
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
let data = data.clone();
pipeline_factory(openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)))
.and_then(
HttpService::build().h2(move |_| {
let mut builder = Response::Ok();
for idx in 0..90 {
builder.header(
format!("X-TEST-{}", idx).as_str(),
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
);
}
ok::<_, ()>(builder.body(data.clone()))
}).map_err(|_| ()))
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).await.unwrap();
assert_eq!(bytes, Bytes::from(data2));
})
}
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World";
#[test]
fn test_h2_body2() {
block_on(async {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).await.unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
})
}
#[test]
fn test_h2_head_empty() {
block_on(async {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.shead("/").send().await.unwrap();
assert!(response.status().is_success());
assert_eq!(response.version(), Version::HTTP_2);
{
let len = response.headers().get(header::CONTENT_LENGTH).unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
// read response
let bytes = srv.load_body(response).await.unwrap();
assert!(bytes.is_empty());
})
}
#[test]
fn test_h2_head_binary() {
block_on(async {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.h2(|_| {
ok::<_, ()>(
Response::Ok().content_length(STR.len() as u64).body(STR),
)
})
.map_err(|_| ()),
)
});
let response = srv.shead("/").send().await.unwrap();
assert!(response.status().is_success());
{
let len = response.headers().get(header::CONTENT_LENGTH).unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
// read response
let bytes = srv.load_body(response).await.unwrap();
assert!(bytes.is_empty());
})
}
#[test]
fn test_h2_head_binary2() {
block_on(async {
let openssl = ssl_acceptor().unwrap();
let srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.shead("/").send().await.unwrap();
assert!(response.status().is_success());
{
let len = response.headers().get(header::CONTENT_LENGTH).unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
})
}
#[test]
fn test_h2_body_length() {
block_on(async {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.h2(|_| {
let body = once(ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(
Response::Ok()
.body(body::SizedStream::new(STR.len() as u64, body)),
)
})
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).await.unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
})
}
#[test]
fn test_h2_body_chunked_explicit() {
block_on(async {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.h2(|_| {
let body =
once(ok::<_, Error>(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(
Response::Ok()
.header(header::TRANSFER_ENCODING, "chunked")
.streaming(body),
)
})
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
assert!(!response.headers().contains_key(header::TRANSFER_ENCODING));
// read response
let bytes = srv.load_body(response).await.unwrap();
// decode
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
})
}
#[test]
fn test_h2_response_http_error_handling() {
block_on(async {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.h2(factory_fn_cfg(|_: &ServerConfig| {
ok::<_, ()>(service_fn2(|_| {
let broken_header = Bytes::from_static(b"\0\0\0");
ok::<_, ()>(
Response::Ok()
.header(header::CONTENT_TYPE, broken_header)
.body(STR),
)
}))
}))
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
// read response
let bytes = srv.load_body(response).await.unwrap();
assert_eq!(bytes, Bytes::from_static(b"failed to parse header value"));
})
}
#[test]
fn test_h2_service_error() {
block_on(async {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.h2(|_| err::<Response, Error>(ErrorBadRequest("error")))
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
// read response
let bytes = srv.load_body(response).await.unwrap();
assert_eq!(bytes, Bytes::from_static(b"error"));
})
}
#[test]
fn test_h2_on_connect() {
block_on(async {
let openssl = ssl_acceptor().unwrap();
let srv = TestServer::start(move || {
pipeline_factory(
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e)),
)
.and_then(
HttpService::build()
.on_connect(|_| 10usize)
.h2(|req: Request| {
assert!(req.extensions().contains::<usize>());
ok::<_, ()>(Response::Ok().finish())
})
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
})
}

View File

@ -0,0 +1,474 @@
#![cfg(feature = "rustls")]
use actix_codec::{AsyncRead, AsyncWrite};
use actix_http::error::PayloadError;
use actix_http::http::header::{self, HeaderName, HeaderValue};
use actix_http::http::{Method, StatusCode, Version};
use actix_http::{body, error, Error, HttpService, Request, Response};
use actix_http_test::{block_on, TestServer};
use actix_server::ssl::RustlsAcceptor;
use actix_server_config::ServerConfig;
use actix_service::{factory_fn_cfg, pipeline_factory, service_fn2, ServiceFactory};
use bytes::{Bytes, BytesMut};
use futures::future::{self, err, ok};
use futures::stream::{once, Stream, StreamExt};
use rust_tls::{
internal::pemfile::{certs, pkcs8_private_keys},
NoClientAuth, ServerConfig as RustlsServerConfig,
};
use std::fs::File;
use std::io::{self, BufReader};
async fn load_body<S>(mut stream: S) -> Result<BytesMut, PayloadError>
where
S: Stream<Item = Result<Bytes, PayloadError>> + Unpin,
{
let mut body = BytesMut::new();
while let Some(item) = stream.next().await {
body.extend_from_slice(&item?)
}
Ok(body)
}
fn ssl_acceptor<T: AsyncRead + AsyncWrite>() -> io::Result<RustlsAcceptor<T, ()>> {
// load ssl keys
let mut config = RustlsServerConfig::new(NoClientAuth::new());
let cert_file = &mut BufReader::new(File::open("../tests/cert.pem").unwrap());
let key_file = &mut BufReader::new(File::open("../tests/key.pem").unwrap());
let cert_chain = certs(cert_file).unwrap();
let mut keys = pkcs8_private_keys(key_file).unwrap();
config.set_single_cert(cert_chain, keys.remove(0)).unwrap();
let protos = vec![b"h2".to_vec()];
config.set_protocols(&protos);
Ok(RustlsAcceptor::new(config))
}
#[test]
fn test_h2() -> io::Result<()> {
block_on(async {
let rustls = ssl_acceptor()?;
let srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.h2(|_| future::ok::<_, Error>(Response::Ok().finish()))
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
Ok(())
})
}
#[test]
fn test_h2_1() -> io::Result<()> {
block_on(async {
let rustls = ssl_acceptor()?;
let srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.finish(|req: Request| {
assert!(req.peer_addr().is_some());
assert_eq!(req.version(), Version::HTTP_2);
future::ok::<_, Error>(Response::Ok().finish())
})
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
Ok(())
})
}
#[test]
fn test_h2_body1() -> io::Result<()> {
block_on(async {
let data = "HELLOWORLD".to_owned().repeat(64 * 1024);
let rustls = ssl_acceptor()?;
let mut srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.h2(|mut req: Request<_>| {
async move {
let body = load_body(req.take_payload()).await?;
Ok::<_, Error>(Response::Ok().body(body))
}
})
.map_err(|_| ()),
)
});
let response = srv.sget("/").send_body(data.clone()).await.unwrap();
assert!(response.status().is_success());
let body = srv.load_body(response).await.unwrap();
assert_eq!(&body, data.as_bytes());
Ok(())
})
}
#[test]
fn test_h2_content_length() {
block_on(async {
let rustls = ssl_acceptor().unwrap();
let srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.h2(|req: Request| {
let indx: usize = req.uri().path()[1..].parse().unwrap();
let statuses = [
StatusCode::NO_CONTENT,
StatusCode::CONTINUE,
StatusCode::SWITCHING_PROTOCOLS,
StatusCode::PROCESSING,
StatusCode::OK,
StatusCode::NOT_FOUND,
];
future::ok::<_, ()>(Response::new(statuses[indx]))
})
.map_err(|_| ()),
)
});
let header = HeaderName::from_static("content-length");
let value = HeaderValue::from_static("0");
{
for i in 0..4 {
let req = srv
.request(Method::GET, srv.surl(&format!("/{}", i)))
.send();
let response = req.await.unwrap();
assert_eq!(response.headers().get(&header), None);
let req = srv
.request(Method::HEAD, srv.surl(&format!("/{}", i)))
.send();
let response = req.await.unwrap();
assert_eq!(response.headers().get(&header), None);
}
for i in 4..6 {
let req = srv
.request(Method::GET, srv.surl(&format!("/{}", i)))
.send();
let response = req.await.unwrap();
assert_eq!(response.headers().get(&header), Some(&value));
}
}
})
}
#[test]
fn test_h2_headers() {
block_on(async {
let data = STR.repeat(10);
let data2 = data.clone();
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
let data = data.clone();
pipeline_factory(rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build().h2(move |_| {
let mut config = Response::Ok();
for idx in 0..90 {
config.header(
format!("X-TEST-{}", idx).as_str(),
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
);
}
future::ok::<_, ()>(config.body(data.clone()))
}).map_err(|_| ()))
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).await.unwrap();
assert_eq!(bytes, Bytes::from(data2));
})
}
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World";
#[test]
fn test_h2_body2() {
block_on(async {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.h2(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).await.unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
})
}
#[test]
fn test_h2_head_empty() {
block_on(async {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.shead("/").send().await.unwrap();
assert!(response.status().is_success());
assert_eq!(response.version(), Version::HTTP_2);
{
let len = response
.headers()
.get(http::header::CONTENT_LENGTH)
.unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
// read response
let bytes = srv.load_body(response).await.unwrap();
assert!(bytes.is_empty());
})
}
#[test]
fn test_h2_head_binary() {
block_on(async {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.h2(|_| {
ok::<_, ()>(
Response::Ok()
.content_length(STR.len() as u64)
.body(STR),
)
})
.map_err(|_| ()),
)
});
let response = srv.shead("/").send().await.unwrap();
assert!(response.status().is_success());
{
let len = response
.headers()
.get(http::header::CONTENT_LENGTH)
.unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
// read response
let bytes = srv.load_body(response).await.unwrap();
assert!(bytes.is_empty());
})
}
#[test]
fn test_h2_head_binary2() {
block_on(async {
let rustls = ssl_acceptor().unwrap();
let srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.shead("/").send().await.unwrap();
assert!(response.status().is_success());
{
let len = response
.headers()
.get(http::header::CONTENT_LENGTH)
.unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
})
}
#[test]
fn test_h2_body_length() {
block_on(async {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.h2(|_| {
let body = once(ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(
Response::Ok().body(body::SizedStream::new(
STR.len() as u64,
body,
)),
)
})
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).await.unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
})
}
#[test]
fn test_h2_body_chunked_explicit() {
block_on(async {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.h2(|_| {
let body =
once(ok::<_, Error>(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(
Response::Ok()
.header(header::TRANSFER_ENCODING, "chunked")
.streaming(body),
)
})
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert!(response.status().is_success());
assert!(!response.headers().contains_key(header::TRANSFER_ENCODING));
// read response
let bytes = srv.load_body(response).await.unwrap();
// decode
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
})
}
#[test]
fn test_h2_response_http_error_handling() {
block_on(async {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.h2(factory_fn_cfg(|_: &ServerConfig| {
ok::<_, ()>(service_fn2(|_| {
let broken_header = Bytes::from_static(b"\0\0\0");
ok::<_, ()>(
Response::Ok()
.header(
http::header::CONTENT_TYPE,
broken_header,
)
.body(STR),
)
}))
}))
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
// read response
let bytes = srv.load_body(response).await.unwrap();
assert_eq!(bytes, Bytes::from_static(b"failed to parse header value"));
})
}
#[test]
fn test_h2_service_error() {
block_on(async {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::start(move || {
pipeline_factory(rustls.clone().map_err(|e| println!("Rustls error: {}", e)))
.and_then(
HttpService::build()
.h2(|_| err::<Response, Error>(error::ErrorBadRequest("error")))
.map_err(|_| ()),
)
});
let response = srv.sget("/").send().await.unwrap();
assert_eq!(response.status(), http::StatusCode::BAD_REQUEST);
// read response
let bytes = srv.load_body(response).await.unwrap();
assert_eq!(bytes, Bytes::from_static(b"error"));
})
}

View File

@ -1,462 +0,0 @@
#![cfg(feature = "rust-tls")]
use actix_codec::{AsyncRead, AsyncWrite};
use actix_http::error::PayloadError;
use actix_http::http::header::{self, HeaderName, HeaderValue};
use actix_http::http::{Method, StatusCode, Version};
use actix_http::{body, error, Error, HttpService, Request, Response};
use actix_http_test::TestServer;
use actix_server::ssl::RustlsAcceptor;
use actix_server_config::ServerConfig;
use actix_service::{new_service_cfg, NewService};
use bytes::{Bytes, BytesMut};
use futures::future::{self, ok, Future};
use futures::stream::{once, Stream};
use rustls::{
internal::pemfile::{certs, pkcs8_private_keys},
NoClientAuth, ServerConfig as RustlsServerConfig,
};
use std::fs::File;
use std::io::{BufReader, Result};
fn load_body<S>(stream: S) -> impl Future<Item = BytesMut, Error = PayloadError>
where
S: Stream<Item = Bytes, Error = PayloadError>,
{
stream.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, PayloadError>(body)
})
}
fn ssl_acceptor<T: AsyncRead + AsyncWrite>() -> Result<RustlsAcceptor<T, ()>> {
// load ssl keys
let mut config = RustlsServerConfig::new(NoClientAuth::new());
let cert_file = &mut BufReader::new(File::open("../tests/cert.pem").unwrap());
let key_file = &mut BufReader::new(File::open("../tests/key.pem").unwrap());
let cert_chain = certs(cert_file).unwrap();
let mut keys = pkcs8_private_keys(key_file).unwrap();
config.set_single_cert(cert_chain, keys.remove(0)).unwrap();
let protos = vec![b"h2".to_vec()];
config.set_protocols(&protos);
Ok(RustlsAcceptor::new(config))
}
#[test]
fn test_h2() -> Result<()> {
let rustls = ssl_acceptor()?;
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.h2(|_| future::ok::<_, Error>(Response::Ok().finish()))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
Ok(())
}
#[test]
fn test_h2_1() -> Result<()> {
let rustls = ssl_acceptor()?;
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.finish(|req: Request| {
assert!(req.peer_addr().is_some());
assert_eq!(req.version(), Version::HTTP_2);
future::ok::<_, Error>(Response::Ok().finish())
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
Ok(())
}
#[test]
fn test_h2_body() -> Result<()> {
let data = "HELLOWORLD".to_owned().repeat(64 * 1024);
let rustls = ssl_acceptor()?;
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.h2(|mut req: Request<_>| {
load_body(req.take_payload())
.and_then(|body| Ok(Response::Ok().body(body)))
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send_body(data.clone())).unwrap();
assert!(response.status().is_success());
let body = srv.load_body(response).unwrap();
assert_eq!(&body, data.as_bytes());
Ok(())
}
#[test]
fn test_h2_content_length() {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.h2(|req: Request| {
let indx: usize = req.uri().path()[1..].parse().unwrap();
let statuses = [
StatusCode::NO_CONTENT,
StatusCode::CONTINUE,
StatusCode::SWITCHING_PROTOCOLS,
StatusCode::PROCESSING,
StatusCode::OK,
StatusCode::NOT_FOUND,
];
future::ok::<_, ()>(Response::new(statuses[indx]))
})
.map_err(|_| ()),
)
});
let header = HeaderName::from_static("content-length");
let value = HeaderValue::from_static("0");
{
for i in 0..4 {
let req = srv
.request(Method::GET, srv.surl(&format!("/{}", i)))
.send();
let response = srv.block_on(req).unwrap();
assert_eq!(response.headers().get(&header), None);
let req = srv
.request(Method::HEAD, srv.surl(&format!("/{}", i)))
.send();
let response = srv.block_on(req).unwrap();
assert_eq!(response.headers().get(&header), None);
}
for i in 4..6 {
let req = srv
.request(Method::GET, srv.surl(&format!("/{}", i)))
.send();
let response = srv.block_on(req).unwrap();
assert_eq!(response.headers().get(&header), Some(&value));
}
}
}
#[test]
fn test_h2_headers() {
let data = STR.repeat(10);
let data2 = data.clone();
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
let data = data.clone();
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build().h2(move |_| {
let mut config = Response::Ok();
for idx in 0..90 {
config.header(
format!("X-TEST-{}", idx).as_str(),
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
);
}
future::ok::<_, ()>(config.body(data.clone()))
}).map_err(|_| ()))
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).unwrap();
assert_eq!(bytes, Bytes::from(data2));
}
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World";
#[test]
fn test_h2_body2() {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.h2(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}
#[test]
fn test_h2_head_empty() {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.shead("/").send()).unwrap();
assert!(response.status().is_success());
assert_eq!(response.version(), Version::HTTP_2);
{
let len = response
.headers()
.get(http::header::CONTENT_LENGTH)
.unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
// read response
let bytes = srv.load_body(response).unwrap();
assert!(bytes.is_empty());
}
#[test]
fn test_h2_head_binary() {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.h2(|_| {
ok::<_, ()>(
Response::Ok().content_length(STR.len() as u64).body(STR),
)
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.shead("/").send()).unwrap();
assert!(response.status().is_success());
{
let len = response
.headers()
.get(http::header::CONTENT_LENGTH)
.unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
// read response
let bytes = srv.load_body(response).unwrap();
assert!(bytes.is_empty());
}
#[test]
fn test_h2_head_binary2() {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.shead("/").send()).unwrap();
assert!(response.status().is_success());
{
let len = response
.headers()
.get(http::header::CONTENT_LENGTH)
.unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
}
#[test]
fn test_h2_body_length() {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.h2(|_| {
let body = once(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(
Response::Ok()
.body(body::SizedStream::new(STR.len() as u64, body)),
)
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}
#[test]
fn test_h2_body_chunked_explicit() {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.h2(|_| {
let body =
once::<_, Error>(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(
Response::Ok()
.header(header::TRANSFER_ENCODING, "chunked")
.streaming(body),
)
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
assert!(!response.headers().contains_key(header::TRANSFER_ENCODING));
// read response
let bytes = srv.load_body(response).unwrap();
// decode
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}
#[test]
fn test_h2_response_http_error_handling() {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.h2(new_service_cfg(|_: &ServerConfig| {
Ok::<_, ()>(|_| {
let broken_header = Bytes::from_static(b"\0\0\0");
ok::<_, ()>(
Response::Ok()
.header(http::header::CONTENT_TYPE, broken_header)
.body(STR),
)
})
}))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert_eq!(response.status(), http::StatusCode::INTERNAL_SERVER_ERROR);
// read response
let bytes = srv.load_body(response).unwrap();
assert_eq!(bytes, Bytes::from_static(b"failed to parse header value"));
}
#[test]
fn test_h2_service_error() {
let rustls = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
rustls
.clone()
.map_err(|e| println!("Rustls error: {}", e))
.and_then(
HttpService::build()
.h2(|_| Err::<Response, Error>(error::ErrorBadRequest("error")))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert_eq!(response.status(), http::StatusCode::BAD_REQUEST);
// read response
let bytes = srv.load_body(response).unwrap();
assert_eq!(bytes, Bytes::from_static(b"error"));
}

File diff suppressed because it is too large Load Diff

View File

@ -1,480 +0,0 @@
#![cfg(feature = "ssl")]
use actix_codec::{AsyncRead, AsyncWrite};
use actix_http_test::TestServer;
use actix_server::ssl::OpensslAcceptor;
use actix_server_config::ServerConfig;
use actix_service::{new_service_cfg, NewService};
use bytes::{Bytes, BytesMut};
use futures::future::{ok, Future};
use futures::stream::{once, Stream};
use openssl::ssl::{AlpnError, SslAcceptor, SslFiletype, SslMethod};
use std::io::Result;
use actix_http::error::{ErrorBadRequest, PayloadError};
use actix_http::http::header::{self, HeaderName, HeaderValue};
use actix_http::http::{Method, StatusCode, Version};
use actix_http::httpmessage::HttpMessage;
use actix_http::{body, Error, HttpService, Request, Response};
fn load_body<S>(stream: S) -> impl Future<Item = BytesMut, Error = PayloadError>
where
S: Stream<Item = Bytes, Error = PayloadError>,
{
stream.fold(BytesMut::new(), move |mut body, chunk| {
body.extend_from_slice(&chunk);
Ok::<_, PayloadError>(body)
})
}
fn ssl_acceptor<T: AsyncRead + AsyncWrite>() -> Result<OpensslAcceptor<T, ()>> {
// load ssl keys
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder
.set_private_key_file("../tests/key.pem", SslFiletype::PEM)
.unwrap();
builder
.set_certificate_chain_file("../tests/cert.pem")
.unwrap();
builder.set_alpn_select_callback(|_, protos| {
const H2: &[u8] = b"\x02h2";
if protos.windows(3).any(|window| window == H2) {
Ok(b"h2")
} else {
Err(AlpnError::NOACK)
}
});
builder.set_alpn_protos(b"\x02h2")?;
Ok(OpensslAcceptor::new(builder.build()))
}
#[test]
fn test_h2() -> Result<()> {
let openssl = ssl_acceptor()?;
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.h2(|_| ok::<_, Error>(Response::Ok().finish()))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
Ok(())
}
#[test]
fn test_h2_1() -> Result<()> {
let openssl = ssl_acceptor()?;
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.finish(|req: Request| {
assert!(req.peer_addr().is_some());
assert_eq!(req.version(), Version::HTTP_2);
ok::<_, Error>(Response::Ok().finish())
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
Ok(())
}
#[test]
fn test_h2_body() -> Result<()> {
let data = "HELLOWORLD".to_owned().repeat(64 * 1024);
let openssl = ssl_acceptor()?;
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.h2(|mut req: Request<_>| {
load_body(req.take_payload())
.and_then(|body| Ok(Response::Ok().body(body)))
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send_body(data.clone())).unwrap();
assert!(response.status().is_success());
let body = srv.load_body(response).unwrap();
assert_eq!(&body, data.as_bytes());
Ok(())
}
#[test]
fn test_h2_content_length() {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.h2(|req: Request| {
let indx: usize = req.uri().path()[1..].parse().unwrap();
let statuses = [
StatusCode::NO_CONTENT,
StatusCode::CONTINUE,
StatusCode::SWITCHING_PROTOCOLS,
StatusCode::PROCESSING,
StatusCode::OK,
StatusCode::NOT_FOUND,
];
ok::<_, ()>(Response::new(statuses[indx]))
})
.map_err(|_| ()),
)
});
let header = HeaderName::from_static("content-length");
let value = HeaderValue::from_static("0");
{
for i in 0..4 {
let req = srv
.request(Method::GET, srv.surl(&format!("/{}", i)))
.send();
let response = srv.block_on(req).unwrap();
assert_eq!(response.headers().get(&header), None);
let req = srv
.request(Method::HEAD, srv.surl(&format!("/{}", i)))
.send();
let response = srv.block_on(req).unwrap();
assert_eq!(response.headers().get(&header), None);
}
for i in 4..6 {
let req = srv
.request(Method::GET, srv.surl(&format!("/{}", i)))
.send();
let response = srv.block_on(req).unwrap();
assert_eq!(response.headers().get(&header), Some(&value));
}
}
}
#[test]
fn test_h2_headers() {
let data = STR.repeat(10);
let data2 = data.clone();
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
let data = data.clone();
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build().h2(move |_| {
let mut builder = Response::Ok();
for idx in 0..90 {
builder.header(
format!("X-TEST-{}", idx).as_str(),
"TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \
TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ",
);
}
ok::<_, ()>(builder.body(data.clone()))
}).map_err(|_| ()))
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).unwrap();
assert_eq!(bytes, Bytes::from(data2));
}
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World \
Hello World Hello World Hello World Hello World Hello World";
#[test]
fn test_h2_body2() {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}
#[test]
fn test_h2_head_empty() {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.shead("/").send()).unwrap();
assert!(response.status().is_success());
assert_eq!(response.version(), Version::HTTP_2);
{
let len = response.headers().get(header::CONTENT_LENGTH).unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
// read response
let bytes = srv.load_body(response).unwrap();
assert!(bytes.is_empty());
}
#[test]
fn test_h2_head_binary() {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.h2(|_| {
ok::<_, ()>(
Response::Ok().content_length(STR.len() as u64).body(STR),
)
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.shead("/").send()).unwrap();
assert!(response.status().is_success());
{
let len = response.headers().get(header::CONTENT_LENGTH).unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
// read response
let bytes = srv.load_body(response).unwrap();
assert!(bytes.is_empty());
}
#[test]
fn test_h2_head_binary2() {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.h2(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.shead("/").send()).unwrap();
assert!(response.status().is_success());
{
let len = response.headers().get(header::CONTENT_LENGTH).unwrap();
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
}
}
#[test]
fn test_h2_body_length() {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.h2(|_| {
let body = once(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(
Response::Ok()
.body(body::SizedStream::new(STR.len() as u64, body)),
)
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
// read response
let bytes = srv.load_body(response).unwrap();
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}
#[test]
fn test_h2_body_chunked_explicit() {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.h2(|_| {
let body =
once::<_, Error>(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(
Response::Ok()
.header(header::TRANSFER_ENCODING, "chunked")
.streaming(body),
)
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
assert!(!response.headers().contains_key(header::TRANSFER_ENCODING));
// read response
let bytes = srv.load_body(response).unwrap();
// decode
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
}
#[test]
fn test_h2_response_http_error_handling() {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.h2(new_service_cfg(|_: &ServerConfig| {
Ok::<_, ()>(|_| {
let broken_header = Bytes::from_static(b"\0\0\0");
ok::<_, ()>(
Response::Ok()
.header(header::CONTENT_TYPE, broken_header)
.body(STR),
)
})
}))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
// read response
let bytes = srv.load_body(response).unwrap();
assert_eq!(bytes, Bytes::from_static(b"failed to parse header value"));
}
#[test]
fn test_h2_service_error() {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.h2(|_| Err::<Response, Error>(ErrorBadRequest("error")))
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
// read response
let bytes = srv.load_body(response).unwrap();
assert_eq!(bytes, Bytes::from_static(b"error"));
}
#[test]
fn test_h2_on_connect() {
let openssl = ssl_acceptor().unwrap();
let mut srv = TestServer::new(move || {
openssl
.clone()
.map_err(|e| println!("Openssl error: {}", e))
.and_then(
HttpService::build()
.on_connect(|_| 10usize)
.h2(|req: Request| {
assert!(req.extensions().contains::<usize>());
ok::<_, ()>(Response::Ok().finish())
})
.map_err(|_| ()),
)
});
let response = srv.block_on(srv.sget("/").send()).unwrap();
assert!(response.status().is_success());
}

View File

@ -1,26 +1,27 @@
use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_http::{body, h1, ws, Error, HttpService, Request, Response}; use actix_http::{body, h1, ws, Error, HttpService, Request, Response};
use actix_http_test::TestServer; use actix_http_test::{block_on, TestServer};
use actix_utils::framed::FramedTransport; use actix_utils::framed::FramedTransport;
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
use futures::future::{self, ok}; use futures::future;
use futures::{Future, Sink, Stream}; use futures::{SinkExt, StreamExt};
fn ws_service<T: AsyncRead + AsyncWrite>( async fn ws_service<T: AsyncRead + AsyncWrite + Unpin>(
(req, framed): (Request, Framed<T, h1::Codec>), (req, mut framed): (Request, Framed<T, h1::Codec>),
) -> impl Future<Item = (), Error = Error> { ) -> Result<(), Error> {
let res = ws::handshake(req.head()).unwrap().message_body(()); let res = ws::handshake(req.head()).unwrap().message_body(());
framed framed
.send((res, body::BodySize::None).into()) .send((res, body::BodySize::None).into())
.await
.unwrap();
FramedTransport::new(framed.into_framed(ws::Codec::new()), service)
.await
.map_err(|_| panic!()) .map_err(|_| panic!())
.and_then(|framed| {
FramedTransport::new(framed.into_framed(ws::Codec::new()), service)
.map_err(|_| panic!())
})
} }
fn service(msg: ws::Frame) -> impl Future<Item = ws::Message, Error = Error> { async fn service(msg: ws::Frame) -> Result<ws::Message, Error> {
let msg = match msg { let msg = match msg {
ws::Frame::Ping(msg) => ws::Message::Pong(msg), ws::Frame::Ping(msg) => ws::Message::Pong(msg),
ws::Frame::Text(text) => { ws::Frame::Text(text) => {
@ -30,47 +31,56 @@ fn service(msg: ws::Frame) -> impl Future<Item = ws::Message, Error = Error> {
ws::Frame::Close(reason) => ws::Message::Close(reason), ws::Frame::Close(reason) => ws::Message::Close(reason),
_ => panic!(), _ => panic!(),
}; };
ok(msg) Ok(msg)
} }
#[test] #[test]
fn test_simple() { fn test_simple() {
let mut srv = TestServer::new(|| { block_on(async {
HttpService::build() let mut srv = TestServer::start(|| {
.upgrade(ws_service) HttpService::build()
.finish(|_| future::ok::<_, ()>(Response::NotFound())) .upgrade(actix_service::service_fn(ws_service))
}); .finish(|_| future::ok::<_, ()>(Response::NotFound()))
});
// client service // client service
let framed = srv.ws().unwrap(); let mut framed = srv.ws().await.unwrap();
let framed = srv framed
.block_on(framed.send(ws::Message::Text("text".to_string()))) .send(ws::Message::Text("text".to_string()))
.unwrap(); .await
let (item, framed) = srv.block_on(framed.into_future()).map_err(|_| ()).unwrap(); .unwrap();
assert_eq!(item, Some(ws::Frame::Text(Some(BytesMut::from("text"))))); let (item, mut framed) = framed.into_future().await;
assert_eq!(
item.unwrap().unwrap(),
ws::Frame::Text(Some(BytesMut::from("text")))
);
let framed = srv framed
.block_on(framed.send(ws::Message::Binary("text".into()))) .send(ws::Message::Binary("text".into()))
.unwrap(); .await
let (item, framed) = srv.block_on(framed.into_future()).map_err(|_| ()).unwrap(); .unwrap();
assert_eq!( let (item, mut framed) = framed.into_future().await;
item, assert_eq!(
Some(ws::Frame::Binary(Some(Bytes::from_static(b"text").into()))) item.unwrap().unwrap(),
); ws::Frame::Binary(Some(Bytes::from_static(b"text").into()))
);
let framed = srv framed.send(ws::Message::Ping("text".into())).await.unwrap();
.block_on(framed.send(ws::Message::Ping("text".into()))) let (item, mut framed) = framed.into_future().await;
.unwrap(); assert_eq!(
let (item, framed) = srv.block_on(framed.into_future()).map_err(|_| ()).unwrap(); item.unwrap().unwrap(),
assert_eq!(item, Some(ws::Frame::Pong("text".to_string().into()))); ws::Frame::Pong("text".to_string().into())
);
let framed = srv framed
.block_on(framed.send(ws::Message::Close(Some(ws::CloseCode::Normal.into())))) .send(ws::Message::Close(Some(ws::CloseCode::Normal.into())))
.unwrap(); .await
.unwrap();
let (item, _framed) = srv.block_on(framed.into_future()).map_err(|_| ()).unwrap(); let (item, _framed) = framed.into_future().await;
assert_eq!( assert_eq!(
item, item.unwrap().unwrap(),
Some(ws::Frame::Close(Some(ws::CloseCode::Normal.into()))) ws::Frame::Close(Some(ws::CloseCode::Normal.into()))
); );
})
} }

View File

@ -7,7 +7,7 @@ use actix_rt::{System};
use actix_server::{Server, ServiceFactory}; use actix_server::{Server, ServiceFactory};
use awc::{error::PayloadError, ws, Client, ClientRequest, ClientResponse, Connector}; use awc::{error::PayloadError, ws, Client, ClientRequest, ClientResponse, Connector};
use bytes::Bytes; use bytes::Bytes;
use futures::{Stream, future::lazy}; use futures::Stream;
use http::Method; use http::Method;
use net2::TcpBuilder; use net2::TcpBuilder;
use tokio_net::tcp::TcpStream; use tokio_net::tcp::TcpStream;
@ -55,7 +55,7 @@ pub struct TestServerRuntime {
impl TestServer { impl TestServer {
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
/// Start new test server with application factory /// Start new test server with application factory
pub fn new<F: ServiceFactory<TcpStream>>(factory: F) -> TestServerRuntime { pub fn start<F: ServiceFactory<TcpStream>>(factory: F) -> TestServerRuntime {
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
// run server in separate thread // run server in separate thread
@ -76,11 +76,11 @@ impl TestServer {
let (system, addr) = rx.recv().unwrap(); let (system, addr) = rx.recv().unwrap();
let client = block_on(lazy(move |_| { let client = {
let connector = { let connector = {
#[cfg(feature = "ssl")] #[cfg(feature = "openssl")]
{ {
use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode}; use open_ssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
let mut builder = SslConnector::builder(SslMethod::tls()).unwrap(); let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
builder.set_verify(SslVerifyMode::NONE); builder.set_verify(SslVerifyMode::NONE);
@ -93,7 +93,7 @@ impl TestServer {
.ssl(builder.build()) .ssl(builder.build())
.finish() .finish()
} }
#[cfg(not(feature = "ssl"))] #[cfg(not(feature = "openssl"))]
{ {
Connector::new() Connector::new()
.conn_lifetime(time::Duration::from_secs(0)) .conn_lifetime(time::Duration::from_secs(0))
@ -102,14 +102,9 @@ impl TestServer {
} }
}; };
Ok::<Client, ()>(Client::build().connector(connector).finish()) Client::build().connector(connector).finish()
})) };
.unwrap(); actix_connect::start_default_resolver();
block_on(lazy(|_| {
Ok::<_, ()>(actix_connect::start_default_resolver())
}))
.unwrap();
TestServerRuntime { TestServerRuntime {
addr, addr,
@ -228,35 +223,33 @@ impl TestServerRuntime {
self.client.request(method, path.as_ref()) self.client.request(method, path.as_ref())
} }
pub fn load_body<S>( pub async fn load_body<S>(
&mut self, &mut self,
mut response: ClientResponse<S>, mut response: ClientResponse<S>,
) -> Result<Bytes, PayloadError> ) -> Result<Bytes, PayloadError>
where where
S: Stream<Item = Result<Bytes, PayloadError>> + Unpin + 'static, S: Stream<Item = Result<Bytes, PayloadError>> + Unpin + 'static,
{ {
block_on(response.body().limit(10_485_760)) response.body().limit(10_485_760).await
} }
/// Connect to websocket server at a given path /// Connect to websocket server at a given path
pub fn ws_at( pub async fn ws_at(
&mut self, &mut self,
path: &str, path: &str,
) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError> ) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError>
{ {
let url = self.url(path); let url = self.url(path);
let connect = self.client.ws(url).connect(); let connect = self.client.ws(url).connect();
block_on(async move { connect.await.map(|(_, framed)| framed)
connect.await.map(|(_, framed)| framed)
})
} }
/// Connect to a websocket server /// Connect to a websocket server
pub fn ws( pub async fn ws(
&mut self, &mut self,
) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError> ) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError>
{ {
self.ws_at("/") self.ws_at("/").await
} }
/// Stop http server /// Stop http server

View File

@ -1,32 +1,19 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFfjCCA2agAwIBAgIJAOIBvp/w68KrMA0GCSqGSIb3DQEBCwUAMGsxCzAJBgNV MIIDEDCCAfgCCQCQdmIZc/Ib/jANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQGEwJ1
BAYTAlJVMRkwFwYDVQQIDBBTYWludC1QZXRlcnNidXJnMRkwFwYDVQQHDBBTYWlu czELMAkGA1UECAwCY2ExCzAJBgNVBAcMAnNmMSEwHwYJKoZIhvcNAQkBFhJmYWZo
dC1QZXRlcnNidXJnMRIwEAYDVQQKDAlLdXBpYmlsZXQxEjAQBgNVBAMMCWxvY2Fs cmQ5MUBnbWFpbC5jb20wHhcNMTkxMTE5MTEwNjU1WhcNMjkxMTE2MTEwNjU1WjBK
aG9zdDAgFw0xOTA3MjcxODIzMTJaGA8zMDE5MDcyNzE4MjMxMlowazELMAkGA1UE MQswCQYDVQQGEwJ1czELMAkGA1UECAwCY2ExCzAJBgNVBAcMAnNmMSEwHwYJKoZI
BhMCUlUxGTAXBgNVBAgMEFNhaW50LVBldGVyc2J1cmcxGTAXBgNVBAcMEFNhaW50 hvcNAQkBFhJmYWZocmQ5MUBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
LVBldGVyc2J1cmcxEjAQBgNVBAoMCUt1cGliaWxldDESMBAGA1UEAwwJbG9jYWxo DwAwggEKAoIBAQDcnaz12CKzUL7248V7Axhms/O9UQXfAdw0yolEfC3P5jADa/1C
b3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuiQZzTO3gRRPr6ZH +kLWKjAc2coqDSbGsrsR6KiH2g06Kunx+tSGqUO+Sct7HEehmxndiSwx/hfMWezy
wcmKqkoXig9taCCqx72Qvb9tvCLhQLE1dDPZV8I/r8bx+mM4Yz3r0Hm5LxTIhCM9 XRe/olcHFTeCk/Tllz4xGEplhPua6GLhJygLOhAMiV8cwCYrgyPqsDduExLDFCqc
p3/abuiJAZENC/VkxgFzBGg7KGLSFmzU+A8Ft+2mrKmj5MpIPBCxDeVg80TCQOJy K2xntIPreumXpiE3QY4+MWyteiJko4IWDFf/UwwsdCY5MlFfw1F/Uv9vz7FfOfvu
hj+NU3PpBo9nxTgxWNWO6X+ZovZohdp78fYLLtns8rxjug3FVzdPrrLnBvihkGlq GccHd/ex8cOwotUqd6emZb+0bVE24Sv8U+yLnHIVx/tOkxgMAnJEpAnf2G3Wp3zU
gfImkh+vZxMTj1OgtxyCOhdbO4Ol4jCbn7a5yIw+iixHOEgBQfTQopRP7z1PEUV2 b2GJosbmfGaf+xTfnGGhTLLL7kCtva+NvZr5AgMBAAEwDQYJKoZIhvcNAQELBQAD
WIy2VEGzvQDlj2OyzH86T1IOFV5rz5MjdZuW0qNzeS0w3Jzgp/olSbIZLhGAaIk0 ggEBANftoL8zDGrjCwWvct8kOOqset2ukK8vjIGwfm88CKsy0IfSochNz2qeIu9R
gN7y9XvSHqs7rO0wW+467ico7+uP1ScGgPgJA5fGu7ahp7F7G3ZSoAqAcS60wYsX ZuO7c0pfjmRkir9ZQdq9vXgG3ccL9UstFsferPH9W3YJ83kgXg3fa0EmCiN/0hwz
kStoA3RWAuqste6aChv1tlgTt+Rhk8qjGhuh0ng2qVnTGyo2T3OCHB/c47Bcsp6L 6Ij1ZBiN1j3+d6+PJPgyYFNu2nGwox5mJ9+aRAGe0/9c63PEOY8P2TI4HsiPmYSl
xiyTCnQIPH3fh2iO/SC7gPw3jihPMCAQZYlkC3MhMk974rn2zs9cKtJ8ubnG2m5F fFR8k/03vr6e+rTKW85BgctjvYKe/TnFxeCQ7dZ+na7vlEtch4tNmy6O/vEk2kCt
VFVYmduRqS/YQS/O802jVCFdc8KDmoeAYNuHzgRZjQv9018UUeW3jtWKnopJnWs5 5jW0DUxhmRsv2wGmfFRI0+LotHjoXQQZi6nN5aGL3odaGF3gYwIVlZNd3AdkwDQz
ae9pbtmYeOtc7OovOxT7J2AaVfUkHRhmlqWZMzEJTcZws0fRPTZDifFJ5LFWbZsC BzG0ZwXuDDV9bSs3MfWEWcy4xuU=
zW4tCKBKvYM9eAnbb+abiHXlY1MCAwEAAaMjMCEwHwYDVR0RBBgwFoIJbG9jYWxo
b3N0ggkxMjcuMC4wLjEwDQYJKoZIhvcNAQELBQADggIBAC1EU4SVCfUKc7JbhYRf
P87F+8e13bBTLxevJdnTCH3Xw2AN8UPmwQ2vv9Mv2FMulMBQ7yLnQLGtgGUua2OE
XO+EdBBEKnglo9cwXGzU6qHhaiCeXZDM8s53qOOrD42XsDsY0nOoFYqDLW3WixP9
f1fWbcEf6+ktlvqi/1/3R6QtQR+6LS43enbsYHq8aAP60NrpXxdXxEoUwW6Z/sje
XAQluH8jzledwJcY8bXRskAHZlE4kGlOVuGgnyI3BXyLiwB4g9smFzYIs98iAGmV
7ZBaR5IIiRCtoKBG+SngM7Log0bHphvFPjDDvgqWYiWaOHboYM60Y2Z/gRbcjuMU
WZX64jw29fa8UPFdtGTupt+iuO7iXnHnm0lBBK36rVdOvsZup76p6L4BXmFsRmFK
qJ2Zd8uWNPDq80Am0mYaAqENuIANHHJXX38SesC+QO+G2JZt6vCwkGk/Qune4GIg
1GwhvsDRfTQopSxg1rdPwPM7HWeTfUGHZ34B5p/iILA3o6PfYQU8fNAWIsCDkRX2
MrgDgCnLZxKb6pjR4DYNAdPwkxyMFACZ2T46z6WvLWFlnkK5nbZoqsOsp+GJHole
llafhrelXEzt3zFR0q4zGcqheJDI+Wy+fBy3XawgAc4eN0T2UCzL/jKxKgzlzSU3
+xh1SDNjFLRd6sGzZHPMgXN0
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,52 +1,28 @@
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQC6JBnNM7eBFE+v MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDcnaz12CKzUL72
pkfByYqqSheKD21oIKrHvZC9v228IuFAsTV0M9lXwj+vxvH6YzhjPevQebkvFMiE 48V7Axhms/O9UQXfAdw0yolEfC3P5jADa/1C+kLWKjAc2coqDSbGsrsR6KiH2g06
Iz2nf9pu6IkBkQ0L9WTGAXMEaDsoYtIWbNT4DwW37aasqaPkykg8ELEN5WDzRMJA Kunx+tSGqUO+Sct7HEehmxndiSwx/hfMWezyXRe/olcHFTeCk/Tllz4xGEplhPua
4nKGP41Tc+kGj2fFODFY1Y7pf5mi9miF2nvx9gsu2ezyvGO6DcVXN0+usucG+KGQ 6GLhJygLOhAMiV8cwCYrgyPqsDduExLDFCqcK2xntIPreumXpiE3QY4+MWyteiJk
aWqB8iaSH69nExOPU6C3HII6F1s7g6XiMJuftrnIjD6KLEc4SAFB9NCilE/vPU8R o4IWDFf/UwwsdCY5MlFfw1F/Uv9vz7FfOfvuGccHd/ex8cOwotUqd6emZb+0bVE2
RXZYjLZUQbO9AOWPY7LMfzpPUg4VXmvPkyN1m5bSo3N5LTDcnOCn+iVJshkuEYBo 4Sv8U+yLnHIVx/tOkxgMAnJEpAnf2G3Wp3zUb2GJosbmfGaf+xTfnGGhTLLL7kCt
iTSA3vL1e9Ieqzus7TBb7jruJyjv64/VJwaA+AkDl8a7tqGnsXsbdlKgCoBxLrTB va+NvZr5AgMBAAECggEBAKoU0UwzVgVCQgca8Jt2dnBvWYDhnxIfYAI/BvaKedMm
ixeRK2gDdFYC6qy17poKG/W2WBO35GGTyqMaG6HSeDapWdMbKjZPc4IcH9zjsFyy 1ms87OKfB7oOiksjyI0E2JklH72dzZf2jm4CuZt5UjGC+xwPzlTaJ4s6hQVbBHyC
novGLJMKdAg8fd+HaI79ILuA/DeOKE8wIBBliWQLcyEyT3viufbOz1wq0ny5ucba NRyxU1BCXtW5tThbrhD4OjxqjmLRJEIB9OunLtwAEQoeuFLB8Va7+HFhR+Zd9k3f
bkVUVViZ25GpL9hBL87zTaNUIV1zwoOah4Bg24fOBFmNC/3TXxRR5beO1Yqeikmd 7aVA93pC5A50NRbZlke4miJ3Q8n7ZF0+UmxkBfm3fbqLk7aMWkoEKwLLTadjRlu1
azlp72lu2Zh461zs6i87FPsnYBpV9SQdGGaWpZkzMQlNxnCzR9E9NkOJ8UnksVZt bBp0YDStX66I/p1kujqBOdh6VpPvxFOa1sV9pq0jeiGc9YfSkzRSKzIn8GoyviFB
mwLNbi0IoEq9gz14Cdtv5puIdeVjUwIDAQABAoICAQCZVVezw+BsAjFKPi1qIv2J fHeszQdNlcnrSDSNnMABAw+ZpxUO7SCaftjwejEmKZUCgYEA+TY43VpmV95eY7eo
HZOadO7pEc/czflHdUON8SWgxtmDqZpmQmt3/ugiHE284qs4hqzXbcVnpCgLrLRh WKwGepiHE0fwQLuKGELmZdZI80tFi73oZMuiB5WzwmkaKGcJmm7KGE9KEvHQCo9j
HEiP887NhQ3IVjVK8hmZQR5SvsAIv0c0ph3gqbWKqF8sq4tOKR/eBUwHawJwODXR xvmktBR0VEZH8pmVfun+4h6+0H7m/NKMBBeOyv/IK8jBgHjkkB6e6nmeR7CqTxCw
AvB4KPWQbqOny/P3wNbseRLNAJeNT+MSaw5XPnzgLKvdFoEbJeBNy847Sbsk5DaF tf9tbajl1QN8gNzXZSjBDT/lanMCgYEA4qANOKOSiEARtgwyXQeeSJcM2uPv6zF3
tHgm7n30WS1Q6bkU5VyP//hMBUKNJFaSL4TtCWB5qkbu8B5VbtsR9m0FizTb6L3h ffM7vjSedtuEOHUSVeyBP/W8KDt7zyPppO/WNbURHS+HV0maS9yyj6zpVS2HGmbs
VmYbUXvIzJXjAwMjiDJ1w9wHl+tj3BE33tEmhuVzNf+SH+tLc9xuKJighDWt2vpD 3fetswsQ+zYVdokW89x4oc2z4XOGHd1LcSlyhRwPt0u2g1E9L0irwTQLWU0npFmG
eTpZ1qest26ANLOmNXWVCVTGpcWvOu5yhG/P7En10EzjFruMfHAFdwLm1gMx1rlR PRf7sN9+LeMCgYAGkDUDL2ROoB6gRa/7Vdx90hKMoXJkYgwLA4gJ2pDlR3A3c/Lw
9fyNAk/0ROJ+5BUtuWgDiyytS5f2T9KGiOHni7UbBIkv0CV2H6VL39Twxf+3OHnx 5KQJyxmG3zm/IqeQF6be6QesZA30mT4peV2rGHbP2WH/s6fKReNelSy1VQJEWk8x
JJ7OWZ8DRuLM/EJfN3C1+3eDsXOvcdvbo2TFBmCCl4Pa2pm4k3g2NBfxy/zSYWIh tGUgV4gwDwN5nLV4TjYlOrq+bJqvpmLhCC8bmj0jVQosYqSRl3cuICasnQKBgGlV
ccGPZorFKNMUi29U0Ool6fxeVflbll570pWVBLAB31HdkLSESv9h+2j/IiEJcJXj VO/Xb1su1EyWPK5qxRIeSxZOTYw2sMB01nbgxCqge0M2fvA6/hQ5ZlwY0cIEgits
nzl2RtYB0Uxzk6SjO0z4WXjz/SXg5tQQkm/dx8kM8TvHICFq68AEnw8t9Hagsdxs YlcSMsMq/TAAANxz1vbaupUhlSMbZcsBvNV0Nk9c4vr2Wxm7hsJF9u66IEMvQUp2
v5jNyOEeI1I5gPgZmKuboQKCAQEA7Hw6s8Xc3UtNaywMcK1Eb1O+kwRdztgtm0uE pkjiMxfR9CHzF4orr9EcHI5EQ0Grbq5kwFKEfoRbAoGAcWoFPILeJOlp2yW/Ds3E
uqsHWmGqbBxXN4jiVLh3dILIXFuVbvDSsSZtPLhOj1wqxgsTHg93b4BtvowyNBgo g2fQdI9BAamtEZEaslJmZMmsDTg5ACPcDkOSFEQIaJ7wLPXeZy74FVk/NrY5F8Gz
X4tErMu7/6NRael/hfOEdtpfv2gV+0eQa+8KKqYJPbqpMz/r5L/3RaxS3iXkj3QM bjX9OD/xzwp852yW5L9r62vYJakAlXef5jI6CFdYKDDCcarU0S7W5k6kq9n+wrBR
6oC4+cRuwy/flPMIpxhDriH5yjfiMOdDsi3ZfMTJu/58DTrKV7WkJxQZmha4EoZn i1NklYmUAMr2q59uJA5zsic=
IiXeRhzo+2ukMDWrr3GGPyDfjd/NB7rmY8QBdmhB5NSk+6B66JCNTIbKka/pichS
36bwSYFNji4NaHUUlYDUjfKoTNuQMEZknMGhc/433ADO7s17iQKCAQEAyYBYVG7/
LE2IkvQy9Nwly5tRCNlSvSkloz7PUwRbzG5uF5mweWEa8YECJe9/vrFXvyBW+NR8
XABFn4eG0POTR9nyb4n2nUlqiGugDIPgkrKCkJws5InifITZ/+Viocd4YZL5UwCU
R1/kMf0UjK2iJjWEeTPS6RmwRI2Iu7kym9BzphDyNYBQSbUE/f+4hNP6nUT/h09c
VH4/sUhubSgVKeK4onOci8bKitAkwVBYCYSyhuBCeCu8fTk2hVRWviRaJPVq2PMB
LHw1FCcfJLIPJG6MZpFAPkMQxpiewdggXIgi46ZlZcsNXEJ81ocT4GU2j+ArQXCf
lgEycyD3mx4k+wKCAQBGneohmKoVYtEheavVUcgnvkggOqOQirlDsE9YNo4hjRyI
4AWjTbrYNaVmI0+VVLvQvxULVUA1a4v5/zm+nbv9s/ykTSN4TQEI0VXtAfdl6gif
k7NR/ynXZBpgK2GAFKLLwFj+Agl1JtOHnV+9MA9O5Yv/QDAWqhYQSEU7GWkjHGc+
3eLT5ablzrcXHooqunlOxSBP6qURPupGuv1sLewSOOllyfjDLJmW3o+ZgNlY8nUX
7tK+mqhD4ZCG9VgMU5I0BrmZfQQ6yXMz09PYV9mb7N5kxbNjwbXpMOqeYolKSdRQ
6quST7Pv2OKf6KAdI0txPvP4Y1HFA1rG1W71nGKRAoIBAHlDU+T8J3Rx9I77hu70
zYoKnmnE35YW/R+Q3RQIu3X7vyVUyG9DkQNlr/VEfIw2Dahnve9hcLWtNDkdRnTZ
IPlMoCmfzVo6pHIU0uy1MKEX7Js6YYnnsPVevhLR6NmTQU73NDRPVOzfOGUc+RDw
LXTxIBgQqAy/+ORIiNDwUxSSDgcSi7DG14qD9c0l59WH/HpI276Cc/4lPA9kl4/5
X0MlvheFm+BCcgG34Wa1A0Y3JXkl3NqU94oktDro1or3NYioaPTGyR4MYaUPJh7f
SV2TacsP/ql5ks7xahkeB9un0ddOfBcWa6PqH1a7U6rnPj63mVB4hpGvhrziSiB/
s6ECggEAOp2P4Yd9Vm9/CptxS50HFF4adyLscAtsDd3S2hIAXhDovcPbvRek4pLQ
idPhHlRAfqrEztnhaVAmCK9HlhgthtiQGQX62YI4CS4QL2IhzDFo3M1a2snjFEdl
QuFk3XI7kQ0Yp8BLLG7T436JUrUkCXc4gQX2uRNut+ff34RIR2CjcQQjChxuHVeG
sP/3xFFj8OSs7ZoSPbmDBLrMOl64YHwezQUNAZiRYiaGbFiY0QUV6dHq8qX/qE1h
a/0Rq+gTqObDST0TqhMzI8V/i7R8SwVcD5ODHaZp5I2N2P/hV5OWY7ghQXhh89WM
o21xtGh0nP2Fq1TC6jFO+9cpbK8jNA==
-----END PRIVATE KEY----- -----END PRIVATE KEY-----