Refactor errors internals (#556)

h2::Error now knows whether protocol errors happened because the user
sent them, because it was received from the remote peer, or because
the library itself emitted an error because it detected a protocol
violation.

It also keeps track of whether it came from a RST_STREAM or GO_AWAY
frame, and in the case of the latter, it includes the additional
debug data if any.

Fixes #530
This commit is contained in:
Anthony Ramine
2021-09-28 18:04:35 +02:00
committed by GitHub
parent cab307d2ed
commit 465f0337f8
26 changed files with 464 additions and 432 deletions

View File

@@ -1,7 +1,8 @@
use crate::SendFrame;
use h2::frame::{self, Frame};
use h2::{self, RecvError, SendError};
use h2::proto::Error;
use h2::{self, SendError};
use futures::future::poll_fn;
use futures::{ready, Stream, StreamExt};
@@ -284,7 +285,7 @@ impl Handle {
}
impl Stream for Handle {
type Item = Result<Frame, RecvError>;
type Item = Result<Frame, Error>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Pin::new(&mut self.codec).poll_next(cx)

View File

@@ -410,7 +410,11 @@ async fn send_reset_notifies_recv_stream() {
};
let rx = async {
let mut body = res.into_body();
body.next().await.unwrap().expect_err("RecvBody");
let err = body.next().await.unwrap().expect_err("RecvBody");
assert_eq!(
err.to_string(),
"stream error sent by user: refused stream before processing any application logic"
);
};
// a FuturesUnordered is used on purpose!
@@ -672,7 +676,7 @@ async fn sending_request_on_closed_connection() {
};
let poll_err = poll_fn(|cx| client.poll_ready(cx)).await.unwrap_err();
let msg = "protocol error: unspecific protocol error detected";
let msg = "connection error detected: unspecific protocol error detected";
assert_eq!(poll_err.to_string(), msg);
let request = Request::builder()

View File

@@ -236,7 +236,7 @@ async fn read_goaway_with_debug_data() {
let data = poll_frame!(GoAway, codec);
assert_eq!(data.reason(), Reason::ENHANCE_YOUR_CALM);
assert_eq!(data.last_stream_id(), 1);
assert_eq!(data.debug_data(), b"too_many_pings");
assert_eq!(&**data.debug_data(), b"too_many_pings");
assert_closed!(codec);
}

View File

@@ -217,7 +217,7 @@ async fn recv_data_overflows_connection_window() {
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
"protocol error: flow-control protocol violated"
"connection error detected: flow-control protocol violated"
);
};
@@ -227,7 +227,7 @@ async fn recv_data_overflows_connection_window() {
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
"protocol error: flow-control protocol violated"
"connection error detected: flow-control protocol violated"
);
};
join(conn, req).await;
@@ -278,7 +278,7 @@ async fn recv_data_overflows_stream_window() {
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
"protocol error: flow-control protocol violated"
"stream error detected: flow-control protocol violated"
);
};
@@ -358,7 +358,7 @@ async fn stream_error_release_connection_capacity() {
.expect_err("body");
assert_eq!(
err.to_string(),
"protocol error: unspecific protocol error detected"
"stream error detected: unspecific protocol error detected"
);
cap.release_capacity(to_release).expect("release_capacity");
};

View File

@@ -164,7 +164,7 @@ async fn recv_push_when_push_disabled_is_conn_error() {
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
"protocol error: unspecific protocol error detected"
"connection error detected: unspecific protocol error detected"
);
};
@@ -174,7 +174,7 @@ async fn recv_push_when_push_disabled_is_conn_error() {
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
"protocol error: unspecific protocol error detected"
"connection error detected: unspecific protocol error detected"
);
};
@@ -380,8 +380,16 @@ async fn recv_push_promise_skipped_stream_id() {
.unwrap();
let req = async move {
let res = client.send_request(request, true).unwrap().0.await;
assert!(res.is_err());
let err = client
.send_request(request, true)
.unwrap()
.0
.await
.unwrap_err();
assert_eq!(
err.to_string(),
"connection error detected: unspecific protocol error detected"
);
};
// client should see a protocol error
@@ -390,7 +398,7 @@ async fn recv_push_promise_skipped_stream_id() {
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
"protocol error: unspecific protocol error detected"
"connection error detected: unspecific protocol error detected"
);
};
@@ -435,7 +443,11 @@ async fn recv_push_promise_dup_stream_id() {
let req = async move {
let res = client.send_request(request, true).unwrap().0.await;
assert!(res.is_err());
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
"connection error detected: unspecific protocol error detected"
);
};
// client should see a protocol error
@@ -444,7 +456,7 @@ async fn recv_push_promise_dup_stream_id() {
let err = res.unwrap_err();
assert_eq!(
err.to_string(),
"protocol error: unspecific protocol error detected"
"connection error detected: unspecific protocol error detected"
);
};

View File

@@ -207,13 +207,19 @@ async fn errors_if_recv_frame_exceeds_max_frame_size() {
let body = resp.into_parts().1;
let res = util::concat(body).await;
let err = res.unwrap_err();
assert_eq!(err.to_string(), "protocol error: frame with invalid size");
assert_eq!(
err.to_string(),
"connection error detected: frame with invalid size"
);
};
// client should see a conn error
let conn = async move {
let err = h2.await.unwrap_err();
assert_eq!(err.to_string(), "protocol error: frame with invalid size");
assert_eq!(
err.to_string(),
"connection error detected: frame with invalid size"
);
};
join(conn, req).await;
};
@@ -321,7 +327,10 @@ async fn recv_goaway_finishes_processed_streams() {
// this request will trigger a goaway
let req2 = async move {
let err = client.get("https://example.com/").await.unwrap_err();
assert_eq!(err.to_string(), "protocol error: not a result of an error");
assert_eq!(
err.to_string(),
"connection error received: not a result of an error"
);
};
join3(async move { h2.await.expect("client") }, req1, req2).await;