test: resolve paths against `server.url` instead of joining with a slash
Behaviour change: none
Problem
server.urlis aURLwhosehrefends with/. So${server.url}/pathishttp://host//path, with two slashes. 12 test files and 3 fixtures build a request URL this way.- These requests reach
/pathonly becausefetch()drops the second slash:URL::parse_with(src/url/lib.rs) shortens apathnamethat starts with//. Node and curl send//path. docs/runtime/http/server.mdxprintedserver.urlashttp://localhost:3000, without the slash.
Fix
- Each join becomes
new URL("/path", server.url), orserver.urlfor the root. Every assertion stays. - The docs page prints
server.url.hrefwith its slash, and shows how to build the URL of a path. - Correct because no request line changes: fetch sends
/pathfor both spellings today. - Verified: the 13 test files that use these joins pass on a debug build of main (463 tests).
Background
- A temporary log in
HTTPClient::build_requestrecorded each request whose path starts with//while 437 test files ran. 13 test files sent one by accident, all through this join. - With a fetch that sends the path as written, 24 tests in 7 of these files fail. The routes and handlers of the test servers do not match
//path. - A draft of that fetch change is on the branch
robobun/91e8acaa/fetch-keep-leading-slashes. It is not final and has no PR: it needs a maintainer decision first. The question is in a comment below.
Notes
Files. cookie.test.ts, async-iterator-stream.test.ts, bun-serve-html.test.ts, bun-serve-static.test.ts, bun-server.test.ts and its js-sink-sourmap-fixture/index.mjs, node-http-maxHeaderSize.test.ts and max-header-size-fixture.ts, abortsignal-leak-fixture.ts, fetch-args.test.ts, fetch.brotli.test.ts, bun-add.test.ts, and the regression tests 18547, 24817 and test-21049.
test-21049.test.ts compared response.url with the same ${server.url}/redirect string. The request URL and the expectation now share one constant, new URL("/redirect", server.url).href.
bun-add.test.ts named a tarball dependency ${server.url.href}/booop-0.0.1.tgz. It is now ${server.url.href}booop-0.0.1.tgz, in the dependency and in the expected package.json.
What the draft branch does. It deletes the loop for every caller of URL::parse, so the HTTP client sends the path of the URL on the first request, on each followed redirect, in the proxy absolute form and in the HTTP/2 and HTTP/3 :path. It repairs three places where bun wrote // itself and the loop hid it: href_without_auth for a root registry with credentials (the change of #38812), a registry typed http://host//, and a bun.lock tarball URL from the package-lock.json migration. FileSystemRouter#match(url) and server.fetch(path) keep their output. The branch holds the two commits of this PR and one more. A review of the draft found more work in its install half, so it can still change. #33496 adds a rule that keeps // for signed S3 URLs only. With the loop gone, that rule is not needed.