Compare commits

...

2 Commits

Author SHA1 Message Date
autofix-ci[bot]
5a4a93d651 [autofix.ci] apply automated fixes 2025-11-27 10:31:35 +00:00
Claude Bot
852e327667 fix(url): preserve auth credentials in url.format for WHATWG URLs (#24343)
`url.format()` was stripping username and password when given a WHATWG
URL object because it looked for `this.auth` which doesn't exist on
WHATWG URLs (they use `username` and `password` properties instead).

Now correctly handles WHATWG URL objects by reading credentials from
the `username` and `password` properties. These values are already
percent-encoded by the URL API, so we use them directly without
additional encoding.

Before: url.format(new URL('https://a:b@example.org/')) → 'https://example.org/'
After:  url.format(new URL('https://a:b@example.org/')) → 'https://a:b@example.org/'

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 10:29:36 +00:00
4 changed files with 52 additions and 4 deletions

View File

@@ -100,8 +100,8 @@ declare module "bun" {
declare namespace WebAssembly {
interface ValueTypeMap extends Bun.WebAssembly.ValueTypeMap {}
interface GlobalDescriptor<T extends keyof ValueTypeMap = keyof ValueTypeMap>
extends Bun.WebAssembly.GlobalDescriptor<T> {}
interface GlobalDescriptor<T extends keyof ValueTypeMap = keyof ValueTypeMap> extends Bun.WebAssembly
.GlobalDescriptor<T> {}
interface MemoryDescriptor extends Bun.WebAssembly.MemoryDescriptor {}
interface ModuleExportDescriptor extends Bun.WebAssembly.ModuleExportDescriptor {}
interface ModuleImportDescriptor extends Bun.WebAssembly.ModuleImportDescriptor {}

View File

@@ -484,7 +484,19 @@ function urlFormat(urlObject: unknown) {
Url.prototype.format = function format() {
var auth: string = this.auth || "";
if (auth) {
// Handle WHATWG URL objects which have username/password instead of auth
if (!auth && (this.username || this.password)) {
if (this.username) {
auth = this.username;
}
if (this.password) {
auth += ":" + this.password;
}
if (auth) {
auth += "@";
}
} else if (auth) {
auth = encodeURIComponent(auth);
auth = auth.replace(/%3A/i, ":");
auth += "@";

View File

@@ -1941,7 +1941,7 @@ test("no assertion failures 3", () => {
],
[
class // Random { // comments /* */ are part of the toString() result
äß /**/
äß /**/
extends /*{*/ TypeError {},
"[class äß extends TypeError]",
],

View File

@@ -0,0 +1,36 @@
import { expect, test } from "bun:test";
import url from "node:url";
test("url.format with WHATWG URL preserves username and password", () => {
const result = url.format(new URL("https://a:b@example.org/"));
expect(result).toBe("https://a:b@example.org/");
});
test("url.format with WHATWG URL preserves username only", () => {
const result = url.format(new URL("https://user@example.org/"));
expect(result).toBe("https://user@example.org/");
});
test("url.format with WHATWG URL without auth", () => {
const result = url.format(new URL("https://example.org/"));
expect(result).toBe("https://example.org/");
});
test("url.format with WHATWG URL preserves username, password, and path", () => {
const result = url.format(new URL("https://user:pass@example.org/path?query=1#hash"));
expect(result).toBe("https://user:pass@example.org/path?query=1#hash");
});
test("url.format with WHATWG URL with special characters in credentials", () => {
// When creating a URL, special characters in credentials are already percent-encoded
// url.format should preserve the encoding from the URL object
const result = url.format(new URL("https://us%40er:p%40ss@example.org/"));
// The username and password are already encoded by the URL object, so we should preserve them as-is
expect(result).toBe("https://us%40er:p%40ss@example.org/");
});
test("url.format with legacy Url object still works", () => {
const parsed = url.parse("https://a:b@example.org/path");
const result = url.format(parsed);
expect(result).toBe("https://a:b@example.org/path");
});