Skip to content

Commit 9e8fc8f

Browse files
seanmonstarXuanwo
andauthoredAug 24, 2022
feat(body): remove "full" constructors from Body (#2958)
The constructors of `hyper::Body` from a full bytes are removed. Along with `Body::empty()`. BREAKING CHANGE: Use the types from `http-body-util`. Co-authored-by: Xuanwo <github@xuanwo.io>
1 parent 952756b commit 9e8fc8f

34 files changed

+236
-463
lines changed
 

‎Cargo.toml

-5
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,6 @@ name = "state"
181181
path = "examples/state.rs"
182182
required-features = ["full"]
183183

184-
[[example]]
185-
name = "tower_server"
186-
path = "examples/tower_server.rs"
187-
required-features = ["full"]
188-
189184
[[example]]
190185
name = "upgrades"
191186
path = "examples/upgrades.rs"

‎benches/pipeline.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@
33

44
extern crate test;
55

6+
use std::convert::Infallible;
67
use std::io::{Read, Write};
78
use std::net::{SocketAddr, TcpStream};
89
use std::sync::mpsc;
910
use std::time::Duration;
1011

12+
use bytes::Bytes;
13+
use http_body_util::Full;
1114
use tokio::net::TcpListener;
1215
use tokio::sync::oneshot;
1316

1417
use hyper::server::conn::Http;
1518
use hyper::service::service_fn;
16-
use hyper::{Body, Response};
19+
use hyper::Response;
1720

1821
const PIPELINED_REQUESTS: usize = 16;
1922

@@ -43,7 +46,9 @@ fn hello_world_16(b: &mut test::Bencher) {
4346
.serve_connection(
4447
stream,
4548
service_fn(|_| async {
46-
Ok::<_, hyper::Error>(Response::new(Body::from("Hello, World!")))
49+
Ok::<_, Infallible>(Response::new(Full::new(Bytes::from(
50+
"Hello, World!",
51+
))))
4752
}),
4853
)
4954
.await

‎benches/server.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ use std::net::{SocketAddr, TcpListener, TcpStream};
88
use std::sync::mpsc;
99
use std::time::Duration;
1010

11+
use bytes::Bytes;
1112
use futures_util::{stream, StreamExt};
12-
use http_body_util::{BodyExt, StreamBody};
13+
use http_body_util::{BodyExt, Full, StreamBody};
1314
use tokio::sync::oneshot;
1415

1516
use hyper::server::conn::Http;
@@ -87,8 +88,8 @@ macro_rules! bench_server {
8788
}};
8889
}
8990

