1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
use std::io;
use tokio::io::AsyncReadExt;
use crate::{Response, local::asynchronous, http::CookieJar};
use super::Client;
/// A `blocking` response from a dispatched [`LocalRequest`](super::LocalRequest).
///
/// This `LocalResponse` implements [`io::Read`]. As such, if
/// [`into_string()`](LocalResponse::into_string()) and
/// [`into_bytes()`](LocalResponse::into_bytes()) do not suffice, the response's
/// body can be read directly:
///
/// ```rust
/// # #[macro_use] extern crate rocket;
/// use std::io::{self, Read};
///
/// use rocket::local::blocking::Client;
/// use rocket::http::Status;
///
/// #[get("/")]
/// fn hello_world() -> &'static str {
/// "Hello, world!"
/// }
///
/// #[launch]
/// fn rocket() -> _ {
/// rocket::build().mount("/", routes![hello_world])
/// # .reconfigure(rocket::Config::debug_default())
/// }
///
/// # fn read_body_manually() -> io::Result<()> {
/// // Dispatch a `GET /` request.
/// let client = Client::tracked(rocket()).expect("valid rocket");
/// let mut response = client.get("/").dispatch();
///
/// // Check metadata validity.
/// assert_eq!(response.status(), Status::Ok);
/// assert_eq!(response.body().preset_size(), Some(13));
///
/// // Read 10 bytes of the body. Note: in reality, we'd use `into_string()`.
/// let mut buffer = [0; 10];
/// response.read(&mut buffer)?;
/// assert_eq!(buffer, "Hello, wor".as_bytes());
/// # Ok(())
/// # }
/// # read_body_manually().expect("read okay");
/// ```
///
/// For more, see [the top-level documentation](../index.html#localresponse).
pub struct LocalResponse<'c> {
pub(in super) inner: asynchronous::LocalResponse<'c>,
pub(in super) client: &'c Client,
}
impl LocalResponse<'_> {
fn _response(&self) -> &Response<'_> {
self.inner._response()
}
pub(crate) fn _cookies(&self) -> &CookieJar<'_> {
self.inner._cookies()
}
fn _into_string(self) -> io::Result<String> {
self.client.block_on(self.inner._into_string())
}
fn _into_bytes(self) -> io::Result<Vec<u8>> {
self.client.block_on(self.inner._into_bytes())
}
#[cfg(feature = "json")]
fn _into_json<T: Send + 'static>(self) -> Option<T>
where T: serde::de::DeserializeOwned
{
serde_json::from_reader(self).ok()
}
#[cfg(feature = "msgpack")]
fn _into_msgpack<T: Send + 'static>(self) -> Option<T>
where T: serde::de::DeserializeOwned
{
rmp_serde::from_read(self).ok()
}
// Generates the public API methods, which call the private methods above.
pub_response_impl!("# use rocket::local::blocking::Client;\n\
use rocket::local::blocking::LocalResponse;");
}
impl io::Read for LocalResponse<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.client.block_on(self.inner.read(buf))
}
}
impl std::fmt::Debug for LocalResponse<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self._response().fmt(f)
}
}