Commit cfe34a20 authored by Leo Iannacone's avatar Leo Iannacone

updated http-proxy - eventemitter3

parent 6a701184
......@@ -23,7 +23,7 @@ proxies and load balancers.
### Core Concept
A new proxy is created by calling `createProxyServer` and passing
an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L26-L39))
an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L34-L51))
```javascript
var httpProxy = require('http-proxy');
......@@ -283,6 +283,7 @@ If you are using the `proxyServer.listen` method, the following options are also
* **ssl**: object to be passed to https.createServer()
* **ws**: true/false, if you want to proxy websockets
* **xfwd**: true/false, adds x-forward headers
* **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies)
### Test
......
......@@ -16,7 +16,7 @@ Check the [README.md](https://github.com/nodejitsu/node-http-proxy/blob/caronte/
## Proxying
Web proying is done by calling the `.web()` method on a Proxy instance. You can check among some use cases in the [examples folder](https://github.com/nodejitsu/node-http-proxy/tree/caronte/examples/http)
Web proxying is done by calling the `.web()` method on a Proxy instance. You can check among some use cases in the [examples folder](https://github.com/nodejitsu/node-http-proxy/tree/caronte/examples/http)
```javascript
//
......
......@@ -8,13 +8,6 @@ var http = require('http'),
*/
module.exports = httpProxy.Server;
module.exports.createProxy = function(options) {
return {
web: httpProxy.createRightProxy('web')(options),
ws: httpProxy.createRightProxy('ws')(options)
};
}
/**
* Creates the proxy server.
*
......@@ -30,7 +23,9 @@ module.exports.createProxy = function(options) {
* @api public
*/
module.exports.createProxyServer = module.exports.createServer = function createProxyServer(options) {
module.exports.createProxyServer =
module.exports.createServer =
module.exports.createProxy = function createProxyServer(options) {
/*
* `options` is needed and it must have the following layout:
*
......@@ -42,6 +37,8 @@ module.exports.createProxyServer = module.exports.createServer = function create
* ws : <true/false, if you want to proxy websockets>
* xfwd : <true/false, adds x-forward headers>
* secure : <true/false, verify SSL certificate>
* toProxy: <true/false, explicitly specify if we are proxying to another proxy>
* localAddress : <Local interface string to bind for outgoing connections>
* }
*
* NOTE: `options.ws` and `options.ssl` are optional.
......
......@@ -44,7 +44,26 @@ common.setupOutgoing = function(outgoing, options, req, forward) {
outgoing.agent = options.agent || false;
outgoing.path = url.parse(req.url).path;
outgoing.localAddress = options.localAddress;
//
// Remark: If we are false and not upgrading, set the connection: close. This is the right thing to do
// as node core doesn't handle this COMPLETELY properly yet.
//
if (!outgoing.agent) {
outgoing.headers = outgoing.headers || {};
if (typeof outgoing.headers.connection !== 'string'
|| outgoing.headers.connection.toLowerCase() !== 'upgrade'
) { outgoing.headers.connection = 'close'; }
}
//
// Remark: Can we somehow not use url.parse as a perf optimization?
//
outgoing.path = !options.toProxy
? url.parse(req.url).path
: req.url;
return outgoing;
};
......@@ -75,7 +94,7 @@ common.setupSocket = function(socket) {
};
common.getPort = function(req) {
var res = req.headers.host.match(/:(\d+)/);
var res = req.headers.host ? req.headers.host.match(/:(\d+)/) : "";
return res ?
res[1] :
req.connection.pair ? '443' : '80' ;
......
......@@ -26,15 +26,10 @@ httpProxy.Server = ProxyServer;
*/
function createRightProxy(type) {
var webPasses = Object.keys(web).map(function(pass) {
return web[pass];
});
var wsPasses = Object.keys(ws).map(function(pass) {
return ws[pass];
});
return function(options) {
return function(req, res /*, [head], [opts] */) {
var passes = (type === 'ws') ? (this.wsPasses || wsPasses) : (this.webPasses || webPasses),
var passes = (type === 'ws') ? this.wsPasses : this.webPasses,
args = [].slice.call(arguments),
cntr = args.length - 1,
head, cbl;
......
......@@ -90,6 +90,11 @@ web_o = Object.keys(web_o).map(function(pass) {
*/
function stream(req, res, options, _, server, clb) {
// And we begin!
if (!clb) {
server.emit('start', req, res, options.target)
}
if(options.forward) {
// If forward enable, so just pipe the request
var forwardReq = (options.forward.protocol === 'https:' ? https : http).request(
......@@ -104,24 +109,40 @@ web_o = Object.keys(web_o).map(function(pass) {
common.setupOutgoing(options.ssl || {}, options, req)
);
// Ensure we abort proxy if request is aborted
req.on('aborted', function () {
proxyReq.abort();
});
// Handle errors on incoming request as well as it makes sense to
req.on('error', proxyError);
// Error Handler
proxyReq.on('error', function(err){
if(options.buffer) { options.buffer.destroy(); }
proxyReq.on('error', proxyError);
function proxyError (err){
if (clb) {
clb(err, req, res);
} else {
server.emit('error', err, req, res);
}
});
}
(options.buffer || req).pipe(proxyReq);
proxyReq.on('response', function(proxyRes) {
if(server) { server.emit('proxyRes', proxyRes); }
if(server) { server.emit('proxyRes', proxyRes, req, res); }
for(var i=0; i < web_o.length; i++) {
if(web_o[i](req, res, proxyRes)) { break; }
}
// Allow us to listen when the proxy has completed
proxyRes.on('end', function () {
if (!clb) {
server.emit('end', req, res, proxyRes);
}
})
proxyRes.pipe(res);
});
......
......@@ -40,6 +40,8 @@ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
, i;
if (1 === length) {
if (fn.__EE3_once) this.removeListener(event, fn);
switch (len) {
case 1:
fn.call(fn.__EE3_context || this);
......@@ -67,16 +69,14 @@ EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
fn.apply(fn.__EE3_context || this, args);
}
if (fn.__EE3_once) this.removeListener(event, fn);
} else {
for (i = 1, args = new Array(len -1); i < len; i++) {
args[i - 1] = arguments[i];
}
for (i = 0; i < length; fn = listeners[++i]) {
fn.apply(fn.__EE3_context || this, args);
if (fn.__EE3_once) this.removeListener(event, fn);
fn.apply(fn.__EE3_context || this, args);
}
}
......
{
"name": "eventemitter3",
"version": "0.1.1",
"version": "0.1.2",
"description": "EventEmitter3 focuses on performance while maintaining a Node.js AND browser compatible interface. This the source of the same EventEmitter that is used in Primus.",
"main": "index.js",
"scripts": {
......@@ -17,8 +17,12 @@
"Events",
"reactor",
"pub/sub",
"publish",
"subscribe",
"event",
"emitter"
"emitter",
"addListener",
"addEventListener"
],
"author": {
"name": "Arnout Kazemier"
......@@ -28,12 +32,16 @@
"url": "https://github.com/3rd-Eden/EventEmitter3/issues"
},
"devDependencies": {
"mocha": "1.13.x",
"mocha": "1.18.x",
"pre-commit": "0.0.x",
"chai": "1.8.x"
"chai": "1.9.x"
},
"readme": "# EventEmitter3\n\nEventEmitter3 is a faster alternative to EventEmitter2 and the build-in\nEventEmitter that ships within Node.js. It removes some features that you might\nnot need:\n\n- Domain support.\n- Thrown errors when there are no error listeners specified.\n- That a `newListener` event is emitted when an event is emitted.\n- No silly `setMaxListeners`.\n- No silly `listenerCount` function.. Just do `EventEmitter.listeners(event).length`\n\nAnd adds some features you want:\n\n- Emit events with a custom context without binding: `EE.on(event, fn, context)`\n which also works with once `EE.once(event, fn, context)`\n\nIt's a drop in replacement of your existing EventEmitters, but just faster. Free\nperformance, who wouldn't want that.\n\nThe source of the EventEmitter is compatible for browser usage, no fancy pancy\n`Array.isArray` stuff is used, it's just plain ol JavaScript that should even\nwork IE5 if you want to. This module currently serves it's use in\n[Primus](http://github.com/primus/primus)'s client file.\n\n## Installation\n\n```bash\n$ npm install --save eventemitter3\n```\nor as a [component](http://component.io)\n\n```bash\n$ component install eventemitter3\n```\n\nthen\n\n```js\nvar EventEmitter = require('eventemitter3');\n\n// or\n\nvar EventEmitter = require('eventemitter3').EventEmitter;\n```\n\nFor API methods see the official Node.js documentation: \n\nhttp://nodejs.org/api/events.html\n",
"readmeFilename": "README.md",
"_id": "eventemitter3@0.1.1",
"_from": "eventemitter3@*"
"_id": "eventemitter3@0.1.2",
"dist": {
"shasum": "82f49c44c217e6d8cf13be4be6af527f76fecc3b"
},
"_from": "eventemitter3@*",
"_resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-0.1.2.tgz"
}
......@@ -122,6 +122,20 @@ describe('EventEmitter', function tests() {
expect(calls).to.equal(1);
});
it('only emits once if emits are nested inside the listener', function () {
var e = new EventEmitter()
, calls = 0;
e.once('foo', function () {
calls++;
e.emit('foo');
});
e.emit('foo');
expect(e.listeners('foo').length).to.equal(0);
expect(calls).to.equal(1);
});
it('only emits once for multiple events', function () {
var e = new EventEmitter()
, multi = 0
......
This diff is collapsed.
......@@ -15,6 +15,7 @@ describe('lib/http-proxy/common.js', function () {
port : 'you',
},
headers: {'fizz': 'bang', 'overwritten':true},
localAddress: 'local.address',
},
{
method : 'i',
......@@ -34,6 +35,49 @@ describe('lib/http-proxy/common.js', function () {
expect(outgoing.headers.pro).to.eql('xy');
expect(outgoing.headers.fizz).to.eql('bang');
expect(outgoing.headers.overwritten).to.eql(true);
expect(outgoing.localAddress).to.eql('local.address');
});
it('should not override agentless upgrade header', function () {
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent: undefined,
target: {
host : 'hey',
hostname : 'how',
socketPath: 'are',
port : 'you',
},
headers: {'connection': 'upgrade'},
},
{
method : 'i',
url : 'am',
headers : {'pro':'xy','overwritten':false}
});
expect(outgoing.headers.connection).to.eql('upgrade');
});
it('should override agentless non-upgrade header to close', function () {
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent: undefined,
target: {
host : 'hey',
hostname : 'how',
socketPath: 'are',
port : 'you',
},
headers: {'connection': 'xyz'},
},
{
method : 'i',
url : 'am',
headers : {'pro':'xy','overwritten':false}
});
expect(outgoing.headers.connection).to.eql('close');
});
it('should set the agent to false if none is given', function () {
......
......@@ -127,4 +127,32 @@ describe('#createProxyServer.web() using own http server', function () {
method: 'GET',
}, function() {}).end();
});
it('should proxy the request and provide a proxyRes event with the request and response parameters', function(done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080'
});
function requestHandler(req, res) {
proxy.once('proxyRes', function (proxyRes, pReq, pRes) {
source.close();
proxyServer.close();
expect(pReq).to.be.equal(req);
expect(pRes).to.be.equal(res);
done();
});
proxy.web(req, res);
}
var proxyServer = http.createServer(requestHandler);
var source = http.createServer(function(req, res) {
res.end('Response');
});
proxyServer.listen('8084');
source.listen('8080');
http.request('http://127.0.0.1:8084', function() {}).end();
});
});
\ No newline at end of file
......@@ -159,6 +159,11 @@ describe('lib/http-proxy.js', function() {
timeout: 3
}).listen(ports.proxy);
proxy.on('error', function (e) {
expect(e).to.be.an(Error);
expect(e.code).to.be.eql('ECONNRESET');
});
var source = http.createServer(function(req, res) {
setTimeout(function () {
res.end('At this point the socket should be closed');
......
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