Route backend requests through the HTTP client factory (#34490)

## Why

Backend-backed features need to use the same outbound routing configuration as the rest of Codex.

## What changed

- Build the backend client on a route-aware client pool supplied by `HttpClientFactory`.
- Pass the configured factory through app-server account requests, cloud config loading, cloud tasks, and memory rate-limit checks.
- Preserve task query encoding, authentication headers, JSON request bodies, and ChatGPT cookie handling during the migration.

## Testing

- Add backend-client tests for proxy-policy propagation, task query encoding, bearer authentication, and JSON request bodies.

GitOrigin-RevId: c17d162e0dce9cec758df7cdeecf982207c6512b
This commit is contained in:
Michael Bolin authored and copyberry committed 2026-07-21 08:28:51 +00:00
1 parent d5998e7452
commit dc21b46aea
20 files changed
+365 -124

No files matched your search

@@ -7,8 +7,9 @@ use crate::types::RateLimitResetCreditsDetails;
use crate::types::RateLimitStatusWithResetCredits;
use crate::types::RateLimitsWithResetCredits;
use anyhow::Result;
use reqwest::header::CONTENT_TYPE;
use reqwest::header::HeaderValue;
use http::Method;
use http::header::CONTENT_TYPE;
use http::header::HeaderValue;
use serde::Serialize;
#[derive(Serialize)]
@@ -29,14 +30,14 @@ impl Client {
pub(super) async fn get_rate_limit_status(&self) -> Result<RateLimitStatusWithResetCredits> {
let url = self.rate_limit_status_url();
let req = self.http.get(&url).headers(self.headers());
let req = self.request(Method::GET, &url).headers(self.headers());
let (body, ct) = self.exec_request(req, "GET", &url).await?;
self.decode_json(&url, &ct, &body)
}
pub async fn list_rate_limit_reset_credits(&self) -> Result<RateLimitResetCreditsDetails> {
let url = self.rate_limit_reset_credits_url();
let req = self.http.get(&url).headers(self.headers());
let req = self.request(Method::GET, &url).headers(self.headers());
let (body, ct) = self.exec_request(req, "GET", &url).await?;
self.decode_json(&url, &ct, &body)
}
@@ -65,8 +66,7 @@ impl Client {
) -> Result<ConsumeRateLimitResetCreditResponse> {
let url = self.consume_rate_limit_reset_credit_url();
let req = self
.http
.post(&url)
.request(Method::POST, &url)
.headers(self.headers())
.header(CONTENT_TYPE, HeaderValue::from_static("application/json"))
.json(&ConsumeRateLimitResetCreditRequest {
@@ -138,7 +138,12 @@ fn rate_limit_reset_contract_uses_expected_paths_and_payloads() {
fn test_client(base_url: &str, path_style: PathStyle) -> Client {
Client {
base_url: base_url.to_string(),
http: reqwest::Client::new(),
http: codex_http_client::RouteAwareClientPool::new(
codex_http_client::HttpClientFactory::new(
codex_http_client::OutboundProxyPolicy::ReqwestDefault,
),
codex_http_client::ClientRouteClass::Api,
),
auth_provider: codex_model_provider::unauthenticated_auth_provider(),
user_agent: None,
chatgpt_account_id: None,