mirror of
https://github.com/openai/codex.git
synced 2026-09-04 15:08:45 +00:00
Add system proxy routing to network proxy
This commit is contained in:
1
codex-rs/Cargo.lock
generated
1
codex-rs/Cargo.lock
generated
@@ -3451,6 +3451,7 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"clap",
|
||||
"codex-client",
|
||||
"codex-utils-absolute-path",
|
||||
"codex-utils-home-dir",
|
||||
"codex-utils-rustls-provider",
|
||||
|
||||
@@ -31,7 +31,9 @@ pub use crate::outbound_proxy::ClientRouteClass;
|
||||
pub use crate::outbound_proxy::OutboundProxyConfig;
|
||||
pub use crate::outbound_proxy::OutboundProxyMode;
|
||||
pub use crate::outbound_proxy::RouteFailureClass;
|
||||
pub use crate::outbound_proxy::SystemProxyRouteDecision;
|
||||
pub use crate::outbound_proxy::build_reqwest_client_for_route;
|
||||
pub use crate::outbound_proxy::resolve_system_proxy_for_url;
|
||||
pub use crate::request::PreparedRequestBody;
|
||||
pub use crate::request::Request;
|
||||
pub use crate::request::RequestBody;
|
||||
|
||||
@@ -109,6 +109,14 @@ impl fmt::Display for RouteFailureClass {
|
||||
}
|
||||
}
|
||||
|
||||
/// URL-specific system proxy decision from the platform resolver.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum SystemProxyRouteDecision {
|
||||
Direct,
|
||||
Proxy { url: String },
|
||||
Unavailable { failure: RouteFailureClass },
|
||||
}
|
||||
|
||||
/// How a resolver-aware client should choose an outbound proxy.
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum OutboundProxyMode {
|
||||
@@ -383,6 +391,36 @@ enum SystemProxyDecision {
|
||||
Unavailable { failure: RouteFailureClass },
|
||||
}
|
||||
|
||||
impl From<SystemProxyDecision> for SystemProxyRouteDecision {
|
||||
fn from(decision: SystemProxyDecision) -> Self {
|
||||
match decision {
|
||||
SystemProxyDecision::Direct => Self::Direct,
|
||||
SystemProxyDecision::Proxy { url } => Self::Proxy { url },
|
||||
SystemProxyDecision::Unavailable { failure } => Self::Unavailable { failure },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve system proxy/PAC routing for a single outbound URL.
|
||||
pub fn resolve_system_proxy_for_url(
|
||||
request_url: &str,
|
||||
include_auto_detect: bool,
|
||||
) -> SystemProxyRouteDecision {
|
||||
if !SystemProxyEnvOverride::from_env().system_discovery_enabled() || !system_proxy_supported() {
|
||||
return SystemProxyRouteDecision::Unavailable {
|
||||
failure: RouteFailureClass::ProxyResolutionUnavailable,
|
||||
};
|
||||
}
|
||||
|
||||
let Some(origin) = RequestOrigin::parse(request_url) else {
|
||||
return SystemProxyRouteDecision::Unavailable {
|
||||
failure: RouteFailureClass::InvalidProxyConfig,
|
||||
};
|
||||
};
|
||||
|
||||
resolve_system_proxy(request_url, &origin, include_auto_detect).into()
|
||||
}
|
||||
|
||||
fn resolve_system_proxy(
|
||||
request_url: &str,
|
||||
origin: &RequestOrigin,
|
||||
|
||||
@@ -137,6 +137,7 @@ use crate::config_lock::config_without_lock_controls;
|
||||
use crate::config_lock::lock_layer_from_config;
|
||||
use crate::config_lock::read_config_lock_from_path;
|
||||
use codex_network_proxy::NetworkProxyConfig;
|
||||
use codex_network_proxy::UpstreamProxyMode;
|
||||
use toml::Value as TomlValue;
|
||||
use toml_edit::DocumentMut;
|
||||
|
||||
@@ -2483,6 +2484,21 @@ fn resolved_system_proxy_config(
|
||||
resolved_system_proxy_config_from_features(cfg, features.get(), mode_requirement)
|
||||
}
|
||||
|
||||
fn apply_system_proxy_feature_config_to_network_proxy(
|
||||
config: &mut NetworkProxyConfig,
|
||||
system_proxy: Option<&SystemProxyFeatureConfigToml>,
|
||||
) {
|
||||
let Some(system_proxy) = system_proxy else {
|
||||
return;
|
||||
};
|
||||
config.network.upstream_proxy_mode = match system_proxy.mode.unwrap_or_default() {
|
||||
SystemProxyFeatureModeToml::Auto => UpstreamProxyMode::Auto,
|
||||
SystemProxyFeatureModeToml::Env => UpstreamProxyMode::Env,
|
||||
SystemProxyFeatureModeToml::System => UpstreamProxyMode::System,
|
||||
SystemProxyFeatureModeToml::Direct => UpstreamProxyMode::Direct,
|
||||
};
|
||||
}
|
||||
|
||||
/// Resolves `[features.system_proxy]` for the initial cloud-config bootstrap.
|
||||
///
|
||||
/// This runs before cloud-managed config can be fetched, so it can only use
|
||||
@@ -3081,6 +3097,10 @@ impl Config {
|
||||
network_proxy,
|
||||
);
|
||||
}
|
||||
apply_system_proxy_feature_config_to_network_proxy(
|
||||
&mut configured_network_proxy_config,
|
||||
system_proxy.as_ref(),
|
||||
);
|
||||
configured_network_proxy_config.network.enabled = true;
|
||||
}
|
||||
let approval_policy_was_explicit =
|
||||
@@ -3841,6 +3861,10 @@ impl Config {
|
||||
network_proxy,
|
||||
);
|
||||
}
|
||||
apply_system_proxy_feature_config_to_network_proxy(
|
||||
&mut configured_network_proxy_config,
|
||||
self.system_proxy.as_ref(),
|
||||
);
|
||||
configured_network_proxy_config.network.enabled = true;
|
||||
}
|
||||
configured_network_proxy_config
|
||||
|
||||
@@ -18,6 +18,7 @@ async-trait = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
clap = { workspace = true, features = ["derive"] }
|
||||
chrono = { workspace = true }
|
||||
codex-client = { workspace = true }
|
||||
codex-utils-absolute-path = { workspace = true }
|
||||
codex-utils-home-dir = { workspace = true }
|
||||
codex-utils-rustls-provider = { workspace = true }
|
||||
|
||||
@@ -116,6 +116,16 @@ pub struct NetworkUnixSocketPermissions {
|
||||
pub entries: BTreeMap<String, NetworkUnixSocketPermission>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum UpstreamProxyMode {
|
||||
Auto,
|
||||
#[default]
|
||||
Env,
|
||||
System,
|
||||
Direct,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(default)]
|
||||
pub struct NetworkProxySettings {
|
||||
@@ -129,6 +139,8 @@ pub struct NetworkProxySettings {
|
||||
pub enable_socks5_udp: bool,
|
||||
pub allow_upstream_proxy: bool,
|
||||
#[serde(default)]
|
||||
pub upstream_proxy_mode: UpstreamProxyMode,
|
||||
#[serde(default)]
|
||||
pub dangerously_allow_non_loopback_proxy: bool,
|
||||
#[serde(default)]
|
||||
pub dangerously_allow_all_unix_sockets: bool,
|
||||
@@ -154,6 +166,7 @@ impl Default for NetworkProxySettings {
|
||||
socks_url: default_socks_url(),
|
||||
enable_socks5_udp: true,
|
||||
allow_upstream_proxy: true,
|
||||
upstream_proxy_mode: UpstreamProxyMode::default(),
|
||||
dangerously_allow_non_loopback_proxy: false,
|
||||
dangerously_allow_all_unix_sockets: false,
|
||||
mode: NetworkMode::default(),
|
||||
@@ -586,6 +599,7 @@ mod tests {
|
||||
socks_url: "http://127.0.0.1:8081".to_string(),
|
||||
enable_socks5_udp: true,
|
||||
allow_upstream_proxy: true,
|
||||
upstream_proxy_mode: UpstreamProxyMode::Env,
|
||||
dangerously_allow_non_loopback_proxy: false,
|
||||
dangerously_allow_all_unix_sockets: false,
|
||||
mode: NetworkMode::Full,
|
||||
|
||||
@@ -383,7 +383,25 @@ async fn http_connect_proxy(upgraded: Upgraded) -> Result<(), Infallible> {
|
||||
};
|
||||
|
||||
let proxy = if allow_upstream_proxy {
|
||||
proxy_for_connect()
|
||||
let upstream_proxy_mode = match app_state.upstream_proxy_mode().await {
|
||||
Ok(mode) => mode,
|
||||
Err(err) => {
|
||||
error!("failed to read upstream proxy mode: {err}");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let target_host = target.host.to_string();
|
||||
let target_url = https_url_for_host_port(&target_host, target.port);
|
||||
match proxy_for_connect(&target_url, upstream_proxy_mode) {
|
||||
Ok(proxy) => proxy,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"CONNECT upstream proxy resolution failed (host={}, port={}): {err}",
|
||||
target.host, target.port
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -786,7 +804,15 @@ async fn http_plain_proxy(
|
||||
Err(resp) => return Ok(resp),
|
||||
};
|
||||
let client = if allow_upstream_proxy {
|
||||
UpstreamClient::from_env_proxy(app_state.clone())
|
||||
let upstream_proxy_mode = match app_state
|
||||
.upstream_proxy_mode()
|
||||
.await
|
||||
.map_err(|err| internal_error("failed to read upstream proxy mode", err))
|
||||
{
|
||||
Ok(mode) => mode,
|
||||
Err(resp) => return Ok(resp),
|
||||
};
|
||||
UpstreamClient::from_proxy_mode(app_state.clone(), upstream_proxy_mode)
|
||||
} else {
|
||||
UpstreamClient::direct(app_state.clone())
|
||||
};
|
||||
@@ -837,6 +863,15 @@ fn client_addr<T: ExtensionsRef>(input: &T) -> Option<String> {
|
||||
.map(|info| info.peer_addr().to_string())
|
||||
}
|
||||
|
||||
fn https_url_for_host_port(host: &str, port: u16) -> String {
|
||||
let host = if host.contains(':') && !host.starts_with('[') {
|
||||
format!("[{host}]")
|
||||
} else {
|
||||
host.to_string()
|
||||
};
|
||||
format!("https://{host}:{port}/")
|
||||
}
|
||||
|
||||
fn validate_absolute_form_host_header(
|
||||
req: &Request,
|
||||
request_ctx: &RequestContext,
|
||||
|
||||
@@ -25,6 +25,7 @@ pub use config::NetworkMode;
|
||||
pub use config::NetworkProxyConfig;
|
||||
pub use config::NetworkUnixSocketPermission;
|
||||
pub use config::NetworkUnixSocketPermissions;
|
||||
pub use config::UpstreamProxyMode;
|
||||
pub use config::host_and_port_from_network_addr;
|
||||
pub use mitm_hook::InjectedHeaderConfig;
|
||||
pub use mitm_hook::MitmHookActionsConfig;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::certs::ManagedMitmCa;
|
||||
use crate::config::NetworkMode;
|
||||
use crate::config::UpstreamProxyMode;
|
||||
use crate::mitm_hook::HookEvaluation;
|
||||
use crate::mitm_hook::MitmHookActions;
|
||||
use crate::policy::normalize_host;
|
||||
@@ -61,6 +62,7 @@ pub struct MitmState {
|
||||
|
||||
pub(crate) struct MitmUpstreamConfig {
|
||||
pub(crate) allow_upstream_proxy: bool,
|
||||
pub(crate) upstream_proxy_mode: UpstreamProxyMode,
|
||||
pub(crate) allow_local_binding: bool,
|
||||
}
|
||||
|
||||
@@ -109,7 +111,10 @@ impl MitmState {
|
||||
let ca = ManagedMitmCa::load_or_create()?;
|
||||
|
||||
let upstream = if config.allow_upstream_proxy {
|
||||
UpstreamClient::from_env_proxy_with_allow_local_binding(config.allow_local_binding)
|
||||
UpstreamClient::from_proxy_mode_with_allow_local_binding(
|
||||
config.upstream_proxy_mode,
|
||||
config.allow_local_binding,
|
||||
)
|
||||
} else {
|
||||
UpstreamClient::direct_with_allow_local_binding(config.allow_local_binding)
|
||||
};
|
||||
|
||||
@@ -546,6 +546,12 @@ impl NetworkProxyState {
|
||||
Ok(guard.config.network.allow_upstream_proxy)
|
||||
}
|
||||
|
||||
pub async fn upstream_proxy_mode(&self) -> Result<crate::config::UpstreamProxyMode> {
|
||||
self.reload_if_needed().await?;
|
||||
let guard = self.state.read().await;
|
||||
Ok(guard.config.network.upstream_proxy_mode)
|
||||
}
|
||||
|
||||
pub async fn allow_local_binding(&self) -> Result<bool> {
|
||||
self.reload_if_needed().await?;
|
||||
let guard = self.state.read().await;
|
||||
|
||||
@@ -76,6 +76,7 @@ pub fn build_config_state(
|
||||
let mitm = if config.network.mitm {
|
||||
Some(Arc::new(MitmState::new(MitmUpstreamConfig {
|
||||
allow_upstream_proxy: config.network.allow_upstream_proxy,
|
||||
upstream_proxy_mode: config.network.upstream_proxy_mode,
|
||||
allow_local_binding: config.network.allow_local_binding,
|
||||
})?))
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use crate::config::UpstreamProxyMode;
|
||||
use crate::connect_policy::TargetCheckedTcpConnector;
|
||||
use crate::state::NetworkProxyState;
|
||||
use codex_client::RouteFailureClass;
|
||||
use codex_client::SystemProxyRouteDecision;
|
||||
use codex_client::resolve_system_proxy_for_url;
|
||||
use codex_utils_rustls_provider::ensure_rustls_crypto_provider;
|
||||
use rama_core::Layer;
|
||||
use rama_core::Service;
|
||||
@@ -23,20 +27,33 @@ use rama_tls_rustls::client::TlsConnectorDataBuilder;
|
||||
use rama_tls_rustls::client::TlsConnectorLayer;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use thiserror::Error;
|
||||
use tracing::info;
|
||||
use tracing::warn;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
use rama_unix::client::UnixConnector;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum UpstreamProxyError {
|
||||
#[error("system proxy resolution failed: {0}")]
|
||||
SystemProxyUnavailable(RouteFailureClass),
|
||||
|
||||
#[error("system proxy returned invalid proxy URL: {url}")]
|
||||
InvalidSystemProxyUrl { url: String },
|
||||
|
||||
#[error("system proxy returned unsupported proxy protocol: {url}")]
|
||||
UnsupportedSystemProxyProtocol { url: String },
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
struct ProxyConfig {
|
||||
struct EnvProxyConfig {
|
||||
http: Option<ProxyAddress>,
|
||||
https: Option<ProxyAddress>,
|
||||
all: Option<ProxyAddress>,
|
||||
}
|
||||
|
||||
impl ProxyConfig {
|
||||
impl EnvProxyConfig {
|
||||
fn from_env() -> Self {
|
||||
let http = read_proxy_env(&["HTTP_PROXY", "http_proxy"]);
|
||||
let https = read_proxy_env(&["HTTPS_PROXY", "https_proxy"]);
|
||||
@@ -56,6 +73,83 @@ impl ProxyConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ProxyConfig {
|
||||
mode: UpstreamProxyMode,
|
||||
env: EnvProxyConfig,
|
||||
}
|
||||
|
||||
impl ProxyConfig {
|
||||
fn direct() -> Self {
|
||||
Self {
|
||||
mode: UpstreamProxyMode::Direct,
|
||||
env: EnvProxyConfig::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_mode(mode: UpstreamProxyMode) -> Self {
|
||||
Self {
|
||||
mode,
|
||||
env: EnvProxyConfig::from_env(),
|
||||
}
|
||||
}
|
||||
|
||||
fn proxy_for_url(
|
||||
&self,
|
||||
request_url: &str,
|
||||
is_secure: bool,
|
||||
) -> Result<Option<ProxyAddress>, UpstreamProxyError> {
|
||||
match self.mode {
|
||||
UpstreamProxyMode::Direct => Ok(None),
|
||||
UpstreamProxyMode::Env => Ok(self.env.proxy_for_protocol(is_secure)),
|
||||
UpstreamProxyMode::System => {
|
||||
system_proxy_for_url(request_url, /*include_auto_detect*/ true)
|
||||
}
|
||||
UpstreamProxyMode::Auto => {
|
||||
match system_proxy_for_url(request_url, /*include_auto_detect*/ true) {
|
||||
Ok(proxy) => Ok(proxy),
|
||||
Err(err) => {
|
||||
warn!("system proxy unavailable; falling back to env proxy ({err})");
|
||||
Ok(self.env.proxy_for_protocol(is_secure))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn system_proxy_for_url(
|
||||
request_url: &str,
|
||||
include_auto_detect: bool,
|
||||
) -> Result<Option<ProxyAddress>, UpstreamProxyError> {
|
||||
match resolve_system_proxy_for_url(request_url, include_auto_detect) {
|
||||
SystemProxyRouteDecision::Direct => Ok(None),
|
||||
SystemProxyRouteDecision::Proxy { url } => proxy_address_from_system_url(&url).map(Some),
|
||||
SystemProxyRouteDecision::Unavailable { failure } => {
|
||||
Err(UpstreamProxyError::SystemProxyUnavailable(failure))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn proxy_address_from_system_url(proxy_url: &str) -> Result<ProxyAddress, UpstreamProxyError> {
|
||||
let proxy = ProxyAddress::try_from(proxy_url).map_err(|_| {
|
||||
UpstreamProxyError::InvalidSystemProxyUrl {
|
||||
url: proxy_url.to_string(),
|
||||
}
|
||||
})?;
|
||||
if proxy
|
||||
.protocol
|
||||
.as_ref()
|
||||
.map(rama_net::Protocol::is_http)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
return Ok(proxy);
|
||||
}
|
||||
Err(UpstreamProxyError::UnsupportedSystemProxyProtocol {
|
||||
url: proxy_url.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
fn read_proxy_env(keys: &[&str]) -> Option<ProxyAddress> {
|
||||
for key in keys {
|
||||
let Ok(value) = std::env::var(key) else {
|
||||
@@ -85,8 +179,11 @@ fn read_proxy_env(keys: &[&str]) -> Option<ProxyAddress> {
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn proxy_for_connect() -> Option<ProxyAddress> {
|
||||
ProxyConfig::from_env().proxy_for_protocol(/*is_secure*/ true)
|
||||
pub(crate) fn proxy_for_connect(
|
||||
request_url: &str,
|
||||
mode: UpstreamProxyMode,
|
||||
) -> Result<Option<ProxyAddress>, UpstreamProxyError> {
|
||||
ProxyConfig::from_mode(mode).proxy_for_url(request_url, /*is_secure*/ true)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -101,29 +198,29 @@ pub(crate) struct UpstreamClient {
|
||||
|
||||
impl UpstreamClient {
|
||||
pub(crate) fn direct(state: Arc<NetworkProxyState>) -> Self {
|
||||
Self::new(
|
||||
ProxyConfig::default(),
|
||||
TargetCheckedTcpConnector::new(state),
|
||||
)
|
||||
Self::new(ProxyConfig::direct(), TargetCheckedTcpConnector::new(state))
|
||||
}
|
||||
|
||||
pub(crate) fn from_env_proxy(state: Arc<NetworkProxyState>) -> Self {
|
||||
pub(crate) fn from_proxy_mode(state: Arc<NetworkProxyState>, mode: UpstreamProxyMode) -> Self {
|
||||
Self::new(
|
||||
ProxyConfig::from_env(),
|
||||
ProxyConfig::from_mode(mode),
|
||||
TargetCheckedTcpConnector::new(state),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn direct_with_allow_local_binding(allow_local_binding: bool) -> Self {
|
||||
Self::new(
|
||||
ProxyConfig::default(),
|
||||
ProxyConfig::direct(),
|
||||
TargetCheckedTcpConnector::from_allow_local_binding(allow_local_binding),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn from_env_proxy_with_allow_local_binding(allow_local_binding: bool) -> Self {
|
||||
pub(crate) fn from_proxy_mode_with_allow_local_binding(
|
||||
mode: UpstreamProxyMode,
|
||||
allow_local_binding: bool,
|
||||
) -> Self {
|
||||
Self::new(
|
||||
ProxyConfig::from_env(),
|
||||
ProxyConfig::from_mode(mode),
|
||||
TargetCheckedTcpConnector::from_allow_local_binding(allow_local_binding),
|
||||
)
|
||||
}
|
||||
@@ -133,7 +230,7 @@ impl UpstreamClient {
|
||||
let connector = build_unix_connector(path);
|
||||
Self {
|
||||
connector,
|
||||
proxy_config: ProxyConfig::default(),
|
||||
proxy_config: ProxyConfig::direct(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,12 +253,28 @@ impl Service<Request<Body>> for UpstreamClient {
|
||||
.as_ref()
|
||||
.map(|ctx| ctx.host_with_port().to_string())
|
||||
.unwrap_or_else(|| "<unknown>".to_string());
|
||||
let proxy = self.proxy_config.proxy_for_protocol(
|
||||
request_context
|
||||
.as_ref()
|
||||
.map(|ctx| ctx.protocol.is_secure())
|
||||
.unwrap_or(false),
|
||||
);
|
||||
let proxy = match request_context
|
||||
.as_ref()
|
||||
.map(|ctx| request_target_url(&req, ctx))
|
||||
.map(|request_url| {
|
||||
self.proxy_config.proxy_for_url(
|
||||
&request_url,
|
||||
request_context
|
||||
.as_ref()
|
||||
.map(|ctx| ctx.protocol.is_secure())
|
||||
.unwrap_or(false),
|
||||
)
|
||||
})
|
||||
.transpose()
|
||||
{
|
||||
Ok(proxy) => proxy.flatten(),
|
||||
Err(err) => {
|
||||
warn!("HTTP upstream proxy resolution failed (target={authority}): {err}");
|
||||
return Err(OpaqueError::from_display(format!(
|
||||
"upstream proxy resolution failed: {err}"
|
||||
)));
|
||||
}
|
||||
};
|
||||
match proxy.as_ref() {
|
||||
Some(proxy) => info!(
|
||||
"HTTP upstream route selected (target={authority}, route=upstream_proxy, proxy={})",
|
||||
@@ -219,6 +332,25 @@ impl Service<Request<Body>> for UpstreamClient {
|
||||
}
|
||||
}
|
||||
|
||||
fn request_target_url(req: &Request<Body>, request_context: &RequestContext) -> String {
|
||||
if req.uri().scheme_str().is_some() && req.uri().authority().is_some() {
|
||||
return req.uri().to_string();
|
||||
}
|
||||
|
||||
let scheme = if request_context.protocol.is_secure() {
|
||||
"https"
|
||||
} else {
|
||||
"http"
|
||||
};
|
||||
let authority = request_context.host_with_port();
|
||||
let path = req
|
||||
.uri()
|
||||
.path_and_query()
|
||||
.map(rama_http::uri::PathAndQuery::as_str)
|
||||
.unwrap_or("/");
|
||||
format!("{scheme}://{authority}{path}")
|
||||
}
|
||||
|
||||
fn build_http_connector(
|
||||
transport: TargetCheckedTcpConnector,
|
||||
) -> BoxService<
|
||||
|
||||
Reference in New Issue
Block a user