90-
fn body(b: &'static [u8]) -> hyper::Body {
91-
b.into()
91+
fn body(b: &'static [u8]) -> Full<Bytes> {
92+
Full::new(b.into())
9293
}
9394

9495
#[bench]

‎examples/client.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
#![warn(rust_2018_idioms)]
33
use std::env;
44

5-
use hyper::{body::HttpBody as _, Body, Request};
5+
use bytes::Bytes;
6+
use http_body_util::Empty;
7+
use hyper::{body::HttpBody as _, Request};
68
use tokio::io::{self, AsyncWriteExt as _};
79
use tokio::net::TcpStream;
810

@@ -51,7 +53,7 @@ async fn fetch_url(url: hyper::Uri) -> Result<()> {
5153
let req = Request::builder()
5254
.uri(url)
5355
.header(hyper::header::HOST, authority.as_str())
54-
.body(Body::empty())?;
56+
.body(Empty::<Bytes>::new())?;
5557

5658
let mut res = sender.send_request(req).await?;
5759

‎examples/client_json.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#![deny(warnings)]
22
#![warn(rust_2018_idioms)]
33

4-
use hyper::Body;
4+
use bytes::Bytes;
5+
use http_body_util::Empty;
56
use hyper::{body::Buf, Request};
67
use serde::Deserialize;
78
use tokio::net::TcpStream;
@@ -42,7 +43,7 @@ async fn fetch_json(url: hyper::Uri) -> Result<Vec<User>> {
4243
let req = Request::builder()
4344
.uri(url)
4445
.header(hyper::header::HOST, authority.as_str())
45-
.body(Body::empty())?;
46+
.body(Empty::<Bytes>::new())?;
4647

4748
let res = sender.send_request(req).await?;
4849

‎examples/echo.rs

+20-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
use std::net::SocketAddr;
44

5+
use bytes::Bytes;
6+
use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};
57
use hyper::body::HttpBody as _;
68
use hyper::server::conn::Http;
79
use hyper::service::service_fn;
@@ -10,15 +12,15 @@ use tokio::net::TcpListener;
1012

1113
/// This is our service handler. It receives a Request, routes on its
1214
/// path, and returns a Future of a Response.
13-
async fn echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
15+
async fn echo(req: Request<Body>) -> Result<Response<BoxBody<Bytes, hyper::Error>>, hyper::Error> {
1416
match (req.method(), req.uri().path()) {
1517
// Serve some instructions at /
16-
(&Method::GET, "/") => Ok(Response::new(Body::from(
18+
(&Method::GET, "/") => Ok(Response::new(full(
1719
"Try POSTing data to /echo such as: `curl localhost:3000/echo -XPOST -d 'hello world'`",
1820
))),
1921

2022
// Simply echo the body back to the client.
21-
(&Method::POST, "/echo") => Ok(Response::new(req.into_body())),
23+
(&Method::POST, "/echo") => Ok(Response::new(req.into_body().boxed())),
2224

2325
// TODO: Fix this, broken in PR #2896
2426
// Convert to uppercase before sending back to client using a stream.
@@ -43,26 +45,38 @@ async fn echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
4345
// 64kbs of data.
4446
let max = req.body().size_hint().upper().unwrap_or(u64::MAX);
4547
if max > 1024 * 64 {
46-
let mut resp = Response::new(Body::from("Body too big"));
48+
let mut resp = Response::new(full("Body too big"));
4749
*resp.status_mut() = hyper::StatusCode::PAYLOAD_TOO_LARGE;
4850
return Ok(resp);
4951
}
5052

5153
let whole_body = hyper::body::to_bytes(req.into_body()).await?;
5254

5355
let reversed_body = whole_body.iter().rev().cloned().collect::<Vec<u8>>();
54-
Ok(Response::new(Body::from(reversed_body)))
56+
Ok(Response::new(full(reversed_body)))
5557
}
5658

5759
// Return the 404 Not Found for other routes.
5860
_ => {
59-
let mut not_found = Response::default();
61+
let mut not_found = Response::new(empty());
6062
*not_found.status_mut() = StatusCode::NOT_FOUND;
6163
Ok(not_found)
6264
}
6365
}
6466
}
6567

68+
fn empty() -> BoxBody<Bytes, hyper::Error> {
69+
Empty::<Bytes>::new()
70+
.map_err(|never| match never {})
71+
.boxed()
72+
}
73+
74+
fn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, hyper::Error> {
75+
Full::new(chunk.into())
76+
.map_err(|never| match never {})
77+
.boxed()
78+
}
79+
6680
#[tokio::main]
6781
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
6882
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));

‎examples/hello.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
use std::convert::Infallible;
44
use std::net::SocketAddr;
55

6+
use bytes::Bytes;
7+
use http_body_util::Full;
68
use hyper::server::conn::Http;
79
use hyper::service::service_fn;
810
use hyper::{Body, Request, Response};
911
use tokio::net::TcpListener;
1012

11-
async fn hello(_: Request<Body>) -> Result<Response<Body>, Infallible> {
12-
Ok(Response::new(Body::from("Hello World!")))
13+
async fn hello(_: Request<Body>) -> Result<Response<Full<Bytes>>, Infallible> {
14+
Ok(Response::new(Full::new(Bytes::from("Hello World!"))))
1315
}
1416

1517
#[tokio::main]

‎examples/http_proxy.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
use std::net::SocketAddr;
44

5+
use bytes::Bytes;
6+
use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};
57
use hyper::client::conn::Builder;
68
use hyper::server::conn::Http;
79
use hyper::service::service_fn;
@@ -41,7 +43,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
4143
}
4244
}
4345

