diff --git a/cli/js/web/fetch.ts b/cli/js/web/fetch.ts index 543560c8d5..d692b83e1d 100644 --- a/cli/js/web/fetch.ts +++ b/cli/js/web/fetch.ts @@ -342,11 +342,7 @@ export async function fetch( !redirectUrl.startsWith("http://") && !redirectUrl.startsWith("https://") ) { - redirectUrl = - url.split("//")[0] + - "//" + - url.split("//")[1].split("/")[0] + - redirectUrl; // TODO: handle relative redirection more gracefully + redirectUrl = new URL(redirectUrl, url).href; } url = redirectUrl; redirected = true; diff --git a/cli/tests/unit/fetch_test.ts b/cli/tests/unit/fetch_test.ts index 84f2c28223..c93cc0c85a 100644 --- a/cli/tests/unit/fetch_test.ts +++ b/cli/tests/unit/fetch_test.ts @@ -335,6 +335,27 @@ unitTest( } ); +unitTest( + { + perms: { net: true }, + }, + async function fetchWithRelativeRedirectionUrl(): Promise { + const cases = [ + ["end", "http://localhost:4550/a/b/end"], + ["/end", "http://localhost:4550/end"], + ]; + for (const [loc, redUrl] of cases) { + const response = await fetch("http://localhost:4550/a/b/c", { + headers: new Headers([["x-location", loc]]), + }); + assertEquals(response.url, redUrl); + assertEquals(response.redirected, true); + assertEquals(response.status, 404); + assertEquals(await response.text(), ""); + } + } +); + unitTest( { perms: { net: true }, diff --git a/cli/tests/unit/url_test.ts b/cli/tests/unit/url_test.ts index 177f605c15..3e7ac62140 100644 --- a/cli/tests/unit/url_test.ts +++ b/cli/tests/unit/url_test.ts @@ -240,6 +240,19 @@ unitTest(function urlBaseURL(): void { ); const url = new URL("/foo/bar?baz=foo#qux", base); assertEquals(url.href, "https://foo:bar@baz.qat:8000/foo/bar?baz=foo#qux"); + + assertEquals( + new URL("D", "https://foo.bar/path/a/b/c/d").href, + "https://foo.bar/path/a/b/c/D" + ); + + assertEquals(new URL("D", "https://foo.bar").href, "https://foo.bar/D"); + assertEquals(new URL("D", "https://foo.bar/").href, "https://foo.bar/D"); + + assertEquals( + new URL("/d", "https://foo.bar/path/a/b/c/d").href, + "https://foo.bar/d" + ); }); unitTest(function urlBaseString(): void { diff --git a/test_util/src/lib.rs b/test_util/src/lib.rs index 73a1df043d..10e803f5f6 100644 --- a/test_util/src/lib.rs +++ b/test_util/src/lib.rs @@ -146,6 +146,14 @@ pub async fn run_all_servers() { let u = url.parse::().unwrap(); warp::redirect(u) }) + .or( + warp::path!("a" / "b" / "c") + .and(warp::header::("x-location")) + .map(|token: String| { + let uri: Uri = token.parse().unwrap(); + warp::redirect(uri) + }), + ) .or( warp::any() .and(warp::path::peek())