mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
chore: add minimal proxy egress diagnostics (#21220)
## Why Recent Auto Review reports show Git traffic hanging through the local proxy on both SSH and HTTPS paths. Today the support bundle does not make it obvious whether a request is stuck before upstream dialing, during the proxy hop, or after the upstream response begins, which slows down root-cause triage. This adds a small amount of runtime visibility at the existing proxy boundaries without changing routing or policy behavior. ## What changed - log whether HTTP and CONNECT traffic take the direct or upstream-proxy route - log start / success / failure timings for CONNECT, HTTP, and SOCKS5 upstream dials - log CONNECT forwarding lifecycle events - describe HTTP success at the response-header boundary that is actually observed, rather than implying the full body finished ## Verification - `cargo test -p codex-network-proxy` - `cargo clippy -p codex-network-proxy --all-targets -- -D warnings`
This commit is contained in:
committed by
GitHub
Unverified
parent
ed6082c9f9
commit
172303bbfa
@@ -75,6 +75,7 @@ use std::convert::Infallible;
|
||||
use std::net::SocketAddr;
|
||||
use std::net::TcpListener as StdTcpListener;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use tracing::error;
|
||||
use tracing::info;
|
||||
use tracing::warn;
|
||||
@@ -370,6 +371,16 @@ async fn http_connect_proxy(upgraded: Upgraded) -> Result<(), Infallible> {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
match proxy.as_ref() {
|
||||
Some(proxy) => info!(
|
||||
"CONNECT route selected (host={}, port={}, route=upstream_proxy, proxy={})",
|
||||
target.host, target.port, proxy.address
|
||||
),
|
||||
None => info!(
|
||||
"CONNECT route selected (host={}, port={}, route=direct)",
|
||||
target.host, target.port
|
||||
),
|
||||
}
|
||||
|
||||
if let Err(err) = forward_connect_tunnel(upgraded, proxy, app_state).await {
|
||||
warn!("tunnel error: {err}");
|
||||
@@ -402,21 +413,47 @@ async fn forward_connect_tunnel(
|
||||
let connector = TlsConnectorLayer::tunnel(None)
|
||||
.with_connector_data(tls_config)
|
||||
.into_layer(proxy_connector);
|
||||
let EstablishedClientConnection { conn: target, .. } =
|
||||
connector.connect(req).await.map_err(|err| {
|
||||
OpaqueError::from_boxed(err)
|
||||
info!("CONNECT upstream dial started (target={authority})");
|
||||
let connect_started_at = Instant::now();
|
||||
let EstablishedClientConnection { conn: target, .. } = match connector.connect(req).await {
|
||||
Ok(connection) => {
|
||||
info!(
|
||||
"CONNECT upstream dial established (target={authority}, elapsed_ms={})",
|
||||
connect_started_at.elapsed().as_millis()
|
||||
);
|
||||
connection
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"CONNECT upstream dial failed (target={authority}, elapsed_ms={})",
|
||||
connect_started_at.elapsed().as_millis()
|
||||
);
|
||||
return Err(OpaqueError::from_boxed(err)
|
||||
.with_context(|| format!("establish CONNECT tunnel to {authority}"))
|
||||
.into_boxed()
|
||||
})?;
|
||||
.into_boxed());
|
||||
}
|
||||
};
|
||||
|
||||
let proxy_req = ProxyRequest {
|
||||
source: upgraded,
|
||||
target,
|
||||
};
|
||||
info!("CONNECT tunnel forwarding started (target={authority})");
|
||||
let forward_started_at = Instant::now();
|
||||
StreamForwardService::default()
|
||||
.serve(proxy_req)
|
||||
.await
|
||||
.map(|_| {
|
||||
info!(
|
||||
"CONNECT tunnel forwarding completed (target={authority}, elapsed_ms={})",
|
||||
forward_started_at.elapsed().as_millis()
|
||||
);
|
||||
})
|
||||
.map_err(|err| {
|
||||
warn!(
|
||||
"CONNECT tunnel forwarding failed (target={authority}, elapsed_ms={})",
|
||||
forward_started_at.elapsed().as_millis()
|
||||
);
|
||||
OpaqueError::from_boxed(err.into())
|
||||
.with_context(|| format!("forward CONNECT tunnel to {authority}"))
|
||||
.into_boxed()
|
||||
|
||||
@@ -40,6 +40,7 @@ use std::io;
|
||||
use std::net::SocketAddr;
|
||||
use std::net::TcpListener as StdTcpListener;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use tracing::error;
|
||||
use tracing::info;
|
||||
use tracing::warn;
|
||||
@@ -290,7 +291,20 @@ async fn handle_socks5_tcp(
|
||||
}
|
||||
}
|
||||
|
||||
tcp_connector.serve(req).await
|
||||
info!("SOCKS upstream dial started (host={host}, port={port})");
|
||||
let connect_started_at = Instant::now();
|
||||
let result = tcp_connector.serve(req).await;
|
||||
match &result {
|
||||
Ok(_) => info!(
|
||||
"SOCKS upstream dial established (host={host}, port={port}, elapsed_ms={})",
|
||||
connect_started_at.elapsed().as_millis()
|
||||
),
|
||||
Err(_) => warn!(
|
||||
"SOCKS upstream dial failed (host={host}, port={port}, elapsed_ms={})",
|
||||
connect_started_at.elapsed().as_millis()
|
||||
),
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
async fn inspect_socks5_udp(
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::state::NetworkProxyState;
|
||||
use rama_core::Layer;
|
||||
use rama_core::Service;
|
||||
use rama_core::error::BoxError;
|
||||
use rama_core::error::ErrorContext as _;
|
||||
use rama_core::error::ErrorExt as _;
|
||||
use rama_core::error::OpaqueError;
|
||||
use rama_core::extensions::ExtensionsMut;
|
||||
use rama_core::extensions::ExtensionsRef;
|
||||
@@ -21,6 +21,8 @@ use rama_net::http::RequestContext;
|
||||
use rama_tls_rustls::client::TlsConnectorDataBuilder;
|
||||
use rama_tls_rustls::client::TlsConnectorLayer;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use tracing::info;
|
||||
use tracing::warn;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -41,13 +43,6 @@ impl ProxyConfig {
|
||||
Self { http, https, all }
|
||||
}
|
||||
|
||||
fn proxy_for_request(&self, req: &Request) -> Option<ProxyAddress> {
|
||||
let is_secure = RequestContext::try_from(req)
|
||||
.map(|ctx| ctx.protocol.is_secure())
|
||||
.unwrap_or(false);
|
||||
self.proxy_for_protocol(is_secure)
|
||||
}
|
||||
|
||||
fn proxy_for_protocol(&self, is_secure: bool) -> Option<ProxyAddress> {
|
||||
if is_secure {
|
||||
self.https
|
||||
@@ -155,28 +150,71 @@ impl Service<Request<Body>> for UpstreamClient {
|
||||
type Error = OpaqueError;
|
||||
|
||||
async fn serve(&self, mut req: Request<Body>) -> Result<Self::Output, Self::Error> {
|
||||
if let Some(proxy) = self.proxy_config.proxy_for_request(&req) {
|
||||
let request_context = RequestContext::try_from(&req).ok();
|
||||
let authority = request_context
|
||||
.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),
|
||||
);
|
||||
match proxy.as_ref() {
|
||||
Some(proxy) => info!(
|
||||
"HTTP upstream route selected (target={authority}, route=upstream_proxy, proxy={})",
|
||||
proxy.address
|
||||
),
|
||||
None => info!("HTTP upstream route selected (target={authority}, route=direct)"),
|
||||
}
|
||||
if let Some(proxy) = proxy {
|
||||
req.extensions_mut().insert(proxy);
|
||||
}
|
||||
|
||||
let uri = req.uri().clone();
|
||||
let connect_started_at = Instant::now();
|
||||
let EstablishedClientConnection {
|
||||
input: mut req,
|
||||
conn: http_connection,
|
||||
} = self
|
||||
.connector
|
||||
.serve(req)
|
||||
.await
|
||||
.map_err(OpaqueError::from_boxed)?;
|
||||
} = match self.connector.serve(req).await {
|
||||
Ok(connection) => {
|
||||
info!(
|
||||
"HTTP upstream connection established (target={authority}, elapsed_ms={})",
|
||||
connect_started_at.elapsed().as_millis()
|
||||
);
|
||||
connection
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"HTTP upstream connection failed (target={authority}, elapsed_ms={})",
|
||||
connect_started_at.elapsed().as_millis()
|
||||
);
|
||||
return Err(OpaqueError::from_boxed(err));
|
||||
}
|
||||
};
|
||||
|
||||
req.extensions_mut()
|
||||
.extend(http_connection.extensions().clone());
|
||||
|
||||
http_connection
|
||||
.serve(req)
|
||||
.await
|
||||
.map_err(OpaqueError::from_boxed)
|
||||
.with_context(|| format!("http request failure for uri: {uri}"))
|
||||
let request_started_at = Instant::now();
|
||||
match http_connection.serve(req).await {
|
||||
Ok(resp) => {
|
||||
info!(
|
||||
"HTTP upstream response headers received (target={authority}, elapsed_ms={})",
|
||||
request_started_at.elapsed().as_millis()
|
||||
);
|
||||
Ok(resp)
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"HTTP upstream response headers failed (target={authority}, elapsed_ms={})",
|
||||
request_started_at.elapsed().as_millis()
|
||||
);
|
||||
Err(OpaqueError::from_boxed(err)
|
||||
.context(format!("http request failure for uri: {uri}")))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user