diff --git a/packages/request/lib/request.js b/packages/request/lib/request.js index c254eae94..e53555cb1 100644 --- a/packages/request/lib/request.js +++ b/packages/request/lib/request.js @@ -34,7 +34,11 @@ module.exports = async function request(url, options = {}) { // DNS cache lookup has already been configured. } - if (_.isEmpty(url) || !validator.isURL(url)) { + const isUrlValid = + typeof url === 'string' && + // `validator.isURL` doesn't let us express "any TLD or localhost", so we do two checks. + (validator.isURL(url) || validator.isURL(url, { host_whitelist: ['localhost'] })); + if (!isUrlValid) { return Promise.reject( new errors.InternalServerError({ message: 'URL empty or invalid.', diff --git a/packages/request/test/request.test.js b/packages/request/test/request.test.js index 957f1be35..eaf5f5874 100644 --- a/packages/request/test/request.test.js +++ b/packages/request/test/request.test.js @@ -120,6 +120,35 @@ describe('Request', function () { ); }); + it('[failure] rejects URL longer than 2084 characters', function () { + const url = `http://example.com/${'a'.repeat(2066)}`; + + assert.equal(url.length, 2085); + + return assert.rejects(request(url), { + message: 'URL empty or invalid.', + }); + }); + + ['http://example.com/white space', 'http://example.com/'].forEach((url) => { + it(`[failure] rejects URL containing invalid characters: ${url}`, function () { + return assert.rejects(request(url), { + message: 'URL empty or invalid.', + }); + }); + }); + + it('[success] allows localhost URL', function () { + const url = 'http://localhost:2368/endpoint/'; + const requestMock = nock('http://localhost:2368') + .get('/endpoint/') + .reply(200, 'Response body'); + + return request(url).then(function () { + assert.equal(requestMock.isDone(), true); + }); + }); + it('[failure] can handle empty url', function () { const url = ''; const options = {