feat(server): allow !Send Servers
Until this commit, servers have required that `Service` and their `Future` to be `Send`, since the server needs to spawn some internal tasks to an executor, and by default, that is `tokio::spawn`, which could be spawning to a threadpool. This was true even if the user were certain there was no threadpool involved, and was instead using a different single-threaded runtime, like `tokio::runtime::current_thread`. This changes makes all the server pieces generic over an `E`, which is essentially `Executor<PrivateTypes<Server::Future>>`. There's a new set of internal traits, `H2Exec` and `NewSvcExec`, which allow for the type signature to only show the generics that the user is providing. The traits cannot be implemented explicitly, but there are blanket implementations for `E: Executor<SpecificType>`. If the user provides their own executor, it simply needs to have a generic `impl<F> Executor<F> for MyExec`. That impl can have bounds deciding whether to require `F: Send`. If the executor does require `Send`, and the `Service` futures are `!Send`, there will be compiler errors. To prevent a breaking change, all the types that gained the `E` generic have a default type set, which is the original `tokio::spawn` executor.
This commit is contained in:
@@ -10,7 +10,7 @@ use http::HeaderMap;
|
||||
use body::Payload;
|
||||
|
||||
mod client;
|
||||
mod server;
|
||||
pub(crate) mod server;
|
||||
|
||||
pub(crate) use self::client::Client;
|
||||
pub(crate) use self::server::Server;
|
||||
|
||||
@@ -5,7 +5,7 @@ use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use ::headers::content_length_parse_all;
|
||||
use ::body::Payload;
|
||||
use ::common::Exec;
|
||||
use ::common::exec::H2Exec;
|
||||
use ::headers;
|
||||
use ::service::Service;
|
||||
use ::proto::Dispatched;
|
||||
@@ -13,12 +13,12 @@ use super::{PipeToSendStream, SendBuf};
|
||||
|
||||
use ::{Body, Response};
|
||||
|
||||
pub(crate) struct Server<T, S, B>
|
||||
pub(crate) struct Server<T, S, B, E>
|
||||
where
|
||||
S: Service,
|
||||
B: Payload,
|
||||
{
|
||||
exec: Exec,
|
||||
exec: E,
|
||||
service: S,
|
||||
state: State<T, B>,
|
||||
}
|
||||
@@ -40,15 +40,16 @@ where
|
||||
}
|
||||
|
||||
|
||||
impl<T, S, B> Server<T, S, B>
|
||||
impl<T, S, B, E> Server<T, S, B, E>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
S: Service<ReqBody=Body, ResBody=B>,
|
||||
S::Error: Into<Box<::std::error::Error + Send + Sync>>,
|
||||
S::Future: Send + 'static,
|
||||
//S::Future: Send + 'static,
|
||||
B: Payload,
|
||||
E: H2Exec<S::Future, B>,
|
||||
{
|
||||
pub(crate) fn new(io: T, service: S, exec: Exec) -> Server<T, S, B> {
|
||||
pub(crate) fn new(io: T, service: S, exec: E) -> Server<T, S, B, E> {
|
||||
let handshake = Builder::new()
|
||||
.handshake(io);
|
||||
Server {
|
||||
@@ -76,13 +77,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, B> Future for Server<T, S, B>
|
||||
impl<T, S, B, E> Future for Server<T, S, B, E>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
S: Service<ReqBody=Body, ResBody=B>,
|
||||
S::Error: Into<Box<::std::error::Error + Send + Sync>>,
|
||||
S::Future: Send + 'static,
|
||||
//S::Future: Send + 'static,
|
||||
B: Payload,
|
||||
E: H2Exec<S::Future, B>,
|
||||
{
|
||||
type Item = Dispatched;
|
||||
type Error = ::Error;
|
||||
@@ -116,14 +118,14 @@ where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
B: Payload,
|
||||
{
|
||||
fn poll_server<S>(&mut self, service: &mut S, exec: &Exec) -> Poll<(), ::Error>
|
||||
fn poll_server<S, E>(&mut self, service: &mut S, exec: &E) -> Poll<(), ::Error>
|
||||
where
|
||||
S: Service<
|
||||
ReqBody=Body,
|
||||
ResBody=B,
|
||||
>,
|
||||
S::Error: Into<Box<::std::error::Error + Send + Sync>>,
|
||||
S::Future: Send + 'static,
|
||||
E: H2Exec<S::Future, B>,
|
||||
{
|
||||
while let Some((req, respond)) = try_ready!(self.conn.poll().map_err(::Error::new_h2)) {
|
||||
trace!("incoming request");
|
||||
@@ -132,7 +134,7 @@ where
|
||||
::Body::h2(stream, content_length)
|
||||
});
|
||||
let fut = H2Stream::new(service.call(req), respond);
|
||||
exec.execute(fut)?;
|
||||
exec.execute_h2stream(fut)?;
|
||||
}
|
||||
|
||||
// no more incoming streams...
|
||||
@@ -141,7 +143,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
struct H2Stream<F, B>
|
||||
#[allow(missing_debug_implementations)]
|
||||
pub struct H2Stream<F, B>
|
||||
where
|
||||
B: Payload,
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user