From 3412535be4a0ec94cea18c5d186b7ffbd6f8209c Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Fri, 3 May 2024 21:01:25 +0200 Subject: [PATCH] fix: don't include port twice from x-forwarded-host and x-forwarded-port headers (#10917) * fix: don't include port twice from x-forwarded-host and x-forwarded-port headers * add changeset * add test for port both in forwarded host and forwarded port * don't include port if undefined * Update .changeset/forty-wolves-turn.md Co-authored-by: Florian Lefebvre --------- Co-authored-by: Florian Lefebvre --- .changeset/forty-wolves-turn.md | 5 +++++ packages/astro/src/core/app/node.ts | 7 ++++++- packages/integrations/node/test/url.test.js | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 .changeset/forty-wolves-turn.md diff --git a/.changeset/forty-wolves-turn.md b/.changeset/forty-wolves-turn.md new file mode 100644 index 000000000000..87f6e50226c5 --- /dev/null +++ b/.changeset/forty-wolves-turn.md @@ -0,0 +1,5 @@ +--- +"astro": patch +--- + +Fixes a case where the local server would crash when the host also contained the port, eg. with `X-Forwarded-Host: hostname:8080` and `X-Forwarded-Port: 8080` headers diff --git a/packages/astro/src/core/app/node.ts b/packages/astro/src/core/app/node.ts index b90a9ec8e789..c28fa8754d7c 100644 --- a/packages/astro/src/core/app/node.ts +++ b/packages/astro/src/core/app/node.ts @@ -66,7 +66,12 @@ export class NodeApp extends App { const hostname = req.headers['x-forwarded-host'] ?? req.headers.host ?? req.headers[':authority']; const port = req.headers['x-forwarded-port']; - const url = `${protocol}://${hostname}${port ? `:${port}` : ''}${req.url}`; + + const portInHostname = + typeof hostname === 'string' && typeof port === 'string' && hostname.endsWith(port); + const hostnamePort = portInHostname ? hostname : hostname + (port ? `:${port}` : ''); + + const url = `${protocol}://${hostnamePort}${req.url}`; const options: RequestInit = { method: req.method || 'GET', headers: makeRequestHeaders(req), diff --git a/packages/integrations/node/test/url.test.js b/packages/integrations/node/test/url.test.js index 6fc008236613..77ca45836638 100644 --- a/packages/integrations/node/test/url.test.js +++ b/packages/integrations/node/test/url.test.js @@ -92,4 +92,24 @@ describe('URL', () => { assert.equal($('body').text(), 'https://abc.xyz:444/'); }); + + it('accepts port in forwarded host and forwarded port', async () => { + const { handler } = await import('./fixtures/url/dist/server/entry.mjs'); + let { req, res, text } = createRequestAndResponse({ + headers: { + 'X-Forwarded-Proto': 'https', + 'X-Forwarded-Host': 'abc.xyz:444', + 'X-Forwarded-Port': '444', + }, + url: '/', + }); + + handler(req, res); + req.send(); + + const html = await text(); + const $ = cheerio.load(html); + + assert.equal($('body').text(), 'https://abc.xyz:444/'); + }); });