Skip to main content

ResponseBody

Struct ResponseBody 

Source
pub struct ResponseBody<'a> { /* private fields */ }
Expand description

A response body received from a server.

Most of the time this represents a body that will be read from the underlying transport, but it can also wrap an override body installed by middleware via ConnExt::set_response_body — e.g. cache hits, mocked responses, or circuit-breaker short-circuits. Reads, encoding handling, and max_len enforcement work transparently across both cases.

use trillium_client::Client;
use trillium_testing::{client_config, with_server};

with_server("hello from trillium", |url| async move {
    let client = Client::new(client_config());
    let mut conn = client.get(url).await?;
    let body = conn.response_body(); //<-
    assert_eq!(Some(19), body.content_length());
    assert_eq!("hello from trillium", body.read_string().await?);
    Ok(())
});

§Bounds checking

Every ResponseBody has a maximum length beyond which it will return an error, expressed as a u64. To override this on the specific ResponseBody, use ResponseBody::with_max_len or ResponseBody::set_max_len. The bound is enforced on override bodies as well as transport-backed ones, so a user-set memory cap holds even when middleware has replaced the body with externally-sourced bytes.

Implementations§

Source§

impl ResponseBody<'_>

Source

pub async fn read_bytes(self) -> Result<Vec<u8>, Error>

Similar to ResponseBody::read_string, but returns the raw bytes. This is useful for bodies that are not text.

You can use this in conjunction with encoding if you need different handling of malformed character encoding than the lossy conversion provided by ResponseBody::read_string.

An empty or nonexistent body will yield an empty Vec, not an error.

§Errors

This will return an error if there is an IO error on the underlying transport such as a disconnect.

This will also return an error if the length exceeds the maximum length. To configure the value on this specific request body, use ResponseBody::with_max_len or ResponseBody::set_max_len

Source

pub async fn read_string(self) -> Result<String, Error>

Reads the entire body to a String.

Uses the encoding determined by the content-type (mime) charset. If an encoding problem is encountered, the returned String will contain utf8 replacement characters.

Note that this can only be performed once per Conn, as the underlying data is not cached anywhere. This is the only copy of the body contents.

An empty or nonexistent body will yield an empty String, not an error

§Errors

This will return an error if there is an IO error on the underlying transport such as a disconnect

This will also return an error if the length exceeds the maximum length. To configure the value on this specific response body, use ResponseBody::with_max_len or ResponseBody::set_max_len.

Source

pub fn with_max_len(self, max_len: u64) -> Self

Set the maximum content length to read, returning self

This protects against a memory-use denial-of-service attack wherein an untrusted peer sends an unbounded request body. This is especially important when using ResponseBody::read_string and ResponseBody::read_bytes instead of streaming with AsyncRead.

The default value can be found documented in the trillium-http crate

Source

pub fn set_max_len(&mut self, max_len: u64) -> &mut Self

Set the maximum content length to read

This protects against a memory-use denial-of-service attack wherein an untrusted peer sends an unbounded request body. This is especially important when using ResponseBody::read_string and ResponseBody::read_bytes instead of streaming with AsyncRead.

The default value can be found documented in the trillium-http crate

Source

pub fn content_length(&self) -> Option<u64>

The content-length of this body, if available.

Usually derived from the content-length header. If the response uses transfer-encoding chunked, this will be None.

Source§

impl ResponseBody<'static>

Source

pub async fn recycle(self)

Drains and pools the underlying transport when worthwhile, closes it otherwise.

Use this to release a keepalive transport synchronously before reissuing a request on the same client — the redirect/retry handler pattern. For an h1.1 keepalive transport this drives the body to EOF and returns the transport to the pool. For a non-keepalive transport this calls transport.close() directly without draining (since draining would just waste bytes on a connection we’re about to close).

For an Override body (cache hit, mocked response, tee), this is a no-op — the body’s own components handle their own teardown when dropped.

Trait Implementations§

Source§

impl AsyncRead for ResponseBody<'_>

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 BodySource for ResponseBody<'static>

Source§

fn trailers(self: Pin<&mut Self>) -> Option<Headers>

Returns the trailers for this body, called after the body has been fully read. Read more
Source§

impl Debug for ResponseBody<'_>

Source§

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

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

impl Drop for ResponseBody<'_>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<'a> From<ReceivedBody<'a, Box<dyn Transport>>> for ResponseBody<'a>

Source§

fn from(received_body: ReceivedBody<'a, Box<dyn Transport>>) -> Self

Converts to this type from the input type.
Source§

impl<'a> IntoFuture for ResponseBody<'a>

Source§

type IntoFuture = Pin<Box<dyn Future<Output = <ResponseBody<'a> as IntoFuture>::Output> + Send + 'a>>

Which kind of future are we turning this into?
Source§

type Output = Result<String, Error>

The output that the future will produce on completion.
Source§

fn into_future(self) -> Self::IntoFuture

Creates a future from a value. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for ResponseBody<'a>

§

impl<'a> !RefUnwindSafe for ResponseBody<'a>

§

impl<'a> Send for ResponseBody<'a>

§

impl<'a> Sync for ResponseBody<'a>

§

impl<'a> Unpin for ResponseBody<'a>

§

impl<'a> UnsafeUnpin for ResponseBody<'a>

§

impl<'a> !UnwindSafe for ResponseBody<'a>

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 read<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadFuture<'a, Self>
where Self: Unpin,

Reads some bytes from the byte stream. Read more
Source§

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

Like read(), except it reads into a slice of buffers. Read more
Source§

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

Reads the entire contents and appends them to a Vec. Read more
Source§

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

Reads the entire contents and appends them to a String. Read more
Source§

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

Reads the exact number of bytes required to fill buf. Read more
Source§

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

Creates an adapter which will read at most limit bytes from it. Read more
Source§

fn bytes(self) -> Bytes<Self>
where Self: Sized,

Converts this AsyncRead into a Stream of bytes. Read more
Source§

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

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

fn boxed_reader<'a>(self) -> Pin<Box<dyn AsyncRead + Send + 'a>>
where Self: Sized + Send + 'a,

Available on crate feature alloc only.
Boxes the reader and changes its type to dyn AsyncRead + Send + 'a. 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, 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> Same for T

Source§

type Output = T

Should always be Self
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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V