Body

Struct Body 

Source
pub struct Body { /* private fields */ }
Expand description

Body of an http request or response.

§Creating a body

Bodies are created either by using a constructor function, or the Into trait. The into trait can be used where rust knows the result should be Body such as in the request builder .send().

use hreq::prelude::*;

let res = Request::post("https://post-to-server/")
    // send has Into<Body> type, which means we can
    // provide the Into type straight up
    .send("some body content")
    .block().unwrap();

Or if we use .into() explcitly.

use hreq::Body;

// call into() to get a Body
let body: Body = "some body content".into();

The constructor with corresponding expression usable with Into.

ConstructorInto
Body::empty()()
Body::from_str("abc")"abc"
Body::from_string("abc".to_string())"abc".to_string()
Body::from_bytes(&[42_u8, 43_u8])&[42_u8, 43_u8]
Body::from_vec(vec![42_u8, 43_u8])vec![42_u8, 43_u8]
Body::from_file(file)file
Body::from_async_read(reader, None)-
Body::from_sync_read(reader, None)-

§Readers and performance

The most performant way provide a large body is as an AsyncRead. It will be streamed through hreq without using up too much memory.

Sync readers risks blocking the async runtime. This is not a big concern if the reader is something like a std::io::Cursor over a slice of memory, or maybe even a std::fs::File with a fast disk.

§charset encoding

hreq automatically encodes the request body’s character encoding for MIME types starting text/.

The mechanic is triggered by setting a content-type request header with the charset that is wanted:

  • content-type: text/html charset=iso8859-1

The source material encoding is assumed to be utf-8 unless changed by charset_encode_source.

The behavior can be completely disabled using charset_encode.

§compression

hreq can compress the request body. The mechanic is triggered by setting a content-encoding header with the compression algorithm.

  • content-encoding: gzip

The only supported algorithm is gzip.

§Reading a body

hreq provides a number of ways to read the contents of a body.

Finaly Body implements AsyncRead, which means that in many cases, it can be used as is in rust’s async ecosystem.

use hreq::prelude::*;
use futures_util::io::AsyncReadExt;

let res = Request::get("https://my-special-host/")
    .call().block().unwrap();

let mut body = res.into_body();
let mut first_ten = vec![0_u8; 10];
// read_exact comes from AsyncReadExt
body.read_exact(&mut first_ten[..]).block().unwrap();

§charset decoding

hreq automatically decodes the response body’s character encoding for MIME types starting text/.

The mechanic is triggered by receving a content-type response header with the charset of the incoming body:

  • content-type: text/html charset=iso8859-1

The wanted charset is assumed to be utf-8 unless changed by charset_decode_target.

The function can be disabled by using charset_decode.

§compression

hreq decompresses the request body. The mechanic is triggered by the presence of a content-encoding: gzip response header.

One can “ask” the server to compress the response by providing a header like accept-encoding: gzip. There’s however no guarantee the server will provide compression.

The only supported algorithm is currently gzip.

Implementations§

Source§

impl Body

Source

pub fn empty() -> Self

Constructs an empty request body.

The content-length is know to be 0 and will be set for requests where a body is expected.

§Examples
use hreq::Body;

// The are the same.
let body1: Body = Body::empty();
let body2: Body = ().into();

In Request.send() we can skip the into()

use hreq::prelude::*;

Request::get("https://get-from-here")
    .call().block().unwrap();
Source

pub fn from_str(text: &str) -> Self

Creates a body from a &str by cloning the data.

Will automatically set a content-length header unless compression or chunked encoding is used.

§Examples
use hreq::Body;

// The are the same.
let body1: Body = Body::from_str("Hello world");
let body2: Body = "Hello world".into();

In Request.send() we can skip the into()

use hreq::prelude::*;

Request::post("https://post-to-here")
    .send("Hello world").block().unwrap();
Source

pub fn from_string(text: String) -> Self

Creates a body from a String.

Will automatically set a content-length header unless compression or chunked encoding is used.

§Examples
use hreq::Body;

// The are the same.
let body1: Body = Body::from_string("Hello world".to_string());
let body2: Body = "Hello world".to_string().into();

In Request.send() we can skip the into()

use hreq::prelude::*;

Request::post("https://post-to-here")
    .send("Hello world".to_string()).block().unwrap();
Source

pub fn from_bytes(bytes: &[u8]) -> Self

Creates a body from a &[u8] by cloning the data.

Will automatically set a content-length header unless compression or chunked encoding is used.

§Examples
use hreq::Body;

let data = [0x42, 0x43];

