Route exec-server HTTP through configured proxy policy (#35023)

## Why

Delegated HTTP requests need to honor the same outbound proxy policy as the
Codex process that starts the exec server.

## What changed

- Pass the configured `HttpClientFactory` through local and remote exec-server
  startup and use route-aware client pools for delegated HTTP and local MCP
  requests.
- Preserve per-request timeouts and follow-or-stop redirect behavior while
  keeping request URLs and sensitive response headers out of diagnostics.

## Testing

- Cover configured system-proxy routing across the exec-server transport.
- Cover both redirect policies and verify that success and failure logs do not
  expose request or response secrets.

GitOrigin-RevId: 4af6aec1d265c4db62dfcb6e1fb076fb31736137
This commit is contained in:
Celia Chen
2026-07-23 22:39:28 +00:00
committed by copyberry
parent fe0d472c4c
commit 1ee8f49175
25 changed files with 569 additions and 85 deletions
+22 -5
View File
@@ -12,6 +12,7 @@ use axum::response::IntoResponse;
use axum::response::Response;
use axum::routing::any;
use axum::routing::get;
use codex_http_client::HttpClientFactory;
use std::io::Write as _;
use std::net::SocketAddr;
use tokio::io;
@@ -83,20 +84,32 @@ pub(crate) async fn run_transport(
listen_url: &str,
runtime_paths: ExecServerRuntimePaths,
telemetry: ExecServerTelemetry,
http_client_factory: HttpClientFactory,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
match parse_listen_url(listen_url)? {
ExecServerListenTransport::WebSocket(bind_address) => {
run_websocket_listener(bind_address, runtime_paths, telemetry).await
run_websocket_listener(bind_address, runtime_paths, telemetry, http_client_factory)
.await
}
ExecServerListenTransport::Stdio => {
run_stdio_connection(runtime_paths, telemetry, http_client_factory).await
}
ExecServerListenTransport::Stdio => run_stdio_connection(runtime_paths, telemetry).await,
}
}
async fn run_stdio_connection(
runtime_paths: ExecServerRuntimePaths,
telemetry: ExecServerTelemetry,
http_client_factory: HttpClientFactory,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
run_stdio_connection_with_io(io::stdin(), io::stdout(), runtime_paths, telemetry).await
run_stdio_connection_with_io(
io::stdin(),
io::stdout(),
runtime_paths,
telemetry,
http_client_factory,
)
.await
}
async fn run_stdio_connection_with_io<R, W>(
@@ -104,12 +117,14 @@ async fn run_stdio_connection_with_io<R, W>(
writer: W,
runtime_paths: ExecServerRuntimePaths,
telemetry: ExecServerTelemetry,
http_client_factory: HttpClientFactory,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
where
R: AsyncRead + Unpin + Send + 'static,
W: AsyncWrite + Unpin + Send + 'static,
{
let processor = ConnectionProcessor::new_with_telemetry(runtime_paths, telemetry);
let processor =
ConnectionProcessor::new_with_telemetry(runtime_paths, telemetry, http_client_factory);
tracing::info!("codex-exec-server listening on stdio");
processor
.run_connection(
@@ -126,10 +141,12 @@ async fn run_websocket_listener(
bind_address: SocketAddr,
runtime_paths: ExecServerRuntimePaths,
telemetry: ExecServerTelemetry,
http_client_factory: HttpClientFactory,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let listener = TcpListener::bind(bind_address).await?;
let local_addr = listener.local_addr()?;
let processor = ConnectionProcessor::new_with_telemetry(runtime_paths, telemetry);
let processor =
ConnectionProcessor::new_with_telemetry(runtime_paths, telemetry, http_client_factory);
info!("codex-exec-server listening on ws://{local_addr}");
println!("ws://{local_addr}");
std::io::stdout().flush()?;