[go: up one dir, main page]

tide/
response.rs

1use std::convert::TryInto;
2use std::fmt::{Debug, Display};
3use std::ops::Index;
4
5use crate::http::cookies::Cookie;
6use crate::http::headers::{self, HeaderName, HeaderValues, ToHeaderValues};
7use crate::http::{self, Body, Error, Mime, StatusCode};
8use crate::ResponseBuilder;
9
10#[derive(Debug)]
11pub(crate) enum CookieEvent {
12    Added(Cookie<'static>),
13    Removed(Cookie<'static>),
14}
15
16/// An HTTP response
17#[derive(Debug)]
18pub struct Response {
19    pub(crate) res: http::Response,
20    pub(crate) error: Option<Error>,
21    // tracking here
22    pub(crate) cookie_events: Vec<CookieEvent>,
23}
24
25impl Response {
26    /// Create a new instance.
27    #[must_use]
28    pub fn new<S>(status: S) -> Self
29    where
30        S: TryInto<StatusCode>,
31        S::Error: Debug,
32    {
33        let res = http::Response::new(status);
34        Self {
35            res,
36            error: None,
37            cookie_events: vec![],
38        }
39    }
40
41    /// Begin a chained response builder. For more details, see [ResponseBuilder](crate::ResponseBuilder)
42    ///
43    /// # Example:
44    /// ```rust
45    /// # use tide::{StatusCode, Response, http::mime};
46    /// # async_std::task::block_on(async move {
47    /// let mut response = Response::builder(203)
48    ///     .body("<html>hi</html>")
49    ///     .header("custom-header", "value")
50    ///     .content_type(mime::HTML)
51    ///     .build();
52    ///
53    /// assert_eq!(response.take_body().into_string().await.unwrap(), "<html>hi</html>");
54    /// assert_eq!(response.status(), StatusCode::NonAuthoritativeInformation);
55    /// assert_eq!(response["custom-header"], "value");
56    /// assert_eq!(response["content-type"], "text/html;charset=utf-8");
57    /// # });
58    /// ```
59    #[must_use]
60    pub fn builder<S>(status: S) -> ResponseBuilder
61    where
62        S: TryInto<StatusCode>,
63        S::Error: Debug,
64    {
65        ResponseBuilder::new(status)
66    }
67
68    /// Returns the http status code.
69    #[must_use]
70    pub fn status(&self) -> crate::StatusCode {
71        self.res.status()
72    }
73
74    /// Set the http status code.
75    ///
76    /// # Example:
77    /// ```rust
78    /// # use tide::{StatusCode, Response};
79    /// let mut response = Response::new(StatusCode::Ok);
80    ///
81    /// response.set_status(418); // the status can be a valid u16 http status code
82    /// assert_eq!(response.status(), StatusCode::ImATeapot);
83    ///
84    /// response.set_status(StatusCode::NonAuthoritativeInformation); // or a tide::StatusCode
85    /// assert_eq!(response.status(), StatusCode::NonAuthoritativeInformation);
86    /// ```
87    /// # Panics
88    /// `set_status` will panic if the status argument cannot be successfully converted into a StatusCode.
89    ///
90    /// ```should_panic
91    /// # use tide::Response;
92    /// Response::new(200).set_status(210); // this is not an established status code and will panic
93    /// ```
94    pub fn set_status<S>(&mut self, status: S)
95    where
96        S: TryInto<StatusCode>,
97        S::Error: Debug,
98    {
99        let status = status
100            .try_into()
101            .expect("Could not convert into a valid `StatusCode`");
102
103        self.res.set_status(status);
104    }
105
106    /// Get the length of the body.
107    #[must_use]
108    pub fn len(&self) -> Option<usize> {
109        self.res.len()
110    }
111
112    /// Checks if the body is empty.
113    #[must_use]
114    pub fn is_empty(&self) -> Option<bool> {
115        Some(self.res.len()? == 0)
116    }
117
118    /// Get an HTTP header.
119    #[must_use]
120    pub fn header(&self, name: impl Into<HeaderName>) -> Option<&HeaderValues> {
121        self.res.header(name)
122    }
123
124    /// Get an HTTP header mutably.
125    #[must_use]
126    pub fn header_mut(&mut self, name: impl Into<HeaderName>) -> Option<&mut HeaderValues> {
127        self.res.header_mut(name)
128    }
129
130    /// Remove a header.
131    pub fn remove_header(&mut self, name: impl Into<HeaderName>) -> Option<HeaderValues> {
132        self.res.remove_header(name)
133    }
134
135    /// Insert an HTTP header.
136    pub fn insert_header(&mut self, key: impl Into<HeaderName>, value: impl ToHeaderValues) {
137        self.res.insert_header(key, value);
138    }
139
140    /// Append an HTTP header.
141    pub fn append_header(&mut self, key: impl Into<HeaderName>, value: impl ToHeaderValues) {
142        self.res.append_header(key, value);
143    }
144
145    /// An iterator visiting all header pairs in arbitrary order.
146    #[must_use]
147    pub fn iter(&self) -> headers::Iter<'_> {
148        self.res.iter()
149    }
150
151    /// An iterator visiting all header pairs in arbitrary order, with mutable references to the
152    /// values.
153    #[must_use]
154    pub fn iter_mut(&mut self) -> headers::IterMut<'_> {
155        self.res.iter_mut()
156    }
157
158    /// An iterator visiting all header names in arbitrary order.
159    #[must_use]
160    pub fn header_names(&self) -> headers::Names<'_> {
161        self.res.header_names()
162    }
163
164    /// An iterator visiting all header values in arbitrary order.
165    #[must_use]
166    pub fn header_values(&self) -> headers::Values<'_> {
167        self.res.header_values()
168    }
169
170    /// Get the response content type as a `Mime`.
171    ///
172    /// This gets the request `Content-Type` header.
173    ///
174    /// [Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types)
175    #[must_use]
176    pub fn content_type(&self) -> Option<Mime> {
177        self.res.content_type()
178    }
179
180    /// Set the response content type from a `MIME`.
181    ///
182    /// This sets the response `Content-Type` header.
183    ///
184    /// [Read more on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types)
185    pub fn set_content_type(&mut self, mime: impl Into<Mime>) {
186        self.res.set_content_type(mime.into());
187    }
188
189    /// Set the body reader.
190    pub fn set_body(&mut self, body: impl Into<Body>) {
191        self.res.set_body(body);
192    }
193
194    /// Take the response body as a `Body`.
195    ///
196    /// This method can be called after the body has already been taken or read,
197    /// but will return an empty `Body`.
198    ///
199    /// Useful for adjusting the whole body, such as in middleware.
200    pub fn take_body(&mut self) -> Body {
201        self.res.take_body()
202    }
203
204    /// Swaps the value of the body with another body, without deinitializing
205    /// either one.
206    ///
207    /// # Examples
208    ///
209    /// ```
210    /// # use async_std::io::prelude::*;
211    /// # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
212    /// # async_std::task::block_on(async {
213    /// #
214    /// use tide::Response;
215    ///
216    /// let mut req = Response::new(200);
217    /// req.set_body("Hello, Nori!");
218    ///
219    /// let mut body = "Hello, Chashu!".into();
220    /// req.swap_body(&mut body);
221    ///
222    /// let mut string = String::new();
223    /// body.read_to_string(&mut string).await?;
224    /// assert_eq!(&string, "Hello, Nori!");
225    /// #
226    /// # Ok(()) }) }
227    /// ```
228    pub fn swap_body(&mut self, body: &mut Body) {
229        self.res.swap_body(body)
230    }
231
232    /// Insert cookie in the cookie jar.
233    pub fn insert_cookie(&mut self, cookie: Cookie<'static>) {
234        self.cookie_events.push(CookieEvent::Added(cookie));
235    }
236
237    /// Removes the cookie. This instructs the `CookiesMiddleware` to send a cookie with empty value
238    /// in the response.
239    ///
240    /// ## Warning
241    /// Take care when calling this function with a cookie that was returned by
242    /// [`Request::cookie`](crate::Request::cookie).  As per [section 5.3 step 11 of RFC 6265], a new
243    /// cookie is only treated as the same as an old one if it has a matching name, domain and
244    /// path.
245    ///
246    /// The domain and path are not sent to the server on subsequent HTTP requests, so if a cookie
247    /// was originally set with a domain and/or path, calling this function on a cookie with the
248    /// same name but with either a different, or no, domain and/or path will lead to us sending an
249    /// empty cookie that the user agent will treat as unrelated to the original one, and will thus
250    /// not remove the old one.
251    ///
252    /// To avoid this you can manually set the [domain](Cookie::set_domain) and
253    /// [path](Cookie::set_path) as necessary after retrieving the cookie using
254    /// [`Request::cookie`](crate::Request::cookie).
255    ///
256    /// [section 5.3 step 11 of RFC 6265]: https://tools.ietf.org/html/rfc6265#section-5.3
257    pub fn remove_cookie(&mut self, cookie: Cookie<'static>) {
258        self.cookie_events.push(CookieEvent::Removed(cookie));
259    }
260
261    /// Returns an optional reference to an error if the response contains one.
262    pub fn error(&self) -> Option<&Error> {
263        self.error.as_ref()
264    }
265
266    /// Returns a reference to the original error associated with this response if there is one and
267    /// if it can be downcast to the specified type.
268    ///
269    /// # Example
270    ///
271    /// ```
272    /// # use std::io::ErrorKind;
273    /// # use async_std::task::block_on;
274    /// # fn main() -> Result<(), std::io::Error> { block_on(async {
275    /// #
276    /// use tide::Response;
277    ///
278    /// let error = std::io::Error::new(ErrorKind::Other, "oh no!");
279    /// let error = tide::http::Error::from(error);
280    ///
281    /// let mut res = Response::new(400);
282    /// res.set_error(error);
283    ///
284    /// if let Some(err) = res.downcast_error::<std::io::Error>() {
285    ///   // Do something with the `std::io::Error`.
286    /// }
287    /// # Ok(())
288    /// # })}
289    pub fn downcast_error<E>(&self) -> Option<&E>
290    where
291        E: Display + Debug + Send + Sync + 'static,
292    {
293        self.error.as_ref()?.downcast_ref()
294    }
295
296    /// Takes the error from the response if one exists, replacing it with `None`.
297    pub fn take_error(&mut self) -> Option<Error> {
298        self.error.take()
299    }
300
301    /// Sets the response's error, overwriting any existing error.
302    ///
303    /// This is particularly useful for middleware which would like to notify further
304    /// middleware that an error has occured without overwriting the existing response.
305    pub fn set_error(&mut self, error: impl Into<Error>) {
306        self.error = Some(error.into());
307    }
308
309    /// Get a response scoped extension value.
310    #[must_use]
311    pub fn ext<T: Send + Sync + 'static>(&self) -> Option<&T> {
312        self.res.ext().get()
313    }
314
315    /// Set a response scoped extension value.
316    pub fn insert_ext<T: Send + Sync + 'static>(&mut self, val: T) {
317        self.res.ext_mut().insert(val);
318    }
319
320    /// Create a `tide::Response` from a type that can be converted into an
321    /// `http_types::Response`.
322    pub fn from_res<T>(value: T) -> Self
323    where
324        T: Into<http_types::Response>,
325    {
326        let res: http_types::Response = value.into();
327        Self {
328            res,
329            error: None,
330            cookie_events: vec![],
331        }
332    }
333}
334
335impl AsRef<http::Response> for Response {
336    fn as_ref(&self) -> &http::Response {
337        &self.res
338    }
339}
340
341impl AsMut<http::Response> for Response {
342    fn as_mut(&mut self) -> &mut http::Response {
343        &mut self.res
344    }
345}
346
347impl AsRef<http::Headers> for Response {
348    fn as_ref(&self) -> &http::Headers {
349        self.res.as_ref()
350    }
351}
352
353impl AsMut<http::Headers> for Response {
354    fn as_mut(&mut self) -> &mut http::Headers {
355        self.res.as_mut()
356    }
357}
358
359impl Into<http::Response> for Response {
360    fn into(self) -> http_types::Response {
361        self.res
362    }
363}
364
365impl From<http::Body> for Response {
366    fn from(body: http::Body) -> Self {
367        let mut res = Response::new(200);
368        res.set_body(body);
369        res
370    }
371}
372
373impl From<serde_json::Value> for Response {
374    fn from(json_value: serde_json::Value) -> Self {
375        Body::from_json(&json_value)
376            .map(|body| body.into())
377            .unwrap_or_else(|_| Response::new(StatusCode::InternalServerError))
378    }
379}
380
381impl From<Error> for Response {
382    fn from(err: Error) -> Self {
383        Self {
384            res: http::Response::new(err.status()),
385            error: Some(err),
386            cookie_events: vec![],
387        }
388    }
389}
390
391impl From<http::Response> for Response {
392    fn from(res: http::Response) -> Self {
393        Self {
394            res,
395            error: None,
396            cookie_events: vec![],
397        }
398    }
399}
400
401impl From<StatusCode> for Response {
402    fn from(status: StatusCode) -> Self {
403        let res: http::Response = status.into();
404        res.into()
405    }
406}
407
408impl From<String> for Response {
409    fn from(s: String) -> Self {
410        Body::from_string(s).into()
411    }
412}
413
414impl<'a> From<&'a str> for Response {
415    fn from(s: &'a str) -> Self {
416        Body::from_string(String::from(s)).into()
417    }
418}
419
420impl IntoIterator for Response {
421    type Item = (HeaderName, HeaderValues);
422    type IntoIter = http_types::headers::IntoIter;
423
424    /// Returns a iterator of references over the remaining items.
425    #[inline]
426    fn into_iter(self) -> Self::IntoIter {
427        self.res.into_iter()
428    }
429}
430
431impl<'a> IntoIterator for &'a Response {
432    type Item = (&'a HeaderName, &'a HeaderValues);
433    type IntoIter = http_types::headers::Iter<'a>;
434
435    #[inline]
436    fn into_iter(self) -> Self::IntoIter {
437        self.res.iter()
438    }
439}
440
441impl<'a> IntoIterator for &'a mut Response {
442    type Item = (&'a HeaderName, &'a mut HeaderValues);
443    type IntoIter = http_types::headers::IterMut<'a>;
444
445    #[inline]
446    fn into_iter(self) -> Self::IntoIter {
447        self.res.iter_mut()
448    }
449}
450
451impl Index<HeaderName> for Response {
452    type Output = HeaderValues;
453
454    /// Returns a reference to the value corresponding to the supplied name.
455    ///
456    /// # Panics
457    ///
458    /// Panics if the name is not present in `Response`.
459    #[inline]
460    fn index(&self, name: HeaderName) -> &HeaderValues {
461        &self.res[name]
462    }
463}
464
465impl Index<&str> for Response {
466    type Output = HeaderValues;
467
468    /// Returns a reference to the value corresponding to the supplied name.
469    ///
470    /// # Panics
471    ///
472    /// Panics if the name is not present in `Response`.
473    #[inline]
474    fn index(&self, name: &str) -> &HeaderValues {
475        &self.res[name]
476    }
477}