44-
async fn proxy(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
46+
async fn proxy(req: Request<Body>) -> Result<Response<BoxBody<Bytes, hyper::Error>>, hyper::Error> {
4547
println!("req: {:?}", req);
4648

4749
if Method::CONNECT == req.method() {
@@ -70,10 +72,10 @@ async fn proxy(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
7072
}
7173
});
7274

73-
Ok(Response::new(Body::empty()))
75+
Ok(Response::new(empty()))
7476
} else {
7577
eprintln!("CONNECT host is not socket addr: {:?}", req.uri());
76-
let mut resp = Response::new(Body::from("CONNECT must be to a socket address"));
78+
let mut resp = Response::new(full("CONNECT must be to a socket address"));
7779
*resp.status_mut() = http::StatusCode::BAD_REQUEST;
7880

7981
Ok(resp)
@@ -96,14 +98,27 @@ async fn proxy(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
9698
}
9799
});
98100

99-
sender.send_request(req).await
101+
let resp = sender.send_request(req).await?;
102+
Ok(resp.map(|b| b.boxed()))
100103
}
101104
}
102105

103106
fn host_addr(uri: &http::Uri) -> Option<String> {
104107
uri.authority().and_then(|auth| Some(auth.to_string()))
105108
}
106109

110+
fn empty() -> BoxBody<Bytes, hyper::Error> {
111+
Empty::<Bytes>::new()
112+
.map_err(|never| match never {})
113+
.boxed()
114+
}
115+
116+
fn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, hyper::Error> {
117+
Full::new(chunk.into())
118+
.map_err(|never| match never {})
119+
.boxed()
120+
}
121+
107122
// Create a TCP connection to host:port, build a tunnel between the connection and
108123
// the upgraded connection
109124
async fn tunnel(mut upgraded: Upgraded, addr: String) -> std::io::Result<()> {

‎examples/multi_server.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
use std::net::SocketAddr;
55

6+
use bytes::Bytes;
67
use futures_util::future::join;
8+
use http_body_util::Full;
79
use hyper::server::conn::Http;
810
use hyper::service::service_fn;
911
use hyper::{Body, Request, Response};
@@ -12,12 +14,12 @@ use tokio::net::TcpListener;
1214
static INDEX1: &[u8] = b"The 1st service!";
1315
static INDEX2: &[u8] = b"The 2nd service!";
1416

15-
async fn index1(_: Request<Body>) -> Result<Response<Body>, hyper::Error> {
16-
Ok(Response::new(Body::from(INDEX1)))
17+
async fn index1(_: Request<Body>) -> Result<Response<Full<Bytes>>, hyper::Error> {
18+
Ok(Response::new(Full::new(Bytes::from(INDEX1))))
1719
}
1820

19-
async fn index2(_: Request<Body>) -> Result<Response<Body>, hyper::Error> {
20-
Ok(Response::new(Body::from(INDEX2)))
21+
async fn index2(_: Request<Body>) -> Result<Response<Full<Bytes>>, hyper::Error> {
22+
Ok(Response::new(Full::new(Bytes::from(INDEX2))))
2123
}
2224

2325
#[tokio::main]

‎examples/params.rs

+23-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
// #![deny(warnings)] // FIXME: https://github.com/rust-lang/rust/issues/62411
22
#![warn(rust_2018_idioms)]
33

4+
use bytes::Bytes;
5+
use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};
46
use hyper::server::conn::Http;
57
use hyper::service::service_fn;
68
use hyper::{Body, Method, Request, Response, StatusCode};
79
use tokio::net::TcpListener;
810

911
use std::collections::HashMap;
12+
use std::convert::Infallible;
1013
use std::net::SocketAddr;
1114
use url::form_urlencoded;
1215

@@ -15,9 +18,11 @@ static MISSING: &[u8] = b"Missing field";
1518
static NOTNUMERIC: &[u8] = b"Number field is not numeric";
1619

1720
// Using service_fn, we can turn this function into a `Service`.
18-
async fn param_example(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
21+
async fn param_example(
22+
req: Request<Body>,
23+
) -> Result<Response<BoxBody<Bytes, Infallible>>, hyper::Error> {
1924
match (req.method(), req.uri().path()) {
20-
(&Method::GET, "/") | (&Method::GET, "/post") => Ok(Response::new(INDEX.into())),
25+
(&Method::GET, "/") | (&Method::GET, "/post") => Ok(Response::new(full(INDEX))),
2126
(&Method::POST, "/post") => {
2227
// Concatenate the body...
2328
let b = hyper::body::to_bytes(req).await?;
@@ -43,7 +48,7 @@ async fn param_example(req: Request<Body>) -> Result<Response<Body>, hyper::Erro
4348
} else {
4449
return Ok(Response::builder()
4550
.status(StatusCode::UNPROCESSABLE_ENTITY)
46-
.body(MISSING.into())
51+
.body(full(MISSING))
4752
.unwrap());
4853
};
4954
let number = if let Some(n) = params.get("number") {
@@ -52,13 +57,13 @@ async fn param_example(req: Request<Body>) -> Result<Response<Body>, hyper::Erro
5257
} else {
5358
return Ok(Response::builder()
5459
.status(StatusCode::UNPROCESSABLE_ENTITY)
55-
.body(NOTNUMERIC.into())
60+
.body(full(NOTNUMERIC))
5661
.unwrap());
5762
}
5863
} else {
5964
return Ok(Response::builder()
6065
.status(StatusCode::UNPROCESSABLE_ENTITY)
61-
.body(MISSING.into())
66+
.body(full(MISSING))
6267
.unwrap());
6368
};
6469

@@ -69,15 +74,15 @@ async fn param_example(req: Request<Body>) -> Result<Response<Body>, hyper::Erro
6974
// responses such as InternalServiceError may be
7075
// needed here, too.
7176
let body = format!("Hello {}, your number is {}", name, number);
72-
Ok(Response::new(body.into()))
77+
Ok(Response::new(full(body)))
7378
}
7479
(&Method::GET, "/get") => {
7580
let query = if let Some(q) = req.uri().query() {
7681
q
7782
} else {
7883
return Ok(Response::builder()
7984
.status(StatusCode::UNPROCESSABLE_ENTITY)
80-
.body(MISSING.into())
85+
.body(full(MISSING))
8186
.unwrap());
8287
};
8388
let params = form_urlencoded::parse(query.as_bytes())
@@ -88,19 +93,27 @@ async fn param_example(req: Request<Body>) -> Result<Response<Body>, hyper::Erro
8893
} else {
8994
return Ok(Response::builder()
9095
.status(StatusCode::UNPROCESSABLE_ENTITY)
91-
.body(MISSING.into())
96+
.body(full(MISSING))
9297
.unwrap());
9398
};
9499
let body = format!("You requested {}", page);
95-
Ok(Response::new(body.into()))
100+
Ok(Response::new(full(body)))
96101
}
97102
_ => Ok(Response::builder()
98103
.status(StatusCode::NOT_FOUND)
99-
.body(Body::empty())
104+
.body(empty())
100105
.unwrap()),
101106
}
102107
}
103108

109+
fn empty() -> BoxBody<Bytes, Infallible> {
110+
Empty::<Bytes>::new().boxed()
111+
}
112+
113+
fn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, Infallible> {
114+
Full::new(chunk.into()).boxed()
115+
}
116+
104117
#[tokio::main]
105118
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
106119
pretty_env_logger::init();

0 commit comments

Comments
 (0)