/
redirect.rs
93 lines (86 loc) · 3.1 KB
/
redirect.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use axum_core::response::{IntoResponse, Response};
use http::{header::LOCATION, HeaderValue, StatusCode};
/// Response that redirects the request to another location.
///
/// # Example
///
/// ```rust
/// use axum::{
/// routing::get,
/// response::Redirect,
/// Router,
/// };
///
/// let app = Router::new()
/// .route("/old", get(|| async { Redirect::permanent("/new") }))
/// .route("/new", get(|| async { "Hello!" }));
/// # async {
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
/// # };
/// ```
#[must_use = "needs to be returned from a handler or otherwise turned into a Response to be useful"]
#[derive(Debug, Clone)]
pub struct Redirect {
status_code: StatusCode,
location: HeaderValue,
}
impl Redirect {
/// Create a new [`Redirect`] that uses a [`303 See Other`][mdn] status code.
///
/// This redirect instructs the client to change the method to GET for the subsequent request
/// to the given `uri`, which is useful after successful form submission, file upload or when
/// you generally don't want the redirected-to page to observe the original request method and
/// body (if non-empty). If you want to preserve the request method and body,
/// [`Redirect::temporary`] should be used instead.
///
/// # Panics
///
/// If `uri` isn't a valid [`HeaderValue`].
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/303
pub fn to(uri: &str) -> Self {
Self::with_status_code(StatusCode::SEE_OTHER, uri)
}
/// Create a new [`Redirect`] that uses a [`307 Temporary Redirect`][mdn] status code.
///
/// This has the same behavior as [`Redirect::to`], except it will preserve the original HTTP
/// method and body.
///
/// # Panics
///
/// If `uri` isn't a valid [`HeaderValue`].
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307
pub fn temporary(uri: &str) -> Self {
Self::with_status_code(StatusCode::TEMPORARY_REDIRECT, uri)
}
/// Create a new [`Redirect`] that uses a [`308 Permanent Redirect`][mdn] status code.
///
/// # Panics
///
/// If `uri` isn't a valid [`HeaderValue`].
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308
pub fn permanent(uri: &str) -> Self {
Self::with_status_code(StatusCode::PERMANENT_REDIRECT, uri)
}
// This is intentionally not public since other kinds of redirects might not
// use the `Location` header, namely `304 Not Modified`.
//
// We're open to adding more constructors upon request, if they make sense :)
fn with_status_code(status_code: StatusCode, uri: &str) -> Self {
assert!(
status_code.is_redirection(),
"not a redirection status code"
);
Self {
status_code,
location: HeaderValue::try_from(uri).expect("URI isn't a valid header value"),
}
}
}
impl IntoResponse for Redirect {
fn into_response(self) -> Response {
(self.status_code, [(LOCATION, self.location)]).into_response()
}
}