3 * Copyright(c) 2014 Jonathan Ong
4 * Copyright(c) 2014-2015 Douglas Christopher Wilson
15 module.exports = vhost
22 var asteriskRegExp = /\*/g
23 var asteriskReplace = '([^\.]+)'
24 var endAnchoredRegExp = /(?:^|[^\\])(?:\\\\)*\$$/
25 var escapeRegExp = /([.+?^=!:${}()|\[\]\/\\])/g
26 var escapeReplace = '\\$1'
29 * Create a vhost middleware.
31 * @param {string|RegExp} hostname
32 * @param {function} handle
37 function vhost(hostname, handle) {
39 throw new TypeError('argument hostname is required')
43 throw new TypeError('argument handle is required')
46 if (typeof handle !== 'function') {
47 throw new TypeError('argument handle must be a function')
50 // create regular expression for hostname
51 var regexp = hostregexp(hostname)
53 return function vhost(req, res, next) {
54 var vhostdata = vhostof(req, regexp)
64 handle(req, res, next)
69 * Get hostname of request.
76 function hostnameof(req) {
77 var host = req.headers.host
83 var offset = host[0] === '['
84 ? host.indexOf(']') + 1
86 var index = host.indexOf(':', offset)
89 ? host.substring(0, index)
94 * Determine if object is RegExp.
101 function isregexp(val) {
102 return Object.prototype.toString.call(val) === '[object RegExp]'
106 * Generate RegExp for given hostname value.
108 * @param (string|RegExp} val
112 function hostregexp(val) {
113 var source = !isregexp(val)
114 ? String(val).replace(escapeRegExp, escapeReplace).replace(asteriskRegExp, asteriskReplace)
117 // force leading anchor matching
118 if (source[0] !== '^') {
119 source = '^' + source
122 // force trailing anchor matching
123 if (!endAnchoredRegExp.test(source)) {
127 return new RegExp(source, 'i')
131 * Get the vhost data of the request for RegExp
133 * @param (object} req
134 * @param (RegExp} regexp
139 function vhostof(req, regexp) {
140 var host = req.headers.host
141 var hostname = hostnameof(req)
147 var match = regexp.exec(hostname)
153 var obj = Object.create(null)
156 obj.hostname = hostname
157 obj.length = match.length - 1
159 for (var i = 1; i < match.length; i++) {
160 obj[i - 1] = match[i]