Files
hyper/src/proto/h2/server.rs
Sean McArthur 2dc6202fe7 feat(service): introduce hyper-specific Service
This introduces the `hyper::service` module, which replaces
`tokio-service`.

Since the trait is specific to hyper, its associated
types have been adjusted. It didn't make sense to need to define
`Service<Request=http::Request>`, since we already know the context is
HTTP. Instead, the request and response bodies are associated types now,
and slightly stricter bounds have been placed on `Error`.

The helpers `service_fn` and `service_fn_ok` should be sufficient for
now to ease creating `Service`s.

The `NewService` trait now allows service creation to also be
asynchronous.

These traits are similar to `tower` in nature, and possibly will be
replaced completely by it in the future. For now, hyper defining its own
allows the traits to have better context, and prevents breaking changes
in `tower` from affecting hyper.

Closes #1461

BREAKING CHANGE: The `Service` trait has changed: it has some changed
  associated types, and `call` is now bound to `&mut self`.

  The `NewService` trait has changed: it has some changed associated
  types, and `new_service` now returns a `Future`.

  `Client` no longer implements `Service` for now.

  `hyper::server::conn::Serve` now returns `Connecting` instead of
  `Connection`s, since `new_service` can now return a `Future`. The
  `Connecting` is a future wrapping the new service future, returning
  a `Connection` afterwards. In many cases, `Future::flatten` can be
  used.
2018-04-17 17:09:15 -07:00

199 lines
5.2 KiB
Rust

use futures::{Async, Future, Poll, Stream};
use h2::Reason;
use h2::server::{Builder, Connection, Handshake, SendResponse};
use tokio_io::{AsyncRead, AsyncWrite};
use ::body::Payload;
use ::common::Exec;
use ::service::Service;
use super::{PipeToSendStream, SendBuf};
use ::{Body, Response};
pub(crate) struct Server<T, S, B>
where
S: Service,
B: Payload,
{
exec: Exec,
service: S,
state: State<T, B>,
}
enum State<T, B>
where
B: Payload,
{
Handshaking(Handshake<T, SendBuf<B::Data>>),
Serving(Serving<T, B>),
}
struct Serving<T, B>
where
B: Payload,
{
conn: Connection<T, SendBuf<B::Data>>,
}
impl<T, S, B> Server<T, S, B>
where
T: AsyncRead + AsyncWrite,
S: Service<ReqBody=Body, ResBody=B>,
S::Error: Into<Box<::std::error::Error + Send + Sync>>,
S::Future: Send + 'static,
B: Payload,
{
pub(crate) fn new(io: T, service: S, exec: Exec) -> Server<T, S, B> {
let handshake = Builder::new()
.handshake(io);
Server {
exec,
state: State::Handshaking(handshake),
service,
}
}
pub fn graceful_shutdown(&mut self) {
unimplemented!("h2 server graceful shutdown");
}
}
impl<T, S, B> Future for Server<T, S, B>
where
T: AsyncRead + AsyncWrite,
S: Service<ReqBody=Body, ResBody=B>,
S::Error: Into<Box<::std::error::Error + Send + Sync>>,
S::Future: Send + 'static,
B: Payload,
{
type Item = ();
type Error = ::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
let next = match self.state {
State::Handshaking(ref mut h) => {
let conn = try_ready!(h.poll().map_err(::Error::new_h2));
State::Serving(Serving {
conn: conn,
})
},
State::Serving(ref mut srv) => {
return srv.poll_server(&mut self.service, &self.exec);
}
};
self.state = next;
}
}
}
impl<T, B> Serving<T, B>
where
T: AsyncRead + AsyncWrite,
B: Payload,
{
fn poll_server<S>(&mut self, service: &mut S, exec: &Exec) -> Poll<(), ::Error>
where
S: Service<
ReqBody=Body,
ResBody=B,
>,
S::Error: Into<Box<::std::error::Error + Send + Sync>>,
S::Future: Send + 'static,
{
while let Some((req, respond)) = try_ready!(self.conn.poll().map_err(::Error::new_h2)) {
trace!("incoming request");
let req = req.map(::Body::h2);
let fut = H2Stream::new(service.call(req), respond);
exec.execute(fut);
}
// no more incoming streams...
trace!("incoming connection complete");
Ok(Async::Ready(()))
}
}
struct H2Stream<F, B>
where
B: Payload,
{
reply: SendResponse<SendBuf<B::Data>>,
state: H2StreamState<F, B>,
}
enum H2StreamState<F, B>
where
B: Payload,
{
Service(F),
Body(PipeToSendStream<B>),
}
impl<F, B> H2Stream<F, B>
where
F: Future<Item=Response<B>>,
F::Error: Into<Box<::std::error::Error + Send + Sync>>,
B: Payload,
{
fn new(fut: F, respond: SendResponse<SendBuf<B::Data>>) -> H2Stream<F, B> {
H2Stream {
reply: respond,
state: H2StreamState::Service(fut),
}
}
fn poll2(&mut self) -> Poll<(), ::Error> {
loop {
let next = match self.state {
H2StreamState::Service(ref mut h) => {
let res = try_ready!(h.poll().map_err(::Error::new_user_service));
let (head, body) = res.into_parts();
let mut res = ::http::Response::from_parts(head, ());
super::strip_connection_headers(res.headers_mut());
macro_rules! reply {
($eos:expr) => ({
match self.reply.send_response(res, $eos) {
Ok(tx) => tx,
Err(e) => {
trace!("send response error: {}", e);
self.reply.send_reset(Reason::INTERNAL_ERROR);
return Err(::Error::new_h2(e));
}
}
})
}
if !body.is_end_stream() {
let body_tx = reply!(false);
H2StreamState::Body(PipeToSendStream::new(body, body_tx))
} else {
reply!(true);
return Ok(Async::Ready(()));
}
},
H2StreamState::Body(ref mut pipe) => {
return pipe.poll();
}
};
self.state = next;
}
}
}
impl<F, B> Future for H2Stream<F, B>
where
F: Future<Item=Response<B>>,
F::Error: Into<Box<::std::error::Error + Send + Sync>>,
B: Payload,
{
type Item = ();
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.poll2()
.map_err(|e| debug!("stream error: {}", e))
}
}