feat(http2): add HTTP/2 support for Client and Server

This commit is contained in:
Sean McArthur
2018-04-13 13:20:47 -07:00
parent fe1578acf6
commit c119097fd0
25 changed files with 2014 additions and 363 deletions

View File

@@ -1 +1,121 @@
use bytes::Buf;
use futures::{Async, Future, Poll};
use h2::{Reason, SendStream};
use http::HeaderMap;
use http::header::{CONNECTION, TRANSFER_ENCODING};
use ::body::Payload;
use ::proto::h1::Cursor;
mod client;
mod server;
pub(crate) use self::client::Client;
pub(crate) use self::server::Server;
fn strip_connection_headers(headers: &mut HeaderMap) {
if headers.remove(TRANSFER_ENCODING).is_some() {
trace!("removed illegal Transfer-Encoding header");
}
if headers.contains_key(CONNECTION) {
warn!("Connection header illegal in HTTP/2");
//TODO: actually remove it, after checking the value
//and removing all related headers
}
}
// body adapters used by both Client and Server
struct PipeToSendStream<S>
where
S: Payload,
{
body_tx: SendStream<SendBuf<S::Data>>,
stream: S,
}
impl<S> PipeToSendStream<S>
where
S: Payload,
{
fn new(stream: S, tx: SendStream<SendBuf<S::Data>>) -> PipeToSendStream<S> {
PipeToSendStream {
body_tx: tx,
stream: stream,
}
}
}
impl<S> Future for PipeToSendStream<S>
where
S: Payload,
{
type Item = ();
type Error = ::Error;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
// TODO: make use of flow control on SendStream
// If you're looking at this and thinking of trying to fix this TODO,
// you may want to look at:
// https://docs.rs/h2/0.1.*/h2/struct.SendStream.html
//
// With that doc open, we'd want to do these things:
// - check self.body_tx.capacity() to see if we can send *any* data
// - if > 0:
// - poll self.stream
// - reserve chunk.len() more capacity (because its about to be used)?
// - send the chunk
// - else:
// - try reserve a smallish amount of capacity
// - call self.body_tx.poll_capacity(), return if NotReady
match self.stream.poll_data() {
Ok(Async::Ready(Some(chunk))) => {
trace!("send body chunk: {}B", chunk.as_ref().len());
self.body_tx.send_data(SendBuf(Some(Cursor::new(chunk))), false)
.map_err(::Error::new_h2)?;
},
Ok(Async::Ready(None)) => {
trace!("send body eos");
self.body_tx.send_data(SendBuf(None), true)
.map_err(::Error::new_h2)?;
return Ok(Async::Ready(()));
},
Ok(Async::NotReady) => return Ok(Async::NotReady),
Err(err) => {
let err = ::Error::new_user_body(err);
trace!("send body user stream error: {}", err);
self.body_tx.send_reset(Reason::INTERNAL_ERROR);
return Err(err);
}
}
}
}
}
struct SendBuf<B>(Option<Cursor<B>>);
impl<B: AsRef<[u8]>> Buf for SendBuf<B> {
#[inline]
fn remaining(&self) -> usize {
self.0
.as_ref()
.map(|b| b.remaining())
.unwrap_or(0)
}
#[inline]
fn bytes(&self) -> &[u8] {
self.0
.as_ref()
.map(|b| b.bytes())
.unwrap_or(&[])
}
#[inline]
fn advance(&mut self, cnt: usize) {
self.0
.as_mut()
.map(|b| b.advance(cnt));
}
}