mirror of
https://github.com/scratchfoundation/restify-cors-middleware.git
synced 2024-12-18 11:52:26 -05:00
Pre-process origin matchers for better performance (regexes created once only)
This commit is contained in:
parent
97a01584c3
commit
9a388d0168
5 changed files with 48 additions and 29 deletions
|
@ -1,13 +1,14 @@
|
||||||
var origin = require('./origin.js')
|
var originMatcher = require('./origin-matcher.js')
|
||||||
var constants = require('./constants.js')
|
var constants = require('./constants.js')
|
||||||
|
|
||||||
exports.handler = function (options) {
|
exports.handler = function (options) {
|
||||||
|
var matcher = originMatcher.create(options.origins)
|
||||||
return function (req, res, next) {
|
return function (req, res, next) {
|
||||||
var originHeader = req.headers['origin']
|
var originHeader = req.headers['origin']
|
||||||
|
|
||||||
// If either no origin was set, or the origin isn't supported, continue
|
// If either no origin was set, or the origin isn't supported, continue
|
||||||
// without setting any headers
|
// without setting any headers
|
||||||
if (!originHeader || !origin.allowed(options.origins || [], originHeader)) {
|
if (!originHeader || !matcher(originHeader)) {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
24
src/origin-matcher.js
Normal file
24
src/origin-matcher.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
exports.create = function (allowedOrigins) {
|
||||||
|
// pre-compile list of matchers, so regexes are only built once
|
||||||
|
var matchers = allowedOrigins.map(createMatcher)
|
||||||
|
// does a given request Origin match the list?
|
||||||
|
return function (requestOrigin) {
|
||||||
|
if (requestOrigin) {
|
||||||
|
return matchers.some(matcher => matcher(requestOrigin))
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMatcher (allowedOrigin) {
|
||||||
|
if (allowedOrigin.indexOf('*') === -1) {
|
||||||
|
// simple string comparison
|
||||||
|
return requestOrigin => requestOrigin === allowedOrigin
|
||||||
|
} else {
|
||||||
|
// need to build a regex
|
||||||
|
var regex = '^' + allowedOrigin.replace('.', '\\.').replace('*', '.*') + '$'
|
||||||
|
return requestOrigin => requestOrigin.match(regex)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
|
|
||||||
exports.allowed = function (list, requestOrigin) {
|
|
||||||
function match (origin) {
|
|
||||||
if (origin.indexOf('*') !== -1) {
|
|
||||||
var regex = '^' + origin.replace('.', '\\.').replace('*', '.*') + '$'
|
|
||||||
return requestOrigin.match(regex)
|
|
||||||
} else {
|
|
||||||
return requestOrigin === origin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (requestOrigin) {
|
|
||||||
return list.some(match)
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,14 @@
|
||||||
var origin = require('./origin')
|
var originMatcher = require('./origin-matcher')
|
||||||
var constants = require('./constants.js')
|
var constants = require('./constants.js')
|
||||||
|
|
||||||
exports.handler = function (options) {
|
exports.handler = function (options) {
|
||||||
|
var matcher = originMatcher.create(options.origins)
|
||||||
return function (req, res, next) {
|
return function (req, res, next) {
|
||||||
if (req.method !== 'OPTIONS') return next()
|
if (req.method !== 'OPTIONS') return next()
|
||||||
|
|
||||||
// 6.2.1 and 6.2.2
|
// 6.2.1 and 6.2.2
|
||||||
var originHeader = req.headers['origin']
|
var originHeader = req.headers['origin']
|
||||||
if (origin.allowed(options.origins, originHeader) === false) return next()
|
if (!matcher(originHeader)) return next()
|
||||||
|
|
||||||
// 6.2.3
|
// 6.2.3
|
||||||
var requestedMethod = req.headers[constants['AC_REQ_METHOD']]
|
var requestedMethod = req.headers[constants['AC_REQ_METHOD']]
|
||||||
|
|
|
@ -1,46 +1,55 @@
|
||||||
/* eslint-env mocha */
|
/* eslint-env mocha */
|
||||||
require('should')
|
require('should')
|
||||||
var origin = require('../src/origin')
|
var originMatcher = require('../src/origin-matcher')
|
||||||
|
|
||||||
describe('Origin list', function () {
|
describe('Origin list', function () {
|
||||||
it('returns false if the request has no origin', function () {
|
it('returns false if the request has no origin', function () {
|
||||||
var list = ['http://api.myapp.com', 'http://www.myapp.com']
|
var list = ['http://api.myapp.com', 'http://www.myapp.com']
|
||||||
origin.allowed(list, null).should.eql(false)
|
var matcher = originMatcher.create(list)
|
||||||
|
matcher(null).should.eql(false)
|
||||||
|
matcher('').should.eql(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns false if the origin is not in the list', function () {
|
it('returns false if the origin is not in the list', function () {
|
||||||
var list = ['http://api.myapp.com', 'http://www.myapp.com']
|
var list = ['http://api.myapp.com', 'http://www.myapp.com']
|
||||||
origin.allowed(list, 'http://random-website.com').should.eql(false)
|
var matcher = originMatcher.create(list)
|
||||||
|
matcher('http://random-website.com').should.eql(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns true if the origin matched', function () {
|
it('returns true if the origin matched', function () {
|
||||||
var list = ['http://api.myapp.com', 'http://www.myapp.com']
|
var list = ['http://api.myapp.com', 'http://www.myapp.com']
|
||||||
origin.allowed(list, 'http://api.myapp.com').should.eql(true)
|
var matcher = originMatcher.create(list)
|
||||||
|
matcher('http://api.myapp.com').should.eql(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('does not do partial matches by default', function () {
|
it('does not do partial matches by default', function () {
|
||||||
var list = ['http://api.myapp.com', 'http://www.myapp.com']
|
var list = ['http://api.myapp.com', 'http://www.myapp.com']
|
||||||
origin.allowed(list, 'api.myapp.com').should.eql(false)
|
var matcher = originMatcher.create(list)
|
||||||
|
matcher('api.myapp.com').should.eql(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('always matches if the list contains *', function () {
|
it('always matches if the list contains *', function () {
|
||||||
var list = ['*']
|
var list = ['*']
|
||||||
origin.allowed(list, 'http://random-website.com').should.eql(true)
|
var matcher = originMatcher.create(list)
|
||||||
|
matcher('http://random-website.com').should.eql(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('supports * for partial matches', function () {
|
it('supports * for partial matches', function () {
|
||||||
var list = ['http://*.myapp.com', 'http://other-website.com']
|
var list = ['http://*.myapp.com', 'http://other-website.com']
|
||||||
origin.allowed(list, 'http://api.myapp.com').should.eql(true)
|
var matcher = originMatcher.create(list)
|
||||||
|
matcher('http://api.myapp.com').should.eql(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('escapes the partial regex properly', function () {
|
it('escapes the partial regex properly', function () {
|
||||||
// the "." should be a real dot, not mean "[any character]myapp"
|
// the "." should be a real dot, not mean "[any character]myapp"
|
||||||
var list = ['http://*.myapp.com', 'http://other-website.com']
|
var list = ['http://*.myapp.com', 'http://other-website.com']
|
||||||
origin.allowed(list, 'http://xmyapp.com').should.eql(false)
|
var matcher = originMatcher.create(list)
|
||||||
|
matcher('http://xmyapp.com').should.eql(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns false if there was no partial match', function () {
|
it('returns false if there was no partial match', function () {
|
||||||
var list = ['http://*.myapp.com']
|
var list = ['http://*.myapp.com']
|
||||||
origin.allowed(list, 'http://random-website.com').should.eql(false)
|
var matcher = originMatcher.create(list)
|
||||||
|
matcher('http://random-website.com').should.eql(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue