Commit f765f90e authored by indexzero's avatar indexzero

[api] Finalized the RoutingProxy API

parent 598fe2e3
......@@ -80,7 +80,7 @@ var HttpProxy = exports.HttpProxy = function (options) {
self[key].base = httpProxy._getBase(self[key]);
}
setupProxy('target')
setupProxy('target');
if (this.forward) {
setupProxy('forward');
}
......@@ -102,7 +102,7 @@ var HttpProxy = exports.HttpProxy = function (options) {
//
this.source = options.source || { host: 'localhost', port: 8000 };
this.source.https = this.source.https || options.https;
this.changeOrigin = options.changeOrigin || false;
this.changeOrigin = options.changeOrigin || false;
};
// Inherit from events.EventEmitter
......
/*
node-http-proxy.js: Lookup table for proxy targets in node.js
Copyright (c) 2010 Charlie Robbins
Copyright (c) 2010 Charlie Robbins
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
......@@ -29,7 +29,7 @@ var util = require('util'),
fs = require('fs');
//
// ### function ProxyTable (router, silent)
// ### function ProxyTable (router, silent)
// #### @router {Object} Object containing the host based routes
// #### @silent {Boolean} Value indicating whether we should suppress logs
// #### @hostnameOnly {Boolean} Value indicating if we should route based on __hostname string only__
......@@ -37,31 +37,34 @@ var util = require('util'),
// locations of proxy targets based on ServerRequest headers; specifically
// the HTTP host header.
//
var ProxyTable = exports.ProxyTable = function (router, silent, hostnameOnly) {
var ProxyTable = exports.ProxyTable = function (options) {
events.EventEmitter.call(this);
this.silent = typeof silent !== 'undefined' ? silent : true;
this.hostnameOnly = typeof hostnameOnly !== 'undefined' ? hostnameOnly : false;
if (typeof router === 'object') {
this.silent = options.silent || options.silent !== true;
this.hostnameOnly = options.hostnameOnly === true;
if (typeof options.router === 'object') {
//
// If we are passed an object literal setup
// the routes with RegExps from the router
// If we are passed an object literal setup
// the routes with RegExps from the router
//
this.setRoutes(router);
this.setRoutes(options.router);
}
else if (typeof router === 'string') {
else if (typeof options.router === 'string') {
//
// If we are passed a string then assume it is a
// If we are passed a string then assume it is a
// file path, parse that file and watch it for changes
//
var self = this;
this.routeFile = router;
this.setRoutes(JSON.parse(fs.readFileSync(router)).router);
this.routeFile = options.router;
this.setRoutes(JSON.parse(fs.readFileSync(options.router)).router);
fs.watchFile(this.routeFile, function () {
fs.readFile(self.routeFile, function (err, data) {
if (err) throw err;
if (err) {
self.emit('error', err);
}
self.setRoutes(JSON.parse(data).router);
self.emit('routes', self.hostnameOnly === false ? self.routes : self.router);
});
......@@ -78,17 +81,17 @@ var ProxyTable = exports.ProxyTable = function (router, silent, hostnameOnly) {
util.inherits(ProxyTable, events.EventEmitter);
//
// ### function setRoutes (router)
// ### function setRoutes (router)
// #### @router {Object} Object containing the host based routes
// Sets the host-based routes to be used by this instance.
// Sets the host-based routes to be used by this instance.
//
ProxyTable.prototype.setRoutes = function (router) {
if (!router) {
throw new Error('Cannot update ProxyTable routes without router.');
}
this.router = router;
if (this.hostnameOnly === false) {
var self = this;
this.routes = [];
......@@ -105,7 +108,7 @@ ProxyTable.prototype.setRoutes = function (router) {
};
//
// ### function getProxyLocation (req)
// ### function getProxyLocation (req)
// #### @req {ServerRequest} The incoming server request to get proxy information about.
// Returns the proxy location based on the HTTP Headers in the ServerRequest `req`
// available to this instance.
......@@ -114,14 +117,14 @@ ProxyTable.prototype.getProxyLocation = function (req) {
if (!req || !req.headers || !req.headers.host) {
return null;
}
var target = req.headers.host.split(':')[0];
if (this.hostnameOnly == true) {
if (this.router.hasOwnProperty(target)) {
var location = this.router[target].split(':'),
host = location[0],
port = location.length === 1 ? 80 : location[1];
return {
port: port,
host: host
......@@ -131,7 +134,9 @@ ProxyTable.prototype.getProxyLocation = function (req) {
else {
target += req.url;
for (var i in this.routes) {
var match, route = this.routes[i];
var route = this.routes[i],
match;
if (match = target.match(route.route)) {
var location = route.target.split(':'),
host = location[0],
......@@ -144,7 +149,7 @@ ProxyTable.prototype.getProxyLocation = function (req) {
}
}
}
return null;
};
......
/*
* routing-proxy.js: A routing proxy consuming a RoutingTable and multiple HttpProxy instances
*
* (C) 2011 Nodejitsu Inc.
* MIT LICENCE
*
*/
var events = require('events'),
util = require('util'),
HttpProxy = require('./http-proxy').HttpProxy,
......@@ -12,11 +20,15 @@ var events = require('events'),
//
var RoutingProxy = exports.RoutingProxy = function (options) {
events.EventEmitter.call(this);
var self = this;
options = options || {};
if (options.router) {
//
// TODO: Consume the RoutingTable for various things: `this.proxyTable`
//
this.proxyTable = new ProxyTable(options);
this.proxyTable.on('routes', function (routes) {
self.emit('routes', routes);
});
}
//
......@@ -24,6 +36,21 @@ var RoutingProxy = exports.RoutingProxy = function (options) {
// to `.proxyRequest()` and `.proxyWebSocketRequest()`.
//
this.proxies = {};
//
// Setup default target options (such as `https`).
//
this.target  = {};
this.target.https = options.target && options.target.https;
//
// Setup other default options to be used for instances of
// `HttpProxy` created by this `RoutingProxy` instance.
//
this.source = options.source || { host: 'localhost', port: 8000 };
this.https = this.source.https || options.https;
this.enable = options.enable;
this.forward = options.forward;
};
......@@ -39,7 +66,30 @@ util.inherits(RoutingProxy, events.EventEmitter);
// for the specified `options.host` and `options.port`.
//
RoutingProxy.prototype.add = function (options) {
var self = this,
key = this._getKey(options);
//
// TODO: Consume properties in `options` related to the `ProxyTable`.
//
options.target = options.target || {};
options.target.host = options.target.host || options.host;
options.target.port = options.target.port || options.port;
options.target.https = this.target && this.target.https ||
options.target && options.target.https ||
options.https;
//
// Setup options to pass-thru to the new `HttpProxy` instance
// for the specified `options.host` and `options.port` pair.
//
['https', 'enable', 'forward'].forEach(function (key) {
if (options[key] !== false && self[key]) {
options[key] = self[key];
}
});
this.proxies[key] = new HttpProxy(options);
};
//
......@@ -49,7 +99,7 @@ RoutingProxy.prototype.add = function (options) {
// for the specified `options.host` and `options.port` (if they exist).
//
RoutingProxy.prototype.remove = function (options) {
var key = this._getKey(options);
};
//
......@@ -129,8 +179,13 @@ RoutingProxy.prototype.proxyRequest = function (req, res, options) {
}
var key = options.host + ':' + options.port,
proxy = this.proxies[key] || this._addTarget(options);
proxy;
if (!this.proxies[key]) {
this.add(options);
}
proxy = this.proxies[key];
proxy.proxyRequest(req, res, options.buffer);
};
......@@ -161,7 +216,32 @@ RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, opti
}
var key = options.host + ':' + options.port,
proxy = this.proxies[key] || this._addTarget(options);
proxy;
if (!this.proxies[key]) {
this.add(options);
}
proxy = this.proxies[key];
proxy.proxyWebSocketRequest(req, socket, head, options.buffer);
};
\ No newline at end of file
};
//
// ### @private function _getKey (options)
// #### @options {Object} Options to extract the key from
// Ensures that the appropriate options are present in the `options`
// provided and responds with a string key representing the `host`, `port`
// combination contained within.
//
RoutingProxy.prototype._getKey = function (options) {
if (!options || ((!options.host || !options.port)
&& (!options.target || !options.target.host || !options.target.port))) {
throw new Error('options.host and options.port or options.target are required.');
return;
}
return [
options.host || options.target.host,
options.port || options.target.port
].join(':');
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment