From a1be1150282c944080e48d3f03af14005fc19c04 Mon Sep 17 00:00:00 2001 From: Gar Date: Thu, 13 Apr 2023 13:08:03 -0700 Subject: [PATCH] fix: handle invalid redirect header in a response (#100) Co-authored-by: Mohammad macbook --- lib/index.js | 16 ++++++++++++++-- test/fixtures/server.js | 6 ++++++ test/index.js | 19 +++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index b1878ac..f81492d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -143,8 +143,20 @@ const fetch = async (url, opts) => { const location = headers.get('Location') // HTTP fetch step 5.3 - const locationURL = location === null ? null - : (new URL(location, request.url)).toString() + let locationURL = null + try { + locationURL = location === null ? null : new URL(location, request.url).toString() + } catch { + // error here can only be invalid URL in Location: header + // do not throw when options.redirect == manual + // let the user extract the errorneous redirect URL + if (request.redirect !== 'manual') { + /* eslint-disable-next-line max-len */ + reject(new FetchError(`uri requested responds with an invalid redirect URL: ${location}`, 'invalid-redirect')) + finalize() + return + } + } // HTTP fetch step 5.5 if (request.redirect === 'error') { diff --git a/test/fixtures/server.js b/test/fixtures/server.js index 05c1b69..c2215c5 100644 --- a/test/fixtures/server.js +++ b/test/fixtures/server.js @@ -223,6 +223,12 @@ class TestServer { res.end() } + if (p === '/redirect/301/invalid') { + res.statusCode = 301 + res.setHeader('Location', '//super:invalid:url%/') + res.end() + } + if (p === '/redirect/302') { res.statusCode = 302 res.setHeader('Location', '/inspect') diff --git a/test/index.js b/test/index.js index 6acc1c4..bbbbf36 100644 --- a/test/index.js +++ b/test/index.js @@ -380,6 +380,25 @@ t.test('treat broken redirect as ordinary response (manual)', async t => { t.equal(res.headers.get('location'), null) }) +t.test('should process an invalid redirect (manual)', async t => { + const url = `${base}redirect/301/invalid` + const options = { + redirect: 'manual', + } + const res = await fetch(url, options) + t.equal(res.url, url) + t.equal(res.status, 301) + t.equal(res.headers.get('location'), '//super:invalid:url%/') +}) + +t.test('should throw an error on invalid redirect url', async t => { + const url = `${base}redirect/301/invalid` + await t.rejects(fetch(url), { + name: 'FetchError', + message: 'uri requested responds with an invalid redirect URL: //super:invalid:url%/', + }) +}) + t.test('set redirected property on response when redirect', t => fetch(`${base}redirect/301`).then(res => t.equal(res.redirected, true)))