From 121235ca2857eb642d88c7e162c4a1cf8524f6d4 Mon Sep 17 00:00:00 2001 From: Robert Krahn Date: Tue, 27 Aug 2024 18:54:41 +0200 Subject: [PATCH] add proxy option `no_redirect` When serving responses with the Trunk proxy, redirects are automatically followed by default. This can be undesirable, e.g. when serving a login page that response with a redirect and a set-cookie header like ``` HTTP/1.1 303 See Other location: / set-cookie: session=...; ...; ``` This PR adds a proxy option `no_redirect` that when set will instruct the proxy to not automatically follow redirects. The default behavior is unchanged. --- site/content/configuration.md | 1 + src/cmd/serve.rs | 9 +++++++++ src/config/models/mod.rs | 1 + src/config/models/proxy.rs | 4 ++++ src/config/models/serve.rs | 4 ++++ src/config/rt/serve.rs | 1 + src/serve/mod.rs | 1 + src/serve/proxy.rs | 10 +++++++++- 8 files changed, 30 insertions(+), 1 deletion(-) diff --git a/site/content/configuration.md b/site/content/configuration.md index 6ca26795..57a3765f 100644 --- a/site/content/configuration.md +++ b/site/content/configuration.md @@ -119,6 +119,7 @@ ws = false # Use WebSocket for this proxy insecure = false # Disable certificate validation no_system_proxy = false # Disable system proxy rewrite = "" # Strip the given prefix off paths +no_redirect = false # Disable following redirects of proxy responses ``` ## Hooks section diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index dd95f412..0e533349 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -90,6 +90,13 @@ pub struct ProxyArgs { requires = "proxy_backend" )] pub proxy_no_system_proxy: bool, + /// Configure the proxy to not automatically follow redirects if a backend responds with a redirect + #[arg( + long, + env = "TRUNK_SERVE_PROXY_NO_REDIRECT", + requires = "proxy_backend" + )] + pub proxy_no_redirect: bool, } impl Serve { @@ -107,6 +114,7 @@ impl Serve { proxy_ws, proxy_insecure, proxy_no_system_proxy, + proxy_no_redirect, }, no_autoreload, no_error_reporting, @@ -148,6 +156,7 @@ impl Serve { ws: proxy_ws, insecure: proxy_insecure, no_system_proxy: proxy_no_system_proxy, + no_redirect: proxy_no_redirect, }); } diff --git a/src/config/models/mod.rs b/src/config/models/mod.rs index c2c0e0b2..94d6eff9 100644 --- a/src/config/models/mod.rs +++ b/src/config/models/mod.rs @@ -106,6 +106,7 @@ impl ConfigModel for Configuration { ws: self.serve.proxy_ws.unwrap_or_default(), insecure: self.serve.proxy_insecure.unwrap_or_default(), no_system_proxy: self.serve.proxy_no_system_proxy.unwrap_or_default(), + no_redirect: self.serve.proxy_no_redirect.unwrap_or_default(), }) } diff --git a/src/config/models/proxy.rs b/src/config/models/proxy.rs index 42f2ed7f..d0797ba5 100644 --- a/src/config/models/proxy.rs +++ b/src/config/models/proxy.rs @@ -28,6 +28,10 @@ pub struct Proxy { #[serde(alias = "no-system-proxy")] #[serde(default)] pub no_system_proxy: bool, + /// Automatically redirect proxy requests? `no_redirect` Defaults to + /// `false`, i.e. yes, follow redirects automatically. + #[serde(default)] + pub no_redirect: bool, } #[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, JsonSchema)] diff --git a/src/config/models/serve.rs b/src/config/models/serve.rs index ad0c2c99..ffc51db5 100644 --- a/src/config/models/serve.rs +++ b/src/config/models/serve.rs @@ -52,6 +52,9 @@ pub struct Serve { /// A base path to serve the application from #[serde(default)] pub serve_base: Option, + /// Configure the proxy to not follow redirects + #[serde(default)] + pub proxy_no_redirect: Option, /// A URL to which requests will be proxied [default: None] #[deprecated] @@ -98,6 +101,7 @@ impl Default for Serve { proxy_ws: None, proxy_insecure: None, proxy_no_system_proxy: None, + proxy_no_redirect: None, } } } diff --git a/src/config/rt/serve.rs b/src/config/rt/serve.rs index a1919cb1..bec0939b 100644 --- a/src/config/rt/serve.rs +++ b/src/config/rt/serve.rs @@ -93,6 +93,7 @@ impl RtcServe { proxy_ws: _, proxy_insecure: _, proxy_no_system_proxy: _, + proxy_no_redirect: _, } = config.serve; let tls = tls_config( diff --git a/src/serve/mod.rs b/src/serve/mod.rs index baa253e5..7264d7b7 100644 --- a/src/serve/mod.rs +++ b/src/serve/mod.rs @@ -384,6 +384,7 @@ fn router(state: Arc, cfg: Arc) -> Result { ProxyClientOptions { insecure: proxy.insecure, no_system_proxy: proxy.no_system_proxy, + redirect: !proxy.no_redirect, }, )?; } diff --git a/src/serve/proxy.rs b/src/serve/proxy.rs index b000efa0..cb99a3c8 100644 --- a/src/serve/proxy.rs +++ b/src/serve/proxy.rs @@ -5,6 +5,7 @@ use axum::http::Uri; use axum::Router; use console::Emoji; use http::HeaderMap; +use reqwest::redirect::Policy; use reqwest::Client; use std::collections::hash_map::Entry; use std::collections::HashMap; @@ -86,6 +87,7 @@ impl ProxyBuilder { pub(crate) struct ProxyClientOptions { pub insecure: bool, pub no_system_proxy: bool, + pub redirect: bool, } #[derive(Default)] @@ -107,7 +109,13 @@ impl ProxyClients { /// Create a new client for proxying fn create_client(opts: ProxyClientOptions) -> anyhow::Result { - let mut builder = reqwest::ClientBuilder::new().http1_only(); + let mut builder = reqwest::ClientBuilder::new() + .http1_only() + .redirect(if opts.redirect { + Policy::default() + } else { + Policy::none() + }); #[cfg(any(feature = "native-tls", feature = "rustls"))] if opts.insecure {