Files
codex/codex-rs/http-client/src/lib.rs
T
smurching-oai 09ec2451bf Add request-scoped OAuth credentials and session lifecycle APIs (#56036)
## What changed

- Add `OAuthSessionRequest` to pair access tokens with their authorization identity and retain rejected-token recovery across transient failures and retries. New sign-ins receive an identity that survives token refresh.
- Expose explicit login, logout, and authorization identity lookup, plus a per-manager option to disable automatic browser login while allowing credential reuse and refresh.
- Move serializable `OAuthSessionConfig` into `codex-model-provider-info`, add an optional `device_authorization_url` field, and share endpoint URL validation through `codex-http-client`.
- Distinguish permission failures, transient token endpoint failures, and invalid responses using `io::ErrorKind`.

## Testing

Add coverage for sign-in identity preservation through refresh retries, removal of saved and cached credentials on logout, and suppression of automatic browser login. Extend token endpoint error classification coverage.

GitOrigin-RevId: ae9f72e787171e179fe139a3b840a9f7e1e46506
2026-10-22 01:07:13 +00:00

112 lines
4.1 KiB
Rust

use url::Host;
use url::Url;
mod chatgpt_cloudflare_cookies;
mod chatgpt_hosts;
mod client;
mod client_builder;
mod client_tls;
mod custom_ca;
mod error;
mod native_roots;
mod network_policy;
mod outbound_proxy;
mod request;
mod request_builder;
mod request_draft;
mod response;
mod retry_after;
mod route_aware_client_pool;
mod route_aware_redirect;
mod tls_backend_fallback;
mod transport;
pub use crate::chatgpt_cloudflare_cookies::with_chatgpt_cloudflare_cookie_store;
pub use crate::chatgpt_hosts::is_allowed_chatgpt_host;
pub use crate::client::HttpClient;
pub use crate::client::HttpError;
pub use crate::client_builder::HttpClientBuilder;
pub use crate::client_tls::HttpClientTlsConfig;
pub use crate::custom_ca::BuildCustomCaTransportError;
/// Test-only subprocess hook for custom CA coverage.
///
/// This stays public only so the `custom_ca_probe` binary target can reuse the shared helper. It
/// is hidden from normal docs because ordinary callers should use
/// [`build_reqwest_client_with_custom_ca`] instead.
#[doc(hidden)]
pub use crate::custom_ca::build_reqwest_client_for_subprocess_tests;
pub use crate::custom_ca::build_reqwest_client_with_custom_ca;
pub use crate::custom_ca::build_rustls_client_config_with_custom_ca;
pub use crate::custom_ca::maybe_build_rustls_client_config_with_custom_ca;
pub use crate::error::StreamError;
pub use crate::error::TransportError;
pub use crate::network_policy::DestinationPolicy;
pub use crate::network_policy::NetworkPermit;
pub use crate::network_policy::NetworkPolicy;
pub use crate::network_policy::NetworkPolicyController;
pub use crate::network_policy::NetworkPolicyDenied;
pub use crate::network_policy::NetworkPolicyRevision;
pub use crate::outbound_proxy::BuildRouteAwareHttpClientError;
pub use crate::outbound_proxy::ClientRouteClass;
pub use crate::outbound_proxy::HttpClientFactory;
#[cfg(target_os = "macos")]
pub use crate::outbound_proxy::MacosSystemProxyConfiguration;
pub use crate::outbound_proxy::OutboundProxyPolicy;
pub use crate::outbound_proxy::OutboundProxyRoute;
pub use crate::outbound_proxy::RouteFailureClass;
#[doc(hidden)]
pub use crate::outbound_proxy::cache_system_proxy_route_for_test;
#[cfg(target_os = "macos")]
pub use crate::outbound_proxy::macos_system_proxy_configuration;
pub use crate::request::EncodedJsonBody;
pub use crate::request::PreparedRequestBody;
pub use crate::request::Request;
pub use crate::request::RequestBody;
pub use crate::request::RequestCompression;
pub use crate::request::Response;
pub use crate::request_builder::RequestBuilder;
pub use crate::response::HttpResponse;
pub use crate::retry_after::RetryAfter;
pub use crate::route_aware_client_pool::RouteAwareClientPool;
pub use crate::route_aware_client_pool::RouteAwareClientPoolError;
pub use crate::route_aware_client_pool::RouteAwareRequestError;
pub use crate::transport::ByteStream;
pub use crate::transport::HttpTransport;
pub use crate::transport::ReqwestTransport;
pub use crate::transport::StreamResponse;
#[cfg(windows)]
mod windows_proxy_auth;
#[cfg(windows)]
mod windows_tls;
#[cfg(windows)]
pub use crate::windows_proxy_auth::WindowsProxyTls;
#[cfg(windows)]
pub use crate::windows_proxy_auth::connect_windows_proxy;
#[cfg(windows)]
pub use crate::windows_tls::build_windows_platform_tls_config;
/// Validates HTTPS or loopback HTTP endpoints, rejecting userinfo and fragments.
/// Errors identify the caller-supplied field without including the URL.
pub fn validate_endpoint_url(value: &str, field: &str) -> Result<Url, String> {
let url = Url::parse(value).map_err(|_| format!("invalid {field} URL"))?;
let loopback = match url.host() {
Some(Host::Domain(host)) => host.eq_ignore_ascii_case("localhost"),
Some(Host::Ipv4(host)) => host.is_loopback(),
Some(Host::Ipv6(host)) => host.is_loopback(),
None => false,
};
if url.host().is_none()
|| !url.username().is_empty()
|| url.password().is_some()
|| url.fragment().is_some()
|| !(url.scheme() == "https" || (url.scheme() == "http" && loopback))
{
return Err(format!(
"{field} must use HTTPS (or loopback HTTP), without userinfo or a fragment"
));
}
Ok(url)
}