Skip to content

Commit 7dc70bf

Browse files
authored
New redirect inspection (#3377)
1 parent 6d78e84 commit 7dc70bf

File tree

1 file changed

+60
-15
lines changed

1 file changed

+60
-15
lines changed

axum/src/response/redirect.rs

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use http::{header::LOCATION, HeaderValue, StatusCode};
2121
#[derive(Debug, Clone)]
2222
pub struct Redirect {
2323
status_code: StatusCode,
24-
location: HeaderValue,
24+
location: String,
2525
}
2626

2727
impl Redirect {
@@ -33,10 +33,6 @@ impl Redirect {
3333
/// body (if non-empty). If you want to preserve the request method and body,
3434
/// [`Redirect::temporary`] should be used instead.
3535
///
36-
/// # Panics
37-
///
38-
/// If `uri` isn't a valid [`HeaderValue`].
39-
///
4036
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/303
4137
pub fn to(uri: &str) -> Self {
4238
Self::with_status_code(StatusCode::SEE_OTHER, uri)
@@ -47,26 +43,28 @@ impl Redirect {
4743
/// This has the same behavior as [`Redirect::to`], except it will preserve the original HTTP
4844
/// method and body.
4945
///
50-
/// # Panics
51-
///
52-
/// If `uri` isn't a valid [`HeaderValue`].
53-
///
5446
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307
5547
pub fn temporary(uri: &str) -> Self {
5648
Self::with_status_code(StatusCode::TEMPORARY_REDIRECT, uri)
5749
}
5850

5951
/// Create a new [`Redirect`] that uses a [`308 Permanent Redirect`][mdn] status code.
6052
///
61-
/// # Panics
62-
///
63-
/// If `uri` isn't a valid [`HeaderValue`].
64-
///
6553
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308
6654
pub fn permanent(uri: &str) -> Self {
6755
Self::with_status_code(StatusCode::PERMANENT_REDIRECT, uri)
6856
}
6957

58+
/// Returns the HTTP status code of the `Redirect`.
59+
pub fn status_code(&self) -> StatusCode {
60+
self.status_code
61+
}
62+
63+
/// Returns the `Redirect`'s URI.
64+
pub fn location(&self) -> &str {
65+
&self.location
66+
}
67+
7068
// This is intentionally not public since other kinds of redirects might not
7169
// use the `Location` header, namely `304 Not Modified`.
7270
//
@@ -79,13 +77,60 @@ impl Redirect {
7977

8078
Self {
8179
status_code,
82-
location: HeaderValue::try_from(uri).expect("URI isn't a valid header value"),
80+
location: uri.to_owned(),
8381
}
8482
}
8583
}
8684

8785
impl IntoResponse for Redirect {
8886
fn into_response(self) -> Response {
89-
(self.status_code, [(LOCATION, self.location)]).into_response()
87+
match HeaderValue::try_from(self.location) {
88+
Ok(location) => (self.status_code, [(LOCATION, location)]).into_response(),
89+
Err(error) => (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response(),
90+
}
91+
}
92+
}
93+
94+
#[cfg(test)]
95+
mod tests {
96+
use super::Redirect;
97+
use axum_core::response::IntoResponse;
98+
use http::StatusCode;
99+
100+
const EXAMPLE_URL: &str = "https://example.com";
101+
102+
// Tests to make sure Redirect has the correct status codes
103+
// based on the way it was constructed.
104+
#[test]
105+
fn correct_status() {
106+
assert_eq!(
107+
StatusCode::SEE_OTHER,
108+
Redirect::to(EXAMPLE_URL).status_code()
109+
);
110+
111+
assert_eq!(
112+
StatusCode::TEMPORARY_REDIRECT,
113+
Redirect::temporary(EXAMPLE_URL).status_code()
114+
);
115+
116+
assert_eq!(
117+
StatusCode::PERMANENT_REDIRECT,
118+
Redirect::permanent(EXAMPLE_URL).status_code()
119+
);
120+
}
121+
122+
#[test]
123+
fn correct_location() {
124+
assert_eq!(EXAMPLE_URL, Redirect::permanent(EXAMPLE_URL).location());
125+
126+
assert_eq!("/redirect", Redirect::permanent("/redirect").location())
127+
}
128+
129+
#[test]
130+
fn test_internal_error() {
131+
let response = Redirect::permanent("Axum is awesome, \n but newlines aren't allowed :(")
132+
.into_response();
133+
134+
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
90135
}
91136
}

0 commit comments

Comments
 (0)