diff --git a/src/proto/h1/role.rs b/src/proto/h1/role.rs index fce1df78af..f32b8770a5 100644 --- a/src/proto/h1/role.rs +++ b/src/proto/h1/role.rs @@ -1349,7 +1349,8 @@ impl Client { }; // HTTP/1.0 doesn't know about chunked - let can_chunked = head.version == Version::HTTP_11; + // HTTP/2 requests are serialized as HTTP/1.1. + let can_chunked = matches!(head.version, Version::HTTP_11 | Version::HTTP_2); let headers = &mut head.headers; // If the user already set specific headers, we should respect them, regardless diff --git a/tests/client.rs b/tests/client.rs index 4cb6615657..6e174c4d18 100644 --- a/tests/client.rs +++ b/tests/client.rs @@ -1992,6 +1992,50 @@ mod conn { rt.block_on(future::join(res, rx).map(|r| r.0)).unwrap(); } + #[tokio::test] + async fn http1_conn_coerces_http2_streaming_request() { + tokio::time::timeout(Duration::from_secs(5), async { + let (client_io, server_io) = tokio::io::duplex(1024); + let svc = hyper::service::service_fn(|req: Request| async { + assert_eq!(req.method(), Method::POST); + assert_eq!(req.version(), hyper::Version::HTTP_11); + let chunked = req.headers().get("transfer-encoding").cloned(); + let body = concat(req).await?; + assert_eq!(body, "hello world"); + assert_eq!(chunked.as_ref().unwrap(), "chunked"); + Ok::<_, hyper::Error>(Response::new(Full::new(body))) + }); + let server = tokio::spawn( + hyper::server::conn::http1::Builder::new() + .serve_connection(TokioIo::new(server_io), svc), + ); + + let (mut client, connection) = conn::http1::handshake(TokioIo::new(client_io)) + .await + .unwrap(); + let connection = tokio::spawn(connection); + let body = StreamBody::new(futures_util::stream::iter([ + Ok::<_, std::convert::Infallible>(Frame::data(Bytes::from_static(b"hello"))), + Ok(Frame::data(Bytes::from_static(b" world"))), + ])); + assert_eq!(body.size_hint().exact(), None); + let req = Request::post("/a") + .version(hyper::Version::HTTP_2) + .body(body) + .unwrap(); + + let response = client.send_request(req).await.unwrap(); + assert_eq!(response.status(), StatusCode::OK); + assert_eq!(concat(response).await.unwrap(), "hello world"); + + drop(client); + connection.await.unwrap().unwrap(); + server.await.unwrap().unwrap(); + }) + .await + .expect("coerced request body should reach the server"); + } + #[test] fn pipeline() { let (server, addr) = setup_std_test_server();