pub struct Body { /* private fields */ }
Expand description
A response body returned as http::Response<Body>
.
§Default size limit
Methods like read_to_string()
, read_to_vec()
, and read_json()
have a default 10MB limit
to prevent memory exhaustion. To download larger files, use with_config().limit(new_size)
:
// Download a 20MB file
let bytes = ureq::get("http://httpbin.org/bytes/200000000")
.call()?
.body_mut()
.with_config()
.limit(20 * 1024 * 1024) // 20MB
.read_to_vec()?;
§Body lengths
HTTP/1.1 has two major modes of transfering body data. Either a Content-Length
header defines exactly how many bytes to transfer, or Transfer-Encoding: chunked
facilitates a streaming style when the size is not known up front.
To protect against a problem called request smuggling, ureq has heuristics for
how to interpret a server sending both Transfer-Encoding
and Content-Length
headers.
chunked
takes precedence if there both headers are present (not for HTTP/1.0)content-length
is used if there is no chunked- If there are no headers, fall back on “close delimited” meaning the socket must close to end the body
When a Content-Length
header is used, ureq will ensure the received body is EXACTLY
as many bytes as declared (it cannot be less). This mechanic is in ureq-proto
and is different to the BodyWithConfig::limit()
below.
§Pool reuse
To return a connection (aka Transport
)
to the Agent’s pool, the body must be read to end. If BodyWithConfig::limit()
is set
shorter size than the actual response body, the connection will not be reused.
§Example
use std::io::Read;
let mut res = ureq::get("http://httpbin.org/bytes/100")
.call()?;
assert!(res.headers().contains_key("Content-Length"));
let len: usize = res.headers().get("Content-Length")
.unwrap().to_str().unwrap().parse().unwrap();
let mut bytes: Vec<u8> = Vec::with_capacity(len);
res.body_mut().as_reader()
.read_to_end(&mut bytes)?;
assert_eq!(bytes.len(), len);
Implementations§
Source§impl Body
impl Body
Sourcepub fn builder() -> BodyBuilder
pub fn builder() -> BodyBuilder
Builder for creating a body
This is useful for testing, or for Middleware
that
returns another body than the requested one.
Sourcepub fn mime_type(&self) -> Option<&str>
pub fn mime_type(&self) -> Option<&str>
The mime-type of the content-type
header.
For the below header, we would get Some("text/plain")
:
Content-Type: text/plain; charset=iso-8859-1
Caution: A bad server might set Content-Type
to one thing and send
something else. There is no way ureq can verify this.
§Example
let res = ureq::get("https://www.google.com/")
.call()?;
assert_eq!(res.body().mime_type(), Some("text/html"));
Sourcepub fn charset(&self) -> Option<&str>
pub fn charset(&self) -> Option<&str>
The charset of the content-type
header.
For the below header, we would get Some("iso-8859-1")
:
Content-Type: text/plain; charset=iso-8859-1
Caution: A bad server might set Content-Type
to one thing and send
something else. There is no way ureq can verify this.
§Example
let res = ureq::get("https://www.google.com/")
.call()?;
assert_eq!(res.body().charset(), Some("ISO-8859-1"));
Sourcepub fn content_length(&self) -> Option<u64>
pub fn content_length(&self) -> Option<u64>
The content length of the body.
This is the value of the Content-Length
header, if there is one. For chunked
responses (Transfer-Encoding: chunked
) , this will be None
. Similarly for
HTTP/1.0 without a Content-Length
header, the response is close delimited,
which means the length is unknown.
A bad server might set Content-Length
to one thing and send something else.
ureq will double check this, see section on body length heuristics.
§Example
let res = ureq::get("https://httpbin.org/bytes/100")
.call()?;
assert_eq!(res.body().content_length(), Some(100));
Sourcepub fn as_reader(&mut self) -> BodyReader<'_> ⓘ
pub fn as_reader(&mut self) -> BodyReader<'_> ⓘ
Handle this body as a shared impl Read
of the body.
This is the regular API which goes via http::Response::body_mut()
to get a
mut reference to the Body
, and then use as_reader()
. It is also possible to
get a non-shared, owned reader via Body::into_reader()
.
- Reader is not limited by default. That means a malicious server could
exhaust all avaliable memory on your client machine.
To set a limit use
Body::into_with_config()
. - Reader will error if
Content-Length
is set, but the connection is closed before all bytes are received.
§Example
use std::io::Read;
let mut res = ureq::get("http://httpbin.org/bytes/100")
.call()?;
let mut bytes: Vec<u8> = Vec::with_capacity(1000);
res.body_mut().as_reader()
.read_to_end(&mut bytes)?;
Sourcepub fn into_reader(self) -> BodyReader<'static> ⓘ
pub fn into_reader(self) -> BodyReader<'static> ⓘ
Turn this response into an owned impl Read
of the body.
Sometimes it might be useful to disconnect the body reader from the body.
The reader returned by Body::as_reader()
borrows the body, while this
variant consumes the body and turns it into a reader with lifetime 'static
.
The reader can for instance be sent to another thread.
- Reader is not limited by default. That means a malicious server could
exhaust all avaliable memory on your client machine.
To set a limit use
Body::into_with_config()
. - Reader will error if
Content-Length
is set, but the connection is closed before all bytes are received.
use std::io::Read;
let res = ureq::get("http://httpbin.org/bytes/100")
.call()?;
let (_, body) = res.into_parts();
let mut bytes: Vec<u8> = Vec::with_capacity(1000);
body.into_reader()
.read_to_end(&mut bytes)?;
Sourcepub fn read_to_string(&mut self) -> Result<String, Error>
pub fn read_to_string(&mut self) -> Result<String, Error>
Read the response as a string.
- Response is limited to 10MB
- Replaces incorrect utf-8 chars to
?
To change these defaults use Body::with_config()
.
let mut res = ureq::get("http://httpbin.org/robots.txt")
.call()?;
let s = res.body_mut().read_to_string()?;
assert_eq!(s, "User-agent: *\nDisallow: /deny\n");
For larger text files, you must explicitly increase the limit:
// Read a large text file (25MB)
let text = ureq::get("http://httpbin.org/get")
.call()?
.body_mut()
.with_config()
.limit(25 * 1024 * 1024) // 25MB
.read_to_string()?;
Sourcepub fn read_to_vec(&mut self) -> Result<Vec<u8>, Error>
pub fn read_to_vec(&mut self) -> Result<Vec<u8>, Error>
Read the response to a vec.
- Response is limited to 10MB.
To change this default use Body::with_config()
.
let mut res = ureq::get("http://httpbin.org/bytes/100")
.call()?;
let bytes = res.body_mut().read_to_vec()?;
assert_eq!(bytes.len(), 100);
For larger files, you must explicitly increase the limit:
// Download a larger file (50MB)
let bytes = ureq::get("http://httpbin.org/bytes/200000000")
.call()?
.body_mut()
.with_config()
.limit(50 * 1024 * 1024) // 50MB
.read_to_vec()?;
Sourcepub fn read_json<T: DeserializeOwned>(&mut self) -> Result<T, Error>
pub fn read_json<T: DeserializeOwned>(&mut self) -> Result<T, Error>
Read the response from JSON.
- Response is limited to 10MB.
To change this default use Body::with_config()
.
The returned value is something that derives Deserialize
.
You might need to be explicit with which type you want. See example below.
use serde::Deserialize;
#[derive(Deserialize)]
struct BodyType {
slideshow: BodyTypeInner,
}
#[derive(Deserialize)]
struct BodyTypeInner {
author: String,
}
let body = ureq::get("https://httpbin.org/json")
.call()?
.body_mut()
.read_json::<BodyType>()?;
assert_eq!(body.slideshow.author, "Yours Truly");
For larger JSON files, you must explicitly increase the limit:
use serde_json::Value;
// Parse a large JSON file (30MB)
let json: Value = ureq::get("https://httpbin.org/json")
.call()?
.body_mut()
.with_config()
.limit(30 * 1024 * 1024) // 30MB
.read_json()?;
Sourcepub fn with_config(&mut self) -> BodyWithConfig<'_>
pub fn with_config(&mut self) -> BodyWithConfig<'_>
Read the body data with configuration.
This borrows the body which gives easier use with http::Response::body_mut()
.
To get a non-borrowed reader use Body::into_with_config()
.
§Example
let reader = ureq::get("http://httpbin.org/bytes/100")
.call()?
.body_mut()
.with_config()
// Reader will only read 50 bytes
.limit(50)
.reader();
Sourcepub fn into_with_config(self) -> BodyWithConfig<'static>
pub fn into_with_config(self) -> BodyWithConfig<'static>
Consume self and read the body with configuration.
This consumes self and returns a reader with 'static
lifetime.
§Example
// Get the body out of http::Response
let (_, body) = ureq::get("http://httpbin.org/bytes/100")
.call()?
.into_parts();
let reader = body
.into_with_config()
// Reader will only read 50 bytes
.limit(50)
.reader();
This limit behavior can be used to prevent a malicious server from exhausting memory on the client machine. For example, if the machine running ureq has 1GB of RAM, you could protect the machine by setting a smaller limit such as 128MB. The exact number will vary by your client’s download needs, available system resources, and system utilization.