From 0a62aaa854e49a8b5786afa1a7448519ff40fc91 Mon Sep 17 00:00:00 2001 From: Vlad Cirstean <47884248+vlad-cirstean@users.noreply.github.com> Date: Thu, 18 Feb 2021 12:15:40 +0200 Subject: [PATCH 1/4] fix: add port to host header if available (#146) --- index.js | 2 +- test/host-header.js | 71 +++++++++++++++++++++++++++++++-------------- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/index.js b/index.js index 7b19f832..655fd90d 100644 --- a/index.js +++ b/index.js @@ -47,7 +47,7 @@ module.exports = fp(function from (fastify, opts, next) { const sourceHttp2 = req.httpVersionMajor === 2 const headers = sourceHttp2 ? filterPseudoHeaders(req.headers) : req.headers - headers.host = url.hostname + headers.host = url.host const qs = getQueryString(url.search, req.url, opts) let body = '' diff --git a/test/host-header.js b/test/host-header.js index 98670ebd..f504e9ef 100644 --- a/test/host-header.js +++ b/test/host-header.js @@ -1,38 +1,65 @@ 'use strict' -const t = require('tap') +const { test } = require('tap') const Fastify = require('fastify') const From = require('..') -const get = require('simple-get').concat const nock = require('nock') +const got = require('got') -const instance = Fastify() +test('hostname', async (t) => { + const instance = Fastify() + t.tearDown(instance.close.bind(instance)) -nock('http://httpbin.org') - .get('/ip') - .reply(200, function (uri, requestBody) { - t.is(this.req.headers.host, 'httpbin.org') - return { origin: '127.0.0.1' } + nock('http://httpbin.org') + .get('/ip') + .reply(200, function (uri, requestBody) { + t.is(this.req.headers.host, 'httpbin.org') + return { origin: '127.0.0.1' } + }) + + instance.get('*', (request, reply) => { + reply.from() }) -t.plan(6) -t.tearDown(instance.close.bind(instance)) + instance.register(From, { + base: 'http://httpbin.org' + }) -instance.get('*', (request, reply) => { - reply.from() -}) + await instance.listen(0) -instance.register(From, { - base: 'http://httpbin.org' + const res = await got.get(`http://localhost:${instance.server.address().port}/ip`, { + retry: 0 + }) + t.strictEqual(res.statusCode, 200) + t.strictEqual(res.headers['content-type'], 'application/json') + t.strictEqual(typeof JSON.parse(res.body).origin, 'string') }) -instance.listen(0, (err) => { - t.error(err) +test('hostname and port', async (t) => { + const instance = Fastify() + t.tearDown(instance.close.bind(instance)) + + nock('http://httpbin.org:8080') + .get('/ip') + .reply(200, function (uri, requestBody) { + t.is(this.req.headers.host, 'httpbin.org:8080') + return { origin: '127.0.0.1' } + }) + + instance.get('*', (request, reply) => { + reply.from() + }) + + instance.register(From, { + base: 'http://httpbin.org:8080' + }) + + await instance.listen(0) - get(`http://localhost:${instance.server.address().port}/ip`, (err, res, data) => { - t.error(err) - t.strictEqual(res.statusCode, 200) - t.strictEqual(res.headers['content-type'], 'application/json') - t.strictEqual(typeof JSON.parse(data).origin, 'string') + const res = await got.get(`http://localhost:${instance.server.address().port}/ip`, { + retry: 0 }) + t.strictEqual(res.statusCode, 200) + t.strictEqual(res.headers['content-type'], 'application/json') + t.strictEqual(typeof JSON.parse(res.body).origin, 'string') }) From 18f1de216505ebf0f851d70ef89bd01506f7dd41 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 18 Feb 2021 11:20:39 +0100 Subject: [PATCH 2/4] Bumped v4.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c9952b6c..406a4356 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fastify-reply-from", - "version": "4.0.0", + "version": "4.0.1", "description": "forward your HTTP request to another server, for fastify", "main": "index.js", "types": "index.d.ts", From 641be7591f5138bb74c19c08128b234de8b3854a Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Fri, 19 Feb 2021 18:45:06 +0100 Subject: [PATCH 3/4] Merge pull request from GHSA-qmw8-3v4g-gwj4 * fix: Re-enable unix+http:// base URL, prevent escape of base URL path Co-Authored-By: Corey Farrell * More fixes * Test more build-url error cases Co-authored-by: Corey Farrell --- lib/utils.js | 10 ++++++++-- test/build-url.js | 20 +++++++++++++++++++- test/unix-http.js | 9 +++++---- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index 48572cdc..3bcd6859 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -59,8 +59,14 @@ function buildURL (source, reqBase) { const dest = new URL(source, reqBase) // if base is specified, source url should not override it - if (reqBase && !reqBase.startsWith(dest.origin)) { - throw new Error('source must be a relative path string') + if (reqBase) { + if (!reqBase.endsWith('/') && dest.href.length > reqBase.length) { + reqBase = reqBase + '/' + } + + if (!dest.href.startsWith(reqBase)) { + throw new Error('source must be a relative path string') + } } return dest diff --git a/test/build-url.js b/test/build-url.js index f9010dc4..2eb5b3a0 100644 --- a/test/build-url.js +++ b/test/build-url.js @@ -21,13 +21,31 @@ test('should return same source when base is not specified', (t) => { t.equal(url.href, 'http://localhost/hi') }) +test('should handle lack of trailing slash in base', (t) => { + t.plan(3) + let url = buildURL('hi', 'http://localhost/hi') + t.equal(url.href, 'http://localhost/hi') + + url = buildURL('hi/', 'http://localhost/hi') + t.equal(url.href, 'http://localhost/hi/') + + url = buildURL('hi/more', 'http://localhost/hi') + t.equal(url.href, 'http://localhost/hi/more') +}) + const errorInputs = [ { source: '//10.0.0.10/hi', base: 'http://localhost' }, { source: 'http://10.0.0.10/hi', base: 'http://localhost' }, { source: 'https://10.0.0.10/hi', base: 'http://localhost' }, { source: 'blah://10.0.0.10/hi', base: 'http://localhost' }, { source: '//httpbin.org/hi', base: 'http://localhost' }, - { source: 'urn:foo:bar', base: 'http://localhost' } + { source: 'urn:foo:bar', base: 'http://localhost' }, + { source: 'http://localhost/private', base: 'http://localhost/exposed/' }, + { source: 'http://localhost/exposed-extra', base: 'http://localhost/exposed' }, + { source: '/private', base: 'http://localhost/exposed/' }, + { source: '/exposed-extra', base: 'http://localhost/exposed' }, + { source: '../private', base: 'http://localhost/exposed/' }, + { source: 'exposed-extra', base: 'http://localhost/exposed' } ] test('should throw when trying to override base', (t) => { diff --git a/test/unix-http.js b/test/unix-http.js index a8845c46..fddeb5c9 100644 --- a/test/unix-http.js +++ b/test/unix-http.js @@ -13,14 +13,15 @@ if (process.platform === 'win32') { process.exit(0) } +const socketPath = `${__filename}.socket` +const upstream = `unix+http://${querystring.escape(socketPath)}/` + const instance = Fastify() -instance.register(From) +instance.register(From, { base: upstream }) t.plan(10) t.tearDown(instance.close.bind(instance)) -const socketPath = `${__filename}.socket` - try { fs.unlinkSync(socketPath) } catch (_) { @@ -37,7 +38,7 @@ const target = http.createServer((req, res) => { }) instance.get('/', (request, reply) => { - reply.from(`unix+http://${querystring.escape(socketPath)}/hello`) + reply.from('hello') }) t.tearDown(target.close.bind(target)) From e158d9b1dec30ba130c4db7aedb047024f8dbeea Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Fri, 19 Feb 2021 18:46:38 +0100 Subject: [PATCH 4/4] Bumped v4.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 406a4356..093c1b52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fastify-reply-from", - "version": "4.0.1", + "version": "4.0.2", "description": "forward your HTTP request to another server, for fastify", "main": "index.js", "types": "index.d.ts",