From 1552d62e7c6e1000ed4545b45603ce6fa355eb19 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Tue, 19 Dec 2017 15:06:05 -0800 Subject: [PATCH] ignore trailers for some time on locally reset streams (#194) --- src/proto/streams/streams.rs | 9 +++++++ tests/stream_states.rs | 51 +++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/proto/streams/streams.rs b/src/proto/streams/streams.rs index 6a431dc..29011b8 100644 --- a/src/proto/streams/streams.rs +++ b/src/proto/streams/streams.rs @@ -143,6 +143,15 @@ where }; let stream = me.store.resolve(key); + + if stream.state.is_local_reset() { + // Locally reset streams must ignore frames "for some time". + // This is because the remote may have sent trailers before + // receiving the RST_STREAM frame. + trace!("recv_headers; ignoring trailers on {:?}", stream.id); + return Ok(()); + } + let actions = &mut me.actions; let mut send_buffer = self.send_buffer.inner.lock().unwrap(); let send_buffer = &mut *send_buffer; diff --git a/tests/stream_states.rs b/tests/stream_states.rs index 4832226..e599da0 100644 --- a/tests/stream_states.rs +++ b/tests/stream_states.rs @@ -467,7 +467,7 @@ fn skipped_stream_ids_are_implicitly_closed() { } #[test] -fn send_rst_stream_allows_recv_frames() { +fn send_rst_stream_allows_recv_data() { let _ = ::env_logger::init(); let (io, srv) = mock::new(); @@ -518,6 +518,55 @@ fn send_rst_stream_allows_recv_frames() { client.join(srv).wait().expect("wait"); } +#[test] +fn send_rst_stream_allows_recv_trailers() { + let _ = ::env_logger::init(); + let (io, srv) = mock::new(); + + let srv = srv.assert_client_handshake() + .unwrap() + .recv_settings() + .recv_frame( + frames::headers(1) + .request("GET", "https://example.com/") + .eos(), + ) + .send_frame(frames::headers(1).response(200)) + .send_frame(frames::data(1, vec![0; 16_384])) + .recv_frame(frames::reset(1).cancel()) + // sending frames after canceled! + .send_frame(frames::headers(1).field("foo", "bar").eos()) + // do a pingpong to ensure no other frames were sent + .ping_pong([1; 8]) + .close(); + + let client = Client::handshake(io) + .expect("handshake") + .and_then(|(mut client, conn)| { + let request = Request::builder() + .method(Method::GET) + .uri("https://example.com/") + .body(()) + .unwrap(); + + let req = client.send_request(request, true) + .unwrap() + .0.expect("response") + .and_then(|resp| { + assert_eq!(resp.status(), StatusCode::OK); + // drop resp will send a reset + Ok(()) + }); + + conn.expect("client") + .drive(req) + .and_then(|(conn, _)| conn) + }); + + + client.join(srv).wait().expect("wait"); +} + #[test] fn rst_stream_expires() { let _ = ::env_logger::init();