Skip to content

feat(net-http): real Net::HTTP over the socket/TLS transport - #181

Merged
tannevaled merged 1 commit into
mainfrom
feat/nethttp-real-transport
Jul 6, 2026
Merged

tannevaled merged 1 commit into
mainfrom
feat/nethttp-real-transport

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Makes Net::HTTP actually perform requests, now that the socket/TLS transport (#173) is in main.

What

nethttp.go builds the loadable shell (class tree, header surface, HTTPResponse status subclasses) and stubbed every networking method with NotImplementedError. This PR adds internal/vm/nethttp_bind.go (registerNetHTTPTransport, run right after registerNetHTTP) that replaces those stubs with real ones wiring the go-ruby-net-http MRI-byte-exact HTTP/1.1 codec to the socket transport:

NewRequest → Request.Bytes → write to a TCPSocket (or a TLS SSLSocket for https)
  → read the response off the socket → ParseResponse → a Net::HTTPResponse

The wire codec is go-ruby-net-http; the byte I/O is rbgo's own TCPSocket / OpenSSL::SSL::SSLSocket transport (nethttpDial builds a tcpSocket, wrapping it in an sslSocket for https, and reuses the shared streamIO write/read surface).

Surface bound

  • Class: Net::HTTP.get (→ body String) / get_response / post / post_form / start(host,port){|http| ... }
  • Instance: Net::HTTP.new(host,port), start/finish, verb helpers get/head/post/put/delete/patch/options, request(req), use_ssl=/verify_mode=
  • Request objects: Net::HTTP::Get/Post/... with method/path/body/body=/set_form_data
  • Response: code/message/body/http_version/read_body/content_type/each_header + [] (Net::HTTPHeader) + the status subclass identity (Net::HTTPOK, Net::HTTPNotFound, …)
  • Both Content-Length and chunked response framing decode; HEAD handled; over http AND https

Semantics / deviations

  • Each request is one connection (Connection: close) so the read drains to EOF.
  • TLS defaults to VERIFY_NONE (the SSLSocket transport's bare-context default); verify_mode = OpenSSL::SSL::VERIFY_PEER turns on Go's chain + hostname verification.

Deferred follow-ups

Keep-alive / persistent connections, redirect following (Net::HTTP never auto-follows anyway), proxies, streaming bodies, read timeouts, and full certificate-store verification wiring.

Proof

Hermetic, no external network: every assertion drives a Ruby script through the rbgo engine against in-process httptest.NewServer (http) and httptest.NewTLSServer (https). TestNetHTTPThroughRbgoBinary builds the cmd/rbgo binary and runs Net::HTTP.get(URI(...)) against both, asserting the body on stdout. 100% coverage on the new binding code (nethttp_bind.go).

🤖 Generated with Claude Code

Bind github.com/go-ruby-net-http/net-http (the MRI-byte-exact HTTP/1.1
message codec) onto the just-landed socket transport so Net::HTTP actually
performs requests. nethttp.go builds the loadable shell and stubbed every
networking method with NotImplementedError; registerNetHTTPTransport now
replaces those stubs with real ones that wire the codec to the sockets:

  NewRequest -> Request.Bytes -> write to a TCPSocket (or a TLS SSLSocket
  for https) -> read the response off the socket -> ParseResponse -> a
  Net::HTTPResponse (code / message / body / headers).

Surface bound: Net::HTTP.get / get_response / post / post_form / start,
instance new + start/finish + the verb helpers (get/head/post/put/delete/
patch/options) + request(req), the Net::HTTP::Get/Post/... request objects
(method/path/body/set_form_data), and the response accessors (code/message/
body/http_version/read_body/content_type/each_header) over http AND https.
Content-Length and chunked response framing both decode; HEAD is handled.

Each request is one connection (Connection: close) so the read drains to
EOF. TLS defaults to VERIFY_NONE (the SSLSocket transport's bare-context
default); verify_mode = OpenSSL::SSL::VERIFY_PEER turns on Go's chain +
hostname verification. Persistent/keep-alive connections, redirect
following, proxies, streaming bodies, read timeouts and full certificate-
store verification wiring are flagged follow-ups.

Proven end-to-end through the rbgo binary against in-process
httptest.NewServer (http) and httptest.NewTLSServer (https); 100% coverage
on the new binding, hermetic (no external network).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 621bbe5 into main Jul 6, 2026
9 checks passed
@tannevaled
tannevaled deleted the feat/nethttp-real-transport branch July 6, 2026 17:46
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