Skip to content

Commit f51c677

Browse files
authoredJul 21, 2021
fix(http2): improve I/O errors emitted by H2Upgraded (#2598)
When a `CONNECT` over HTTP2 has been established, and the user tries to write data right when the peer closes the stream, it will no longer return as a "user error". The reset code is checked, and converted into an appropriate `io::ErrorKind`.
1 parent 090ee08 commit f51c677

File tree

1 file changed

+32
-13
lines changed

1 file changed

+32
-13
lines changed
 

‎src/proto/h2/mod.rs

+32-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use bytes::{Buf, Bytes};
2-
use h2::{RecvStream, SendStream};
2+
use h2::{Reason, RecvStream, SendStream};
33
use http::header::{HeaderName, CONNECTION, TE, TRAILER, TRANSFER_ENCODING, UPGRADE};
44
use http::HeaderMap;
55
use pin_project_lite::pin_project;
@@ -313,7 +313,11 @@ where
313313
break buf;
314314
}
315315
Some(Err(e)) => {
316-
return Poll::Ready(Err(h2_to_io_error(e)));
316+
return Poll::Ready(match e.reason() {
317+
Some(Reason::NO_ERROR) | Some(Reason::CANCEL) => Ok(()),
318+
Some(Reason::STREAM_CLOSED) => Err(io::ErrorKind::BrokenPipe.into()),
319+
_ => Err(h2_to_io_error(e)),
320+
})
317321
}
318322
}
319323
};
@@ -335,21 +339,36 @@ where
335339
cx: &mut Context<'_>,
336340
buf: &[u8],
337341
) -> Poll<Result<usize, io::Error>> {
338-
if let Poll::Ready(reset) = self.send_stream.poll_reset(cx) {
339-
return Poll::Ready(Err(h2_to_io_error(match reset {
340-
Ok(reason) => reason.into(),
341-
Err(e) => e,
342-
})));
343-
}
344342
if buf.is_empty() {
345343
return Poll::Ready(Ok(0));
346344
}
347345
self.send_stream.reserve_capacity(buf.len());
348-
Poll::Ready(match ready!(self.send_stream.poll_capacity(cx)) {
349-
None => Ok(0),
350-
Some(Ok(cnt)) => self.send_stream.write(&buf[..cnt], false).map(|()| cnt),
351-
Some(Err(e)) => Err(h2_to_io_error(e)),
352-
})
346+
347+
// We ignore all errors returned by `poll_capacity` and `write`, as we
348+
// will get the correct from `poll_reset` anyway.
349+
let cnt = match ready!(self.send_stream.poll_capacity(cx)) {
350+
None => Some(0),
351+
Some(Ok(cnt)) => self
352+
.send_stream
353+
.write(&buf[..cnt], false)
354+
.ok()
355+
.map(|()| cnt),
356+
Some(Err(_)) => None,
357+
};
358+
359+
if let Some(cnt) = cnt {
360+
return Poll::Ready(Ok(cnt));
361+
}
362+
363+
Poll::Ready(Err(h2_to_io_error(
364+
match ready!(self.send_stream.poll_reset(cx)) {
365+
Ok(Reason::NO_ERROR) | Ok(Reason::CANCEL) | Ok(Reason::STREAM_CLOSED) => {
366+
return Poll::Ready(Err(io::ErrorKind::BrokenPipe.into()))
367+
}
368+
Ok(reason) => reason.into(),
369+
Err(e) => e,
370+
},
371+
)))
353372
}
354373

355374
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {

1 commit comments

Comments
 (1)

github-actions[bot] commented on Jul 21, 2021

@github-actions[bot]

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'end_to_end'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: f51c677 Previous: 090ee08 Ratio
http2_parallel_x10_req_10kb_100_chunks_adaptive_window 20385415 ns/iter (± 9617285) 9050074 ns/iter (± 37035) 2.25

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.