Merge pull request #12 from carllerche/stream-api
Restructure API using a handle per stream
This commit is contained in:
		| @@ -8,7 +8,7 @@ futures = "0.1" | |||||||
| tokio-io = "0.1" | tokio-io = "0.1" | ||||||
| tokio-timer = "0.1" | tokio-timer = "0.1" | ||||||
| bytes = "0.4" | bytes = "0.4" | ||||||
| http = { git = "https://github.com/carllerche/http" } | http = { git = "https://github.com/carllerche/http", branch = "uri-try-from-parts" } | ||||||
| byteorder = "1.0" | byteorder = "1.0" | ||||||
| log = "0.3.8" | log = "0.3.8" | ||||||
| fnv = "1.0.5" | fnv = "1.0.5" | ||||||
|   | |||||||
| @@ -8,23 +8,29 @@ extern crate openssl; | |||||||
| extern crate io_dump; | extern crate io_dump; | ||||||
| extern crate env_logger; | extern crate env_logger; | ||||||
|  |  | ||||||
| use h2::client; | use h2::client::Client; | ||||||
|  |  | ||||||
| use http::request; |  | ||||||
|  |  | ||||||
|  | use http::{method, Request}; | ||||||
| use futures::*; | use futures::*; | ||||||
|  |  | ||||||
| use tokio_core::reactor; | use tokio_core::reactor; | ||||||
| use tokio_core::net::TcpStream; | use tokio_core::net::TcpStream; | ||||||
|  |  | ||||||
|  | use std::net::ToSocketAddrs; | ||||||
|  |  | ||||||
| pub fn main() { | pub fn main() { | ||||||
|     let _ = env_logger::init(); |     let _ = env_logger::init(); | ||||||
|  |  | ||||||
|     let mut core = reactor::Core::new().unwrap();; |     // Sync DNS resolution. | ||||||
|  |     let addr = "http2.akamai.com:443".to_socket_addrs() | ||||||
|  |         .unwrap().next().unwrap(); | ||||||
|  |  | ||||||
|     let tcp = TcpStream::connect( |     println!("ADDR: {:?}", addr); | ||||||
|         &"23.39.23.98:443".parse().unwrap(), |  | ||||||
|         &core.handle()); |     let mut core = reactor::Core::new().unwrap();; | ||||||
|  |     let handle = core.handle(); | ||||||
|  |  | ||||||
|  |     let tcp = TcpStream::connect(&addr, &handle); | ||||||
|  |  | ||||||
|     let tcp = tcp.then(|res| { |     let tcp = tcp.then(|res| { | ||||||
|         use openssl::ssl::{SslMethod, SslConnectorBuilder}; |         use openssl::ssl::{SslMethod, SslConnectorBuilder}; | ||||||
| @@ -46,24 +52,29 @@ pub fn main() { | |||||||
|                 // Dump output to stdout |                 // Dump output to stdout | ||||||
|                 let tls = io_dump::Dump::to_stdout(tls); |                 let tls = io_dump::Dump::to_stdout(tls); | ||||||
|  |  | ||||||
|                 client::handshake(tls) |                 println!("Starting client handshake"); | ||||||
|  |                 Client::handshake(tls) | ||||||
|             }) |             }) | ||||||
|             .then(|res| { |             .then(|res| { | ||||||
|                 let conn = res.unwrap(); |                 let mut h2 = res.unwrap(); | ||||||
|  |  | ||||||
|                 let mut request = request::Head::default(); |                 let request = Request::builder() | ||||||
|                 request.uri = "https://http2.akamai.com/".parse().unwrap(); |                     .method(method::GET) | ||||||
|                 // request.version = version::H2; |                     .uri("https://http2.akamai.com/") | ||||||
|  |                     .body(()).unwrap(); | ||||||
|  |  | ||||||
|                 conn.send_request(1.into(), request, true) |                 let stream = h2.request(request, true).unwrap(); | ||||||
|             }) |  | ||||||
|             .then(|res| { |                 let stream = stream.and_then(|response| { | ||||||
|                 let conn = res.unwrap(); |                     let (_, body) = response.into_parts(); | ||||||
|                 // Get the next message |  | ||||||
|                 conn.for_each(|frame| { |                     body.for_each(|chunk| { | ||||||
|                     println!("RX: {:?}", frame); |                         println!("RX: {:?}", chunk); | ||||||
|                         Ok(()) |                         Ok(()) | ||||||
|                     }) |                     }) | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |                 h2.join(stream) | ||||||
|             }) |             }) | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | /* | ||||||
| extern crate h2; | extern crate h2; | ||||||
| extern crate http; | extern crate http; | ||||||
| extern crate futures; | extern crate futures; | ||||||
| @@ -59,3 +60,6 @@ pub fn main() { | |||||||
|  |  | ||||||
|     core.run(tcp).unwrap(); |     core.run(tcp).unwrap(); | ||||||
| } | } | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pub fn main() {} | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | /* | ||||||
| extern crate h2; | extern crate h2; | ||||||
| extern crate http; | extern crate http; | ||||||
| extern crate futures; | extern crate futures; | ||||||
| @@ -72,3 +73,6 @@ pub fn main() { | |||||||
|  |  | ||||||
|     core.run(server).unwrap(); |     core.run(server).unwrap(); | ||||||
| } | } | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | pub fn main() {} | ||||||
|   | |||||||
							
								
								
									
										219
									
								
								src/client.rs
									
									
									
									
									
								
							
							
						
						
									
										219
									
								
								src/client.rs
									
									
									
									
									
								
							| @@ -1,7 +1,9 @@ | |||||||
| use {frame, proto, Peer, ConnectionError, StreamId}; | use {frame, ConnectionError, StreamId}; | ||||||
|  | use proto::{self, Connection}; | ||||||
|  | use error::Reason::*; | ||||||
|  |  | ||||||
| use http; | use http::{self, Request, Response}; | ||||||
| use futures::{Future, Poll, Sink, AsyncSink}; | use futures::{self, Future, Poll, Sink, AsyncSink}; | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
| use bytes::{Bytes, IntoBuf}; | use bytes::{Bytes, IntoBuf}; | ||||||
|  |  | ||||||
| @@ -10,29 +12,50 @@ use std::fmt; | |||||||
| /// In progress H2 connection binding | /// In progress H2 connection binding | ||||||
| pub struct Handshake<T, B: IntoBuf = Bytes> { | pub struct Handshake<T, B: IntoBuf = Bytes> { | ||||||
|     // TODO: unbox |     // TODO: unbox | ||||||
|     inner: Box<Future<Item = Connection<T, B>, Error = ConnectionError>>, |     inner: Box<Future<Item = Client<T, B>, Error = ConnectionError>>, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub(crate) struct Peer; | ||||||
|  |  | ||||||
| /// Marker type indicating a client peer | /// Marker type indicating a client peer | ||||||
| #[derive(Debug)] | pub struct Client<T, B: IntoBuf> { | ||||||
| pub struct Client; |     connection: Connection<T, Peer, B>, | ||||||
|  |  | ||||||
| pub type Connection<T, B = Bytes> = super::Connection<T, Client, B>; |  | ||||||
|  |  | ||||||
| pub fn handshake<T>(io: T) -> Handshake<T, Bytes> |  | ||||||
|     where T: AsyncRead + AsyncWrite + 'static, |  | ||||||
| { |  | ||||||
|     handshake2(io) |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Stream<B: IntoBuf> { | ||||||
|  |     inner: proto::StreamRef<Peer, B::Buf>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Body<B: IntoBuf> { | ||||||
|  |     inner: proto::StreamRef<Peer, B::Buf>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Chunk<B: IntoBuf> { | ||||||
|  |     inner: proto::Chunk<Peer, B::Buf>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T> Client<T, Bytes> | ||||||
|  |     where T: AsyncRead + AsyncWrite + 'static, | ||||||
|  | { | ||||||
|  |     pub fn handshake(io: T) -> Handshake<T, Bytes> { | ||||||
|  |         Client::handshake2(io) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T, B> Client<T, B> | ||||||
|  |     // TODO: Get rid of 'static | ||||||
|  |     where T: AsyncRead + AsyncWrite + 'static, | ||||||
|  |           B: IntoBuf + 'static, | ||||||
|  | { | ||||||
|     /// Bind an H2 client connection. |     /// Bind an H2 client connection. | ||||||
|     /// |     /// | ||||||
|     /// Returns a future which resolves to the connection value once the H2 |     /// Returns a future which resolves to the connection value once the H2 | ||||||
|     /// handshake has been completed. |     /// handshake has been completed. | ||||||
| pub fn handshake2<T, B>(io: T) -> Handshake<T, B> |     pub fn handshake2(io: T) -> Handshake<T, B> { | ||||||
|     where T: AsyncRead + AsyncWrite + 'static, |  | ||||||
|           B: IntoBuf + 'static, |  | ||||||
| { |  | ||||||
|         use tokio_io::io; |         use tokio_io::io; | ||||||
|  |  | ||||||
|         debug!("binding client connection"); |         debug!("binding client connection"); | ||||||
| @@ -48,7 +71,8 @@ pub fn handshake2<T, B>(io: T) -> Handshake<T, B> | |||||||
|                 // Send initial settings frame |                 // Send initial settings frame | ||||||
|                 match framed_write.start_send(settings.into()) { |                 match framed_write.start_send(settings.into()) { | ||||||
|                     Ok(AsyncSink::Ready) => { |                     Ok(AsyncSink::Ready) => { | ||||||
|                     Ok(proto::from_framed_write(framed_write)) |                         let conn = proto::from_framed_write(framed_write); | ||||||
|  |                         Ok(Client { connection: conn }) | ||||||
|                     } |                     } | ||||||
|                     Ok(_) => unreachable!(), |                     Ok(_) => unreachable!(), | ||||||
|                     Err(e) => Err(ConnectionError::from(e)), |                     Err(e) => Err(ConnectionError::from(e)), | ||||||
| @@ -58,9 +82,131 @@ pub fn handshake2<T, B>(io: T) -> Handshake<T, B> | |||||||
|         Handshake { inner: Box::new(handshake) } |         Handshake { inner: Box::new(handshake) } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| impl Peer for Client { |     /// Returns `Ready` when the connection can initialize a new HTTP 2.0 | ||||||
|     type Send = http::request::Head; |     /// stream. | ||||||
|     type Poll = http::response::Head; |     pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||||
|  |         unimplemented!(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Send a request on a new HTTP 2.0 stream | ||||||
|  |     pub fn request(&mut self, request: Request<()>, end_of_stream: bool) | ||||||
|  |         -> Result<Stream<B>, ConnectionError> | ||||||
|  |     { | ||||||
|  |         self.connection.send_request(request, end_of_stream) | ||||||
|  |             .map(|stream| Stream { | ||||||
|  |                 inner: stream, | ||||||
|  |             }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T, B> Future for Client<T, B> | ||||||
|  |     // TODO: Get rid of 'static | ||||||
|  |     where T: AsyncRead + AsyncWrite + 'static, | ||||||
|  |           B: IntoBuf + 'static, | ||||||
|  | { | ||||||
|  |     type Item = (); | ||||||
|  |     type Error = ConnectionError; | ||||||
|  |  | ||||||
|  |     fn poll(&mut self) -> Poll<(), ConnectionError> { | ||||||
|  |         self.connection.poll() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T, B> fmt::Debug for Client<T, B> | ||||||
|  |     where T: fmt::Debug, | ||||||
|  |           B: fmt::Debug + IntoBuf, | ||||||
|  |           B::Buf: fmt::Debug + IntoBuf, | ||||||
|  | { | ||||||
|  |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||||
|  |         fmt.debug_struct("Client") | ||||||
|  |             .field("connection", &self.connection) | ||||||
|  |             .finish() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Handshake ===== | ||||||
|  |  | ||||||
|  | impl<T, B: IntoBuf> Future for Handshake<T, B> { | ||||||
|  |     type Item = Client<T, B>; | ||||||
|  |     type Error = ConnectionError; | ||||||
|  |  | ||||||
|  |     fn poll(&mut self) -> Poll<Self::Item, Self::Error> { | ||||||
|  |         self.inner.poll() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T, B> fmt::Debug for Handshake<T, B> | ||||||
|  |     where T: fmt::Debug, | ||||||
|  |           B: fmt::Debug + IntoBuf, | ||||||
|  |           B::Buf: fmt::Debug + IntoBuf, | ||||||
|  | { | ||||||
|  |     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||||||
|  |         write!(fmt, "client::Handshake") | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Stream ===== | ||||||
|  |  | ||||||
|  | impl<B: IntoBuf> Stream<B> { | ||||||
|  |     /// Receive the HTTP/2.0 response, if it is ready. | ||||||
|  |     pub fn poll_response(&mut self) -> Poll<Response<Body<B>>, ConnectionError> { | ||||||
|  |         let (parts, _) = try_ready!(self.inner.poll_response()).into_parts(); | ||||||
|  |         let body = Body { inner: self.inner.clone() }; | ||||||
|  |  | ||||||
|  |         Ok(Response::from_parts(parts, body).into()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Send data | ||||||
|  |     pub fn send_data(&mut self, data: B, end_of_stream: bool) | ||||||
|  |         -> Result<(), ConnectionError> | ||||||
|  |     { | ||||||
|  |         self.inner.send_data(data.into_buf(), end_of_stream) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Send trailers | ||||||
|  |     pub fn send_trailers(&mut self, trailers: ()) | ||||||
|  |         -> Result<(), ConnectionError> | ||||||
|  |     { | ||||||
|  |         unimplemented!(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<B: IntoBuf> Future for Stream<B> { | ||||||
|  |     type Item = Response<Body<B>>; | ||||||
|  |     type Error = ConnectionError; | ||||||
|  |  | ||||||
|  |     fn poll(&mut self) -> Poll<Self::Item, Self::Error> { | ||||||
|  |         self.poll_response() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Body ===== | ||||||
|  |  | ||||||
|  | impl<B: IntoBuf> futures::Stream for Body<B> { | ||||||
|  |     type Item = Chunk<B>; | ||||||
|  |     type Error = ConnectionError; | ||||||
|  |  | ||||||
|  |     fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> { | ||||||
|  |         let chunk = try_ready!(self.inner.poll_data()) | ||||||
|  |             .map(|inner| Chunk { inner }); | ||||||
|  |  | ||||||
|  |         Ok(chunk.into()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Chunk ===== | ||||||
|  |  | ||||||
|  | impl<B: IntoBuf> Chunk<B> { | ||||||
|  |     pub fn pop_bytes(&mut self) -> Option<Bytes> { | ||||||
|  |         self.inner.pop_bytes() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Peer ===== | ||||||
|  |  | ||||||
|  | impl proto::Peer for Peer { | ||||||
|  |     type Send = Request<()>; | ||||||
|  |     type Poll = Response<()>; | ||||||
|  |  | ||||||
|     fn is_server() -> bool { |     fn is_server() -> bool { | ||||||
|         false |         false | ||||||
| @@ -68,15 +214,12 @@ impl Peer for Client { | |||||||
|  |  | ||||||
|     fn convert_send_message( |     fn convert_send_message( | ||||||
|         id: StreamId, |         id: StreamId, | ||||||
|         headers: Self::Send, |         request: Self::Send, | ||||||
|         end_of_stream: bool) -> frame::Headers |         end_of_stream: bool) -> frame::Headers | ||||||
|     { |     { | ||||||
|         use http::request::Head; |         use http::request::Parts; | ||||||
|  |  | ||||||
|         // Extract the components of the HTTP request |         let (Parts { method, uri, headers, .. }, _) = request.into_parts(); | ||||||
|         let Head { method, uri, headers, .. } = headers; |  | ||||||
|  |  | ||||||
|         // TODO: Ensure that the version is set to H2 |  | ||||||
|  |  | ||||||
|         // Build the set pseudo header set. All requests will include `method` |         // Build the set pseudo header set. All requests will include `method` | ||||||
|         // and `path`. |         // and `path`. | ||||||
| @@ -92,25 +235,9 @@ impl Peer for Client { | |||||||
|         frame |         frame | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn convert_poll_message(headers: frame::Headers) -> Self::Poll { |     fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ConnectionError> { | ||||||
|         headers.into_response() |         headers.into_response() | ||||||
|     } |             // TODO: Is this always a protocol error? | ||||||
| } |             .map_err(|_| ProtocolError.into()) | ||||||
|  |  | ||||||
| impl<T, B: IntoBuf> Future for Handshake<T, B> { |  | ||||||
|     type Item = Connection<T, B>; |  | ||||||
|     type Error = ConnectionError; |  | ||||||
|  |  | ||||||
|     fn poll(&mut self) -> Poll<Self::Item, Self::Error> { |  | ||||||
|         self.inner.poll() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<T, B> fmt::Debug for Handshake<T, B> |  | ||||||
|     where T: fmt::Debug, |  | ||||||
|           B: fmt::Debug + IntoBuf, |  | ||||||
| { |  | ||||||
|     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |  | ||||||
|         write!(fmt, "client::Handshake") |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,7 +3,8 @@ use hpack; | |||||||
| use frame::{self, Frame, Head, Kind, Error}; | use frame::{self, Frame, Head, Kind, Error}; | ||||||
| use HeaderMap; | use HeaderMap; | ||||||
|  |  | ||||||
| use http::{request, response, version, uri, Method, StatusCode, Uri}; | use http::{self, request, response, version, uri, Method, StatusCode, Uri}; | ||||||
|  | use http::{Request, Response}; | ||||||
| use http::header::{self, HeaderName, HeaderValue}; | use http::header::{self, HeaderName, HeaderValue}; | ||||||
|  |  | ||||||
| use bytes::{BytesMut, Bytes}; | use bytes::{BytesMut, Bytes}; | ||||||
| @@ -46,11 +47,11 @@ pub struct PushPromise { | |||||||
|     promised_id: StreamId, |     promised_id: StreamId, | ||||||
|  |  | ||||||
|     /// The associated flags |     /// The associated flags | ||||||
|     flags: HeadersFlag, |     flags: PushPromiseFlag, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl PushPromise { | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||||||
| } | pub struct PushPromiseFlag(u8); | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Continuation { | pub struct Continuation { | ||||||
| @@ -199,31 +200,28 @@ impl Headers { | |||||||
|         self.flags.set_end_stream() |         self.flags.set_end_stream() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn into_response(self) -> response::Head { |     pub fn into_response(self) -> http::Result<Response<()>> { | ||||||
|         let mut response = response::Head::default(); |         let mut b = Response::builder(); | ||||||
|  |  | ||||||
|         if let Some(status) = self.pseudo.status { |         if let Some(status) = self.pseudo.status { | ||||||
|             response.status = status; |             b.status(status); | ||||||
|         } else { |  | ||||||
|             unimplemented!(); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         response.headers = self.fields; |         let mut response = try!(b.body(())); | ||||||
|         response |         *response.headers_mut() = self.fields; | ||||||
|  |  | ||||||
|  |         Ok(response) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn into_request(self) -> request::Head { |     pub fn into_request(self) -> http::Result<Request<()>> { | ||||||
|         let mut request = request::Head::default(); |         let mut b = Request::builder(); | ||||||
|  |  | ||||||
|         // TODO: should we distinguish between HTTP_2 and HTTP_2C? |         // TODO: should we distinguish between HTTP_2 and HTTP_2C? | ||||||
|         // carllerche/http#42 |         // carllerche/http#42 | ||||||
|         request.version = version::HTTP_2; |         b.version(version::HTTP_2); | ||||||
|  |  | ||||||
|         if let Some(method) = self.pseudo.method { |         if let Some(method) = self.pseudo.method { | ||||||
|             request.method = method; |             b.method(method); | ||||||
|         } else { |  | ||||||
|             // TODO: invalid request |  | ||||||
|             unimplemented!(); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Convert the URI |         // Convert the URI | ||||||
| @@ -244,12 +242,12 @@ impl Headers { | |||||||
|             parts.origin_form = Some(uri::OriginForm::try_from_shared(path.into_inner()).unwrap()); |             parts.origin_form = Some(uri::OriginForm::try_from_shared(path.into_inner()).unwrap()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         request.uri = parts.into(); |         b.uri(parts); | ||||||
|  |  | ||||||
|         // Set the header fields |         let mut request = try!(b.body(())); | ||||||
|         request.headers = self.fields; |         *request.headers_mut() = self.fields; | ||||||
|  |  | ||||||
|         request |         Ok(request) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn into_fields(self) -> HeaderMap { |     pub fn into_fields(self) -> HeaderMap { | ||||||
| @@ -298,12 +296,46 @@ impl Headers { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<Headers> for Frame { | impl<T> From<Headers> for Frame<T> { | ||||||
|     fn from(src: Headers) -> Frame { |     fn from(src: Headers) -> Self { | ||||||
|         Frame::Headers(src) |         Frame::Headers(src) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ===== impl PushPromise ===== | ||||||
|  |  | ||||||
|  | impl PushPromise { | ||||||
|  |     pub fn load(head: Head, payload: &[u8]) | ||||||
|  |         -> Result<Self, Error> | ||||||
|  |     { | ||||||
|  |         let flags = PushPromiseFlag(head.flag()); | ||||||
|  |  | ||||||
|  |         // TODO: Handle padding | ||||||
|  |  | ||||||
|  |         let promised_id = StreamId::parse(&payload[..4]); | ||||||
|  |  | ||||||
|  |         Ok(PushPromise { | ||||||
|  |             stream_id: head.stream_id(), | ||||||
|  |             promised_id: promised_id, | ||||||
|  |             flags: flags, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn stream_id(&self) -> StreamId { | ||||||
|  |         self.stream_id | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn promised_id(&self) -> StreamId { | ||||||
|  |         self.promised_id | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T> From<PushPromise> for Frame<T> { | ||||||
|  |     fn from(src: PushPromise) -> Self { | ||||||
|  |         Frame::PushPromise(src) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| // ===== impl Pseudo ===== | // ===== impl Pseudo ===== | ||||||
|  |  | ||||||
| impl Pseudo { | impl Pseudo { | ||||||
|   | |||||||
| @@ -67,6 +67,15 @@ pub enum Frame<T = Bytes> { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl<T> Frame<T> { | impl<T> Frame<T> { | ||||||
|  |     /// Returns true if the frame is a DATA frame. | ||||||
|  |     pub fn is_data(&self) -> bool { | ||||||
|  |         use self::Frame::*; | ||||||
|  |  | ||||||
|  |         match *self { | ||||||
|  |             Data(..) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<T> fmt::Debug for Frame<T> { | impl<T> fmt::Debug for Frame<T> { | ||||||
|   | |||||||
| @@ -39,6 +39,10 @@ impl StreamId { | |||||||
|     pub fn is_zero(&self) -> bool { |     pub fn is_zero(&self) -> bool { | ||||||
|         self.0 == 0 |         self.0 == 0 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn increment(&mut self) { | ||||||
|  |         self.0 += 2; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<u32> for StreamId { | impl From<u32> for StreamId { | ||||||
|   | |||||||
| @@ -495,29 +495,29 @@ impl From<Utf8Error> for DecoderError { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<header::InvalidValueError> for DecoderError { | impl From<header::InvalidHeaderValue> for DecoderError { | ||||||
|     fn from(_: header::InvalidValueError) -> DecoderError { |     fn from(_: header::InvalidHeaderValue) -> DecoderError { | ||||||
|         // TODO: Better error? |         // TODO: Better error? | ||||||
|         DecoderError::InvalidUtf8 |         DecoderError::InvalidUtf8 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<method::FromBytesError> for DecoderError { | impl From<header::InvalidHeaderName> for DecoderError { | ||||||
|     fn from(_: method::FromBytesError) -> DecoderError { |     fn from(_: header::InvalidHeaderName) -> DecoderError { | ||||||
|         // TODO: Better error |         // TODO: Better error | ||||||
|         DecoderError::InvalidUtf8 |         DecoderError::InvalidUtf8 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<header::FromBytesError> for DecoderError { | impl From<method::InvalidMethod> for DecoderError { | ||||||
|     fn from(_: header::FromBytesError) -> DecoderError { |     fn from(_: method::InvalidMethod) -> DecoderError { | ||||||
|         // TODO: Better error |         // TODO: Better error | ||||||
|         DecoderError::InvalidUtf8 |         DecoderError::InvalidUtf8 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl From<status::FromStrError> for DecoderError { | impl From<status::InvalidStatusCode> for DecoderError { | ||||||
|     fn from(_: status::FromStrError) -> DecoderError { |     fn from(_: status::InvalidStatusCode) -> DecoderError { | ||||||
|         // TODO: Better error |         // TODO: Better error | ||||||
|         DecoderError::InvalidUtf8 |         DecoderError::InvalidUtf8 | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -251,7 +251,6 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName { | |||||||
|             header::ACCEPT_CHARSET, |             header::ACCEPT_CHARSET, | ||||||
|             header::ACCEPT_ENCODING, |             header::ACCEPT_ENCODING, | ||||||
|             header::ACCEPT_LANGUAGE, |             header::ACCEPT_LANGUAGE, | ||||||
|             header::ACCEPT_PATCH, |  | ||||||
|             header::ACCEPT_RANGES, |             header::ACCEPT_RANGES, | ||||||
|             header::ACCESS_CONTROL_ALLOW_CREDENTIALS, |             header::ACCESS_CONTROL_ALLOW_CREDENTIALS, | ||||||
|             header::ACCESS_CONTROL_ALLOW_HEADERS, |             header::ACCESS_CONTROL_ALLOW_HEADERS, | ||||||
| @@ -272,7 +271,6 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName { | |||||||
|             header::CONTENT_LANGUAGE, |             header::CONTENT_LANGUAGE, | ||||||
|             header::CONTENT_LENGTH, |             header::CONTENT_LENGTH, | ||||||
|             header::CONTENT_LOCATION, |             header::CONTENT_LOCATION, | ||||||
|             header::CONTENT_MD5, |  | ||||||
|             header::CONTENT_RANGE, |             header::CONTENT_RANGE, | ||||||
|             header::CONTENT_SECURITY_POLICY, |             header::CONTENT_SECURITY_POLICY, | ||||||
|             header::CONTENT_SECURITY_POLICY_REPORT_ONLY, |             header::CONTENT_SECURITY_POLICY_REPORT_ONLY, | ||||||
| @@ -292,7 +290,6 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName { | |||||||
|             header::IF_RANGE, |             header::IF_RANGE, | ||||||
|             header::IF_UNMODIFIED_SINCE, |             header::IF_UNMODIFIED_SINCE, | ||||||
|             header::LAST_MODIFIED, |             header::LAST_MODIFIED, | ||||||
|             header::KEEP_ALIVE, |  | ||||||
|             header::LINK, |             header::LINK, | ||||||
|             header::LOCATION, |             header::LOCATION, | ||||||
|             header::MAX_FORWARDS, |             header::MAX_FORWARDS, | ||||||
| @@ -311,10 +308,8 @@ fn gen_header_name(g: &mut StdRng) -> HeaderName { | |||||||
|             header::SET_COOKIE, |             header::SET_COOKIE, | ||||||
|             header::STRICT_TRANSPORT_SECURITY, |             header::STRICT_TRANSPORT_SECURITY, | ||||||
|             header::TE, |             header::TE, | ||||||
|             header::TK, |  | ||||||
|             header::TRAILER, |             header::TRAILER, | ||||||
|             header::TRANSFER_ENCODING, |             header::TRANSFER_ENCODING, | ||||||
|             header::TSV, |  | ||||||
|             header::USER_AGENT, |             header::USER_AGENT, | ||||||
|             header::UPGRADE, |             header::UPGRADE, | ||||||
|             header::UPGRADE_INSECURE_REQUESTS, |             header::UPGRADE_INSECURE_REQUESTS, | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								src/lib.rs
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| // #![allow(warnings)] | #![allow(warnings)] | ||||||
| #![deny(missing_debug_implementations)] | // #![deny(missing_debug_implementations)] | ||||||
|  |  | ||||||
| #[macro_use] | #[macro_use] | ||||||
| extern crate futures; | extern crate futures; | ||||||
| @@ -20,6 +20,8 @@ extern crate fnv; | |||||||
|  |  | ||||||
| extern crate byteorder; | extern crate byteorder; | ||||||
|  |  | ||||||
|  | extern crate slab; | ||||||
|  |  | ||||||
| #[macro_use] | #[macro_use] | ||||||
| extern crate log; | extern crate log; | ||||||
|  |  | ||||||
| @@ -30,11 +32,10 @@ pub mod error; | |||||||
| mod hpack; | mod hpack; | ||||||
| mod proto; | mod proto; | ||||||
| mod frame; | mod frame; | ||||||
| pub mod server; | // pub mod server; | ||||||
|  |  | ||||||
| pub use error::{ConnectionError, Reason}; | pub use error::{ConnectionError, Reason}; | ||||||
| pub use frame::StreamId; | pub use frame::StreamId; | ||||||
| pub use proto::Connection; |  | ||||||
|  |  | ||||||
| use bytes::Bytes; | use bytes::Bytes; | ||||||
|  |  | ||||||
| @@ -68,23 +69,3 @@ pub enum Frame<T, B = Bytes> { | |||||||
|         error: Reason, |         error: Reason, | ||||||
|     }, |     }, | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Either a Client or a Server |  | ||||||
| pub trait Peer { |  | ||||||
|     /// Message type sent into the transport |  | ||||||
|     type Send; |  | ||||||
|  |  | ||||||
|     /// Message type polled from the transport |  | ||||||
|     type Poll; |  | ||||||
|  |  | ||||||
|     fn is_server() -> bool; |  | ||||||
|  |  | ||||||
|     #[doc(hidden)] |  | ||||||
|     fn convert_send_message( |  | ||||||
|         id: StreamId, |  | ||||||
|         headers: Self::Send, |  | ||||||
|         end_of_stream: bool) -> frame::Headers; |  | ||||||
|  |  | ||||||
|     #[doc(hidden)] |  | ||||||
|     fn convert_poll_message(headers: frame::Headers) -> Self::Poll; |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,12 +1,10 @@ | |||||||
| use {ConnectionError, Frame, Peer}; | use {client, ConnectionError, Frame}; | ||||||
| use HeaderMap; | use HeaderMap; | ||||||
| use frame::{self, StreamId}; | use frame::{self, StreamId}; | ||||||
| use client::Client; |  | ||||||
| use server::Server; |  | ||||||
|  |  | ||||||
| use proto::*; | use proto::*; | ||||||
|  |  | ||||||
| use http::{request, response}; | use http::{Request, Response}; | ||||||
| use bytes::{Bytes, IntoBuf}; | use bytes::{Bytes, IntoBuf}; | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
|  |  | ||||||
| @@ -21,17 +19,17 @@ pub struct Connection<T, P, B: IntoBuf = Bytes> { | |||||||
|     // TODO: Remove <B> |     // TODO: Remove <B> | ||||||
|     ping_pong: PingPong<B::Buf>, |     ping_pong: PingPong<B::Buf>, | ||||||
|     settings: Settings, |     settings: Settings, | ||||||
|     streams: Streams<P>, |     streams: Streams<P, B::Buf>, | ||||||
|  |  | ||||||
|     _phantom: PhantomData<P>, |     _phantom: PhantomData<P>, | ||||||
| } | } | ||||||
|  |  | ||||||
| pub fn new<T, P, B>(codec: Codec<T, B::Buf>) | impl<T, P, B> Connection<T, P, B> | ||||||
|     -> Connection<T, P, B> |  | ||||||
|     where T: AsyncRead + AsyncWrite, |     where T: AsyncRead + AsyncWrite, | ||||||
|           P: Peer, |           P: Peer, | ||||||
|           B: IntoBuf, |           B: IntoBuf, | ||||||
| { | { | ||||||
|  |     pub fn new(codec: Codec<T, B::Buf>) -> Connection<T, P, B> { | ||||||
|         // TODO: Actually configure |         // TODO: Actually configure | ||||||
|         let streams = Streams::new(streams::Config { |         let streams = Streams::new(streams::Config { | ||||||
|             max_remote_initiated: None, |             max_remote_initiated: None, | ||||||
| @@ -49,11 +47,6 @@ pub fn new<T, P, B>(codec: Codec<T, B::Buf>) | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| impl<T, P, B> Connection<T, P, B> |  | ||||||
|     where T: AsyncRead + AsyncWrite, |  | ||||||
|           P: Peer, |  | ||||||
|           B: IntoBuf, |  | ||||||
| { |  | ||||||
|     /// Polls for the next update to a remote flow control window. |     /// Polls for the next update to a remote flow control window. | ||||||
|     pub fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError> { |     pub fn poll_window_update(&mut self) -> Poll<WindowUpdate, ConnectionError> { | ||||||
|         self.streams.poll_window_update() |         self.streams.poll_window_update() | ||||||
| @@ -87,6 +80,7 @@ impl<T, P, B> Connection<T, P, B> | |||||||
|         unimplemented!(); |         unimplemented!(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Returns `Ready` when the connection is ready to receive a frame. | ||||||
|     pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> { |     pub fn poll_ready(&mut self) -> Poll<(), ConnectionError> { | ||||||
|         try_ready!(self.poll_send_ready()); |         try_ready!(self.poll_send_ready()); | ||||||
|  |  | ||||||
| @@ -96,6 +90,94 @@ impl<T, P, B> Connection<T, P, B> | |||||||
|         Ok(().into()) |         Ok(().into()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Advances the internal state of the connection. | ||||||
|  |     pub fn poll(&mut self) -> Poll<(), ConnectionError> { | ||||||
|  |         match self.poll2() { | ||||||
|  |             Err(e) => { | ||||||
|  |                 self.streams.recv_err(&e); | ||||||
|  |                 Err(e) | ||||||
|  |             } | ||||||
|  |             ret => ret, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn poll2(&mut self) -> Poll<(), ConnectionError> { | ||||||
|  |         use frame::Frame::*; | ||||||
|  |  | ||||||
|  |         loop { | ||||||
|  |             // First, ensure that the `Connection` is able to receive a frame | ||||||
|  |             try_ready!(self.poll_recv_ready()); | ||||||
|  |  | ||||||
|  |             trace!("polling codec"); | ||||||
|  |  | ||||||
|  |             let frame = match try!(self.codec.poll()) { | ||||||
|  |                 Async::Ready(frame) => frame, | ||||||
|  |                 Async::NotReady => { | ||||||
|  |                     // Flush any pending writes | ||||||
|  |                     let _ = try!(self.poll_complete()); | ||||||
|  |                     return Ok(Async::NotReady); | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             match frame { | ||||||
|  |                 Some(Headers(frame)) => { | ||||||
|  |                     trace!("recv HEADERS; frame={:?}", frame); | ||||||
|  |  | ||||||
|  |                     if let Some(frame) = try!(self.streams.recv_headers(frame)) { | ||||||
|  |                         unimplemented!(); | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     /* | ||||||
|  |                     // Update stream state while ensuring that the headers frame | ||||||
|  |                     // can be received. | ||||||
|  |                     if let Some(frame) = try!(self.streams.recv_headers(frame)) { | ||||||
|  |                         let frame = Self::convert_poll_message(frame)?; | ||||||
|  |                         return Ok(Some(frame).into()); | ||||||
|  |                     } | ||||||
|  |                     */ | ||||||
|  |                 } | ||||||
|  |                 Some(Data(frame)) => { | ||||||
|  |                     trace!("recv DATA; frame={:?}", frame); | ||||||
|  |                     try!(self.streams.recv_data(frame)); | ||||||
|  |                 } | ||||||
|  |                 Some(Reset(frame)) => { | ||||||
|  |                     trace!("recv RST_STREAM; frame={:?}", frame); | ||||||
|  |                     try!(self.streams.recv_reset(frame)); | ||||||
|  |                 } | ||||||
|  |                 Some(PushPromise(frame)) => { | ||||||
|  |                     trace!("recv PUSH_PROMISE; frame={:?}", frame); | ||||||
|  |                     self.streams.recv_push_promise(frame)?; | ||||||
|  |                 } | ||||||
|  |                 Some(Settings(frame)) => { | ||||||
|  |                     trace!("recv SETTINGS; frame={:?}", frame); | ||||||
|  |                     self.settings.recv_settings(frame); | ||||||
|  |  | ||||||
|  |                     // TODO: ACK must be sent THEN settings applied. | ||||||
|  |                 } | ||||||
|  |                 Some(Ping(frame)) => { | ||||||
|  |                     unimplemented!(); | ||||||
|  |                     /* | ||||||
|  |                     trace!("recv PING; frame={:?}", frame); | ||||||
|  |                     self.ping_pong.recv_ping(frame); | ||||||
|  |                     */ | ||||||
|  |                 } | ||||||
|  |                 Some(WindowUpdate(frame)) => { | ||||||
|  |                     unimplemented!(); | ||||||
|  |                     /* | ||||||
|  |                     trace!("recv WINDOW_UPDATE; frame={:?}", frame); | ||||||
|  |                     try!(self.streams.recv_window_update(frame)); | ||||||
|  |                     */ | ||||||
|  |                 } | ||||||
|  |                 None => { | ||||||
|  |                     // TODO: Is this correct? | ||||||
|  |                     trace!("codec closed"); | ||||||
|  |                     return Ok(Async::Ready(())); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* | ||||||
|     pub fn send_data(self, |     pub fn send_data(self, | ||||||
|                      id: StreamId, |                      id: StreamId, | ||||||
|                      data: B, |                      data: B, | ||||||
| @@ -119,10 +201,7 @@ impl<T, P, B> Connection<T, P, B> | |||||||
|             headers, |             headers, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |     */ | ||||||
|     pub fn start_ping(&mut self, _body: PingPayload) -> StartSend<PingPayload, ConnectionError> { |  | ||||||
|         unimplemented!(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // ===== Private ===== |     // ===== Private ===== | ||||||
|  |  | ||||||
| @@ -146,110 +225,51 @@ impl<T, P, B> Connection<T, P, B> | |||||||
|     /// This function is currently used by poll_complete, but at some point it |     /// This function is currently used by poll_complete, but at some point it | ||||||
|     /// will probably not be required. |     /// will probably not be required. | ||||||
|     fn poll_send_ready(&mut self) -> Poll<(), ConnectionError> { |     fn poll_send_ready(&mut self) -> Poll<(), ConnectionError> { | ||||||
|  |         // TODO: Is this function needed? | ||||||
|         try_ready!(self.poll_recv_ready()); |         try_ready!(self.poll_recv_ready()); | ||||||
|  |  | ||||||
|         // Ensure all window updates have been sent. |  | ||||||
|         try_ready!(self.streams.send_pending_window_updates(&mut self.codec)); |  | ||||||
|  |  | ||||||
|         Ok(().into()) |         Ok(().into()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Try to receive the next frame |     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { | ||||||
|     fn recv_frame(&mut self) -> Poll<Option<Frame<P::Poll>>, ConnectionError> { |         try_ready!(self.poll_send_ready()); | ||||||
|         use frame::Frame::*; |  | ||||||
|  |  | ||||||
|         loop { |         // Ensure all window updates have been sent. | ||||||
|             // First, ensure that the `Connection` is able to receive a frame |         try_ready!(self.streams.poll_complete(&mut self.codec)); | ||||||
|             try_ready!(self.poll_recv_ready()); |         try_ready!(self.codec.poll_complete()); | ||||||
|  |  | ||||||
|             trace!("polling codec"); |         Ok(().into()) | ||||||
|  |  | ||||||
|             let frame = match try!(self.codec.poll()) { |  | ||||||
|                 Async::Ready(frame) => frame, |  | ||||||
|                 Async::NotReady => { |  | ||||||
|                     // Receiving new frames may depend on ensuring that the write buffer |  | ||||||
|                     // is clear (e.g. if window updates need to be sent), so `poll_complete` |  | ||||||
|                     // is called here. |  | ||||||
|                     let _ = try!(self.poll_complete()); |  | ||||||
|                     return Ok(Async::NotReady); |  | ||||||
|                 } |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             match frame { |  | ||||||
|                 Some(Headers(frame)) => { |  | ||||||
|                     trace!("recv HEADERS; frame={:?}", frame); |  | ||||||
|                     // Update stream state while ensuring that the headers frame |  | ||||||
|                     // can be received. |  | ||||||
|                     if let Some(frame) = try!(self.streams.recv_headers(frame)) { |  | ||||||
|                         let frame = Self::convert_poll_message(frame); |  | ||||||
|                         return Ok(Some(frame).into()); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 Some(Data(frame)) => { |  | ||||||
|                     trace!("recv DATA; frame={:?}", frame); |  | ||||||
|                     try!(self.streams.recv_data(&frame)); |  | ||||||
|  |  | ||||||
|                     let frame = Frame::Data { |  | ||||||
|                         id: frame.stream_id(), |  | ||||||
|                         end_of_stream: frame.is_end_stream(), |  | ||||||
|                         data: frame.into_payload(), |  | ||||||
|                     }; |  | ||||||
|  |  | ||||||
|                     return Ok(Some(frame).into()); |  | ||||||
|                 } |  | ||||||
|                 Some(Reset(frame)) => { |  | ||||||
|                     trace!("recv RST_STREAM; frame={:?}", frame); |  | ||||||
|                     try!(self.streams.recv_reset(&frame)); |  | ||||||
|  |  | ||||||
|                     let frame = Frame::Reset { |  | ||||||
|                         id: frame.stream_id(), |  | ||||||
|                         error: frame.reason(), |  | ||||||
|                     }; |  | ||||||
|  |  | ||||||
|                     return Ok(Some(frame).into()); |  | ||||||
|                 } |  | ||||||
|                 Some(PushPromise(frame)) => { |  | ||||||
|                     trace!("recv PUSH_PROMISE; frame={:?}", frame); |  | ||||||
|                     try!(self.streams.recv_push_promise(frame)); |  | ||||||
|                 } |  | ||||||
|                 Some(Settings(frame)) => { |  | ||||||
|                     trace!("recv SETTINGS; frame={:?}", frame); |  | ||||||
|                     self.settings.recv_settings(frame); |  | ||||||
|  |  | ||||||
|                     // TODO: ACK must be sent THEN settings applied. |  | ||||||
|                 } |  | ||||||
|                 Some(Ping(frame)) => { |  | ||||||
|                     trace!("recv PING; frame={:?}", frame); |  | ||||||
|                     self.ping_pong.recv_ping(frame); |  | ||||||
|                 } |  | ||||||
|                 Some(WindowUpdate(frame)) => { |  | ||||||
|                     trace!("recv WINDOW_UPDATE; frame={:?}", frame); |  | ||||||
|                     try!(self.streams.recv_window_update(frame)); |  | ||||||
|                 } |  | ||||||
|                 None => { |  | ||||||
|                     trace!("codec closed"); |  | ||||||
|                     return Ok(Async::Ready(None)); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn convert_poll_message(frame: frame::Headers) -> Frame<P::Poll> { |     fn convert_poll_message(frame: frame::Headers) -> Result<Frame<P::Poll>, ConnectionError> { | ||||||
|         if frame.is_trailers() { |         if frame.is_trailers() { | ||||||
|             Frame::Trailers { |             Ok(Frame::Trailers { | ||||||
|                 id: frame.stream_id(), |                 id: frame.stream_id(), | ||||||
|                 headers: frame.into_fields() |                 headers: frame.into_fields() | ||||||
|             } |             }) | ||||||
|         } else { |         } else { | ||||||
|             Frame::Headers { |             Ok(Frame::Headers { | ||||||
|                 id: frame.stream_id(), |                 id: frame.stream_id(), | ||||||
|                 end_of_stream: frame.is_end_stream(), |                 end_of_stream: frame.is_end_stream(), | ||||||
|                 headers: P::convert_poll_message(frame), |                 headers: P::convert_poll_message(frame)?, | ||||||
|             } |             }) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl<T, B> Connection<T, client::Peer, B> | ||||||
|  |     where T: AsyncRead + AsyncWrite, | ||||||
|  |           B: IntoBuf, | ||||||
|  | { | ||||||
|  |     /// Initialize a new HTTP/2.0 stream and send the message. | ||||||
|  |     pub fn send_request(&mut self, request: Request<()>, end_of_stream: bool) | ||||||
|  |         -> Result<StreamRef<client::Peer, B::Buf>, ConnectionError> | ||||||
|  |     { | ||||||
|  |         self.streams.send_request(request, end_of_stream) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
| impl<T, B> Connection<T, Client, B> | impl<T, B> Connection<T, Client, B> | ||||||
|     where T: AsyncRead + AsyncWrite, |     where T: AsyncRead + AsyncWrite, | ||||||
|           B: IntoBuf, |           B: IntoBuf, | ||||||
| @@ -296,21 +316,9 @@ impl<T, B> Connection<T, Server, B> | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | */ | ||||||
|  |  | ||||||
| impl<T, P, B> Stream for Connection<T, P, B> | /* | ||||||
|     where T: AsyncRead + AsyncWrite, |  | ||||||
|           P: Peer, |  | ||||||
|           B: IntoBuf, |  | ||||||
| { |  | ||||||
|     type Item = Frame<P::Poll>; |  | ||||||
|     type Error = ConnectionError; |  | ||||||
|  |  | ||||||
|     fn poll(&mut self) -> Poll<Option<Self::Item>, ConnectionError> { |  | ||||||
|         // TODO: intercept errors and flag the connection |  | ||||||
|         self.recv_frame() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<T, P, B> Sink for Connection<T, P, B> | impl<T, P, B> Sink for Connection<T, P, B> | ||||||
|     where T: AsyncRead + AsyncWrite, |     where T: AsyncRead + AsyncWrite, | ||||||
|           P: Peer, |           P: Peer, | ||||||
| @@ -384,11 +392,5 @@ impl<T, P, B> Sink for Connection<T, P, B> | |||||||
|         // Return success |         // Return success | ||||||
|         Ok(AsyncSink::Ready) |         Ok(AsyncSink::Ready) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn poll_complete(&mut self) -> Poll<(), ConnectionError> { |  | ||||||
|         try_ready!(self.poll_send_ready()); |  | ||||||
|         try_ready!(self.codec.poll_complete()); |  | ||||||
|  |  | ||||||
|         Ok(().into()) |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  | */ | ||||||
|   | |||||||
| @@ -92,7 +92,9 @@ impl<T> FramedRead<T> { | |||||||
|                 let _todo = try!(frame::GoAway::load(&bytes[frame::HEADER_LEN..])); |                 let _todo = try!(frame::GoAway::load(&bytes[frame::HEADER_LEN..])); | ||||||
|                 unimplemented!(); |                 unimplemented!(); | ||||||
|             } |             } | ||||||
|             Kind::PushPromise | |             Kind::PushPromise => { | ||||||
|  |                 frame::PushPromise::load(head, &bytes[frame::HEADER_LEN..])?.into() | ||||||
|  |             } | ||||||
|             Kind::Priority | |             Kind::Priority | | ||||||
|             Kind::Continuation | |             Kind::Continuation | | ||||||
|             Kind::Unknown => { |             Kind::Unknown => { | ||||||
| @@ -117,7 +119,7 @@ impl<T: ApplySettings> ApplySettings for FramedRead<T> { | |||||||
| } | } | ||||||
| */ | */ | ||||||
|  |  | ||||||
| impl<T> Stream for FramedRead<T> | impl<T> futures::Stream for FramedRead<T> | ||||||
|     where T: AsyncRead, |     where T: AsyncRead, | ||||||
| { | { | ||||||
|     type Item = Frame; |     type Item = Frame; | ||||||
|   | |||||||
| @@ -6,22 +6,42 @@ mod settings; | |||||||
| mod streams; | mod streams; | ||||||
|  |  | ||||||
| pub use self::connection::Connection; | pub use self::connection::Connection; | ||||||
|  | pub use self::streams::{Streams, StreamRef, Chunk}; | ||||||
|  |  | ||||||
| use self::framed_read::FramedRead; | use self::framed_read::FramedRead; | ||||||
| use self::framed_write::FramedWrite; | use self::framed_write::FramedWrite; | ||||||
| use self::ping_pong::PingPong; | use self::ping_pong::PingPong; | ||||||
| use self::settings::Settings; | use self::settings::Settings; | ||||||
| use self::streams::Streams; |  | ||||||
|  |  | ||||||
| use {StreamId, Peer}; | use {StreamId, ConnectionError}; | ||||||
| use error::Reason; | use error::Reason; | ||||||
| use frame::Frame; | use frame::{self, Frame}; | ||||||
|  |  | ||||||
| use futures::*; | use futures::{self, task, Poll, Async, AsyncSink, Sink, Stream as Stream2}; | ||||||
| use bytes::{Buf, IntoBuf}; | use bytes::{Buf, IntoBuf}; | ||||||
| use tokio_io::{AsyncRead, AsyncWrite}; | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
| use tokio_io::codec::length_delimited; | use tokio_io::codec::length_delimited; | ||||||
|  |  | ||||||
|  | /// Either a Client or a Server | ||||||
|  | pub trait Peer { | ||||||
|  |     /// Message type sent into the transport | ||||||
|  |     type Send; | ||||||
|  |  | ||||||
|  |     /// Message type polled from the transport | ||||||
|  |     type Poll; | ||||||
|  |  | ||||||
|  |     fn is_server() -> bool; | ||||||
|  |  | ||||||
|  |     #[doc(hidden)] | ||||||
|  |     fn convert_send_message( | ||||||
|  |         id: StreamId, | ||||||
|  |         headers: Self::Send, | ||||||
|  |         end_of_stream: bool) -> frame::Headers; | ||||||
|  |  | ||||||
|  |     #[doc(hidden)] | ||||||
|  |     fn convert_poll_message(headers: frame::Headers) -> Result<Self::Poll, ConnectionError>; | ||||||
|  | } | ||||||
|  |  | ||||||
| pub type PingPayload = [u8; 8]; | pub type PingPayload = [u8; 8]; | ||||||
|  |  | ||||||
| pub type WindowSize = u32; | pub type WindowSize = u32; | ||||||
| @@ -69,7 +89,7 @@ pub fn from_framed_write<T, P, B>(framed_write: FramedWrite<T, B::Buf>) | |||||||
|  |  | ||||||
|     let codec = FramedRead::new(framed); |     let codec = FramedRead::new(framed); | ||||||
|  |  | ||||||
|     connection::new(codec) |     Connection::new(codec) | ||||||
| } | } | ||||||
|  |  | ||||||
| impl WindowUpdate { | impl WindowUpdate { | ||||||
|   | |||||||
							
								
								
									
										140
									
								
								src/proto/streams/buffer.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/proto/streams/buffer.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,140 @@ | |||||||
|  | use frame::{self, Frame}; | ||||||
|  |  | ||||||
|  | use slab::Slab; | ||||||
|  |  | ||||||
|  | use std::marker::PhantomData; | ||||||
|  |  | ||||||
|  | /// Buffers frames for multiple streams. | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Buffer<B> { | ||||||
|  |     slab: Slab<Slot<B>>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// A sequence of frames in a `Buffer` | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Deque<B> { | ||||||
|  |     indices: Option<Indices>, | ||||||
|  |     _p: PhantomData<B>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Tracks the head & tail for a sequence of frames in a `Buffer`. | ||||||
|  | #[derive(Debug, Default, Copy, Clone)] | ||||||
|  | struct Indices { | ||||||
|  |     head: usize, | ||||||
|  |     tail: usize, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct Slot<B> { | ||||||
|  |     frame: Frame<B>, | ||||||
|  |     next: Option<usize>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<B> Buffer<B> { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Buffer { | ||||||
|  |             slab: Slab::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<B> Deque<B> { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Deque { | ||||||
|  |             indices: None, | ||||||
|  |             _p: PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn is_empty(&self) -> bool { | ||||||
|  |         self.indices.is_none() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn push_back(&mut self, buf: &mut Buffer<B>, frame: Frame<B>) { | ||||||
|  |         let key = buf.slab.insert(Slot { | ||||||
|  |             frame, | ||||||
|  |             next: None, | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         match self.indices { | ||||||
|  |             Some(ref mut idxs) => { | ||||||
|  |                 buf.slab[idxs.tail].next = Some(key); | ||||||
|  |                 idxs.tail = key; | ||||||
|  |             } | ||||||
|  |             None => { | ||||||
|  |                 self.indices = Some(Indices { | ||||||
|  |                     head: key, | ||||||
|  |                     tail: key, | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn pop_front(&mut self, buf: &mut Buffer<B>) -> Option<Frame<B>> { | ||||||
|  |         match self.indices { | ||||||
|  |             Some(mut idxs) => { | ||||||
|  |                 let mut slot = buf.slab.remove(idxs.head); | ||||||
|  |  | ||||||
|  |                 if idxs.head == idxs.tail { | ||||||
|  |                     assert!(slot.next.is_none()); | ||||||
|  |                     self.indices = None; | ||||||
|  |                 } else { | ||||||
|  |                     idxs.head = slot.next.take().unwrap(); | ||||||
|  |                     self.indices = Some(idxs); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 return Some(slot.frame); | ||||||
|  |             } | ||||||
|  |             None => None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn take_while<F>(&mut self, buf: &mut Buffer<B>, mut f: F) -> Self | ||||||
|  |         where F: FnMut(&Frame<B>) -> bool | ||||||
|  |     { | ||||||
|  |         match self.indices { | ||||||
|  |             Some(mut idxs) => { | ||||||
|  |                 if !f(&buf.slab[idxs.head].frame) { | ||||||
|  |                     return Deque::new(); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 let head = idxs.head; | ||||||
|  |                 let mut tail = idxs.head; | ||||||
|  |  | ||||||
|  |                 loop { | ||||||
|  |                     let next = match buf.slab[tail].next { | ||||||
|  |                         Some(next) => next, | ||||||
|  |                         None => { | ||||||
|  |                             self.indices = None; | ||||||
|  |                             return Deque { | ||||||
|  |                                 indices: Some(idxs), | ||||||
|  |                                 _p: PhantomData, | ||||||
|  |                             }; | ||||||
|  |                         } | ||||||
|  |                     }; | ||||||
|  |  | ||||||
|  |                     if !f(&buf.slab[next].frame) { | ||||||
|  |                         // Split the linked list | ||||||
|  |                         buf.slab[tail].next = None; | ||||||
|  |  | ||||||
|  |                         self.indices = Some(Indices { | ||||||
|  |                             head: next, | ||||||
|  |                             tail: idxs.tail, | ||||||
|  |                         }); | ||||||
|  |  | ||||||
|  |                         return Deque { | ||||||
|  |                             indices: Some(Indices { | ||||||
|  |                                 head: head, | ||||||
|  |                                 tail: tail, | ||||||
|  |                             }), | ||||||
|  |                             _p: PhantomData, | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     tail = next; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             None => Deque::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,43 +1,31 @@ | |||||||
|  | mod buffer; | ||||||
| mod flow_control; | mod flow_control; | ||||||
|  | mod prioritize; | ||||||
| mod recv; | mod recv; | ||||||
| mod send; | mod send; | ||||||
| mod state; | mod state; | ||||||
| mod store; | mod store; | ||||||
|  | mod stream; | ||||||
|  | mod streams; | ||||||
|  |  | ||||||
|  | pub use self::streams::{Streams, StreamRef, Chunk}; | ||||||
|  |  | ||||||
|  | use self::buffer::Buffer; | ||||||
| use self::flow_control::FlowControl; | use self::flow_control::FlowControl; | ||||||
|  | use self::prioritize::Prioritize; | ||||||
| use self::recv::Recv; | use self::recv::Recv; | ||||||
| use self::send::Send; | use self::send::Send; | ||||||
| use self::state::State; | use self::state::State; | ||||||
| use self::store::{Store, Entry}; | use self::store::{Store, Entry}; | ||||||
|  | use self::stream::Stream; | ||||||
|  |  | ||||||
| use {frame, Peer, StreamId, ConnectionError}; | use {frame, StreamId, ConnectionError}; | ||||||
| use proto::*; | use proto::*; | ||||||
| use error::Reason::*; | use error::Reason::*; | ||||||
| use error::User::*; | use error::User::*; | ||||||
|  |  | ||||||
| // TODO: All the VecDeques should become linked lists using the State | use http::{Request, Response}; | ||||||
| // values. | use bytes::Bytes; | ||||||
| #[derive(Debug)] |  | ||||||
| pub struct Streams<P> { |  | ||||||
|     /// State related to managing the set of streams. |  | ||||||
|     inner: Inner<P>, |  | ||||||
|  |  | ||||||
|     /// Streams |  | ||||||
|     streams: Store, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// Fields needed to manage state related to managing the set of streams. This |  | ||||||
| /// is mostly split out to make ownership happy. |  | ||||||
| /// |  | ||||||
| /// TODO: better name |  | ||||||
| #[derive(Debug)] |  | ||||||
| struct Inner<P> { |  | ||||||
|     /// Manages state transitions initiated by receiving frames |  | ||||||
|     recv: Recv<P>, |  | ||||||
|  |  | ||||||
|     /// Manages state transitions initiated by sending frames |  | ||||||
|     send: Send<P>, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Config { | pub struct Config { | ||||||
| @@ -53,218 +41,3 @@ pub struct Config { | |||||||
|     /// Initial window size of locally initiated streams |     /// Initial window size of locally initiated streams | ||||||
|     pub init_local_window_sz: WindowSize, |     pub init_local_window_sz: WindowSize, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<P: Peer> Streams<P> { |  | ||||||
|     pub fn new(config: Config) -> Self { |  | ||||||
|         Streams { |  | ||||||
|             inner: Inner { |  | ||||||
|                 recv: Recv::new(&config), |  | ||||||
|                 send: Send::new(&config), |  | ||||||
|             }, |  | ||||||
|             streams: Store::new(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn recv_headers(&mut self, frame: frame::Headers) |  | ||||||
|         -> Result<Option<frame::Headers>, ConnectionError> |  | ||||||
|     { |  | ||||||
|         let id = frame.stream_id(); |  | ||||||
|  |  | ||||||
|         let state = match self.streams.entry(id) { |  | ||||||
|             Entry::Occupied(e) => e.into_mut(), |  | ||||||
|             Entry::Vacant(e) => { |  | ||||||
|                 // Trailers cannot open a stream. Trailers are header frames |  | ||||||
|                 // that do not contain pseudo headers. Requests MUST contain a |  | ||||||
|                 // method and responses MUST contain a status. If they do not,t |  | ||||||
|                 // hey are considered to be malformed. |  | ||||||
|                 if frame.is_trailers() { |  | ||||||
|                     return Err(ProtocolError.into()); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 match try!(self.inner.recv.open(id)) { |  | ||||||
|                     Some(state) => e.insert(state), |  | ||||||
|                     None => return Ok(None), |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         if frame.is_trailers() { |  | ||||||
|             if !frame.is_end_stream() { |  | ||||||
|                 // TODO: What error should this return? |  | ||||||
|                 unimplemented!(); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             try!(self.inner.recv.recv_eos(state)); |  | ||||||
|         } else { |  | ||||||
|             try!(self.inner.recv.recv_headers(state, frame.is_end_stream())); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if state.is_closed() { |  | ||||||
|             self.inner.dec_num_streams(id); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(Some(frame)) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn recv_data(&mut self, frame: &frame::Data) |  | ||||||
|         -> Result<(), ConnectionError> |  | ||||||
|     { |  | ||||||
|         let id = frame.stream_id(); |  | ||||||
|  |  | ||||||
|         let state = match self.streams.get_mut(&id) { |  | ||||||
|             Some(state) => state, |  | ||||||
|             None => return Err(ProtocolError.into()), |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         // Ensure there's enough capacity on the connection before acting on the |  | ||||||
|         // stream. |  | ||||||
|         try!(self.inner.recv.recv_data(frame, state)); |  | ||||||
|  |  | ||||||
|         if state.is_closed() { |  | ||||||
|             self.inner.dec_num_streams(id); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn recv_reset(&mut self, _frame: &frame::Reset) |  | ||||||
|         -> Result<(), ConnectionError> |  | ||||||
|     { |  | ||||||
|         unimplemented!(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn recv_window_update(&mut self, frame: frame::WindowUpdate) |  | ||||||
|         -> Result<(), ConnectionError> { |  | ||||||
|         let id = frame.stream_id(); |  | ||||||
|  |  | ||||||
|         if id.is_zero() { |  | ||||||
|             try!(self.inner.send.recv_connection_window_update(frame)); |  | ||||||
|         } else { |  | ||||||
|             // The remote may send window updates for streams that the local now |  | ||||||
|             // considers closed. It's ok... |  | ||||||
|             if let Some(state) = self.streams.get_mut(&id) { |  | ||||||
|                 try!(self.inner.send.recv_stream_window_update(frame, state)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn recv_push_promise(&mut self, _frame: frame::PushPromise) |  | ||||||
|         -> Result<(), ConnectionError> |  | ||||||
|     { |  | ||||||
|         unimplemented!(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn send_headers(&mut self, frame: &frame::Headers) |  | ||||||
|         -> Result<(), ConnectionError> |  | ||||||
|     { |  | ||||||
|         let id = frame.stream_id(); |  | ||||||
|  |  | ||||||
|         trace!("send_headers; id={:?}", id); |  | ||||||
|  |  | ||||||
|         let state = match self.streams.entry(id) { |  | ||||||
|             Entry::Occupied(e) => e.into_mut(), |  | ||||||
|             Entry::Vacant(e) => { |  | ||||||
|                 // Trailers cannot open a stream. Trailers are header frames |  | ||||||
|                 // that do not contain pseudo headers. Requests MUST contain a |  | ||||||
|                 // method and responses MUST contain a status. If they do not,t |  | ||||||
|                 // hey are considered to be malformed. |  | ||||||
|                 if frame.is_trailers() { |  | ||||||
|                     // TODO: Should this be a different error? |  | ||||||
|                     return Err(UnexpectedFrameType.into()); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 let state = try!(self.inner.send.open(id)); |  | ||||||
|                 e.insert(state) |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         if frame.is_trailers() { |  | ||||||
|             try!(self.inner.send.send_eos(state)); |  | ||||||
|         } else { |  | ||||||
|             try!(self.inner.send.send_headers(state, frame.is_end_stream())); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if state.is_closed() { |  | ||||||
|             self.inner.dec_num_streams(id); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn send_data<B: Buf>(&mut self, frame: &frame::Data<B>) |  | ||||||
|         -> Result<(), ConnectionError> |  | ||||||
|     { |  | ||||||
|         let id = frame.stream_id(); |  | ||||||
|  |  | ||||||
|         let state = match self.streams.get_mut(&id) { |  | ||||||
|             Some(state) => state, |  | ||||||
|             None => return Err(UnexpectedFrameType.into()), |  | ||||||
|         }; |  | ||||||
|  |  | ||||||
|         // Ensure there's enough capacity on the connection before acting on the |  | ||||||
|         // stream. |  | ||||||
|         try!(self.inner.send.send_data(frame, state)); |  | ||||||
|  |  | ||||||
|         if state.is_closed() { |  | ||||||
|             self.inner.dec_num_streams(id); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn poll_window_update(&mut self) |  | ||||||
|         -> Poll<WindowUpdate, ConnectionError> |  | ||||||
|     { |  | ||||||
|         self.inner.send.poll_window_update(&mut self.streams) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn expand_window(&mut self, id: StreamId, sz: WindowSize) |  | ||||||
|         -> Result<(), ConnectionError> |  | ||||||
|     { |  | ||||||
|         if id.is_zero() { |  | ||||||
|             try!(self.inner.recv.expand_connection_window(sz)); |  | ||||||
|         } else { |  | ||||||
|             if let Some(state) = self.streams.get_mut(&id) { |  | ||||||
|                 try!(self.inner.recv.expand_stream_window(id, sz, state)); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn send_pending_refusal<T, B>(&mut self, dst: &mut Codec<T, B>) |  | ||||||
|         -> Poll<(), ConnectionError> |  | ||||||
|         where T: AsyncWrite, |  | ||||||
|               B: Buf, |  | ||||||
|     { |  | ||||||
|         self.inner.recv.send_pending_refusal(dst) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn send_pending_window_updates<T, B>(&mut self, dst: &mut Codec<T, B>) |  | ||||||
|         -> Poll<(), ConnectionError> |  | ||||||
|         where T: AsyncWrite, |  | ||||||
|               B: Buf, |  | ||||||
|     { |  | ||||||
|         try_ready!(self.inner.recv.send_connection_window_update(dst)); |  | ||||||
|         try_ready!(self.inner.recv.send_stream_window_update(&mut self.streams, dst)); |  | ||||||
|  |  | ||||||
|         Ok(().into()) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl<P: Peer> Inner<P> { |  | ||||||
|     fn dec_num_streams(&mut self, id: StreamId) { |  | ||||||
|         if self.is_local_init(id) { |  | ||||||
|             self.send.dec_num_streams(); |  | ||||||
|         } else { |  | ||||||
|             self.recv.dec_num_streams(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     fn is_local_init(&self, id: StreamId) -> bool { |  | ||||||
|         assert!(!id.is_zero()); |  | ||||||
|         P::is_server() == id.is_server_initiated() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|   | |||||||
							
								
								
									
										97
									
								
								src/proto/streams/prioritize.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/proto/streams/prioritize.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | |||||||
|  | use super::*; | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub(super) struct Prioritize<B> { | ||||||
|  |     pending_send: store::List<B>, | ||||||
|  |  | ||||||
|  |     /// Holds frames that are waiting to be written to the socket | ||||||
|  |     buffer: Buffer<B>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<B> Prioritize<B> | ||||||
|  |     where B: Buf, | ||||||
|  | { | ||||||
|  |     pub fn new() -> Prioritize<B> { | ||||||
|  |         Prioritize { | ||||||
|  |             pending_send: store::List::new(), | ||||||
|  |             buffer: Buffer::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn queue_frame(&mut self, | ||||||
|  |                        frame: Frame<B>, | ||||||
|  |                        stream: &mut store::Ptr<B>) | ||||||
|  |     { | ||||||
|  |         // queue the frame in the buffer | ||||||
|  |         stream.pending_send.push_back(&mut self.buffer, frame); | ||||||
|  |  | ||||||
|  |         if stream.is_pending_send { | ||||||
|  |             debug_assert!(!self.pending_send.is_empty()); | ||||||
|  |  | ||||||
|  |             // Already queued to have frame processed. | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Queue the stream | ||||||
|  |         self.push_sender(stream); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn poll_complete<T>(&mut self, | ||||||
|  |                             store: &mut Store<B>, | ||||||
|  |                             dst: &mut Codec<T, B>) | ||||||
|  |         -> Poll<(), ConnectionError> | ||||||
|  |         where T: AsyncWrite, | ||||||
|  |     { | ||||||
|  |         loop { | ||||||
|  |             // Ensure codec is ready | ||||||
|  |             try_ready!(dst.poll_ready()); | ||||||
|  |  | ||||||
|  |             match self.pop_frame(store) { | ||||||
|  |                 Some(frame) => { | ||||||
|  |                     // TODO: data frames should be handled specially... | ||||||
|  |                     let res = dst.start_send(frame)?; | ||||||
|  |  | ||||||
|  |                     // We already verified that `dst` is ready to accept the | ||||||
|  |                     // write | ||||||
|  |                     assert!(res.is_ready()); | ||||||
|  |                 } | ||||||
|  |                 None => break, | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Ok(().into()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn pop_frame(&mut self, store: &mut Store<B>) -> Option<Frame<B>> { | ||||||
|  |         match self.pop_sender(store) { | ||||||
|  |             Some(mut stream) => { | ||||||
|  |                 let frame = stream.pending_send.pop_front(&mut self.buffer).unwrap(); | ||||||
|  |  | ||||||
|  |                 if !stream.pending_send.is_empty() { | ||||||
|  |                     self.push_sender(&mut stream); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 Some(frame) | ||||||
|  |             } | ||||||
|  |             None => None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn push_sender(&mut self, stream: &mut store::Ptr<B>) { | ||||||
|  |         debug_assert!(!stream.is_pending_send); | ||||||
|  |  | ||||||
|  |         self.pending_send.push(stream); | ||||||
|  |  | ||||||
|  |         stream.is_pending_send = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn pop_sender<'a>(&mut self, store: &'a mut Store<B>) -> Option<store::Ptr<'a, B>> { | ||||||
|  |         match self.pending_send.pop(store) { | ||||||
|  |             Some(mut stream) => { | ||||||
|  |                 stream.is_pending_send = false; | ||||||
|  |                 Some(stream) | ||||||
|  |             } | ||||||
|  |             None => None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| use {frame, Peer, ConnectionError}; | use {client, frame, ConnectionError}; | ||||||
| use proto::*; | use proto::*; | ||||||
| use super::*; | use super::*; | ||||||
|  |  | ||||||
| @@ -8,7 +8,7 @@ use std::collections::VecDeque; | |||||||
| use std::marker::PhantomData; | use std::marker::PhantomData; | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Recv<P> { | pub(super) struct Recv<P, B> { | ||||||
|     /// Maximum number of remote initiated streams |     /// Maximum number of remote initiated streams | ||||||
|     max_streams: Option<usize>, |     max_streams: Option<usize>, | ||||||
|  |  | ||||||
| @@ -21,15 +21,35 @@ pub struct Recv<P> { | |||||||
|     /// Connection level flow control governing received data |     /// Connection level flow control governing received data | ||||||
|     flow_control: FlowControl, |     flow_control: FlowControl, | ||||||
|  |  | ||||||
|  |     /// Streams that have pending window updates | ||||||
|  |     /// TODO: don't use a VecDeque | ||||||
|     pending_window_updates: VecDeque<StreamId>, |     pending_window_updates: VecDeque<StreamId>, | ||||||
|  |  | ||||||
|  |     /// Holds frames that are waiting to be read | ||||||
|  |     buffer: Buffer<Bytes>, | ||||||
|  |  | ||||||
|     /// Refused StreamId, this represents a frame that must be sent out. |     /// Refused StreamId, this represents a frame that must be sent out. | ||||||
|     refused: Option<StreamId>, |     refused: Option<StreamId>, | ||||||
|  |  | ||||||
|     _p: PhantomData<P>, |     _p: PhantomData<(P, B)>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<P: Peer> Recv<P> { | #[derive(Debug)] | ||||||
|  | pub(super) struct Chunk { | ||||||
|  |     /// Data frames pending receival | ||||||
|  |     pub pending_recv: buffer::Deque<Bytes>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug, Clone, Copy)] | ||||||
|  | struct Indices { | ||||||
|  |     head: store::Key, | ||||||
|  |     tail: store::Key, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<P, B> Recv<P, B> | ||||||
|  |     where P: Peer, | ||||||
|  |           B: Buf, | ||||||
|  | { | ||||||
|     pub fn new(config: &Config) -> Self { |     pub fn new(config: &Config) -> Self { | ||||||
|         Recv { |         Recv { | ||||||
|             max_streams: config.max_remote_initiated, |             max_streams: config.max_remote_initiated, | ||||||
| @@ -37,6 +57,7 @@ impl<P: Peer> Recv<P> { | |||||||
|             init_window_sz: config.init_remote_window_sz, |             init_window_sz: config.init_remote_window_sz, | ||||||
|             flow_control: FlowControl::new(config.init_remote_window_sz), |             flow_control: FlowControl::new(config.init_remote_window_sz), | ||||||
|             pending_window_updates: VecDeque::new(), |             pending_window_updates: VecDeque::new(), | ||||||
|  |             buffer: Buffer::new(), | ||||||
|             refused: None, |             refused: None, | ||||||
|             _p: PhantomData, |             _p: PhantomData, | ||||||
|         } |         } | ||||||
| @@ -45,40 +66,58 @@ impl<P: Peer> Recv<P> { | |||||||
|     /// Update state reflecting a new, remotely opened stream |     /// Update state reflecting a new, remotely opened stream | ||||||
|     /// |     /// | ||||||
|     /// Returns the stream state if successful. `None` if refused |     /// Returns the stream state if successful. `None` if refused | ||||||
|     pub fn open(&mut self, id: StreamId) -> Result<Option<State>, ConnectionError> { |     pub fn open(&mut self, id: StreamId) -> Result<Option<Stream<B>>, ConnectionError> { | ||||||
|         assert!(self.refused.is_none()); |         assert!(self.refused.is_none()); | ||||||
|  |  | ||||||
|         try!(self.ensure_can_open(id)); |         try!(self.ensure_can_open(id)); | ||||||
|  |  | ||||||
|         if let Some(max) = self.max_streams { |         if !self.can_inc_num_streams() { | ||||||
|             if max <= self.num_streams { |  | ||||||
|             self.refused = Some(id); |             self.refused = Some(id); | ||||||
|             return Ok(None); |             return Ok(None); | ||||||
|         } |         } | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // Increment the number of remote initiated streams |         Ok(Some(Stream::new(id))) | ||||||
|         self.num_streams += 1; |  | ||||||
|  |  | ||||||
|         Ok(Some(State::default())) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Transition the stream state based on receiving headers |     /// Transition the stream state based on receiving headers | ||||||
|     pub fn recv_headers(&mut self, state: &mut State, eos: bool) |     pub fn recv_headers(&mut self, | ||||||
|         -> Result<(), ConnectionError> |                         frame: frame::Headers, | ||||||
|  |                         stream: &mut store::Ptr<B>) | ||||||
|  |         -> Result<Option<frame::Headers>, ConnectionError> | ||||||
|     { |     { | ||||||
|         state.recv_open(self.init_window_sz, eos) |         let is_initial = stream.state.recv_open(self.init_window_sz, frame.is_end_stream())?; | ||||||
|  |  | ||||||
|  |         if is_initial { | ||||||
|  |             if !self.can_inc_num_streams() { | ||||||
|  |                 unimplemented!(); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|     pub fn recv_eos(&mut self, state: &mut State) |             // Increment the number of concurrent streams | ||||||
|  |             self.inc_num_streams(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Only servers can receive a headers frame that initiates the stream. | ||||||
|  |         // This is verified in `Streams` before calling this function. | ||||||
|  |         if P::is_server() { | ||||||
|  |             Ok(Some(frame)) | ||||||
|  |         } else { | ||||||
|  |             // Push the frame onto the recv buffer | ||||||
|  |             stream.pending_recv.push_back(&mut self.buffer, frame.into()); | ||||||
|  |             stream.notify_recv(); | ||||||
|  |  | ||||||
|  |             Ok(None) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_eos(&mut self, stream: &mut Stream<B>) | ||||||
|         -> Result<(), ConnectionError> |         -> Result<(), ConnectionError> | ||||||
|     { |     { | ||||||
|         state.recv_close() |         stream.state.recv_close() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn recv_data(&mut self, |     pub fn recv_data(&mut self, | ||||||
|                      frame: &frame::Data, |                      frame: frame::Data, | ||||||
|                      state: &mut State) |                      stream: &mut store::Ptr<B>) | ||||||
|         -> Result<(), ConnectionError> |         -> Result<(), ConnectionError> | ||||||
|     { |     { | ||||||
|         let sz = frame.payload().len(); |         let sz = frame.payload().len(); | ||||||
| @@ -89,7 +128,7 @@ impl<P: Peer> Recv<P> { | |||||||
|  |  | ||||||
|         let sz = sz as WindowSize; |         let sz = sz as WindowSize; | ||||||
|  |  | ||||||
|         match state.recv_flow_control() { |         match stream.recv_flow_control() { | ||||||
|             Some(flow) => { |             Some(flow) => { | ||||||
|                 // Ensure there's enough capacity on the connection before |                 // Ensure there's enough capacity on the connection before | ||||||
|                 // acting on the stream. |                 // acting on the stream. | ||||||
| @@ -106,12 +145,97 @@ impl<P: Peer> Recv<P> { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if frame.is_end_stream() { |         if frame.is_end_stream() { | ||||||
|             try!(state.recv_close()); |             try!(stream.state.recv_close()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // Push the frame onto the recv buffer | ||||||
|  |         stream.pending_recv.push_back(&mut self.buffer, frame.into()); | ||||||
|  |         stream.notify_recv(); | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_push_promise(&mut self, frame: frame::PushPromise, stream: &mut store::Ptr<B>) | ||||||
|  |         -> Result<(), ConnectionError> | ||||||
|  |     { | ||||||
|  |         // First, make sure that the values are legit | ||||||
|  |         self.ensure_can_reserve(frame.promised_id())?; | ||||||
|  |  | ||||||
|  |         // Make sure that the stream state is valid | ||||||
|  |         stream.state.ensure_recv_open()?; | ||||||
|  |  | ||||||
|  |         // TODO: Streams in the reserved states do not count towards the concurrency | ||||||
|  |         // limit. However, it seems like there should be a cap otherwise this | ||||||
|  |         // could grow in memory indefinitely. | ||||||
|  |  | ||||||
|  |         /* | ||||||
|  |         if !self.inc_num_streams() { | ||||||
|  |             self.refused = Some(frame.promised_id()); | ||||||
|  |             return Ok(()); | ||||||
|  |         } | ||||||
|  |         */ | ||||||
|  |  | ||||||
|  |         // TODO: All earlier stream IDs should be implicitly closed. | ||||||
|  |  | ||||||
|  |         // Now, create a new entry for the stream | ||||||
|  |         let mut new_stream = Stream::new(frame.promised_id()); | ||||||
|  |         new_stream.state.reserve_remote(); | ||||||
|  |  | ||||||
|  |         let mut ppp = stream.pending_push_promises.take(); | ||||||
|  |  | ||||||
|  |         { | ||||||
|  |             // Store the stream | ||||||
|  |             let mut new_stream = stream.store() | ||||||
|  |                 .insert(frame.promised_id(), new_stream); | ||||||
|  |  | ||||||
|  |             ppp.push(&mut new_stream); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         stream.pending_push_promises = ppp; | ||||||
|  |         stream.notify_recv(); | ||||||
|  |  | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_reset(&mut self, frame: frame::Reset, stream: &mut Stream<B>) | ||||||
|  |         -> Result<(), ConnectionError> | ||||||
|  |     { | ||||||
|  |         let err = ConnectionError::Proto(frame.reason()); | ||||||
|  |  | ||||||
|  |         // Notify the stream | ||||||
|  |         stream.state.recv_err(&err); | ||||||
|  |         stream.notify_recv(); | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_err(&mut self, err: &ConnectionError, stream: &mut Stream<B>) { | ||||||
|  |         // Receive an error | ||||||
|  |         stream.state.recv_err(err); | ||||||
|  |  | ||||||
|  |         // If a receiver is waiting, notify it | ||||||
|  |         stream.notify_recv(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Returns true if the current stream concurrency can be incremetned | ||||||
|  |     fn can_inc_num_streams(&self) -> bool { | ||||||
|  |         if let Some(max) = self.max_streams { | ||||||
|  |             max > self.num_streams | ||||||
|  |         } else { | ||||||
|  |             true | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Increments the number of concurrenty streams. Panics on failure as this | ||||||
|  |     /// should have been validated before hand. | ||||||
|  |     fn inc_num_streams(&mut self) { | ||||||
|  |         if !self.can_inc_num_streams() { | ||||||
|  |             panic!(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Increment the number of remote initiated streams | ||||||
|  |         self.num_streams += 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn dec_num_streams(&mut self) { |     pub fn dec_num_streams(&mut self) { | ||||||
|         self.num_streams -= 1; |         self.num_streams -= 1; | ||||||
|     } |     } | ||||||
| @@ -132,11 +256,25 @@ impl<P: Peer> Recv<P> { | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Returns true if the remote peer can reserve a stream with the given ID. | ||||||
|  |     fn ensure_can_reserve(&self, promised_id: StreamId) -> Result<(), ConnectionError> { | ||||||
|  |         // TODO: Are there other rules? | ||||||
|  |         if P::is_server() { | ||||||
|  |             // The remote is a client and cannot reserve | ||||||
|  |             return Err(ProtocolError.into()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if !promised_id.is_server_initiated() { | ||||||
|  |             return Err(ProtocolError.into()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Send any pending refusals. |     /// Send any pending refusals. | ||||||
|     pub fn send_pending_refusal<T, B>(&mut self, dst: &mut Codec<T, B>) |     pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, B>) | ||||||
|         -> Poll<(), ConnectionError> |         -> Poll<(), ConnectionError> | ||||||
|         where T: AsyncWrite, |         where T: AsyncWrite, | ||||||
|               B: Buf, |  | ||||||
|     { |     { | ||||||
|         if let Some(stream_id) = self.refused.take() { |         if let Some(stream_id) = self.refused.take() { | ||||||
|             let frame = frame::Reset::new(stream_id, RefusedStream); |             let frame = frame::Reset::new(stream_id, RefusedStream); | ||||||
| @@ -168,11 +306,11 @@ impl<P: Peer> Recv<P> { | |||||||
|     pub fn expand_stream_window(&mut self, |     pub fn expand_stream_window(&mut self, | ||||||
|                                 id: StreamId, |                                 id: StreamId, | ||||||
|                                 sz: WindowSize, |                                 sz: WindowSize, | ||||||
|                                 state: &mut State) |                                 stream: &mut store::Ptr<B>) | ||||||
|         -> Result<(), ConnectionError> |         -> Result<(), ConnectionError> | ||||||
|     { |     { | ||||||
|         // TODO: handle overflow |         // TODO: handle overflow | ||||||
|         if let Some(flow) = state.recv_flow_control() { |         if let Some(flow) = stream.recv_flow_control() { | ||||||
|             flow.expand_window(sz); |             flow.expand_window(sz); | ||||||
|             self.pending_window_updates.push_back(id); |             self.pending_window_updates.push_back(id); | ||||||
|         } |         } | ||||||
| @@ -181,10 +319,9 @@ impl<P: Peer> Recv<P> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Send connection level window update |     /// Send connection level window update | ||||||
|     pub fn send_connection_window_update<T, B>(&mut self, dst: &mut Codec<T, B>) |     pub fn send_connection_window_update<T>(&mut self, dst: &mut Codec<T, B>) | ||||||
|         -> Poll<(), ConnectionError> |         -> Poll<(), ConnectionError> | ||||||
|         where T: AsyncWrite, |         where T: AsyncWrite, | ||||||
|               B: Buf, |  | ||||||
|     { |     { | ||||||
|         if let Some(incr) = self.flow_control.peek_window_update() { |         if let Some(incr) = self.flow_control.peek_window_update() { | ||||||
|             let frame = frame::WindowUpdate::new(StreamId::zero(), incr); |             let frame = frame::WindowUpdate::new(StreamId::zero(), incr); | ||||||
| @@ -199,17 +336,47 @@ impl<P: Peer> Recv<P> { | |||||||
|         Ok(().into()) |         Ok(().into()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     pub fn poll_chunk(&mut self, stream: &mut Stream<B>) | ||||||
|  |         -> Poll<Option<Chunk>, ConnectionError> | ||||||
|  |     { | ||||||
|  |         let frames = stream.pending_recv | ||||||
|  |             .take_while(&mut self.buffer, |frame| frame.is_data()); | ||||||
|  |  | ||||||
|  |         if frames.is_empty() { | ||||||
|  |             if stream.state.is_recv_closed() { | ||||||
|  |                 Ok(None.into()) | ||||||
|  |             } else { | ||||||
|  |                 stream.recv_task = Some(task::current()); | ||||||
|  |                 Ok(Async::NotReady) | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             Ok(Some(Chunk { | ||||||
|  |                 pending_recv: frames, | ||||||
|  |             }).into()) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn pop_bytes(&mut self, chunk: &mut Chunk) -> Option<Bytes> { | ||||||
|  |         match chunk.pending_recv.pop_front(&mut self.buffer) { | ||||||
|  |             Some(Frame::Data(frame)) => { | ||||||
|  |                 Some(frame.into_payload()) | ||||||
|  |             } | ||||||
|  |             None => None, | ||||||
|  |             _ => panic!("unexpected frame type"), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Send stream level window update |     /// Send stream level window update | ||||||
|     pub fn send_stream_window_update<T, B>(&mut self, |     pub fn send_stream_window_update<T>(&mut self, | ||||||
|                                            streams: &mut Store, |                                         streams: &mut Store<B>, | ||||||
|                                         dst: &mut Codec<T, B>) |                                         dst: &mut Codec<T, B>) | ||||||
|         -> Poll<(), ConnectionError> |         -> Poll<(), ConnectionError> | ||||||
|         where T: AsyncWrite, |         where T: AsyncWrite, | ||||||
|               B: Buf, |  | ||||||
|     { |     { | ||||||
|         while let Some(id) = self.pending_window_updates.pop_front() { |         while let Some(id) = self.pending_window_updates.pop_front() { | ||||||
|             let flow = streams.get_mut(&id) |             let flow = streams.find_mut(&id) | ||||||
|                 .and_then(|state| state.recv_flow_control()); |                 .and_then(|stream| stream.into_mut().recv_flow_control()); | ||||||
|  |  | ||||||
|  |  | ||||||
|             if let Some(flow) = flow { |             if let Some(flow) = flow { | ||||||
| @@ -233,3 +400,27 @@ impl<P: Peer> Recv<P> { | |||||||
|         unimplemented!(); |         unimplemented!(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | impl<B> Recv<client::Peer, B> | ||||||
|  |     where B: Buf, | ||||||
|  | { | ||||||
|  |     pub fn poll_response(&mut self, stream: &mut store::Ptr<B>) | ||||||
|  |         -> Poll<Response<()>, ConnectionError> { | ||||||
|  |         // If the buffer is not empty, then the first frame must be a HEADERS | ||||||
|  |         // frame or the user violated the contract. | ||||||
|  |         match stream.pending_recv.pop_front(&mut self.buffer) { | ||||||
|  |             Some(Frame::Headers(v)) => { | ||||||
|  |                 // TODO: This error should probably be caught on receipt of the | ||||||
|  |                 // frame vs. now. | ||||||
|  |                 Ok(client::Peer::convert_poll_message(v)?.into()) | ||||||
|  |             } | ||||||
|  |             Some(frame) => unimplemented!(), | ||||||
|  |             None => { | ||||||
|  |                 stream.state.ensure_recv_open()?; | ||||||
|  |  | ||||||
|  |                 stream.recv_task = Some(task::current()); | ||||||
|  |                 Ok(Async::NotReady) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| use {frame, Peer, ConnectionError}; | use {frame, ConnectionError}; | ||||||
| use proto::*; | use proto::*; | ||||||
| use super::*; | use super::*; | ||||||
|  |  | ||||||
| @@ -10,13 +10,16 @@ use std::collections::VecDeque; | |||||||
| use std::marker::PhantomData; | use std::marker::PhantomData; | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Send<P> { | pub(super) struct Send<P, B> { | ||||||
|     /// Maximum number of locally initiated streams |     /// Maximum number of locally initiated streams | ||||||
|     max_streams: Option<usize>, |     max_streams: Option<usize>, | ||||||
|  |  | ||||||
|     /// Current number of locally initiated streams |     /// Current number of locally initiated streams | ||||||
|     num_streams: usize, |     num_streams: usize, | ||||||
|  |  | ||||||
|  |     /// Stream identifier to use for next initialized stream. | ||||||
|  |     next_stream_id: StreamId, | ||||||
|  |  | ||||||
|     /// Initial window size of locally initiated streams |     /// Initial window size of locally initiated streams | ||||||
|     init_window_sz: WindowSize, |     init_window_sz: WindowSize, | ||||||
|  |  | ||||||
| @@ -27,6 +30,8 @@ pub struct Send<P> { | |||||||
|     // XXX It would be cool if this didn't exist. |     // XXX It would be cool if this didn't exist. | ||||||
|     pending_window_updates: VecDeque<StreamId>, |     pending_window_updates: VecDeque<StreamId>, | ||||||
|  |  | ||||||
|  |     prioritize: Prioritize<B>, | ||||||
|  |  | ||||||
|     /// When `poll_window_update` is not ready, then the calling task is saved to |     /// When `poll_window_update` is not ready, then the calling task is saved to | ||||||
|     /// be notified later. Access to poll_window_update must not be shared across tasks, |     /// be notified later. Access to poll_window_update must not be shared across tasks, | ||||||
|     /// as we only track a single task (and *not* i.e. a task per stream id). |     /// as we only track a single task (and *not* i.e. a task per stream id). | ||||||
| @@ -35,13 +40,24 @@ pub struct Send<P> { | |||||||
|     _p: PhantomData<P>, |     _p: PhantomData<P>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<P: Peer> Send<P> { | impl<P, B> Send<P, B> | ||||||
|  |     where P: Peer, | ||||||
|  |           B: Buf, | ||||||
|  | { | ||||||
|     pub fn new(config: &Config) -> Self { |     pub fn new(config: &Config) -> Self { | ||||||
|  |         let next_stream_id = if P::is_server() { | ||||||
|  |             2 | ||||||
|  |         } else { | ||||||
|  |             1 | ||||||
|  |         }; | ||||||
|  |  | ||||||
|         Send { |         Send { | ||||||
|             max_streams: config.max_local_initiated, |             max_streams: config.max_local_initiated, | ||||||
|             num_streams: 0, |             num_streams: 0, | ||||||
|  |             next_stream_id: next_stream_id.into(), | ||||||
|             init_window_sz: config.init_local_window_sz, |             init_window_sz: config.init_local_window_sz, | ||||||
|             flow_control: FlowControl::new(config.init_local_window_sz), |             flow_control: FlowControl::new(config.init_local_window_sz), | ||||||
|  |             prioritize: Prioritize::new(), | ||||||
|             pending_window_updates: VecDeque::new(), |             pending_window_updates: VecDeque::new(), | ||||||
|             blocked: None, |             blocked: None, | ||||||
|             _p: PhantomData, |             _p: PhantomData, | ||||||
| @@ -51,8 +67,8 @@ impl<P: Peer> Send<P> { | |||||||
|     /// Update state reflecting a new, locally opened stream |     /// Update state reflecting a new, locally opened stream | ||||||
|     /// |     /// | ||||||
|     /// Returns the stream state if successful. `None` if refused |     /// Returns the stream state if successful. `None` if refused | ||||||
|     pub fn open(&mut self, id: StreamId) -> Result<State, ConnectionError> { |     pub fn open(&mut self) -> Result<Stream<B>, ConnectionError> { | ||||||
|         try!(self.ensure_can_open(id)); |         try!(self.ensure_can_open()); | ||||||
|  |  | ||||||
|         if let Some(max) = self.max_streams { |         if let Some(max) = self.max_streams { | ||||||
|             if max <= self.num_streams { |             if max <= self.num_streams { | ||||||
| @@ -60,27 +76,38 @@ impl<P: Peer> Send<P> { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         let ret = Stream::new(self.next_stream_id); | ||||||
|  |  | ||||||
|         // Increment the number of locally initiated streams |         // Increment the number of locally initiated streams | ||||||
|         self.num_streams += 1; |         self.num_streams += 1; | ||||||
|  |         self.next_stream_id.increment(); | ||||||
|  |  | ||||||
|         Ok(State::default()) |         Ok(ret) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn send_headers(&mut self, state: &mut State, eos: bool) |     pub fn send_headers(&mut self, | ||||||
|  |                         frame: frame::Headers, | ||||||
|  |                         stream: &mut store::Ptr<B>) | ||||||
|         -> Result<(), ConnectionError> |         -> Result<(), ConnectionError> | ||||||
|     { |     { | ||||||
|         state.send_open(self.init_window_sz, eos) |         // Update the state | ||||||
|  |         stream.state.send_open(self.init_window_sz, frame.is_end_stream())?; | ||||||
|  |  | ||||||
|  |         // Queue the frame for sending | ||||||
|  |         self.prioritize.queue_frame(frame.into(), stream); | ||||||
|  |  | ||||||
|  |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn send_eos(&mut self, state: &mut State) |     pub fn send_eos(&mut self, stream: &mut Stream<B>) | ||||||
|         -> Result<(), ConnectionError> |         -> Result<(), ConnectionError> | ||||||
|     { |     { | ||||||
|         state.send_close() |         stream.state.send_close() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn send_data<B: Buf>(&mut self, |     pub fn send_data(&mut self, | ||||||
|                              frame: &frame::Data<B>, |                      frame: frame::Data<B>, | ||||||
|                              state: &mut State) |                      stream: &mut store::Ptr<B>) | ||||||
|         -> Result<(), ConnectionError> |         -> Result<(), ConnectionError> | ||||||
|     { |     { | ||||||
|         let sz = frame.payload().remaining(); |         let sz = frame.payload().remaining(); | ||||||
| @@ -94,7 +121,7 @@ impl<P: Peer> Send<P> { | |||||||
|  |  | ||||||
|         // Make borrow checker happy |         // Make borrow checker happy | ||||||
|         loop { |         loop { | ||||||
|             match state.send_flow_control() { |             match stream.send_flow_control() { | ||||||
|                 Some(flow) => { |                 Some(flow) => { | ||||||
|                     try!(self.flow_control.ensure_window(sz, FlowControlViolation)); |                     try!(self.flow_control.ensure_window(sz, FlowControlViolation)); | ||||||
|  |  | ||||||
| @@ -110,7 +137,7 @@ impl<P: Peer> Send<P> { | |||||||
|                 None => {} |                 None => {} | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if state.is_closed() { |             if stream.state.is_closed() { | ||||||
|                 return Err(InactiveStreamId.into()) |                 return Err(InactiveStreamId.into()) | ||||||
|             } else { |             } else { | ||||||
|                 return Err(UnexpectedFrameType.into()) |                 return Err(UnexpectedFrameType.into()) | ||||||
| @@ -118,14 +145,25 @@ impl<P: Peer> Send<P> { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if frame.is_end_stream() { |         if frame.is_end_stream() { | ||||||
|             try!(state.send_close()); |             try!(stream.state.send_close()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         self.prioritize.queue_frame(frame.into(), stream); | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn poll_complete<T>(&mut self, | ||||||
|  |                             store: &mut Store<B>, | ||||||
|  |                             dst: &mut Codec<T, B>) | ||||||
|  |         -> Poll<(), ConnectionError> | ||||||
|  |         where T: AsyncWrite, | ||||||
|  |     { | ||||||
|  |         self.prioritize.poll_complete(store, dst) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Get pending window updates |     /// Get pending window updates | ||||||
|     pub fn poll_window_update(&mut self, streams: &mut Store) |     pub fn poll_window_update(&mut self, streams: &mut Store<B>) | ||||||
|         -> Poll<WindowUpdate, ConnectionError> |         -> Poll<WindowUpdate, ConnectionError> | ||||||
|     { |     { | ||||||
|         // This biases connection window updates, which probably makes sense. |         // This biases connection window updates, which probably makes sense. | ||||||
| @@ -138,8 +176,8 @@ impl<P: Peer> Send<P> { | |||||||
|         // TODO this should probably account for stream priority? |         // TODO this should probably account for stream priority? | ||||||
|         let update = self.pending_window_updates.pop_front() |         let update = self.pending_window_updates.pop_front() | ||||||
|             .and_then(|id| { |             .and_then(|id| { | ||||||
|                 streams.get_mut(&id) |                 streams.find_mut(&id) | ||||||
|                     .and_then(|state| state.send_flow_control()) |                     .and_then(|stream| stream.into_mut().send_flow_control()) | ||||||
|                     .and_then(|flow| flow.apply_window_update()) |                     .and_then(|flow| flow.apply_window_update()) | ||||||
|                     .map(|incr| WindowUpdate::new(id, incr)) |                     .map(|incr| WindowUpdate::new(id, incr)) | ||||||
|             }); |             }); | ||||||
| @@ -171,10 +209,10 @@ impl<P: Peer> Send<P> { | |||||||
|  |  | ||||||
|     pub fn recv_stream_window_update(&mut self, |     pub fn recv_stream_window_update(&mut self, | ||||||
|                                      frame: frame::WindowUpdate, |                                      frame: frame::WindowUpdate, | ||||||
|                                      state: &mut State) |                                      stream: &mut store::Ptr<B>) | ||||||
|         -> Result<(), ConnectionError> |         -> Result<(), ConnectionError> | ||||||
|     { |     { | ||||||
|         if let Some(flow) = state.send_flow_control() { |         if let Some(flow) = stream.send_flow_control() { | ||||||
|             // TODO: Handle invalid increment |             // TODO: Handle invalid increment | ||||||
|             flow.expand_window(frame.size_increment()); |             flow.expand_window(frame.size_increment()); | ||||||
|         } |         } | ||||||
| @@ -191,15 +229,13 @@ impl<P: Peer> Send<P> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Returns true if the local actor can initiate a stream with the given ID. |     /// Returns true if the local actor can initiate a stream with the given ID. | ||||||
|     fn ensure_can_open(&self, id: StreamId) -> Result<(), ConnectionError> { |     fn ensure_can_open(&self) -> Result<(), ConnectionError> { | ||||||
|         if P::is_server() { |         if P::is_server() { | ||||||
|             // Servers cannot open streams. PushPromise must first be reserved. |             // Servers cannot open streams. PushPromise must first be reserved. | ||||||
|             return Err(UnexpectedFrameType.into()); |             return Err(UnexpectedFrameType.into()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if !id.is_client_initiated() { |         // TODO: Handle StreamId overflow | ||||||
|             return Err(InvalidStreamId.into()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -58,7 +58,7 @@ enum Inner { | |||||||
|     Idle, |     Idle, | ||||||
|     // TODO: these states shouldn't count against concurrency limits: |     // TODO: these states shouldn't count against concurrency limits: | ||||||
|     //ReservedLocal, |     //ReservedLocal, | ||||||
|     //ReservedRemote, |     ReservedRemote, | ||||||
|     Open { |     Open { | ||||||
|         local: Peer, |         local: Peer, | ||||||
|         remote: Peer, |         remote: Peer, | ||||||
| @@ -66,7 +66,7 @@ enum Inner { | |||||||
|     HalfClosedLocal(Peer), // TODO: explicitly name this value |     HalfClosedLocal(Peer), // TODO: explicitly name this value | ||||||
|     HalfClosedRemote(Peer), |     HalfClosedRemote(Peer), | ||||||
|     // When reset, a reason is provided |     // When reset, a reason is provided | ||||||
|     Closed(Option<Reason>), |     Closed(Option<Cause>), | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Copy, Clone)] | #[derive(Debug, Copy, Clone)] | ||||||
| @@ -76,6 +76,12 @@ enum Peer { | |||||||
|     Streaming(FlowControl), |     Streaming(FlowControl), | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[derive(Debug, Copy, Clone)] | ||||||
|  | enum Cause { | ||||||
|  |     Proto(Reason), | ||||||
|  |     Io, | ||||||
|  | } | ||||||
|  |  | ||||||
| impl State { | impl State { | ||||||
|     /// Opens the send-half of a stream if it is not already open. |     /// Opens the send-half of a stream if it is not already open. | ||||||
|     pub fn send_open(&mut self, sz: WindowSize, eos: bool) -> Result<(), ConnectionError> { |     pub fn send_open(&mut self, sz: WindowSize, eos: bool) -> Result<(), ConnectionError> { | ||||||
| @@ -120,11 +126,16 @@ impl State { | |||||||
|  |  | ||||||
|     /// Open the receive have of the stream, this action is taken when a HEADERS |     /// Open the receive have of the stream, this action is taken when a HEADERS | ||||||
|     /// frame is received. |     /// frame is received. | ||||||
|     pub fn recv_open(&mut self, sz: WindowSize, eos: bool) -> Result<(), ConnectionError> { |     /// | ||||||
|  |     /// Returns true if this transitions the state to Open | ||||||
|  |     pub fn recv_open(&mut self, sz: WindowSize, eos: bool) -> Result<bool, ConnectionError> { | ||||||
|         let remote = Peer::streaming(sz); |         let remote = Peer::streaming(sz); | ||||||
|  |         let mut initial = false; | ||||||
|  |  | ||||||
|         self.inner = match self.inner { |         self.inner = match self.inner { | ||||||
|             Idle => { |             Idle => { | ||||||
|  |                 initial = true; | ||||||
|  |  | ||||||
|                 if eos { |                 if eos { | ||||||
|                     HalfClosedRemote(AwaitingHeaders) |                     HalfClosedRemote(AwaitingHeaders) | ||||||
|                 } else { |                 } else { | ||||||
| @@ -134,6 +145,18 @@ impl State { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             ReservedRemote => { | ||||||
|  |                 initial = true; | ||||||
|  |  | ||||||
|  |                 if eos { | ||||||
|  |                     Closed(None) | ||||||
|  |                 } else { | ||||||
|  |                     Open { | ||||||
|  |                         local: AwaitingHeaders, | ||||||
|  |                         remote, | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|             Open { local, remote: AwaitingHeaders } => { |             Open { local, remote: AwaitingHeaders } => { | ||||||
|                 if eos { |                 if eos { | ||||||
|                     HalfClosedRemote(local) |                     HalfClosedRemote(local) | ||||||
| @@ -157,7 +180,18 @@ impl State { | |||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         return Ok(()); |         return Ok(initial); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Transition from Idle -> ReservedRemote | ||||||
|  |     pub fn reserve_remote(&mut self) -> Result<(), ConnectionError> { | ||||||
|  |         match self.inner { | ||||||
|  |             Idle => { | ||||||
|  |                 self.inner = ReservedRemote; | ||||||
|  |                 Ok(()) | ||||||
|  |             } | ||||||
|  |             _ => Err(ProtocolError.into()), | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Indicates that the remote side will not send more data to the local. |     /// Indicates that the remote side will not send more data to the local. | ||||||
| @@ -178,6 +212,19 @@ impl State { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_err(&mut self, err: &ConnectionError) { | ||||||
|  |         match self.inner { | ||||||
|  |             Closed(..) => {} | ||||||
|  |             _ => { | ||||||
|  |                 self.inner = Closed(match *err { | ||||||
|  |                     ConnectionError::Proto(reason) => Some(Cause::Proto(reason)), | ||||||
|  |                     ConnectionError::Io(..) => Some(Cause::Io), | ||||||
|  |                     _ => panic!("cannot terminate stream with user error"), | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Indicates that the local side will not send more data to the local. |     /// Indicates that the local side will not send more data to the local. | ||||||
|     pub fn send_close(&mut self) -> Result<(), ConnectionError> { |     pub fn send_close(&mut self) -> Result<(), ConnectionError> { | ||||||
|         match self.inner { |         match self.inner { | ||||||
| @@ -196,6 +243,17 @@ impl State { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// Returns true if a stream with the current state counts against the | ||||||
|  |     /// concurrency limit. | ||||||
|  |     pub fn is_counted(&self) -> bool { | ||||||
|  |         match self.inner { | ||||||
|  |             Open { .. } => true, | ||||||
|  |             HalfClosedLocal(..) => true, | ||||||
|  |             HalfClosedRemote(..) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn is_closed(&self) -> bool { |     pub fn is_closed(&self) -> bool { | ||||||
|         match self.inner { |         match self.inner { | ||||||
|             Closed(_) => true, |             Closed(_) => true, | ||||||
| @@ -203,6 +261,13 @@ impl State { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn is_recv_closed(&self) -> bool { | ||||||
|  |         match self.inner { | ||||||
|  |             Closed(..) | HalfClosedRemote(..) => true, | ||||||
|  |             _ => false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     pub fn recv_flow_control(&mut self) -> Option<&mut FlowControl> { |     pub fn recv_flow_control(&mut self) -> Option<&mut FlowControl> { | ||||||
|         match self.inner { |         match self.inner { | ||||||
|             Open { ref mut remote, .. } | |             Open { ref mut remote, .. } | | ||||||
| @@ -218,6 +283,21 @@ impl State { | |||||||
|             _ => None, |             _ => None, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn ensure_recv_open(&self) -> Result<(), ConnectionError> { | ||||||
|  |         use std::io; | ||||||
|  |  | ||||||
|  |         // TODO: Is this correct? | ||||||
|  |         match self.inner { | ||||||
|  |             Closed(Some(Cause::Proto(reason))) => { | ||||||
|  |                 Err(ConnectionError::Proto(reason)) | ||||||
|  |             } | ||||||
|  |             Closed(Some(Cause::Io)) => { | ||||||
|  |                 Err(ConnectionError::Io(io::ErrorKind::BrokenPipe.into())) | ||||||
|  |             } | ||||||
|  |             _ => Ok(()), | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Default for State { | impl Default for State { | ||||||
|   | |||||||
| @@ -1,32 +1,59 @@ | |||||||
| extern crate slab; |  | ||||||
|  |  | ||||||
| use super::*; | use super::*; | ||||||
|  |  | ||||||
|  | use slab; | ||||||
|  |  | ||||||
|  | use std::ops; | ||||||
| use std::collections::{HashMap, hash_map}; | use std::collections::{HashMap, hash_map}; | ||||||
|  | use std::marker::PhantomData; | ||||||
|  |  | ||||||
| /// Storage for streams | /// Storage for streams | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct Store { | pub(super) struct Store<B> { | ||||||
|     slab: slab::Slab<State>, |     slab: slab::Slab<Stream<B>>, | ||||||
|     ids: HashMap<StreamId, usize>, |     ids: HashMap<StreamId, usize>, | ||||||
| } | } | ||||||
|  |  | ||||||
| pub enum Entry<'a> { | /// "Pointer" to an entry in the store | ||||||
|     Occupied(OccupiedEntry<'a>), | pub(super) struct Ptr<'a, B: 'a> { | ||||||
|     Vacant(VacantEntry<'a>), |     key: Key, | ||||||
|  |     store: &'a mut Store<B>, | ||||||
| } | } | ||||||
|  |  | ||||||
| pub struct OccupiedEntry<'a> { | /// References an entry in the store. | ||||||
|  | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||||||
|  | pub(super) struct Key(usize); | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub(super) struct List<B> { | ||||||
|  |     indices: Option<store::Indices>, | ||||||
|  |     _p: PhantomData<B>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// A linked list | ||||||
|  | #[derive(Debug, Clone, Copy)] | ||||||
|  | struct Indices { | ||||||
|  |     pub head: Key, | ||||||
|  |     pub tail: Key, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub(super) enum Entry<'a, B: 'a> { | ||||||
|  |     Occupied(OccupiedEntry<'a, B>), | ||||||
|  |     Vacant(VacantEntry<'a, B>), | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pub(super) struct OccupiedEntry<'a, B: 'a> { | ||||||
|     ids: hash_map::OccupiedEntry<'a, StreamId, usize>, |     ids: hash_map::OccupiedEntry<'a, StreamId, usize>, | ||||||
|     slab: &'a mut slab::Slab<State>, |     slab: &'a mut slab::Slab<Stream<B>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| pub struct VacantEntry<'a> { | pub(super) struct VacantEntry<'a, B: 'a> { | ||||||
|     ids: hash_map::VacantEntry<'a, StreamId, usize>, |     ids: hash_map::VacantEntry<'a, StreamId, usize>, | ||||||
|     slab: &'a mut slab::Slab<State>, |     slab: &'a mut slab::Slab<Stream<B>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Store { | // ===== impl Store ===== | ||||||
|  |  | ||||||
|  | impl<B> Store<B> { | ||||||
|     pub fn new() -> Self { |     pub fn new() -> Self { | ||||||
|         Store { |         Store { | ||||||
|             slab: slab::Slab::new(), |             slab: slab::Slab::new(), | ||||||
| @@ -34,15 +61,35 @@ impl Store { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn get_mut(&mut self, id: &StreamId) -> Option<&mut State> { |     pub fn resolve(&mut self, key: Key) -> Ptr<B> { | ||||||
|         if let Some(handle) = self.ids.get(id) { |         Ptr { | ||||||
|             Some(&mut self.slab[*handle]) |             key: key, | ||||||
|  |             store: self, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn find_mut(&mut self, id: &StreamId) -> Option<Ptr<B>> { | ||||||
|  |         if let Some(&key) = self.ids.get(id) { | ||||||
|  |             Some(Ptr { | ||||||
|  |                 key: Key(key), | ||||||
|  |                 store: self, | ||||||
|  |             }) | ||||||
|         } else { |         } else { | ||||||
|             None |             None | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub fn entry(&mut self, id: StreamId) -> Entry { |     pub fn insert(&mut self, id: StreamId, val: Stream<B>) -> Ptr<B> { | ||||||
|  |         let key = self.slab.insert(val); | ||||||
|  |         assert!(self.ids.insert(id, key).is_none()); | ||||||
|  |  | ||||||
|  |         Ptr { | ||||||
|  |             key: Key(key), | ||||||
|  |             store: self, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn find_entry(&mut self, id: StreamId) -> Entry<B> { | ||||||
|         use self::hash_map::Entry::*; |         use self::hash_map::Entry::*; | ||||||
|  |  | ||||||
|         match self.ids.entry(id) { |         match self.ids.entry(id) { | ||||||
| @@ -60,22 +107,145 @@ impl Store { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn for_each<F>(&mut self, mut f: F) | ||||||
|  |         where F: FnMut(&mut Stream<B>) | ||||||
|  |     { | ||||||
|  |         for &id in self.ids.values() { | ||||||
|  |             f(&mut self.slab[id]) | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> OccupiedEntry<'a> { | // ===== impl List ===== | ||||||
|     pub fn into_mut(self) -> &'a mut State { |  | ||||||
|  | impl<B> List<B> { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         List { | ||||||
|  |             indices: None, | ||||||
|  |             _p: PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn is_empty(&self) -> bool { | ||||||
|  |         self.indices.is_none() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn take(&mut self) -> Self { | ||||||
|  |         List { | ||||||
|  |             indices: self.indices.take(), | ||||||
|  |             _p: PhantomData, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn push(&mut self, stream: &mut store::Ptr<B>) { | ||||||
|  |         // The next pointer shouldn't be set | ||||||
|  |         debug_assert!(stream.next.is_none()); | ||||||
|  |  | ||||||
|  |         // Queue the stream | ||||||
|  |         match self.indices { | ||||||
|  |             Some(ref mut idxs) => { | ||||||
|  |                 // Update the current tail node to point to `stream` | ||||||
|  |                 stream.resolve(idxs.tail).next = Some(stream.key()); | ||||||
|  |  | ||||||
|  |                 // Update the tail pointer | ||||||
|  |                 idxs.tail = stream.key(); | ||||||
|  |             } | ||||||
|  |             None => { | ||||||
|  |                 self.indices = Some(store::Indices { | ||||||
|  |                     head: stream.key(), | ||||||
|  |                     tail: stream.key(), | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn pop<'a>(&mut self, store: &'a mut Store<B>) -> Option<store::Ptr<'a, B>> { | ||||||
|  |         if let Some(mut idxs) = self.indices { | ||||||
|  |             let mut stream = store.resolve(idxs.head); | ||||||
|  |  | ||||||
|  |             if idxs.head == idxs.tail { | ||||||
|  |                 assert!(stream.next.is_none()); | ||||||
|  |                 self.indices = None; | ||||||
|  |             } else { | ||||||
|  |                 idxs.head = stream.next.take().unwrap(); | ||||||
|  |                 self.indices = Some(idxs); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             return Some(stream); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         None | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Ptr ===== | ||||||
|  |  | ||||||
|  | impl<'a, B: 'a> Ptr<'a, B> { | ||||||
|  |     pub fn key(&self) -> Key { | ||||||
|  |         self.key | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn store(&mut self) -> &mut Store<B> { | ||||||
|  |         &mut self.store | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn resolve(&mut self, key: Key) -> Ptr<B> { | ||||||
|  |         Ptr { | ||||||
|  |             key: key, | ||||||
|  |             store: self.store, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn into_mut(self) -> &'a mut Stream<B> { | ||||||
|  |         &mut self.store.slab[self.key.0] | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<'a, B: 'a> ops::Deref for Ptr<'a, B> { | ||||||
|  |     type Target = Stream<B>; | ||||||
|  |  | ||||||
|  |     fn deref(&self) -> &Stream<B> { | ||||||
|  |         &self.store.slab[self.key.0] | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<'a, B: 'a> ops::DerefMut for Ptr<'a, B> { | ||||||
|  |     fn deref_mut(&mut self) -> &mut Stream<B> { | ||||||
|  |         &mut self.store.slab[self.key.0] | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl OccupiedEntry ===== | ||||||
|  |  | ||||||
|  | impl<'a, B> OccupiedEntry<'a, B> { | ||||||
|  |     pub fn key(&self) -> Key { | ||||||
|  |         Key(*self.ids.get()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn get(&self) -> &Stream<B> { | ||||||
|  |         &self.slab[*self.ids.get()] | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn get_mut(&mut self) -> &mut Stream<B> { | ||||||
|  |         &mut self.slab[*self.ids.get()] | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn into_mut(self) -> &'a mut Stream<B> { | ||||||
|         &mut self.slab[*self.ids.get()] |         &mut self.slab[*self.ids.get()] | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<'a> VacantEntry<'a> { | // ===== impl VacantEntry ===== | ||||||
|     pub fn insert(self, value: State) -> &'a mut State { |  | ||||||
|  | impl<'a, B> VacantEntry<'a, B> { | ||||||
|  |     pub fn insert(self, value: Stream<B>) -> Key { | ||||||
|         // Insert the value in the slab |         // Insert the value in the slab | ||||||
|         let handle = self.slab.insert(value); |         let key = self.slab.insert(value); | ||||||
|  |  | ||||||
|         // Insert the handle in the ID map |         // Insert the handle in the ID map | ||||||
|         self.ids.insert(handle); |         self.ids.insert(key); | ||||||
|  |  | ||||||
|         &mut self.slab[handle] |         Key(key) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								src/proto/streams/stream.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/proto/streams/stream.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | use super::*; | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub(super) struct Stream<B> { | ||||||
|  |     /// The h2 stream identifier | ||||||
|  |     pub id: StreamId, | ||||||
|  |  | ||||||
|  |     /// Current state of the stream | ||||||
|  |     pub state: State, | ||||||
|  |  | ||||||
|  |     /// Frames pending for this stream to read | ||||||
|  |     pub pending_recv: buffer::Deque<Bytes>, | ||||||
|  |  | ||||||
|  |     /// Task tracking receiving frames | ||||||
|  |     pub recv_task: Option<task::Task>, | ||||||
|  |  | ||||||
|  |     /// Frames pending for this stream being sent to the socket | ||||||
|  |     pub pending_send: buffer::Deque<B>, | ||||||
|  |  | ||||||
|  |     /// Next node in the `Stream` linked list. | ||||||
|  |     /// | ||||||
|  |     /// This field is used in different linked lists depending on the stream | ||||||
|  |     /// state. | ||||||
|  |     pub next: Option<store::Key>, | ||||||
|  |  | ||||||
|  |     /// The stream's pending push promises | ||||||
|  |     pub pending_push_promises: store::List<B>, | ||||||
|  |  | ||||||
|  |     /// True if the stream is currently pending send | ||||||
|  |     pub is_pending_send: bool, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<B> Stream<B> { | ||||||
|  |     pub fn new(id: StreamId) -> Stream<B> { | ||||||
|  |         Stream { | ||||||
|  |             id, | ||||||
|  |             state: State::default(), | ||||||
|  |             pending_recv: buffer::Deque::new(), | ||||||
|  |             recv_task: None, | ||||||
|  |             pending_send: buffer::Deque::new(), | ||||||
|  |             next: None, | ||||||
|  |             pending_push_promises: store::List::new(), | ||||||
|  |             is_pending_send: false, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn send_flow_control(&mut self) -> Option<&mut FlowControl> { | ||||||
|  |         self.state.send_flow_control() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_flow_control(&mut self) -> Option<&mut FlowControl> { | ||||||
|  |         self.state.recv_flow_control() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn notify_recv(&mut self) { | ||||||
|  |         if let Some(ref mut task) = self.recv_task { | ||||||
|  |             task.notify(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										446
									
								
								src/proto/streams/streams.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										446
									
								
								src/proto/streams/streams.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,446 @@ | |||||||
|  | use client; | ||||||
|  | use proto::*; | ||||||
|  | use super::*; | ||||||
|  |  | ||||||
|  | use std::sync::{Arc, Mutex}; | ||||||
|  |  | ||||||
|  | // TODO: All the VecDeques should become linked lists using the State | ||||||
|  | // values. | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Streams<P, B> { | ||||||
|  |     inner: Arc<Mutex<Inner<P, B>>>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Reference to the stream state | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct StreamRef<P, B> { | ||||||
|  |     inner: Arc<Mutex<Inner<P, B>>>, | ||||||
|  |     key: store::Key, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Chunk<P, B> | ||||||
|  |     where P: Peer, | ||||||
|  |           B: Buf, | ||||||
|  | { | ||||||
|  |     inner: Arc<Mutex<Inner<P, B>>>, | ||||||
|  |     recv: recv::Chunk, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /// Fields needed to manage state related to managing the set of streams. This | ||||||
|  | /// is mostly split out to make ownership happy. | ||||||
|  | /// | ||||||
|  | /// TODO: better name | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct Inner<P, B> { | ||||||
|  |     actions: Actions<P, B>, | ||||||
|  |     store: Store<B>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Debug)] | ||||||
|  | struct Actions<P, B> { | ||||||
|  |     /// Manages state transitions initiated by receiving frames | ||||||
|  |     recv: Recv<P, B>, | ||||||
|  |  | ||||||
|  |     /// Manages state transitions initiated by sending frames | ||||||
|  |     send: Send<P, B>, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<P, B> Streams<P, B> | ||||||
|  |     where P: Peer, | ||||||
|  |           B: Buf, | ||||||
|  | { | ||||||
|  |     pub fn new(config: Config) -> Self { | ||||||
|  |         Streams { | ||||||
|  |             inner: Arc::new(Mutex::new(Inner { | ||||||
|  |                 actions: Actions { | ||||||
|  |                     recv: Recv::new(&config), | ||||||
|  |                     send: Send::new(&config), | ||||||
|  |                 }, | ||||||
|  |                 store: Store::new(), | ||||||
|  |             })), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// Process inbound headers | ||||||
|  |     pub fn recv_headers(&mut self, frame: frame::Headers) | ||||||
|  |         -> Result<Option<frame::Headers>, ConnectionError> | ||||||
|  |     { | ||||||
|  |         let id = frame.stream_id(); | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         let key = match me.store.find_entry(id) { | ||||||
|  |             Entry::Occupied(e) => e.key(), | ||||||
|  |             Entry::Vacant(e) => { | ||||||
|  |                 // Trailers cannot open a stream. Trailers are header frames | ||||||
|  |                 // that do not contain pseudo headers. Requests MUST contain a | ||||||
|  |                 // method and responses MUST contain a status. If they do not,t | ||||||
|  |                 // hey are considered to be malformed. | ||||||
|  |                 if frame.is_trailers() { | ||||||
|  |                     return Err(ProtocolError.into()); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 match try!(me.actions.recv.open(id)) { | ||||||
|  |                     Some(stream) => e.insert(stream), | ||||||
|  |                     None => return Ok(None), | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         let stream = me.store.resolve(key); | ||||||
|  |  | ||||||
|  |         me.actions.transition(stream, |actions, stream| { | ||||||
|  |             if frame.is_trailers() { | ||||||
|  |                 unimplemented!(); | ||||||
|  |                 /* | ||||||
|  |                 if !frame.is_end_stream() { | ||||||
|  |                     // TODO: What error should this return? | ||||||
|  |                     unimplemented!(); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 try!(me.actions.recv.recv_eos(stream)); | ||||||
|  |                 */ | ||||||
|  |             } else { | ||||||
|  |                 actions.recv.recv_headers(frame, stream) | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_data(&mut self, frame: frame::Data) | ||||||
|  |         -> Result<(), ConnectionError> | ||||||
|  |     { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         let id = frame.stream_id(); | ||||||
|  |  | ||||||
|  |         let stream = match me.store.find_mut(&id) { | ||||||
|  |             Some(stream) => stream, | ||||||
|  |             None => return Err(ProtocolError.into()), | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         me.actions.transition(stream, |actions, stream| { | ||||||
|  |             actions.recv.recv_data(frame, stream) | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_reset(&mut self, frame: frame::Reset) | ||||||
|  |         -> Result<(), ConnectionError> | ||||||
|  |     { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         let id = frame.stream_id(); | ||||||
|  |  | ||||||
|  |         let mut stream = match me.store.find_mut(&id) { | ||||||
|  |             Some(stream) => stream, | ||||||
|  |             // TODO: should this be an error? | ||||||
|  |             None => return Ok(()), | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         me.actions.transition(stream, |actions, stream| { | ||||||
|  |             actions.recv.recv_reset(frame, stream)?; | ||||||
|  |             assert!(stream.state.is_closed()); | ||||||
|  |             Ok(()) | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_err(&mut self, err: &ConnectionError) { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         let actions = &mut me.actions; | ||||||
|  |         me.store.for_each(|stream| actions.recv.recv_err(err, stream)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_window_update(&mut self, frame: frame::WindowUpdate) | ||||||
|  |         -> Result<(), ConnectionError> { | ||||||
|  |         let id = frame.stream_id(); | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         if id.is_zero() { | ||||||
|  |             try!(me.actions.send.recv_connection_window_update(frame)); | ||||||
|  |         } else { | ||||||
|  |             // The remote may send window updates for streams that the local now | ||||||
|  |             // considers closed. It's ok... | ||||||
|  |             if let Some(mut stream) = me.store.find_mut(&id) { | ||||||
|  |                 try!(me.actions.send.recv_stream_window_update(frame, &mut stream)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn recv_push_promise(&mut self, frame: frame::PushPromise) | ||||||
|  |         -> Result<(), ConnectionError> | ||||||
|  |     { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         let id = frame.stream_id(); | ||||||
|  |  | ||||||
|  |         let mut stream = match me.store.find_mut(&id) { | ||||||
|  |             Some(stream) => stream, | ||||||
|  |             None => return Err(ProtocolError.into()), | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         me.actions.recv.recv_push_promise(frame, &mut stream) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn send_headers(&mut self, headers: frame::Headers) | ||||||
|  |         -> Result<(), ConnectionError> | ||||||
|  |     { | ||||||
|  |         unimplemented!(); | ||||||
|  |         /* | ||||||
|  |         let id = frame.stream_id(); | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         // let (id, state) = me.actions.send.open()); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         let state = match me.store.entry(id) { | ||||||
|  |             Entry::Occupied(e) => e.into_mut(), | ||||||
|  |             Entry::Vacant(e) => { | ||||||
|  |                 let (id, state) = try!(me.actions.send.open()); | ||||||
|  |                 e.insert(state) | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         if frame.is_trailers() { | ||||||
|  |             try!(me.actions.send.send_eos(state)); | ||||||
|  |         } else { | ||||||
|  |             try!(me.actions.send.send_headers(state, frame.is_end_stream())); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if state.is_closed() { | ||||||
|  |             me.actions.dec_num_streams(id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Ok(()) | ||||||
|  |         */ | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn poll_window_update(&mut self) | ||||||
|  |         -> Poll<WindowUpdate, ConnectionError> | ||||||
|  |     { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |         me.actions.send.poll_window_update(&mut me.store) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn expand_window(&mut self, id: StreamId, sz: WindowSize) | ||||||
|  |         -> Result<(), ConnectionError> | ||||||
|  |     { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         if id.is_zero() { | ||||||
|  |             try!(me.actions.recv.expand_connection_window(sz)); | ||||||
|  |         } else { | ||||||
|  |             if let Some(mut stream) = me.store.find_mut(&id) { | ||||||
|  |                 try!(me.actions.recv.expand_stream_window(id, sz, &mut stream)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn send_pending_refusal<T>(&mut self, dst: &mut Codec<T, B>) | ||||||
|  |         -> Poll<(), ConnectionError> | ||||||
|  |         where T: AsyncWrite, | ||||||
|  |     { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |         me.actions.recv.send_pending_refusal(dst) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn poll_complete<T>(&mut self, dst: &mut Codec<T, B>) | ||||||
|  |         -> Poll<(), ConnectionError> | ||||||
|  |         where T: AsyncWrite, | ||||||
|  |     { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         // TODO: sending window updates should be part of Prioritize | ||||||
|  |         /* | ||||||
|  |         try_ready!(me.actions.recv.send_connection_window_update(dst)); | ||||||
|  |         try_ready!(me.actions.recv.send_stream_window_update(&mut me.store, dst)); | ||||||
|  |         */ | ||||||
|  |  | ||||||
|  |         me.actions.send.poll_complete(&mut me.store, dst) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<B> Streams<client::Peer, B> | ||||||
|  |     where B: Buf, | ||||||
|  | { | ||||||
|  |     pub fn send_request(&mut self, request: Request<()>, end_of_stream: bool) | ||||||
|  |         -> Result<StreamRef<client::Peer, B>, ConnectionError> | ||||||
|  |     { | ||||||
|  |         // TODO: There is a hazard with assigning a stream ID before the | ||||||
|  |         // prioritize layer. If prioritization reorders new streams, this | ||||||
|  |         // implicitly closes the earlier stream IDs. | ||||||
|  |         // | ||||||
|  |         // See: carllerche/h2#11 | ||||||
|  |         let key = { | ||||||
|  |             let mut me = self.inner.lock().unwrap(); | ||||||
|  |             let me = &mut *me; | ||||||
|  |  | ||||||
|  |             // Initialize a new stream. This fails if the connection is at capacity. | ||||||
|  |             let mut stream = me.actions.send.open()?; | ||||||
|  |  | ||||||
|  |             // Convert the message | ||||||
|  |             let headers = client::Peer::convert_send_message( | ||||||
|  |                 stream.id, request, end_of_stream); | ||||||
|  |  | ||||||
|  |             let mut stream = me.store.insert(stream.id, stream); | ||||||
|  |  | ||||||
|  |             me.actions.send.send_headers(headers, &mut stream)?; | ||||||
|  |  | ||||||
|  |             // Given that the stream has been initialized, it should not be in the | ||||||
|  |             // closed state. | ||||||
|  |             debug_assert!(!stream.state.is_closed()); | ||||||
|  |  | ||||||
|  |             stream.key() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         Ok(StreamRef { | ||||||
|  |             inner: self.inner.clone(), | ||||||
|  |             key: key, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl StreamRef ===== | ||||||
|  |  | ||||||
|  | impl<P, B> StreamRef<P, B> | ||||||
|  |     where P: Peer, | ||||||
|  |           B: Buf, | ||||||
|  | { | ||||||
|  |     pub fn send_data(&mut self, data: B, end_of_stream: bool) | ||||||
|  |         -> Result<(), ConnectionError> | ||||||
|  |     { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         let stream = me.store.resolve(self.key); | ||||||
|  |  | ||||||
|  |         // Create the data frame | ||||||
|  |         let frame = frame::Data::from_buf(stream.id, data, end_of_stream); | ||||||
|  |  | ||||||
|  |         me.actions.transition(stream, |actions, stream| { | ||||||
|  |             // Send the data frame | ||||||
|  |             actions.send.send_data(frame, stream) | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pub fn poll_data(&mut self) -> Poll<Option<Chunk<P, B>>, ConnectionError> { | ||||||
|  |         let recv = { | ||||||
|  |             let mut me = self.inner.lock().unwrap(); | ||||||
|  |             let me = &mut *me; | ||||||
|  |  | ||||||
|  |             let mut stream = me.store.resolve(self.key); | ||||||
|  |  | ||||||
|  |             try_ready!(me.actions.recv.poll_chunk(&mut stream)) | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         // Convert to a chunk | ||||||
|  |         let chunk = recv.map(|recv| { | ||||||
|  |             Chunk { | ||||||
|  |                 inner: self.inner.clone(), | ||||||
|  |                 recv: recv, | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         Ok(chunk.into()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<B> StreamRef<client::Peer, B> | ||||||
|  |     where B: Buf, | ||||||
|  | { | ||||||
|  |     pub fn poll_response(&mut self) -> Poll<Response<()>, ConnectionError> { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         let mut stream = me.store.resolve(self.key); | ||||||
|  |  | ||||||
|  |         me.actions.recv.poll_response(&mut stream) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | impl<P, B> Clone for StreamRef<P, B> { | ||||||
|  |     fn clone(&self) -> Self { | ||||||
|  |         StreamRef { | ||||||
|  |             inner: self.inner.clone(), | ||||||
|  |             key: self.key.clone(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Chunk ===== | ||||||
|  |  | ||||||
|  | impl<P, B> Chunk<P, B> | ||||||
|  |     where P: Peer, | ||||||
|  |           B: Buf, | ||||||
|  | { | ||||||
|  |     // TODO: Come up w/ a better API | ||||||
|  |     pub fn pop_bytes(&mut self) -> Option<Bytes> { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         me.actions.recv.pop_bytes(&mut self.recv) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<P, B> Drop for Chunk<P, B> | ||||||
|  |     where P: Peer, | ||||||
|  |           B: Buf, | ||||||
|  | { | ||||||
|  |     fn drop(&mut self) { | ||||||
|  |         let mut me = self.inner.lock().unwrap(); | ||||||
|  |         let me = &mut *me; | ||||||
|  |  | ||||||
|  |         while let Some(_) = me.actions.recv.pop_bytes(&mut self.recv) { | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ===== impl Actions ===== | ||||||
|  |  | ||||||
|  | impl<P, B> Actions<P, B> | ||||||
|  |     where P: Peer, | ||||||
|  |           B: Buf, | ||||||
|  | { | ||||||
|  |     fn dec_num_streams(&mut self, id: StreamId) { | ||||||
|  |         if self.is_local_init(id) { | ||||||
|  |             self.send.dec_num_streams(); | ||||||
|  |         } else { | ||||||
|  |             self.recv.dec_num_streams(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn is_local_init(&self, id: StreamId) -> bool { | ||||||
|  |         assert!(!id.is_zero()); | ||||||
|  |         P::is_server() == id.is_server_initiated() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fn transition<F, U>(&mut self, mut stream: store::Ptr<B>, f: F) -> U | ||||||
|  |         where F: FnOnce(&mut Self, &mut store::Ptr<B>) -> U, | ||||||
|  |     { | ||||||
|  |         let is_counted = stream.state.is_counted(); | ||||||
|  |  | ||||||
|  |         let ret = f(self, &mut stream); | ||||||
|  |  | ||||||
|  |         if is_counted && stream.state.is_closed() { | ||||||
|  |             self.dec_num_streams(stream.id); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         ret | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -14,78 +14,13 @@ fn handshake() { | |||||||
|         .write(SETTINGS_ACK) |         .write(SETTINGS_ACK) | ||||||
|         .build(); |         .build(); | ||||||
|  |  | ||||||
|     let h2 = client::handshake(mock) |     let h2 = Client::handshake(mock) | ||||||
|         .wait().unwrap(); |         .wait().unwrap(); | ||||||
|  |  | ||||||
|     trace!("hands have been shook"); |     trace!("hands have been shook"); | ||||||
|  |  | ||||||
|     // At this point, the connection should be closed |     // At this point, the connection should be closed | ||||||
|     assert!(Stream::wait(h2).next().is_none()); |     h2.wait().unwrap(); | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #[test] |  | ||||||
| fn send_request_with_zero_stream_id() { |  | ||||||
|     let mock = mock_io::Builder::new() |  | ||||||
|         .handshake() |  | ||||||
|         .build(); |  | ||||||
|  |  | ||||||
|     let h2 = client::handshake(mock) |  | ||||||
|         .wait().unwrap(); |  | ||||||
|  |  | ||||||
|     // Send the request |  | ||||||
|     let mut request = request::Head::default(); |  | ||||||
|     request.uri = "https://http2.akamai.com/".parse().unwrap(); |  | ||||||
|  |  | ||||||
|     let err = h2.send_request(0.into(), request, true).wait().unwrap_err(); |  | ||||||
|     assert_user_err!(err, InvalidStreamId); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[test] |  | ||||||
| fn send_request_with_server_stream_id() { |  | ||||||
|     let mock = mock_io::Builder::new() |  | ||||||
|         .handshake() |  | ||||||
|         .build(); |  | ||||||
|  |  | ||||||
|     let h2 = client::handshake(mock) |  | ||||||
|         .wait().unwrap(); |  | ||||||
|  |  | ||||||
|     // Send the request |  | ||||||
|     let mut request = request::Head::default(); |  | ||||||
|     request.uri = "https://http2.akamai.com/".parse().unwrap(); |  | ||||||
|  |  | ||||||
|     let err = h2.send_request(2.into(), request, true).wait().unwrap_err(); |  | ||||||
|     assert_user_err!(err, InvalidStreamId); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[test] |  | ||||||
| #[ignore] |  | ||||||
| fn request_without_scheme() { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[test] |  | ||||||
| #[ignore] |  | ||||||
| fn request_with_h1_version() { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[test] |  | ||||||
| fn send_invalid_client_stream_id() { |  | ||||||
|     let _ = ::env_logger::init(); |  | ||||||
|  |  | ||||||
|     for &id in &[0, 2] { |  | ||||||
|         let mock = mock_io::Builder::new() |  | ||||||
|             .handshake() |  | ||||||
|             .build(); |  | ||||||
|  |  | ||||||
|         let h2 = client::handshake(mock) |  | ||||||
|             .wait().unwrap(); |  | ||||||
|  |  | ||||||
|         // Send the request |  | ||||||
|         let mut request = request::Head::default(); |  | ||||||
|         request.uri = "https://http2.akamai.com/".parse().unwrap(); |  | ||||||
|         let err = h2.send_request(id.into(), request, true).wait().unwrap_err(); |  | ||||||
|  |  | ||||||
|         assert_user_err!(err, InvalidStreamId); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[test] | #[test] | ||||||
| @@ -104,17 +39,38 @@ fn recv_invalid_server_stream_id() { | |||||||
|         .read(&[0, 0, 1, 1, 5, 0, 0, 0, 2, 137]) |         .read(&[0, 0, 1, 1, 5, 0, 0, 0, 2, 137]) | ||||||
|         .build(); |         .build(); | ||||||
|  |  | ||||||
|     let h2 = client::handshake(mock) |     let mut h2 = Client::handshake(mock) | ||||||
|         .wait().unwrap(); |         .wait().unwrap(); | ||||||
|  |  | ||||||
|     // Send the request |     // Send the request | ||||||
|     let mut request = request::Head::default(); |     let request = Request::builder() | ||||||
|     request.uri = "https://http2.akamai.com/".parse().unwrap(); |         .uri("https://http2.akamai.com/") | ||||||
|     let h2 = h2.send_request(1.into(), request, true).wait().unwrap(); |         .body(()).unwrap(); | ||||||
|  |  | ||||||
|     // Get the response |     info!("sending request"); | ||||||
|     let (err, _) = h2.into_future().wait().unwrap_err(); |     let mut stream = h2.request(request, true).unwrap(); | ||||||
|     assert_proto_err!(err, ProtocolError); |  | ||||||
|  |     // The connection errors | ||||||
|  |     assert_proto_err!(h2.wait().unwrap_err(), ProtocolError); | ||||||
|  |  | ||||||
|  |     // The stream errors | ||||||
|  |     assert_proto_err!(stream.wait().unwrap_err(), ProtocolError); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[test] | ||||||
|  | #[ignore] | ||||||
|  | fn request_without_scheme() { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[test] | ||||||
|  | #[ignore] | ||||||
|  | fn request_with_h1_version() { | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #[test] | ||||||
|  | #[ignore] | ||||||
|  | fn sending_request_on_closed_soket() { | ||||||
| } | } | ||||||
|  |  | ||||||
| const SETTINGS: &'static [u8] = &[0, 0, 0, 4, 0, 0, 0, 0, 0]; | const SETTINGS: &'static [u8] = &[0, 0, 0, 4, 0, 0, 0, 0, 0]; | ||||||
|   | |||||||
| @@ -31,10 +31,10 @@ fn recv_single_ping() { | |||||||
|         */ |         */ | ||||||
|         .build(); |         .build(); | ||||||
|  |  | ||||||
|  |     /* | ||||||
|     let h2 = client::handshake(mock) |     let h2 = client::handshake(mock) | ||||||
|         .wait().unwrap(); |         .wait().unwrap(); | ||||||
|  |  | ||||||
|     /* |  | ||||||
|     // Send the request |     // Send the request | ||||||
|     let mut request = request::Head::default(); |     let mut request = request::Head::default(); | ||||||
|     request.method = method::POST; |     request.method = method::POST; | ||||||
|   | |||||||
| @@ -29,6 +29,7 @@ fn single_stream_send_large_body() { | |||||||
|         ]) |         ]) | ||||||
|         .build(); |         .build(); | ||||||
|  |  | ||||||
|  |     /* | ||||||
|     let h2 = client::handshake(mock) |     let h2 = client::handshake(mock) | ||||||
|         .wait().unwrap(); |         .wait().unwrap(); | ||||||
|  |  | ||||||
| @@ -65,4 +66,5 @@ fn single_stream_send_large_body() { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     assert!(Stream::wait(h2).next().is_none());; |     assert!(Stream::wait(h2).next().is_none());; | ||||||
|  |     */ | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ extern crate futures; | |||||||
| extern crate mock_io; | extern crate mock_io; | ||||||
| extern crate env_logger; | extern crate env_logger; | ||||||
|  |  | ||||||
| use h2::server; | // use h2::server; | ||||||
|  |  | ||||||
| use futures::*; | use futures::*; | ||||||
|  |  | ||||||
| @@ -13,6 +13,7 @@ const SETTINGS_ACK: &'static [u8] = &[0, 0, 0, 4, 1, 0, 0, 0, 0]; | |||||||
|  |  | ||||||
| #[test] | #[test] | ||||||
| fn read_preface_in_multiple_frames() { | fn read_preface_in_multiple_frames() { | ||||||
|  |     /* | ||||||
|     let _ = ::env_logger::init().unwrap(); |     let _ = ::env_logger::init().unwrap(); | ||||||
|  |  | ||||||
|     let mock = mock_io::Builder::new() |     let mock = mock_io::Builder::new() | ||||||
| @@ -28,4 +29,5 @@ fn read_preface_in_multiple_frames() { | |||||||
|         .wait().unwrap(); |         .wait().unwrap(); | ||||||
|  |  | ||||||
|     assert!(Stream::wait(h2).next().is_none()); |     assert!(Stream::wait(h2).next().is_none()); | ||||||
|  |     */ | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,8 +5,6 @@ extern crate log; | |||||||
| pub mod support; | pub mod support; | ||||||
| use support::*; | use support::*; | ||||||
|  |  | ||||||
| use h2::Frame; |  | ||||||
|  |  | ||||||
| #[test] | #[test] | ||||||
| fn send_recv_headers_only() { | fn send_recv_headers_only() { | ||||||
|     let _ = env_logger::init(); |     let _ = env_logger::init(); | ||||||
| @@ -23,31 +21,21 @@ fn send_recv_headers_only() { | |||||||
|         .read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89]) |         .read(&[0, 0, 1, 1, 5, 0, 0, 0, 1, 0x89]) | ||||||
|         .build(); |         .build(); | ||||||
|  |  | ||||||
|     let h2 = client::handshake(mock) |     let mut h2 = Client::handshake(mock) | ||||||
|         .wait().unwrap(); |         .wait().unwrap(); | ||||||
|  |  | ||||||
|     // Send the request |     // Send the request | ||||||
|     let mut request = request::Head::default(); |     let request = Request::builder() | ||||||
|     request.uri = "https://http2.akamai.com/".parse().unwrap(); |         .uri("https://http2.akamai.com/") | ||||||
|  |         .body(()).unwrap(); | ||||||
|  |  | ||||||
|     info!("sending request"); |     info!("sending request"); | ||||||
|     let h2 = h2.send_request(1.into(), request, true).wait().unwrap(); |     let mut stream = h2.request(request, true).unwrap(); | ||||||
|  |  | ||||||
|     // Get the response |     let resp = h2.run(poll_fn(|| stream.poll_response())).unwrap(); | ||||||
|  |     assert_eq!(resp.status(), status::NO_CONTENT); | ||||||
|  |  | ||||||
|     info!("getting response"); |     h2.wait().unwrap(); | ||||||
|     let (resp, h2) = h2.into_future().wait().unwrap(); |  | ||||||
|  |  | ||||||
|     match resp.unwrap() { |  | ||||||
|         Frame::Headers { headers, .. } => { |  | ||||||
|             assert_eq!(headers.status, status::NO_CONTENT); |  | ||||||
|         } |  | ||||||
|         _ => panic!("unexpected frame"), |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // No more frames |  | ||||||
|     info!("ensure no more responses"); |  | ||||||
|     assert!(Stream::wait(h2).next().is_none());; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #[test] | #[test] | ||||||
| @@ -75,46 +63,44 @@ fn send_recv_data() { | |||||||
|         ]) |         ]) | ||||||
|         .build(); |         .build(); | ||||||
|  |  | ||||||
|     let h2 = client::handshake(mock).wait().expect("handshake"); |     let mut h2 = Client::handshake2(mock) | ||||||
|  |         .wait().unwrap(); | ||||||
|  |  | ||||||
|     // Send the request |     let request = Request::builder() | ||||||
|     let mut request = request::Head::default(); |         .method(method::POST) | ||||||
|     request.method = method::POST; |         .uri("https://http2.akamai.com/") | ||||||
|     request.uri = "https://http2.akamai.com/".parse().unwrap(); |         .body(()).unwrap(); | ||||||
|     let h2 = h2.send_request(1.into(), request, false).wait().expect("send request"); |  | ||||||
|  |  | ||||||
|     let b = "hello"; |     info!("sending request"); | ||||||
|  |     let mut stream = h2.request(request, false).unwrap(); | ||||||
|  |  | ||||||
|     // Send the data |     // Send the data | ||||||
|     let h2 = h2.send_data(1.into(), b.into(), true).wait().expect("send data"); |     stream.send_data("hello", true).unwrap(); | ||||||
|  |  | ||||||
|     // Get the response headers |     // Get the response | ||||||
|     let (resp, h2) = h2.into_future().wait().expect("into future"); |     let resp = h2.run(poll_fn(|| stream.poll_response())).unwrap(); | ||||||
|  |     assert_eq!(resp.status(), status::OK); | ||||||
|  |  | ||||||
|     match resp.expect("response headers") { |     // Take the body | ||||||
|         Frame::Headers { headers, .. } => { |     let (_, body) = resp.into_parts(); | ||||||
|             assert_eq!(headers.status, status::OK); |  | ||||||
|         } |  | ||||||
|         _ => panic!("unexpected frame"), |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Get the response body |     // Wait for all the data frames to be received | ||||||
|     let (data, h2) = h2.into_future().wait().expect("into future"); |     let mut chunks = h2.run(body.collect()).unwrap(); | ||||||
|  |  | ||||||
|     match data.expect("response data") { |     // Only one chunk since two frames are coalesced. | ||||||
|         Frame::Data { id, data, end_of_stream, .. } => { |     assert_eq!(1, chunks.len()); | ||||||
|             assert_eq!(id, 1.into()); |  | ||||||
|  |     let data = chunks[0].pop_bytes().unwrap(); | ||||||
|     assert_eq!(data, &b"world"[..]); |     assert_eq!(data, &b"world"[..]); | ||||||
|             assert!(end_of_stream); |  | ||||||
|         } |  | ||||||
|         _ => panic!("unexpected frame"), |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     assert!(Stream::wait(h2).next().is_none());; |     assert!(chunks[0].pop_bytes().is_none()); | ||||||
|  |  | ||||||
|  |     // The H2 connection is closed | ||||||
|  |     h2.wait().unwrap(); | ||||||
| } | } | ||||||
|  |  | ||||||
| #[test] | #[test] | ||||||
| fn send_headers_recv_data() { | fn send_headers_recv_data_single_frame() { | ||||||
|     let _ = env_logger::init(); |     let _ = env_logger::init(); | ||||||
|  |  | ||||||
|     let mock = mock_io::Builder::new() |     let mock = mock_io::Builder::new() | ||||||
| @@ -132,80 +118,42 @@ fn send_headers_recv_data() { | |||||||
|         ]) |         ]) | ||||||
|         .build(); |         .build(); | ||||||
|  |  | ||||||
|     let h2 = client::handshake(mock) |     let mut h2 = Client::handshake(mock) | ||||||
|         .wait().unwrap(); |         .wait().unwrap(); | ||||||
|  |  | ||||||
|     // Send the request |     // Send the request | ||||||
|     let mut request = request::Head::default(); |     let request = Request::builder() | ||||||
|     request.uri = "https://http2.akamai.com/".parse().unwrap(); |         .uri("https://http2.akamai.com/") | ||||||
|     let h2 = h2.send_request(1.into(), request, true).wait().unwrap(); |         .body(()).unwrap(); | ||||||
|  |  | ||||||
|     // Get the response headers |     info!("sending request"); | ||||||
|     let (resp, h2) = h2.into_future().wait().unwrap(); |     let mut stream = h2.request(request, true).unwrap(); | ||||||
|  |  | ||||||
|     match resp.unwrap() { |     let resp = h2.run(poll_fn(|| stream.poll_response())).unwrap(); | ||||||
|         Frame::Headers { headers, .. } => { |     assert_eq!(resp.status(), status::OK); | ||||||
|             assert_eq!(headers.status, status::OK); |  | ||||||
|         } |  | ||||||
|         _ => panic!("unexpected frame"), |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Get the response body |     // Take the body | ||||||
|     let (data, h2) = h2.into_future().wait().unwrap(); |     let (_, body) = resp.into_parts(); | ||||||
|  |  | ||||||
|     match data.unwrap() { |     // Wait for all the data frames to be received | ||||||
|         Frame::Data { id, data, end_of_stream, .. } => { |     let mut chunks = h2.run(body.collect()).unwrap(); | ||||||
|             assert_eq!(id, 1.into()); |  | ||||||
|  |     // Only one chunk since two frames are coalesced. | ||||||
|  |     assert_eq!(1, chunks.len()); | ||||||
|  |  | ||||||
|  |     let data = chunks[0].pop_bytes().unwrap(); | ||||||
|     assert_eq!(data, &b"hello"[..]); |     assert_eq!(data, &b"hello"[..]); | ||||||
|             assert!(!end_of_stream); |  | ||||||
|         } |  | ||||||
|         _ => panic!("unexpected frame"), |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Get the response body |     let data = chunks[0].pop_bytes().unwrap(); | ||||||
|     let (data, h2) = h2.into_future().wait().unwrap(); |  | ||||||
|  |  | ||||||
|     match data.unwrap() { |  | ||||||
|         Frame::Data { id, data, end_of_stream, .. } => { |  | ||||||
|             assert_eq!(id, 1.into()); |  | ||||||
|     assert_eq!(data, &b"world"[..]); |     assert_eq!(data, &b"world"[..]); | ||||||
|             assert!(end_of_stream); |  | ||||||
|         } |     assert!(chunks[0].pop_bytes().is_none()); | ||||||
|         _ => panic!("unexpected frame"), |  | ||||||
|     } |     // The H2 connection is closed | ||||||
|  |     h2.wait().unwrap(); | ||||||
|     assert!(Stream::wait(h2).next().is_none());; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[test] |  | ||||||
| fn send_headers_twice_with_same_stream_id() { |  | ||||||
|     let _ = env_logger::init(); |  | ||||||
|  |  | ||||||
|     let mock = mock_io::Builder::new() |  | ||||||
|         .handshake() |  | ||||||
|         // Write GET / |  | ||||||
|         .write(&[ |  | ||||||
|             0, 0, 0x10, 1, 5, 0, 0, 0, 1, 0x82, 0x87, 0x41, 0x8B, 0x9D, 0x29, |  | ||||||
|                 0xAC, 0x4B, 0x8F, 0xA8, 0xE9, 0x19, 0x97, 0x21, 0xE9, 0x84, |  | ||||||
|         ]) |  | ||||||
|         .build(); |  | ||||||
|  |  | ||||||
|     let h2 = client::handshake(mock) |  | ||||||
|         .wait().unwrap(); |  | ||||||
|  |  | ||||||
|     // Send the request |  | ||||||
|     let mut request = request::Head::default(); |  | ||||||
|     request.uri = "https://http2.akamai.com/".parse().unwrap(); |  | ||||||
|     let h2 = h2.send_request(1.into(), request, true).wait().unwrap(); |  | ||||||
|  |  | ||||||
|     // Send another request with the same stream ID |  | ||||||
|     let mut request = request::Head::default(); |  | ||||||
|     request.uri = "https://http2.akamai.com/".parse().unwrap(); |  | ||||||
|     let err = h2.send_request(1.into(), request, true).wait().unwrap_err(); |  | ||||||
|  |  | ||||||
|     assert_user_err!(err, UnexpectedFrameType); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
| #[test] | #[test] | ||||||
| fn send_data_after_headers_eos() { | fn send_data_after_headers_eos() { | ||||||
|     let _ = env_logger::init(); |     let _ = env_logger::init(); | ||||||
| @@ -238,22 +186,8 @@ fn send_data_after_headers_eos() { | |||||||
|     assert_user_err!(err, UnexpectedFrameType); |     assert_user_err!(err, UnexpectedFrameType); | ||||||
| } | } | ||||||
|  |  | ||||||
| #[test] |  | ||||||
| fn send_data_without_headers() { |  | ||||||
|     let mock = mock_io::Builder::new() |  | ||||||
|         .handshake() |  | ||||||
|         .build(); |  | ||||||
|  |  | ||||||
|     let h2 = client::handshake(mock) |  | ||||||
|         .wait().unwrap(); |  | ||||||
|  |  | ||||||
|     let b = Bytes::from_static(b"hello world"); |  | ||||||
|     let err = h2.send_data(1.into(), b, true).wait().unwrap_err(); |  | ||||||
|  |  | ||||||
|     assert_user_err!(err, UnexpectedFrameType); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[test] | #[test] | ||||||
| #[ignore] | #[ignore] | ||||||
| fn exceed_max_streams() { | fn exceed_max_streams() { | ||||||
| } | } | ||||||
|  | */ | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| pub extern crate bytes; | pub extern crate bytes; | ||||||
| pub extern crate h2; | pub extern crate h2; | ||||||
| pub extern crate http; | pub extern crate http; | ||||||
|  | pub extern crate tokio_io; | ||||||
| pub extern crate futures; | pub extern crate futures; | ||||||
| pub extern crate mock_io; | pub extern crate mock_io; | ||||||
| pub extern crate env_logger; | pub extern crate env_logger; | ||||||
| @@ -12,26 +13,30 @@ pub use self::futures::{ | |||||||
|     Sink, |     Sink, | ||||||
|     Stream, |     Stream, | ||||||
| }; | }; | ||||||
|  | pub use self::futures::future::poll_fn; | ||||||
|  |  | ||||||
| pub use self::http::{ | pub use self::http::{ | ||||||
|     request, |     request, | ||||||
|     response, |     response, | ||||||
|     method, |     method, | ||||||
|     status, |     status, | ||||||
|  |     Request, | ||||||
|  |     Response, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| pub use self::h2::{ | pub use self::h2::client::{self, Client}; | ||||||
|     client, | // pub use self::h2::server; | ||||||
|     server, |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| pub use self::bytes::{ | pub use self::bytes::{ | ||||||
|     Buf, |     Buf, | ||||||
|     BufMut, |     BufMut, | ||||||
|     Bytes, |     Bytes, | ||||||
|     BytesMut, |     BytesMut, | ||||||
|  |     IntoBuf, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | use tokio_io::{AsyncRead, AsyncWrite}; | ||||||
|  |  | ||||||
| pub trait MockH2 { | pub trait MockH2 { | ||||||
|     fn handshake(&mut self) -> &mut Self; |     fn handshake(&mut self) -> &mut Self; | ||||||
| } | } | ||||||
| @@ -46,6 +51,33 @@ impl MockH2 for mock_io::Builder { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | pub trait ClientExt { | ||||||
|  |     fn run<F: Future>(&mut self, f: F) -> Result<F::Item, F::Error>; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | impl<T, B> ClientExt for Client<T, B> | ||||||
|  |     where T: AsyncRead + AsyncWrite + 'static, | ||||||
|  |           B: IntoBuf + 'static, | ||||||
|  | { | ||||||
|  |     fn run<F: Future>(&mut self, f: F) -> Result<F::Item, F::Error> { | ||||||
|  |         use futures::future::{self, Future}; | ||||||
|  |         use futures::future::Either::*; | ||||||
|  |  | ||||||
|  |         let res = future::poll_fn(|| self.poll()) | ||||||
|  |             .select2(f).wait(); | ||||||
|  |  | ||||||
|  |         match res { | ||||||
|  |             Ok(A((_, b))) => { | ||||||
|  |                 // Connection is done... | ||||||
|  |                 b.wait() | ||||||
|  |             } | ||||||
|  |             Ok(B((v, _))) => return Ok(v), | ||||||
|  |             Err(A((e, _))) => panic!("err: {:?}", e), | ||||||
|  |             Err(B((e, _))) => return Err(e), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| pub mod frames { | pub mod frames { | ||||||
|     //! Some useful frames |     //! Some useful frames | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user