feat(proxy): add per-route disable_secure_redirection; preserve query string in redirect
By default every plain-HTTP request is 301-redirected to HTTPS — no upstream is ever contacted, making it as close to an L4 redirect as HTTP allows. New RouteConfig field `disable_secure_redirection` (bool, default false): when set to true on a route, plain-HTTP requests for that host pass through to the backend unchanged instead of being redirected. Also fixes the redirect URL to include the original query string, which was previously dropped (e.g. ?next=/dashboard would be lost after redirect). Signed-off-by: Sienna Meridian Satterwhite <sienna@sunbeam.pt>
This commit is contained in:
@@ -46,6 +46,10 @@ pub struct RouteConfig {
|
||||
pub backend: String,
|
||||
#[serde(default)]
|
||||
pub websocket: bool,
|
||||
/// When true, plain-HTTP requests for this host are forwarded as-is rather
|
||||
/// than being redirected to HTTPS. Defaults to false (redirect enforced).
|
||||
#[serde(default)]
|
||||
pub disable_secure_redirection: bool,
|
||||
/// Optional path-based sub-routes (longest prefix wins).
|
||||
/// If the request path matches a sub-route, its backend is used instead.
|
||||
#[serde(default)]
|
||||
|
||||
25
src/proxy.rs
25
src/proxy.rs
@@ -102,9 +102,29 @@ impl ProxyHttp for SunbeamProxy {
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// All other plain-HTTP traffic: redirect to HTTPS.
|
||||
// All other plain-HTTP traffic.
|
||||
let host = extract_host(session);
|
||||
let location = format!("https://{host}{path}");
|
||||
let prefix = host.split('.').next().unwrap_or("");
|
||||
|
||||
// Routes that explicitly opt out of HTTPS enforcement pass through.
|
||||
// All other requests — including unknown hosts — are redirected.
|
||||
// This is as close to an L4 redirect as HTTP allows: the upstream is
|
||||
// never contacted; the 301 is written directly to the downstream socket.
|
||||
if self
|
||||
.find_route(prefix)
|
||||
.map(|r| r.disable_secure_redirection)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let query = session
|
||||
.req_header()
|
||||
.uri
|
||||
.query()
|
||||
.map(|q| format!("?{q}"))
|
||||
.unwrap_or_default();
|
||||
let location = format!("https://{host}{path}{query}");
|
||||
let mut resp = ResponseHeader::build(301, None)?;
|
||||
resp.insert_header("Location", location)?;
|
||||
resp.insert_header("Content-Length", "0")?;
|
||||
@@ -162,6 +182,7 @@ impl ProxyHttp for SunbeamProxy {
|
||||
host_prefix: route.host_prefix.clone(),
|
||||
backend: pr.backend.clone(),
|
||||
websocket: pr.websocket || route.websocket,
|
||||
disable_secure_redirection: route.disable_secure_redirection,
|
||||
paths: vec![],
|
||||
});
|
||||
return Ok(Box::new(HttpPeer::new(
|
||||
|
||||
Reference in New Issue
Block a user