diff --git a/cli/rt/11_url.js b/cli/rt/11_url.js index a7200f11c4..7e01f4d887 100644 --- a/cli/rt/11_url.js +++ b/cli/rt/11_url.js @@ -370,7 +370,7 @@ } if (usedNonBase || restUrl.startsWith("?")) { [parts.query, restUrl] = takePattern(restUrl, /^(\?[^#]*)/); - parts.query = encodeSearch(parts.query); + parts.query = encodeSearch(parts.query, isSpecial); usedNonBase = true; } else { parts.query = baseParts.query; @@ -660,7 +660,8 @@ set search(value) { value = String(value); const query = value == "" || value.charAt(0) == "?" ? value : `?${value}`; - parts.get(this).query = encodeSearch(query); + const isSpecial = specialSchemes.includes(parts.get(this).protocol); + parts.get(this).query = encodeSearch(query, isSpecial); this.#updateSearchParams(); } @@ -766,9 +767,9 @@ return (c >= "\u0000" && c <= "\u001F") || c > "\u007E"; } - function charInSearchSet(c) { + function charInSearchSet(c, isSpecial) { // deno-fmt-ignore - return charInC0ControlSet(c) || ["\u0020", "\u0022", "\u0023", "\u0027", "\u003C", "\u003E"].includes(c) || c > "\u007E"; + return charInC0ControlSet(c) || ["\u0020", "\u0022", "\u0023", "\u003C", "\u003E"].includes(c) || isSpecial && c == "\u0027" || c > "\u007E"; } function charInFragmentSet(c) { @@ -871,8 +872,10 @@ return [...s].map((c) => (charInPathSet(c) ? encodeChar(c) : c)).join(""); } - function encodeSearch(s) { - return [...s].map((c) => (charInSearchSet(c) ? encodeChar(c) : c)).join(""); + function encodeSearch(s, isSpecial) { + return [...s].map(( + c, + ) => (charInSearchSet(c, isSpecial) ? encodeChar(c) : c)).join(""); } function encodeHash(s) { diff --git a/cli/tests/unit/url_test.ts b/cli/tests/unit/url_test.ts index ed8ae55001..438e80892d 100644 --- a/cli/tests/unit/url_test.ts +++ b/cli/tests/unit/url_test.ts @@ -272,26 +272,30 @@ unitTest(function urlTrim() { unitTest(function urlEncoding() { assertEquals( - new URL("https://a !$&*()=,;+'\"@example.com").username, + new URL("http://a !$&*()=,;+'\"@example.com").username, "a%20!$&*()%3D,%3B+%27%22", ); assertEquals( - new URL("https://:a !$&*()=,;+'\"@example.com").password, + new URL("http://:a !$&*()=,;+'\"@example.com").password, "a%20!$&*()%3D,%3B+%27%22", ); - assertEquals(new URL("abcde://mañana/c?d#e").hostname, "ma%C3%B1ana"); // https://url.spec.whatwg.org/#idna - assertEquals(new URL("https://mañana/c?d#e").hostname, "xn--maana-pta"); + assertEquals(new URL("http://mañana/c?d#e").hostname, "xn--maana-pta"); + assertEquals(new URL("abcd://mañana/c?d#e").hostname, "ma%C3%B1ana"); assertEquals( - new URL("https://example.com/a ~!@$&*()=:/,;+'\"\\").pathname, + new URL("http://example.com/a ~!@$&*()=:/,;+'\"\\").pathname, "/a%20~!@$&*()=:/,;+'%22/", ); assertEquals( - new URL("https://example.com?a ~!@$&*()=:/,;?+'\"\\").search, + new URL("http://example.com?a ~!@$&*()=:/,;?+'\"\\").search, "?a%20~!@$&*()=:/,;?+%27%22\\", ); assertEquals( - new URL("https://example.com#a ~!@#$&*()=:/,;?+'\"\\").hash, + new URL("abcd://example.com?a ~!@$&*()=:/,;?+'\"\\").search, + "?a%20~!@$&*()=:/,;?+'%22\\", + ); + assertEquals( + new URL("http://example.com#a ~!@#$&*()=:/,;?+'\"\\").hash, "#a%20~!@#$&*()=:/,;?+'%22\\", ); });