feat(body): add body::aggregate and body::to_bytes functions
Adds utility functions to `hyper::body` to help asynchronously collecting all the buffers of some `HttpBody` into one. - `aggregate` will collect all into an `impl Buf` without copying the contents. This is ideal if you don't need a contiguous buffer. - `to_bytes` will copy all the data into a single contiguous `Bytes` buffer.
This commit is contained in:
@@ -40,6 +40,8 @@ async fn fetch_url(url: hyper::Uri) -> Result<()> {
|
||||
println!("Response: {}", res.status());
|
||||
println!("Headers: {:#?}\n", res.headers());
|
||||
|
||||
// Stream the body, writing each chunk to stdout as we get it
|
||||
// (instead of buffering and printing at the end).
|
||||
while let Some(next) = res.body_mut().data().await {
|
||||
let chunk = next?;
|
||||
io::stdout().write_all(&chunk).await?;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
use futures_util::StreamExt;
|
||||
use bytes::buf::BufExt as _;
|
||||
use hyper::Client;
|
||||
|
||||
// A simple type alias so as to DRY.
|
||||
@@ -27,14 +27,13 @@ async fn fetch_json(url: hyper::Uri) -> Result<Vec<User>> {
|
||||
let client = Client::new();
|
||||
|
||||
// Fetch the url...
|
||||
let mut res = client.get(url).await?;
|
||||
// asynchronously concatenate chunks of the body
|
||||
let mut body = Vec::new();
|
||||
while let Some(chunk) = res.body_mut().next().await {
|
||||
body.extend_from_slice(&chunk?);
|
||||
}
|
||||
let res = client.get(url).await?;
|
||||
|
||||
// asynchronously aggregate the chunks of the body
|
||||
let body = hyper::body::aggregate(res.into_body()).await?;
|
||||
|
||||
// try to parse as json with serde_json
|
||||
let users = serde_json::from_slice(&body)?;
|
||||
let users = serde_json::from_reader(body.reader())?;
|
||||
|
||||
Ok(users)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
//#![deny(warnings)]
|
||||
#![deny(warnings)]
|
||||
|
||||
use futures_util::{StreamExt, TryStreamExt};
|
||||
use futures_util::TryStreamExt;
|
||||
use hyper::service::{make_service_fn, service_fn};
|
||||
use hyper::{Body, Method, Request, Response, Server, StatusCode};
|
||||
|
||||
/// This is our service handler. It receives a Request, routes on its
|
||||
/// path, and returns a Future of a Response.
|
||||
async fn echo(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
|
||||
async fn echo(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
|
||||
match (req.method(), req.uri().path()) {
|
||||
// Serve some instructions at /
|
||||
(&Method::GET, "/") => Ok(Response::new(Body::from(
|
||||
@@ -34,10 +34,7 @@ async fn echo(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
|
||||
// So here we do `.await` on the future, waiting on concatenating the full body,
|
||||
// then afterwards the content can be reversed. Only then can we return a `Response`.
|
||||
(&Method::POST, "/echo/reversed") => {
|
||||
let mut whole_body = Vec::new();
|
||||
while let Some(chunk) = req.body_mut().next().await {
|
||||
whole_body.extend_from_slice(&chunk?);
|
||||
}
|
||||
let whole_body = hyper::body::to_bytes(req.into_body()).await?;
|
||||
|
||||
let reversed_body = whole_body.iter().rev().cloned().collect::<Vec<u8>>();
|
||||
Ok(Response::new(Body::from(reversed_body)))
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use hyper::service::{make_service_fn, service_fn};
|
||||
use hyper::{Body, Method, Request, Response, Server, StatusCode};
|
||||
|
||||
use futures_util::StreamExt;
|
||||
use std::collections::HashMap;
|
||||
use url::form_urlencoded;
|
||||
|
||||
@@ -13,15 +12,12 @@ static MISSING: &[u8] = b"Missing field";
|
||||
static NOTNUMERIC: &[u8] = b"Number field is not numeric";
|
||||
|
||||
// Using service_fn, we can turn this function into a `Service`.
|
||||
async fn param_example(mut req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
|
||||
async fn param_example(req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
|
||||
match (req.method(), req.uri().path()) {
|
||||
(&Method::GET, "/") | (&Method::GET, "/post") => Ok(Response::new(INDEX.into())),
|
||||
(&Method::POST, "/post") => {
|
||||
// Concatenate the body...
|
||||
let mut b = Vec::new();
|
||||
while let Some(chunk) = req.body_mut().next().await {
|
||||
b.extend_from_slice(&chunk?);
|
||||
}
|
||||
let b = hyper::body::to_bytes(req.into_body()).await?;
|
||||
// Parse the request body. form_urlencoded::parse
|
||||
// always succeeds, but in general parsing may
|
||||
// fail (for example, an invalid post of json), so
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![deny(warnings)]
|
||||
|
||||
use futures_util::{StreamExt, TryStreamExt};
|
||||
use bytes::buf::BufExt;
|
||||
use futures_util::{stream, StreamExt};
|
||||
use hyper::client::HttpConnector;
|
||||
use hyper::service::{make_service_fn, service_fn};
|
||||
use hyper::{header, Body, Client, Method, Request, Response, Server, StatusCode};
|
||||
@@ -24,25 +25,24 @@ async fn client_request_response(client: &Client<HttpConnector>) -> Result<Respo
|
||||
|
||||
let web_res = client.request(req).await?;
|
||||
// Compare the JSON we sent (before) with what we received (after):
|
||||
let body = Body::wrap_stream(web_res.into_body().map_ok(|b| {
|
||||
format!(
|
||||
"<b>POST request body</b>: {}<br><b>Response</b>: {}",
|
||||
let before = stream::once(async {
|
||||
Ok(format!(
|
||||
"<b>POST request body</b>: {}<br><b>Response</b>: ",
|
||||
POST_DATA,
|
||||
std::str::from_utf8(&b).unwrap()
|
||||
)
|
||||
}));
|
||||
.into())
|
||||
});
|
||||
let after = web_res.into_body();
|
||||
let body = Body::wrap_stream(before.chain(after));
|
||||
|
||||
Ok(Response::new(body))
|
||||
}
|
||||
|
||||
async fn api_post_response(mut req: Request<Body>) -> Result<Response<Body>> {
|
||||
// Concatenate the body...
|
||||
let mut whole_body = Vec::new();
|
||||
while let Some(chunk) = req.body_mut().next().await {
|
||||
whole_body.extend_from_slice(&chunk?);
|
||||
}
|
||||
async fn api_post_response(req: Request<Body>) -> Result<Response<Body>> {
|
||||
// Aggregate the body...
|
||||
let whole_body = hyper::body::aggregate(req.into_body()).await?;
|
||||
// Decode as JSON...
|
||||
let mut data: serde_json::Value = serde_json::from_slice(&whole_body)?;
|
||||
let mut data: serde_json::Value = serde_json::from_reader(whole_body.reader())?;
|
||||
// Change the JSON...
|
||||
data["test"] = serde_json::Value::from("test_value");
|
||||
// And respond with the new JSON.
|
||||
|
||||
Reference in New Issue
Block a user