mirror of https://gitee.com/bigwinds/arangodb
Add SyntheticRequest tests
This commit is contained in:
parent
2993b73c25
commit
18ff55b7dd
|
@ -328,7 +328,11 @@ exports.loadStartup = function (path) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
if (global.SYS_RAW_REQUEST_BODY) {
|
if (global.SYS_RAW_REQUEST_BODY) {
|
||||||
exports.rawRequestBody = global.SYS_RAW_REQUEST_BODY;
|
const $_RAW_BODY_BUFFER = Symbol.for('@arangodb/request.rawBodyBuffer');
|
||||||
|
const getRawBodyBuffer = global.SYS_RAW_REQUEST_BODY;
|
||||||
|
exports.rawRequestBody = function (req) {
|
||||||
|
return req[$_RAW_BODY_BUFFER] || getRawBodyBuffer(req);
|
||||||
|
};
|
||||||
delete global.SYS_RAW_REQUEST_BODY;
|
delete global.SYS_RAW_REQUEST_BODY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const parseUrl = require('url').parse;
|
const parseUrl = require('url').parse;
|
||||||
|
const formatUrl = require('url').format;
|
||||||
|
const joinPath = require('path').posix.join;
|
||||||
const typeIs = require('type-is').is;
|
const typeIs = require('type-is').is;
|
||||||
const accepts = require('accepts');
|
const accepts = require('accepts');
|
||||||
const parseRange = require('range-parser');
|
const parseRange = require('range-parser');
|
||||||
|
@ -36,7 +38,7 @@ module.exports = class SyntheticRequest {
|
||||||
this._raw = req;
|
this._raw = req;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.suffix = req.suffix.join('/');
|
this.suffix = req.suffix.join('/');
|
||||||
this.baseUrl = `/_db/${encodeURIComponent(this._raw.database)}`;
|
this.baseUrl = joinPath('/_db', encodeURIComponent(this._raw.database));
|
||||||
this.path = this._url.pathname;
|
this.path = this._url.pathname;
|
||||||
this.pathParams = {};
|
this.pathParams = {};
|
||||||
this.queryParams = querystring.decode(this._url.query);
|
this.queryParams = querystring.decode(this._url.query);
|
||||||
|
@ -66,7 +68,11 @@ module.exports = class SyntheticRequest {
|
||||||
// Express compat
|
// Express compat
|
||||||
|
|
||||||
get originalUrl() {
|
get originalUrl() {
|
||||||
return this.baseUrl + this._url.pathname + (this._url.search || '');
|
return joinPath(
|
||||||
|
'/_db',
|
||||||
|
encodeURIComponent(this._raw.database),
|
||||||
|
this._url.pathname
|
||||||
|
) + (this._url.search || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
get secure() {
|
get secure() {
|
||||||
|
@ -82,39 +88,54 @@ module.exports = class SyntheticRequest {
|
||||||
return Boolean(header && header.toLowerCase() === 'xmlhttprequest');
|
return Boolean(header && header.toLowerCase() === 'xmlhttprequest');
|
||||||
}
|
}
|
||||||
|
|
||||||
accepts(types) {
|
accepts() {
|
||||||
const accept = accepts(this);
|
const accept = accepts(this);
|
||||||
return accept.type(types);
|
return accept.types.apply(accept, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptsCharsets() {
|
acceptsCharsets() {
|
||||||
const accept = accepts(this);
|
const accept = accepts(this);
|
||||||
return accept.charset.apply(accept, arguments);
|
return accept.charsets.apply(accept, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptsEncodings() {
|
acceptsEncodings() {
|
||||||
const accept = accepts(this);
|
const accept = accepts(this);
|
||||||
return accept.encoding.apply(accept, arguments);
|
return accept.encodings.apply(accept, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptsLanguages() {
|
acceptsLanguages() {
|
||||||
const accept = accepts(this);
|
const accept = accepts(this);
|
||||||
return accept.language.apply(accept, arguments);
|
return accept.languages.apply(accept, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
range(size) {
|
||||||
|
const range = this.headers.range;
|
||||||
|
if (!range) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return parseRange(size, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
get(name) {
|
get(name) {
|
||||||
name = name.toLowerCase();
|
const lc = name.toLowerCase();
|
||||||
if (name === 'referer' || name === 'referrer') {
|
if (lc === 'referer' || lc === 'referrer') {
|
||||||
return this.headers.referer || this.headers.referrer;
|
return this.headers.referer || this.headers.referrer;
|
||||||
}
|
}
|
||||||
return this.headers[name];
|
return this.headers[lc];
|
||||||
|
}
|
||||||
|
|
||||||
|
header(name) {
|
||||||
|
return this.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
is(mediaType) {
|
is(mediaType) {
|
||||||
if (!this.headers['content-type']) {
|
if (!this.headers['content-type']) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return Boolean(typeIs(this.headers['content-type'], mediaType));
|
if (!Array.isArray(mediaType)) {
|
||||||
|
mediaType = Array.prototype.slice.call(arguments);
|
||||||
|
}
|
||||||
|
return typeIs(this, mediaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// idiosyncratic
|
// idiosyncratic
|
||||||
|
@ -139,18 +160,26 @@ module.exports = class SyntheticRequest {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
makeAbsolute(path) {
|
makeAbsolute(path, query) {
|
||||||
return this.protocol + '://' + this.hostname + (
|
const opts = {
|
||||||
(this.secure ? this.port !== 443 : this.port !== 80)
|
protocol: this.protocol,
|
||||||
? ':' + this.port : ''
|
hostname: this.hostname,
|
||||||
) + this.baseUrl + path;
|
port: (this.secure ? this.port !== 443 : this.port !== 80) && this.port,
|
||||||
}
|
pathname: joinPath(
|
||||||
|
'/_db',
|
||||||
ranges(size) {
|
encodeURIComponent(this._raw.database),
|
||||||
if (!this.headers.range) {
|
this.context.mount,
|
||||||
return [];
|
path
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if (query) {
|
||||||
|
if (typeof query === 'string') {
|
||||||
|
opts.search = query;
|
||||||
|
} else {
|
||||||
|
opts.query = query;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return parseRange(size, this.headers.range);
|
return formatUrl(opts);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
const joinPath = require('path').posix.join;
|
||||||
const querystring = require('querystring');
|
const querystring = require('querystring');
|
||||||
const httpError = require('http-errors');
|
const httpError = require('http-errors');
|
||||||
const union = require('@arangodb/util').union;
|
const union = require('@arangodb/util').union;
|
||||||
|
@ -269,7 +270,7 @@ function dispatch(route, req, res) {
|
||||||
req.path = '/' + item.path.join('/');
|
req.path = '/' + item.path.join('/');
|
||||||
req.suffix = item.suffix.join('/');
|
req.suffix = item.suffix.join('/');
|
||||||
if (req.suffix) {
|
if (req.suffix) {
|
||||||
req.path += '/' + req.suffix.join('/');
|
req.path = joinPath(req.path, req.suffix.join('/'));
|
||||||
}
|
}
|
||||||
res._responses = item._responses;
|
res._responses = item._responses;
|
||||||
req.reverse = function (routeName, params, suffix) {
|
req.reverse = function (routeName, params, suffix) {
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
'use strict';
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// DISCLAIMER
|
||||||
|
///
|
||||||
|
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
/// you may not use this file except in compliance with the License.
|
||||||
|
/// You may obtain a copy of the License at
|
||||||
|
///
|
||||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
///
|
||||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
/// See the License for the specific language governing permissions and
|
||||||
|
/// limitations under the License.
|
||||||
|
///
|
||||||
|
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||||
|
///
|
||||||
|
/// @author Alan Plum
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
exports.createNativeRequest = function (opts) {
|
||||||
|
const req = {
|
||||||
|
requestType: opts.method || 'get',
|
||||||
|
protocol: opts.protocol || 'http',
|
||||||
|
database: opts.db || '_system',
|
||||||
|
url: `${opts.mount || ''}${opts.path || ''}${opts.search || ''}`,
|
||||||
|
suffix: opts.path ? opts.path.split('/').filter(Boolean) : [],
|
||||||
|
headers: opts.headers || {},
|
||||||
|
cookies: opts.cookies || {},
|
||||||
|
server: opts.server || {
|
||||||
|
address: '127.0.0.1',
|
||||||
|
port: opts.port || 8529
|
||||||
|
},
|
||||||
|
client: opts.client || {
|
||||||
|
address: '127.0.0.1',
|
||||||
|
port: 33333
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (opts.body) {
|
||||||
|
req[Symbol.for('@arangodb/request.rawBodyBuffer')] = (
|
||||||
|
opts.body instanceof Buffer ? opts.body : new Buffer(
|
||||||
|
typeof opts.body !== 'string'
|
||||||
|
? JSON.stringify(opts.body, null, 2)
|
||||||
|
: opts.body
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return req;
|
||||||
|
};
|
|
@ -1,26 +1,9 @@
|
||||||
/*global describe, it */
|
/*global describe, it */
|
||||||
'use strict';
|
'use strict';
|
||||||
const expect = require('chai').expect;
|
const expect = require('chai').expect;
|
||||||
|
const crypto = require('@arangodb/crypto');
|
||||||
const SyntheticRequest = require('@arangodb/foxx/router/request');
|
const SyntheticRequest = require('@arangodb/foxx/router/request');
|
||||||
|
const createNativeRequest = require('@arangodb/foxx/test-utils').createNativeRequest;
|
||||||
function createNativeRequest(opts) {
|
|
||||||
return {
|
|
||||||
requestType: opts.method || 'get',
|
|
||||||
protocol: opts.protocol || 'http',
|
|
||||||
database: opts.db || '_system',
|
|
||||||
url: `${opts.mount || ''}${opts.path || ''}${opts.query || ''}`,
|
|
||||||
suffix: opts.path ? opts.path.split('/').filter(Boolean) : [],
|
|
||||||
headers: opts.headers || {},
|
|
||||||
server: opts.server || {
|
|
||||||
address: '127.0.0.1',
|
|
||||||
port: opts.port || 8529
|
|
||||||
},
|
|
||||||
client: opts.client || {
|
|
||||||
address: '127.0.0.1',
|
|
||||||
port: 33333
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('SyntheticRequest', function () {
|
describe('SyntheticRequest', function () {
|
||||||
describe('protocol/secure', function () {
|
describe('protocol/secure', function () {
|
||||||
|
@ -73,6 +56,7 @@ describe('SyntheticRequest', function () {
|
||||||
expect(req.secure).to.equal(false);
|
expect(req.secure).to.equal(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hostname/port', function () {
|
describe('hostname/port', function () {
|
||||||
it('defaults to the host header of the native request', function () {
|
it('defaults to the host header of the native request', function () {
|
||||||
const rawReq = createNativeRequest({
|
const rawReq = createNativeRequest({
|
||||||
|
@ -143,6 +127,7 @@ describe('SyntheticRequest', function () {
|
||||||
expect(req.port).to.equal(5678);
|
expect(req.port).to.equal(5678);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('remoteAddress(es)', function () {
|
describe('remoteAddress(es)', function () {
|
||||||
it('defaults to the client info of the native request', function () {
|
it('defaults to the client info of the native request', function () {
|
||||||
const rawReq = createNativeRequest({
|
const rawReq = createNativeRequest({
|
||||||
|
@ -206,6 +191,7 @@ describe('SyntheticRequest', function () {
|
||||||
expect(req.remoteAddresses).to.eql(ips);
|
expect(req.remoteAddresses).to.eql(ips);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('remotePort', function () {
|
describe('remotePort', function () {
|
||||||
it('defaults to the client info of the native request', function () {
|
it('defaults to the client info of the native request', function () {
|
||||||
const rawReq = createNativeRequest({
|
const rawReq = createNativeRequest({
|
||||||
|
@ -251,6 +237,7 @@ describe('SyntheticRequest', function () {
|
||||||
expect(req.remotePort).to.equal(9999);
|
expect(req.remotePort).to.equal(9999);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('queryParams', function () {
|
describe('queryParams', function () {
|
||||||
it('is correctly derived from the native request when empty', function () {
|
it('is correctly derived from the native request when empty', function () {
|
||||||
const rawReq = createNativeRequest({});
|
const rawReq = createNativeRequest({});
|
||||||
|
@ -259,7 +246,7 @@ describe('SyntheticRequest', function () {
|
||||||
});
|
});
|
||||||
it('is correctly derived from the native request', function () {
|
it('is correctly derived from the native request', function () {
|
||||||
const rawReq = createNativeRequest({
|
const rawReq = createNativeRequest({
|
||||||
query: '?a=1&b=2&c=3'
|
search: '?a=1&b=2&c=3'
|
||||||
});
|
});
|
||||||
const req = new SyntheticRequest(rawReq, {});
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
expect(req.queryParams).to.eql({
|
expect(req.queryParams).to.eql({
|
||||||
|
@ -269,6 +256,7 @@ describe('SyntheticRequest', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('baseUrl', function () {
|
describe('baseUrl', function () {
|
||||||
it('is correctly derived from the native request', function () {
|
it('is correctly derived from the native request', function () {
|
||||||
const rawReq = createNativeRequest({
|
const rawReq = createNativeRequest({
|
||||||
|
@ -280,6 +268,7 @@ describe('SyntheticRequest', function () {
|
||||||
expect(req.baseUrl).to.equal('/_db/bananas');
|
expect(req.baseUrl).to.equal('/_db/bananas');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('headers', function () {
|
describe('headers', function () {
|
||||||
it('exposes the headers of the native request', function () {
|
it('exposes the headers of the native request', function () {
|
||||||
const headers = {};
|
const headers = {};
|
||||||
|
@ -290,6 +279,7 @@ describe('SyntheticRequest', function () {
|
||||||
expect(req.headers).to.equal(headers);
|
expect(req.headers).to.equal(headers);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('method', function () {
|
describe('method', function () {
|
||||||
it('exposes the method of the native request', function () {
|
it('exposes the method of the native request', function () {
|
||||||
const rawReq = createNativeRequest({
|
const rawReq = createNativeRequest({
|
||||||
|
@ -299,54 +289,59 @@ describe('SyntheticRequest', function () {
|
||||||
expect(req.method).to.equal('potato');
|
expect(req.method).to.equal('potato');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('originalUrl', function () {
|
describe('originalUrl', function () {
|
||||||
it('exposes the root relative URL of the native request', function () {
|
it('exposes the root relative URL of the native request', function () {
|
||||||
const rawReq = createNativeRequest({
|
const rawReq = createNativeRequest({
|
||||||
db: 'bananas',
|
db: 'bananas',
|
||||||
mount: '/hi',
|
mount: '/hi',
|
||||||
path: '/friend/of/mine',
|
path: '/friend/of/mine',
|
||||||
query: '?hello=yes&goodbye=indeed'
|
search: '?hello=yes&goodbye=indeed'
|
||||||
});
|
});
|
||||||
const req = new SyntheticRequest(rawReq, {});
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
expect(req.originalUrl).to.equal('/_db/bananas/hi/friend/of/mine?hello=yes&goodbye=indeed');
|
expect(req.originalUrl).to.equal('/_db/bananas/hi/friend/of/mine?hello=yes&goodbye=indeed');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('url', function () {
|
describe('url', function () {
|
||||||
it('exposes the database relative URL of the native request', function () {
|
it('exposes the database relative URL of the native request', function () {
|
||||||
const rawReq = createNativeRequest({
|
const rawReq = createNativeRequest({
|
||||||
db: 'bananas',
|
db: 'bananas',
|
||||||
mount: '/hi',
|
mount: '/hi',
|
||||||
path: '/friend/of/mine',
|
path: '/friend/of/mine',
|
||||||
query: '?hello=yes&goodbye=indeed'
|
search: '?hello=yes&goodbye=indeed'
|
||||||
});
|
});
|
||||||
const req = new SyntheticRequest(rawReq, {});
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
expect(req.url).to.equal('/hi/friend/of/mine?hello=yes&goodbye=indeed');
|
expect(req.url).to.equal('/hi/friend/of/mine?hello=yes&goodbye=indeed');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('path', function () {
|
describe('path', function () {
|
||||||
it('exposes the database relative pathname of the native request', function () {
|
it('exposes the database relative pathname of the native request', function () {
|
||||||
const rawReq = createNativeRequest({
|
const rawReq = createNativeRequest({
|
||||||
db: 'bananas',
|
db: 'bananas',
|
||||||
mount: '/hi',
|
mount: '/hi',
|
||||||
path: '/friend/of/mine',
|
path: '/friend/of/mine',
|
||||||
query: '?hello=yes&goodbye=indeed'
|
search: '?hello=yes&goodbye=indeed'
|
||||||
});
|
});
|
||||||
const req = new SyntheticRequest(rawReq, {});
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
expect(req.path).to.equal('/hi/friend/of/mine');
|
expect(req.path).to.equal('/hi/friend/of/mine');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('suffix', function () {
|
describe('suffix', function () {
|
||||||
it('exposes the linearized suffix of the native request', function () {
|
it('exposes the linearized suffix of the native request', function () {
|
||||||
const rawReq = createNativeRequest({
|
const rawReq = createNativeRequest({
|
||||||
db: 'bananas',
|
db: 'bananas',
|
||||||
mount: '/hi',
|
mount: '/hi',
|
||||||
path: '/friend/of/mine',
|
path: '/friend/of/mine',
|
||||||
query: '?hello=yes&goodbye=indeed'
|
search: '?hello=yes&goodbye=indeed'
|
||||||
});
|
});
|
||||||
const req = new SyntheticRequest(rawReq, {});
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
expect(req.suffix).to.equal('friend/of/mine');
|
expect(req.suffix).to.equal('friend/of/mine');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('xhr', function () {
|
describe('xhr', function () {
|
||||||
it('is false if the XHR header was not set', function () {
|
it('is false if the XHR header was not set', function () {
|
||||||
const rawReq = createNativeRequest({});
|
const rawReq = createNativeRequest({});
|
||||||
|
@ -368,5 +363,434 @@ describe('SyntheticRequest', function () {
|
||||||
expect(req.xhr).to.equal(false);
|
expect(req.xhr).to.equal(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('TODO');
|
|
||||||
|
describe('cookie', function () {
|
||||||
|
it('returns nothing if the cookie is not set', function () {
|
||||||
|
const rawReq = createNativeRequest({});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.cookie('banana')).to.equal(undefined);
|
||||||
|
});
|
||||||
|
it('returns the value of the cookie if it is set', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
cookies: {banana: 'hello'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.cookie('banana')).to.equal('hello');
|
||||||
|
});
|
||||||
|
it('returns nothing if a secret is provided but no signature exists', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
cookies: {banana: 'hello'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.cookie('banana', {secret: 'potato'})).to.equal(undefined);
|
||||||
|
});
|
||||||
|
it('returns nothing if a secret is provided but the signature is invalid', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
cookies: {
|
||||||
|
banana: 'hello',
|
||||||
|
'banana.sig': 'invalid'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.cookie('banana', {secret: 'potato'})).to.equal(undefined);
|
||||||
|
});
|
||||||
|
it('returns the value if a secret is provided and the signature matches', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
cookies: {
|
||||||
|
banana: 'hello',
|
||||||
|
'banana.sig': crypto.hmac('potato', 'hello')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.cookie('banana', {secret: 'potato'})).to.equal('hello');
|
||||||
|
});
|
||||||
|
it('accepts a secret instead of an options object', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
cookies: {
|
||||||
|
banana: 'hello',
|
||||||
|
'banana.sig': crypto.hmac('potato', 'hello')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.cookie('banana', 'potato')).to.equal('hello');
|
||||||
|
});
|
||||||
|
it('correctly handles other algorithms', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
cookies: {
|
||||||
|
banana: 'hello',
|
||||||
|
'banana.sig': crypto.hmac('potato', 'hello', 'sha512')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.cookie('banana', {
|
||||||
|
secret: 'potato',
|
||||||
|
algorithm: 'sha512'
|
||||||
|
})).to.equal('hello');
|
||||||
|
});
|
||||||
|
it('correctly handles algorithm mismatches', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
cookies: {
|
||||||
|
banana: 'hello',
|
||||||
|
'banana.sig': crypto.hmac('potato', 'hello', 'sha256')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.cookie('banana', {
|
||||||
|
secret: 'potato',
|
||||||
|
algorithm: 'sha512'
|
||||||
|
})).to.equal(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('makeAbsolute', function () {
|
||||||
|
it('correctly generates absolute URLs', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
db: 'bananas',
|
||||||
|
mount: '/foxx',
|
||||||
|
headers: {host: 'www.example.com:9999'},
|
||||||
|
path: '/some/place/special',
|
||||||
|
search: '?a=1&b=2',
|
||||||
|
protocol: 'https'
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {mount: '/foxx'});
|
||||||
|
expect(req.makeAbsolute('/another/place', 'x=y&z=w')).to.equal(
|
||||||
|
'https://www.example.com:9999/_db/bananas/foxx/another/place?x=y&z=w'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('also accepts a query params object', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
db: 'bananas',
|
||||||
|
mount: '/foxx',
|
||||||
|
headers: {host: 'www.example.com:9999'},
|
||||||
|
path: '/some/place/special',
|
||||||
|
search: '?a=1&b=2',
|
||||||
|
protocol: 'https'
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {mount: '/foxx'});
|
||||||
|
expect(req.makeAbsolute('/another/place', {x: 'y', z: 'w'})).to.equal(
|
||||||
|
'https://www.example.com:9999/_db/bananas/foxx/another/place?x=y&z=w'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('omits the port if port is 80 and protocol is http', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
db: 'bananas',
|
||||||
|
mount: '/foxx',
|
||||||
|
headers: {host: 'www.example.com:80'},
|
||||||
|
path: '/some/place/special',
|
||||||
|
search: '?a=1&b=2',
|
||||||
|
protocol: 'http'
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {mount: '/foxx'});
|
||||||
|
expect(req.makeAbsolute('/another/place', 'x=y&z=w')).to.equal(
|
||||||
|
'http://www.example.com/_db/bananas/foxx/another/place?x=y&z=w'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('omits the port if port is 443 and protocol is https', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
db: 'bananas',
|
||||||
|
mount: '/foxx',
|
||||||
|
headers: {host: 'www.example.com:443'},
|
||||||
|
path: '/some/place/special',
|
||||||
|
search: '?a=1&b=2',
|
||||||
|
protocol: 'https'
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {mount: '/foxx'});
|
||||||
|
expect(req.makeAbsolute('/another/place', 'x=y&z=w')).to.equal(
|
||||||
|
'https://www.example.com/_db/bananas/foxx/another/place?x=y&z=w'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('works without query params', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
db: 'bananas',
|
||||||
|
mount: '/foxx',
|
||||||
|
headers: {host: 'www.example.com:9999'},
|
||||||
|
path: '/some/place/special',
|
||||||
|
search: '?a=1&b=2',
|
||||||
|
protocol: 'https'
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {mount: '/foxx'});
|
||||||
|
expect(req.makeAbsolute('/another/place')).to.equal(
|
||||||
|
'https://www.example.com:9999/_db/bananas/foxx/another/place'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('correctly handles non-root paths', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
db: 'bananas',
|
||||||
|
mount: '/foxx',
|
||||||
|
headers: {host: 'www.example.com:9999'},
|
||||||
|
path: '/some/place/special',
|
||||||
|
search: '?a=1&b=2',
|
||||||
|
protocol: 'https'
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {mount: '/foxx'});
|
||||||
|
expect(req.makeAbsolute('another/place')).to.equal(
|
||||||
|
'https://www.example.com:9999/_db/bananas/foxx/another/place'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it('correctly handles relative paths', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
db: 'bananas',
|
||||||
|
mount: '/foxx',
|
||||||
|
headers: {host: 'www.example.com:9999'},
|
||||||
|
path: '/some/place/special',
|
||||||
|
search: '?a=1&b=2',
|
||||||
|
protocol: 'https'
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {mount: '/foxx'});
|
||||||
|
expect(req.makeAbsolute('../another/place')).to.equal(
|
||||||
|
'https://www.example.com:9999/_db/bananas/another/place'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('accepts', function () {
|
||||||
|
it('returns the acceptable type', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {accept: 'application/json, text/javascript; q=0.01'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.accepts(['text/javascript'])).to.equal('text/javascript');
|
||||||
|
});
|
||||||
|
it('returns the preferred acceptable type', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {accept: 'application/json, text/javascript; q=0.01'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.accepts(['text/javascript', 'json'])).to.equal('json');
|
||||||
|
});
|
||||||
|
it('returns false if no type is acceptable', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {accept: 'application/json, text/javascript; q=0.01'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.accepts(['kitty/soft', 'kitty/warm'])).to.equal(false);
|
||||||
|
});
|
||||||
|
it('accepts multiple arguments instead of an array', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {accept: 'application/json, text/javascript; q=0.01'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.accepts('potato', 'json')).to.equal('json');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('acceptsCharsets', function () {
|
||||||
|
it('returns the acceptable charset', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-charset': 'utf-8, iso-8859-1; q=0.01'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsCharsets(['iso-8859-1'])).to.equal('iso-8859-1');
|
||||||
|
});
|
||||||
|
it('returns the preferred acceptable charset', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-charset': 'utf-8, iso-8859-1; q=0.01'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsCharsets(['iso-8859-1', 'utf-8'])).to.equal('utf-8');
|
||||||
|
});
|
||||||
|
it('returns false if no charset is acceptable', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-charset': 'utf-8, iso-8859-1; q=0.01'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsCharsets(['kitty-soft', 'kitty-warm'])).to.equal(false);
|
||||||
|
});
|
||||||
|
it('accepts multiple arguments instead of an array', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-charset': 'utf-8, iso-8859-1; q=0.01'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsCharsets('potato', 'utf-8')).to.equal('utf-8');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('acceptsEncodings', function () {
|
||||||
|
it('returns the acceptable encoding', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-encoding': 'gzip, deflate, sdch'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsEncodings(['deflate'])).to.equal('deflate');
|
||||||
|
});
|
||||||
|
it('returns the preferred acceptable encoding', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-encoding': 'gzip, deflate, sdch'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsEncodings(['deflate', 'gzip'])).to.equal('gzip');
|
||||||
|
});
|
||||||
|
it('returns false if no encoding is acceptable', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-encoding': 'gzip, deflate, sdch'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsEncodings(['softkitty', 'warmkitty'])).to.equal(false);
|
||||||
|
});
|
||||||
|
it('accepts multiple arguments instead of an array', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-encoding': 'gzip, deflate, sdch'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsEncodings('potato', 'gzip')).to.equal('gzip');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('acceptsLanguages', function () {
|
||||||
|
it('returns the acceptable language', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-language': 'en-GB,en;q=0.8,en-US;q=0.6,de;q=0.4,de-DE;q=0.2'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsLanguages(['de-DE'])).to.equal('de-DE');
|
||||||
|
});
|
||||||
|
it('returns the preferred acceptable language', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-language': 'en-GB,en;q=0.8,en-US;q=0.6,de;q=0.4,de-DE;q=0.2'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsLanguages(['de-DE', 'en-GB'])).to.equal('en-GB');
|
||||||
|
});
|
||||||
|
it('returns false if no language is acceptable', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-language': 'en-GB,en;q=0.8,en-US;q=0.6,de;q=0.4,de-DE;q=0.2'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsLanguages(['kitty-SOFT', 'kitty-WARM'])).to.equal(false);
|
||||||
|
});
|
||||||
|
it('accepts multiple arguments instead of an array', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'accept-language': 'en-GB,en;q=0.8,en-US;q=0.6,de;q=0.4,de-DE;q=0.2'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.acceptsLanguages('potato', 'en-GB')).to.equal('en-GB');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('range', function () {
|
||||||
|
it('returns -2 for malformed header', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {range: 'banana'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.range(Infinity)).to.equal(-2);
|
||||||
|
});
|
||||||
|
it('returns -1 for invalid header range', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {range: 'bananas=500-20'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.range(Infinity)).to.equal(-1);
|
||||||
|
});
|
||||||
|
it('parses single ranges', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {range: 'bananas=0-499'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
const range = req.range(Infinity);
|
||||||
|
expect(range).to.have.a.property('type', 'bananas');
|
||||||
|
expect(range).to.have.a.property('length', 1);
|
||||||
|
expect(range[0]).to.eql({start: 0, end: 499});
|
||||||
|
});
|
||||||
|
it('parses multiple ranges', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {range: 'bananas=0-499,500-749'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
const range = req.range(Infinity);
|
||||||
|
expect(range).to.have.a.property('type', 'bananas');
|
||||||
|
expect(range).to.have.a.property('length', 2);
|
||||||
|
expect(range[0]).to.eql({start: 0, end: 499});
|
||||||
|
expect(range[1]).to.eql({start: 500, end: 749});
|
||||||
|
});
|
||||||
|
it('caps end at size', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {range: 'bananas=0-999'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
const range = req.range(100);
|
||||||
|
expect(range).to.have.a.property('type', 'bananas');
|
||||||
|
expect(range).to.have.a.property('length', 1);
|
||||||
|
expect(range[0]).to.eql({start: 0, end: 99});
|
||||||
|
});
|
||||||
|
it('parses "-X"', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {range: 'bananas=-400'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
const range = req.range(1000);
|
||||||
|
expect(range).to.have.a.property('type', 'bananas');
|
||||||
|
expect(range).to.have.a.property('length', 1);
|
||||||
|
expect(range[0]).to.eql({start: 600, end: 999});
|
||||||
|
});
|
||||||
|
it('parses "X-"', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {range: 'bananas=400-'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
const range = req.range(1000);
|
||||||
|
expect(range).to.have.a.property('type', 'bananas');
|
||||||
|
expect(range).to.have.a.property('length', 1);
|
||||||
|
expect(range[0]).to.eql({start: 400, end: 999});
|
||||||
|
});
|
||||||
|
it('parses "0-"', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {range: 'bananas=0-'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
const range = req.range(1000);
|
||||||
|
expect(range).to.have.a.property('type', 'bananas');
|
||||||
|
expect(range).to.have.a.property('length', 1);
|
||||||
|
expect(range[0]).to.eql({start: 0, end: 999});
|
||||||
|
});
|
||||||
|
it('parses "-1"', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {range: 'bananas=-1'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
const range = req.range(1000);
|
||||||
|
expect(range).to.have.a.property('type', 'bananas');
|
||||||
|
expect(range).to.have.a.property('length', 1);
|
||||||
|
expect(range[0]).to.eql({start: 999, end: 999});
|
||||||
|
});
|
||||||
|
it('parses "0-0"', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {range: 'bananas=0-0'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
const range = req.range(Infinity);
|
||||||
|
expect(range).to.have.a.property('type', 'bananas');
|
||||||
|
expect(range).to.have.a.property('length', 1);
|
||||||
|
expect(range[0]).to.eql({start: 0, end: 0});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('is', function () {
|
||||||
|
it('returns false if no content-type is set', function () {
|
||||||
|
const rawReq = createNativeRequest({});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.is(['application/xhtml+xml', 'text/html'])).to.equal(false);
|
||||||
|
});
|
||||||
|
it('returns the first matching mime type', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'content-type': 'text/html; charset=utf-8'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.is(['application/xhtml+xml', 'text/html'])).to.equal('text/html');
|
||||||
|
});
|
||||||
|
it('returns false if no mime type matches', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'content-type': 'text/html; charset=utf-8'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.is(['application/xhtml+xml'])).to.equal(false);
|
||||||
|
});
|
||||||
|
it('accepts multiple arguments instead of an array', function () {
|
||||||
|
const rawReq = createNativeRequest({
|
||||||
|
headers: {'content-type': 'text/html; charset=utf-8'}
|
||||||
|
});
|
||||||
|
const req = new SyntheticRequest(rawReq, {});
|
||||||
|
expect(req.is('application/xhtml+xml', 'text/html')).to.equal('text/html');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue