1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-06-26 06:57:43 +02:00

make actix-http compile with std::future

This commit is contained in:
Nikolay Kim
2019-11-15 15:54:11 +06:00
parent 5cb2d500d1
commit 8cba1170e6
28 changed files with 1176 additions and 822 deletions

View File

@ -1,5 +1,8 @@
use std::collections::VecDeque;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Instant;
use std::{fmt, mem, net};
@ -8,7 +11,7 @@ use actix_server_config::IoStream;
use actix_service::Service;
use bitflags::bitflags;
use bytes::{Bytes, BytesMut};
use futures::{try_ready, Async, Future, Poll, Sink, Stream};
use futures::{ready, Sink, Stream};
use h2::server::{Connection, SendResponse};
use h2::{RecvStream, SendStream};
use http::header::{
@ -43,13 +46,24 @@ pub struct Dispatcher<T: IoStream, S: Service<Request = Request>, B: MessageBody
_t: PhantomData<B>,
}
impl<T, S, B> Unpin for Dispatcher<T, S, B>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
B: MessageBody + 'static,
{
}
impl<T, S, B> Dispatcher<T, S, B>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
S::Response: Into<Response<B>>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
B: MessageBody + 'static,
{
pub(crate) fn new(
@ -93,61 +107,75 @@ impl<T, S, B> Future for Dispatcher<T, S, B>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
S::Response: Into<Response<B>>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
B: MessageBody + 'static,
{
type Item = ();
type Error = DispatchError;
type Output = Result<(), DispatchError>;
#[inline]
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut();
loop {
match self.connection.poll()? {
Async::Ready(None) => return Ok(Async::Ready(())),
Async::Ready(Some((req, res))) => {
match Pin::new(&mut this.connection).poll_accept(cx) {
Poll::Ready(None) => return Poll::Ready(Ok(())),
Poll::Ready(Some(Err(err))) => return Poll::Ready(Err(err.into())),
Poll::Ready(Some(Ok((req, res)))) => {
// update keep-alive expire
if self.ka_timer.is_some() {
if let Some(expire) = self.config.keep_alive_expire() {
self.ka_expire = expire;
if this.ka_timer.is_some() {
if let Some(expire) = this.config.keep_alive_expire() {
this.ka_expire = expire;
}
}
let (parts, body) = req.into_parts();
let mut req = Request::with_payload(body.into());
// let b: () = body;
let mut req = Request::with_payload(Payload::<
crate::payload::PayloadStream,
>::H2(
crate::h2::Payload::new(body)
));
let head = &mut req.head_mut();
head.uri = parts.uri;
head.method = parts.method;
head.version = parts.version;
head.headers = parts.headers.into();
head.peer_addr = self.peer_addr;
head.peer_addr = this.peer_addr;
// set on_connect data
if let Some(ref on_connect) = self.on_connect {
if let Some(ref on_connect) = this.on_connect {
on_connect.set(&mut req.extensions_mut());
}
tokio_current_thread::spawn(ServiceResponse::<S::Future, B> {
state: ServiceResponseState::ServiceCall(
self.service.call(req),
Some(res),
),
config: self.config.clone(),
buffer: None,
})
// tokio_executor::current_thread::spawn(ServiceResponse::<
// S::Future,
// S::Response,
// S::Error,
// B,
// > {
// state: ServiceResponseState::ServiceCall(
// this.service.call(req),
// Some(res),
// ),
// config: this.config.clone(),
// buffer: None,
// _t: PhantomData,
// });
}
Async::NotReady => return Ok(Async::NotReady),
Poll::Pending => return Poll::Pending,
}
}
}
}
struct ServiceResponse<F, B> {
struct ServiceResponse<F, I, E, B> {
state: ServiceResponseState<F, B>,
config: ServiceConfig,
buffer: Option<Bytes>,
_t: PhantomData<(I, E)>,
}
enum ServiceResponseState<F, B> {
@ -155,11 +183,11 @@ enum ServiceResponseState<F, B> {
SendPayload(SendStream<Bytes>, ResponseBody<B>),
}
impl<F, B> ServiceResponse<F, B>
impl<F, I, E, B> ServiceResponse<F, I, E, B>
where
F: Future,
F::Error: Into<Error>,
F::Item: Into<Response<B>>,
F: Future<Output = Result<I, E>> + Unpin,
E: Into<Error> + Unpin + 'static,
I: Into<Response<B>> + Unpin + 'static,
B: MessageBody + 'static,
{
fn prepare_response(
@ -223,109 +251,116 @@ where
}
}
impl<F, B> Future for ServiceResponse<F, B>
impl<F, I, E, B> Future for ServiceResponse<F, I, E, B>
where
F: Future,
F::Error: Into<Error>,
F::Item: Into<Response<B>>,
F: Future<Output = Result<I, E>> + Unpin,
E: Into<Error> + Unpin + 'static,
I: Into<Response<B>> + Unpin + 'static,
B: MessageBody + 'static,
{
type Item = ();
type Error = ();
type Output = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.state {
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut();
match this.state {
ServiceResponseState::ServiceCall(ref mut call, ref mut send) => {
match call.poll() {
Ok(Async::Ready(res)) => {
match Pin::new(call).poll(cx) {
Poll::Ready(Ok(res)) => {
let (res, body) = res.into().replace_body(());
let mut send = send.take().unwrap();
let mut size = body.size();
let h2_res = self.prepare_response(res.head(), &mut size);
let h2_res = this.prepare_response(res.head(), &mut size);
let stream =
send.send_response(h2_res, size.is_eof()).map_err(|e| {
let stream = match send.send_response(h2_res, size.is_eof()) {
Err(e) => {
trace!("Error sending h2 response: {:?}", e);
})?;
return Poll::Ready(());
}
Ok(stream) => stream,
};
if size.is_eof() {
Ok(Async::Ready(()))
Poll::Ready(())
} else {
self.state = ServiceResponseState::SendPayload(stream, body);
self.poll()
this.state = ServiceResponseState::SendPayload(stream, body);
Pin::new(this).poll(cx)
}
}
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(e) => {
Poll::Pending => Poll::Pending,
Poll::Ready(Err(e)) => {
let res: Response = e.into().into();
let (res, body) = res.replace_body(());
let mut send = send.take().unwrap();
let mut size = body.size();
let h2_res = self.prepare_response(res.head(), &mut size);
let h2_res = this.prepare_response(res.head(), &mut size);
let stream =
send.send_response(h2_res, size.is_eof()).map_err(|e| {
let stream = match send.send_response(h2_res, size.is_eof()) {
Err(e) => {
trace!("Error sending h2 response: {:?}", e);
})?;
return Poll::Ready(());
}
Ok(stream) => stream,
};
if size.is_eof() {
Ok(Async::Ready(()))
Poll::Ready(())
} else {
self.state = ServiceResponseState::SendPayload(
this.state = ServiceResponseState::SendPayload(
stream,
body.into_body(),
);
self.poll()
Pin::new(this).poll(cx)
}
}
}
}
ServiceResponseState::SendPayload(ref mut stream, ref mut body) => loop {
loop {
if let Some(ref mut buffer) = self.buffer {
match stream.poll_capacity().map_err(|e| warn!("{:?}", e))? {
Async::NotReady => return Ok(Async::NotReady),
Async::Ready(None) => return Ok(Async::Ready(())),
Async::Ready(Some(cap)) => {
if let Some(ref mut buffer) = this.buffer {
match stream.poll_capacity(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(None) => return Poll::Ready(()),
Poll::Ready(Some(Ok(cap))) => {
let len = buffer.len();
let bytes = buffer.split_to(std::cmp::min(cap, len));
if let Err(e) = stream.send_data(bytes, false) {
warn!("{:?}", e);
return Err(());
return Poll::Ready(());
} else if !buffer.is_empty() {
let cap = std::cmp::min(buffer.len(), CHUNK_SIZE);
stream.reserve_capacity(cap);
} else {
self.buffer.take();
this.buffer.take();
}
}
Poll::Ready(Some(Err(e))) => {
warn!("{:?}", e);
return Poll::Ready(());
}
}
} else {
match body.poll_next() {
Ok(Async::NotReady) => {
return Ok(Async::NotReady);
}
Ok(Async::Ready(None)) => {
match body.poll_next(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(None) => {
if let Err(e) = stream.send_data(Bytes::new(), true) {
warn!("{:?}", e);
return Err(());
} else {
return Ok(Async::Ready(()));
}
return Poll::Ready(());
}
Ok(Async::Ready(Some(chunk))) => {
Poll::Ready(Some(Ok(chunk))) => {
stream.reserve_capacity(std::cmp::min(
chunk.len(),
CHUNK_SIZE,
));
self.buffer = Some(chunk);
this.buffer = Some(chunk);
}
Err(e) => {
Poll::Ready(Some(Err(e))) => {
error!("Response payload stream error: {:?}", e);
return Err(());
return Poll::Ready(());
}
}
}

View File

@ -1,9 +1,11 @@
#![allow(dead_code, unused_imports)]
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use bytes::Bytes;
use futures::{Async, Poll, Stream};
use futures::Stream;
use h2::RecvStream;
mod dispatcher;
@ -25,22 +27,23 @@ impl Payload {
}
impl Stream for Payload {
type Item = Bytes;
type Error = PayloadError;
type Item = Result<Bytes, PayloadError>;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match self.pl.poll() {
Ok(Async::Ready(Some(chunk))) => {
fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
let this = self.get_mut();
match Pin::new(&mut this.pl).poll_data(cx) {
Poll::Ready(Some(Ok(chunk))) => {
let len = chunk.len();
if let Err(err) = self.pl.release_capacity().release_capacity(len) {
Err(err.into())
if let Err(err) = this.pl.release_capacity().release_capacity(len) {
Poll::Ready(Some(Err(err.into())))
} else {
Ok(Async::Ready(Some(chunk)))
Poll::Ready(Some(Ok(chunk)))
}
}
Ok(Async::Ready(None)) => Ok(Async::Ready(None)),
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(err) => Err(err.into()),
Poll::Ready(Some(Err(err))) => Poll::Ready(Some(Err(err.into()))),
Poll::Pending => Poll::Pending,
Poll::Ready(None) => Poll::Ready(None),
}
}
}

View File

@ -1,13 +1,16 @@
use std::fmt::Debug;
use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::{io, net, rc};
use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_server_config::{Io, IoStream, ServerConfig as SrvConfig};
use actix_service::{IntoNewService, NewService, Service};
use actix_service::{IntoServiceFactory, Service, ServiceFactory};
use bytes::Bytes;
use futures::future::{ok, FutureResult};
use futures::{try_ready, Async, Future, IntoFuture, Poll, Stream};
use futures::future::{ok, Ready};
use futures::{ready, Stream};
use h2::server::{self, Connection, Handshake};
use h2::RecvStream;
use log::error;
@ -23,7 +26,7 @@ use crate::response::Response;
use super::dispatcher::Dispatcher;
/// `NewService` implementation for HTTP2 transport
/// `ServiceFactory` implementation for HTTP2 transport
pub struct H2Service<T, P, S, B> {
srv: S,
cfg: ServiceConfig,
@ -33,30 +36,35 @@ pub struct H2Service<T, P, S, B> {
impl<T, P, S, B> H2Service<T, P, S, B>
where
S: NewService<Config = SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static,
S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Future: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody + 'static,
P: Unpin,
{
/// Create new `HttpService` instance.
pub fn new<F: IntoNewService<S>>(service: F) -> Self {
pub fn new<F: IntoServiceFactory<S>>(service: F) -> Self {
let cfg = ServiceConfig::new(KeepAlive::Timeout(5), 5000, 0);
H2Service {
cfg,
on_connect: None,
srv: service.into_new_service(),
srv: service.into_factory(),
_t: PhantomData,
}
}
/// Create new `HttpService` instance with config.
pub fn with_config<F: IntoNewService<S>>(cfg: ServiceConfig, service: F) -> Self {
pub fn with_config<F: IntoServiceFactory<S>>(
cfg: ServiceConfig,
service: F,
) -> Self {
H2Service {
cfg,
on_connect: None,
srv: service.into_new_service(),
srv: service.into_factory(),
_t: PhantomData,
}
}
@ -71,14 +79,16 @@ where
}
}
impl<T, P, S, B> NewService for H2Service<T, P, S, B>
impl<T, P, S, B> ServiceFactory for H2Service<T, P, S, B>
where
T: IoStream,
S: NewService<Config = SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static,
S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Future: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody + 'static,
P: Unpin,
{
type Config = SrvConfig;
type Request = Io<T, P>;
@ -90,7 +100,7 @@ where
fn new_service(&self, cfg: &SrvConfig) -> Self::Future {
H2ServiceResponse {
fut: self.srv.new_service(cfg).into_future(),
fut: self.srv.new_service(cfg),
cfg: Some(self.cfg.clone()),
on_connect: self.on_connect.clone(),
_t: PhantomData,
@ -99,8 +109,8 @@ where
}
#[doc(hidden)]
pub struct H2ServiceResponse<T, P, S: NewService, B> {
fut: <S::Future as IntoFuture>::Future,
pub struct H2ServiceResponse<T, P, S: ServiceFactory, B> {
fut: S::Future,
cfg: Option<ServiceConfig>,
on_connect: Option<rc::Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
_t: PhantomData<(T, P, B)>,
@ -109,22 +119,26 @@ pub struct H2ServiceResponse<T, P, S: NewService, B> {
impl<T, P, S, B> Future for H2ServiceResponse<T, P, S, B>
where
T: IoStream,
S: NewService<Config = SrvConfig, Request = Request>,
S::Error: Into<Error>,
S::Response: Into<Response<B>>,
<S::Service as Service>::Future: 'static,
S: ServiceFactory<Config = SrvConfig, Request = Request>,
S::Error: Into<Error> + Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
S::Future: Unpin,
<S::Service as Service>::Future: Unpin + 'static,
B: MessageBody + 'static,
P: Unpin,
{
type Item = H2ServiceHandler<T, P, S::Service, B>;
type Error = S::InitError;
type Output = Result<H2ServiceHandler<T, P, S::Service, B>, S::InitError>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let service = try_ready!(self.fut.poll());
Ok(Async::Ready(H2ServiceHandler::new(
self.cfg.take().unwrap(),
self.on_connect.clone(),
service,
)))
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.get_mut();
Poll::Ready(ready!(Pin::new(&mut this.fut).poll(cx)).map(|service| {
H2ServiceHandler::new(
this.cfg.take().unwrap(),
this.on_connect.clone(),
service,
)
}))
}
}
@ -139,10 +153,11 @@ pub struct H2ServiceHandler<T, P, S, B> {
impl<T, P, S, B> H2ServiceHandler<T, P, S, B>
where
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
S::Response: Into<Response<B>>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
B: MessageBody + 'static,
P: Unpin,
{
fn new(
cfg: ServiceConfig,
@ -162,18 +177,19 @@ impl<T, P, S, B> Service for H2ServiceHandler<T, P, S, B>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
S::Response: Into<Response<B>>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
B: MessageBody + 'static,
P: Unpin,
{
type Request = Io<T, P>;
type Response = ();
type Error = DispatchError;
type Future = H2ServiceHandlerResponse<T, S, B>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.srv.poll_ready().map_err(|e| {
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.srv.poll_ready(cx).map_err(|e| {
let e = e.into();
error!("Service readiness error: {:?}", e);
DispatchError::Service(e)
@ -219,9 +235,9 @@ pub struct H2ServiceHandlerResponse<T, S, B>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
S::Response: Into<Response<B>>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
B: MessageBody + 'static,
{
state: State<T, S, B>,
@ -231,25 +247,24 @@ impl<T, S, B> Future for H2ServiceHandlerResponse<T, S, B>
where
T: IoStream,
S: Service<Request = Request>,
S::Error: Into<Error>,
S::Future: 'static,
S::Response: Into<Response<B>>,
S::Error: Into<Error> + Unpin + 'static,
S::Future: Unpin + 'static,
S::Response: Into<Response<B>> + Unpin + 'static,
B: MessageBody,
{
type Item = ();
type Error = DispatchError;
type Output = Result<(), DispatchError>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
match self.state {
State::Incoming(ref mut disp) => disp.poll(),
State::Incoming(ref mut disp) => Pin::new(disp).poll(cx),
State::Handshake(
ref mut srv,
ref mut config,
ref peer_addr,
ref mut on_connect,
ref mut handshake,
) => match handshake.poll() {
Ok(Async::Ready(conn)) => {
) => match Pin::new(handshake).poll(cx) {
Poll::Ready(Ok(conn)) => {
self.state = State::Incoming(Dispatcher::new(
srv.take().unwrap(),
conn,
@ -258,13 +273,13 @@ where
None,
*peer_addr,
));
self.poll()
self.poll(cx)
}
Ok(Async::NotReady) => Ok(Async::NotReady),
Err(err) => {
Poll::Ready(Err(err)) => {
trace!("H2 handshake error: {}", err);
Err(err.into())
Poll::Ready(Err(err.into()))
}
Poll::Pending => Poll::Pending,
},
}
}