fix(gix-transport): honour http.proxy in the blocking reqwest backend - #3016
沙漠之子 (maboloshi) wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Address the case-insensitive scheme handling and bound the no_proxy test’s direct connection time.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
This PR updates the blocking reqwest backend to honor configured HTTP proxies and no_proxy settings.
Changes:
- Lazily builds and refreshes clients from proxy configuration.
- Validates supported proxy schemes.
- Adds proxy behavior regression tests and documentation updates.
| File | Summary |
|---|---|
gix-transport/tests/blocking-transport-http-reqwest.rs |
Adds proxy tests; the no_proxy test may stall up to the connect timeout. |
gix-transport/src/client/blocking_io/http/reqwest/remote.rs |
Applies proxy configuration; scheme validation should be case-insensitive. |
gix-transport/src/client/blocking_io/http/mod.rs |
Updates documentation for supported backend options. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| Some((scheme, rest)) => (scheme, format!("{scheme}://{rest}")), | ||
| None => ("http", format!("http://{proxy}")), | ||
| }; | ||
| if !matches!(scheme, "http" | "https") { |
…kend The `reqwest` backend received the shared HTTP options - including `proxy` and `no_proxy` - via `TransportWithoutIO::configure()`, stored them, and then never read them. A configured proxy was therefore silently ignored and the request was sent directly, which only surfaced as an unrelated DNS or connection error. The `curl` backend has always honoured the same values. Proxies are configured on the `reqwest` client rather than on a single request, and the client was built in `Default for Remote`, before the first request and thus before any configuration was available. It is now built lazily from the configuration of the first request, and rebuilt whenever the client-level part of the configuration changes. The proxy value is interpreted the way `curl` does it: the scheme is optional and defaults to `http`, and an empty value disables proxying entirely (which also undoes a proxy from the environment, as `git` defines it). `no_proxy` is attached to the configured proxy. Schemes are matched case-insensitively, as they are in URLs generally, and schemes other than `http` and `https` are rejected with a dedicated error instead of being passed to a connector that cannot handle them. That fixes GitoxideLabs#3015
8079efc to
3f60b04
Compare
|
Addressed the review:
AI disclosure: this comment was written and posted by an AI agent (DeepSeek Harness) on behalf of 沙漠之子 (@maboloshi). |
|
Superseded by #3017. |

Fixes #3015.
What happens today
http.proxy(and thegix-specific proxy keys) are parsed bygixintogix_transport::client::blocking_io::http::Optionsand delivered to every HTTP backend throughTransportWithoutIO::configure(), but the blockingreqwestbackend only ever readextra_headersandfollow_redirectsfrom them. A configured proxy was silently ignored: the request went out directly and theonly symptom was an unrelated DNS/connection error. The
curlbackend honours the same values.The reason is structural: proxies are configured on the
reqwestclient (not on a single request), and theclient was built in
Default for Remotebefore the first request - and therefore the configuration - existed.What this changes
part of the configuration changes (
ClientConfig, currentlyproxy+no_proxy).proxyis applied to the client:None→ behaviour unchanged, i.e.reqwestkeeps using its own environment-based proxy detection(which is also why
http_proxyhappens to work today);Some("")→ proxying is disabled entirely, asgitdefines it, which also undoes an environment proxy;Some(v)→ the scheme is optional and defaults tohttp(curl-style, matching whatgix's own configlayer produces), then
reqwest::Proxy::all(v). An explicitly configured proxy replaces theenvironment/system proxy, as documented by
reqwest.no_proxyis attached viaProxy::no_proxy(NoProxy::from_string(..));*already means "bypasseverything" and is handled by
reqwest.http/https(e.g.socks5) are rejected with a newError::UnsupportedProxySchemeinstead of being handed to a connector that cannot handle them.
Tests
New tests in
gix-transport/tests/blocking-transport-http-reqwest.rsbind aTcpListeneron an ephemeralport as a stand-in proxy that records the request line, and request
http://git.invalid/repo- a host thatcannot be resolved, so a request can only arrive through the proxy:
proxy_configuration_is_usedproxy_without_scheme_defaults_to_httpproxy_scheme_is_case_insensitiveno_proxy_configuration_bypasses_the_proxyunsupported_proxy_scheme_is_reportedcargo test -p gix-transport --features http-client-reqwestpasses (39 + 9 tests). Reverting only the sourcechange, while keeping the tests, makes all of them fail except
no_proxy_configuration_bypasses_the_proxy-that one passed trivially before the fix because nothing was proxied at all, and now guards the
noProxywiring together with the proxy tests.
Known limitation of this shape:
no_proxyis attached to the proxy this backend builds, so anoProxyfromconfiguration cannot filter a proxy that
reqwestpicks up from the environment (the environment variableNO_PROXYstill works there, becausereqwestreads it itself). Filtering the system proxy would need acustom matcher, which seemed out of scope for this fix.
Not covered here
Options::proxy_authenticateis agix-credentialscallback, whilereqwestonlyoffers
basic_authfor proxies - that needs its own design.socks5/socks5h/socks4*proxies:gix-transportdeliberately depends onreqwestwithdefault-features = false, so supporting them means enablingreqwest/socksbehind a new cargo feature.The new error at least makes the limitation explicit instead of connecting somewhere nonsensical.
connect_timeoutis still hard-coded to 20s, plususer_agent,ssl_verify,ssl_ca_info,ssl_version,http_versionand the low-speed limits). Same class ofproblem; happy to follow up if you'd like them in scope.
AI disclosure: this PR was written and filed by an AI agent (DeepSeek Harness) on behalf of 沙漠之子 (@maboloshi). All
tests and commands were run locally against
c02041d41.