use std::collections::HashMap;
use axum::{
http::{HeaderName, HeaderValue, StatusCode},
response::{IntoResponse, Response as AxumResponse},
};
#[derive(Debug, Clone)]
pub struct Redirect {
code: StatusCode,
location: String,
headers: Option<HashMap<HeaderName, HeaderValue>>,
}
impl Redirect {
pub fn status(
code: impl TryInto<StatusCode>,
location: impl Into<String>,
) -> Self {
Self {
code: code.try_into().unwrap_or(StatusCode::TEMPORARY_REDIRECT),
location: location.into(),
headers: None,
}
}
pub fn permanent(location: impl Into<String>) -> Self {
Self::status(StatusCode::MOVED_PERMANENTLY, location)
}
pub fn found(location: impl Into<String>) -> Self {
Self::status(StatusCode::FOUND, location)
}
pub fn see_other(location: impl Into<String>) -> Self {
Self::status(StatusCode::SEE_OTHER, location)
}
pub fn temporary(location: impl Into<String>) -> Self {
Self::status(StatusCode::TEMPORARY_REDIRECT, location)
}
pub fn permanent_redirect(location: impl Into<String>) -> Self {
Self::status(StatusCode::PERMANENT_REDIRECT, location)
}
pub fn header(mut self, key: &str, value: &str) -> Self {
if let (Ok(header_name), Ok(header_value)) =
(HeaderName::try_from(key), HeaderValue::try_from(value))
{
(*self.headers.get_or_insert_with(HashMap::new))
.insert(header_name, header_value);
}
self
}
}
impl IntoResponse for Redirect {
fn into_response(self) -> AxumResponse {
let mut response =
(self.code, [("Location", self.location)]).into_response();
if let Some(headers) = self.headers {
for (key, value) in headers.iter() {
response.headers_mut().insert(key, value.clone());
}
}
response
}
}