plane_dynamic_proxy/
https_redirect.rs1use crate::body::{simple_empty_body, BoxedError, SimpleBody};
2use http::{
3 header,
4 uri::{Authority, Scheme},
5 Request, Response, StatusCode, Uri,
6};
7use hyper::{body::Incoming, service::Service};
8use std::{future::ready, pin::Pin, str::FromStr};
9
10#[derive(Debug, Clone)]
12pub struct HttpsRedirectService;
13
14impl HttpsRedirectService {
15 fn call_inner(request: Request<Incoming>) -> Result<Response<SimpleBody>, StatusCode> {
16 let hostname = request
18 .headers()
19 .get(header::HOST)
20 .ok_or(StatusCode::BAD_REQUEST)?;
21 let authority =
23 Authority::from_str(hostname.to_str().map_err(|_| StatusCode::BAD_REQUEST)?)
24 .map_err(|_| StatusCode::BAD_REQUEST)?;
25 let authority =
27 Authority::from_str(authority.host()).expect("Valid host is always valid authority.");
28
29 let request_uri = request.uri().clone();
30
31 let mut parts = request_uri.into_parts();
33 parts.scheme = Some(Scheme::HTTPS);
34
35 parts.authority = Some(authority);
36
37 let new_uri = Uri::from_parts(parts).expect("URI is always valid");
39
40 let response = Response::builder()
41 .status(StatusCode::MOVED_PERMANENTLY)
42 .header(header::LOCATION, new_uri.to_string())
43 .body(simple_empty_body());
44
45 response.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
46 }
47}
48
49impl Service<Request<Incoming>> for HttpsRedirectService {
50 type Response = Response<SimpleBody>;
51 type Error = BoxedError;
52 type Future = Pin<Box<std::future::Ready<Result<Response<SimpleBody>, BoxedError>>>>;
53
54 fn call(&self, request: Request<Incoming>) -> Self::Future {
55 let result = Self::call_inner(request);
56
57 let result = match result {
58 Ok(response) => response,
59 Err(status) => {
60 tracing::error!("Error redirecting to HTTPS: {}", status);
61 Response::builder()
62 .status(status)
63 .body(simple_empty_body())
64 .expect("Response is always valid")
65 }
66 };
67
68 Box::pin(ready(Ok(result)))
69 }
70}