Fix receiving a GOAWAY frame from updating the max recv ID

Receiving a GOAWAY should update the max *send* ID, it shouldn't affect
the max recv.
This commit is contained in:
Sean McArthur
2020-03-24 17:36:13 -07:00
parent 5041a4d428
commit d6dc63276f
4 changed files with 116 additions and 17 deletions

View File

@@ -18,6 +18,15 @@ pub(super) struct Send {
/// Stream identifier to use for next initialized stream.
next_stream_id: Result<StreamId, StreamIdOverflow>,
/// Any streams with a higher ID are ignored.
///
/// This starts as MAX, but is lowered when a GOAWAY is received.
///
/// > After sending a GOAWAY frame, the sender can discard frames for
/// > streams initiated by the receiver with identifiers higher than
/// > the identified last stream.
max_stream_id: StreamId,
/// Initial window size of locally initiated streams
init_window_sz: WindowSize,
@@ -37,6 +46,7 @@ impl Send {
pub fn new(config: &Config) -> Self {
Send {
init_window_sz: config.remote_init_window_sz,
max_stream_id: StreamId::MAX,
next_stream_id: Ok(config.local_next_stream_id),
prioritize: Prioritize::new(config),
}
@@ -370,6 +380,26 @@ impl Send {
Ok(())
}
pub(super) fn recv_go_away(&mut self, last_stream_id: StreamId) -> Result<(), RecvError> {
if last_stream_id > self.max_stream_id {
// The remote endpoint sent a `GOAWAY` frame indicating a stream
// that we never sent, or that we have already terminated on account
// of previous `GOAWAY` frame. In either case, that is illegal.
// (When sending multiple `GOAWAY`s, "Endpoints MUST NOT increase
// the value they send in the last stream identifier, since the
// peers might already have retried unprocessed requests on another
// connection.")
proto_err!(conn:
"recv_go_away: last_stream_id ({:?}) > max_stream_id ({:?})",
last_stream_id, self.max_stream_id,
);
return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
}
self.max_stream_id = last_stream_id;
Ok(())
}
pub fn recv_err<B>(
&mut self,
buffer: &mut Buffer<Frame<B>>,

View File

@@ -392,25 +392,11 @@ where
let send_buffer = &mut *send_buffer;
let last_stream_id = frame.last_stream_id();
actions.send.recv_go_away(last_stream_id)?;
let err = frame.reason().into();
if last_stream_id > actions.recv.max_stream_id() {
// The remote endpoint sent a `GOAWAY` frame indicating a stream
// that we never sent, or that we have already terminated on account
// of previous `GOAWAY` frame. In either case, that is illegal.
// (When sending multiple `GOAWAY`s, "Endpoints MUST NOT increase
// the value they send in the last stream identifier, since the
// peers might already have retried unprocessed requests on another
// connection.")
proto_err!(conn:
"recv_go_away: last_stream_id ({:?}) > max_stream_id ({:?})",
last_stream_id, actions.recv.max_stream_id(),
);
return Err(RecvError::Connection(Reason::PROTOCOL_ERROR));
}
actions.recv.go_away(last_stream_id);
me.store
.for_each(|stream| {
if stream.id > last_stream_id {