diff --git a/lib/index.js b/lib/index.js index b1878ac..f0a2d9d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -143,8 +143,19 @@ 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') { + 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 d498fd5..ce1fe5f 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 2d72347..07b6dcf 100644 --- a/test/index.js +++ b/test/index.js @@ -379,6 +379,29 @@ t.test('treat broken redirect as ordinary response (manual)', t => { }) }) +t.test('should process an invalid redirect (manual)', t => { + const url = `${base}redirect/301/invalid` + const options = { + redirect: 'manual', + } + return fetch(url, options).then(res => { + 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', t => { + const url = `${base}redirect/301/invalid` + return fetch(url).then(res => { + t.fail() + }).catch((err) => { + t.type(err, FetchError) + t.equal(err.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)))