feat(http2): add HTTP/2 support for Client and Server
This commit is contained in:
@@ -129,7 +129,7 @@ where I: AsyncRead + AsyncWrite,
|
||||
let must_error = self.should_error_on_eof();
|
||||
self.state.close_read();
|
||||
self.io.consume_leading_lines();
|
||||
let was_mid_parse = !self.io.read_buf().is_empty();
|
||||
let was_mid_parse = e.is_parse() || !self.io.read_buf().is_empty();
|
||||
return if was_mid_parse || must_error {
|
||||
debug!("parse error ({}) with {} bytes", e, self.io.read_buf().len());
|
||||
self.on_parse_error(e)
|
||||
@@ -566,7 +566,7 @@ where I: AsyncRead + AsyncWrite,
|
||||
match self.io.io_mut().shutdown() {
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
Ok(Async::Ready(())) => {
|
||||
trace!("shut down IO");
|
||||
trace!("shut down IO complete");
|
||||
Ok(Async::Ready(()))
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -599,6 +599,12 @@ where I: AsyncRead + AsyncWrite,
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Used in h1::dispatch tests
|
||||
#[cfg(test)]
|
||||
pub(super) fn io_mut(&mut self) -> &mut I {
|
||||
self.io.io_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, B: AsRef<[u8]>, T> fmt::Debug for Conn<I, B, T> {
|
||||
|
||||
@@ -7,8 +7,8 @@ use tokio_service::Service;
|
||||
use body::{Body, Payload};
|
||||
use proto::{BodyLength, Conn, Http1Transaction, MessageHead, RequestHead, RequestLine, ResponseHead};
|
||||
|
||||
pub(crate) struct Dispatcher<D, Bs, I, B, T> {
|
||||
conn: Conn<I, B, T>,
|
||||
pub(crate) struct Dispatcher<D, Bs: Payload, I, T> {
|
||||
conn: Conn<I, Bs::Data, T>,
|
||||
dispatch: D,
|
||||
body_tx: Option<::body::Sender>,
|
||||
body_rx: Option<Bs>,
|
||||
@@ -31,23 +31,20 @@ pub struct Server<S: Service> {
|
||||
}
|
||||
|
||||
pub struct Client<B> {
|
||||
callback: Option<::client::dispatch::Callback<ClientMsg<B>, Response<Body>>>,
|
||||
callback: Option<::client::dispatch::Callback<Request<B>, Response<Body>>>,
|
||||
rx: ClientRx<B>,
|
||||
}
|
||||
|
||||
pub type ClientMsg<B> = Request<B>;
|
||||
type ClientRx<B> = ::client::dispatch::Receiver<Request<B>, Response<Body>>;
|
||||
|
||||
type ClientRx<B> = ::client::dispatch::Receiver<ClientMsg<B>, Response<Body>>;
|
||||
|
||||
impl<D, Bs, I, B, T> Dispatcher<D, Bs, I, B, T>
|
||||
impl<D, Bs, I, T> Dispatcher<D, Bs, I, T>
|
||||
where
|
||||
D: Dispatch<PollItem=MessageHead<T::Outgoing>, PollBody=Bs, RecvItem=MessageHead<T::Incoming>>,
|
||||
I: AsyncRead + AsyncWrite,
|
||||
B: AsRef<[u8]>,
|
||||
T: Http1Transaction,
|
||||
Bs: Payload<Data=B>,
|
||||
Bs: Payload,
|
||||
{
|
||||
pub fn new(dispatch: D, conn: Conn<I, B, T>) -> Self {
|
||||
pub fn new(dispatch: D, conn: Conn<I, Bs::Data, T>) -> Self {
|
||||
Dispatcher {
|
||||
conn: conn,
|
||||
dispatch: dispatch,
|
||||
@@ -286,13 +283,12 @@ where
|
||||
}
|
||||
|
||||
|
||||
impl<D, Bs, I, B, T> Future for Dispatcher<D, Bs, I, B, T>
|
||||
impl<D, Bs, I, T> Future for Dispatcher<D, Bs, I, T>
|
||||
where
|
||||
D: Dispatch<PollItem=MessageHead<T::Outgoing>, PollBody=Bs, RecvItem=MessageHead<T::Incoming>>,
|
||||
I: AsyncRead + AsyncWrite,
|
||||
B: AsRef<[u8]>,
|
||||
T: Http1Transaction,
|
||||
Bs: Payload<Data=B>,
|
||||
Bs: Payload,
|
||||
{
|
||||
type Item = ();
|
||||
type Error = ::Error;
|
||||
@@ -493,11 +489,18 @@ mod tests {
|
||||
fn client_read_bytes_before_writing_request() {
|
||||
let _ = pretty_env_logger::try_init();
|
||||
::futures::lazy(|| {
|
||||
let io = AsyncIo::new_buf(b"HTTP/1.1 200 OK\r\n\r\n".to_vec(), 100);
|
||||
// Block at 0 for now, but we will release this response before
|
||||
// the request is ready to write later...
|
||||
let io = AsyncIo::new_buf(b"HTTP/1.1 200 OK\r\n\r\n".to_vec(), 0);
|
||||
let (mut tx, rx) = ::client::dispatch::channel();
|
||||
let conn = Conn::<_, ::Chunk, ClientTransaction>::new(io);
|
||||
let mut dispatcher = Dispatcher::new(Client::new(rx), conn);
|
||||
|
||||
// First poll is needed to allow tx to send...
|
||||
assert!(dispatcher.poll().expect("nothing is ready").is_not_ready());
|
||||
// Unblock our IO, which has a response before we've sent request!
|
||||
dispatcher.conn.io_mut().block_in(100);
|
||||
|
||||
let res_rx = tx.try_send(::Request::new(::Body::empty())).unwrap();
|
||||
|
||||
let a1 = dispatcher.poll().expect("error should be sent on channel");
|
||||
@@ -506,13 +509,6 @@ mod tests {
|
||||
.expect("callback poll")
|
||||
.expect_err("callback response");
|
||||
|
||||
/*
|
||||
let err = match async {
|
||||
Async::Ready(result) => result.unwrap_err(),
|
||||
Async::Pending => panic!("callback should be ready"),
|
||||
};
|
||||
*/
|
||||
|
||||
match (err.0.kind(), err.1) {
|
||||
(&::error::Kind::Canceled, Some(_)) => (),
|
||||
other => panic!("expected Canceled, got {:?}", other),
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
pub(crate) use self::conn::Conn;
|
||||
pub(crate) use self::dispatch::Dispatcher;
|
||||
pub use self::decode::Decoder;
|
||||
pub use self::encode::{EncodedBuf, Encoder};
|
||||
pub use self::io::Cursor; //TODO: move out of h1::io
|
||||
|
||||
mod conn;
|
||||
mod date;
|
||||
|
||||
Reference in New Issue
Block a user