hyperium / hyper

An HTTP library for Rust
https://hyper.rs
MIT License
14.42k stars 1.59k forks source link

Streaming request recv hang if client interrupted #3291

Open wangyoucao577 opened 1 year ago

wangyoucao577 commented 1 year ago

Version v0.14.27

Platform Linux demo 5.15.90.1-microsoft-standard-WSL2 #1 SMP Fri Jan 27 02:56:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux Tested on several other linux platforms(ubuntu, debian, etc), same issue occurred.

Description

I tried this code: add a stream request handler in the echo example as below.

diff --git a/examples/echo.rs b/examples/echo.rs
index ff757304..6fa05793 100644
--- a/examples/echo.rs
+++ b/examples/echo.rs
@@ -4,10 +4,25 @@ use futures_util::TryStreamExt;
 use hyper::service::{make_service_fn, service_fn};
 use hyper::{Body, Method, Request, Response, Server, StatusCode};

+use futures_util:: StreamExt;
+
 /// This is our service handler. It receives a Request, routes on its
 /// path, and returns a Future of a Response.
 async fn echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
     match (req.method(), req.uri().path()) {
+
+        // Serve streaming body
+        (&Method::POST, "/stream") => {
+
+            let mut payload = req.into_body();
+            while let Some(item) = payload.next().await {
+                let item = item?;
+                println!("payload len: {}", item.len());
+            }
+            println!("stream body finished");
+            Ok(Response::default())
+        }
+

then run it

$ cargo run --example echo --features=full
Compiling hyper v0.14.27 (/home/workspace/hyper)
    Finished dev [unoptimized + debuginfo] target(s) in 3.22s
     Running `target/debug/examples/echo`
Listening on http://127.0.0.1:3000

Open another terminal, and test against the server by curl:

curl -v -X POST --data-binary @"YOUR_TEST_FILE" --limit-rate 1M http://127.0.0.1:3000/stream

I expected to see this happen:

Normally logs like below will output by the echo server if curl finished correctly(transfer succeed), which is expected.

...
payload len: 65536
payload len: 65536
payload len: 17317
stream body finished

However, if curl was interruptted by CTRL + C, the stream body finished won't be printed and the session seems hang forever on the server side.

...
payload len: 65536
payload len: 65536
==> hang here
dswij commented 8 months ago

The server itself does not hang when a client close the connection abruptly, but there isn't a good way to see the error in hyper 0.14. In hyper v1.0.1, it will be propagated to the caller as UnexpectedEof

The error propagation stops here: https://github.com/hyperium/hyper/blob/dedcb674f35eaec765a42b550caabe6f694d86d1/src/server/server.rs#L794, and it's only written to debug-level logs.