Skip to content

feat(net-http): keep-alive + timeouts + proxy - #183

Merged
tannevaled merged 4 commits into
mainfrom
feat/net-http-keepalive-timeout-proxy
Jul 6, 2026
Merged

tannevaled merged 4 commits into
mainfrom
feat/net-http-keepalive-timeout-proxy

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Extends the Net::HTTP transport binding (internal/vm/nethttp_bind.go, from #181) with the deferred features, MRI-faithful, on top of the existing socket/TLS transport.

Keep-alive / persistent connections

Within Net::HTTP.start(host, port) { |http| ... } a single connection is reused across requests. Each response is framed by its exact Content-Length or chunked Transfer-Encoding (a dedicated framed reader, nethttpReadResponse, that leaves following bytes buffered for the next request), so pipelined requests read at the right offset. The connection is cached on the instance (@conn), closed on #finish / start-block teardown, and dropped when the server sends Connection: close (or the body is unframed and read to EOF). A cached connection that fails a write/read is redialed once.

Timeouts

open_timeout / read_timeout / write_timeout accessors (seconds; default 60, MRI's defaults) set socket deadlines. open_timeout bounds the TCP dial and the TLS handshake. A timed-out open/read/write raises Net::OpenTimeout / Net::ReadTimeout / Net::WriteTimeout.

Proxy

Net::HTTP.new(host, port, p_addr, p_port[, user, pass]) and the matching Net::HTTP.start proxy args. Plain HTTP emits an absolute-URI request-line to the proxy (with Proxy-Authorization when credentials are given); HTTPS tunnels via CONNECT then runs TLS through the tunnel. proxy? / proxy_address / proxy_port / proxy_user / proxy_pass accessors.

Proofs (hermetic, in-VM)

Extends the binding test suite with in-process httptest servers: keep-alive asserts 3 requests in one start block share exactly 1 accepted TCP connection; a slow handler + short read_timeout raises Net::ReadTimeout; a tiny in-test forwarding proxy asserts routing (plain HTTP) and a CONNECT tunnel.

Deferred: environment-proxy (:ENV) resolution.

🤖 Generated with Claude Code

tannevaled and others added 4 commits July 6, 2026 21:20
Extend the Net::HTTP transport binding with the deferred features, built on
the existing socket/TLS transport:

- Keep-alive: within Net::HTTP.start's block a single connection is reused
  across requests, each response framed by exact Content-Length / chunked
  encoding so the next request reads at the right offset; the connection is
  closed on #finish / block end, or when the server sends Connection: close.
- Timeouts: open_timeout / read_timeout / write_timeout accessors set socket
  deadlines (open_timeout bounds the dial + TLS handshake); a timed-out
  open/read/write raises Net::OpenTimeout / Net::ReadTimeout /
  Net::WriteTimeout as MRI does.
- Proxy: Net::HTTP.new(host, port, p_addr, p_port[, user, pass]) and the
  matching Net::HTTP.start proxy args; plain http emits an absolute-URI
  request-line to the proxy, https tunnels via CONNECT then TLS through it.
  proxy? / proxy_address / proxy_port / proxy_user / proxy_pass accessors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Route the class-level URL conveniences (get/post/...) through the same
  nethttpDoXfer transport as instance requests, removing the now-redundant
  one-shot nethttpDo / nethttpRoundTrip / nethttpDial / httpExchange so there
  is a single, fully-exercised request path.
- Add hermetic proofs: keep-alive (3 requests, 1 accepted TCP connection),
  server-Connection:close fallback, stale-connection redial retry, read
  timeout (Net::ReadTimeout), open timeout, http proxy (absolute-URI
  request-line + Proxy-Authorization routed through a forwarding proxy) and
  https-via-CONNECT tunnel, plus unit coverage of every transport helper and
  error arm. 100% coverage on nethttp_bind.go.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nethttpExchangeFramed now reports which half (write/read) failed so a
write-deadline timeout raises Net::WriteTimeout instead of being misreported
as Net::ReadTimeout, matching MRI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
hostHdr omits the port for a default-port target; CONNECT requires an
explicit host:port, so build it from host + port.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 39cbfed into main Jul 6, 2026
9 checks passed
@tannevaled
tannevaled deleted the feat/net-http-keepalive-timeout-proxy branch July 6, 2026 20:37
tannevaled added a commit that referenced this pull request Jul 6, 2026
…y) (#198)

Net::HTTP's p_addr now defaults to MRI's :ENV, resolving the proxy from
the environment at request time instead of leaving the instance
proxy-less (the item deferred by #183).

- p_addr :ENV / omitted -> resolve from the environment against the
  instance's scheme (@use_ssl) and target host; nil/false -> no proxy;
  an explicit host String -> that fixed proxy (unchanged).
- http requests read http_proxy/HTTP_PROXY, https requests read
  https_proxy/HTTPS_PROXY; the resolved userinfo becomes the
  Proxy-Authorization credentials.
- no_proxy/NO_PROXY (comma/space list of hosts, leading-dot or bare
  domain suffixes, host:port qualifiers and CIDRs/IPs) forces a direct
  connection, mirroring URI::Generic.use_proxy?.
- CGI-safety: when REQUEST_METHOD is set, the attacker-controllable
  uppercase HTTP_PROXY is ignored and only the lowercase http_proxy is
  honored (MRI's find_proxy rule).
- proxy?/proxy_address/proxy_port/proxy_user/proxy_pass reflect the
  effective (explicit or env-resolved) proxy.

Proven end-to-end through the VM against in-process httptest proxies
(plain-http routing, https CONNECT tunnelling, no_proxy bypass, nil
opt-out, CGI-safety) plus unit coverage of the resolver and no_proxy
matcher; 100% coverage on the new code.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant