Support configured ChatGPT cookies in HTTP clients (#36984)

## What changed

- Let `HttpClientFactory` carry additional ChatGPT cookies and share their store across cloned factories.
- Attach configured cookies when route-aware clients or explicitly opted-in clients enable the ChatGPT cookie store.
- Combine configured cookies with the current path-scoped Cloudflare cookies only for HTTPS ChatGPT hosts, while preserving sensitive-header metadata.

## Testing

- Cover cookie merging, path-scoped Cloudflare updates, host and scheme restrictions, sensitive values, and factory clone/equality behavior.

GitOrigin-RevId: 5baf745859e14db739fd62ab931720dbe90c04e0
This commit is contained in:
stevenlee-oai authored and copyberry committed 2026-08-04 22:18:09 +00:00
1 parent bf05737da4
commit 411f3f0680
4 files changed
+198 -4

No files matched your search

+19 -3
View File
@@ -6,6 +6,7 @@
//! paths.
use http::HeaderMap;
use std::sync::Arc;
use std::time::Duration;
use crate::BuildCustomCaTransportError;
@@ -14,6 +15,7 @@ use crate::ClientRouteClass;
use crate::HttpClient;
use crate::HttpClientFactory;
use crate::OutboundProxyRoute;
use crate::chatgpt_cloudflare_cookies::ChatGptCookieStore;
use crate::client::RequestLogging;
use crate::custom_ca::build_reqwest_client_with_custom_ca;
use crate::with_chatgpt_cloudflare_cookie_store;
@@ -29,6 +31,7 @@ pub struct HttpClientBuilder {
follow_redirects: bool,
connect_timeout: Option<Duration>,
chatgpt_cloudflare_cookie_store: bool,
chatgpt_cookie_store: Option<Arc<ChatGptCookieStore>>,
request_logging: RequestLogging,
}
@@ -93,6 +96,13 @@ impl HttpClientBuilder {
self
}
/// Uses the factory's configured ChatGPT cookies without changing proxy behavior.
pub fn with_chatgpt_cookies(mut self, http_client_factory: &HttpClientFactory) -> Self {
self.chatgpt_cloudflare_cookie_store = true;
self.chatgpt_cookie_store = http_client_factory.chatgpt_cookie_store();
self
}
/// Suppresses request URL and response-header diagnostics.
pub fn without_request_logging(mut self) -> Self {
self.request_logging = RequestLogging::Disabled;
@@ -105,11 +115,12 @@ impl HttpClientBuilder {
/// resolve a concrete direct or proxy route when the factory is configured with
/// [`crate::OutboundProxyPolicy::RespectSystemProxy`].
pub fn build_respecting_outbound_proxy_policy(
self,
mut self,
http_client_factory: &HttpClientFactory,
request_url: &str,
route_class: ClientRouteClass,
) -> Result<HttpClient, BuildRouteAwareHttpClientError> {
self.chatgpt_cookie_store = http_client_factory.chatgpt_cookie_store();
let (builder, request_logging) = self.into_reqwest_parts();
let inner = http_client_factory.build_reqwest_client(builder, request_url, route_class)?;
Ok(HttpClient::from_parts(inner, request_logging))
@@ -117,11 +128,12 @@ impl HttpClientBuilder {
/// Builds a client for a route that was already resolved by a route-aware caller.
pub(crate) fn build_for_resolved_route(
self,
mut self,
http_client_factory: &HttpClientFactory,
route_class: ClientRouteClass,
route: &OutboundProxyRoute,
) -> Result<HttpClient, BuildRouteAwareHttpClientError> {
self.chatgpt_cookie_store = http_client_factory.chatgpt_cookie_store();
let (builder, request_logging) = self.into_reqwest_parts();
let inner = http_client_factory.build_reqwest_client_for_resolved_route(
builder,
@@ -258,7 +270,10 @@ impl HttpClientBuilder {
builder = builder.connect_timeout(connect_timeout);
}
if self.chatgpt_cloudflare_cookie_store {
builder = with_chatgpt_cloudflare_cookie_store(builder);
builder = match self.chatgpt_cookie_store {
Some(store) => builder.cookie_provider(store),
None => with_chatgpt_cloudflare_cookie_store(builder),
};
}
builder
}
@@ -271,6 +286,7 @@ impl Default for HttpClientBuilder {
follow_redirects: true,
connect_timeout: None,
chatgpt_cloudflare_cookie_store: false,
chatgpt_cookie_store: None,
request_logging: RequestLogging::Enabled,
}
}