From 989d2d1333b4d9008e00ca542a1405e0601e0d3b Mon Sep 17 00:00:00 2001 From: Hazel Date: Mon, 4 Jul 2022 10:46:03 +0200 Subject: [PATCH] fix: improper handling of relative location header (#1523) --- lib/handler/redirect.js | 2 +- test/redirect-relative.js | 22 ++++++++++++++++++++++ test/utils/redirecting-servers.js | 24 +++++++++++++++++++++++- 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 test/redirect-relative.js diff --git a/lib/handler/redirect.js b/lib/handler/redirect.js index 32f74ffa381..998a8c2352b 100644 --- a/lib/handler/redirect.js +++ b/lib/handler/redirect.js @@ -99,7 +99,7 @@ class RedirectHandler { return this.handler.onHeaders(statusCode, headers, resume, statusText) } - const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin)) + const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))) const path = search ? `${pathname}${search}` : pathname // Remove headers referring to the original URL. diff --git a/test/redirect-relative.js b/test/redirect-relative.js new file mode 100644 index 00000000000..ca9c5411ba4 --- /dev/null +++ b/test/redirect-relative.js @@ -0,0 +1,22 @@ +'use strict' + +const t = require('tap') +const { request } = require('..') +const { + startRedirectingWithRelativePath +} = require('./utils/redirecting-servers') + +t.test('should redirect to relative URL according to RFC 7231', async t => { + t.plan(2) + + const server = await startRedirectingWithRelativePath(t) + + const { statusCode, body } = await request(`http://${server}`, { + maxRedirections: 3 + }) + + const finalPath = await body.text() + + t.equal(statusCode, 200) + t.equal(finalPath, '/absolute/b') +}) diff --git a/test/utils/redirecting-servers.js b/test/utils/redirecting-servers.js index bfb2415e7c4..02812a9759d 100644 --- a/test/utils/redirecting-servers.js +++ b/test/utils/redirecting-servers.js @@ -178,11 +178,33 @@ async function startRedirectingWithAuthorization (t, authorization) { return [server1, server2] } +async function startRedirectingWithRelativePath (t) { + const server = await startServer(t, (req, res) => { + res.setHeader('Connection', 'close') + + if (req.url === '/') { + res.statusCode = 301 + res.setHeader('Location', '/absolute/a') + res.end('') + } else if (req.url === '/absolute/a') { + res.statusCode = 301 + res.setHeader('Location', 'b') + res.end('') + } else { + res.statusCode = 200 + res.end(req.url) + } + }) + + return server +} + module.exports = { startServer, startRedirectingServer, startRedirectingWithBodyServer, startRedirectingWithoutLocationServer, startRedirectingChainServers, - startRedirectingWithAuthorization + startRedirectingWithAuthorization, + startRedirectingWithRelativePath }