static_web_server/
https_redirect.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// This file is part of Static Web Server.
3// See https://static-web-server.net/ for more information
4// Copyright (C) 2019-present Jose Quintana <joseluisq.net>
5
6//! Module to redirect HTTP requests to HTTPS.
7//!
8
9use headers::{HeaderMapExt, Host};
10use hyper::{header::LOCATION, Body, Request, Response, StatusCode};
11use std::sync::Arc;
12
13use crate::Result;
14
15/// HTTPS redirect options.
16pub struct RedirectOpts {
17    /// HTTPS hostname to redirect to.
18    pub https_hostname: String,
19    /// HTTPS hostname port to redirect to.
20    pub https_port: u16,
21    /// Hostnames or IPS to redirect from.
22    pub allowed_hosts: Vec<String>,
23}
24
25/// It redirects all requests from HTTP to HTTPS.
26pub fn redirect_to_https<T>(
27    req: &Request<T>,
28    opts: Arc<RedirectOpts>,
29) -> Result<Response<Body>, StatusCode> {
30    if let Some(ref host) = req.headers().typed_get::<Host>() {
31        let from_hostname = host.hostname();
32        if !opts
33            .allowed_hosts
34            .iter()
35            .any(|s| s.as_str() == from_hostname)
36        {
37            tracing::debug!("redirect host is not allowed!");
38            return Err(StatusCode::BAD_REQUEST);
39        }
40
41        let url = format!(
42            "https://{}:{}{}",
43            opts.https_hostname,
44            opts.https_port,
45            req.uri()
46        );
47        tracing::debug!("https redirect to {}", url);
48
49        let mut resp = Response::new(Body::empty());
50        *resp.status_mut() = StatusCode::MOVED_PERMANENTLY;
51        resp.headers_mut().insert(LOCATION, url.parse().unwrap());
52        return Ok(resp);
53    }
54
55    tracing::debug!("redirect host was not determined!");
56    Err(StatusCode::BAD_REQUEST)
57}