check for StreamId overflow (#68)
This commit is contained in:
		| @@ -23,7 +23,7 @@ use self::store::{Entry, Store}; | ||||
| use self::stream::Stream; | ||||
|  | ||||
| use error::Reason::*; | ||||
| use frame::StreamId; | ||||
| use frame::{StreamId, StreamIdOverflow}; | ||||
| use proto::*; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| @@ -37,6 +37,9 @@ pub struct Config { | ||||
|     /// Maximum number of locally initiated streams | ||||
|     pub local_max_initiated: Option<usize>, | ||||
|  | ||||
|     /// The stream ID to start the next local stream with | ||||
|     pub local_next_stream_id: StreamId, | ||||
|  | ||||
|     /// If the local peer is willing to receive push promises | ||||
|     pub local_push_enabled: bool, | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,7 @@ where | ||||
|     flow: FlowControl, | ||||
|  | ||||
|     /// The lowest stream ID that is still idle | ||||
|     next_stream_id: StreamId, | ||||
|     next_stream_id: Result<StreamId, StreamIdOverflow>, | ||||
|  | ||||
|     /// The stream ID of the last processed stream | ||||
|     last_processed_id: StreamId, | ||||
| @@ -76,7 +76,7 @@ where | ||||
|         Recv { | ||||
|             init_window_sz: config.local_init_window_sz, | ||||
|             flow: flow, | ||||
|             next_stream_id: next_stream_id.into(), | ||||
|             next_stream_id: Ok(next_stream_id.into()), | ||||
|             pending_window_updates: store::Queue::new(), | ||||
|             last_processed_id: StreamId::zero(), | ||||
|             pending_accept: store::Queue::new(), | ||||
| @@ -109,12 +109,12 @@ where | ||||
|  | ||||
|         self.ensure_can_open(id)?; | ||||
|  | ||||
|         if id < self.next_stream_id { | ||||
|         let next_id = self.next_stream_id()?; | ||||
|         if id < next_id { | ||||
|             return Err(RecvError::Connection(ProtocolError)); | ||||
|         } | ||||
|  | ||||
|         self.next_stream_id = id; | ||||
|         self.next_stream_id.increment(); | ||||
|         self.next_stream_id = id.next_id(); | ||||
|  | ||||
|         if !counts.can_inc_num_recv_streams() { | ||||
|             self.refused = Some(id); | ||||
| @@ -137,6 +137,13 @@ where | ||||
|         let is_initial = stream.state.recv_open(frame.is_end_stream())?; | ||||
|  | ||||
|         if is_initial { | ||||
|             let next_id = self.next_stream_id()?; | ||||
|             if frame.stream_id() >= next_id { | ||||
|                 self.next_stream_id = frame.stream_id().next_id(); | ||||
|             } else { | ||||
|                 return Err(RecvError::Connection(ProtocolError)); | ||||
|             } | ||||
|  | ||||
|             // TODO: be smarter about this logic | ||||
|             if frame.stream_id() > self.last_processed_id { | ||||
|                 self.last_processed_id = frame.stream_id(); | ||||
| @@ -383,9 +390,12 @@ where | ||||
|  | ||||
|     /// Ensures that `id` is not in the `Idle` state. | ||||
|     pub fn ensure_not_idle(&self, id: StreamId) -> Result<(), Reason> { | ||||
|         if id >= self.next_stream_id { | ||||
|             return Err(ProtocolError); | ||||
|         if let Ok(next) = self.next_stream_id { | ||||
|             if id >= next { | ||||
|                 return Err(ProtocolError); | ||||
|             } | ||||
|         } | ||||
|         // if next_stream_id is overflowed, that's ok. | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
| @@ -428,6 +438,14 @@ where | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn next_stream_id(&self) -> Result<StreamId, RecvError> { | ||||
|         if let Ok(id) = self.next_stream_id { | ||||
|             Ok(id) | ||||
|         } else { | ||||
|             Err(RecvError::Connection(ProtocolError)) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the remote peer can reserve a stream with the given ID. | ||||
|     fn ensure_can_reserve(&self, promised_id: StreamId) -> Result<(), RecvError> { | ||||
|         // TODO: Are there other rules? | ||||
|   | ||||
| @@ -15,7 +15,7 @@ where | ||||
|     P: Peer, | ||||
| { | ||||
|     /// Stream identifier to use for next initialized stream. | ||||
|     next_stream_id: StreamId, | ||||
|     next_stream_id: Result<StreamId, StreamIdOverflow>, | ||||
|  | ||||
|     /// Initial window size of locally initiated streams | ||||
|     init_window_sz: WindowSize, | ||||
| @@ -31,11 +31,9 @@ where | ||||
| { | ||||
|     /// Create a new `Send` | ||||
|     pub fn new(config: &Config) -> Self { | ||||
|         let next_stream_id = if P::is_server() { 2 } else { 1 }; | ||||
|  | ||||
|         Send { | ||||
|             next_stream_id: next_stream_id.into(), | ||||
|             init_window_sz: config.local_init_window_sz, | ||||
|             next_stream_id: Ok(config.local_next_stream_id), | ||||
|             prioritize: Prioritize::new(config), | ||||
|         } | ||||
|     } | ||||
| @@ -49,19 +47,17 @@ where | ||||
|     /// | ||||
|     /// Returns the stream state if successful. `None` if refused | ||||
|     pub fn open(&mut self, counts: &mut Counts<P>) -> Result<StreamId, UserError> { | ||||
|         self.ensure_can_open()?; | ||||
|  | ||||
|         if !counts.can_inc_num_send_streams() { | ||||
|             return Err(Rejected.into()); | ||||
|         } | ||||
|  | ||||
|         let ret = self.next_stream_id; | ||||
|         self.next_stream_id.increment(); | ||||
|         let stream_id = self.try_open()?; | ||||
|  | ||||
|         // Increment the number of locally initiated streams | ||||
|         counts.inc_num_send_streams(); | ||||
|         self.next_stream_id = stream_id.next_id(); | ||||
|  | ||||
|         Ok(ret) | ||||
|         Ok(stream_id) | ||||
|     } | ||||
|  | ||||
|     pub fn send_headers( | ||||
| @@ -293,22 +289,23 @@ where | ||||
|     } | ||||
|  | ||||
|     pub fn ensure_not_idle(&self, id: StreamId) -> Result<(), Reason> { | ||||
|         if id >= self.next_stream_id { | ||||
|             return Err(ProtocolError); | ||||
|         if let Ok(next) = self.next_stream_id { | ||||
|             if id >= next { | ||||
|                 return Err(ProtocolError); | ||||
|             } | ||||
|         } | ||||
|         // if next_stream_id is overflowed, that's ok. | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the local actor can initiate a stream with the given ID. | ||||
|     fn ensure_can_open(&self) -> Result<(), UserError> { | ||||
|     /// Returns a new StreamId if the local actor can initiate a new stream. | ||||
|     fn try_open(&self) -> Result<StreamId, UserError> { | ||||
|         if P::is_server() { | ||||
|             // Servers cannot open streams. PushPromise must first be reserved. | ||||
|             return Err(UnexpectedFrameType); | ||||
|         } | ||||
|  | ||||
|         // TODO: Handle StreamId overflow | ||||
|  | ||||
|         Ok(()) | ||||
|         self.next_stream_id.map_err(|_| OverflowedStreamId) | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user