check for StreamId overflow (#68)
This commit is contained in:
@@ -61,13 +61,14 @@ where
|
||||
pub fn new(
|
||||
codec: Codec<T, Prioritized<B::Buf>>,
|
||||
settings: &frame::Settings,
|
||||
next_stream_id: frame::StreamId
|
||||
) -> Connection<T, P, B> {
|
||||
// TODO: Actually configure
|
||||
let streams = Streams::new(streams::Config {
|
||||
local_init_window_sz: settings
|
||||
.initial_window_size()
|
||||
.unwrap_or(DEFAULT_INITIAL_WINDOW_SIZE),
|
||||
local_max_initiated: None,
|
||||
local_next_stream_id: next_stream_id,
|
||||
local_push_enabled: settings.is_push_enabled(),
|
||||
remote_init_window_sz: DEFAULT_INITIAL_WINDOW_SIZE,
|
||||
remote_max_initiated: None,
|
||||
|
||||
@@ -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