| @@ -1,3 +1,5 @@ | ||||
| use std::fmt; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| use futures::{Async, AsyncSink, Future, Poll, Sink, StartSend, Stream}; | ||||
| use futures::sync::{mpsc, oneshot}; | ||||
| @@ -13,11 +15,12 @@ pub type BodySender = mpsc::Sender<Result<Chunk, ::Error>>; | ||||
|  | ||||
| /// A `Stream` for `Chunk`s used in requests and responses. | ||||
| #[must_use = "streams do nothing unless polled"] | ||||
| #[derive(Debug)] | ||||
| pub struct Body(Inner); | ||||
| pub struct Body { | ||||
|     kind: Kind, | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| enum Inner { | ||||
| enum Kind { | ||||
|     #[cfg(feature = "tokio-proto")] | ||||
|     Tokio(TokioBody), | ||||
|     Chan { | ||||
| @@ -40,7 +43,7 @@ impl Body { | ||||
|     /// Return an empty body stream | ||||
|     #[inline] | ||||
|     pub fn empty() -> Body { | ||||
|         Body(Inner::Empty) | ||||
|         Body::new(Kind::Empty) | ||||
|     } | ||||
|  | ||||
|     /// Return a body stream with an associated sender half | ||||
| @@ -60,11 +63,32 @@ impl Body { | ||||
|     /// there are more chunks immediately. | ||||
|     #[inline] | ||||
|     pub fn is_empty(&self) -> bool { | ||||
|         match self.0 { | ||||
|             Inner::Empty => true, | ||||
|         match self.kind { | ||||
|             Kind::Empty => true, | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn new(kind: Kind) -> Body { | ||||
|         Body { | ||||
|             kind: kind, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn poll_inner(&mut self) -> Poll<Option<Chunk>, ::Error> { | ||||
|         match self.kind { | ||||
|             #[cfg(feature = "tokio-proto")] | ||||
|             Kind::Tokio(ref mut rx) => rx.poll(), | ||||
|             Kind::Chan { ref mut rx, .. } => match rx.poll().expect("mpsc cannot error") { | ||||
|                 Async::Ready(Some(Ok(chunk))) => Ok(Async::Ready(Some(chunk))), | ||||
|                 Async::Ready(Some(Err(err))) => Err(err), | ||||
|                 Async::Ready(None) => Ok(Async::Ready(None)), | ||||
|                 Async::NotReady => Ok(Async::NotReady), | ||||
|             }, | ||||
|             Kind::Once(ref mut val) => Ok(Async::Ready(val.take())), | ||||
|             Kind::Empty => Ok(Async::Ready(None)), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Default for Body { | ||||
| @@ -80,18 +104,15 @@ impl Stream for Body { | ||||
|  | ||||
|     #[inline] | ||||
|     fn poll(&mut self) -> Poll<Option<Chunk>, ::Error> { | ||||
|         match self.0 { | ||||
|             #[cfg(feature = "tokio-proto")] | ||||
|             Inner::Tokio(ref mut rx) => rx.poll(), | ||||
|             Inner::Chan { ref mut rx, .. } => match rx.poll().expect("mpsc cannot error") { | ||||
|                 Async::Ready(Some(Ok(chunk))) => Ok(Async::Ready(Some(chunk))), | ||||
|                 Async::Ready(Some(Err(err))) => Err(err), | ||||
|                 Async::Ready(None) => Ok(Async::Ready(None)), | ||||
|                 Async::NotReady => Ok(Async::NotReady), | ||||
|             }, | ||||
|             Inner::Once(ref mut val) => Ok(Async::Ready(val.take())), | ||||
|             Inner::Empty => Ok(Async::Ready(None)), | ||||
|         } | ||||
|         self.poll_inner() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for Body { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.debug_tuple("Body") | ||||
|             .field(&self.kind) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -105,7 +126,7 @@ pub fn channel() -> (ChunkSender, Body) { | ||||
|         close_rx_check: true, | ||||
|         tx: tx, | ||||
|     }; | ||||
|     let rx = Body(Inner::Chan { | ||||
|     let rx = Body::new(Kind::Chan { | ||||
|         close_tx: close_tx, | ||||
|         rx: rx, | ||||
|     }); | ||||
| @@ -142,24 +163,24 @@ impl ChunkSender { | ||||
| feat_server_proto! { | ||||
|     impl From<Body> for tokio_proto::streaming::Body<Chunk, ::Error> { | ||||
|         fn from(b: Body) -> tokio_proto::streaming::Body<Chunk, ::Error> { | ||||
|             match b.0 { | ||||
|                 Inner::Tokio(b) => b, | ||||
|                 Inner::Chan { close_tx, rx } => { | ||||
|             match b.kind { | ||||
|                 Kind::Tokio(b) => b, | ||||
|                 Kind::Chan { close_tx, rx } => { | ||||
|                     // disable knowing if the Rx gets dropped, since we cannot | ||||
|                     // pass this tx along. | ||||
|                     let _ = close_tx.send(false); | ||||
|                     rx.into() | ||||
|                 }, | ||||
|                 Inner::Once(Some(chunk)) => TokioBody::from(chunk), | ||||
|                 Inner::Once(None) | | ||||
|                 Inner::Empty => TokioBody::empty(), | ||||
|                 Kind::Once(Some(chunk)) => TokioBody::from(chunk), | ||||
|                 Kind::Once(None) | | ||||
|                 Kind::Empty => TokioBody::empty(), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     impl From<tokio_proto::streaming::Body<Chunk, ::Error>> for Body { | ||||
|         fn from(tokio_body: tokio_proto::streaming::Body<Chunk, ::Error>) -> Body { | ||||
|             Body(Inner::Tokio(tokio_body)) | ||||
|             Body::new(Kind::Tokio(tokio_body)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -168,7 +189,7 @@ impl From<mpsc::Receiver<Result<Chunk, ::Error>>> for Body { | ||||
|     #[inline] | ||||
|     fn from(src: mpsc::Receiver<Result<Chunk, ::Error>>) -> Body { | ||||
|         let (tx, _) = oneshot::channel(); | ||||
|         Body(Inner::Chan { | ||||
|         Body::new(Kind::Chan { | ||||
|             close_tx: tx, | ||||
|             rx: src, | ||||
|         }) | ||||
| @@ -178,7 +199,7 @@ impl From<mpsc::Receiver<Result<Chunk, ::Error>>> for Body { | ||||
| impl From<Chunk> for Body { | ||||
|     #[inline] | ||||
|     fn from (chunk: Chunk) -> Body { | ||||
|         Body(Inner::Once(Some(chunk))) | ||||
|         Body::new(Kind::Once(Some(chunk))) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ use std::fmt; | ||||
| use std::io::{self}; | ||||
| use std::marker::PhantomData; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| use futures::{Async, AsyncSink, Poll, StartSend}; | ||||
| #[cfg(feature = "tokio-proto")] | ||||
| use futures::{Sink, Stream}; | ||||
| @@ -10,7 +11,7 @@ use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| #[cfg(feature = "tokio-proto")] | ||||
| use tokio_proto::streaming::pipeline::{Frame, Transport}; | ||||
|  | ||||
| use proto::{Chunk, Http1Transaction, MessageHead}; | ||||
| use proto::{Chunk, Decode, Http1Transaction, MessageHead}; | ||||
| use super::io::{Cursor, Buffered}; | ||||
| use super::{EncodedBuf, Encoder, Decoder}; | ||||
| use method::Method; | ||||
| @@ -24,24 +25,34 @@ use version::HttpVersion; | ||||
| /// The connection will determine when a message begins and ends as well as | ||||
| /// determine if this  connection can be kept alive after the message, | ||||
| /// or if it is complete. | ||||
| pub struct Conn<I, B, T, K = KA> { | ||||
| pub struct Conn<I, B, T> { | ||||
|     io: Buffered<I, EncodedBuf<Cursor<B>>>, | ||||
|     state: State<K>, | ||||
|     state: State, | ||||
|     _marker: PhantomData<T> | ||||
| } | ||||
|  | ||||
| impl<I, B, T, K> Conn<I, B, T, K> | ||||
| /* | ||||
| impl<I, B> Conn<I, B, ClientTransaction> | ||||
| where I: AsyncRead + AsyncWrite, | ||||
|       B: AsRef<[u8]>, | ||||
| { | ||||
|     pub fn new_client(io: I) -> Conn<I, B, ClientTransaction> { | ||||
|         Conn::new(io) | ||||
|     } | ||||
| } | ||||
| */ | ||||
|  | ||||
| impl<I, B, T> Conn<I, B, T> | ||||
| where I: AsyncRead + AsyncWrite, | ||||
|       B: AsRef<[u8]>, | ||||
|       T: Http1Transaction, | ||||
|       K: KeepAlive | ||||
| { | ||||
|     pub fn new(io: I, keep_alive: K) -> Conn<I, B, T, K> { | ||||
|     pub fn new(io: I) -> Conn<I, B, T> { | ||||
|         Conn { | ||||
|             io: Buffered::new(io), | ||||
|             state: State { | ||||
|                 error: None, | ||||
|                 keep_alive: keep_alive, | ||||
|                 keep_alive: KA::Busy, | ||||
|                 method: None, | ||||
|                 read_task: None, | ||||
|                 reading: Reading::Init, | ||||
| @@ -66,6 +77,10 @@ where I: AsyncRead + AsyncWrite, | ||||
|         self.io.set_write_strategy_flatten(); | ||||
|     } | ||||
|  | ||||
|     pub fn into_inner(self) -> (I, Bytes) { | ||||
|         self.io.into_inner() | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "tokio-proto")] | ||||
|     fn poll_incoming(&mut self) -> Poll<Option<Frame<MessageHead<T::Incoming>, Chunk, ::Error>>, io::Error> { | ||||
|         trace!("Conn::poll_incoming()"); | ||||
| @@ -205,8 +220,16 @@ where I: AsyncRead + AsyncWrite, | ||||
|             }; | ||||
|  | ||||
|             let decoder = match T::decoder(&head, &mut self.state.method) { | ||||
|                 Ok(Some(d)) => d, | ||||
|                 Ok(None) => { | ||||
|                 Ok(Decode::Normal(d)) => { | ||||
|                     d | ||||
|                 }, | ||||
|                 Ok(Decode::Final(d)) => { | ||||
|                     trace!("final decoder, HTTP ending"); | ||||
|                     debug_assert!(d.is_eof()); | ||||
|                     self.state.close_read(); | ||||
|                     d | ||||
|                 }, | ||||
|                 Ok(Decode::Ignore) => { | ||||
|                     // likely a 1xx message that we can ignore | ||||
|                     continue; | ||||
|                 } | ||||
| @@ -232,7 +255,11 @@ where I: AsyncRead + AsyncWrite, | ||||
|             } else { | ||||
|                 (true, Reading::Body(decoder)) | ||||
|             }; | ||||
|             self.state.reading = reading; | ||||
|             if let Reading::Closed = self.state.reading { | ||||
|                 // actually want an `if not let ...` | ||||
|             } else { | ||||
|                 self.state.reading = reading; | ||||
|             } | ||||
|             if !body { | ||||
|                 self.try_keep_alive(); | ||||
|             } | ||||
| @@ -434,6 +461,12 @@ where I: AsyncRead + AsyncWrite, | ||||
|     } | ||||
|  | ||||
|     pub fn can_write_head(&self) -> bool { | ||||
|         if !T::should_read_first() { | ||||
|             match self.state.reading { | ||||
|                 Reading::Closed => return false, | ||||
|                 _ => {}, | ||||
|             } | ||||
|         } | ||||
|         match self.state.writing { | ||||
|             Writing::Init => true, | ||||
|             _ => false | ||||
| @@ -456,6 +489,10 @@ where I: AsyncRead + AsyncWrite, | ||||
|     pub fn write_head(&mut self, mut head: MessageHead<T::Outgoing>, body: bool) { | ||||
|         debug_assert!(self.can_write_head()); | ||||
|  | ||||
|         if !T::should_read_first() { | ||||
|             self.state.busy(); | ||||
|         } | ||||
|  | ||||
|         self.enforce_version(&mut head); | ||||
|  | ||||
|         let buf = self.io.write_buf_mut(); | ||||
| @@ -623,11 +660,10 @@ where I: AsyncRead + AsyncWrite, | ||||
| // ==== tokio_proto impl ==== | ||||
|  | ||||
| #[cfg(feature = "tokio-proto")] | ||||
| impl<I, B, T, K> Stream for Conn<I, B, T, K> | ||||
| impl<I, B, T> Stream for Conn<I, B, T> | ||||
| where I: AsyncRead + AsyncWrite, | ||||
|       B: AsRef<[u8]>, | ||||
|       T: Http1Transaction, | ||||
|       K: KeepAlive, | ||||
|       T::Outgoing: fmt::Debug { | ||||
|     type Item = Frame<MessageHead<T::Incoming>, Chunk, ::Error>; | ||||
|     type Error = io::Error; | ||||
| @@ -642,11 +678,10 @@ where I: AsyncRead + AsyncWrite, | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "tokio-proto")] | ||||
| impl<I, B, T, K> Sink for Conn<I, B, T, K> | ||||
| impl<I, B, T> Sink for Conn<I, B, T> | ||||
| where I: AsyncRead + AsyncWrite, | ||||
|       B: AsRef<[u8]>, | ||||
|       T: Http1Transaction, | ||||
|       K: KeepAlive, | ||||
|       T::Outgoing: fmt::Debug { | ||||
|     type SinkItem = Frame<MessageHead<T::Outgoing>, B, ::Error>; | ||||
|     type SinkError = io::Error; | ||||
| @@ -711,14 +746,13 @@ where I: AsyncRead + AsyncWrite, | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "tokio-proto")] | ||||
| impl<I, B, T, K> Transport for Conn<I, B, T, K> | ||||
| impl<I, B, T> Transport for Conn<I, B, T> | ||||
| where I: AsyncRead + AsyncWrite + 'static, | ||||
|       B: AsRef<[u8]> + 'static, | ||||
|       T: Http1Transaction + 'static, | ||||
|       K: KeepAlive + 'static, | ||||
|       T::Outgoing: fmt::Debug {} | ||||
|  | ||||
| impl<I, B: AsRef<[u8]>, T, K: KeepAlive> fmt::Debug for Conn<I, B, T, K> { | ||||
| impl<I, B: AsRef<[u8]>, T> fmt::Debug for Conn<I, B, T> { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.debug_struct("Conn") | ||||
|             .field("state", &self.state) | ||||
| @@ -727,9 +761,9 @@ impl<I, B: AsRef<[u8]>, T, K: KeepAlive> fmt::Debug for Conn<I, B, T, K> { | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct State<K> { | ||||
| struct State { | ||||
|     error: Option<::Error>, | ||||
|     keep_alive: K, | ||||
|     keep_alive: KA, | ||||
|     method: Option<Method>, | ||||
|     read_task: Option<Task>, | ||||
|     reading: Reading, | ||||
| @@ -752,12 +786,12 @@ enum Writing { | ||||
|     Closed, | ||||
| } | ||||
|  | ||||
| impl<K: KeepAlive> fmt::Debug for State<K> { | ||||
| impl fmt::Debug for State { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.debug_struct("State") | ||||
|             .field("reading", &self.reading) | ||||
|             .field("writing", &self.writing) | ||||
|             .field("keep_alive", &self.keep_alive.status()) | ||||
|             .field("keep_alive", &self.keep_alive) | ||||
|             .field("error", &self.error) | ||||
|             //.field("method", &self.method) | ||||
|             .field("read_task", &self.read_task) | ||||
| @@ -786,15 +820,8 @@ impl ::std::ops::BitAndAssign<bool> for KA { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait KeepAlive: fmt::Debug + ::std::ops::BitAndAssign<bool> { | ||||
|     fn busy(&mut self); | ||||
|     fn disable(&mut self); | ||||
|     fn idle(&mut self); | ||||
|     fn status(&self) -> KA; | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Copy, Debug)] | ||||
| pub enum KA { | ||||
| enum KA { | ||||
|     Idle, | ||||
|     Busy, | ||||
|     Disabled, | ||||
| @@ -806,7 +833,7 @@ impl Default for KA { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl KeepAlive for KA { | ||||
| impl KA { | ||||
|     fn idle(&mut self) { | ||||
|         *self = KA::Idle; | ||||
|     } | ||||
| @@ -824,7 +851,7 @@ impl KeepAlive for KA { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<K: KeepAlive> State<K> { | ||||
| impl State { | ||||
|     fn close(&mut self) { | ||||
|         trace!("State::close()"); | ||||
|         self.reading = Reading::Closed; | ||||
| @@ -976,7 +1003,7 @@ mod tests { | ||||
|         let good_message = b"GET / HTTP/1.1\r\n\r\n".to_vec(); | ||||
|         let len = good_message.len(); | ||||
|         let io = AsyncIo::new_buf(good_message, len); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|  | ||||
|         match conn.poll().unwrap() { | ||||
|             Async::Ready(Some(Frame::Message { message, body: false })) => { | ||||
| @@ -994,7 +1021,7 @@ mod tests { | ||||
|         let _: Result<(), ()> = future::lazy(|| { | ||||
|             let good_message = b"GET / HTTP/1.1\r\nHost: foo.bar\r\n\r\n".to_vec(); | ||||
|             let io = AsyncIo::new_buf(good_message, 10); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|             assert!(conn.poll().unwrap().is_not_ready()); | ||||
|             conn.io.io_mut().block_in(50); | ||||
|             let async = conn.poll().unwrap(); | ||||
| @@ -1010,7 +1037,7 @@ mod tests { | ||||
|     #[test] | ||||
|     fn test_conn_init_read_eof_idle() { | ||||
|         let io = AsyncIo::new_buf(vec![], 1); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|         conn.state.idle(); | ||||
|  | ||||
|         match conn.poll().unwrap() { | ||||
| @@ -1022,7 +1049,7 @@ mod tests { | ||||
|     #[test] | ||||
|     fn test_conn_init_read_eof_idle_partial_parse() { | ||||
|         let io = AsyncIo::new_buf(b"GET / HTTP/1.1".to_vec(), 100); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|         conn.state.idle(); | ||||
|  | ||||
|         match conn.poll() { | ||||
| @@ -1036,7 +1063,7 @@ mod tests { | ||||
|         let _: Result<(), ()> = future::lazy(|| { | ||||
|             // server ignores | ||||
|             let io = AsyncIo::new_eof(); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|             conn.state.busy(); | ||||
|  | ||||
|             match conn.poll().unwrap() { | ||||
| @@ -1046,7 +1073,7 @@ mod tests { | ||||
|  | ||||
|             // client | ||||
|             let io = AsyncIo::new_eof(); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io); | ||||
|             conn.state.busy(); | ||||
|  | ||||
|             match conn.poll() { | ||||
| @@ -1061,7 +1088,7 @@ mod tests { | ||||
|     fn test_conn_body_finish_read_eof() { | ||||
|         let _: Result<(), ()> = future::lazy(|| { | ||||
|             let io = AsyncIo::new_eof(); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io); | ||||
|             conn.state.busy(); | ||||
|             conn.state.writing = Writing::KeepAlive; | ||||
|             conn.state.reading = Reading::Body(Decoder::length(0)); | ||||
| @@ -1086,7 +1113,7 @@ mod tests { | ||||
|     fn test_conn_message_empty_body_read_eof() { | ||||
|         let _: Result<(), ()> = future::lazy(|| { | ||||
|             let io = AsyncIo::new_buf(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".to_vec(), 1024); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ClientTransaction>::new(io); | ||||
|             conn.state.busy(); | ||||
|             conn.state.writing = Writing::KeepAlive; | ||||
|  | ||||
| @@ -1110,7 +1137,7 @@ mod tests { | ||||
|     fn test_conn_read_body_end() { | ||||
|         let _: Result<(), ()> = future::lazy(|| { | ||||
|             let io = AsyncIo::new_buf(b"POST / HTTP/1.1\r\nContent-Length: 5\r\n\r\n12345".to_vec(), 1024); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|             conn.state.busy(); | ||||
|  | ||||
|             match conn.poll() { | ||||
| @@ -1140,7 +1167,7 @@ mod tests { | ||||
|     #[test] | ||||
|     fn test_conn_closed_read() { | ||||
|         let io = AsyncIo::new_buf(vec![], 0); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|         conn.state.close(); | ||||
|  | ||||
|         match conn.poll().unwrap() { | ||||
| @@ -1155,7 +1182,7 @@ mod tests { | ||||
|         let _ = pretty_env_logger::try_init(); | ||||
|         let _: Result<(), ()> = future::lazy(|| { | ||||
|             let io = AsyncIo::new_buf(vec![], 0); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|             let max = super::super::io::DEFAULT_MAX_BUFFER_SIZE + 4096; | ||||
|             conn.state.writing = Writing::Body(Encoder::length((max * 2) as u64)); | ||||
|  | ||||
| @@ -1180,7 +1207,7 @@ mod tests { | ||||
|     fn test_conn_body_write_chunked() { | ||||
|         let _: Result<(), ()> = future::lazy(|| { | ||||
|             let io = AsyncIo::new_buf(vec![], 4096); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|             conn.state.writing = Writing::Body(Encoder::chunked()); | ||||
|  | ||||
|             assert!(conn.start_send(Frame::Body { chunk: Some("headers".into()) }).unwrap().is_ready()); | ||||
| @@ -1193,7 +1220,7 @@ mod tests { | ||||
|     fn test_conn_body_flush() { | ||||
|         let _: Result<(), ()> = future::lazy(|| { | ||||
|             let io = AsyncIo::new_buf(vec![], 1024 * 1024 * 5); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|             conn.state.writing = Writing::Body(Encoder::length(1024 * 1024)); | ||||
|             assert!(conn.start_send(Frame::Body { chunk: Some(vec![b'a'; 1024 * 1024].into()) }).unwrap().is_ready()); | ||||
|             assert!(!conn.can_buffer_body()); | ||||
| @@ -1230,7 +1257,7 @@ mod tests { | ||||
|         // test that once writing is done, unparks | ||||
|         let f = future::lazy(|| { | ||||
|             let io = AsyncIo::new_buf(vec![], 4096); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|             conn.state.reading = Reading::KeepAlive; | ||||
|             assert!(conn.poll().unwrap().is_not_ready()); | ||||
|  | ||||
| @@ -1244,7 +1271,7 @@ mod tests { | ||||
|         // test that flushing when not waiting on read doesn't unpark | ||||
|         let f = future::lazy(|| { | ||||
|             let io = AsyncIo::new_buf(vec![], 4096); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|             conn.state.writing = Writing::KeepAlive; | ||||
|             assert!(conn.poll_complete().unwrap().is_ready()); | ||||
|             Ok::<(), ()>(()) | ||||
| @@ -1255,7 +1282,7 @@ mod tests { | ||||
|         // test that flushing and writing isn't done doesn't unpark | ||||
|         let f = future::lazy(|| { | ||||
|             let io = AsyncIo::new_buf(vec![], 4096); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|             let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|             conn.state.reading = Reading::KeepAlive; | ||||
|             assert!(conn.poll().unwrap().is_not_ready()); | ||||
|             conn.state.writing = Writing::Body(Encoder::length(5_000)); | ||||
| @@ -1268,7 +1295,7 @@ mod tests { | ||||
|     #[test] | ||||
|     fn test_conn_closed_write() { | ||||
|         let io = AsyncIo::new_buf(vec![], 0); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|         conn.state.close(); | ||||
|  | ||||
|         match conn.start_send(Frame::Body { chunk: Some(b"foobar".to_vec().into()) }) { | ||||
| @@ -1282,7 +1309,7 @@ mod tests { | ||||
|     #[test] | ||||
|     fn test_conn_write_empty_chunk() { | ||||
|         let io = AsyncIo::new_buf(vec![], 0); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io, Default::default()); | ||||
|         let mut conn = Conn::<_, proto::Chunk, ServerTransaction>::new(io); | ||||
|         conn.state.writing = Writing::KeepAlive; | ||||
|  | ||||
|         assert!(conn.start_send(Frame::Body { chunk: None }).unwrap().is_ready()); | ||||
|   | ||||
| @@ -1,15 +1,16 @@ | ||||
| use std::io; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| use futures::{Async, AsyncSink, Future, Poll, Stream}; | ||||
| use futures::sync::oneshot; | ||||
| use tokio_io::{AsyncRead, AsyncWrite}; | ||||
| use tokio_service::Service; | ||||
|  | ||||
| use proto::{Body, Conn, KeepAlive, Http1Transaction, MessageHead, RequestHead, ResponseHead}; | ||||
| use proto::{Body, Conn, Http1Transaction, MessageHead, RequestHead, ResponseHead}; | ||||
| use ::StatusCode; | ||||
|  | ||||
| pub struct Dispatcher<D, Bs, I, B, T, K> { | ||||
|     conn: Conn<I, B, T, K>, | ||||
| pub struct Dispatcher<D, Bs, I, B, T> { | ||||
|     conn: Conn<I, B, T>, | ||||
|     dispatch: D, | ||||
|     body_tx: Option<::proto::body::ChunkSender>, | ||||
|     body_rx: Option<Bs>, | ||||
| @@ -40,16 +41,15 @@ pub type ClientMsg<B> = (RequestHead, Option<B>); | ||||
|  | ||||
| type ClientRx<B> = ::client::dispatch::Receiver<ClientMsg<B>, ::Response>; | ||||
|  | ||||
| impl<D, Bs, I, B, T, K> Dispatcher<D, Bs, I, B, T, K> | ||||
| impl<D, Bs, I, B, T> Dispatcher<D, Bs, I, B, T> | ||||
| where | ||||
|     D: Dispatch<PollItem=MessageHead<T::Outgoing>, PollBody=Bs, RecvItem=MessageHead<T::Incoming>>, | ||||
|     I: AsyncRead + AsyncWrite, | ||||
|     B: AsRef<[u8]>, | ||||
|     T: Http1Transaction, | ||||
|     K: KeepAlive, | ||||
|     Bs: Stream<Item=B, Error=::Error>, | ||||
| { | ||||
|     pub fn new(dispatch: D, conn: Conn<I, B, T, K>) -> Self { | ||||
|     pub fn new(dispatch: D, conn: Conn<I, B, T>) -> Self { | ||||
|         Dispatcher { | ||||
|             conn: conn, | ||||
|             dispatch: dispatch, | ||||
| @@ -63,15 +63,44 @@ where | ||||
|         self.conn.disable_keep_alive() | ||||
|     } | ||||
|  | ||||
|     fn poll2(&mut self) -> Poll<(), ::Error> { | ||||
|     pub fn into_inner(self) -> (I, Bytes) { | ||||
|         self.conn.into_inner() | ||||
|     } | ||||
|  | ||||
|     /// The "Future" poll function. Runs this dispatcher until the | ||||
|     /// connection is shutdown, or an error occurs. | ||||
|     pub fn poll_until_shutdown(&mut self) -> Poll<(), ::Error> { | ||||
|         self.poll_catch(true) | ||||
|     } | ||||
|  | ||||
|     /// Run this dispatcher until HTTP says this connection is done, | ||||
|     /// but don't call `AsyncWrite::shutdown` on the underlying IO. | ||||
|     /// | ||||
|     /// This is useful for HTTP upgrades. | ||||
|     pub fn poll_without_shutdown(&mut self) -> Poll<(), ::Error> { | ||||
|         self.poll_catch(false) | ||||
|     } | ||||
|  | ||||
|     fn poll_catch(&mut self, should_shutdown: bool) -> Poll<(), ::Error> { | ||||
|         self.poll_inner(should_shutdown).or_else(|e| { | ||||
|             // An error means we're shutting down either way. | ||||
|             // We just try to give the error to the user, | ||||
|             // and close the connection with an Ok. If we | ||||
|             // cannot give it to the user, then return the Err. | ||||
|             self.dispatch.recv_msg(Err(e)).map(Async::Ready) | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     fn poll_inner(&mut self, should_shutdown: bool) -> Poll<(), ::Error> { | ||||
|         self.poll_read()?; | ||||
|         self.poll_write()?; | ||||
|         self.poll_flush()?; | ||||
|  | ||||
|         if self.is_done() { | ||||
|             try_ready!(self.conn.shutdown()); | ||||
|             if should_shutdown { | ||||
|                 try_ready!(self.conn.shutdown()); | ||||
|             } | ||||
|             self.conn.take_error()?; | ||||
|             trace!("Dispatch::poll done"); | ||||
|             Ok(Async::Ready(())) | ||||
|         } else { | ||||
|             Ok(Async::NotReady) | ||||
| @@ -183,7 +212,7 @@ where | ||||
|         loop { | ||||
|             if self.is_closing { | ||||
|                 return Ok(Async::Ready(())); | ||||
|             } else if self.body_rx.is_none() && self.dispatch.should_poll() { | ||||
|             } else if self.body_rx.is_none() && self.conn.can_write_head() && self.dispatch.should_poll() { | ||||
|                 if let Some((head, body)) = try_ready!(self.dispatch.poll_msg()) { | ||||
|                     self.conn.write_head(head, body.is_some()); | ||||
|                     self.body_rx = body; | ||||
| @@ -257,13 +286,12 @@ where | ||||
| } | ||||
|  | ||||
|  | ||||
| impl<D, Bs, I, B, T, K> Future for Dispatcher<D, Bs, I, B, T, K> | ||||
| impl<D, Bs, I, B, T> Future for Dispatcher<D, Bs, I, B, T> | ||||
| where | ||||
|     D: Dispatch<PollItem=MessageHead<T::Outgoing>, PollBody=Bs, RecvItem=MessageHead<T::Incoming>>, | ||||
|     I: AsyncRead + AsyncWrite, | ||||
|     B: AsRef<[u8]>, | ||||
|     T: Http1Transaction, | ||||
|     K: KeepAlive, | ||||
|     Bs: Stream<Item=B, Error=::Error>, | ||||
| { | ||||
|     type Item = (); | ||||
| @@ -271,14 +299,7 @@ where | ||||
|  | ||||
|     #[inline] | ||||
|     fn poll(&mut self) -> Poll<Self::Item, Self::Error> { | ||||
|         trace!("Dispatcher::poll"); | ||||
|         self.poll2().or_else(|e| { | ||||
|             // An error means we're shutting down either way. | ||||
|             // We just try to give the error to the user, | ||||
|             // and close the connection with an Ok. If we | ||||
|             // cannot give it to the user, then return the Err. | ||||
|             self.dispatch.recv_msg(Err(e)).map(Async::Ready) | ||||
|         }) | ||||
|         self.poll_until_shutdown() | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -445,8 +466,8 @@ mod tests { | ||||
|         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); | ||||
|             let (tx, rx) = ::client::dispatch::channel(); | ||||
|             let conn = Conn::<_, ::Chunk, ClientTransaction>::new(io, Default::default()); | ||||
|             let (mut tx, rx) = ::client::dispatch::channel(); | ||||
|             let conn = Conn::<_, ::Chunk, ClientTransaction>::new(io); | ||||
|             let mut dispatcher = Dispatcher::new(Client::new(rx), conn); | ||||
|  | ||||
|             let req = RequestHead { | ||||
|   | ||||
| @@ -152,6 +152,10 @@ where | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     pub fn into_inner(self) -> (T, Bytes) { | ||||
|         (self.io, self.read_buf.freeze()) | ||||
|     } | ||||
|  | ||||
|     pub fn io_mut(&mut self) -> &mut T { | ||||
|         &mut self.io | ||||
|     } | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| pub use self::conn::{Conn, KeepAlive, KA}; | ||||
| pub use self::conn::Conn; | ||||
| pub use self::decode::Decoder; | ||||
| pub use self::encode::{EncodedBuf, Encoder}; | ||||
|  | ||||
|   | ||||
| @@ -5,8 +5,8 @@ use httparse; | ||||
| use bytes::{BytesMut, Bytes}; | ||||
|  | ||||
| use header::{self, Headers, ContentLength, TransferEncoding}; | ||||
| use proto::{MessageHead, RawStatus, Http1Transaction, ParseResult, | ||||
|            ServerTransaction, ClientTransaction, RequestLine, RequestHead}; | ||||
| use proto::{Decode, MessageHead, RawStatus, Http1Transaction, ParseResult, | ||||
|            RequestLine, RequestHead}; | ||||
| use proto::h1::{Encoder, Decoder, date}; | ||||
| use method::Method; | ||||
| use status::StatusCode; | ||||
| @@ -15,7 +15,19 @@ use version::HttpVersion::{Http10, Http11}; | ||||
| const MAX_HEADERS: usize = 100; | ||||
| const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific | ||||
|  | ||||
| impl Http1Transaction for ServerTransaction { | ||||
| // There are 2 main roles, Client and Server. | ||||
| // | ||||
| // There is 1 modifier, OnUpgrade, which can wrap Client and Server, | ||||
| // to signal that HTTP upgrades are not supported. | ||||
|  | ||||
| pub struct Client<T>(T); | ||||
|  | ||||
| pub struct Server<T>(T); | ||||
|  | ||||
| impl<T> Http1Transaction for Server<T> | ||||
| where | ||||
|     T: OnUpgrade, | ||||
| { | ||||
|     type Incoming = RequestLine; | ||||
|     type Outgoing = StatusCode; | ||||
|  | ||||
| @@ -72,7 +84,7 @@ impl Http1Transaction for ServerTransaction { | ||||
|         }, len))) | ||||
|     } | ||||
|  | ||||
|     fn decoder(head: &MessageHead<Self::Incoming>, method: &mut Option<Method>) -> ::Result<Option<Decoder>> { | ||||
|     fn decoder(head: &MessageHead<Self::Incoming>, method: &mut Option<Method>) -> ::Result<Decode> { | ||||
|         use ::header; | ||||
|  | ||||
|         *method = Some(head.subject.0.clone()); | ||||
| @@ -95,37 +107,40 @@ impl Http1Transaction for ServerTransaction { | ||||
|                 debug!("HTTP/1.0 has Transfer-Encoding header"); | ||||
|                 Err(::Error::Header) | ||||
|             } else if encodings.last() == Some(&header::Encoding::Chunked) { | ||||
|                 Ok(Some(Decoder::chunked())) | ||||
|                 Ok(Decode::Normal(Decoder::chunked())) | ||||
|             } else { | ||||
|                 debug!("request with transfer-encoding header, but not chunked, bad request"); | ||||
|                 Err(::Error::Header) | ||||
|             } | ||||
|         } else if let Some(&header::ContentLength(len)) = head.headers.get() { | ||||
|             Ok(Some(Decoder::length(len))) | ||||
|             Ok(Decode::Normal(Decoder::length(len))) | ||||
|         } else if head.headers.has::<header::ContentLength>() { | ||||
|             debug!("illegal Content-Length: {:?}", head.headers.get_raw("Content-Length")); | ||||
|             Err(::Error::Header) | ||||
|         } else { | ||||
|             Ok(Some(Decoder::length(0))) | ||||
|             Ok(Decode::Normal(Decoder::length(0))) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     fn encode(mut head: MessageHead<Self::Outgoing>, has_body: bool, method: &mut Option<Method>, dst: &mut Vec<u8>) -> ::Result<Encoder> { | ||||
|         trace!("ServerTransaction::encode has_body={}, method={:?}", has_body, method); | ||||
|         trace!("Server::encode has_body={}, method={:?}", has_body, method); | ||||
|  | ||||
|         // hyper currently doesn't support returning 1xx status codes as a Response | ||||
|         // This is because Service only allows returning a single Response, and | ||||
|         // so if you try to reply with a e.g. 100 Continue, you have no way of | ||||
|         // replying with the latter status code response. | ||||
|         let ret = if head.subject.is_informational() { | ||||
|         let ret = if ::StatusCode::SwitchingProtocols == head.subject { | ||||
|             T::on_encode_upgrade(&mut head) | ||||
|                 .map(|_| Server::set_length(&mut head, has_body, method.as_ref())) | ||||
|         } else if head.subject.is_informational() { | ||||
|             error!("response with 1xx status code not supported"); | ||||
|             head = MessageHead::default(); | ||||
|             head.subject = ::StatusCode::InternalServerError; | ||||
|             head.headers.set(ContentLength(0)); | ||||
|             Err(::Error::Status) | ||||
|         } else { | ||||
|             Ok(ServerTransaction::set_length(&mut head, has_body, method.as_ref())) | ||||
|             Ok(Server::set_length(&mut head, has_body, method.as_ref())) | ||||
|         }; | ||||
|  | ||||
|  | ||||
| @@ -179,7 +194,7 @@ impl Http1Transaction for ServerTransaction { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ServerTransaction { | ||||
| impl Server<()> { | ||||
|     fn set_length(head: &mut MessageHead<StatusCode>, has_body: bool, method: Option<&Method>) -> Encoder { | ||||
|         // these are here thanks to borrowck | ||||
|         // `if method == Some(&Method::Get)` says the RHS doesn't live long enough | ||||
| @@ -214,7 +229,10 @@ impl ServerTransaction { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Http1Transaction for ClientTransaction { | ||||
| impl<T> Http1Transaction for Client<T> | ||||
| where | ||||
|     T: OnUpgrade, | ||||
| { | ||||
|     type Incoming = RawStatus; | ||||
|     type Outgoing = RequestLine; | ||||
|  | ||||
| @@ -262,7 +280,7 @@ impl Http1Transaction for ClientTransaction { | ||||
|         }, len))) | ||||
|     } | ||||
|  | ||||
|     fn decoder(inc: &MessageHead<Self::Incoming>, method: &mut Option<Method>) -> ::Result<Option<Decoder>> { | ||||
|     fn decoder(inc: &MessageHead<Self::Incoming>, method: &mut Option<Method>) -> ::Result<Decode> { | ||||
|         // According to https://tools.ietf.org/html/rfc7230#section-3.3.3 | ||||
|         // 1. HEAD responses, and Status 1xx, 204, and 304 cannot have a body. | ||||
|         // 2. Status 2xx to a CONNECT cannot have a body. | ||||
| @@ -274,30 +292,29 @@ impl Http1Transaction for ClientTransaction { | ||||
|  | ||||
|         match inc.subject.0 { | ||||
|             101 => { | ||||
|                 debug!("received 101 upgrade response, not supported"); | ||||
|                 return Err(::Error::Upgrade); | ||||
|                 return T::on_decode_upgrade().map(Decode::Final); | ||||
|             }, | ||||
|             100...199 => { | ||||
|                 trace!("ignoring informational response: {}", inc.subject.0); | ||||
|                 return Ok(None); | ||||
|                 return Ok(Decode::Ignore); | ||||
|             }, | ||||
|             204 | | ||||
|             304 => return Ok(Some(Decoder::length(0))), | ||||
|             304 => return Ok(Decode::Normal(Decoder::length(0))), | ||||
|             _ => (), | ||||
|         } | ||||
|         match *method { | ||||
|             Some(Method::Head) => { | ||||
|                 return Ok(Some(Decoder::length(0))); | ||||
|                 return Ok(Decode::Normal(Decoder::length(0))); | ||||
|             } | ||||
|             Some(Method::Connect) => match inc.subject.0 { | ||||
|                 200...299 => { | ||||
|                     return Ok(Some(Decoder::length(0))); | ||||
|                     return Ok(Decode::Final(Decoder::length(0))); | ||||
|                 }, | ||||
|                 _ => {}, | ||||
|             }, | ||||
|             Some(_) => {}, | ||||
|             None => { | ||||
|                 trace!("ClientTransaction::decoder is missing the Method"); | ||||
|                 trace!("Client::decoder is missing the Method"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
| @@ -307,28 +324,28 @@ impl Http1Transaction for ClientTransaction { | ||||
|                 debug!("HTTP/1.0 has Transfer-Encoding header"); | ||||
|                 Err(::Error::Header) | ||||
|             } else if codings.last() == Some(&header::Encoding::Chunked) { | ||||
|                 Ok(Some(Decoder::chunked())) | ||||
|                 Ok(Decode::Normal(Decoder::chunked())) | ||||
|             } else { | ||||
|                 trace!("not chunked. read till eof"); | ||||
|                 Ok(Some(Decoder::eof())) | ||||
|                 Ok(Decode::Normal(Decoder::eof())) | ||||
|             } | ||||
|         } else if let Some(&header::ContentLength(len)) = inc.headers.get() { | ||||
|             Ok(Some(Decoder::length(len))) | ||||
|             Ok(Decode::Normal(Decoder::length(len))) | ||||
|         } else if inc.headers.has::<header::ContentLength>() { | ||||
|             debug!("illegal Content-Length: {:?}", inc.headers.get_raw("Content-Length")); | ||||
|             Err(::Error::Header) | ||||
|         } else { | ||||
|             trace!("neither Transfer-Encoding nor Content-Length"); | ||||
|             Ok(Some(Decoder::eof())) | ||||
|             Ok(Decode::Normal(Decoder::eof())) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn encode(mut head: MessageHead<Self::Outgoing>, has_body: bool, method: &mut Option<Method>, dst: &mut Vec<u8>) -> ::Result<Encoder> { | ||||
|         trace!("ClientTransaction::encode has_body={}, method={:?}", has_body, method); | ||||
|         trace!("Client::encode has_body={}, method={:?}", has_body, method); | ||||
|  | ||||
|         *method = Some(head.subject.0.clone()); | ||||
|  | ||||
|         let body = ClientTransaction::set_length(&mut head, has_body); | ||||
|         let body = Client::set_length(&mut head, has_body); | ||||
|  | ||||
|         let init_cap = 30 + head.headers.len() * AVERAGE_HEADER_SIZE; | ||||
|         dst.reserve(init_cap); | ||||
| @@ -351,7 +368,7 @@ impl Http1Transaction for ClientTransaction { | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl ClientTransaction { | ||||
| impl Client<()> { | ||||
|     fn set_length(head: &mut RequestHead, has_body: bool) -> Encoder { | ||||
|         if has_body { | ||||
|             let can_chunked = head.version == Http11 | ||||
| @@ -393,6 +410,42 @@ fn set_length(headers: &mut Headers, can_chunked: bool) -> Encoder { | ||||
|     } | ||||
| } | ||||
|  | ||||
| pub trait OnUpgrade { | ||||
|     fn on_encode_upgrade(head: &mut MessageHead<StatusCode>) -> ::Result<()>; | ||||
|     fn on_decode_upgrade() -> ::Result<Decoder>; | ||||
| } | ||||
|  | ||||
| pub enum YesUpgrades {} | ||||
|  | ||||
| pub enum NoUpgrades {} | ||||
|  | ||||
| impl OnUpgrade for YesUpgrades { | ||||
|     fn on_encode_upgrade(_head: &mut MessageHead<StatusCode>) -> ::Result<()> { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn on_decode_upgrade() -> ::Result<Decoder> { | ||||
|         debug!("101 response received, upgrading"); | ||||
|         // 101 upgrades always have no body | ||||
|         Ok(Decoder::length(0)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl OnUpgrade for NoUpgrades { | ||||
|     fn on_encode_upgrade(head: &mut MessageHead<StatusCode>) -> ::Result<()> { | ||||
|         error!("response with 101 status code not supported"); | ||||
|         *head = MessageHead::default(); | ||||
|         head.subject = ::StatusCode::InternalServerError; | ||||
|         head.headers.set(ContentLength(0)); | ||||
|         Err(::Error::Status) | ||||
|     } | ||||
|  | ||||
|     fn on_decode_upgrade() -> ::Result<Decoder> { | ||||
|         debug!("received 101 upgrade response, not supported"); | ||||
|         return Err(::Error::Upgrade); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Clone, Copy)] | ||||
| struct HeaderIndices { | ||||
|     name: (usize, usize), | ||||
| @@ -456,16 +509,43 @@ fn extend(dst: &mut Vec<u8>, data: &[u8]) { | ||||
| mod tests { | ||||
|     use bytes::BytesMut; | ||||
|  | ||||
|     use proto::{MessageHead, ServerTransaction, ClientTransaction, Http1Transaction}; | ||||
|     use proto::{Decode, MessageHead}; | ||||
|     use super::{Decoder, Server as S, Client as C, NoUpgrades, Http1Transaction}; | ||||
|     use header::{ContentLength, TransferEncoding}; | ||||
|  | ||||
|     type Server = S<NoUpgrades>; | ||||
|     type Client = C<NoUpgrades>; | ||||
|  | ||||
|     impl Decode { | ||||
|         fn final_(self) -> Decoder { | ||||
|             match self { | ||||
|                 Decode::Final(d) => d, | ||||
|                 other => panic!("expected Final, found {:?}", other), | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         fn normal(self) -> Decoder { | ||||
|             match self { | ||||
|                 Decode::Normal(d) => d, | ||||
|                 other => panic!("expected Normal, found {:?}", other), | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         fn ignore(self) { | ||||
|             match self { | ||||
|                 Decode::Ignore => {}, | ||||
|                 other => panic!("expected Ignore, found {:?}", other), | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_parse_request() { | ||||
|         extern crate pretty_env_logger; | ||||
|         let _ = pretty_env_logger::try_init(); | ||||
|         let mut raw = BytesMut::from(b"GET /echo HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec()); | ||||
|         let expected_len = raw.len(); | ||||
|         let (req, len) = ServerTransaction::parse(&mut raw).unwrap().unwrap(); | ||||
|         let (req, len) = Server::parse(&mut raw).unwrap().unwrap(); | ||||
|         assert_eq!(len, expected_len); | ||||
|         assert_eq!(req.subject.0, ::Method::Get); | ||||
|         assert_eq!(req.subject.1, "/echo"); | ||||
| @@ -481,7 +561,7 @@ mod tests { | ||||
|         let _ = pretty_env_logger::try_init(); | ||||
|         let mut raw = BytesMut::from(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n".to_vec()); | ||||
|         let expected_len = raw.len(); | ||||
|         let (req, len) = ClientTransaction::parse(&mut raw).unwrap().unwrap(); | ||||
|         let (req, len) = Client::parse(&mut raw).unwrap().unwrap(); | ||||
|         assert_eq!(len, expected_len); | ||||
|         assert_eq!(req.subject.0, 200); | ||||
|         assert_eq!(req.subject.1, "OK"); | ||||
| @@ -493,17 +573,17 @@ mod tests { | ||||
|     #[test] | ||||
|     fn test_parse_request_errors() { | ||||
|         let mut raw = BytesMut::from(b"GET htt:p// HTTP/1.1\r\nHost: hyper.rs\r\n\r\n".to_vec()); | ||||
|         ServerTransaction::parse(&mut raw).unwrap_err(); | ||||
|         Server::parse(&mut raw).unwrap_err(); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
|     fn test_parse_raw_status() { | ||||
|         let mut raw = BytesMut::from(b"HTTP/1.1 200 OK\r\n\r\n".to_vec()); | ||||
|         let (res, _) = ClientTransaction::parse(&mut raw).unwrap().unwrap(); | ||||
|         let (res, _) = Client::parse(&mut raw).unwrap().unwrap(); | ||||
|         assert_eq!(res.subject.1, "OK"); | ||||
|  | ||||
|         let mut raw = BytesMut::from(b"HTTP/1.1 200 Howdy\r\n\r\n".to_vec()); | ||||
|         let (res, _) = ClientTransaction::parse(&mut raw).unwrap().unwrap(); | ||||
|         let (res, _) = Client::parse(&mut raw).unwrap().unwrap(); | ||||
|         assert_eq!(res.subject.1, "Howdy"); | ||||
|     } | ||||
|  | ||||
| @@ -516,32 +596,32 @@ mod tests { | ||||
|         let mut head = MessageHead::<::proto::RequestLine>::default(); | ||||
|  | ||||
|         head.subject.0 = ::Method::Get; | ||||
|         assert_eq!(Decoder::length(0), ServerTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(0), Server::decoder(&head, method).unwrap().normal()); | ||||
|         assert_eq!(*method, Some(::Method::Get)); | ||||
|  | ||||
|         head.subject.0 = ::Method::Post; | ||||
|         assert_eq!(Decoder::length(0), ServerTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(0), Server::decoder(&head, method).unwrap().normal()); | ||||
|         assert_eq!(*method, Some(::Method::Post)); | ||||
|  | ||||
|         head.headers.set(TransferEncoding::chunked()); | ||||
|         assert_eq!(Decoder::chunked(), ServerTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::chunked(), Server::decoder(&head, method).unwrap().normal()); | ||||
|         // transfer-encoding and content-length = chunked | ||||
|         head.headers.set(ContentLength(10)); | ||||
|         assert_eq!(Decoder::chunked(), ServerTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::chunked(), Server::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         head.headers.remove::<TransferEncoding>(); | ||||
|         assert_eq!(Decoder::length(10), ServerTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(10), Server::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         head.headers.set_raw("Content-Length", vec![b"5".to_vec(), b"5".to_vec()]); | ||||
|         assert_eq!(Decoder::length(5), ServerTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(5), Server::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         head.headers.set_raw("Content-Length", vec![b"10".to_vec(), b"11".to_vec()]); | ||||
|         ServerTransaction::decoder(&head, method).unwrap_err(); | ||||
|         Server::decoder(&head, method).unwrap_err(); | ||||
|  | ||||
|         head.headers.remove::<ContentLength>(); | ||||
|  | ||||
|         head.headers.set_raw("Transfer-Encoding", "gzip"); | ||||
|         ServerTransaction::decoder(&head, method).unwrap_err(); | ||||
|         Server::decoder(&head, method).unwrap_err(); | ||||
|  | ||||
|  | ||||
|         // http/1.0 | ||||
| @@ -549,14 +629,14 @@ mod tests { | ||||
|         head.headers.clear(); | ||||
|  | ||||
|         // 1.0 requests can only have bodies if content-length is set | ||||
|         assert_eq!(Decoder::length(0), ServerTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(0), Server::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         head.headers.set(TransferEncoding::chunked()); | ||||
|         ServerTransaction::decoder(&head, method).unwrap_err(); | ||||
|         Server::decoder(&head, method).unwrap_err(); | ||||
|         head.headers.remove::<TransferEncoding>(); | ||||
|  | ||||
|         head.headers.set(ContentLength(15)); | ||||
|         assert_eq!(Decoder::length(15), ServerTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(15), Server::decoder(&head, method).unwrap().normal()); | ||||
|     } | ||||
|  | ||||
|     #[test] | ||||
| @@ -567,64 +647,64 @@ mod tests { | ||||
|         let mut head = MessageHead::<::proto::RawStatus>::default(); | ||||
|  | ||||
|         head.subject.0 = 204; | ||||
|         assert_eq!(Decoder::length(0), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(0), Client::decoder(&head, method).unwrap().normal()); | ||||
|         head.subject.0 = 304; | ||||
|         assert_eq!(Decoder::length(0), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(0), Client::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         head.subject.0 = 200; | ||||
|         assert_eq!(Decoder::eof(), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::eof(), Client::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         *method = Some(::Method::Head); | ||||
|         assert_eq!(Decoder::length(0), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(0), Client::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         *method = Some(::Method::Connect); | ||||
|         assert_eq!(Decoder::length(0), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(0), Client::decoder(&head, method).unwrap().final_()); | ||||
|  | ||||
|  | ||||
|         // CONNECT receiving non 200 can have a body | ||||
|         head.subject.0 = 404; | ||||
|         head.headers.set(ContentLength(10)); | ||||
|         assert_eq!(Decoder::length(10), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(10), Client::decoder(&head, method).unwrap().normal()); | ||||
|         head.headers.remove::<ContentLength>(); | ||||
|  | ||||
|  | ||||
|         *method = Some(::Method::Get); | ||||
|         head.headers.set(TransferEncoding::chunked()); | ||||
|         assert_eq!(Decoder::chunked(), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::chunked(), Client::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         // transfer-encoding and content-length = chunked | ||||
|         head.headers.set(ContentLength(10)); | ||||
|         assert_eq!(Decoder::chunked(), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::chunked(), Client::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         head.headers.remove::<TransferEncoding>(); | ||||
|         assert_eq!(Decoder::length(10), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(10), Client::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         head.headers.set_raw("Content-Length", vec![b"5".to_vec(), b"5".to_vec()]); | ||||
|         assert_eq!(Decoder::length(5), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::length(5), Client::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         head.headers.set_raw("Content-Length", vec![b"10".to_vec(), b"11".to_vec()]); | ||||
|         ClientTransaction::decoder(&head, method).unwrap_err(); | ||||
|         Client::decoder(&head, method).unwrap_err(); | ||||
|         head.headers.clear(); | ||||
|  | ||||
|         // 1xx status codes | ||||
|         head.subject.0 = 100; | ||||
|         assert!(ClientTransaction::decoder(&head, method).unwrap().is_none()); | ||||
|         Client::decoder(&head, method).unwrap().ignore(); | ||||
|  | ||||
|         head.subject.0 = 103; | ||||
|         assert!(ClientTransaction::decoder(&head, method).unwrap().is_none()); | ||||
|         Client::decoder(&head, method).unwrap().ignore(); | ||||
|  | ||||
|         // 101 upgrade not supported yet | ||||
|         head.subject.0 = 101; | ||||
|         ClientTransaction::decoder(&head, method).unwrap_err(); | ||||
|         Client::decoder(&head, method).unwrap_err(); | ||||
|         head.subject.0 = 200; | ||||
|  | ||||
|         // http/1.0 | ||||
|         head.version = ::HttpVersion::Http10; | ||||
|  | ||||
|         assert_eq!(Decoder::eof(), ClientTransaction::decoder(&head, method).unwrap().unwrap()); | ||||
|         assert_eq!(Decoder::eof(), Client::decoder(&head, method).unwrap().normal()); | ||||
|  | ||||
|         head.headers.set(TransferEncoding::chunked()); | ||||
|         ClientTransaction::decoder(&head, method).unwrap_err(); | ||||
|         Client::decoder(&head, method).unwrap_err(); | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "nightly")] | ||||
| @@ -656,7 +736,7 @@ mod tests { | ||||
|  | ||||
|         b.bytes = len as u64; | ||||
|         b.iter(|| { | ||||
|             ServerTransaction::parse(&mut raw).unwrap(); | ||||
|             Server::parse(&mut raw).unwrap(); | ||||
|             restart(&mut raw, len); | ||||
|         }); | ||||
|  | ||||
| @@ -688,7 +768,7 @@ mod tests { | ||||
|  | ||||
|         b.iter(|| { | ||||
|             let mut vec = Vec::new(); | ||||
|             ServerTransaction::encode(head.clone(), true, &mut None, &mut vec).unwrap(); | ||||
|             Server::encode(head.clone(), true, &mut None, &mut vec).unwrap(); | ||||
|             assert_eq!(vec.len(), len); | ||||
|             ::test::black_box(vec); | ||||
|         }) | ||||
|   | ||||
| @@ -16,7 +16,7 @@ pub use self::body::Body; | ||||
| #[cfg(feature = "tokio-proto")] | ||||
| pub use self::body::TokioBody; | ||||
| pub use self::chunk::Chunk; | ||||
| pub use self::h1::{dispatch, Conn, KeepAlive, KA}; | ||||
| pub use self::h1::{dispatch, Conn}; | ||||
|  | ||||
| mod body; | ||||
| mod chunk; | ||||
| @@ -134,17 +134,16 @@ pub fn expecting_continue(version: HttpVersion, headers: &Headers) -> bool { | ||||
|     ret | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub enum ServerTransaction {} | ||||
| pub type ServerTransaction = h1::role::Server<h1::role::NoUpgrades>; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub enum ClientTransaction {} | ||||
| pub type ClientTransaction = h1::role::Client<h1::role::NoUpgrades>; | ||||
| pub type ClientUpgradeTransaction = h1::role::Client<h1::role::YesUpgrades>; | ||||
|  | ||||
| pub trait Http1Transaction { | ||||
|     type Incoming; | ||||
|     type Outgoing: Default; | ||||
|     fn parse(bytes: &mut BytesMut) -> ParseResult<Self::Incoming>; | ||||
|     fn decoder(head: &MessageHead<Self::Incoming>, method: &mut Option<::Method>) -> ::Result<Option<h1::Decoder>>; | ||||
|     fn decoder(head: &MessageHead<Self::Incoming>, method: &mut Option<::Method>) -> ::Result<Decode>; | ||||
|     fn encode(head: MessageHead<Self::Outgoing>, has_body: bool, method: &mut Option<Method>, dst: &mut Vec<u8>) -> ::Result<h1::Encoder>; | ||||
|     fn on_error(err: &::Error) -> Option<MessageHead<Self::Outgoing>>; | ||||
|  | ||||
| @@ -154,6 +153,16 @@ pub trait Http1Transaction { | ||||
|  | ||||
| pub type ParseResult<T> = ::Result<Option<(MessageHead<T>, usize)>>; | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub enum Decode { | ||||
|     /// Decode normally. | ||||
|     Normal(h1::Decoder), | ||||
|     /// After this decoder is done, HTTP is done. | ||||
|     Final(h1::Decoder), | ||||
|     /// A header block that should be ignored, like unknown 1xx responses. | ||||
|     Ignore, | ||||
| } | ||||
|  | ||||
| #[test] | ||||
| fn test_should_keep_alive() { | ||||
|     let mut headers = Headers::new(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user