Current behavior 😯
When gix is compiled with the blocking reqwest backend (blocking-http-transport-reqwest*) and a proxy is configured in git configuration, the setting is parsed but silently ignored: the request is sent directly, the configured proxy never receives a connection, and nothing reports that the configuration had no effect.
gix-transport/src/client/blocking_io/http/reqwest/ does not reference proxy anywhere.
$ git config --local http.proxy http://127.0.0.1:18080
$ # reqwest backend
$ transport options: proxy=Some("http://127.0.0.1:18080") no_proxy=Some("") ssl_verify=true
$ ref_map: ERROR: An IO error occurred when talking to the server
caused by: error sending request for url (http://git.invalid/repo.git/info/refs?service=git-upload-pack)
caused by: client error (Connect)
caused by: dns error
caused by: error resolving DNS
$ # ^ the recording proxy on port 18080 logged *no* connection
$ # curl backend, same repository configuration
$ transport options: proxy=Some("http://127.0.0.1:18080") no_proxy=None ssl_verify=true
$ ref_map: ERROR: An IO error occurred when talking to the server
caused by: Received HTTP status 502
$ # ^ recording proxy logged: CONNECTION / GET http://git.invalid/repo.git/info/refs?service=git-upload-pack HTTP/1.1
Measured with a recording proxy that only logs the first request line and answers 502 (so a request that reaches it is unambiguous):
| backend |
proxy given via |
request reached the proxy? |
curl |
http.proxy config |
yes |
reqwest |
http.proxy config |
no — direct DNS failure |
reqwest |
http_proxy environment variable |
yes (see workaround below) |
So the behaviour depends on the compiled-in backend, and the reqwest case degrades to a direct connection without any diagnostic — the only visible symptom is an unrelated DNS/connection error.
Expected behavior 🤔
http.proxy — and the equivalent gix-specific keys — should be honoured by every blocking HTTP backend, as they already are by the curl backend. If a backend cannot honour them, that should be surfaced (error/warning) or documented as a per-key deviation instead of being dropped silently.
Git behavior
git (via libcurl) honours http.proxy, http.<url>.proxy, remote.<name>.proxy, and the http_proxy/HTTPS_PROXY/ALL_PROXY/no_proxy environment variables. gix's config layer already models this faithfully and fills the shared http::Options — the value simply never reaches the reqwest client.
Steps to reproduce 🕹
- Create a repository that configures a proxy pointing at a port where a trivial "recording proxy" listens (it only has to log incoming connections):
$ git init repo && git -C repo config http.proxy http://127.0.0.1:18080
- Run any HTTP request against a host that would only be reachable through that proxy (an unresolvable name is enough, since we only care whether the proxy is contacted at all). With the
gix crate, Repository::transport_options() + remote.connect(Direction::Fetch) + Connection::ref_map() is sufficient:
let repo = gix::open("repo")?;
let options = repo.transport_options("http://git.invalid/repo.git", None)?; // prints proxy=Some(..)
let remote = repo.remote_at("http://git.invalid/repo.git")?;
let connection = remote.connect(gix::remote::Direction::Fetch)?;
connection.ref_map(gix::progress::Discard, Default::default())
Cargo features: gix/blocking-http-transport-reqwest-rust-tls versus gix/blocking-http-transport-curl-rustls.
- Make sure the proxy is not also inherited from the environment (
http_proxy, https_proxy) — otherwise the reqwest backend accidentally works through reqwest's own environment handling and the bug is masked. The curl and reqwest runs above were done with all proxy environment variables unset.
The failure is not specific to a hand-written client: gix parses the value into gix_transport::client::blocking_io::http::Options { proxy: Some(..) } (shown in the output above) and passes it to the transport via TransportWithoutIO::configure(); the reqwest transport stores it and then never reads it.
Where the value is lost
| step |
location (main @ c02041d41) |
fact |
| config is parsed correctly |
gix/src/repository/config/transport.rs:170-221 |
http.proxy, remote.<name>.proxy, gitoxide.http.proxy/allProxy, gitoxide.http.noProxy → http::Options { proxy, no_proxy, proxy_auth_method, .. } |
| shared option exists and is documented |
gix-transport/src/client/blocking_io/http/mod.rs:142-148 |
pub proxy: Option<String>, pub no_proxy: Option<String> |
| the config key claims support |
gix/src/config/tree/sections/http.rs:16-18 |
http.proxy deviation is only "fails on strings with illformed UTF-8" — nothing backend-specific |
| upstream tracks it as done |
issue #470, "http transport configuration" → [x] http proxy settings; issue #450 → http transport configuration (i.e. proxy settings, ...) (#586) |
both are only true for the curl backend |
| config reaches the reqwest worker thread |
reqwest/remote.rs:300 (config: self.config.clone()) → :110-116 (destructured per request) |
the whole http::Options is available where the request is made |
| ... but is only partially consumed |
reqwest/remote.rs:290 (extra_headers), :161 (follow_redirects) |
extraHeader and followRedirects do work — so a blanket "no shared options" reading cannot be right |
| the client is built without any proxy |
reqwest/remote.rs:50-108, ClientBuilder::new() at :63 |
built once inside the worker thread from Default for Remote, i.e. before/without the configuration; no proxy()/no_proxy() call exists |
the curl backend does it |
curl/remote.rs:453-478 |
handle.proxy(), proxy_type() (incl. socks), handle.noproxy() |
The module documentation at gix-transport/src/client/blocking_io/http/mod.rs:31-34 says the backend "doesn't support any of the shared http options yet", but it already honours http.extraHeader and http.followRedirects from that same struct, and no per-key deviation mentions the backend — so the current state is a silent trap rather than a declared limitation.
Relationship to reqwest environment handling
reqwest enables system/environment proxy detection by default, so http_proxy/https_proxy in the environment do work with this backend even today. That is likely why the gap is easy to miss — but the environment is not a substitute for the configuration, and note that gix's own gitoxide.http.noProxy (http/mod.rs:148) is equally ignored, so the env-only path cannot express everything the configuration can.
Environment
gix 0.87.1, gix-transport 0.59.2, gitoxide main @ c02041d41 (2026-09-23)
- Windows 11, rustc 1.98.0
- feature sets:
gix/blocking-http-transport-reqwest-rust-tls vs. gix/blocking-http-transport-curl-rustls
Question
Is this a bug you would like fixed (i.e. the reqwest backend should honour http.proxy/noProxy), or is it a deliberately accepted limitation of the experimental reqwest backend?
If it is the latter, would you accept a documentation-only change that makes the deviation explicit — e.g. stating in the http.proxy / gitoxide.http.noProxy deviations that they currently only take effect with the curl backend — so users are not silently connected directly?
AI disclosure: this issue was written and filed by an AI agent (DeepSeek Harness) on behalf of 沙漠之子 (@maboloshi). Every command, output and code reference above was produced and verified against main at c02041d41 on a local checkout.
Current behavior 😯
When
gixis compiled with the blockingreqwestbackend (blocking-http-transport-reqwest*) and a proxy is configured in git configuration, the setting is parsed but silently ignored: the request is sent directly, the configured proxy never receives a connection, and nothing reports that the configuration had no effect.gix-transport/src/client/blocking_io/http/reqwest/does not referenceproxyanywhere.Measured with a recording proxy that only logs the first request line and answers
502(so a request that reaches it is unambiguous):curlhttp.proxyconfigreqwesthttp.proxyconfigreqwesthttp_proxyenvironment variableSo the behaviour depends on the compiled-in backend, and the
reqwestcase degrades to a direct connection without any diagnostic — the only visible symptom is an unrelated DNS/connection error.Expected behavior 🤔
http.proxy— and the equivalentgix-specific keys — should be honoured by every blocking HTTP backend, as they already are by thecurlbackend. If a backend cannot honour them, that should be surfaced (error/warning) or documented as a per-key deviation instead of being dropped silently.Git behavior
git(via libcurl) honourshttp.proxy,http.<url>.proxy,remote.<name>.proxy, and thehttp_proxy/HTTPS_PROXY/ALL_PROXY/no_proxyenvironment variables.gix's config layer already models this faithfully and fills the sharedhttp::Options— the value simply never reaches thereqwestclient.Steps to reproduce 🕹
$ git init repo && git -C repo config http.proxy http://127.0.0.1:18080gixcrate,Repository::transport_options()+remote.connect(Direction::Fetch)+Connection::ref_map()is sufficient:gix/blocking-http-transport-reqwest-rust-tlsversusgix/blocking-http-transport-curl-rustls.http_proxy,https_proxy) — otherwise thereqwestbackend accidentally works through reqwest's own environment handling and the bug is masked. Thecurlandreqwestruns above were done with all proxy environment variables unset.The failure is not specific to a hand-written client:
gixparses the value intogix_transport::client::blocking_io::http::Options { proxy: Some(..) }(shown in the output above) and passes it to the transport viaTransportWithoutIO::configure(); thereqwesttransport stores it and then never reads it.Where the value is lost
main@c02041d41)gix/src/repository/config/transport.rs:170-221http.proxy,remote.<name>.proxy,gitoxide.http.proxy/allProxy,gitoxide.http.noProxy→http::Options { proxy, no_proxy, proxy_auth_method, .. }gix-transport/src/client/blocking_io/http/mod.rs:142-148pub proxy: Option<String>,pub no_proxy: Option<String>gix/src/config/tree/sections/http.rs:16-18http.proxydeviation is only"fails on strings with illformed UTF-8"— nothing backend-specific[x] http proxy settings; issue #450 →http transport configuration (i.e. proxy settings, ...) (#586)curlbackendreqwest/remote.rs:300(config: self.config.clone()) →:110-116(destructured per request)http::Optionsis available where the request is madereqwest/remote.rs:290(extra_headers),:161(follow_redirects)extraHeaderandfollowRedirectsdo work — so a blanket "no shared options" reading cannot be rightreqwest/remote.rs:50-108,ClientBuilder::new()at:63Default for Remote, i.e. before/without the configuration; noproxy()/no_proxy()call existscurlbackend does itcurl/remote.rs:453-478handle.proxy(),proxy_type()(incl. socks),handle.noproxy()The module documentation at
gix-transport/src/client/blocking_io/http/mod.rs:31-34says the backend "doesn't support any of the shared http options yet", but it already honourshttp.extraHeaderandhttp.followRedirectsfrom that same struct, and no per-key deviation mentions the backend — so the current state is a silent trap rather than a declared limitation.Relationship to reqwest environment handling
reqwestenables system/environment proxy detection by default, sohttp_proxy/https_proxyin the environment do work with this backend even today. That is likely why the gap is easy to miss — but the environment is not a substitute for the configuration, and note thatgix's owngitoxide.http.noProxy(http/mod.rs:148) is equally ignored, so the env-only path cannot express everything the configuration can.Environment
gix0.87.1,gix-transport0.59.2, gitoxidemain@c02041d41(2026-09-23)gix/blocking-http-transport-reqwest-rust-tlsvs.gix/blocking-http-transport-curl-rustlsQuestion
Is this a bug you would like fixed (i.e. the
reqwestbackend should honourhttp.proxy/noProxy), or is it a deliberately accepted limitation of the experimentalreqwestbackend?If it is the latter, would you accept a documentation-only change that makes the deviation explicit — e.g. stating in the
http.proxy/gitoxide.http.noProxydeviations that they currently only take effect with thecurlbackend — so users are not silently connected directly?AI disclosure: this issue was written and filed by an AI agent (DeepSeek Harness) on behalf of 沙漠之子 (@maboloshi). Every command, output and code reference above was produced and verified against
mainatc02041d41on a local checkout.