Summary
Perry's url.urlToHttpOptions() returns a narrow object with protocol, hostname, port, path, and auth. Node returns a fuller HTTP-options object: it includes hash, search, pathname, path, href, optional numeric port, decoded auth, and enumerable own properties from the URL object. Node also rejects non-object inputs with ERR_INVALID_ARG_TYPE, while Perry currently returns an empty object for non-object values.
Node.js behavior
Observed with Node v25.9.0:
const { urlToHttpOptions } = require("node:url");
const u = new URL("https://u%20ser:p%40w@example.com:8080/p/a?q=1#frag");
u.extra = "own";
console.log(Object.keys(urlToHttpOptions(u)));
console.log(urlToHttpOptions(u));
console.log(urlToHttpOptions(new URL("https://example.com")));
urlToHttpOptions("https://example.com/p");
Node outputs keys like:
["extra","protocol","hostname","hash","search","pathname","path","href","port","auth"]
{ extra: "own", protocol: "https:", hostname: "example.com", hash: "#frag", search: "?q=1", pathname: "/p/a", path: "/p/a?q=1", href: "https://u%20ser:p%40w@example.com:8080/p/a?q=1#frag", port: 8080, auth: "u ser:p@w" }
{ protocol: "https:", hostname: "example.com", hash: "", search: "", pathname: "/", path: "/", href: "https://example.com/" }
TypeError ERR_INVALID_ARG_TYPE for a string input
Current Perry behavior
crates/perry-runtime/src/url/node_compat.rs::js_url_to_http_options() returns only five properties: protocol, hostname, port, path, and auth.
- It does not include
hash, search, pathname, or href.
- It does not copy enumerable own properties from the URL object before adding URL-derived options.
- It formats
auth from the stored username / password strings without Node's percent-decoding behavior for userinfo.
- If
object_from_f64(url_f64) fails, it allocates and returns an empty object instead of throwing TypeError ERR_INVALID_ARG_TYPE.
The existing parity fixtures test-parity/node-suite/url/module/url-to-http-options.ts and url-to-http-options-defaults.ts cover only the narrow subset Perry currently returns, so this wider Node behavior can regress silently.
Suggested test surface
- Assert that
urlToHttpOptions(new URL("https://u%20ser:p%40w@example.com:8080/p/a?q=1#frag")) includes hash, search, pathname, path, href, numeric port, and decoded auth === "u ser:p@w".
- Assert that a URL with no explicit port/auth omits those properties while still including empty
hash/search, pathname, path, and href.
- Assert that enumerable own URL properties are copied to the returned object.
- Assert that non-object input throws
TypeError with code ERR_INVALID_ARG_TYPE.
Scope / non-goals
This issue is scoped to node:url.urlToHttpOptions() result shape, auth decoding, property copying, and input validation. It does not require changing HTTP client option consumption or legacy url.parse().
Summary
Perry's
url.urlToHttpOptions()returns a narrow object withprotocol,hostname,port,path, andauth. Node returns a fuller HTTP-options object: it includeshash,search,pathname,path,href, optional numericport, decodedauth, and enumerable own properties from the URL object. Node also rejects non-object inputs withERR_INVALID_ARG_TYPE, while Perry currently returns an empty object for non-object values.Node.js behavior
Observed with Node v25.9.0:
Node outputs keys like:
Current Perry behavior
crates/perry-runtime/src/url/node_compat.rs::js_url_to_http_options()returns only five properties:protocol,hostname,port,path, andauth.hash,search,pathname, orhref.authfrom the storedusername/passwordstrings without Node's percent-decoding behavior for userinfo.object_from_f64(url_f64)fails, it allocates and returns an empty object instead of throwingTypeError ERR_INVALID_ARG_TYPE.The existing parity fixtures
test-parity/node-suite/url/module/url-to-http-options.tsandurl-to-http-options-defaults.tscover only the narrow subset Perry currently returns, so this wider Node behavior can regress silently.Suggested test surface
urlToHttpOptions(new URL("https://u%20ser:p%40w@example.com:8080/p/a?q=1#frag"))includeshash,search,pathname,path,href, numericport, and decodedauth === "u ser:p@w".hash/search,pathname,path, andhref.TypeErrorwith codeERR_INVALID_ARG_TYPE.Scope / non-goals
This issue is scoped to
node:url.urlToHttpOptions()result shape, auth decoding, property copying, and input validation. It does not require changing HTTP client option consumption or legacyurl.parse().