add https redirection
This commit is contained in:
parent
730ae1f08d
commit
ef5d1c0f2a
3 changed files with 85 additions and 10 deletions
|
|
@ -35,7 +35,7 @@ pub fn parse_opts(globals: &mut Globals, backends: &mut HashMap<String, Backend>
|
||||||
default_destination_uri: "https://google.com/".parse::<Uri>().unwrap(),
|
default_destination_uri: "https://google.com/".parse::<Uri>().unwrap(),
|
||||||
destination_uris: Some(map_example),
|
destination_uris: Some(map_example),
|
||||||
},
|
},
|
||||||
redirect_to_https: None, // TODO: ここはHTTPの時のみの設定。tlsの存在とは排他的。
|
redirect_to_https: Some(true), // TODO: ここはtlsが存在する時はSomeにすべき。Noneはtlsがないときのみのはず
|
||||||
|
|
||||||
tls_cert_path: Some(PathBuf::from(r"localhost1.pem")),
|
tls_cert_path: Some(PathBuf::from(r"localhost1.pem")),
|
||||||
tls_cert_key_path: Some(PathBuf::from(r"localhost1.pem")),
|
tls_cert_key_path: Some(PathBuf::from(r"localhost1.pem")),
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use hyper::{
|
||||||
http,
|
http,
|
||||||
server::conn::Http,
|
server::conn::Http,
|
||||||
service::{service_fn, Service},
|
service::{service_fn, Service},
|
||||||
Body, Client, HeaderMap, Method, Request, Response, StatusCode,
|
Body, Client, HeaderMap, Method, Request, Response, StatusCode, Uri,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, net::SocketAddr, pin::Pin, sync::Arc};
|
use std::{collections::HashMap, net::SocketAddr, pin::Pin, sync::Arc};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
|
|
@ -23,26 +23,95 @@ use tokio::{
|
||||||
pub async fn handle_request(
|
pub async fn handle_request(
|
||||||
req: Request<Body>,
|
req: Request<Body>,
|
||||||
client_ip: SocketAddr,
|
client_ip: SocketAddr,
|
||||||
|
tls_enabled: bool,
|
||||||
globals: Arc<Globals>,
|
globals: Arc<Globals>,
|
||||||
) -> Result<Response<Body>, http::Error> {
|
backends: Arc<HashMap<String, Backend>>,
|
||||||
// http_error(StatusCode::NOT_FOUND)
|
) -> Result<Response<Body>> {
|
||||||
debug!("{:?}", req);
|
let headers = req.headers();
|
||||||
|
|
||||||
|
// Here we start to handle with hostname
|
||||||
|
// Find backend application for given hostname
|
||||||
|
let (hostname, port) = parse_hostname_port(headers, tls_enabled)?;
|
||||||
|
let path = req.uri().path();
|
||||||
|
let backend = if let Some(be) = backends.get(hostname.as_str()) {
|
||||||
|
be
|
||||||
|
} else {
|
||||||
|
return http_error(StatusCode::SERVICE_UNAVAILABLE);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Redirect to https if tls_enabled is false and redirect_to_https is true
|
||||||
|
if !tls_enabled && backend.redirect_to_https.unwrap_or(false) {
|
||||||
|
if let Some(https_port) = globals.https_port {
|
||||||
|
let dest = if https_port == 443 {
|
||||||
|
format!("https://{}{}", hostname, path)
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"https://{}:{}{}",
|
||||||
|
hostname,
|
||||||
|
globals.https_port.unwrap(),
|
||||||
|
path
|
||||||
|
)
|
||||||
|
};
|
||||||
|
return https_redirection(dest);
|
||||||
|
} else {
|
||||||
|
return http_error(StatusCode::SERVICE_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find reverse proxy for given path
|
||||||
|
// let destination_uri = if backend.reverse_proxy.destination_uris.is_some() {
|
||||||
|
// if let (b) = backend.re
|
||||||
|
// } else {
|
||||||
|
// backend.reverse_proxy.default_destination_uri.clone();
|
||||||
|
// };
|
||||||
|
|
||||||
|
debug!("path: {}", req.uri().path());
|
||||||
// if req.version() == hyper::Version::HTTP_11 {
|
// if req.version() == hyper::Version::HTTP_11 {
|
||||||
// Ok(Response::new(Body::from("Hello World")))
|
// Ok(Response::new(Body::from("Hello World")))
|
||||||
// } else {
|
// } else {
|
||||||
// Note: it's usually better to return a Response
|
// Note: it's usually better to return a Response
|
||||||
// with an appropriate StatusCode instead of an Err.
|
// with an appropriate StatusCode instead of an Err.
|
||||||
// Err("not HTTP/1.1, abort connection")
|
// Err("not HTTP/1.1, abort connection")
|
||||||
http_error(StatusCode::NOT_FOUND)
|
// http_error(StatusCode::NOT_FOUND)
|
||||||
|
https_redirection("https://www.google.com/".to_string())
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
fn http_error(status_code: StatusCode) -> Result<Response<Body>> {
|
||||||
fn http_error(status_code: StatusCode) -> Result<Response<Body>, http::Error> {
|
|
||||||
let response = Response::builder()
|
let response = Response::builder()
|
||||||
.status(status_code)
|
.status(status_code)
|
||||||
.body(Body::empty())
|
.body(Body::empty())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn https_redirection(redirect_to: String) -> Result<Response<Body>> {
|
||||||
|
let response = Response::builder()
|
||||||
|
.status(StatusCode::MOVED_PERMANENTLY)
|
||||||
|
.header("Location", redirect_to)
|
||||||
|
.body(Body::empty())
|
||||||
|
.unwrap();
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_hostname_port(headers: &HeaderMap, tls_enabled: bool) -> Result<(String, u16)> {
|
||||||
|
let hostname_port = headers
|
||||||
|
.get("host")
|
||||||
|
.ok_or_else(|| anyhow!("No host in request header"))?;
|
||||||
|
let hp_as_uri = hostname_port.to_str().unwrap().parse::<Uri>().unwrap();
|
||||||
|
|
||||||
|
let hostname = hp_as_uri
|
||||||
|
.host()
|
||||||
|
.ok_or_else(|| anyhow!("Failed to parse hostname"))?;
|
||||||
|
|
||||||
|
let port = if let Some(p) = hp_as_uri.port() {
|
||||||
|
p.as_u16()
|
||||||
|
} else if tls_enabled {
|
||||||
|
443
|
||||||
|
} else {
|
||||||
|
80
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((hostname.to_string(), port))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use super::proxy_handler::handle_request;
|
use super::proxy_handler::handle_request;
|
||||||
use crate::{backend::Backend, error::*, globals::Globals, log::*};
|
use crate::{backend::Backend, error::*, globals::Globals, log::*};
|
||||||
use hyper::{
|
use hyper::{
|
||||||
client::connect::Connect, server::conn::Http, service::service_fn, Body, Client, Request,
|
client::connect::Connect, server::conn::Http, service::service_fn, Body, Client, Method, Request,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
|
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
|
|
@ -65,7 +65,13 @@ where
|
||||||
server.serve_connection(
|
server.serve_connection(
|
||||||
stream,
|
stream,
|
||||||
service_fn(move |req: Request<Body>| {
|
service_fn(move |req: Request<Body>| {
|
||||||
handle_request(req, peer_addr, self.globals.clone())
|
handle_request(
|
||||||
|
req,
|
||||||
|
peer_addr,
|
||||||
|
self.tls_enabled,
|
||||||
|
self.globals.clone(),
|
||||||
|
self.backends.clone(),
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue