From a991989187afcaac7b13294001da68f1c8c1ac7d Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Fri, 6 Nov 2020 19:52:52 +0100 Subject: [PATCH] fix: accept absolute urls as path (#468) --- lib/core/request.js | 10 ++++++++-- test/client.js | 26 ++++++++++++++++++++++++++ test/validations.js | 4 ++-- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/lib/core/request.js b/lib/core/request.js index ee53777e7bd..05304a908c0 100644 --- a/lib/core/request.js +++ b/lib/core/request.js @@ -13,6 +13,10 @@ const kRequestTimeout = Symbol('request timeout') const kTimeout = Symbol('timeout') const kHandler = Symbol('handler') +// Borrowed from https://gist.github.com/dperini/729294 +// eslint-disable-next-line no-control-regex +const REGEXP_ABSOLUTE_URL = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x00a1-\xffff0-9]+-?)*[a-z\x00a1-\xffff0-9]+)(?:\.(?:[a-z\x00a1-\xffff0-9]+-?)*[a-z\x00a1-\xffff0-9]+)*(?:\.(?:[a-z\x00a1-\xffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/ius + class Request { constructor ({ path, @@ -23,8 +27,10 @@ class Request { upgrade, requestTimeout }, handler) { - if (typeof path !== 'string' || path[0] !== '/') { - throw new InvalidArgumentError('path must be a valid path') + if (typeof path !== 'string') { + throw new InvalidArgumentError('path must be a string') + } else if (path[0] !== '/' && !REGEXP_ABSOLUTE_URL.test(path)) { + throw new InvalidArgumentError('path must be an absolute URL or start with a slash') } if (typeof method !== 'string') { diff --git a/test/client.js b/test/client.js index 5974b22db6c..1d8166dcd6c 100644 --- a/test/client.js +++ b/test/client.js @@ -625,6 +625,32 @@ test('url-like url', (t) => { }) }) +test('an absolute url as path', (t) => { + t.plan(2) + + const path = 'http://example.com' + + const server = createServer((req, res) => { + t.strictEqual(req.url, path) + res.end() + }) + t.tearDown(server.close.bind(server)) + + server.listen(0, () => { + const client = new Client({ + hostname: 'localhost', + port: server.address().port, + protocol: 'http' + }) + t.tearDown(client.close.bind(client)) + + client.request({ path, method: 'GET' }, (err, data) => { + t.error(err) + data.body.resume() + }) + }) +}) + test('multiple destroy callback', (t) => { t.plan(4) diff --git a/test/validations.js b/test/validations.js index 996595d42a0..6ce1da1ae83 100644 --- a/test/validations.js +++ b/test/validations.js @@ -23,12 +23,12 @@ server.listen(0, () => { client.request({ path: null, method: 'GET' }, (err, res) => { t.ok(err instanceof errors.InvalidArgumentError) - t.strictEqual(err.message, 'path must be a valid path') + t.strictEqual(err.message, 'path must be a string') }) client.request({ path: 'aaa', method: 'GET' }, (err, res) => { t.ok(err instanceof errors.InvalidArgumentError) - t.strictEqual(err.message, 'path must be a valid path') + t.strictEqual(err.message, 'path must be an absolute URL or start with a slash') }) })