Skip to main content

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::{
11    Body, Request, Response, StatusCode,
12    header::{HeaderValue, LOCATION},
13};
14use std::sync::Arc;
15
16use crate::Result;
17
18/// HTTPS redirect options.
19pub struct RedirectOpts {
20    /// HTTPS hostname to redirect to.
21    pub https_hostname: String,
22    /// HTTPS hostname port to redirect to.
23    pub https_port: u16,
24    /// Hostnames or IPS to redirect from.
25    pub allowed_hosts: Vec<String>,
26}
27
28/// It redirects all requests from HTTP to HTTPS.
29pub fn redirect_to_https<T>(
30    req: &Request<T>,
31    opts: Arc<RedirectOpts>,
32) -> Result<Response<Body>, StatusCode> {
33    if let Some(ref host) = req.headers().typed_get::<Host>() {
34        let from_hostname = host.hostname();
35        if !opts
36            .allowed_hosts
37            .iter()
38            .any(|s| s.as_str() == from_hostname)
39        {
40            tracing::debug!("redirect host is not allowed!");
41            return Err(StatusCode::BAD_REQUEST);
42        }
43
44        let url = format!(
45            "https://{}:{}{}",
46            opts.https_hostname,
47            opts.https_port,
48            req.uri()
49        );
50        tracing::debug!("https redirect to {}", url);
51
52        let location = match HeaderValue::from_str(&url) {
53            Ok(location) => location,
54            Err(err) => {
55                tracing::error!("invalid https redirect location `{url}`: {err:?}");
56                return Err(StatusCode::BAD_REQUEST);
57            }
58        };
59
60        let mut resp = Response::new(Body::empty());
61        *resp.status_mut() = StatusCode::MOVED_PERMANENTLY;
62        resp.headers_mut().insert(LOCATION, location);
63        return Ok(resp);
64    }
65
66    tracing::debug!("redirect host was not determined!");
67    Err(StatusCode::BAD_REQUEST)
68}