Use the shared HTTP client for TUI network checks (#35821)

## Why

TUI update checks and local OSS provider detection constructed their own HTTP
clients instead of using Codex's shared client behavior.

## What changed

- Route update requests through the configured route-aware client pool while
  retaining the existing default headers and custom CA fallback.
- Probe the hardcoded LM Studio and Ollama loopback endpoints with a shared
  direct client and a per-request timeout.
- Limit the legacy invalid-custom-CA fallback to the default routing policy so
  system-proxy routing still reports certificate configuration errors.

## Testing

Add coverage for local provider probes with invalid `CODEX_CA_CERTIFICATE` and
`SSL_CERT_FILE` values, and for custom CA fallback under both routing policies.

GitOrigin-RevId: b5c230b61e8964b3f1af3395052361ff716d6ce1
This commit is contained in:
Celia Chen authored and copyberry committed 2026-07-28 19:58:25 +00:00
1 parent dd6b880353
commit 8bbdf6c8f9
5 files changed
+175 -22

No files matched your search

+27 -9
View File
@@ -13,7 +13,10 @@ use crate::updates_cache::read_version_info;
use crate::updates_cache::version_filepath;
use chrono::Duration;
use chrono::Utc;
use codex_login::default_client::create_client;
use codex_http_client::ClientRouteClass;
use codex_http_client::HttpClientFactory;
use codex_http_client::RouteAwareClientPool;
use codex_login::default_client::default_headers;
use serde::Deserialize;
use std::path::Path;
@@ -34,11 +37,12 @@ pub fn get_upgrade_version(config: &Config) -> Option<String> {
None => true,
Some(info) => info.last_checked_at < Utc::now() - Duration::hours(20),
} {
let http_client_factory = config.http_client_factory();
// Refresh the cached latest version in the background so TUI startup
// isn’t blocked by a network call. The UI reads the previously cached
// value (if any) for this run; the next run shows the banner if needed.
tokio::spawn(async move {
check_for_update(&version_file, action)
check_for_update(&version_file, action, http_client_factory)
.await
.inspect_err(|e| tracing::error!("Failed to update version: {e}"))
});
@@ -67,11 +71,21 @@ struct HomebrewCaskInfo {
version: String,
}
async fn check_for_update(version_file: &Path, action: Option<UpdateAction>) -> anyhow::Result<()> {
async fn check_for_update(
version_file: &Path,
action: Option<UpdateAction>,
http_client_factory: HttpClientFactory,
) -> anyhow::Result<()> {
let client_pool = RouteAwareClientPool::with_chatgpt_cloudflare_cookies(
http_client_factory,
ClientRouteClass::Other,
)
.with_legacy_custom_ca_fallback();
let latest_version = match action {
Some(UpdateAction::BrewUpgrade) => {
let HomebrewCaskInfo { version } = create_client()
let HomebrewCaskInfo { version } = client_pool
.get(HOMEBREW_CASK_API_URL)
.headers(default_headers())
.send()
.await?
.error_for_status()?
@@ -82,9 +96,10 @@ async fn check_for_update(version_file: &Path, action: Option<UpdateAction>) ->
Some(UpdateAction::NpmGlobalLatest)
| Some(UpdateAction::BunGlobalLatest)
| Some(UpdateAction::PnpmGlobalLatest) => {
let latest_version = fetch_latest_github_release_version().await?;
let package_info = create_client()
let latest_version = fetch_latest_github_release_version(&client_pool).await?;
let package_info = client_pool
.get(npm_registry::PACKAGE_URL)
.headers(default_headers())
.send()
.await?
.error_for_status()?
@@ -94,7 +109,7 @@ async fn check_for_update(version_file: &Path, action: Option<UpdateAction>) ->
latest_version
}
Some(UpdateAction::StandaloneUnix) | Some(UpdateAction::StandaloneWindows) | None => {
fetch_latest_github_release_version().await?
fetch_latest_github_release_version(&client_pool).await?
}
};
@@ -114,11 +129,14 @@ async fn check_for_update(version_file: &Path, action: Option<UpdateAction>) ->
Ok(())
}
async fn fetch_latest_github_release_version() -> anyhow::Result<String> {
async fn fetch_latest_github_release_version(
client_pool: &RouteAwareClientPool,
) -> anyhow::Result<String> {
let ReleaseInfo {
tag_name: latest_tag_name,
} = create_client()
} = client_pool
.get(LATEST_RELEASE_URL)
.headers(default_headers())
.send()
.await?
.error_for_status()?