Skip to content

Migrate ureq from 2 to 3 - #637

Open
yangyang-duolingo wants to merge 2 commits into
heroku:mainfrom
yangyang-duolingo:migrate-ureq-3
Open

yangyang-duolingo wants to merge 2 commits into
heroku:mainfrom
yangyang-duolingo:migrate-ureq-3

Conversation

@yangyang-duolingo

Copy link
Copy Markdown

Description

Fixes #636 (and makes #630/#631's http_agent() workaround unnecessary — ureq 3's default Agent config now honours HTTP_PROXY/HTTPS_PROXY/ALL_PROXY/NO_PROXY natively, with no opt-in feature flag needed at all).

Three mechanical API changes, no logic changes:

  • ureq::Error::Status(code, _) → ureq::Error::StatusCode(code) (no longer carries the Response) — one match arm in src/layers/python.rs.
  • response.into_reader() → response.into_body().into_reader() (.call() now returns http::Response<Body> instead of ureq 2's own Response type) — the two download functions in src/utils.rs.
  • Cargo.toml's ureq feature "tls" → "rustls" (renamed upstream).

Added a test (ureq_default_agent_honours_http_proxy_and_no_proxy) that proves the proxy/NO_PROXY behavior at the socket level rather than just asserting on config: a fake local HTTP proxy and a fake direct target, with HTTP_PROXY/NO_PROXY env vars set, confirm that a request to a target not covered by NO_PROXY arrives at the proxy as a CONNECT <host>:<port> tunnel (ureq 3 tunnels every proxied request via CONNECT, even for a plain http:// target), while a request to a target that is covered by NO_PROXY lands directly on the real target and never reaches the proxy at all.

Open questions for maintainers

  • MSRV: ureq 3 requires Rust 1.85; this buildpack already requires 1.99, so no conflict here, but flagging in case there's a constraint I'm not aware of.
  • ureq 3 is a from-scratch rewrite beyond proxying (new http-crate-based API throughout) — worth a wider look at whether anything else in this crate's usage needs attention beyond the three call sites here.

Verification steps

  • cargo test (all 48 non-Docker-dependent tests pass, including the new one)
  • cargo clippy --all-targets -- -D warnings (clean)
  • cargo fmt --check (clean)
  • Integration tests (cargo test -- --ignored) — not run here, no Docker/Pack available in my environment

Gets the Python and uv runtime downloads native HTTP_PROXY/HTTPS_PROXY/
ALL_PROXY and NO_PROXY support for free, with zero buildpack-side proxy
handling code: ureq 3's default Agent config sets proxy: Proxy::try_from_env()
unconditionally (src/config.rs Config::default()), and that now includes
NoProxy::try_from_env() natively (src/proxy.rs) -- unlike ureq 2, where
proxy detection was gated behind an opt-in Cargo feature that didn't exist
by default, and even with it on, had no NO_PROXY support at all (see heroku#630).

Three mechanical API changes, no logic changes:
- ureq::Error::Status(code, _) -> ureq::Error::StatusCode(code) (no longer
  carries the Response).
- response.into_reader() -> response.into_body().into_reader() (.call() now
  returns http::Response<Body> instead of ureq 2's own Response type).
- Cargo.toml's ureq feature "tls" -> "rustls" (renamed upstream).

Added a test that proves this at the socket level rather than just
asserting on config: a fake local HTTP proxy observes a CONNECT tunnel
request for a target not covered by NO_PROXY, and observes nothing at all
for a request whose target *is* covered by NO_PROXY (confirming it went
directly to the real target instead).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@yangyang-duolingo
yangyang-duolingo requested review from a team and edmorley as code owners October 10, 2026 00:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider migrating ureq from 2 to 3 (fixes the HTTP_PROXY/NO_PROXY gap in #630 natively)

1 participant