Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions codex-rs/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions codex-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ strum_macros = "0.28.0"
supports-color = "3.0.2"
syntect = "5"
sys-locale = "0.3.2"
system-configuration = "0.7"
tar = { version = "=0.4.45", default-features = false }
tempfile = "3.23.0"
test-log = "0.2.19"
Expand Down
7 changes: 6 additions & 1 deletion codex-rs/codex-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ tracing-opentelemetry = { workspace = true }
codex-utils-rustls-provider = { workspace = true }
zstd = { workspace = true }

[target.'cfg(target_os = "windows")'.dependencies]
[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies]
sha2 = { workspace = true }

[target.'cfg(target_os = "macos")'.dependencies]
system-configuration = { workspace = true }

[target.'cfg(target_os = "windows")'.dependencies]
windows-sys = { version = "0.52", features = [
"Win32_Foundation",
"Win32_Networking_WinHttp",
Expand Down
34 changes: 25 additions & 9 deletions codex-rs/codex-client/src/outbound_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@ use std::time::Instant;

use crate::custom_ca::BuildCustomCaTransportError;
use crate::custom_ca::build_reqwest_client_with_custom_ca;
#[cfg(target_os = "windows")]
#[cfg(any(target_os = "windows", target_os = "macos"))]
use sha2::Digest;
#[cfg(target_os = "windows")]
#[cfg(any(target_os = "windows", target_os = "macos"))]
use sha2::Sha256;
use thiserror::Error;

const SYSTEM_PROXY_SUCCESS_CACHE_TTL: Duration = Duration::from_secs(60);
const SYSTEM_PROXY_UNAVAILABLE_CACHE_TTL: Duration = Duration::from_secs(5);
const SYSTEM_PROXY_CACHE_MAX_ENTRIES: usize = 256;

#[cfg(target_os = "macos")]
mod macos;
#[cfg(target_os = "windows")]
mod windows;

Expand Down Expand Up @@ -115,15 +117,23 @@ impl From<BuildRouteAwareHttpClientError> for io::Error {
/// Builds a reqwest client with conservative route selection and shared CA handling.
///
/// Unavailable platform resolution falls back to environment proxies and then direct. Errors after
/// a route is selected are returned without trying another route.
/// a route is selected are returned without trying another route. Ordered PAC candidates are
/// currently collapsed to one route on both Windows and macOS; later proxy or `DIRECT` candidates
/// are not retried after a connection failure.
pub fn build_reqwest_client_for_route(
builder: reqwest::ClientBuilder,
request_url: &str,
route_class: ClientRouteClass,
config: Option<&OutboundProxyConfig>,
) -> Result<reqwest::Client, BuildRouteAwareHttpClientError> {
let builder =
configure_proxy_for_route(&ProcessEnv, builder, request_url, route_class, config)?;
let builder = configure_proxy_for_route(
&ProcessEnv,
builder,
request_url,
route_class,
config,
resolve_system_proxy,
)?;
build_reqwest_client_with_custom_ca(builder).map_err(Into::into)
}

Expand All @@ -133,6 +143,7 @@ fn configure_proxy_for_route(
request_url: &str,
route_class: ClientRouteClass,
config: Option<&OutboundProxyConfig>,
resolve_system_proxy: impl FnOnce(&str, &RequestOrigin) -> SystemProxyDecision,
) -> Result<reqwest::ClientBuilder, BuildRouteAwareHttpClientError> {
if config.is_none() {
return Ok(builder);
Expand Down Expand Up @@ -217,7 +228,7 @@ impl RequestOrigin {
}

#[cfg_attr(
not(target_os = "windows"),
not(any(target_os = "windows", target_os = "macos")),
allow(
dead_code,
reason = "Direct and Proxy are constructed only by platform-specific resolvers"
Expand All @@ -240,12 +251,17 @@ fn resolve_system_proxy(request_url: &str, origin: &RequestOrigin) -> SystemProx
decision
}

#[cfg(target_os = "macos")]
fn resolve_platform_system_proxy(request_url: &str, origin: &RequestOrigin) -> SystemProxyDecision {
macos::resolve(request_url, origin)
}

#[cfg(target_os = "windows")]
fn resolve_platform_system_proxy(request_url: &str, origin: &RequestOrigin) -> SystemProxyDecision {
windows::resolve(request_url, origin)
}

#[cfg(not(target_os = "windows"))]
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn resolve_platform_system_proxy(
_request_url: &str,
_origin: &RequestOrigin,
Expand Down Expand Up @@ -317,7 +333,7 @@ fn insert_system_proxy_cache_entry(
}

fn system_proxy_cache_key(request_url: &str) -> String {
#[cfg(target_os = "windows")]
#[cfg(any(target_os = "windows", target_os = "macos"))]
{
// Keep URL-specific PAC decisions without retaining the raw routed URL.
let mut hasher = Sha256::new();
Expand All @@ -326,7 +342,7 @@ fn system_proxy_cache_key(request_url: &str) -> String {
format!("{:x}", hasher.finalize())
}

#[cfg(not(target_os = "windows"))]
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
request_url.to_string()
}

Expand Down
Loading
Loading