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}