diff --git a/src/proto/connection.rs b/src/proto/connection.rs index f7fc8fcb..7a07001c 100644 --- a/src/proto/connection.rs +++ b/src/proto/connection.rs @@ -482,9 +482,11 @@ where // without error // // See https://github.com/hyperium/hyper/issues/3427 - if self.streams.is_server() - && self.streams.is_buffer_empty() + if self.streams.is_buffer_empty() && matches!(kind, io::ErrorKind::UnexpectedEof) + && (self.streams.is_server() + || self.error.as_ref().map(|f| f.reason() == Reason::NO_ERROR) + == Some(true)) { *self.state = State::Closed(Reason::NO_ERROR, Initiator::Library); return Ok(()); diff --git a/tests/h2-tests/tests/client_request.rs b/tests/h2-tests/tests/client_request.rs index 8c991839..c99cc531 100644 --- a/tests/h2-tests/tests/client_request.rs +++ b/tests/h2-tests/tests/client_request.rs @@ -1913,6 +1913,8 @@ async fn receive_settings_frame_twice_with_second_one_non_empty() { join(srv, h2).await; } +// If the server has not sent a go_away message before dropping the connection +// make sure the UnexpectedEof error is propogated. #[tokio::test] async fn server_drop_connection_unexpectedly_return_unexpected_eof_err() { h2_support::trace_init!(); @@ -1953,6 +1955,44 @@ async fn server_drop_connection_unexpectedly_return_unexpected_eof_err() { join(srv, h2).await; } +#[tokio::test] +async fn server_drop_connection_after_go_away() { + h2_support::trace_init!(); + let (io, mut srv) = mock::new(); + + let srv = async move { + let settings = srv.assert_client_handshake().await; + assert_default_settings!(settings); + srv.recv_frame( + frames::headers(1) + .request("GET", "https://http2.akamai.com/") + .eos(), + ) + .await; + srv.send_frame(frames::go_away(1)).await; + tokio::time::sleep(Duration::from_millis(50)).await; + srv.close_without_notify(); + }; + + let h2 = async move { + let (mut client, h2) = client::handshake(io).await.unwrap(); + tokio::spawn(async move { + let request = Request::builder() + .uri("https://http2.akamai.com/") + .body(()) + .unwrap(); + let _res = client + .send_request(request, true) + .unwrap() + .0 + .await + .expect("request"); + }); + let _ = h2.await.unwrap(); + }; + join(srv, h2).await; +} + const SETTINGS: &[u8] = &[0, 0, 0, 4, 0, 0, 0, 0, 0]; const SETTINGS_ACK: &[u8] = &[0, 0, 0, 4, 1, 0, 0, 0, 0];