// The are the same.
let body1: Body = Body::from_bytes(&data[..]);
let body2: Body = (&data[..]).into();

In Request.send() we can skip the into()

use hreq::prelude::*;

let data = [0x42, 0x43];

Request::post("https://post-to-here")
    .send(&data[..]).block().unwrap();
Source

pub fn from_vec(bytes: Vec<u8>) -> Self

Creates a body from a Vec<u8>.

Will automatically set a content-length header unless compression or chunked encoding is used.

§Examples
use hreq::Body;

// The are the same.
let body1: Body = Body::from_vec(vec![0x42, 0x43]);
let body2: Body = vec![0x42, 0x43].into();

In Request.send() we can skip the into()

use hreq::prelude::*;

Request::post("https://post-to-here")
    .send(vec![0x42, 0x43]).block().unwrap();
Source

pub fn from_file(file: File) -> Self

Creates a body from a std::fs::File.

Despite the std origins, hreq will send this efficiently by reading the file in a non-blocking way.

The request will have a content-length header unless compression or chunked encoding is used. Uses content-type from the headers if set , and falls back to application/octet-stream.

§Examples
use hreq::Body;
use std::fs::File;

// The are the same.
let body1: Body = Body::from_file(File::open("myfile.txt").unwrap());
let body2: Body = File::open("myfile.txt").unwrap().into();

In Request.send() we can skip the into()

use hreq::prelude::*;
use std::fs::File;

Request::post("https://post-to-here")
    .send(File::open("myfile.txt").unwrap()).block().unwrap();
Source

pub fn from_json<B: Serialize + ?Sized>(json: &B) -> Self

Creates a body from a JSON encodable type.

This also sets the content-type and content-length headers.

§Example
use hreq::Body;
use serde_derive::Serialize;

#[derive(Serialize)]
struct MyJsonThing {
  name: String,
  age: u8,
}

let json = MyJsonThing {
  name: "Karl Kajal".to_string(),
  age: 32,
};

let body = Body::from_json(&json);
Source

pub fn from_async_read<R>(reader: R, length: Option<u64>) -> Self
where R: AsyncRead + Unpin + Send + Sync + 'static,

Creates a body from anything implementing the AsyncRead trait.

This is a very efficient way of sending bodies since the content

The content-length header will be set depending on whether a length is provided. Combinations of charset and compression might make it so content-length is not known despite being provided.

Source

pub fn from_sync_read<R>(reader: R, length: Option<u64>) -> Self
where R: Read + Send + Sync + 'static,

Creates a body from anything implementing the (blocking) std::io::Read trait.

Might block the async runtime, so whether using this is a good idea depends on circumstances. If the Read is just an std::io::Cursor over some memory or very fast file system, it might be ok.

Use with care.

The content-length header will be set depending on whether a length is provided. Combinations of charset and compression might make it so content-length is not known despite being provided.

Source

pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error>

Read some bytes from this body into the specified buffer, returning how many bytes were read.

If the returned amount is 0, the end of the body has been reached.

See charset_decode and charset_decode_target of headers and options that will affect text/ MIME types.

§Examples
use hreq::prelude::*;

let mut resp = Request::get("http://httpbin.org/html")
    .call().block().unwrap();

let mut data = vec![0_u8; 100];

let amount = resp.body_mut().read(&mut data[..]).block().unwrap();

assert!(amount >= 15);
assert_eq!(&data[..15], b"<!DOCTYPE html>");
Source

pub async fn read_to_vec(&mut self) -> Result<Vec<u8>, Error>

Reads to body to end into a new Vec.

This can potentially take up a lot of memory (or even exhaust your RAM), depending on how big the response body is.

See charset_decode and charset_decode_target of headers and options that will affect text/ MIME types.

§Examples
use hreq::prelude::*;

let mut resp = Request::get("http://httpbin.org/html")
    .call().block().unwrap();

let data = resp.body_mut().read_to_vec().block().unwrap();

assert_eq!(&data[..15], b"<!DOCTYPE html>");
Source

pub async fn read_to_string(&mut self) -> Result<String, Error>

Reads to body to end into a new String.

This can potentially take up a lot of memory (or even exhaust your RAM), depending on how big the response body is.

Since a rust string is always utf-8, charset_decode_target is ignored.

Panics if charset_decode is disabled and incoming data is not valid UTF-8.

§Examples
use hreq::prelude::*;

let mut resp = Request::get("http://httpbin.org/html")
    .call().block().unwrap();

let data = resp.body_mut().read_to_string().block().unwrap();

assert_eq!(&data[..15], "<!DOCTYPE html>");
Source

