rocket/local/blocking/
response.rs

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