tide/redirect.rs
1//! HTTP redirection endpoint.
2//!
3//! # Examples
4//!
5//! ```no_run
6//! # use async_std::task::block_on;
7//! # fn main() -> Result<(), std::io::Error> { block_on(async {
8//! #
9//! use tide::Redirect;
10//!
11//! let mut app = tide::new();
12//! app.at("/").get(|_| async { Ok("meow") });
13//! app.at("/nori").get(Redirect::temporary("/"));
14//! app.listen("127.0.0.1:8080").await?;
15//! #
16//! # Ok(()) }) }
17//! ```
18
19use crate::http::headers::LOCATION;
20use crate::StatusCode;
21use crate::{Endpoint, Request, Response};
22
23/// A redirection endpoint.
24///
25/// # Example
26///
27/// ```
28/// # use tide::{Response, Redirect, Request, StatusCode};
29/// # fn next_product() -> Option<String> { None }
30/// # #[allow(dead_code)]
31/// async fn route_handler(request: Request<()>) -> tide::Result {
32/// if let Some(product_url) = next_product() {
33/// Ok(Redirect::new(product_url).into())
34/// } else {
35/// //...
36/// # Ok(Response::new(StatusCode::Ok)) //...
37/// }
38/// }
39/// ```
40#[derive(Debug, Clone)]
41pub struct Redirect<T: AsRef<str>> {
42 status: StatusCode,
43 location: T,
44}
45
46impl<T: AsRef<str>> Redirect<T> {
47 /// Creates an endpoint that represents a redirect to `location`.
48 ///
49 /// Uses status code 302 Found.
50 pub fn new(location: T) -> Self {
51 Self {
52 status: StatusCode::Found,
53 location,
54 }
55 }
56
57 /// Creates an endpoint that represents a permanent redirect to `location`.
58 ///
59 /// Uses status code 301 Permanent Redirect.
60 pub fn permanent(location: T) -> Self {
61 Self {
62 status: StatusCode::PermanentRedirect,
63 location,
64 }
65 }
66
67 /// Creates an endpoint that represents a temporary redirect to `location`.
68 ///
69 /// Uses status code 307 Temporary Redirect.
70 pub fn temporary(location: T) -> Self {
71 Self {
72 status: StatusCode::TemporaryRedirect,
73 location,
74 }
75 }
76
77 /// Creates an endpoint that represents a see other redirect to `location`.
78 ///
79 /// Uses status code 303 See Other.
80 pub fn see_other(location: T) -> Self {
81 Self {
82 status: StatusCode::SeeOther,
83 location,
84 }
85 }
86}
87
88#[async_trait::async_trait]
89impl<State, T> Endpoint<State> for Redirect<T>
90where
91 State: Clone + Send + Sync + 'static,
92 T: AsRef<str> + Send + Sync + 'static,
93{
94 async fn call(&self, _req: Request<State>) -> crate::Result<Response> {
95 Ok(self.into())
96 }
97}
98
99impl<T: AsRef<str>> Into<Response> for Redirect<T> {
100 fn into(self) -> Response {
101 (&self).into()
102 }
103}
104
105impl<T: AsRef<str>> Into<Response> for &Redirect<T> {
106 fn into(self) -> Response {
107 let mut res = Response::new(self.status);
108 res.insert_header(LOCATION, self.location.as_ref());
109 res
110 }
111}