pax_global_header00006660000000000000000000000064124002671750014516gustar00rootroot0000000000000052 comment=ca444a5351d7e499b8e2b5056163573cd6e671a1 vhost-3.0.0/000077500000000000000000000000001240026717500126615ustar00rootroot00000000000000vhost-3.0.0/.gitignore000066400000000000000000000000461240026717500146510ustar00rootroot00000000000000coverage/ node_modules/ npm-debug.log vhost-3.0.0/.travis.yml000066400000000000000000000003711240026717500147730ustar00rootroot00000000000000language: node_js node_js: - "0.8" - "0.10" - "0.11" matrix: allow_failures: - node_js: "0.11" fast_finish: true script: "npm run-script test-travis" after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls" vhost-3.0.0/HISTORY.md000066400000000000000000000010221240026717500143370ustar00rootroot000000000000003.0.0 / 2014-08-29 ================== * Remove support for sub-http servers; use the `handle` function 2.0.0 / 2014-06-08 ================== * Accept `RegExp` object for `hostname` * Provide `req.vhost` object * Remove old invocation of `server.onvhost` * String `hostname` with `*` behaves more like SSL certificates - Matches 1 or more characters instead of zero - No longer matches "." characters * Support IPv6 literal in `Host` header 1.0.0 / 2014-03-05 ================== * Genesis from `connect` vhost-3.0.0/LICENSE000066400000000000000000000021411240026717500136640ustar00rootroot00000000000000(The MIT License) Copyright (c) 2014 Jonathan Ong Copyright (c) 2014 Douglas Christopher Wilson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. vhost-3.0.0/README.md000066400000000000000000000067271240026717500141540ustar00rootroot00000000000000# vhost [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![Build Status][travis-image]][travis-url] [![Test Coverage][coveralls-image]][coveralls-url] [![Gratipay][gratipay-image]][gratipay-url] ## Install ```sh $ npm install vhost ``` ## API ```js var vhost = require('vhost') ``` ### vhost(hostname, server) Create a new middleware function to hand off request to `server` when the incoming host for the request matches `hostname`. `hostname` can be a string or a RegExp object. When `hostname` is a string it can contain `*` to match 1 or more characters in that section of the hostname. When `hostname` is a RegExp, it will be forced to case-insensitive (since hostnames are) and will be forced to match based on the start and end of the hostname. When host is matched and the request is sent down to a vhost handler, the `req.vhost` property will be populated with an object. This object will have numeric properties corresponding to each wildcard (or capture group if RegExp object provided) and the `hostname` that was matched. ```js // for match of "foo.bar.example.com:8080" against "*.*.example.com": req.vhost.host === 'foo.bar.example.com:8080' req.vhost.hostname === 'foo.bar.example.com' req.vhost.length === 2 req.vhost[0] === 'foo' req.vhost[1] === 'bar' ``` ## Examples ### using with connect for static serving ```js var connect = require('connect') var serveStatic = require('serve-static') var vhost = require('vhost') var mailapp = connect() // add middlewares to mailapp for mail.example.com // create app to serve static files on subdomain var staticapp = connect() staticapp.use(serveStatic('public')) // create main app var app = connect() // add vhost routing to main app for mail app.use(vhost('mail.example.com', mailapp)) // route static assets for "assets-*" subdomain to get // around max host connections limit on browsers app.use(vhost('assets-*.example.com', staticapp)) // add middlewares and main usage to app app.listen(3000) ``` ### using with connect for user subdomains ```js var connect = require('connect') var serveStatic = require('serve-static') var vhost = require('vhost') var mainapp = connect() // add middlewares to mainapp for the main web site // create app that will server user content from public/{username}/ var userapp = connect() userapp.use(function(req, res, next){ var username = req.vhost[0] // username is the "*" // pretend request was for /{username}/* for file serving req.originalUrl = req.url req.url = '/' + username + req.url next() }) userapp.use(serveStatic('public')) // create main app var app = connect() // add vhost routing for main app app.use(vhost('userpages.local', mainapp)) app.use(vhost('www.userpages.local', mainapp)) // listen on all subdomains for user pages app.use(vhost('*.userpages.local', userapp)) app.listen(3000) ``` ## License [MIT](LICENSE) [npm-image]: https://img.shields.io/npm/v/vhost.svg?style=flat [npm-url]: https://npmjs.org/package/vhost [travis-image]: https://img.shields.io/travis/expressjs/vhost.svg?style=flat [travis-url]: https://travis-ci.org/expressjs/vhost [coveralls-image]: https://img.shields.io/coveralls/expressjs/vhost.svg?style=flat [coveralls-url]: https://coveralls.io/r/expressjs/vhost [downloads-image]: https://img.shields.io/npm/dm/vhost.svg?style=flat [downloads-url]: https://npmjs.org/package/vhost [gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg?style=flat [gratipay-url]: https://gratipay.com/dougwilson/ vhost-3.0.0/index.js000066400000000000000000000047661240026717500143430ustar00rootroot00000000000000/*! * vhost * Copyright(c) 2014 Jonathan Ong * Copyright(c) 2014 Douglas Christopher Wilson * MIT Licensed */ /** * Create a vhost middleware. * * @param {string|RegExp} hostname * @param {function} handle * @return {Function} * @api public */ module.exports = function vhost(hostname, handle) { if (!hostname) { throw new TypeError('argument hostname is required') } if (!handle) { throw new TypeError('argument handle is required') } if (typeof handle !== 'function') { throw new TypeError('argument handle must be a function') } // create regular expression for hostname var regexp = hostregexp(hostname) return function vhost(req, res, next){ var vhostdata = vhostof(req, regexp) if (!vhostdata) { return next() } // populate req.vhost = vhostdata // handle handle(req, res, next) }; }; /** * Get hostname of request. * * @param (object} req * @return {string} * @api private */ function hostnameof(req){ var host = req.headers.host if (!host) { return } var offset = host[0] === '[' ? host.indexOf(']') + 1 : 0 var index = host.indexOf(':', offset) return index !== -1 ? host.substring(0, index) : host } /** * Determine if object is RegExp. * * @param (object} val * @return {boolean} * @api private */ function isregexp(val){ return Object.prototype.toString.call(val) === '[object RegExp]' } /** * Generate RegExp for given hostname value. * * @param (string|RegExp} val * @api private */ function hostregexp(val){ var source = !isregexp(val) ? String(val).replace(/([.+?^=!:${}()|\[\]\/\\])/g, '\\$1').replace(/\*/g, '([^\.]+)') : val.source // force leading anchor matching if (source[0] !== '^') { source = '^' + source } // force trailing anchor matching source = source.replace(/(\\*)(.)$/, function(s, b, c){ return c !== '$' || b.length % 2 === 1 ? s + '$' : s }) return new RegExp(source, 'i') } /** * Get the vhost data of the request for RegExp * * @param (object} req * @param (RegExp} regexp * @return {object} * @api private */ function vhostof(req, regexp){ var host = req.headers.host var hostname = hostnameof(req) if (!hostname) { return } var match = regexp.exec(hostname) if (!match) { return } var obj = Object.create(null) obj.host = host obj.hostname = hostname obj.length = match.length - 1 for (var i = 1; i < match.length; i++) { obj[i - 1] = match[i] } return obj } vhost-3.0.0/package.json000066400000000000000000000015151240026717500151510ustar00rootroot00000000000000{ "name": "vhost", "description": "virtual domain hosting", "version": "3.0.0", "author": "Jonathan Ong (http://jongleberry.com)", "contributors": [ "Douglas Christopher Wilson " ], "license": "MIT", "repository": "expressjs/vhost", "devDependencies": { "istanbul": "0.3.0", "mocha": "~1.21.4", "should": "~4.0.1", "supertest": "~0.13.0" }, "files": [ "LICENSE", "HISTORY.md", "index.js" ], "engines": { "node": ">= 0.8.0" }, "scripts": { "test": "mocha --reporter spec --bail --check-leaks test/", "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/", "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/" } } vhost-3.0.0/test/000077500000000000000000000000001240026717500136405ustar00rootroot00000000000000vhost-3.0.0/test/test.js000066400000000000000000000135611240026717500151630ustar00rootroot00000000000000 var http = require('http') var request = require('supertest') var should = require('should') var vhost = require('..') describe('vhost(hostname, server)', function(){ it('should route by Host', function(done){ var vhosts = [] vhosts.push(vhost('tobi.com', tobi)) vhosts.push(vhost('loki.com', loki)) var 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 ignore port in Host', function(done){ var 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){ var 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){ var vhosts = [] vhosts.push(vhost('tobi.com', tobi)) vhosts.push(vhost('loki.com', loki)) var app = createServer(vhosts) function tobi(req, res) { res.end('tobi') } function loki(req, res) { res.end('loki') } request(app.listen()) .get('/') .set('Host', 'ferrets.com') .expect(404, done) }) it('should 404 without Host header', function(done){ var vhosts = [] vhosts.push(vhost('tobi.com', tobi)) vhosts.push(vhost('loki.com', loki)) var app = createServer(vhosts) function tobi(req, res) { res.end('tobi') } function loki(req, res) { res.end('loki') } request(app.listen()) .get('/') .unset('Host') .expect(404, done) }) describe('arguments', function(){ describe('hostname', function(){ it('should be required', function(){ vhost.bind().should.throw(/hostname.*required/) }) it('should accept string', function(){ vhost.bind(null, 'loki.com', function(){}).should.not.throw() }) it('should accept RegExp', function(){ vhost.bind(null, /loki\.com/, function(){}).should.not.throw() }) }) describe('handle', function(){ it('should be required', function(){ vhost.bind(null, 'loki.com').should.throw(/handle.*required/) }) it('should accept function', function(){ vhost.bind(null, 'loki.com', function(){}).should.not.throw() }) it('should reject plain object', function(){ vhost.bind(null, 'loki.com', {}).should.throw(/handle.*function/) }) }) }) describe('with string hostname', function(){ it('should support wildcards', function(done){ var 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){ var 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){ var 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){ var 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){ var app = createServer('user-*.*.com', function(req, res){ var keys = Object.keys(req.vhost).sort() var 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){ var 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){ var vhosts = [] vhosts.push(vhost(/\.tobi$/, tobi)) vhosts.push(vhost(/^loki\./, loki)) var 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){ var app = createServer(/user-(bob|joe)\.([^\.]+)\.com/, function(req, res){ var keys = Object.keys(req.vhost).sort() var 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) { var vhosts = !Array.isArray(hostname) ? [vhost(hostname, server)] : hostname return http.createServer(function onRequest(req, res) { var index = 0 function next(err) { var vhost = vhosts[index++] if (!vhost || err) { res.statusCode = err ? (err.status || 500) : 404 res.end(err ? err.message : 'oops') return } vhost(req, res, next) } next() }) }