pub async fn read_to_json<T: DeserializeOwned>(&mut self) -> Result<T, Error>

Reads to body to end as a JSON string into a deserialized object.

§Examples
use hreq::Body;
use serde_derive::Deserialize;

#[derive(Deserialize)]
struct MyJsonThing {
  name: String,
  age: String,
}

let req: MyJsonThing = Request::get("http://foo")
  .call().block().unwrap()
  .read_json().unwrap();
Source

pub async fn read_and_discard(&mut self) -> Result<(), Error>

Reads to body to end and discards it.

HTTP/1.1 has no “multiplexing” of several concurrent request over the same socket; One must read the previous request’s body to end before being able to read the next response header.

For pooled connections we can’t reuse the connection until the previous body has been exhausted.

§Examples
use hreq::prelude::*;

let mut resp = Request::get("https://httpbin.org/get")
    .call().block().unwrap();

resp.body_mut().read_and_discard();

Trait Implementations§

Source§

impl AsyncRead for Body

Source§

fn poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8], ) -> Poll<Result<usize>>

Attempt to read from the AsyncRead into buf. Read more
Source§

fn poll_read_vectored( self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &mut [IoSliceMut<'_>], ) -> Poll<Result<usize, Error>>

Attempt to read from the AsyncRead into bufs using vectored IO operations. Read more
Source§

impl Debug for Body

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'a> From<&'a [u8]> for Body

Source§

fn from(bytes: &'a [u8]) -> Self

Converts to this type from the input type.
Source§

impl<'a> From<&'a String> for Body

Source§

fn from(s: &'a String) -> Self

Converts to this type from the input type.
Source§

impl<'a> From<&'a Vec<u8>> for Body

Source§

fn from(bytes: &'a Vec<u8>) -> Self

Converts to this type from the input type.
Source§

impl<'a> From<&'a str> for Body

Source§

fn from(s: &'a str) -> Self

Converts to this type from the input type.
Source§

impl From<()> for Body

Source§

fn from(_: ()) -> Self

Converts to this type from the input type.
Source§

impl From<Body> for Reply

Source§

fn from(v: Body) -> Self

Converts to this type from the input type.
Source§

impl From<File> for Body

Source§

fn from(file: File) -> Self

Converts to this type from the input type.
Source§

impl From<String> for Body

Source§

fn from(s: String) -> Self

Converts to this type from the input type.
Source§

impl From<Vec<u8>> for Body

Source§

fn from(bytes: Vec<u8>) -> Self

Converts to this type from the input type.

Auto Trait Implementations§

§

impl !Freeze for Body

§

impl !RefUnwindSafe for Body

§

impl Send for Body

§

impl Sync for Body

§

impl Unpin for Body

§

impl !UnwindSafe for Body

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<R> AsyncReadExt for R
where R: AsyncRead + ?Sized,

Source§

fn chain<R>(self, next: R) -> Chain<Self, R>
where Self: Sized, R: AsyncRead,

Creates an adaptor which will chain this stream with another. Read more
Source§

fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self>
where Self: Unpin,

Tries to read some bytes directly into the given buf in asynchronous manner, returning a future type. Read more
Source§

fn read_vectored<'a>( &'a mut self, bufs: &'a mut [IoSliceMut<'a>], ) -> ReadVectored<'a, Self>
where Self: Unpin,

Creates a future which will read from the AsyncRead into bufs using vectored IO operations. Read more
Source§

fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self>
where Self: Unpin,

Creates a future which will read exactly enough bytes to fill buf, returning an error if end of file (EOF) is hit sooner. Read more
Source§

fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec<u8>) -> ReadToEnd<'a, Self>
where Self: Unpin,

Creates a future which will read all the bytes from this AsyncRead. Read more
Source§

fn read_to_string<'a>( &'a mut self, buf: &'a mut String, ) -> ReadToString<'a, Self>
where Self: Unpin,

Creates a future which will read all the bytes from this AsyncRead. Read more
Source§

fn split(self) -> (ReadHalf<Self>, WriteHalf<Self>)
where Self: Sized + AsyncWrite,

Helper method for splitting this read/write object into two halves. Read more
Source§

fn take(self, limit: u64) -> Take<Self>
where Self: Sized,

Creates an AsyncRead adapter which will read at most limit bytes from the underlying reader. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FuturesAsyncReadCompatExt for T
where T: AsyncRead,

Source§

fn compat(self) -> Compat<Self>
where Self: Sized,

Wraps self with a compatibility layer that implements tokio_io::AsyncRead.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.