FramedWrite
This commit is contained in:
		| @@ -9,6 +9,7 @@ tokio-io = "0.1" | |||||||
| tokio-timer = { git = "https://github.com/tokio-rs/tokio-timer" } | tokio-timer = { git = "https://github.com/tokio-rs/tokio-timer" } | ||||||
| bytes = "0.4" | bytes = "0.4" | ||||||
| http = { path = "/Users/carllerche/Code/Oss/Tokio/tower/http" } | http = { path = "/Users/carllerche/Code/Oss/Tokio/tower/http" } | ||||||
|  | byteorder = "1.0" | ||||||
| log = "0.3.8" | log = "0.3.8" | ||||||
| # tower = { path = "/Users/carllerche/Code/Oss/Tokio/tower/tower-http" } | # tower = { path = "/Users/carllerche/Code/Oss/Tokio/tower/tower-http" } | ||||||
| fnv = "1.0.5" | fnv = "1.0.5" | ||||||
|   | |||||||
| @@ -1,8 +1,13 @@ | |||||||
| use super::StreamId; | use super::StreamId; | ||||||
|  | use {frame, hpack}; | ||||||
|  | use frame::{Head, Kind}; | ||||||
| use util::byte_str::ByteStr; | use util::byte_str::ByteStr; | ||||||
|  |  | ||||||
| use http::{Method, StatusCode}; | use http::{Method, StatusCode}; | ||||||
| use http::header::{self, HeaderMap, HeaderValue}; | use http::header::{self, HeaderMap, HeaderName, HeaderValue}; | ||||||
|  |  | ||||||
|  | use bytes::BytesMut; | ||||||
|  | use byteorder::{BigEndian, ByteOrder}; | ||||||
|  |  | ||||||
| /// Header frame | /// Header frame | ||||||
| /// | /// | ||||||
| @@ -41,6 +46,18 @@ pub struct PushPromise { | |||||||
|     flags: HeadersFlag, |     flags: HeadersFlag, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Continuation { | ||||||
|  |     /// Stream ID of continuation frame | ||||||
|  |     stream_id: StreamId, | ||||||
|  |  | ||||||
|  |     /// Argument to pass to the HPACK encoder to resume encoding | ||||||
|  |     hpack: hpack::EncodeState, | ||||||
|  |  | ||||||
|  |     /// remaining headers to encode | ||||||
|  |     headers: Iter, | ||||||
|  | } | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct StreamDependency { | pub struct StreamDependency { | ||||||
|     /// The ID of the stream dependency target |     /// The ID of the stream dependency target | ||||||
| @@ -85,6 +102,90 @@ const ALL: u8 = END_STREAM | |||||||
|               | PADDED |               | PADDED | ||||||
|               | PRIORITY; |               | PRIORITY; | ||||||
|  |  | ||||||
|  | // ===== impl Headers ===== | ||||||
|  |  | ||||||
|  | impl Headers { | ||||||
|  |     pub fn encode(self, encoder: &mut hpack::Encoder, dst: &mut BytesMut) | ||||||
|  |         -> Option<Continuation> | ||||||
|  |     { | ||||||
|  |         let head = self.head(); | ||||||
|  |         let pos = dst.len(); | ||||||
|  |  | ||||||
|  |         // At this point, we don't know how big the h2 frame will be. | ||||||
|  |         // So, we write the head with length 0, then write the body, and | ||||||
|  |         // finally write the length once we know the size. | ||||||
|  |         head.encode(0, dst); | ||||||
|  |  | ||||||
|  |         // Encode the frame | ||||||
|  |         let mut headers = Iter { | ||||||
|  |             pseudo: Some(self.pseudo), | ||||||
|  |             headers: self.headers.into_iter(), | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         let ret = match encoder.encode(None, &mut headers, dst) { | ||||||
|  |             hpack::Encode::Full => None, | ||||||
|  |             hpack::Encode::Partial(state) => { | ||||||
|  |                 Some(Continuation { | ||||||
|  |                     stream_id: self.stream_id, | ||||||
|  |                     hpack: state, | ||||||
|  |                     headers: headers, | ||||||
|  |                 }) | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Compute the frame length | ||||||
|  |         let len = (dst.len() - pos) - frame::HEADER_LEN; | ||||||
|  |  | ||||||
|  |         // Write the frame length | ||||||
|  |         BigEndian::write_u32(&mut dst[pos..pos+3], len as u32); | ||||||
|  |  | ||||||
|  |         ret | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn head(&self) -> Head { | ||||||
|  |         Head::new(Kind::Data, self.flags.into(), self.stream_id) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Iter ===== | ||||||
|  |  | ||||||
|  | impl Iterator for Iter { | ||||||
|  |     type Item = hpack::Header<Option<HeaderName>>; | ||||||
|  |  | ||||||
|  |     fn next(&mut self) -> Option<Self::Item> { | ||||||
|  |         use hpack::Header::*; | ||||||
|  |  | ||||||
|  |         if let Some(ref mut pseudo) = self.pseudo { | ||||||
|  |             if let Some(method) = pseudo.method.take() { | ||||||
|  |                 return Some(Method(method)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if let Some(scheme) = pseudo.scheme.take() { | ||||||
|  |                 return Some(Scheme(scheme)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if let Some(authority) = pseudo.authority.take() { | ||||||
|  |                 return Some(Authority(authority)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if let Some(path) = pseudo.path.take() { | ||||||
|  |                 return Some(Path(path)); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if let Some(status) = pseudo.status.take() { | ||||||
|  |                 return Some(Status(status)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         self.pseudo = None; | ||||||
|  |  | ||||||
|  |         self.headers.next() | ||||||
|  |             .map(|(name, value)| { | ||||||
|  |                 Field { name: name, value: value} | ||||||
|  |             }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| // ===== impl HeadersFlag ===== | // ===== impl HeadersFlag ===== | ||||||
|  |  | ||||||
| impl HeadersFlag { | impl HeadersFlag { | ||||||
| @@ -112,3 +213,9 @@ impl HeadersFlag { | |||||||
|         self.0 & PRIORITY == PRIORITY |         self.0 & PRIORITY == PRIORITY | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl From<HeadersFlag> for u8 { | ||||||
|  |     fn from(src: HeadersFlag) -> u8 { | ||||||
|  |         src.0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -32,7 +32,7 @@ mod util; | |||||||
|  |  | ||||||
| pub use self::data::Data; | pub use self::data::Data; | ||||||
| pub use self::head::{Head, Kind, StreamId}; | pub use self::head::{Head, Kind, StreamId}; | ||||||
| pub use self::headers::{Headers, PushPromise}; | pub use self::headers::{Headers, PushPromise, Continuation}; | ||||||
| pub use self::settings::{Settings, SettingSet}; | pub use self::settings::{Settings, SettingSet}; | ||||||
|  |  | ||||||
| // Re-export some constants | // Re-export some constants | ||||||
|   | |||||||
| @@ -76,7 +76,7 @@ impl Encoder { | |||||||
|  |  | ||||||
|     /// Encode a set of headers into the provide buffer |     /// Encode a set of headers into the provide buffer | ||||||
|     pub fn encode<I>(&mut self, resume: Option<EncodeState>, headers: &mut I, dst: &mut BytesMut) |     pub fn encode<I>(&mut self, resume: Option<EncodeState>, headers: &mut I, dst: &mut BytesMut) | ||||||
|         -> Result<Encode, EncoderError> |         -> Encode | ||||||
|         where I: Iterator<Item=Header<Option<HeaderName>>>, |         where I: Iterator<Item=Header<Option<HeaderName>>>, | ||||||
|     { |     { | ||||||
|         let len = dst.len(); |         let len = dst.len(); | ||||||
| @@ -86,7 +86,7 @@ impl Encoder { | |||||||
|                 dst.truncate(len); |                 dst.truncate(len); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return Err(e); |             unreachable!(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if let Some(resume) = resume { |         if let Some(resume) = resume { | ||||||
| @@ -104,9 +104,9 @@ impl Encoder { | |||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             if try!(is_buffer_overflow(res)) { |             if res.is_err() { | ||||||
|                 dst.truncate(len); |                 dst.truncate(len); | ||||||
|                 return Ok(Encode::Partial(resume)); |                 return Encode::Partial(resume); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -122,12 +122,12 @@ impl Encoder { | |||||||
|                     let index = self.table.index(header); |                     let index = self.table.index(header); | ||||||
|                     let res = self.encode_header(&index, dst); |                     let res = self.encode_header(&index, dst); | ||||||
|  |  | ||||||
|                     if try!(is_buffer_overflow(res)) { |                     if res.is_err() { | ||||||
|                         dst.truncate(len); |                         dst.truncate(len); | ||||||
|                         return Ok(Encode::Partial(EncodeState { |                         return Encode::Partial(EncodeState { | ||||||
|                             index: index, |                             index: index, | ||||||
|                             value: None, |                             value: None, | ||||||
|                         })); |                         }); | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     last_index = Some(index); |                     last_index = Some(index); | ||||||
| @@ -142,18 +142,18 @@ impl Encoder { | |||||||
|                         &value, |                         &value, | ||||||
|                         dst); |                         dst); | ||||||
|  |  | ||||||
|                     if try!(is_buffer_overflow(res)) { |                     if res.is_err() { | ||||||
|                         dst.truncate(len); |                         dst.truncate(len); | ||||||
|                         return Ok(Encode::Partial(EncodeState { |                         return Encode::Partial(EncodeState { | ||||||
|                             index: last_index.unwrap(), |                             index: last_index.unwrap(), | ||||||
|                             value: Some(value), |                             value: Some(value), | ||||||
|                         })); |                         }); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         Ok(Encode::Full) |         Encode::Full | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn encode_size_updates(&mut self, dst: &mut BytesMut) -> Result<(), EncoderError> { |     fn encode_size_updates(&mut self, dst: &mut BytesMut) -> Result<(), EncoderError> { | ||||||
| @@ -417,14 +417,6 @@ fn encode_int_one_byte(value: usize, prefix_bits: usize) -> bool { | |||||||
|     value < (1 << prefix_bits) - 1 |     value < (1 << prefix_bits) - 1 | ||||||
| } | } | ||||||
|  |  | ||||||
| fn is_buffer_overflow(res: Result<(), EncoderError>) -> Result<bool, EncoderError> { |  | ||||||
|     match res { |  | ||||||
|         Err(EncoderError::BufferOverflow) => Ok(true), |  | ||||||
|         Err(e) => Err(e), |  | ||||||
|         Ok(_) => Ok(false), |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod test { | mod test { | ||||||
|     use super::*; |     use super::*; | ||||||
| @@ -789,7 +781,7 @@ mod test { | |||||||
|             }, |             }, | ||||||
|         ].into_iter(); |         ].into_iter(); | ||||||
|  |  | ||||||
|         let resume = match encoder.encode(None, &mut input, &mut dst).unwrap() { |         let resume = match encoder.encode(None, &mut input, &mut dst) { | ||||||
|             Encode::Partial(r) => r, |             Encode::Partial(r) => r, | ||||||
|             _ => panic!(), |             _ => panic!(), | ||||||
|         }; |         }; | ||||||
| @@ -801,7 +793,7 @@ mod test { | |||||||
|  |  | ||||||
|         dst.clear(); |         dst.clear(); | ||||||
|  |  | ||||||
|         match encoder.encode(Some(resume), &mut input, &mut dst).unwrap() { |         match encoder.encode(Some(resume), &mut input, &mut dst) { | ||||||
|             Encode::Full => {} |             Encode::Full => {} | ||||||
|             _ => panic!(), |             _ => panic!(), | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -214,7 +214,7 @@ impl FuzzHpack { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             loop { |             loop { | ||||||
|                 match encoder.encode(index.take(), &mut input, &mut buf).unwrap() { |                 match encoder.encode(index.take(), &mut input, &mut buf) { | ||||||
|                     Encode::Full => break, |                     Encode::Full => break, | ||||||
|                     Encode::Partial(i) => { |                     Encode::Partial(i) => { | ||||||
|                         index = Some(i); |                         index = Some(i); | ||||||
| @@ -531,7 +531,7 @@ fn test_story(story: Value) { | |||||||
|                 Header::new(name.clone().into(), value.clone().into()).unwrap().into() |                 Header::new(name.clone().into(), value.clone().into()).unwrap().into() | ||||||
|             }).collect(); |             }).collect(); | ||||||
|  |  | ||||||
|             encoder.encode(None, &mut input.clone().into_iter(), &mut buf).unwrap(); |             encoder.encode(None, &mut input.clone().into_iter(), &mut buf); | ||||||
|  |  | ||||||
|             decoder.decode(&buf.into(), |e| { |             decoder.decode(&buf.into(), |e| { | ||||||
|                 assert_eq!(e, input.remove(0).reify().unwrap()); |                 assert_eq!(e, input.remove(0).reify().unwrap()); | ||||||
|   | |||||||
| @@ -16,6 +16,8 @@ extern crate bytes; | |||||||
| // Hash function used for HPACK encoding | // Hash function used for HPACK encoding | ||||||
| extern crate fnv; | extern crate fnv; | ||||||
|  |  | ||||||
|  | extern crate byteorder; | ||||||
|  |  | ||||||
| #[macro_use] | #[macro_use] | ||||||
| extern crate log; | extern crate log; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| use {ConnectionError, Reason}; | use {ConnectionError, Reason}; | ||||||
| use frame::{self, Data, Frame, Error, Headers, PushPromise, Settings}; | use frame::{self, Frame, Error}; | ||||||
| use hpack; | use hpack; | ||||||
|  |  | ||||||
| use futures::*; | use futures::*; | ||||||
| @@ -19,10 +19,7 @@ pub struct FramedWrite<T> { | |||||||
|     hpack: hpack::Encoder, |     hpack: hpack::Encoder, | ||||||
|  |  | ||||||
|     /// Write buffer |     /// Write buffer | ||||||
|     buf: BytesMut, |     buf: Cursor<BytesMut>, | ||||||
|  |  | ||||||
|     /// Position in the frame |  | ||||||
|     pos: usize, |  | ||||||
|  |  | ||||||
|     /// Next frame to encode |     /// Next frame to encode | ||||||
|     next: Option<Next>, |     next: Option<Next>, | ||||||
| @@ -40,16 +37,7 @@ enum Next { | |||||||
|         /// Data frame to encode |         /// Data frame to encode | ||||||
|         data: frame::Data |         data: frame::Data | ||||||
|     }, |     }, | ||||||
|     Continuation { |     Continuation(frame::Continuation), | ||||||
|         /// Stream ID of continuation frame |  | ||||||
|         stream_id: frame::StreamId, |  | ||||||
|  |  | ||||||
|         /// Argument to pass to the HPACK encoder to resume encoding |  | ||||||
|         resume: hpack::EncodeState, |  | ||||||
|  |  | ||||||
|         /// remaining headers to encode |  | ||||||
|         rem: header::IntoIter<HeaderValue>, |  | ||||||
|     }, |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Initialze the connection with this amount of write buffer. | /// Initialze the connection with this amount of write buffer. | ||||||
| @@ -68,18 +56,21 @@ impl<T: AsyncWrite> FramedWrite<T> { | |||||||
|         FramedWrite { |         FramedWrite { | ||||||
|             inner: inner, |             inner: inner, | ||||||
|             hpack: hpack::Encoder::default(), |             hpack: hpack::Encoder::default(), | ||||||
|             buf: BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY), |             buf: Cursor::new(BytesMut::with_capacity(DEFAULT_BUFFER_CAPACITY)), | ||||||
|             pos: 0, |  | ||||||
|             next: None, |             next: None, | ||||||
|             max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE, |             max_frame_size: frame::DEFAULT_MAX_FRAME_SIZE, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn has_capacity(&self) -> bool { |     fn has_capacity(&self) -> bool { | ||||||
|         self.next.is_none() && self.buf.remaining_mut() >= MIN_BUFFER_CAPACITY |         self.next.is_none() && self.buf.get_ref().remaining_mut() >= MIN_BUFFER_CAPACITY | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn frame_len(&self, data: &Data) -> usize { |     fn is_empty(&self) -> bool { | ||||||
|  |         self.next.is_none() && self.buf.has_remaining() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn frame_len(&self, data: &frame::Data) -> usize { | ||||||
|         cmp::min(self.max_frame_size, data.len()) |         cmp::min(self.max_frame_size, data.len()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -105,7 +96,7 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> { | |||||||
|                     let len = self.frame_len(&v); |                     let len = self.frame_len(&v); | ||||||
|  |  | ||||||
|                     // Encode the frame head to the buffer |                     // Encode the frame head to the buffer | ||||||
|                     head.encode(len, &mut self.buf); |                     head.encode(len, self.buf.get_mut()); | ||||||
|  |  | ||||||
|                     // Save the data frame |                     // Save the data frame | ||||||
|                     self.next = Some(Next::Data { |                     self.next = Some(Next::Data { | ||||||
| @@ -113,17 +104,19 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> { | |||||||
|                         data: v, |                         data: v, | ||||||
|                     }); |                     }); | ||||||
|                 } else { |                 } else { | ||||||
|                     v.encode(&mut self.buf); |                     v.encode(self.buf.get_mut()); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             Frame::Headers(v) => { |             Frame::Headers(v) => { | ||||||
|                 unimplemented!(); |                 if let Some(continuation) = v.encode(&mut self.hpack, self.buf.get_mut()) { | ||||||
|  |                     self.next = Some(Next::Continuation(continuation)); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             Frame::PushPromise(v) => { |             Frame::PushPromise(v) => { | ||||||
|                 unimplemented!(); |                 unimplemented!(); | ||||||
|             } |             } | ||||||
|             Frame::Settings(v) => { |             Frame::Settings(v) => { | ||||||
|                 v.encode(&mut self.buf); |                 v.encode(self.buf.get_mut()); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -131,7 +124,22 @@ impl<T: AsyncWrite> Sink for FramedWrite<T> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { |     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||||
|         unimplemented!(); |         // TODO: implement | ||||||
|  |         match self.next { | ||||||
|  |             Some(Next::Data { .. }) => unimplemented!(), | ||||||
|  |             _ => {} | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // As long as there is data to write, try to write it! | ||||||
|  |         while !self.is_empty() { | ||||||
|  |             try_ready!(self.inner.write_buf(&mut self.buf)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Clear internal buffer | ||||||
|  |         self.buf.set_position(0); | ||||||
|  |         self.buf.get_mut().clear(); | ||||||
|  |  | ||||||
|  |         Ok(Async::Ready(())) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn close(&mut self) -> Poll<(), ConnectionError> { |     fn close(&mut self) -> Poll<(), ConnectionError> { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user