Skip to content

jsonrpc(fix): set host header to URL hostname instead of resolved IP#578

Open
lorenzolfm wants to merge 1 commit intorust-bitcoin:masterfrom
lorenzolfm:fix/host-header-uses-url-hostname
Open

jsonrpc(fix): set host header to URL hostname instead of resolved IP#578
lorenzolfm wants to merge 1 commit intorust-bitcoin:masterfrom
lorenzolfm:fix/host-header-uses-url-hostname

Conversation

@lorenzolfm
Copy link
Copy Markdown

@lorenzolfm lorenzolfm commented May 3, 2026

Description and Notes

Fixes rust-bitcoin/corepc#577.

The simple_http writes the resolved socket address to the outgoing Host HTTP header instead of the URL's authority component, violating RFC 9112 §3.2:

If the target URI includes an authority component, then a client MUST send a field value for Host that is identical to that authority component, excluding any userinfo subcomponent and its "@" delimiter.

The fix

The bug: SimpleHttpTransport had no field for the URL hostname, so check_url couldn't preserve it across DNS resolution, so the request serializer had nothing but the resolved SocketAddr to put in the Host header. The fix updates all three.

  1. Struct (SimpleHttpTransport, line 40): add a host_header: String field. Stores the URL's authority component verbatim host or host:port.

  2. URL parser (check_url, line 282): now returns (SocketAddr, host_header, path) instead of (SocketAddr, path). Captures after_auth.to_owned() before calling to_socket_addrs().

  3. Wire serializer (try_request, line 152-153): writes self.host_header to the Host: header instead of self.addr.to_string().

set_url is updated to thread the new tuple. The Default impl initializes host_header consistently with the default addr (127.0.0.1:DEFAULT_PORT).

The tests

Two new tests, plus an existing test extended.

request_uses_url_host_in_host_header: the regression test.

Binds a TcpListener on localhost:0, points the client at http://localhost:<port>/, captures the outgoing request bytes via stream.read(), and asserts the host: line of the request equals localhost:<port>. Against unfixed code it sees [::1]:<port> or 127.0.0.1:<port> (whichever the system resolves localhost to first)

check_url_host_header: unit test for the parser.

Table over hostname / IP / IPv6-bracketed / userinfo URL forms. Asserts the URL authority is preserved in host_header verbatim:

("http://example.com/",                        "example.com"),
("http://example.com:8080/",                   "example.com:8080"),
("https://example.com/walletname",             "example.com"),
("https://example.com:443/",                   "example.com:443"),
("localhost:22",                               "localhost:22"),
("http://me:weak@localhost:22/wallet",         "localhost:22"),
("http://127.0.0.1:8332/",                     "127.0.0.1:8332"),
("http://[2001:0db8:85a3:...]:8300",           "[2001:0db8:85a3:...]:8300"),

The userinfo case (me:weak@) verifies credentials are stripped; the IPv6 case verifies brackets round-trip; the no-port and explicit-port cases verify both default-port branches.

test_urls: existing test, extended.

Already exercised the parser for all valid URLs. Updated to destructure the new 3-tuple and assert that host_header round-trips through Builder::url() alongside the existing addr and path checks. Same coverage as before plus the new field.

@tcharding
Copy link
Copy Markdown
Member

Appreciate the contribution. Is this LLM generated? The PR description smells a bit like it. Can you state what you wrote and what is bot written please. From your GitHub account it looks like you know what you are doing but I'd just like an idea so I can guide my review.

Thanks and beleza.

@lorenzolfm
Copy link
Copy Markdown
Author

The fix and check_url_host_header was written by me. The request_uses_url_host_in_host_header and test cases for check_url_host_header was LLM generated.

The approach was first adding a test the failed. This is the LLM generated test request_uses_url_host_in_host_header. Then I tried to work backwards and see what was missing.

Copy link
Copy Markdown
Collaborator

@jamillambert jamillambert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 622faed

This all looks good to me. Thanks for the issue and the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

jsonrpc: simple_http sets Host header to resolved IP instead of URL hostname

3 participants