From 767ab9755d10b53736693cb1382464a57f4bb596 Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Tue, 16 Sep 2025 08:52:01 +0200 Subject: [PATCH 1/3] fix: produce relative redirect location url for same origin --- edge-runtime/lib/response.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edge-runtime/lib/response.ts b/edge-runtime/lib/response.ts index 31bb7ead7b..fa000a3842 100644 --- a/edge-runtime/lib/response.ts +++ b/edge-runtime/lib/response.ts @@ -210,7 +210,7 @@ export const buildResponse = async ({ logger.withFields({ redirect_url: redirect }).debug('Redirect url is same as original url') return } - edgeResponse.headers.set('location', redirect) + edgeResponse.headers.set('location', relativizeURL(redirect, request.url)) } // Data requests shouldn't automatically redirect in the browser (they might be HTML pages): they're handled by the router From dbde615208ceb6115e7cf181480f2bdac9db3be9 Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Tue, 16 Sep 2025 12:44:43 +0200 Subject: [PATCH 2/3] test: add basic unit tests for relativizeURL --- edge-runtime/lib/util.test.ts | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/edge-runtime/lib/util.test.ts b/edge-runtime/lib/util.test.ts index 99d3bf3d63..98646b58dc 100644 --- a/edge-runtime/lib/util.test.ts +++ b/edge-runtime/lib/util.test.ts @@ -1,5 +1,5 @@ import { assertEquals } from 'https://deno.land/std@0.175.0/testing/asserts.ts' -import { rewriteDataPath } from './util.ts' +import { relativizeURL, rewriteDataPath } from './util.ts' Deno.test('rewriteDataPath', async (t) => { await t.step('should rewrite a data url', async () => { @@ -37,3 +37,26 @@ Deno.test('rewriteDataPath', async (t) => { assertEquals(result, '/_next/data/build-id/target.json') }) }) + +Deno.test('relativizeURL', async (t) => { + await t.step('should relativize a URL when origin matches', async () => { + const url = 'https://example.com/pathname' + const base = 'https://example.com/' + const result = relativizeURL(url, base) + assertEquals(result, '/pathname') + }) + + await t.step('should NOT relativize a URL when origin does not match', async () => { + const url = 'https://example.com/pathname' + const base = 'https://not-example.com/' + const result = relativizeURL(url, base) + assertEquals(result, 'https://example.com/pathname') + }) + + await t.step('accepts relative URL strings and produce relative URL as output', async () => { + const url = '/pathname' + const base = 'https://example.com/' + const result = relativizeURL(url, base) + assertEquals(result, '/pathname') + }) +}) From 9fcd6b4a3950de3256d04ed2dfcbebe2a08eb282 Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Tue, 16 Sep 2025 13:03:57 +0200 Subject: [PATCH 3/3] test: adjust integration tests redirect assertions --- tests/integration/middleware.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/integration/middleware.test.ts b/tests/integration/middleware.test.ts index 5e8e7a2812..04153c97de 100644 --- a/tests/integration/middleware.test.ts +++ b/tests/integration/middleware.test.ts @@ -130,7 +130,7 @@ for (const { expect(response.status).toBe(307) expect(response.headers.get('location'), 'added a location header').toBeTypeOf('string') expect( - new URL(response.headers.get('location') as string).pathname, + new URL(response.headers.get('location') as string, 'http://n').pathname, 'redirected to the correct path', ).toEqual('/other') expect(response.headers.get('x-runtime')).toEqual(expectedRuntime) @@ -154,7 +154,7 @@ for (const { expect(response.status).toBe(307) expect(response.headers.get('location'), 'added a location header').toBeTypeOf('string') expect( - new URL(response.headers.get('location') as string).pathname, + new URL(response.headers.get('location') as string, 'http://n').pathname, 'redirected to the correct path', ).toEqual('/other') expect(response.headers.get('x-header-from-redirect'), 'hello').toBe('hello') @@ -357,7 +357,7 @@ for (const { expect(response.status).toBe(307) expect(response.headers.get('location'), 'added a location header').toBeTypeOf('string') expect( - new URL(response.headers.get('location') as string).pathname, + new URL(response.headers.get('location') as string, 'http://n').pathname, 'redirected to the correct path', ).toEqual('/other') expect(response.headers.get('x-header-from-redirect'), 'hello').toBe('hello') @@ -382,7 +382,7 @@ for (const { expect(response.status).toBe(307) expect(response.headers.get('location'), 'added a location header').toBeTypeOf('string') expect( - new URL(response.headers.get('location') as string).pathname, + new URL(response.headers.get('location') as string, 'http://n').pathname, 'redirected to the correct path', ).toEqual('/other') expect(response.headers.get('x-header-from-redirect'), 'hello').toBe('hello')