rocket_community/response/
responder.rs

1use std::fs::File;
2use std::io::Cursor;
3use std::sync::Arc;
4
5use crate::http::{ContentType, Status, StatusClass};
6use crate::request::Request;
7use crate::response::{self, Response};
8
9/// Trait implemented by types that generate responses for clients.
10///
11/// Any type that implements `Responder` can be used as the return type of a
12/// handler:
13///
14/// ```rust
15/// # #[macro_use] extern crate rocket_community as rocket;
16/// # type T = ();
17/// #
18/// // This works for any `T` that implements `Responder`.
19/// #[get("/")]
20/// fn index() -> T { /* ... */ }
21/// ```
22///
23/// # Deriving
24///
25/// This trait can, and largely _should_, be automatically derived. The derive
26/// can handle all simple cases and most complex cases, too. When deriving
27/// `Responder`, the first field of the annotated structure (or of each variant
28/// if an `enum`) is used to generate a response while the remaining fields are
29/// used as response headers:
30///
31/// ```rust
32/// # #[macro_use] extern crate rocket_community as rocket;
33/// # #[cfg(feature = "json")] mod _main {
34/// # type Template = String;
35/// use rocket::http::ContentType;
36/// use rocket::serde::{Serialize, json::Json};
37///
38/// #[derive(Responder)]
39/// enum Error<T> {
40///     #[response(status = 400)]
41///     Unauthorized(Json<T>),
42///     #[response(status = 404)]
43///     NotFound(Template, ContentType),
44/// }
45/// # }
46/// ```
47///
48/// For full details on deriving `Responder`, see the [`Responder` derive].
49///
50/// [`Responder` derive]: derive@crate::Responder
51///
52/// # Provided Implementations
53///
54/// Rocket implements `Responder` for several standard library types. Their
55/// behavior is documented here. Note that the `Result` implementation is
56/// overloaded, allowing for two `Responder`s to be used at once, depending on
57/// the variant.
58///
59///   * **&str**
60///
61///     Sets the `Content-Type` to `text/plain`. The string is used as the body
62///     of the response, which is fixed size and not streamed. To stream a raw
63///     string, use `Stream::from(Cursor::new(string))`.
64///
65///   * **String**
66///
67///     Sets the `Content-Type` to `text/plain`. The string is used as the body
68///     of the response, which is fixed size and not streamed. To stream a
69///     string, use `Stream::from(Cursor::new(string))`.
70///
71///   * **&\[u8\]**
72///
73///     Sets the `Content-Type` to `application/octet-stream`. The slice
74///     is used as the body of the response, which is fixed size and not
75///     streamed. To stream a slice of bytes, use
76///     `Stream::from(Cursor::new(data))`.
77///
78///   * **Vec&lt;u8>**
79///
80///     Sets the `Content-Type` to `application/octet-stream`. The vector's data
81///     is used as the body of the response, which is fixed size and not
82///     streamed. To stream a vector of bytes, use
83///     `Stream::from(Cursor::new(vec))`.
84///
85///   * **File**
86///
87///     Responds with a streamed body containing the data in the `File`. No
88///     `Content-Type` is set. To automatically have a `Content-Type` set based
89///     on the file's extension, use [`NamedFile`](crate::fs::NamedFile).
90///
91///   * **()**
92///
93///     Responds with an empty body. No `Content-Type` is set.
94///
95///   * **Option&lt;T>**
96///
97///     If the `Option` is `Some`, the wrapped responder is used to respond to
98///     the client. Otherwise, an `Err` with status **404 Not Found** is
99///     returned and a warning is printed to the console.
100///
101///   * **Result&lt;T, E>**
102///
103///     If the `Result` is `Ok`, the wrapped `Ok` responder is used to respond
104///     to the client. If the `Result` is `Err`, the wrapped `Err` responder is
105///     used to respond to the client.
106///
107/// # Return Value
108///
109/// A `Responder` returns a `Result<Response, Status>`.
110///
111///   * An `Ok(Response)` indicates success. The `Response` will be written out
112///     to the client.
113///
114///   * An `Err(Status)` indicates an error. The error catcher for `Status` will
115///     be invoked to generate a response.
116///
117/// # Implementation Tips
118///
119/// This section describes a few best practices to take into account when
120/// implementing `Responder`.
121///
122/// 1. Avoid Manual Implementations
123///
124///    The [`Responder` derive] is a powerful mechanism that eliminates the need
125///    to implement `Responder` in almost all cases. We encourage you to explore
126///    using the derive _before_ attempting to implement `Responder` directly.
127///    It allows you to leverage existing `Responder` implementations through
128///    composition, decreasing the opportunity for mistakes or performance
129///    degradation.
130///
131/// 2. Joining and Merging
132///
133///    When chaining/wrapping other `Responder`s, start with
134///    [`Response::build_from()`] and/or use the [`merge()`](Response::merge())
135///    or [`join()`](Response::join()) methods on the `Response` or
136///    `ResponseBuilder` struct. Ensure that you document merging or joining
137///    behavior appropriately.
138///
139/// 3. Inspecting Requests
140///
141///    While tempting, a `Responder` that varies its functionality based on the
142///    incoming request sacrifices its functionality being understood based
143///    purely on its type. By implication, gleaning the functionality of a
144///    _handler_ from its type signature also becomes more difficult. You should
145///    avoid varying responses based on the `Request` value as much as possible.
146///
147/// 4. Perform `async` I/O in Constructors
148///
149///    The `Responder` trait is not an `async` trait. This is not an oversight.
150///    Instead of performing `async` operations in what would be the
151///    `respond_to` method, perform them in a constructor for the responder. As
152///    an example, see [`NamedFile::open()`](crate::fs::NamedFile::open()),
153///    which performs the requisite I/O for `NamedFile`'s responder.
154///
155/// ## Lifetimes
156///
157/// `Responder` has two lifetimes: `Responder<'r, 'o: 'r>`.
158///
159///   * `'r` bounds the reference to the `&'r Request`.
160///
161///   * `'o` bounds the returned `Response<'o>` to values that live at least as
162///     long as the request.
163///
164///     This includes borrows from the `Request` itself (where `'o` would be
165///     `'r` as in `impl<'r> Responder<'r, 'r>`) as well as `'static` data
166///     (where `'o` would be `'static` as in `impl<'r> Responder<'r, 'static>`).
167///
168/// In practice, you are likely choosing between four signatures:
169///
170/// ```rust
171/// # extern crate rocket_community as rocket;
172/// # use rocket::request::Request;
173/// # use rocket::response::{self, Responder};
174/// # struct A;
175/// // If the response contains no borrowed data.
176/// impl<'r> Responder<'r, 'static> for A {
177///     fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
178///         todo!()
179///     }
180/// }
181///
182/// # struct B<'r>(&'r str);
183/// // If the response borrows from the request.
184/// impl<'r> Responder<'r, 'r> for B<'r> {
185///     fn respond_to(self, _: &'r Request<'_>) -> response::Result<'r> {
186///         todo!()
187///     }
188/// }
189///
190/// # struct C;
191/// // If the response is or wraps a borrow that may outlive the request.
192/// impl<'r, 'o: 'r> Responder<'r, 'o> for &'o C {
193///     fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> {
194///         todo!()
195///     }
196/// }
197///
198/// # struct D<R>(R);
199/// // If the response wraps an existing responder.
200/// impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for D<R> {
201///     fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> {
202///         todo!()
203///     }
204/// }
205/// ```
206///
207/// # Example
208///
209/// Say that you have a custom type, `Person`:
210///
211/// ```rust
212/// struct Person {
213///     name: String,
214///     age: u16
215/// }
216/// ```
217///
218/// You'd like to use `Person` as a `Responder` so that you can return a
219/// `Person` directly from a handler:
220///
221/// ```rust
222/// # #[macro_use] extern crate rocket_community as rocket;
223/// # type Person = String;
224/// #[get("/person/<id>")]
225/// fn person(id: usize) -> Option<Person> {
226///     # /*
227///     Person::from_id(id)
228///     # */ None
229/// }
230/// # fn main() {}
231/// ```
232///
233/// You want the `Person` responder to set two header fields: `X-Person-Name`
234/// and `X-Person-Age` as well as supply a custom representation of the object
235/// (`Content-Type: application/x-person`) in the body of the response. The
236/// following `Responder` implementation accomplishes this:
237///
238/// ```rust
239/// # #[macro_use] extern crate rocket_community as rocket;
240/// #
241/// # #[derive(Debug)]
242/// # struct Person { name: String, age: u16 }
243/// #
244/// use std::io::Cursor;
245///
246/// use rocket::request::Request;
247/// use rocket::response::{self, Response, Responder};
248/// use rocket::http::ContentType;
249///
250/// impl<'r> Responder<'r, 'static> for Person {
251///     fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
252///         let string = format!("{}:{}", self.name, self.age);
253///         Response::build_from(string.respond_to(req)?)
254///             .raw_header("X-Person-Name", self.name)
255///             .raw_header("X-Person-Age", self.age.to_string())
256///             .header(ContentType::new("application", "x-person"))
257///             .ok()
258///     }
259/// }
260/// #
261/// # #[get("/person")]
262/// # fn person() -> Person { Person { name: "a".to_string(), age: 20 } }
263/// # fn main() {  }
264/// ```
265///
266/// Note that the implementation could have instead been derived if structured
267/// in a slightly different manner:
268///
269/// ```rust
270/// # extern crate rocket_community as rocket;
271/// use rocket::http::Header;
272/// use rocket::response::Responder;
273///
274/// #[derive(Responder)]
275/// #[response(content_type = "application/x-person")]
276/// struct Person {
277///     text: String,
278///     name: Header<'static>,
279///     age: Header<'static>,
280/// }
281///
282/// impl Person {
283///     fn new(name: &str, age: usize) -> Person {
284///         Person {
285///             text: format!("{}:{}", name, age),
286///             name: Header::new("X-Person-Name", name.to_string()),
287///             age: Header::new("X-Person-Age", age.to_string())
288///         }
289///     }
290/// }
291/// #
292/// # #[rocket::get("/person")]
293/// # fn person() -> Person { Person::new("Bob", 29) }
294/// ```
295pub trait Responder<'r, 'o: 'r> {
296    /// Returns `Ok` if a `Response` could be generated successfully. Otherwise,
297    /// returns an `Err` with a failing `Status`.
298    ///
299    /// The `request` parameter is the `Request` that this `Responder` is
300    /// responding to.
301    ///
302    /// When using Rocket's code generation, if an `Ok(Response)` is returned,
303    /// the response will be written out to the client. If an `Err(Status)` is
304    /// returned, the error catcher for the given status is retrieved and called
305    /// to generate a final error response, which is then written out to the
306    /// client.
307    fn respond_to(self, request: &'r Request<'_>) -> response::Result<'o>;
308}
309
310/// Returns a response with Content-Type `text/plain` and a fixed-size body
311/// containing the string `self`. Always returns `Ok`.
312impl<'r, 'o: 'r> Responder<'r, 'o> for &'o str {
313    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> {
314        Response::build()
315            .header(ContentType::Plain)
316            .sized_body(self.len(), Cursor::new(self))
317            .ok()
318    }
319}
320
321/// Returns a response with Content-Type `text/plain` and a fixed-size body
322/// containing the string `self`. Always returns `Ok`.
323impl<'r> Responder<'r, 'static> for String {
324    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
325        Response::build()
326            .header(ContentType::Plain)
327            .sized_body(self.len(), Cursor::new(self))
328            .ok()
329    }
330}
331
332#[repr(transparent)]
333struct DerefRef<T>(T);
334
335impl<T: std::ops::Deref> AsRef<[u8]> for DerefRef<T>
336where
337    T::Target: AsRef<[u8]>,
338{
339    fn as_ref(&self) -> &[u8] {
340        self.0.deref().as_ref()
341    }
342}
343
344/// Returns a response with Content-Type `text/plain` and a fixed-size body
345/// containing the string `self`. Always returns `Ok`.
346impl<'r> Responder<'r, 'static> for Arc<str> {
347    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
348        Response::build()
349            .header(ContentType::Plain)
350            .sized_body(self.len(), Cursor::new(DerefRef(self)))
351            .ok()
352    }
353}
354
355/// Returns a response with Content-Type `text/plain` and a fixed-size body
356/// containing the string `self`. Always returns `Ok`.
357impl<'r> Responder<'r, 'static> for Box<str> {
358    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
359        Response::build()
360            .header(ContentType::Plain)
361            .sized_body(self.len(), Cursor::new(DerefRef(self)))
362            .ok()
363    }
364}
365
366/// Returns a response with Content-Type `application/octet-stream` and a
367/// fixed-size body containing the data in `self`. Always returns `Ok`.
368impl<'r, 'o: 'r> Responder<'r, 'o> for &'o [u8] {
369    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'o> {
370        Response::build()
371            .header(ContentType::Binary)
372            .sized_body(self.len(), Cursor::new(self))
373            .ok()
374    }
375}
376
377/// Returns a response with Content-Type `application/octet-stream` and a
378/// fixed-size body containing the data in `self`. Always returns `Ok`.
379impl<'r> Responder<'r, 'static> for Vec<u8> {
380    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
381        Response::build()
382            .header(ContentType::Binary)
383            .sized_body(self.len(), Cursor::new(self))
384            .ok()
385    }
386}
387
388/// Returns a response with Content-Type `application/octet-stream` and a
389/// fixed-size body containing the data in `self`. Always returns `Ok`.
390impl<'r> Responder<'r, 'static> for Arc<[u8]> {
391    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
392        Response::build()
393            .header(ContentType::Binary)
394            .sized_body(self.len(), Cursor::new(self))
395            .ok()
396    }
397}
398
399/// Returns a response with Content-Type `application/octet-stream` and a
400/// fixed-size body containing the data in `self`. Always returns `Ok`.
401impl<'r> Responder<'r, 'static> for Box<[u8]> {
402    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
403        Response::build()
404            .header(ContentType::Binary)
405            .sized_body(self.len(), Cursor::new(self))
406            .ok()
407    }
408}
409
410/// Returns the response generated by the inner `T`. Note that this explicitly
411/// does not support `Box<dyn Responder>`.
412///
413/// ```rust,compile_fail
414/// #[macro_use] extern crate rocket_community as rocket;
415///
416/// use rocket::response::Responder;
417///
418/// #[get("/")]
419/// fn f() -> Box<dyn Responder<'static,'static>> {
420///     Box::new(())
421/// }
422/// ```
423///
424/// However, this `impl` allows boxing sized responders:
425///
426/// ```rust
427/// #[macro_use] extern crate rocket_community as rocket;
428///
429/// #[derive(Responder)]
430/// enum Content {
431///     Redirect(Box<rocket::response::Redirect>),
432///     Text(String),
433/// }
434///
435/// #[get("/")]
436/// fn f() -> Option<Box<String>> {
437///     None
438/// }
439///
440/// #[get("/")]
441/// fn g() -> Content {
442///     Content::Text("hello".to_string())
443/// }
444/// ```
445impl<'r, 'o: 'r, T: Responder<'r, 'o> + Sized> Responder<'r, 'o> for Box<T> {
446    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
447        let inner = *self;
448        inner.respond_to(req)
449    }
450}
451
452/// Returns a response with a sized body for the file. Always returns `Ok`.
453impl<'r> Responder<'r, 'static> for File {
454    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
455        tokio::fs::File::from(self).respond_to(req)
456    }
457}
458
459/// Returns a response with a sized body for the file. Always returns `Ok`.
460impl<'r> Responder<'r, 'static> for tokio::fs::File {
461    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
462        Response::build().sized_body(None, self).ok()
463    }
464}
465
466/// Returns an empty, default `Response`. Always returns `Ok`.
467impl<'r> Responder<'r, 'static> for () {
468    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
469        Ok(Response::new())
470    }
471}
472
473/// Responds with the inner `Responder` in `Cow`.
474impl<'r, 'o: 'r, R: ?Sized + ToOwned> Responder<'r, 'o> for std::borrow::Cow<'o, R>
475where
476    &'o R: Responder<'r, 'o> + 'o,
477    <R as ToOwned>::Owned: Responder<'r, 'o> + 'r,
478{
479    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
480        match self {
481            std::borrow::Cow::Borrowed(b) => b.respond_to(req),
482            std::borrow::Cow::Owned(o) => o.respond_to(req),
483        }
484    }
485}
486
487/// If `self` is `Some`, responds with the wrapped `Responder`. Otherwise prints
488/// a warning message and returns an `Err` of `Status::NotFound`.
489impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Option<R> {
490    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
491        match self {
492            Some(r) => r.respond_to(req),
493            None => {
494                let type_name = std::any::type_name::<Self>();
495                debug!(type_name, "`Option` responder returned `None`");
496                Err(Status::NotFound)
497            }
498        }
499    }
500}
501
502/// Responds with the wrapped `Responder` in `self`, whether it is `Ok` or
503/// `Err`.
504impl<'r, 'o: 'r, 't: 'o, 'e: 'o, T, E> Responder<'r, 'o> for Result<T, E>
505where
506    T: Responder<'r, 't>,
507    E: Responder<'r, 'e>,
508{
509    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
510        match self {
511            Ok(responder) => responder.respond_to(req),
512            Err(responder) => responder.respond_to(req),
513        }
514    }
515}
516
517/// Responds with the wrapped `Responder` in `self`, whether it is `Left` or
518/// `Right`.
519impl<'r, 'o: 'r, 't: 'o, 'e: 'o, T, E> Responder<'r, 'o> for either::Either<T, E>
520where
521    T: Responder<'r, 't>,
522    E: Responder<'r, 'e>,
523{
524    fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
525        match self {
526            either::Either::Left(r) => r.respond_to(req),
527            either::Either::Right(r) => r.respond_to(req),
528        }
529    }
530}
531
532/// The response generated by `Status` depends on the status code itself. The
533/// table below summarizes the functionality:
534///
535/// | Status Code Range | Response                              |
536/// |-------------------|---------------------------------------|
537/// | [400, 599]        | Forwards to catcher for given status. |
538/// | 100, [200, 205]   | Empty with status of `self`.          |
539/// | All others.       | Invalid. Errors to `500` catcher.     |
540///
541/// In short, a client or server error status codes will forward to the
542/// corresponding error catcher, a successful status code less than `206` or
543/// `100` responds with any empty body and the given status code, and all other
544/// status code emit an error message and forward to the `500` (internal server
545/// error) catcher.
546impl<'r> Responder<'r, 'static> for Status {
547    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
548        match self.class() {
549            StatusClass::ClientError | StatusClass::ServerError => Err(self),
550            StatusClass::Success if self.code < 206 => Response::build().status(self).ok(),
551            StatusClass::Informational if self.code == 100 => Response::build().status(self).ok(),
552            _ => {
553                error!(
554                    status = self.code,
555                    "invalid status used as responder\n\
556                    status must be one of 100, 200..=205, 400..=599"
557                );
558
559                Err(Status::InternalServerError)
560            }
561        }
562    }
563}