use headers::{HeaderMapExt, Host};
use hyper::{header::LOCATION, Body, Request, Response, StatusCode};
use std::sync::Arc;
use crate::Result;
pub struct RedirectOpts {
pub https_hostname: String,
pub https_port: u16,
pub allowed_hosts: Vec<String>,
}
pub fn redirect_to_https<T>(
req: &Request<T>,
opts: Arc<RedirectOpts>,
) -> Result<Response<Body>, StatusCode> {
if let Some(ref host) = req.headers().typed_get::<Host>() {
let from_hostname = host.hostname();
if !opts
.allowed_hosts
.iter()
.any(|s| s.as_str() == from_hostname)
{
tracing::debug!("redirect host is not allowed!");
return Err(StatusCode::BAD_REQUEST);
}
let url = format!(
"https://{}:{}{}",
opts.https_hostname,
opts.https_port,
req.uri()
);
tracing::debug!("https redirect to {}", url);
let mut resp = Response::new(Body::empty());
*resp.status_mut() = StatusCode::MOVED_PERMANENTLY;
resp.headers_mut().insert(LOCATION, url.parse().unwrap());
return Ok(resp);
}
tracing::debug!("redirect host was not determined!");
Err(StatusCode::BAD_REQUEST)
}