Ghost/ghost/mw-vhost/test/vhost.test.js
Hannah Wolfe 6161f94910
Updated to use assert/strict everywhere (#17047)
refs: https://github.com/TryGhost/Toolbox/issues/595

We're rolling out new rules around the node assert library, the first of which is enforcing the use of assert/strict. This means we don't need to use the strict version of methods, as the standard version will work that way by default.

This caught some gotchas in our existing usage of assert where the lack of strict mode had unexpected results:
- Url matching needs to be done on `url.href` see aa58b354a4
- Null and undefined are not the same thing,  there were a few cases of this being confused
- Particularly questionable changes in [PostExporter tests](c1a468744b) tracked [here](https://github.com/TryGhost/Team/issues/3505).
- A typo see eaac9c293a

Moving forward, using assert strict should help us to catch unexpected behaviour, particularly around nulls and undefineds during implementation.
2023-06-21 09:56:59 +01:00

294 lines
8.6 KiB
JavaScript

const assert = require('assert/strict');
const http = require('http');
const request = require('supertest');
const vhost = require('..');
describe('vhost(hostname, server)', function () {
it('should route by Host', function (done) {
const vhosts = [];
vhosts.push(vhost('tobi.com', tobi));
vhosts.push(vhost('loki.com', loki));
const app = createServer(vhosts);
function tobi(req, res) {
res.end('tobi');
}
function loki(req, res) {
res.end('loki');
}
request(app)
.get('/')
.set('Host', 'tobi.com')
.expect(200, 'tobi', done);
});
it('should route by `req.hostname` (express v4)', function (done) {
const vhosts = [];
vhosts.push(vhost('anotherhost.com', anotherhost));
vhosts.push(vhost('loki.com', loki));
const app = createServer(vhosts, null, function (req) {
// simulate express setting req.hostname based on x-forwarded-host
req.hostname = 'anotherhost.com';
});
function anotherhost(req, res) {
res.end('anotherhost');
}
function loki(req, res) {
res.end('loki');
}
request(app)
.get('/')
.set('Host', 'loki.com')
.expect(200, 'anotherhost', done);
});
it('should ignore port in Host', function (done) {
const app = createServer('tobi.com', function (req, res) {
res.end('tobi');
});
request(app)
.get('/')
.set('Host', 'tobi.com:8080')
.expect(200, 'tobi', done);
});
it('should support IPv6 literal in Host', function (done) {
const app = createServer('[::1]', function (req, res) {
res.end('loopback');
});
request(app)
.get('/')
.set('Host', '[::1]:8080')
.expect(200, 'loopback', done);
});
it('should 404 unless matched', function (done) {
const vhosts = [];
vhosts.push(vhost('tobi.com', tobi));
vhosts.push(vhost('loki.com', loki));
const app = createServer(vhosts);
function tobi(req, res) {
res.end('tobi');
}
function loki(req, res) {
res.end('loki');
}
request(app)
.get('/')
.set('Host', 'ferrets.com')
.expect(404, done);
});
it('should 404 without Host header', function (done) {
const vhosts = [];
vhosts.push(vhost('tobi.com', tobi));
vhosts.push(vhost('loki.com', loki));
const server = createServer(vhosts);
const listeners = server.listeners('request');
server.removeAllListeners('request');
listeners.unshift(function (req) {
req.headers.host = undefined;
});
listeners.forEach(function (l) {
server.addListener('request', l);
});
function tobi(req, res) {
res.end('tobi');
}
function loki(req, res) {
res.end('loki');
}
request(server)
.get('/')
.expect(404, 'no vhost for "undefined"', done);
});
describe('arguments', function () {
describe('hostname', function () {
it('should be required', function () {
assert.throws(vhost.bind(), /hostname.*required/);
});
it('should accept string', function () {
assert.doesNotThrow(vhost.bind(null, 'loki.com', function () {}));
});
it('should accept RegExp', function () {
assert.doesNotThrow(vhost.bind(null, /loki\.com/, function () {}));
});
});
describe('handle', function () {
it('should be required', function () {
assert.throws(vhost.bind(null, 'loki.com'), /handle.*required/);
});
it('should accept function', function () {
assert.doesNotThrow(vhost.bind(null, 'loki.com', function () {}));
});
it('should reject plain object', function () {
assert.throws(vhost.bind(null, 'loki.com', {}), /handle.*function/);
});
});
});
describe('with string hostname', function () {
it('should support wildcards', function (done) {
const app = createServer('*.ferrets.com', function (req, res) {
res.end('wildcard!');
});
request(app)
.get('/')
.set('Host', 'loki.ferrets.com')
.expect(200, 'wildcard!', done);
});
it('should restrict wildcards to single part', function (done) {
const app = createServer('*.ferrets.com', function (req, res) {
res.end('wildcard!');
});
request(app)
.get('/')
.set('Host', 'foo.loki.ferrets.com')
.expect(404, done);
});
it('should treat dot as a dot', function (done) {
const app = createServer('a.b.com', function (req, res) {
res.end('tobi');
});
request(app)
.get('/')
.set('Host', 'aXb.com')
.expect(404, done);
});
it('should match entire string', function (done) {
const app = createServer('.com', function (req, res) {
res.end('commercial');
});
request(app)
.get('/')
.set('Host', 'foo.com')
.expect(404, done);
});
it('should populate req.vhost', function (done) {
const app = createServer('user-*.*.com', function (req, res) {
const keys = Object.keys(req.vhost).sort();
const arr = keys.map(function (k) {
return [k, req.vhost[k]];
});
res.end(JSON.stringify(arr));
});
request(app)
.get('/')
.set('Host', 'user-bob.foo.com:8080')
.expect(200, '[["0","bob"],["1","foo"],["host","user-bob.foo.com:8080"],["hostname","user-bob.foo.com"],["length",2]]', done);
});
});
describe('with RegExp hostname', function () {
it('should match using RegExp', function (done) {
const app = createServer(/[tl]o[bk]i\.com/, function (req, res) {
res.end('tobi');
});
request(app)
.get('/')
.set('Host', 'toki.com')
.expect(200, 'tobi', done);
});
it('should match entire hostname', function (done) {
const vhosts = [];
vhosts.push(vhost(/\.tobi$/, tobi));
vhosts.push(vhost(/^loki\./, loki));
const app = createServer(vhosts);
function tobi(req, res) {
res.end('tobi');
}
function loki(req, res) {
res.end('loki');
}
request(app)
.get('/')
.set('Host', 'loki.tobi.com')
.expect(404, done);
});
it('should populate req.vhost', function (done) {
const app = createServer(/user-(bob|joe)\.([^.]+)\.com/, function (req, res) {
const keys = Object.keys(req.vhost).sort();
const arr = keys.map(function (k) {
return [k, req.vhost[k]];
});
res.end(JSON.stringify(arr));
});
request(app)
.get('/')
.set('Host', 'user-bob.foo.com:8080')
.expect(200, '[["0","bob"],["1","foo"],["host","user-bob.foo.com:8080"],["hostname","user-bob.foo.com"],["length",2]]', done);
});
});
});
function createServer(hostname, server, pretest) {
const vhosts = !Array.isArray(hostname)
? [vhost(hostname, server)]
: hostname;
return http.createServer(function onRequest(req, res) {
// This allows you to perform changes to the request/response
// objects before our assertions
if (pretest) {
pretest(req, res);
}
let index = 0;
function next(err) {
const foundVhost = vhosts[index];
index = index + 1;
if (!foundVhost || err) {
res.statusCode = err ? (err.status || 500) : 404;
res.end(err ? err.message : `no vhost for "${req.headers.host}"`);
return;
}
foundVhost(req, res, next);
}
next();
});
}