├── .gitignore ├── .npmignore ├── .travis.yml ├── Makefile ├── README.md ├── index.js ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | 10 | # Packages # 11 | ############ 12 | # it's better to unpack these files and commit the raw source 13 | # git has its own built in compression methods 14 | *.7z 15 | *.dmg 16 | *.gz 17 | *.iso 18 | *.jar 19 | *.rar 20 | *.tar 21 | *.zip 22 | 23 | # Logs and databases # 24 | ###################### 25 | *.log 26 | *.sql 27 | *.sqlite 28 | 29 | # OS generated files # 30 | ###################### 31 | .DS_Store* 32 | ehthumbs.db 33 | Icon? 34 | Thumbs.db 35 | 36 | # Node.js # 37 | ########### 38 | lib-cov 39 | *.seed 40 | *.log 41 | *.csv 42 | *.dat 43 | *.out 44 | *.pid 45 | *.gz 46 | 47 | pids 48 | logs 49 | results 50 | 51 | node_modules 52 | npm-debug.log 53 | 54 | # Components # 55 | ############## 56 | 57 | /build 58 | /components 59 | 60 | # ImageMagick # 61 | ############### 62 | 63 | *.cache 64 | *.mpc 65 | 66 | # Other # 67 | ######### 68 | test/*.2 69 | test/*/*.2 70 | test/*.mp4 71 | test/images/originalSideways.jpg.2 -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test.js -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | node_js: 2 | - "0.8" 3 | - "0.10" 4 | - "0.11" 5 | language: node_js -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BIN = ./node_modules/.bin/ 2 | 3 | test: 4 | @${BIN}mocha \ 5 | --require should \ 6 | --reporter spec 7 | 8 | .PHONY: test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!CAUTION] 2 | > **This repository is archived and no longer actively maintained.** 3 | > 4 | > We are no longer accepting issues, feature requests, or pull requests. 5 | > For additional support or questions, please visit the [Express.js Discussions page](https://github.com/expressjs/express/discussions). 6 | 7 | 8 | # Virtual Hostess [![Build Status](https://travis-ci.org/expressjs/vhostess.png)](https://travis-ci.org/expressjs/vhostess) 9 | 10 | Virtual host sub-domain mapping. This is semi-extracted from [connect.vhost()](http://www.senchalabs.org/connect/vhost.html). 11 | 12 | This is different than connect's `vhost` as it sits between the HTTP server and any "apps" instead of being used within an app. 13 | 14 | ## Example 15 | 16 | ```js 17 | var koaApp = require('koa')() 18 | var expressApp = require('express')() 19 | var connectApp = require('connect')() 20 | 21 | var hostess = require('vhostess')() 22 | 23 | http.createServer(hostess).listen(3000) 24 | 25 | hostess.use('koa.app.com', koaApp.callback()) 26 | hostess.use('express.app.com', expressApp) 27 | hostess.use('connect.app.com', connectApp) 28 | hostess.use(function (req, res) { 29 | res.statusCode = 404 30 | res.setHeader('Content-Type', 'text/plain; charset=utf-8') 31 | res.end('subdomain needed') 32 | }) 33 | ``` 34 | 35 | ## API 36 | 37 | ### var hostess = Hostess() 38 | 39 | ```js 40 | var hostess = require('vhostess')() 41 | http.createServer(hostess).listen() 42 | ``` 43 | 44 | Returns a `(req, res)` function to be passed to `http.createServer()` or to `app.use()` in Connect/Express. 45 | 46 | ### hostess.use(hostname, fn) 47 | 48 | `hostname` such as `example.com`, `*.example.com`, etc. `fn` is a callback function with the signature `(req, res)`. 49 | 50 | Notes: 51 | 52 | - `next` is __not__ supported. 53 | - Mounting HTTP servers is __not__ supported either. 54 | - Order matters. 55 | 56 | ### hostess.use(fn) 57 | 58 | Default callback. You __must__ supply one, otherwise the server will throw. 59 | 60 | ## License 61 | 62 | The MIT License (MIT) 63 | 64 | Copyright (c) 2013 Jonathan Ong me@jongleberry.com 65 | 66 | Permission is hereby granted, free of charge, to any person obtaining a copy 67 | of this software and associated documentation files (the "Software"), to deal 68 | in the Software without restriction, including without limitation the rights 69 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 70 | copies of the Software, and to permit persons to whom the Software is 71 | furnished to do so, subject to the following conditions: 72 | 73 | The above copyright notice and this permission notice shall be included in 74 | all copies or substantial portions of the Software. 75 | 76 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 77 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 78 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 79 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 80 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 81 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 82 | THE SOFTWARE. 83 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | var ctx = this 3 | 4 | var stack = [] 5 | 6 | listener.use = function (hostname, fn) { 7 | if (typeof hostname === 'function') { 8 | stack.push([null, hostname, null]) 9 | } else { 10 | // i'm not sure what this does - taken from connect 11 | var regexp = new RegExp('^' + hostname.replace(/[^*\w]/g, '\\$&').replace(/[*]/g, '(?:.*?)') + '$', 'i'); 12 | stack.push([regexp, fn, hostname]) 13 | } 14 | 15 | return listener 16 | } 17 | 18 | return listener 19 | 20 | function listener(req, res) { 21 | var host = req.headers.host 22 | host = host ? host.split(':')[0] : false 23 | 24 | var match 25 | for (var i = 0; i < stack.length; i++) { 26 | match = stack[i] 27 | if (match[0] === null || (host && match[0].test(host))) 28 | return match[1].call(ctx, req, res) 29 | } 30 | 31 | throw new Error('no matched functions. you did something wrong!') 32 | } 33 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vhostess", 3 | "description": "virtual host sub-domain mapping", 4 | "version": "1.0.0", 5 | "author": { 6 | "name": "Jonathan Ong", 7 | "email": "me@jongleberry.com", 8 | "url": "http://jongleberry.com", 9 | "twitter": "https://twitter.com/jongleberry" 10 | }, 11 | "license": "MIT", 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/expressjs/vhostess.git" 15 | }, 16 | "bugs": { 17 | "mail": "me@jongleberry.com", 18 | "url": "https://github.com/expressjs/vhostess/issues" 19 | }, 20 | "devDependencies": { 21 | "mocha": "*", 22 | "should": "*" 23 | }, 24 | "scripts": { 25 | "test": "make test" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 2 | var assert = require('assert') 3 | 4 | var hostess = require('./') 5 | 6 | function req(host) { 7 | return { 8 | headers: { 9 | host: arguments.length ? host : '127.0.0.1:3000' 10 | } 11 | } 12 | } 13 | 14 | describe('Virtual Hostess', function () { 15 | describe('should route by host', function () { 16 | it('1', function (done) { 17 | hostess() 18 | .use('*.example.com', function () { 19 | throw new Error('boom') 20 | }) 21 | .use('example.com', function () { 22 | done() 23 | }) 24 | .use(function () { 25 | throw new Error('boom') 26 | })(req('example.com')) 27 | }) 28 | 29 | it('2', function (done) { 30 | hostess() 31 | .use('*.example.com', function () { 32 | done() 33 | }) 34 | .use('example.com', function () { 35 | throw new Error('boom') 36 | }) 37 | .use(function () { 38 | throw new Error('boom') 39 | })(req('asdf.example.com')) 40 | }) 41 | 42 | it('3', function (done) { 43 | hostess() 44 | .use('*.example.com', function () { 45 | done() 46 | }) 47 | .use('example.com', function () { 48 | throw new Error('boom') 49 | }) 50 | .use(function () { 51 | throw new Error('boom') 52 | })(req('asdf.asdfasdf.example.com:123123123')) 53 | }) 54 | 55 | it('4', function (done) { 56 | hostess() 57 | .use(function () { 58 | done() 59 | })(req('asdf.asdfasdf.example.com')) 60 | }) 61 | }) 62 | 63 | describe('when no default is set', function () { 64 | it('should throw', function () { 65 | assert.throws(function () { 66 | hostess()(req('example.com')) 67 | }) 68 | }) 69 | }) 70 | 71 | describe('when no host is set', function () { 72 | it('should default to hostless', function (done) { 73 | hostess() 74 | .use('*.example.com', function () { 75 | throw new Error('boom') 76 | }) 77 | .use('example.com', function () { 78 | throw new Error('boom') 79 | }) 80 | .use('*', function () { 81 | throw new Error('boom') 82 | }) 83 | .use(function () { 84 | done() 85 | })(req('')) 86 | }) 87 | }) 88 | }) --------------------------------------------------------------------------------