Enforce monotonic stream IDs for push promises (#275)

Previously, monotonic stream IDs (spec 5.1.1) for push promises were not
enforced. This was due to push promises going through an entirely
separate code path than normally initiated streams.

This patch unifies the code path for initializing streams via both
HEADERS and PUSH_PROMISE. This is done by first calling `recv.open` in
both cases.

Closes #272
This commit is contained in:
Carl Lerche
2018-05-14 10:20:57 -07:00
committed by GitHub
parent 173f9a67e7
commit bb454e017c
7 changed files with 227 additions and 108 deletions

View File

@@ -1,13 +1,14 @@
use codec::RecvError;
use error::Reason;
use frame::{Headers, StreamId};
use proto::Open;
use http::{Request, Response};
use std::fmt;
/// Either a Client or a Server
pub trait Peer {
pub(crate) trait Peer {
/// Message type polled from the transport
type Poll: fmt::Debug;
@@ -27,7 +28,7 @@ pub trait Peer {
///
/// This is used internally to avoid incurring a generic on all internal types.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Dyn {
pub(crate) enum Dyn {
Client,
Server,
}
@@ -61,20 +62,23 @@ impl Dyn {
}
/// Returns true if the remote peer can initiate a stream with the given ID.
pub fn ensure_can_open(&self, id: StreamId) -> Result<(), RecvError> {
if !self.is_server() {
trace!("Cannot open stream {:?} - not server, PROTOCOL_ERROR", id);
// Remote is a server and cannot open streams. PushPromise is
// registered by reserving, so does not go through this path.
return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
}
pub fn ensure_can_open(&self, id: StreamId, mode: Open) -> Result<(), RecvError> {
if self.is_server() {
// Ensure that the ID is a valid client initiated ID
if mode.is_push_promise() || !id.is_client_initiated() {
trace!("Cannot open stream {:?} - not client initiated, PROTOCOL_ERROR", id);
return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
}
// Ensure that the ID is a valid server initiated ID
if !id.is_client_initiated() {
trace!("Cannot open stream {:?} - not client initiated, PROTOCOL_ERROR", id);
return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
}
Ok(())
} else {
// Ensure that the ID is a valid server initiated ID
if !mode.is_push_promise() || !id.is_server_initiated() {
trace!("Cannot open stream {:?} - not server initiated, PROTOCOL_ERROR", id);
return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
}
Ok(())
Ok(())
}
}
}