Merge branch 'fix/fix/remove-health-and-hardcode-https'

This commit is contained in:
2026-06-12 04:44:54 +00:00
3 changed files with 15 additions and 77 deletions

View File

@@ -74,7 +74,6 @@ async fn run_server(loaded_config: cli::LoadedConfig, config_path: &str) -> Resu
config: config_arc.clone(), config: config_arc.clone(),
http_client, http_client,
https_client, https_client,
is_https: true,
}); });
let reload_handle = Arc::new(ConfigReloadHandle::new( let reload_handle = Arc::new(ConfigReloadHandle::new(

View File

@@ -7,7 +7,6 @@ use axum::body::Body;
use axum::extract::{ConnectInfo, State}; use axum::extract::{ConnectInfo, State};
use axum::http::{Request, StatusCode, Uri}; use axum::http::{Request, StatusCode, Uri};
use axum::response::{IntoResponse, Response}; use axum::response::{IntoResponse, Response};
use axum::routing::get;
use axum::Router; use axum::Router;
use hyper_util::client::legacy::connect::HttpConnector; use hyper_util::client::legacy::connect::HttpConnector;
use hyper_util::client::legacy::Client; use hyper_util::client::legacy::Client;
@@ -22,11 +21,6 @@ pub struct ProxyState {
pub config: Arc<ArcSwap<DynamicConfig>>, pub config: Arc<ArcSwap<DynamicConfig>>,
pub http_client: Client<HttpConnector, Body>, pub http_client: Client<HttpConnector, Body>,
pub https_client: Client<hyper_rustls::HttpsConnector<HttpConnector>, Body>, pub https_client: Client<hyper_rustls::HttpsConnector<HttpConnector>, Body>,
pub is_https: bool,
}
async fn health_handler() -> impl IntoResponse {
StatusCode::OK
} }
async fn proxy_handler( async fn proxy_handler(
@@ -34,10 +28,6 @@ async fn proxy_handler(
State(state): State<Arc<ProxyState>>, State(state): State<Arc<ProxyState>>,
mut req: Request<Body>, mut req: Request<Body>,
) -> Response { ) -> Response {
if req.uri().path() == "/health" {
return StatusCode::OK.into_response();
}
let host = req let host = req
.headers() .headers()
.get(axum::http::header::HOST) .get(axum::http::header::HOST)
@@ -55,7 +45,7 @@ async fn proxy_handler(
}; };
let host_owned = host.to_string(); let host_owned = host.to_string();
inject_proxy_headers(req.headers_mut(), remote_addr, state.is_https); inject_proxy_headers(req.headers_mut(), remote_addr);
remove_hop_by_hop(req.headers_mut()); remove_hop_by_hop(req.headers_mut());
let upstream_scheme = site.upstream_scheme.clone(); let upstream_scheme = site.upstream_scheme.clone();
@@ -165,10 +155,7 @@ fn root_certs() -> rustls::RootCertStore {
} }
pub fn proxy_router(state: Arc<ProxyState>) -> Router { pub fn proxy_router(state: Arc<ProxyState>) -> Router {
Router::new() Router::new().fallback(proxy_handler).with_state(state)
.route("/health", get(health_handler))
.fallback(proxy_handler)
.with_state(state)
} }
#[cfg(test)] #[cfg(test)]
@@ -195,7 +182,6 @@ mod tests {
))), ))),
http_client: create_http_client(), http_client: create_http_client(),
https_client: create_https_client(), https_client: create_https_client(),
is_https: true,
}) })
} }
@@ -214,46 +200,6 @@ mod tests {
req req
} }
#[tokio::test]
async fn health_path_returns_200_regardless_of_host() {
let state = make_proxy_state(vec![SiteConfig {
host: "example.com".to_string(),
upstream: "127.0.0.1:8080".to_string(),
upstream_scheme: "http".to_string(),
upstream_connect_timeout_secs: 5,
upstream_request_timeout_secs: 60,
}]);
let router = proxy_router(state);
let req = make_request_with_connect_info(
"GET",
"/health",
None,
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12345),
);
let resp = router.oneshot(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
#[tokio::test]
async fn health_with_unknown_host_returns_200() {
let state = make_proxy_state(vec![SiteConfig {
host: "example.com".to_string(),
upstream: "127.0.0.1:8080".to_string(),
upstream_scheme: "http".to_string(),
upstream_connect_timeout_secs: 5,
upstream_request_timeout_secs: 60,
}]);
let router = proxy_router(state);
let req = make_request_with_connect_info(
"GET",
"/health",
Some("unknown.host"),
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12345),
);
let resp = router.oneshot(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
#[tokio::test] #[tokio::test]
async fn missing_host_returns_400() { async fn missing_host_returns_400() {
let state = make_proxy_state(vec![SiteConfig { let state = make_proxy_state(vec![SiteConfig {

View File

@@ -18,7 +18,7 @@ pub fn remove_hop_by_hop(headers: &mut HeaderMap) {
} }
} }
pub fn inject_proxy_headers(headers: &mut HeaderMap, remote_addr: SocketAddr, is_https: bool) { pub fn inject_proxy_headers(headers: &mut HeaderMap, remote_addr: SocketAddr) {
let ip_str = remote_addr.ip().to_string(); let ip_str = remote_addr.ip().to_string();
let ip_value = let ip_value =
HeaderValue::from_str(&ip_str).unwrap_or_else(|_| HeaderValue::from_static("0.0.0.0")); HeaderValue::from_str(&ip_str).unwrap_or_else(|_| HeaderValue::from_static("0.0.0.0"));
@@ -27,12 +27,13 @@ pub fn inject_proxy_headers(headers: &mut HeaderMap, remote_addr: SocketAddr, is
headers.insert(HeaderName::from_static("x-forwarded-for"), ip_value); headers.insert(HeaderName::from_static("x-forwarded-for"), ip_value);
let proto_value = if is_https { // X-Forwarded-Proto is always "https" because this proxy only forwards requests
HeaderValue::from_static("https") // received on the TLS listener. The HTTP listener redirects to HTTPS and does not
} else { // proxy requests, so X-Forwarded-Proto is never set for HTTP connections.
HeaderValue::from_static("http") headers.insert(
}; HeaderName::from_static("x-forwarded-proto"),
headers.insert(HeaderName::from_static("x-forwarded-proto"), proto_value); HeaderValue::from_static("https"),
);
} }
#[cfg(test)] #[cfg(test)]
@@ -84,7 +85,7 @@ mod tests {
fn inject_proxy_headers_sets_x_real_ip() { fn inject_proxy_headers_sets_x_real_ip() {
let mut h = HeaderMap::new(); let mut h = HeaderMap::new();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 12345); let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 12345);
inject_proxy_headers(&mut h, addr, true); inject_proxy_headers(&mut h, addr);
assert_eq!(h.get("x-real-ip").unwrap(), "192.168.1.1"); assert_eq!(h.get("x-real-ip").unwrap(), "192.168.1.1");
} }
@@ -96,32 +97,24 @@ mod tests {
HeaderValue::from_static("10.0.0.1, 10.0.0.2"), HeaderValue::from_static("10.0.0.1, 10.0.0.2"),
); );
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 12345); let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 12345);
inject_proxy_headers(&mut h, addr, true); inject_proxy_headers(&mut h, addr);
assert_eq!(h.get("x-forwarded-for").unwrap(), "192.168.1.1"); assert_eq!(h.get("x-forwarded-for").unwrap(), "192.168.1.1");
} }
#[test] #[test]
fn inject_proxy_headers_sets_x_forwarded_proto_https() { fn inject_proxy_headers_sets_x_forwarded_proto_to_https() {
let mut h = HeaderMap::new(); let mut h = HeaderMap::new();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 443); let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 443);
inject_proxy_headers(&mut h, addr, true); inject_proxy_headers(&mut h, addr);
assert_eq!(h.get("x-forwarded-proto").unwrap(), "https"); assert_eq!(h.get("x-forwarded-proto").unwrap(), "https");
} }
#[test]
fn inject_proxy_headers_sets_x_forwarded_proto_http() {
let mut h = HeaderMap::new();
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 80);
inject_proxy_headers(&mut h, addr, false);
assert_eq!(h.get("x-forwarded-proto").unwrap(), "http");
}
#[test] #[test]
fn inject_proxy_headers_preserves_host() { fn inject_proxy_headers_preserves_host() {
let mut h = HeaderMap::new(); let mut h = HeaderMap::new();
h.insert("host", HeaderValue::from_static("example.com")); h.insert("host", HeaderValue::from_static("example.com"));
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 443); let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 443);
inject_proxy_headers(&mut h, addr, true); inject_proxy_headers(&mut h, addr);
assert_eq!(h.get("host").unwrap(), "example.com"); assert_eq!(h.get("host").unwrap(), "example.com");
} }