Add SOCKS5 proxy support (socks5:// and socks5h://)#1299
Merged
Conversation
Route requests through SOCKS5 proxies configured with ProxyURL, ProxyConfig, or ALL_PROXY-style environment variables. Both socks5:// and socks5h:// follow Go's net/http behavior and pass domain targets to the proxy for resolution. Username/password credentials come from the proxy URL userinfo (percent-decoded) and are negotiated with RFC 1929 username/password auth when the proxy selects it. The SOCKS handshake is performed by Reseau.SOCKS.connect! on the pooled TCP connection before TLS, HTTP/1.1, HTTP/2, or WebSocket traffic flows, and connect_timeout bounds the handshake via the existing connect deadline. Plain-HTTP requests over SOCKS write origin-form targets and never attach Proxy-Authorization. Co-authored by Codex
The 250ms request/read/write timeouts were tight enough to flake on loaded CI machines; the test only asserts that configured timeouts propagate into the request context, so the exact value just needs to be distinctive. Co-authored by Codex
- Reject malformed non-bracketed SOCKS proxy authorities (e.g. "socks5://::1:1080") instead of silently treating the whole string as a host with the default port. - Parse SOCKS proxy ports strictly as decimal; "0x50", "+80", and other tryparse-isms are rejected. - Wrap SOCKS handshake failures (AuthenticationError, ReplyError, ProtocolError, TargetAddressError) in HTTP.ConnectError so callers see HTTP-typed exceptions per the public error contract; timeouts and EOFs keep their existing classifications and none of these are retried, matching CONNECT-tunnel behavior. - Close the underlying TCP connection when the TLS handshake fails in _new_conn_tls! instead of leaking the fd until GC; this covers direct, CONNECT-tunnel, and SOCKS TLS paths. - Expand test coverage: parse edge cases (case-insensitive schemes, bracketed IPv6 proxy hosts, default ports, path/query stripping, malformed authorities and ports), no_proxy bypass for SOCKS plans, ConnectError wrapping for command rejection / auth-method mismatch / empty username, connect_timeout enforcement against a stalled proxy, HTTPS h1 over a SOCKS-bridged TLS stream, and connection pool reuse across sequential requests through one SOCKS handshake. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reseau.SOCKS ships in JuliaServices/Reseau.jl#123 and is not registered yet; pin Reseau to that PR head so CI dependency resolution succeeds. Revert this commit once Reseau >= 1.2.1 is registered. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
quinnj
added a commit
to JuliaServices/Reseau.jl
that referenced
this pull request
Jun 11, 2026
The SOCKS support layer is a new feature on top of the released 1.2.1, and HTTP.jl's SOCKS proxy support (JuliaWeb/HTTP.jl#1299) declares compat against the version that first ships Reseau.SOCKS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reseau#123 now bumps its version to 1.3.0 (matching the Reseau = "1.3" compat here) and merges Reseau main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Windows environment variables are case-insensitive, so clearing "all_proxy" after setting "ALL_PROXY" deleted the value and ProxyFromEnvironment saw no proxy at all. Clear the lowercase variants first and set ALL_PROXY last. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1299 +/- ##
==========================================
+ Coverage 86.91% 87.02% +0.10%
==========================================
Files 28 28
Lines 10915 11017 +102
==========================================
+ Hits 9487 9587 +100
- Misses 1428 1430 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
findlast(==('@'), authority) dispatches to the generic Function method,
which the Julia 1.13 juliac trim verifier rejects as an unresolved call
(the SOCKS parser is reachable from ProxyFromEnvironment in trimmed
binaries). Scan code units with the existing _find_last_url_byte helper
like the rest of the URL parsing code. Verified locally with the trim
compile tests under 1.13.0-rc1: 63/63 pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
quinnj
added a commit
to JuliaServices/Reseau.jl
that referenced
this pull request
Jun 11, 2026
* feat(socks): add SOCKS5 connect helper
Add an internal SOCKS module that performs a SOCKS5 CONNECT handshake over an existing TCP.Conn, including no-auth and username/password auth, target encoding, reply parsing, typed errors, and deadline handling.
Cover FQDN, IPv4, IPv6, auth negotiation, command failures, pre-I/O target validation, and stalled proxy deadlines with focused Reseau tests.
* fix(socks): validate targets and credentials before proxy I/O
- Reject zone-scoped IPv6 targets ("[fe80::1%en0]:80") up front: macOS
inet_pton accepts them while embedding the zone index into the address
bytes, and on other platforms they leaked to the proxy as FQDN targets.
- Reject bracketed non-IPv6 hosts ("[1:2:3]:80") instead of sending them
as domain names.
- Validate username/password (presence, 1-255 byte lengths, password
requires username) in connect! before any bytes reach the proxy.
- Parse target ports strictly as decimal ("0x50", "+80", " 80" no longer
accepted).
- Drop a throwaway SocketAddrV6 construction in bound-reply parsing.
- Document deadline overwrite semantics, thrown error types, and the
RFC 1928/1929 scope on the module and connect! docstrings.
- Expand test coverage: protocol-error replies (bad versions, non-zero
RSV, unknown ATYP), auth subnegotiation failures, unsupported method
selections, proxy EOF mid-handshake, no-auth selected despite offered
credentials, username-only auth, 255-byte credential/FQDN boundaries,
IPv4 bound replies, and pre-I/O validation of targets and credentials.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(hostresolvers): reject zone-scoped literals in _parse_ipv6_literal
macOS inet_pton(AF_INET6) accepts "fe80::1%en0" and embeds the zone index
into the returned address bytes, while Linux and Windows reject zoned
input. Reject '%' before calling inet_pton so results are
platform-independent; callers that support zones already split them off
via _split_host_zone first.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Bump version to 1.3.0
The SOCKS support layer is a new feature on top of the released 1.2.1,
and HTTP.jl's SOCKS proxy support (JuliaWeb/HTTP.jl#1299) declares
compat against the version that first ships Reseau.SOCKS.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(socks): add a trim-safe compile workload
Exercise the SOCKS5 CONNECT handshake (scripted loopback proxy, no
second task) plus pre-I/O target validation and error formatting in a
--trim=safe compiled binary, so trim regressions in the SOCKS layer are
caught in-repo instead of by downstream consumers. HTTP.jl's trim suite
already reaches SOCKS.connect! through its proxy plumbing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
quinnj
commented
Jun 12, 2026
quinnj
commented
Jun 12, 2026
…upport # Conflicts: # src/http_client.jl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds SOCKS5 proxy transport to the client, configured the same way as HTTP proxies:
socks5://andsocks5h://URLs work withProxyURL,ProxyConfig, theproxy=request kwarg, andALL_PROXY-style environment variables. Following Go'snet/httpbehavior, both schemes send domain targets to the proxy for remote resolution.connect_timeoutbounds the handshake via the existing connect deadline.Proxy-Authorization; SOCKS plans get distinct pool keys and proxied connections are pooled/reused normally.HTTP.ConnectError(with the SOCKS error ascause), keeping the "HTTP-typed exceptions only" public error contract; handshake timeouts surface asHTTP.TimeoutError. Neither is retried, matching CONNECT-tunnel failure behavior.Hardening that came out of review:
socks5://::1:1080, hex/signed ports, etc. are rejected)_new_conn_tls!now closes the underlying TCP connection when the TLS handshake fails instead of leaking the fd until GC (covers direct, CONNECT-tunnel, and SOCKS paths)Dependencies
Requires Reseau >= 1.3.0, which includes JuliaServices/Reseau.jl#123 (
Reseau.SOCKS) and is available in General.Tests
connect_timeouttest/http_client_proxy_tests.jlstandalone: 162 passingCo-authored by Codex
🤖 Generated with Claude Code