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<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<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<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}