Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 35bd9e8
Showing
4 changed files
with
165 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
virtualhost | ||
=========== | ||
|
||
Make your HTTP server hostname-aware **very simply**. | ||
|
||
You define the handler for each server name, and that will return the final handler to be passed to your HTTP server. | ||
|
||
Works fine with Express. | ||
|
||
Installation | ||
------------ | ||
|
||
`npm install virtualhost` | ||
|
||
Usage | ||
----- | ||
|
||
```javascript | ||
var virtualhost = require('virtualhost'); | ||
var server = http.createServer(virtualhost(servers, catchAll)); | ||
``` | ||
|
||
* `servers` is a hash of server's configuration, each one having following options: | ||
* `pattern` can be a string (hostnames will simply be compared for equality), or a regular expression (you could use `/^hello\.(fr|com)$/i` for example to use this handler for `hello.fr` and `hello.com`, or `/\.domain.tld$/` to match all subdomains of `domain.tld`). Think about anchors (`^` and `$`) when using regular expression as pattern. | ||
* `handler` is a `function (req, res)`. Request matching pattern will simply be forwarded to this handler. | ||
* `with_port` will include the port in the comparison. Default comparison ignores it, which means `pattern: "domain.tld" will match `domain.tld:8080` and `domain.tld:3000` the same way. If you enable this option, you **have to** include port in your pattern. | ||
* `catchAll` is the default handler used when no server matched hostname. It's not mandatory, and defaults to a simple 404. | ||
|
||
### Shorter usage | ||
|
||
`servers` can also be a simple hash of the form `pattern: handler`. | ||
|
||
For example: | ||
|
||
```javascript | ||
virtualhost({ | ||
"one.mydomain.tld": function (req, res) {…}, | ||
"two.mydomain.tld": function (req, res) {…} | ||
}); | ||
``` | ||
|
||
is strictly equivalent to | ||
|
||
```javascript | ||
virtualhost({ | ||
"one.mydomain.tld": { | ||
pattern: "one.mydomain.tld", | ||
handler: function (req, res) {…} | ||
}, | ||
"two.mydomain.tld": { | ||
pattern: "two.mydomain.tld", | ||
handler: function (req, res) {…} | ||
} | ||
}); | ||
``` | ||
|
||
Of course you can mix both syntax. | ||
|
||
Sample usage | ||
------------ | ||
|
||
```javascript | ||
// Example of standard handler | ||
// This one will simply write "handler1" at "sub.domain.tld/*" | ||
var handler1 = function (req, res) { res.end('handler1') }; | ||
|
||
// Example of Express 3.x app | ||
// Good guy Express now simply returns standard handler, which makes this directly usable in virtualhost :) | ||
// This one will write "handler2 (www.)" at "www.domain.tld/" and "handler2 (undefined)" at "domain.tld/" | ||
var handler2 = express().get('/', function (req, res) { res.end('handler2 (' + req.virtualhost.match[1] + ')' }); | ||
|
||
// Example of virtualhost configuration | ||
var apps = { | ||
// Shortcut hostname→handler | ||
sub.domain.tld: handler1, | ||
// Full config with RegExp pattern | ||
express: { pattern: /^(www\.)?domain\.tld$/, handler: handler2 } | ||
}; | ||
|
||
http.createServer(virtualhost(apps)).listen(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"author": "Nicolas Chambrier <naholyr@gmail.com> (http://naholyr.fr)", | ||
"name": "virtualhost", | ||
"description": "Dispatch HTTP request to a handler depending on hostname", | ||
"version": "0.0.1", | ||
"homepage": "https://github.com/lmtm/node-virtualhost", | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/lmtm/node-virtualhost.git" | ||
}, | ||
"main": "virtualhost.js", | ||
"dependencies": {}, | ||
"devDependencies": {}, | ||
"optionalDependencies": {}, | ||
"engines": { | ||
"node": "*" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
|
||
var url = require('url'); | ||
|
||
module.exports = handler; | ||
|
||
function handler (servers, catchAll) { | ||
catchAll = catchAll || _catchAll; | ||
|
||
// Check catch-all | ||
if (typeof catchAll !== 'function') throw new Error('[virtualhost] Catch-all should be a valid callback'); | ||
// Check servers configuration | ||
for (var server in servers) { | ||
var conf = servers[server]; | ||
if (typeof conf === 'function') { | ||
// Direct function assignment | ||
servers[server] = { pattern: server, handler: conf }; | ||
} else if (typeof conf === 'object') { | ||
// Check options | ||
if (typeof conf.handler !== 'function') throw new Error('[virtualhost] Invalid configuration for server "' + server + '": "handler" should be a valid callback'); | ||
if (!conf.pattern || (typeof conf.pattern !== 'string' && !(conf.pattern instanceof RegExp))) throw new Error('[virtualhost] Invalid configuration for server"' + server + '": "pattern" should be a string or a RegExp'); | ||
} else { | ||
// Invalid type | ||
throw new Error('[virtualhost] Invalid configuration for server "' + server + '": object or function expected'); | ||
} | ||
} | ||
|
||
// Valid options, return meta-handler | ||
return function (req, res) { | ||
// Retrieve hostname | ||
var location = url.parse('http://' + req.headers.host); | ||
// Define "req.virtualhost" (can be used by user) | ||
req.virtualhost = { | ||
hostname: location.hostname || '', | ||
port: location.port, | ||
match: false | ||
}; | ||
// Browser available handlers and find the first one matching hostname | ||
for (var server in servers) { | ||
req.virtualhost.match = matchHost(req.virtualhost, servers[server]); | ||
if (req.virtualhost.match) { | ||
req.virtualhost.name = server; | ||
return servers[server].handler.call(this, req, res); | ||
} | ||
} | ||
// None found, fallback to catch-all | ||
req.virtualhost.match = null; | ||
return catchAll.call(this, req, res); | ||
}; | ||
} | ||
|
||
function matchHost (hostInfo, conf) { | ||
var pattern = conf.pattern; | ||
var host = hostInfo.hostname + (conf.with_port ? (':' + hostInfo.port) : ''); | ||
if (conf.pattern instanceof RegExp) { | ||
console.log(host, conf.pattern, host.match(conf.pattern)); | ||
return host.match(conf.pattern); | ||
} else { | ||
return host === conf.pattern; | ||
} | ||
} | ||
|
||
function _catchAll (req, res) { | ||
res.writeHead(404); | ||
res.end('Invalid host name'); | ||
} |