Summary
Assigning client.proxy = "..." after construction throws away the entire client configuration and rebuilds a default reqwest client. TLS verification settings, custom CA bundles, the mTLS identity, redirect policy, https_only and timeout are all silently reset.
Cause
src/lib.rs:343 — set_proxy builds a brand-new client from a bare builder:
let new_client = reqwest::Client::builder()
.proxy(rproxy)
.build()
.map_err(map_reqwest_error)?;
None of the settings applied in new() are carried over, because RClient never retains them.
Reproduction
Verified against a local forward proxy plus a trustme-issued HTTPS server:
| setting at construction |
behaviour after client.proxy = <working proxy> |
verify=False |
lost — ConnectError on the self-signed cert (worked before) |
ca_cert_file=<trusted CA> |
lost — ConnectError, custom root gone |
follow_redirects=False |
lost — 302 became 200 |
https_only=True |
lost — plain-HTTP request now returns 200 instead of erroring |
timeout=1 |
lost — returned 200 against a 3s sleep instead of timing out |
client_pem / client_pem_data (mTLS) |
lost by the same code path |
client headers, referer |
preserved (re-applied per request from self.headers) |
Impact
This is a silent change in security posture: a client configured with a custom CA bundle or an mTLS identity quietly stops presenting/validating them. mTLS is one of the project's headline features. https_only=True being dropped is the most dangerous of the set, since traffic that was restricted to HTTPS can then go out in plaintext — over a proxy.
Proposed fix
Retain the configuration so it can be reapplied:
- Extract the body of
new() (src/lib.rs:120-247) into a fn build_client(cfg: &ClientConfig) -> PyResult<reqwest::Client>, where ClientConfig holds the constructor arguments.
- Store the
ClientConfig on RClient.
- Have
set_proxy update cfg.proxy and rebuild via build_client(&cfg).
This also removes the current duplication between new() and set_proxy.
Worth noting in the docs that reassigning .proxy rebuilds the client and drops the existing connection pool — it's an expensive operation either way.
Suggested tests
One test per row of the table above: assert the behaviour is unchanged across a .proxy assignment. The verify=False and https_only=True cases are the important ones.
Size
~2 hours — mostly the mechanical ClientConfig extraction.
Summary
Assigning
client.proxy = "..."after construction throws away the entire client configuration and rebuilds a default reqwest client. TLS verification settings, custom CA bundles, the mTLS identity, redirect policy,https_onlyandtimeoutare all silently reset.Cause
src/lib.rs:343—set_proxybuilds a brand-new client from a bare builder:None of the settings applied in
new()are carried over, becauseRClientnever retains them.Reproduction
Verified against a local forward proxy plus a
trustme-issued HTTPS server:client.proxy = <working proxy>verify=FalseConnectErroron the self-signed cert (worked before)ca_cert_file=<trusted CA>ConnectError, custom root gonefollow_redirects=False302became200https_only=True200instead of erroringtimeout=1200against a 3s sleep instead of timing outclient_pem/client_pem_data(mTLS)refererself.headers)Impact
This is a silent change in security posture: a client configured with a custom CA bundle or an mTLS identity quietly stops presenting/validating them. mTLS is one of the project's headline features.
https_only=Truebeing dropped is the most dangerous of the set, since traffic that was restricted to HTTPS can then go out in plaintext — over a proxy.Proposed fix
Retain the configuration so it can be reapplied:
new()(src/lib.rs:120-247) into afn build_client(cfg: &ClientConfig) -> PyResult<reqwest::Client>, whereClientConfigholds the constructor arguments.ClientConfigonRClient.set_proxyupdatecfg.proxyand rebuild viabuild_client(&cfg).This also removes the current duplication between
new()andset_proxy.Worth noting in the docs that reassigning
.proxyrebuilds the client and drops the existing connection pool — it's an expensive operation either way.Suggested tests
One test per row of the table above: assert the behaviour is unchanged across a
.proxyassignment. Theverify=Falseandhttps_only=Truecases are the important ones.Size
~2 hours — mostly the mechanical
ClientConfigextraction.