Commit d32ee068 authored by Leo Iannacone's avatar Leo Iannacone

added proxy

parent 97aa2744
node_modules
*.swp
cov
atest.js
notes
primus-proxy.js
tes.js
language: node_js
node_js:
- "0.10"
- "0.11"
notifications:
email:
- travis@nodejitsu.com
irc: "irc.freenode.org#nodejitsu"
script:
npm test
### v 1.0.0-alpha
- Complete refactor with new API
node-http-proxy
Copyright (c) Nodejitsu 2013
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.
\ No newline at end of file
<p align="center">
<img src="https://raw.github.com/nodejitsu/node-http-proxy/master/doc/logo.png"/>
</p>
node-http-proxy
=======
`node-http-proxy` is an HTTP programmable proxying library that supports
websockets. It is suitable for implementing components such as
proxies and load balancers.
### Build Status
<p align="center">
<a href="https://travis-ci.org/nodejitsu/node-http-proxy" target="_blank">
<img src="https://travis-ci.org/nodejitsu/node-http-proxy.png"/></a>&nbsp;&nbsp;
<a href="https://coveralls.io/r/nodejitsu/node-http-proxy" target="_blank">
<img src="https://coveralls.io/repos/nodejitsu/node-http-proxy/badge.png"/></a>
</p>
### Looking to Upgrade from 0.8.x ? Click [here](UPGRADING.md)
### 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))
```javascript
var httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer(options);
```
An object will be returned with four values:
* web `req, res, [options]` (used for proxying regular HTTP(S) requests)
* ws `req, socket, head, [options]` (used for proxying WS(S) requests)
* listen `port` (a function that wraps the object in a webserver, for your convenience)
Is it then possible to proxy requests by calling these functions
```javascript
require('http').createServer(function(req, res) {
proxy.web(req, res, { target: 'http://mytarget.com:8080' });
});
```
Errors can be listened on either using the Event Emitter API
```javascript
proxy.on('error', function(e) {
...
});
```
or using the callback API
```javascript
proxy.web(req, res, { target: 'http://mytarget.com:8080' }, function(e) { ... });
```
When a request is proxied it follows two different pipelines ([available here](lib/http-proxy/passes))
which apply transformations to both the `req` and `res` object.
The first pipeline (ingoing) is responsible for the creation and manipulation of the stream that connects your client to the target.
The second pipeline (outgoing) is responsible for the creation and manipulation of the stream that, from your target, returns data
to the client.
#### Setup a basic stand-alone proxy server
```js
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create your proxy server and set the target in the options.
//
httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000);
//
// Create your target server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9000);
```
#### Setup a stand-alone proxy server with custom server logic
This example show how you can proxy a request using your own HTTP server
and also you can put your own logic to handle the request.
```js
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a proxy server with custom application logic
//
var proxy = httpProxy.createProxyServer({});
//
// Create your custom server and just call `proxy.web()` to proxy
// a web request to the target passed in the options
// also you can use `proxy.ws()` to proxy a websockets request
//
var server = require('http').createServer(function(req, res) {
// You can define here your custom logic to handle the request
// and then proxy the request.
proxy.web(req, res, { target: 'http://127.0.0.1:5060' });
});
console.log("listening on port 5050")
server.listen(5050);
```
#### Setup a stand-alone proxy server with latency
```js
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a proxy server with latency
//
var proxy = httpProxy.createProxyServer();
//
// Create your server that make an operation that take a while
// and then proxy de request
//
http.createServer(function (req, res) {
// This simulate an operation that take 500ms in execute
setTimeout(function () {
proxy.web(req, res, {
target: 'http://localhost:9008'
});
}, 500);
}).listen(8008);
//
// Create your target server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9008);
```
#### Listening for proxy events
* `error`: The error event is emitted if the request to the target fail.
* `proxyRes`: This event is emitted if the request to the target got a response.
```js
var httpProxy = require('http-proxy');
// Error example
//
// Http Proxy Server with bad target
//
var proxy = httpProxy.createServer({
target:'http://localhost:9005'
});
proxy.listen(8005);
//
// Listen for the `error` event on `proxy`.
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong. And we are reporting a custom error message.');
});
//
// Listen for the `proxyRes` event on `proxy`.
//
proxy.on('proxyRes', function (res) {
console.log('RAW Response from the target', JSON.stringify(res.headers, true, 2));
});
```
#### Using HTTPS
You can activate the validation of a secure SSL certificate to the target connection (avoid self signed certs), just set `secure: true` in the options.
##### HTTPS -> HTTP
```js
//
// Create the HTTPS proxy server in front of a HTTP server
//
httpProxy.createServer({
target: {
host: 'localhost',
port: 9009
},
ssl: {
key: fs.readFileSync('valid-ssl-key.pem', 'utf8'),
cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8')
}
}).listen(8009);
```
##### HTTPS -> HTTPS
```js
//
// Create the proxy server listening on port 443
//
httpProxy.createServer({
ssl: {
key: fs.readFileSync('valid-ssl-key.pem', 'utf8'),
cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8')
},
target: 'https://localhost:9010',
secure: true // Depends on your needs, could be false.
}).listen(443);
```
#### Proxying WebSockets
You can activate the websocket support for the proxy using `ws:true` in the options.
```js
//
// Create a proxy server for websockets
//
httpProxy.createServer({
target: 'ws://localhost:9014',
ws: true
}).listen(8014);
```
Also you can proxy the websocket requests just calling the `ws(req, socket, head)` method.
```js
//
// Setup our server to proxy standard HTTP requests
//
var proxy = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 9015
}
});
var proxyServer = http.createServer(function (req, res) {
proxy.web(req, res);
});
//
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
proxyServer.listen(8015);
```
### Contributing and Issues
* Search on Google/Github
* If you can't find anything, open an issue
* If you feel comfortable about fixing the issue, fork the repo
* Commit to your local branch (which must be different from `master`)
* Submit your Pull Request (be sure to include tests and update documentation)
### Options
`httpProxy.createProxyServer` supports the following options:
* **target**: url string to be parsed with the url module
* **forward**: url string to be parsed with the url module
* **agent**: object to be passed to http(s).request (see Node's [https agent](http://nodejs.org/api/https.html#https_class_https_agent) and [http agent](http://nodejs.org/api/http.html#http_class_http_agent) objects)
* **secure**: true/false, if you want to verify the SSL Certs
If you are using the `proxyServer.listen` method, the following options are also applicable:
* **ssl**: object to be passed to https.createServer()
* **ws**: true/false, if you want to proxy websockets
* **xfwd**: true/false, adds x-forward headers
### Test
```
$ npm test
```
### Logo
Logo created by [Diego Pasquali](http://dribbble.com/diegopq)
### License
>The MIT License (MIT)
>
>Copyright (c) 2010 - 2013 Nodejitsu Inc.
>
>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.
Looking to upgrade from `http-proxy@0.x.x` to `http-proxy@1.0`? You've come to the right place!
`http-proxy@1.0` is a from-scratch implementation of `http-proxy` and, as such
brings some breaking changes to APIs.
## Server creation
Available through `.createServer()` or `.createProxyServer()`.
```javascript
httpProxy.createServer({
target:'http://localhost:9003'
}).listen(8003);
```
Check the [README.md](https://github.com/nodejitsu/node-http-proxy/blob/caronte/README.md) for a more detailed explanation of the parameters.
## 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)
```javascript
//
// Create a HTTP Proxy server with a HTTPS target
//
httpProxy.createProxyServer({
target: 'https://google.com',
agent : https.globalAgent,
headers: {
host: 'google.com'
}
}).listen(8011);
```
Websockets are proxied by the `.ws()` method. The [examples folder](https://github.com/nodejitsu/node-http-proxy/tree/caronte/examples/websocket) again provides a lot of useful snippets!
```javascript
var proxy = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 9015
}
});
var proxyServer = http.createServer(function (req, res) {
proxy.web(req, res);
});
//
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
```
## Error Handling
It is possible to listen globally on the `error` event on the server. In alternative, a
callback passed to `.web()` or `.ws()` as last parameter is also accepted.
```javascript
var proxy = httpProxy.createServer({
target:'http://localhost:9005'
});
//
// Tell the proxy to listen on port 8000
//
proxy.listen(8005);
//
// Listen for the `error` event on `proxy`.
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong. And we are reporting a custom error message.');
});
```
## Dropped
Since the API was rewritten to be extremely flexible we decided to drop some features
which were in the core and delegate them to eventual "userland" modules.
- Middleware API
- ProxyTable API
### Middleware API
The new API makes it really easy to implement code that behaves like the old Middleware API. You can check some examples [here](https://github.com/nodejitsu/node-http-proxy/tree/caronte/examples/middleware)
# Benchmarking `node-http-proxy`
The long-term goal of these scripts and documentation is to provide a consistent and well understood benchmarking process for `node-http-proxy` so that performance does not degrade over time. They were initially created to compare the performance of `v0.10.3` and `v1.0.0` (which was a significant rewrite).
## Pre-requisites
All benchmarking shall be done with [wrk](https://github.com/wg/wrk) which _is the same tool used for performance testing by the node.js core team._ **Make sure you have `wrk` installed before continuing**.
```
$ wrk
Usage: wrk <options> <url>
Options:
-c, --connections <n> Connections to keep open
-r, --requests <n> Total requests to make
-t, --threads <n> Number of threads to use
-H, --header <h> Add header to request
-v, --version Print version details
Numeric arguments may include a SI unit (2k, 2M, 2G)
```
## Benchmarks
1. [Simple HTTP benchmark](#simple-http)
### Simple HTTP
_This benchmark requires three terminals running:_
1. **A proxy server:** `node benchmark/scripts/proxy.js`
2. **A target server:** `node benchmark/scripts/hello.js`
3. **A wrk process:** `wrk -c 20 -r 10000 -t 2 http://127.0.0.1:8000`
\ No newline at end of file
require('http').createServer(function(req, res) {
res.end('Hello world!');
}).listen(9000);
\ No newline at end of file
var http = require('http'),
httpProxy = require('../../');
//
// Create your proxy server
//
httpProxy.createProxyServer({ target: 'http://localhost:9000' }).listen(8000);
\ No newline at end of file
var crypto = require('crypto'),
WebSocket = require('ws'),
async = require('async'),
httpProxy = require('../../');
var SERVER_PORT = 8415,
PROXY_PORT = 8514;
var testSets = [
{
size: 1024 * 1024, // 1 MB
count: 128 // 128 MB
},
{
size: 1024, // 1 KB,
count: 1024 // 1 MB
},
{
size: 128, // 128 B
count: 1024 * 8 // 1 MB
}
];
testSets.forEach(function (set) {
set.buffer = new Buffer(crypto.randomBytes(set.size));
set.buffers = [];
for (var i = 0; i < set.count; i++) {
set.buffers.push(set.buffer);
}
});
function runSet(set, callback) {
function runAgainst(port, callback) {
function send(sock) {
sock.send(set.buffers[got++]);
if (got === set.count) {
t = new Date() - t;
server.close();
proxy.close();
callback(null, t);
}
}
var server = new WebSocket.Server({ port: SERVER_PORT }),
proxy = httpProxy.createServer(SERVER_PORT, 'localhost').listen(PROXY_PORT),
client = new WebSocket('ws://localhost:' + port),
got = 0,
t = new Date();
server.on('connection', function (ws) {
send(ws);
ws.on('message', function (msg) {
send(ws);
});
});
client.on('message', function () {
send(client);
});
}
async.series({
server: async.apply(runAgainst, SERVER_PORT),
proxy: async.apply(runAgainst, PROXY_PORT)
}, function (err, results) {
if (err) {
throw err;
}
var mb = (set.size * set.count) / (1024 * 1024);
console.log(set.size / (1024) + ' KB * ' + set.count + ' (' + mb + ' MB)');
Object.keys(results).forEach(function (key) {
var t = results[key],
throughput = mb / (t / 1000);
console.log(' ' + key + ' took ' + t + ' ms (' + throughput + ' MB/s)');
});
callback();
});
}
async.forEachLimit(testSets, 1, runSet);
/*
simple-balancer.js: Example of a simple round robin balancer for websockets
Copyright (c) Nodejitsu 2013
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.
*/
var http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// A simple round-robin load balancing strategy.
//
// First, list the servers you want to use in your rotation.
//
var addresses = [
{
host: 'ws1.0.0.0',
port: 80
},
{
host: 'ws2.0.0.0',
port: 80
}
];
//
// Create a HttpProxy object for each target
//
var proxies = addresses.map(function (target) {
return new httpProxy.createProxyServer({
target: target
});
});
//
// Get the proxy at the front of the array, put it at the end and return it
// If you want a fancier balancer, put your code here
//
function nextProxy() {
var proxy = proxies.shift();
proxies.push(proxy);
return proxy;
}
//
// Get the 'next' proxy and send the http request
//
var server = http.createServer(function (req, res) {
nextProxy().web(req, res);
});
//
// Get the 'next' proxy and send the upgrade request
//
server.on('upgrade', function (req, socket, head) {
nextProxy().ws(req, socket, head);
});
server.listen(8001);
\ No newline at end of file
/*
simple-balancer.js: Example of a simple round robin balancer
Copyright (c) Nodejitsu 2013
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.
*/
var http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// A simple round-robin load balancing strategy.
//
// First, list the servers you want to use in your rotation.
//
var addresses = [
{
host: 'ws1.0.0.0',
port: 80
},
{
host: 'ws2.0.0.0',
port: 80
}
];
var proxy = httpProxy.createServer();
http.createServer(function (req, res) {
//
// On each request, get the first location from the list...
//
var target = { target: addresses.shift() };
//
// ...then proxy to the server whose 'turn' it is...
//
console.log('balancing request to: ', target);
proxy.web(req, res, target);
//
// ...and then the server you just used becomes the last item in the list.
//
addresses.push(target);
}).listen(8021);
// Rinse; repeat; enjoy.
\ No newline at end of file
//
// just to make these example a little bit interesting,
// make a little key value store with an http interface
// (see couchbd for a grown-up version of this)
//
// API:
// GET /
// retrive list of keys
//
// GET /[url]
// retrive object stored at [url]
// will respond with 404 if there is nothing stored at [url]
//
// POST /[url]
//
// JSON.parse the body and store it under [url]
// will respond 400 (bad request) if body is not valid json.
//
// TODO: cached map-reduce views and auto-magic sharding.
//
var Store = module.exports = function Store () {
this.store = {};
};
Store.prototype = {
get: function (key) {
return this.store[key]
},
set: function (key, value) {
return this.store[key] = value
},
handler:function () {
var store = this
return function (req, res) {
function send (obj, status) {
res.writeHead(200 || status,{'Content-Type': 'application/json'})
res.write(JSON.stringify(obj) + '\n')
res.end()
}
var url = req.url.split('?').shift()
if (url === '/') {
console.log('get index')
return send(Object.keys(store.store))
} else if (req.method == 'GET') {
var obj = store.get (url)
send(obj || {error: 'not_found', url: url}, obj ? 200 : 404)
} else {
//post: buffer body, and parse.
var body = '', obj
req.on('data', function (c) { body += c})
req.on('end', function (c) {
try {
obj = JSON.parse(body)
} catch (err) {
return send (err, 400)
}
store.set(url, obj)
send({ok: true})
})
}
}
}
}
/*
basic-proxy.js: Basic example of proxying over HTTP
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/http-proxy');
var welcome = [
'# # ##### ##### ##### ##### ##### #### # # # #',
'# # # # # # # # # # # # # # # # ',
'###### # # # # ##### # # # # # # ## # ',
'# # # # ##### ##### ##### # # ## # ',
'# # # # # # # # # # # # # ',
'# # # # # # # # #### # # # '
].join('\n');
util.puts(welcome.rainbow.bold);
//
// Basic Http Proxy Server
//
httpProxy.createServer({
target:'http://localhost:9003'
}).listen(8003);
//
// Target Http Server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9003);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8003'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9003 '.yellow);
/*
concurrent-proxy.js: check levelof concurrency through proxy.
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// Basic Http Proxy Server
//
httpProxy.createServer({
target:'http://localhost:9004'
}).listen(8004);
//
// Target Http Server
//
// to check apparent problems with concurrent connections
// make a server which only responds when there is a given nubmer on connections
//
var connections = [],
go;
http.createServer(function (req, res) {
connections.push(function () {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
});
process.stdout.write(connections.length + ', ');
if (connections.length > 110 || go) {
go = true;
while (connections.length) {
connections.shift()();
}
}
}).listen(9004);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8004'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9004 '.yellow);
/*
custom-proxy-error.js: Example of using the custom `proxyError` event.
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// Http Proxy Server with bad target
//
var proxy = httpProxy.createServer({
target:'http://localhost:9005'
});
//
// Tell the proxy to listen on port 8000
//
proxy.listen(8005);
//
// Listen for the `error` event on `proxy`.
proxy.on('error', function (err, req, res) {
res.writeHead(500, {
'Content-Type': 'text/plain'
});
res.end('Something went wrong. And we are reporting a custom error message.');
});
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8005 '.yellow + 'with custom error message'.magenta.underline);
\ No newline at end of file
/*
error-handling.js: Example of handle erros for HTTP and WebSockets
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// HTTP Proxy Server
//
var proxy = httpProxy.createProxyServer({target:'http://localhost:9000', ws:true});
//
// Example of error handling
//
function requestHandler(req, res) {
// Pass a callback to the web proxy method
// and catch the error there.
proxy.web(req, res, function (err) {
// Now you can get the err
// and handle it by your self
// if (err) throw err;
res.writeHead(502);
res.end("There was an error proxying your request");
});
// In a websocket request case
req.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head, function (err) {
// Now you can get the err
// and handle it by your self
// if (err) throw err;
socket.close();
})
})
}
http.createServer(requestHandler).listen(8000);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow);
/*
forward-and-target-proxy.js: Example of proxying over HTTP with additional forward proxy
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// Setup proxy server with forwarding
//
httpProxy.createServer({
target: {
port: 9006,
host: 'localhost'
},
forward: {
port: 9007,
host: 'localhost'
}
}).listen(8006);
//
// Target Http Server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9006);
//
// Target Http Forwarding Server
//
http.createServer(function (req, res) {
util.puts('Receiving forward for: ' + req.url);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully forwarded to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9007);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8006 '.yellow + 'with forward proxy'.magenta.underline);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9006 '.yellow);
util.puts('http forward server '.blue + 'started '.green.bold + 'on port '.blue + '9007 '.yellow);
\ No newline at end of file
/*
forward-proxy.js: Example of proxying over HTTP with additional forward proxy
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// Setup proxy server with forwarding
//
httpProxy.createServer({
forward: {
port: 9019,
host: 'localhost'
}
}).listen(8019);
//
// Target Http Forwarding Server
//
http.createServer(function (req, res) {
util.puts('Receiving forward for: ' + req.url);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully forwarded to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9019);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8019 '.yellow + 'with forward proxy'.magenta.underline);
util.puts('http forward server '.blue + 'started '.green.bold + 'on port '.blue + '9019 '.yellow);
\ No newline at end of file
/*
latent-proxy.js: Example of proxying over HTTP with latency
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// Http Proxy Server with Latency
//
var proxy = httpProxy.createProxyServer();
http.createServer(function (req, res) {
setTimeout(function () {
proxy.web(req, res, {
target: 'http://localhost:9008'
});
}, 500);
}).listen(8008);
//
// Target Http Server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9008);
util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8008 '.yellow + 'with latency'.magenta.underline);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9008 '.yellow);
/*
proxy-http-to-https.js: Basic example of proxying over HTTP to a target HTTPS server
Copyright (c) Nodejitsu 2013
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.
*/
var https = require('https'),
http = require('http'),
util = require('util'),
path = require('path'),
fs = require('fs'),
colors = require('colors'),
httpProxy = require('../../lib/http-proxy');
//
// Create a HTTP Proxy server with a HTTPS target
//
httpProxy.createProxyServer({
target: 'https://google.com',
agent : https.globalAgent,
headers: {
host: 'google.com'
}
}).listen(8011);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8011'.yellow);
\ No newline at end of file
/*
proxy-https-to-http.js: Basic example of proxying over HTTPS to a target HTTP server
Copyright (c) Nodejitsu 2013
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.
*/
var https = require('https'),
http = require('http'),
util = require('util'),
path = require('path'),
fs = require('fs'),
colors = require('colors'),
httpProxy = require('../../lib/http-proxy'),
fixturesDir = path.join(__dirname, '..', '..', 'test', 'fixtures');
//
// Create the target HTTP server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('hello http over https\n');
res.end();
}).listen(9009);
//
// Create the HTTPS proxy server listening on port 8000
//
httpProxy.createServer({
target: {
host: 'localhost',
port: 9009
},
ssl: {
key: fs.readFileSync(path.join(fixturesDir, 'agent2-key.pem'), 'utf8'),
cert: fs.readFileSync(path.join(fixturesDir, 'agent2-cert.pem'), 'utf8')
}
}).listen(8009);
util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8009'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9009 '.yellow);
/*
proxy-https-to-https.js: Basic example of proxying over HTTPS to a target HTTPS server
Copyright (c) Nodejitsu 2013
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.
*/
var https = require('https'),
http = require('http'),
util = require('util'),
fs = require('fs'),
path = require('path'),
colors = require('colors'),
httpProxy = require('../../lib/http-proxy'),
fixturesDir = path.join(__dirname, '..', '..', 'test', 'fixtures'),
httpsOpts = {
key: fs.readFileSync(path.join(fixturesDir, 'agent2-key.pem'), 'utf8'),
cert: fs.readFileSync(path.join(fixturesDir, 'agent2-cert.pem'), 'utf8')
};
//
// Create the target HTTPS server
//
https.createServer(httpsOpts, function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('hello https\n');
res.end();
}).listen(9010);
//
// Create the proxy server listening on port 443
//
httpProxy.createServer({
ssl: httpsOpts,
target: 'https://localhost:9010',
secure: false
}).listen(8010);
util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8010'.yellow);
util.puts('https server '.blue + 'started '.green.bold + 'on port '.blue + '9010 '.yellow);
/*
standalone-proxy.js: Example of proxying over HTTP with a standalone HTTP server.
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
colors = require('colors'),
http = require('http'),
httpProxy = require('../../lib/http-proxy');
//
// Http Server with proxyRequest Handler and Latency
//
var proxy = new httpProxy.createProxyServer();
http.createServer(function (req, res) {
setTimeout(function () {
proxy.web(req, res, {
target: 'http://localhost:9002'
});
}, 200);
}).listen(8002);
//
// Target Http Server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9002);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8002 '.yellow + 'with proxy.web() handler'.cyan.underline + ' and latency'.magenta);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9001 '.yellow);
/*
bodyDecoder-middleware.js: Basic example of `connect.bodyParser()` middleware in node-http-proxy
Copyright (c) Nodejitsu 2013
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.
*/
var http = require('http'),
connect = require('connect'),
request = require('request'),
colors = require('colors'),
util = require('util'),
Store = require('../helpers/store'),
httpProxy = require('../../lib/http-proxy'),
proxy = httpProxy.createProxyServer({});
http.createServer(new Store().handler()).listen(7531, function () {
util.puts('http '.blue + 'greetings '.green + 'server'.blue + ' started '.green.bold + 'on port '.blue + '7531'.yellow);
//try these commands:
// get index:
// curl localhost:7531
// []
//
// get a doc:
// curl localhost:7531/foo
// {"error":"not_found"}
//
// post an doc:
// curl -X POST localhost:7531/foo -d '{"content": "hello", "type": "greeting"}'
// {"ok":true}
//
// get index (now, not empty)
// curl localhost:7531
// ["/foo"]
//
// get doc
// curl localhost:7531/foo
// {"content": "hello", "type": "greeting"}
//
// now, suppose we wanted to direct all objects where type == "greeting" to a different store
// than where type == "insult"
//
// we can use connect connect-bodyDecoder and some custom logic to send insults to another Store.
//insult server:
http.createServer(new Store().handler()).listen(2600, function () {
util.puts('http '.blue + 'insults '.red + 'server'.blue + ' started '.green.bold + 'on port '.blue + '2600'.yellow);
//greetings -> 7531, insults-> 2600
// now, start a proxy server.
//don't worry about incoming contont type
//bodyParser.parse[''] = JSON.parse
connect.createServer(
//refactor the body parser and re-streamer into a separate package
connect.bodyParser(),
//body parser absorbs the data and end events before passing control to the next
// middleware. if we want to proxy it, we'll need to re-emit these events after
//passing control to the middleware.
require('connect-restreamer')(),
function (req, res) {
//if your posting an obect which contains type: "insult"
//it will get redirected to port 2600.
//normal get requests will go to 7531 nad will not return insults.
var port = (req.body && req.body.type === 'insult' ? 2600 : 7531)
proxy.web(req, res, { target: { host: 'localhost', port: port }});
}
).listen(1337, function () {
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '1337'.yellow);
//bodyParser needs content-type set to application/json
//if we use request, it will set automatically if we use the 'json:' field.
function post (greeting, type) {
request.post({
url: 'http://localhost:1337/' + greeting,
json: {content: greeting, type: type || "greeting"}
})
}
post("hello")
post("g'day")
post("kiora")
post("houdy")
post("java", "insult")
//now, the insult should have been proxied to 2600
//curl localhost:2600
//["/java"]
//but the greetings will be sent to 7531
//curl localhost:7531
//["/hello","/g%27day","/kiora","/houdy"]
})
})
});
\ No newline at end of file
/*
gzip-middleware.js: Basic example of `connect-gzip` middleware in node-http-proxy
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
colors = require('colors'),
http = require('http'),
connect = require('connect')
httpProxy = require('../../lib/http-proxy');
//
// Basic Connect App
//
connect.createServer(
connect.compress({
// Pass to connect.compress() the options
// that you need, just for show the example
// we use threshold to 1
threshold: 1
}),
function (req, res) {
proxy.web(req, res);
}
).listen(8012);
//
// Basic Http Proxy Server
//
var proxy = httpProxy.createProxyServer({
target: 'http://localhost:9012'
});
//
// Target Http Server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
res.end();
}).listen(9012);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8012'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9012 '.yellow);
/*
modifyBody-middleware.js: Example of middleware which modifies response
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
colors = require('colors'),
http = require('http'),
connect = require('connect'),
httpProxy = require('../../lib/http-proxy');
//
// Basic Connect App
//
connect.createServer(
function (req, res, next) {
var _write = res.write;
res.write = function (data) {
_write.call(res, data.toString().replace("Ruby", "nodejitsu"));
}
next();
},
function (req, res) {
proxy.web(req, res);
}
).listen(8013);
//
// Basic Http Proxy Server
//
var proxy = httpProxy.createProxyServer({
target: 'http://localhost:9013'
});
//
// Target Http Server
//
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, I know Ruby\n');
}).listen(9013);
util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8013'.yellow);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9013 '.yellow);
{
"name": "http-proxy-examples",
"description": "packages required to run the examples",
"version": "0.0.0",
"dependencies": {
"colors": "~0.6.2",
"socket.io": "~0.9.16",
"socket.io-client": "~0.9.16",
"connect": "~2.11.0",
"request": "~2.27.0",
"connect-restreamer": "~1.0.0"
}
}
/*
standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server.
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
http = require('http'),
colors = require('colors'),
httpProxy = require('../../lib/http-proxy');
try {
var io = require('socket.io'),
client = require('socket.io-client');
}
catch (ex) {
console.error('Socket.io is required for this example:');
console.error('npm ' + 'install'.green);
process.exit(1);
}
//
// Create the target HTTP server and setup
// socket.io on it.
//
var server = io.listen(9016);
server.sockets.on('connection', function (client) {
util.debug('Got websocket connection');
client.on('message', function (msg) {
util.debug('Got message from client: ' + msg);
});
client.send('from server');
});
//
// Setup our server to proxy standard HTTP requests
//
var proxy = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 9016
}
});
var proxyServer = http.createServer(function (req, res) {
proxy.web(req, res);
});
//
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
setTimeout(function () {
proxy.ws(req, socket, head);
}, 1000);
});
proxyServer.listen(8016);
//
// Setup the socket.io client against our proxy
//
var ws = client.connect('ws://localhost:8016');
ws.on('message', function (msg) {
util.debug('Got message: ' + msg);
ws.send('I am the client');
});
/*
standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server.
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
http = require('http'),
colors = require('colors'),
httpProxy = require('../../lib/http-proxy');
try {
var io = require('socket.io'),
client = require('socket.io-client');
}
catch (ex) {
console.error('Socket.io is required for this example:');
console.error('npm ' + 'install'.green);
process.exit(1);
}
//
// Create the target HTTP server and setup
// socket.io on it.
//
var server = io.listen(9015);
server.sockets.on('connection', function (client) {
util.debug('Got websocket connection');
client.on('message', function (msg) {
util.debug('Got message from client: ' + msg);
});
client.send('from server');
});
//
// Setup our server to proxy standard HTTP requests
//
var proxy = new httpProxy.createProxyServer({
target: {
host: 'localhost',
port: 9015
}
});
var proxyServer = http.createServer(function (req, res) {
proxy.web(req, res);
});
//
// Listen to the `upgrade` event and proxy the
// WebSocket requests as well.
//
proxyServer.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
proxyServer.listen(8015);
//
// Setup the socket.io client against our proxy
//
var ws = client.connect('ws://localhost:8015');
ws.on('message', function (msg) {
util.debug('Got message: ' + msg);
ws.send('I am the client');
});
/*
web-socket-proxy.js: Example of proxying over HTTP and WebSockets.
Copyright (c) Nodejitsu 2013
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.
*/
var util = require('util'),
http = require('http'),
colors = require('colors'),
httpProxy = require('../../lib/http-proxy');
try {
var io = require('socket.io'),
client = require('socket.io-client');
}
catch (ex) {
console.error('Socket.io is required for this example:');
console.error('npm ' + 'install'.green);
process.exit(1);
}
//
// Create the target HTTP server and setup
// socket.io on it.
//
var server = io.listen(9014);
server.sockets.on('connection', function (client) {
util.debug('Got websocket connection');
client.on('message', function (msg) {
util.debug('Got message from client: ' + msg);
});
client.send('from server');
});
//
// Create a proxy server with node-http-proxy
//
httpProxy.createServer({ target: 'ws://localhost:9014', ws: true }).listen(8014);
//
// Setup the socket.io client against our proxy
//
var ws = client.connect('ws://localhost:8014');
ws.on('message', function (msg) {
util.debug('Got message: ' + msg);
ws.send('I am the client');
});
/*!
* Caron dimonio, con occhi di bragia
* loro accennando, tutte le raccoglie;
* batte col remo qualunque s’adagia
*
* Charon the demon, with the eyes of glede,
* Beckoning to them, collects them all together,
* Beats with his oar whoever lags behind
*
* Dante - The Divine Comedy (Canto III)
*/
module.exports = require('./lib/http-proxy');
\ No newline at end of file
var http = require('http'),
https = require('https'),
url = require('url'),
httpProxy = require('./http-proxy/');
/**
* Export the the proxy "Server" as the main export
*/
module.exports = httpProxy.Server;
module.exports.createProxy = function(options) {
return {
web: httpProxy.createRightProxy('web')(options),
ws: httpProxy.createRightProxy('ws')(options)
};
}
/**
* Creates the proxy server.
*
* Examples:
*
* httpProxy.createProxyServer({ .. }, 8000)
* // => '{ web: [Function], ws: [Function] ... }'
*
* @param {Object} Options Config object passed to the proxy
*
* @return {Object} Proxy Proxy object with handlers for `ws` and `web` requests
*
* @api public
*/
module.exports.createProxyServer = module.exports.createServer = function createProxyServer(options) {
/*
* `options` is needed and it must have the following layout:
*
* {
* target : <url string to be parsed with the url module>
* forward: <url string to be parsed with the url module>
* agent : <object to be passed to http(s).request>
* ssl : <object to be passed to https.createServer()>
* ws : <true/false, if you want to proxy websockets>
* xfwd : <true/false, adds x-forward headers>
* secure : <true/false, verify SSL certificate>
* }
*
* NOTE: `options.ws` and `options.ssl` are optional.
* `options.target and `options.forward` cannot be
* both missing
* }
*/
return new httpProxy.Server(options);
};
var common = exports,
url = require('url'),
extend = require('util')._extend;
/**
* Copies the right headers from `options` and `req` to
* `outgoing` which is then used to fire the proxied
* request.
*
* Examples:
*
* common.setupOutgoing(outgoing, options, req)
* // => { host: ..., hostname: ...}
*
* @param {Object} Outgoing Base object to be filled with required properties
* @param {Object} Options Config object passed to the proxy
* @param {ClientRequest} Req Request Object
* @param {String} Forward String to select forward or target
* @return {Object} Outgoing Object with all required properties set
*
* @api private
*/
common.setupOutgoing = function(outgoing, options, req, forward) {
outgoing.port = options[forward || 'target'].port ||
(~['https:', 'wss:'].indexOf(options[forward || 'target'].protocol) ? 443 : 80);
['host', 'hostname', 'socketPath'].forEach(
function(e) { outgoing[e] = options[forward || 'target'][e]; }
);
['method', 'headers'].forEach(
function(e) { outgoing[e] = req[e]; }
);
if (options.headers){
extend(outgoing.headers, options.headers);
}
if (options[forward || 'target'].protocol == 'https:') {
outgoing.rejectUnauthorized = (typeof options.secure === "undefined") ? true : options.secure;
}
outgoing.agent = options.agent || false;
outgoing.path = url.parse(req.url).path;
return outgoing;
};
/**
* Set the proper configuration for sockets,
* set no delay and set keep alive, also set
* the timeout to 0.
*
* Examples:
*
* common.setupSocket(socket)
* // => Socket
*
* @param {Socket} Socket instance to setup
* @return {Socket} Return the configured socket.
*
* @api private
*/
common.setupSocket = function(socket) {
socket.setTimeout(0);
socket.setNoDelay(true);
socket.setKeepAlive(true, 0);
return socket;
};
common.getPort = function(req) {
var res = req.headers.host.match(/:(\d+)/);
return res ?
res[1] :
req.connection.pair ? '443' : '80' ;
}
var httpProxy = exports,
extend = require('util')._extend,
parse_url = require('url').parse,
EE3 = require('eventemitter3').EventEmitter,
http = require('http'),
https = require('https'),
web = require('./passes/web-incoming'),
ws = require('./passes/ws-incoming');
httpProxy.Server = ProxyServer;
/**
* Returns a function that creates the loader for
* either `ws` or `web`'s passes.
*
* Examples:
*
* httpProxy.createRightProxy('ws')
* // => [Function]
*
* @param {String} Type Either 'ws' or 'web'
* @return {Function} Loader Function that when called returns an iterator for the right passes
*
* @api private
*/
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),
args = [].slice.call(arguments),
cntr = args.length - 1,
head, cbl;
/* optional args parse begin */
if(typeof args[cntr] === 'function') {
cbl = args[cntr];
cntr--;
}
if(
!(args[cntr] instanceof Buffer) &&
args[cntr] !== res
) {
//Copy global options
options = extend({}, options);
//Overwrite with request options
extend(options, args[cntr]);
cntr--;
}
if(args[cntr] instanceof Buffer) {
head = args[cntr];
}
/* optional args parse end */
['target', 'forward'].forEach(function(e) {
if (typeof options[e] === 'string')
options[e] = parse_url(options[e]);
});
if(typeof this.emit === 'undefined' && !cbl) { throw new Error("You need to pass a callback to handle errors") }
for(var i=0; i < passes.length; i++) {
/**
* Call of passes functions
* pass(req, res, options, head)
*
* In WebSockets case the `res` variable
* refer to the connection socket
* pass(req, socket, options, head)
*/
if(passes[i](req, res, options, head, cbl ? false : this, cbl)) { // passes can return a truthy value to halt the loop
break;
}
}
};
};
}
httpProxy.createRightProxy = createRightProxy;
function ProxyServer(options) {
EE3.call(this);
this.web = this.proxyRequest = createRightProxy('web')(options);
this.ws = this.proxyWebsocketRequest = createRightProxy('ws')(options);
this.options = options;
this.webPasses = Object.keys(web).map(function(pass) {
return web[pass];
});
this.wsPasses = Object.keys(ws).map(function(pass) {
return ws[pass];
});
this.on('error', this.onError.bind(this));
}
require('util').inherits(ProxyServer, EE3);
ProxyServer.prototype.onError = function (err) {
//
// Remark: Replicate node core behavior using EE3
// so we force people to handle their own errors
//
if(this.listeners('error').length === 1) {
throw err;
}
};
ProxyServer.prototype.listen = function(port, hostname) {
var self = this,
closure = function(req, res) { self.web(req, res); };
this._server = this.options.ssl ?
https.createServer(this.options.ssl, closure) :
http.createServer(closure);
if(this.options.ws) {
this._server.on('upgrade', function(req, socket, head) { self.ws(req, socket, head); });
}
this._server.listen(port, hostname);
return this;
};
ProxyServer.prototype.before = function(type, passName, callback) {
if (type !== 'ws' && type !== 'web') {
throw new Error('type must be `web` or `ws`');
}
var passes = (type === 'ws') ? this.wsPasses : this.webPasses,
i = false;
passes.forEach(function(v, idx) {
if(v.name === passName) i = idx;
})
if(!i) throw new Error('No such pass');
passes.splice(i, 0, callback);
};
ProxyServer.prototype.after = function(type, passName, callback) {
if (type !== 'ws' && type !== 'web') {
throw new Error('type must be `web` or `ws`');
}
var passes = (type === 'ws') ? this.wsPasses : this.webPasses,
i = false;
passes.forEach(function(v, idx) {
if(v.name === passName) i = idx;
})
if(!i) throw new Error('No such pass');
passes.splice(i++, 0, callback);
};
var http = require('http'),
https = require('https'),
web_o = require('./web-outgoing'),
common = require('../common'),
passes = exports;
web_o = Object.keys(web_o).map(function(pass) {
return web_o[pass];
});
/*!
* Array of passes.
*
* A `pass` is just a function that is executed on `req, res, options`
* so that you can easily add new checks while still keeping the base
* flexible.
*/
[ // <--
/**
* Sets `content-length` to '0' if request is of DELETE type.
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
function deleteLength(req, res, options) {
if(req.method === 'DELETE' && !req.headers['content-length']) {
req.headers['content-length'] = '0';
}
},
/**
* Sets timeout in request socket if it was specified in options.
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
function timeout(req, res, options) {
if(options.timeout) {
req.socket.setTimeout(options.timeout);
}
},
/**
* Sets `x-forwarded-*` headers if specified in config.
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
function XHeaders(req, res, options) {
if(!options.xfwd) return;
var values = {
for : req.connection.remoteAddress || req.socket.remoteAddress,
port : common.getPort(req),
proto: req.isSpdy ? 'https' : (req.connection.pair ? 'https' : 'http')
};
['for', 'port', 'proto'].forEach(function(header) {
req.headers['x-forwarded-' + header] =
(req.headers['x-forwarded-' + header] || '') +
(req.headers['x-forwarded-' + header] ? ',' : '') +
values[header];
});
},
/**
* Does the actual proxying. If `forward` is enabled fires up
* a ForwardStream, same happens for ProxyStream. The request
* just dies otherwise.
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
function stream(req, res, options, _, server, clb) {
if(options.forward) {
// If forward enable, so just pipe the request
var forwardReq = (options.forward.protocol === 'https:' ? https : http).request(
common.setupOutgoing(options.ssl || {}, options, req, 'forward')
);
(options.buffer || req).pipe(forwardReq);
if(!options.target) { return res.end(); }
}
// Request initalization
var proxyReq = (options.target.protocol === 'https:' ? https : http).request(
common.setupOutgoing(options.ssl || {}, options, req)
);
// Error Handler
proxyReq.on('error', function(err){
if(options.buffer) { options.buffer.destroy(); }
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); }
for(var i=0; i < web_o.length; i++) {
if(web_o[i](req, res, proxyRes)) { break; }
}
proxyRes.pipe(res);
});
//proxyReq.end();
}
] // <--
.forEach(function(func) {
passes[func.name] = func;
});
var passes = exports;
/*!
* Array of passes.
*
* A `pass` is just a function that is executed on `req, res, options`
* so that you can easily add new checks while still keeping the base
* flexible.
*/
[ // <--
/**
* If is a HTTP 1.0 request, remove chunk headers
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {proxyResponse} Res Response object from the proxy request
*
* @api private
*/
function removeChunked(req, res, proxyRes) {
if(req.httpVersion === '1.0') {
delete proxyRes.headers['transfer-encoding'];
}
},
/**
* If is a HTTP 1.0 request, set the correct connection header
* or if connection header not present, then use `keep-alive`
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {proxyResponse} Res Response object from the proxy request
*
* @api private
*/
function setConnection(req, res, proxyRes) {
if (req.httpVersion === '1.0') {
proxyRes.headers.connection = req.headers.connection || 'close';
} else if (!proxyRes.headers.connection) {
proxyRes.headers.connection = req.headers.connection || 'keep-alive';
}
},
/**
* Copy headers from proxyResponse to response
* set each header in response object.
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {proxyResponse} Res Response object from the proxy request
*
* @api private
*/
function writeHeaders(req, res, proxyRes) {
Object.keys(proxyRes.headers).forEach(function(key) {
res.setHeader(key, proxyRes.headers[key]);
});
},
/**
* Set the statusCode from the proxyResponse
*
* @param {ClientRequest} Req Request object
* @param {IncomingMessage} Res Response object
* @param {proxyResponse} Res Response object from the proxy request
*
* @api private
*/
function writeStatusCode(req, res, proxyRes) {
res.writeHead(proxyRes.statusCode);
}
] // <--
.forEach(function(func) {
passes[func.name] = func;
});
var http = require('http'),
https = require('https'),
common = require('../common'),
passes = exports;
/*!
* Array of passes.
*
* A `pass` is just a function that is executed on `req, socket, options`
* so that you can easily add new checks while still keeping the base
* flexible.
*/
/*
* Websockets Passes
*
*/
var passes = exports;
[
/**
* WebSocket requests must have the `GET` method and
* the `upgrade:websocket` header
*
* @param {ClientRequest} Req Request object
* @param {Socket} Websocket
*
* @api private
*/
function checkMethodAndHeader (req, socket) {
if (req.method !== 'GET' || !req.headers.upgrade) {
socket.destroy();
return true;
}
if (req.headers.upgrade.toLowerCase() !== 'websocket') {
socket.destroy();
return true;
}
},
/**
* Sets `x-forwarded-*` headers if specified in config.
*
* @param {ClientRequest} Req Request object
* @param {Socket} Websocket
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
function XHeaders(req, socket, options) {
if(!options.xfwd) return;
var values = {
for : req.connection.remoteAddress || req.socket.remoteAddress,
port : common.getPort(req),
proto: req.connection.pair ? 'wss' : 'ws'
};
['for', 'port', 'proto'].forEach(function(header) {
req.headers['x-forwarded-' + header] =
(req.headers['x-forwarded-' + header] || '') +
(req.headers['x-forwarded-' + header] ? ',' : '') +
values[header];
});
},
/**
* Does the actual proxying. Make the request and upgrade it
* send the Switching Protocols request and pipe the sockets.
*
* @param {ClientRequest} Req Request object
* @param {Socket} Websocket
* @param {Object} Options Config object passed to the proxy
*
* @api private
*/
function stream(req, socket, options, head, server, clb) {
common.setupSocket(socket);
if (head && head.length) socket.unshift(head);
var proxyReq = (~['https:', 'wss:'].indexOf(options.target.protocol) ? https : http).request(
common.setupOutgoing(options.ssl || {}, options, req)
);
// Error Handler
proxyReq.on('error', onOutgoingError);
proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) {
proxySocket.on('error', onOutgoingError);
// The pipe below will end proxySocket if socket closes cleanly, but not
// if it errors (eg, vanishes from the net and starts returning
// EHOSTUNREACH). We need to do that explicitly.
socket.on('error', function () {
proxySocket.end();
});
common.setupSocket(proxySocket);
if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead);
socket.write('HTTP/1.1 101 Switching Protocols\r\n');
socket.write(Object.keys(proxyRes.headers).map(function(i) {
return i + ": " + proxyRes.headers[i];
}).join('\r\n') + '\r\n\r\n');
proxySocket.pipe(socket).pipe(proxySocket);
});
return proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT
function onOutgoingError(err) {
if (clb) {
clb(err, req, socket);
} else {
server.emit('error', err, req, socket);
}
}
}
] // <--
.forEach(function(func) {
passes[func.name] = func;
});
node_modules
components
build
\ No newline at end of file
# EventEmitter3
EventEmitter3 is a faster alternative to EventEmitter2 and the build-in
EventEmitter that ships within Node.js. It removes some features that you might
not need:
- Domain support.
- Thrown errors when there are no error listeners specified.
- That a `newListener` event is emitted when an event is emitted.
- No silly `setMaxListeners`.
- No silly `listenerCount` function.. Just do `EventEmitter.listeners(event).length`
And adds some features you want:
- Emit events with a custom context without binding: `EE.on(event, fn, context)`
which also works with once `EE.once(event, fn, context)`
It's a drop in replacement of your existing EventEmitters, but just faster. Free
performance, who wouldn't want that.
The source of the EventEmitter is compatible for browser usage, no fancy pancy
`Array.isArray` stuff is used, it's just plain ol JavaScript that should even
work IE5 if you want to. This module currently serves it's use in
[Primus](http://github.com/primus/primus)'s client file.
## Installation
```bash
$ npm install --save eventemitter3
```
or as a [component](http://component.io)
```bash
$ component install eventemitter3
```
then
```js
var EventEmitter = require('eventemitter3');
// or
var EventEmitter = require('eventemitter3').EventEmitter;
```
For API methods see the official Node.js documentation:
http://nodejs.org/api/events.html
Starting benchmark run/context.js
```
log: Finished benchmarking: "EventEmitter 1"
metric: Count (40497), Cycles (6), Elapsed (5.549), Hz (705850.3082222337)
log: Finished benchmarking: "EventEmitter 2"
metric: Count (37623), Cycles (5), Elapsed (5.404), Hz (719593.0597690663)
log: Finished benchmarking: "EventEmitter 3"
metric: Count (207452), Cycles (5), Elapsed (5.507), Hz (3911957.3530642735)
info: Benchmark: "EventEmitter 3" is was the fastest.
```
Starting benchmark run/emit.js
```
log: Finished benchmarking: "EventEmitter 1"
metric: Count (151634), Cycles (6), Elapsed (5.564), Hz (2908003.5405639685)
log: Finished benchmarking: "EventEmitter 2"
metric: Count (151210), Cycles (7), Elapsed (5.512), Hz (2890645.6115476447)
log: Finished benchmarking: "EventEmitter 3"
metric: Count (205023), Cycles (6), Elapsed (5.462), Hz (3995844.1859591953)
info: Benchmark: "EventEmitter 3" is was the fastest.
```
Starting benchmark run/init.js
```
log: Finished benchmarking: "EventEmitter 1"
metric: Count (623645), Cycles (6), Elapsed (5.565), Hz (11872072.626655262)
log: Finished benchmarking: "EventEmitter 2"
metric: Count (676593), Cycles (4), Elapsed (5.443), Hz (12775701.999457106)
log: Finished benchmarking: "EventEmitter 3"
metric: Count (1085162), Cycles (4), Elapsed (5.461), Hz (20266525.23474324)
info: Benchmark: "EventEmitter 3" is was the fastest.
```
Starting benchmark run/listeners.js
```
log: Finished benchmarking: "EventEmitter 1"
metric: Count (24307), Cycles (3), Elapsed (102.393), Hz (1425.0454776644629)
log: Finished benchmarking: "EventEmitter 3"
metric: Count (4797), Cycles (3), Elapsed (7.401), Hz (5213.673529969181)
info: Benchmark: "EventEmitter 3,EventEmitter 1" is was the fastest.
```
Starting benchmark run/listening.js
```
log: Finished benchmarking: "EventEmitter 1"
metric: Count (41674), Cycles (5), Elapsed (5.473), Hz (769644.1995981695)
log: Finished benchmarking: "EventEmitter 2"
metric: Count (42409), Cycles (6), Elapsed (5.526), Hz (760905.7018658424)
log: Finished benchmarking: "EventEmitter 3"
metric: Count (299107), Cycles (6), Elapsed (5.536), Hz (5568540.252847456)
info: Benchmark: "EventEmitter 3" is was the fastest.
```
Starting benchmark run/multiple-emitters.js
```
log: Finished benchmarking: "EventEmitter 1"
metric: Count (30654), Cycles (7), Elapsed (5.548), Hz (587186.1069434296)
log: Finished benchmarking: "EventEmitter 2"
metric: Count (29149), Cycles (7), Elapsed (5.6), Hz (563374.1685091272)
log: Finished benchmarking: "EventEmitter 3"
metric: Count (42686), Cycles (5), Elapsed (5.527), Hz (813334.9427734262)
info: Benchmark: "EventEmitter 3" is was the fastest.
```
Starting benchmark run/once.js
```
log: Finished benchmarking: "EventEmitter 1"
metric: Count (31977), Cycles (5), Elapsed (5.548), Hz (595560.4093886568)
log: Finished benchmarking: "EventEmitter 2"
metric: Count (23246), Cycles (5), Elapsed (5.518), Hz (434307.42982924567)
log: Finished benchmarking: "EventEmitter 3"
metric: Count (216755), Cycles (5), Elapsed (5.514), Hz (4178956.0532713397)
info: Benchmark: "EventEmitter 3" is was the fastest.
```
'use strict';
var EventEmitter = require('../')
, ee = new EventEmitter();
ee.on('data', function (data) {
// hardcore number crunching
var amount = (data + data) - data * 2 / 2;
return amount;
});
//
// Benchmark configuration:
//
var NR_OF_RUNS = +process.env.NR_OF_RUNS || 50000
, i, dstart, dend, start, end;
//
// Make hot
//
//for (i = 0; i < NR_OF_RUNS; i++) {
// ee.emit('data', i, i, i, i, i, i, i);
// ee.emits('data', i, i, i, i, i, i, i);
//}
//
// The actual run of the optimized function
//
for (i = 0, dstart = process.hrtime(); i < NR_OF_RUNS; i++) {
ee.emit('data', i, i, i, i, i, i, i);
}
dend = process.hrtime(dstart);
for (i = 0, start = process.hrtime(); i < NR_OF_RUNS; i++) {
ee.emits('data', i, i, i, i, i, i, i);
}
end = process.hrtime(start);
console.log('Old: ', dend[1], 'nano sec spend doing', NR_OF_RUNS, 'runs in total');
console.log('New: ', end[1], 'nano sec spend doing', NR_OF_RUNS, 'runs in total');
console.log('new is ', dend[1] - end[1], 'nano sec faster');
{
"name": "benchmarks",
"version": "0.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "BSD",
"dependencies": {
"benchmark": "~1.0.0",
"devnull": "0.0.10",
"microtime": "~0.4.0",
"eventemitter2": "~0.4.13"
}
}
'use strict';
/**
* Benchmark related modules.
*/
var benchmark = require('benchmark')
, microtime = require('microtime');
/**
* Logger.
*/
var logger = new(require('devnull'))({ timestamp: false, namespacing: 0 });
/**
* Preparation code.
*/
var EventEmitter2 = require('eventemitter2').EventEmitter2
, EventEmitter3 = require('../../').EventEmitter
, EventEmitter1 = require('events').EventEmitter;
function handle() {
if (arguments.length > 100) console.log('damn');
}
/**
* Instances.
*/
var ee2 = new EventEmitter2()
, ee3 = new EventEmitter3()
, ee1 = new EventEmitter1();
ee3.on('foo', handle, logger);
ee2.on('foo', handle.bind(logger));
ee1.on('foo', handle.bind(logger));
(
new benchmark.Suite()
).add('EventEmitter 1', function test1() {
ee1.emit('foo');
ee1.emit('foo', 'bar');
ee1.emit('foo', 'bar', 'baz');
ee1.emit('foo', 'bar', 'baz', 'boom');
}).add('EventEmitter 2', function test2() {
ee2.emit('foo');
ee2.emit('foo', 'bar');
ee2.emit('foo', 'bar', 'baz');
ee2.emit('foo', 'bar', 'baz', 'boom');
}).add('EventEmitter 3', function test2() {
ee3.emit('foo');
ee3.emit('foo', 'bar');
ee3.emit('foo', 'bar', 'baz');
ee3.emit('foo', 'bar', 'baz', 'boom');
}).on('cycle', function cycle(e) {
var details = e.target;
logger.log('Finished benchmarking: "%s"', details.name);
logger.metric('Count (%d), Cycles (%d), Elapsed (%d), Hz (%d)'
, details.count
, details.cycles
, details.times.elapsed
, details.hz
);
}).on('complete', function completed() {
logger.info('Benchmark: "%s" is was the fastest.'
, this.filter('fastest').pluck('name')
);
}).run();
'use strict';
/**
* Benchmark related modules.
*/
var benchmark = require('benchmark')
, microtime = require('microtime');
/**
* Logger.
*/
var logger = new(require('devnull'))({ timestamp: false, namespacing: 0 });
/**
* Preparation code.
*/
var EventEmitter2 = require('eventemitter2').EventEmitter2
, EventEmitter3 = require('../../').EventEmitter
, EventEmitter1 = require('events').EventEmitter;
function handle() {
if (arguments.length > 100) console.log('damn');
}
/**
* Instances.
*/
var ee2 = new EventEmitter2()
, ee3 = new EventEmitter3()
, ee1 = new EventEmitter1();
ee3.on('foo', handle);
ee2.on('foo', handle);
ee1.on('foo', handle);
(
new benchmark.Suite()
).add('EventEmitter 1', function test1() {
ee1.emit('foo');
ee1.emit('foo', 'bar');
ee1.emit('foo', 'bar', 'baz');
ee1.emit('foo', 'bar', 'baz', 'boom');
}).add('EventEmitter 2', function test2() {
ee2.emit('foo');
ee2.emit('foo', 'bar');
ee2.emit('foo', 'bar', 'baz');
ee2.emit('foo', 'bar', 'baz', 'boom');
}).add('EventEmitter 3', function test2() {
ee3.emit('foo');
ee3.emit('foo', 'bar');
ee3.emit('foo', 'bar', 'baz');
ee3.emit('foo', 'bar', 'baz', 'boom');
}).on('cycle', function cycle(e) {
var details = e.target;
logger.log('Finished benchmarking: "%s"', details.name);
logger.metric('Count (%d), Cycles (%d), Elapsed (%d), Hz (%d)'
, details.count
, details.cycles
, details.times.elapsed
, details.hz
);
}).on('complete', function completed() {
logger.info('Benchmark: "%s" is was the fastest.'
, this.filter('fastest').pluck('name')
);
}).run();
'use strict';
/**
* Benchmark related modules.
*/
var benchmark = require('benchmark')
, microtime = require('microtime');
/**
* Logger.
*/
var logger = new(require('devnull'))({ timestamp: false, namespacing: 0 });
/**
* Preparation code.
*/
var EventEmitter2 = require('eventemitter2').EventEmitter2
, EventEmitter3 = require('../../').EventEmitter
, EventEmitter1 = require('events').EventEmitter;
(
new benchmark.Suite()
).add('EventEmitter 1', function test1() {
var ee = new EventEmitter1();
}).add('EventEmitter 2', function test2() {
var ee = new EventEmitter2();
}).add('EventEmitter 3', function test3() {
var ee = new EventEmitter3();
}).on('cycle', function cycle(e) {
var details = e.target;
logger.log('Finished benchmarking: "%s"', details.name);
logger.metric('Count (%d), Cycles (%d), Elapsed (%d), Hz (%d)'
, details.count
, details.cycles
, details.times.elapsed
, details.hz
);
}).on('complete', function completed() {
logger.info('Benchmark: "%s" is was the fastest.'
, this.filter('fastest').pluck('name')
);
}).run();
'use strict';
/**
* Benchmark related modules.
*/
var benchmark = require('benchmark')
, microtime = require('microtime');
/**
* Logger.
*/
var logger = new(require('devnull'))({ timestamp: false, namespacing: 0 });
/**
* Preparation code.
*/
var EventEmitter2 = require('eventemitter2').EventEmitter2
, EventEmitter3 = require('../../').EventEmitter
, EventEmitter1 = require('events').EventEmitter;
function handle() {
if (arguments.length > 100) console.log('damn');
}
/**
* Instances.
*/
var ee2 = new EventEmitter2()
, ee3 = new EventEmitter3()
, ee1 = new EventEmitter1();
ee1.setMaxListeners(Infinity);
ee2.setMaxListeners(Infinity);
(
new benchmark.Suite()
).add('EventEmitter 1', function test1() {
ee1.on('foo', handle);
ee1.listeners('foo');
//
// // EE2 doesn't correctly handle listeners as they can be removed by doing a
// // ee2.listeners('foo').length = 0; kills the event emitter
// }).add('EventEmitter 2', function test2() {
// ee2.on('foo', handle);
// ee2.listeners('foo');
//
}).add('EventEmitter 3', function test2() {
ee3.on('foo', handle);
ee3.listeners('foo');
}).on('cycle', function cycle(e) {
var details = e.target;
logger.log('Finished benchmarking: "%s"', details.name);
logger.metric('Count (%d), Cycles (%d), Elapsed (%d), Hz (%d)'
, details.count
, details.cycles
, details.times.elapsed
, details.hz
);
}).on('complete', function completed() {
logger.info('Benchmark: "%s" is was the fastest.'
, this.filter('fastest').pluck('name')
);
}).run();
'use strict';
/**
* Benchmark related modules.
*/
var benchmark = require('benchmark')
, microtime = require('microtime');
/**
* Logger.
*/
var logger = new(require('devnull'))({ timestamp: false, namespacing: 0 });
/**
* Preparation code.
*/
var EventEmitter2 = require('eventemitter2').EventEmitter2
, EventEmitter3 = require('../../').EventEmitter
, EventEmitter1 = require('events').EventEmitter;
function handle() {
if (arguments.length > 100) console.log('damn');
}
/**
* Instances.
*/
var ee2 = new EventEmitter2()
, ee3 = new EventEmitter3()
, ee1 = new EventEmitter1();
(
new benchmark.Suite()
).add('EventEmitter 1', function test1() {
ee1.on('foo', handle);
ee1.removeListener('foo', handle);
}).add('EventEmitter 2', function test2() {
ee2.on('foo', handle);
ee2.removeListener('foo', handle);
}).add('EventEmitter 3', function test2() {
ee3.on('foo', handle);
ee3.removeListener('foo', handle);
}).on('cycle', function cycle(e) {
var details = e.target;
logger.log('Finished benchmarking: "%s"', details.name);
logger.metric('Count (%d), Cycles (%d), Elapsed (%d), Hz (%d)'
, details.count
, details.cycles
, details.times.elapsed
, details.hz
);
}).on('complete', function completed() {
logger.info('Benchmark: "%s" is was the fastest.'
, this.filter('fastest').pluck('name')
);
}).run();
'use strict';
/**
* Benchmark related modules.
*/
var benchmark = require('benchmark')
, microtime = require('microtime');
/**
* Logger.
*/
var logger = new(require('devnull'))({ timestamp: false, namespacing: 0 });
/**
* Preparation code.
*/
var EventEmitter2 = require('eventemitter2').EventEmitter2
, EventEmitter3 = require('../../').EventEmitter
, EventEmitter1 = require('events').EventEmitter;
function foo() {
if (arguments.length > 100) console.log('damn');
return 1;
}
function bar() {
if (arguments.length > 100) console.log('damn');
return false;
}
function baz() {
if (arguments.length > 100) console.log('damn');
return true;
}
/**
* Instances.
*/
var ee2 = new EventEmitter2()
, ee3 = new EventEmitter3()
, ee1 = new EventEmitter1();
ee3.on('foo', foo).on('foo', bar).on('foo', baz);
ee2.on('foo', foo).on('foo', bar).on('foo', baz);
ee1.on('foo', foo).on('foo', bar).on('foo', baz);
(
new benchmark.Suite()
).add('EventEmitter 1', function test1() {
ee1.emit('foo');
ee1.emit('foo', 'bar');
ee1.emit('foo', 'bar', 'baz');
ee1.emit('foo', 'bar', 'baz', 'boom');
}).add('EventEmitter 2', function test2() {
ee2.emit('foo');
ee2.emit('foo', 'bar');
ee2.emit('foo', 'bar', 'baz');
ee2.emit('foo', 'bar', 'baz', 'boom');
}).add('EventEmitter 3', function test2() {
ee3.emit('foo');
ee3.emit('foo', 'bar');
ee3.emit('foo', 'bar', 'baz');
ee3.emit('foo', 'bar', 'baz', 'boom');
}).on('cycle', function cycle(e) {
var details = e.target;
logger.log('Finished benchmarking: "%s"', details.name);
logger.metric('Count (%d), Cycles (%d), Elapsed (%d), Hz (%d)'
, details.count
, details.cycles
, details.times.elapsed
, details.hz
);
}).on('complete', function completed() {
logger.info('Benchmark: "%s" is was the fastest.'
, this.filter('fastest').pluck('name')
);
}).run();
'use strict';
/**
* Benchmark related modules.
*/
var benchmark = require('benchmark')
, microtime = require('microtime');
/**
* Logger.
*/
var logger = new(require('devnull'))({ timestamp: false, namespacing: 0 });
/**
* Preparation code.
*/
var EventEmitter2 = require('eventemitter2').EventEmitter2
, EventEmitter3 = require('../../').EventEmitter
, EventEmitter1 = require('events').EventEmitter;
function handle() {
if (arguments.length > 100) console.log('damn');
}
/**
* Instances.
*/
var ee2 = new EventEmitter2()
, ee3 = new EventEmitter3()
, ee1 = new EventEmitter1();
(
new benchmark.Suite()
).add('EventEmitter 1', function test1() {
ee1.once('foo', handle);
ee1.emit('foo');
}).add('EventEmitter 2', function test2() {
ee2.once('foo', handle);
ee2.emit('foo');
}).add('EventEmitter 3', function test2() {
ee3.once('foo', handle);
ee3.emit('foo');
}).on('cycle', function cycle(e) {
var details = e.target;
logger.log('Finished benchmarking: "%s"', details.name);
logger.metric('Count (%d), Cycles (%d), Elapsed (%d), Hz (%d)'
, details.count
, details.cycles
, details.times.elapsed
, details.hz
);
}).on('complete', function completed() {
logger.info('Benchmark: "%s" is was the fastest.'
, this.filter('fastest').pluck('name')
);
}).run();
#!/bin/sh
for x in `find run -name '*.js'`
do
echo Starting benchmark $x
echo
node $x
echo
done
'use strict';
/**
* Benchmark related modules.
*/
var benchmark = require('benchmark')
, microtime = require('microtime');
/**
* Logger
*/
var logger = new(require('devnull'))({ timestamp: false, namespacing: 0 });
/**
* Preparation code.
*/
(
new benchmark.Suite()
).add('<test1>', function test1() {
}).add('<test2>', function test2() {
}).on('cycle', function cycle(e) {
var details = e.target;
logger.log('Finished benchmarking: "%s"', details.name);
logger.metric('Count (%d), Cycles (%d), Elapsed (%d), Hz (%d)'
, details.count
, details.cycles
, details.times.elapsed
, details.hz
);
}).on('complete', function completed() {
logger.info('Benchmark: "%s" is was the fastest.'
, this.filter('fastest').pluck('name')
);
}).run();
{
"name": "eventemitter3",
"version": "0.0.1",
"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.",
"repo": "3rd-Eden/EventEmitter3",
"main": "index.js",
"scripts": [
"index.js"
],
"license": "MIT"
}
\ No newline at end of file
'use strict';
/**
* Minimal EventEmitter interface that is molded against the Node.js
* EventEmitter interface.
*
* @constructor
* @api public
*/
function EventEmitter() {
this._events = {};
}
/**
* Return a list of assigned event listeners.
*
* @param {String} event The events that should be listed.
* @returns {Array}
* @api public
*/
EventEmitter.prototype.listeners = function listeners(event) {
return Array.apply(this, this._events[event] || []);
};
/**
* Emit an event to all registered event listeners.
*
* @param {String} event The name of the event.
* @returns {Boolean} Indication if we've emitted an event.
* @api public
*/
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
if (!this._events || !this._events[event]) return false;
var listeners = this._events[event]
, length = listeners.length
, len = arguments.length
, fn = listeners[0]
, args
, i;
if (1 === length) {
switch (len) {
case 1:
fn.call(fn.__EE3_context || this);
break;
case 2:
fn.call(fn.__EE3_context || this, a1);
break;
case 3:
fn.call(fn.__EE3_context || this, a1, a2);
break;
case 4:
fn.call(fn.__EE3_context || this, a1, a2, a3);
break;
case 5:
fn.call(fn.__EE3_context || this, a1, a2, a3, a4);
break;
case 6:
fn.call(fn.__EE3_context || this, a1, a2, a3, a4, a5);
break;
default:
for (i = 1, args = new Array(len -1); i < len; i++) {
args[i - 1] = arguments[i];
}
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);
}
}
return true;
};
/**
* Register a new EventListener for the given event.
*
* @param {String} event Name of the event.
* @param {Functon} fn Callback function.
* @param {Mixed} context The context of the function.
* @api public
*/
EventEmitter.prototype.on = function on(event, fn, context) {
if (!this._events) this._events = {};
if (!this._events[event]) this._events[event] = [];
fn.__EE3_context = context;
this._events[event].push(fn);
return this;
};
/**
* Add an EventListener that's only called once.
*
* @param {String} event Name of the event.
* @param {Function} fn Callback function.
* @param {Mixed} context The context of the function.
* @api public
*/
EventEmitter.prototype.once = function once(event, fn, context) {
fn.__EE3_once = true;
return this.on(event, fn, context);
};
/**
* Remove event listeners.
*
* @param {String} event The event we want to remove.
* @param {Function} fn The listener that we need to find.
* @api public
*/
EventEmitter.prototype.removeListener = function removeListener(event, fn) {
if (!this._events || !this._events[event]) return this;
var listeners = this._events[event]
, events = [];
for (var i = 0, length = listeners.length; i < length; i++) {
if (fn && listeners[i] !== fn) {
events.push(listeners[i]);
}
}
//
// Reset the array, or remove it completely if we have no more listeners.
//
if (events.length) this._events[event] = events;
else this._events[event] = null;
return this;
};
/**
* Remove all listeners or only the listeners for the specified event.
*
* @param {String} event The event want to remove all listeners for.
* @api public
*/
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
if (!this._events) return this;
if (event) this._events[event] = null;
else this._events = {};
return this;
};
//
// Alias methods names because people roll like that.
//
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
//
// This function doesn't apply anymore.
//
EventEmitter.prototype.setMaxListeners = function setMaxListeners() {
return this;
};
//
// Expose the module.
//
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.EventEmitter2 = EventEmitter;
EventEmitter.EventEmitter3 = EventEmitter;
try { module.exports = EventEmitter; }
catch (e) {}
{
"name": "eventemitter3",
"version": "0.1.1",
"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": {
"test": "NODE_ENV=testing ./node_modules/.bin/mocha $(find test -name '*.test.js')"
},
"repository": {
"type": "git",
"url": "git://github.com/3rd-Eden/EventEmitter3.git"
},
"keywords": [
"EventEmitter",
"EventEmitter2",
"EventEmitter3",
"Events",
"reactor",
"pub/sub",
"event",
"emitter"
],
"author": {
"name": "Arnout Kazemier"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/3rd-Eden/EventEmitter3/issues"
},
"devDependencies": {
"mocha": "1.13.x",
"pre-commit": "0.0.x",
"chai": "1.8.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@*"
}
'use strict';
describe('EventEmitter', function tests() {
var EventEmitter = require('../').EventEmitter
, chai = require('chai')
, expect = chai.expect;
chai.Assertion.includeStack = true;
describe('EventEmitter#emit', function () {
it('should return false when there are not events to emit', function () {
var e = new EventEmitter();
expect(e.emit('foo')).to.equal(false);
expect(e.emit('bar')).to.equal(false);
});
it('emits with context', function (done) {
var e = new EventEmitter()
, context = 'bar';
e.on('foo', function (bar) {
expect(bar).to.equal('bar');
expect(this).to.equal(context);
done();
}, context).emit('foo', 'bar');
});
it('should return true when there are events to emit', function (done) {
var e = new EventEmitter();
e.on('foo', function () {
process.nextTick(done);
});
expect(e.emit('foo')).to.equal(true);
expect(e.emit('foob')).to.equal(false);
});
it('receives the emitted events', function (done) {
var e = new EventEmitter();
e.on('data', function (a, b, c, d, undef) {
expect(a).to.equal('foo');
expect(b).to.equal(e);
expect(c).to.be.instanceOf(Date);
expect(undef).to.equal(undefined);
expect(arguments.length).to.equal(3);
done();
});
e.emit('data', 'foo', e, new Date());
});
it('emits to all event listeners', function () {
var e = new EventEmitter()
, pattern = [];
e.on('foo', function () {
pattern.push('foo1');
});
e.on('foo', function () {
pattern.push('foo2');
});
e.emit('foo');
expect(pattern.join(';')).to.equal('foo1;foo2');
});
});
describe('EventEmitter#listeners', function () {
it('returns an empty array if no listeners are specified', function () {
var e = new EventEmitter();
expect(e.listeners('foo')).to.be.a('array');
expect(e.listeners('foo').length).to.equal(0);
});
it('returns an array of function', function () {
var e = new EventEmitter();
function foo() {}
e.on('foo', foo);
expect(e.listeners('foo')).to.be.a('array');
expect(e.listeners('foo').length).to.equal(1);
expect(e.listeners('foo')).to.deep.equal([foo]);
});
it('is not vulnerable to modifications', function () {
var e = new EventEmitter();
function foo() {}
e.on('foo', foo);
expect(e.listeners('foo')).to.deep.equal([foo]);
e.listeners('foo').length = 0;
expect(e.listeners('foo')).to.deep.equal([foo]);
});
});
describe('EventEmitter#once', function () {
it('only emits it once', function () {
var e = new EventEmitter()
, calls = 0;
e.once('foo', function () {
calls++;
});
e.emit('foo');
e.emit('foo');
e.emit('foo');
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
, foo = 0
, bar = 0;
e.once('foo', function () {
foo++;
});
e.once('foo', function () {
bar++;
});
e.on('foo', function () {
multi++;
});
e.emit('foo');
e.emit('foo');
e.emit('foo');
e.emit('foo');
e.emit('foo');
expect(e.listeners('foo').length).to.equal(1);
expect(multi).to.equal(5);
expect(foo).to.equal(1);
expect(bar).to.equal(1);
});
it('only emits once with context', function (done) {
var e = new EventEmitter()
, context = 'foo';
e.once('foo', function (bar) {
expect(this).to.equal(context);
expect(bar).to.equal('bar');
done();
}, context).emit('foo', 'bar');
});
});
describe('EventEmitter#removeListener', function () {
it('should only remove the event with the specified function', function () {
var e = new EventEmitter();
function bar() {}
e.on('foo', function () {});
e.on('bar', function () {});
e.on('bar', bar);
expect(e.removeListener('foo', bar)).to.equal(e);
expect(e.listeners('foo').length).to.equal(1);
expect(e.listeners('bar').length).to.equal(2);
expect(e.removeListener('foo')).to.equal(e);
expect(e.listeners('foo').length).to.equal(0);
expect(e.listeners('bar').length).to.equal(2);
expect(e.removeListener('bar', bar)).to.equal(e);
expect(e.listeners('bar').length).to.equal(1);
expect(e.removeListener('bar')).to.equal(e);
expect(e.listeners('bar').length).to.equal(0);
});
});
describe('EventEmitter#removeAllListeners', function () {
it('removes all events for the specified events', function () {
var e = new EventEmitter();
e.on('foo', function () { throw new Error('oops'); });
e.on('foo', function () { throw new Error('oops'); });
e.on('bar', function () { throw new Error('oops'); });
e.on('aaa', function () { throw new Error('oops'); });
expect(e.removeAllListeners('foo')).to.equal(e);
expect(e.listeners('foo').length).to.equal(0);
expect(e.listeners('bar').length).to.equal(1);
expect(e.listeners('aaa').length).to.equal(1);
expect(e.removeAllListeners('bar')).to.equal(e);
expect(e.removeAllListeners('aaa')).to.equal(e);
expect(e.emit('foo')).to.equal(false);
expect(e.emit('bar')).to.equal(false);
expect(e.emit('aaa')).to.equal(false);
});
it('just nukes the fuck out of everything', function () {
var e = new EventEmitter();
e.on('foo', function () { throw new Error('oops'); });
e.on('foo', function () { throw new Error('oops'); });
e.on('bar', function () { throw new Error('oops'); });
e.on('aaa', function () { throw new Error('oops'); });
expect(e.removeAllListeners()).to.equal(e);
expect(e.listeners('foo').length).to.equal(0);
expect(e.listeners('bar').length).to.equal(0);
expect(e.listeners('aaa').length).to.equal(0);
expect(e.emit('foo')).to.equal(false);
expect(e.emit('bar')).to.equal(false);
expect(e.emit('aaa')).to.equal(false);
});
});
it('inherits when used with require(util).inherits', function () {
function Beast() {
/* rawr, i'm a beast */
}
require('util').inherits(Beast, EventEmitter);
var moop = new Beast()
, meap = new Beast();
expect(moop).to.be.instanceOf(Beast);
expect(moop).to.be.instanceof(EventEmitter);
moop.on('data', function () {
throw new Error('I should not emit');
});
meap.emit('data', 'rawr');
meap.removeListener('foo');
meap.removeAllListeners();
});
});
This diff is collapsed.
/*
examples-test.js: Test to run all the examples
Copyright (c) Nodejitsu 2013
*/
var path = require('path'),
fs = require('fs'),
spawn = require('child_process').spawn,
expect = require('expect.js'),
async = require('async');
var rootDir = path.join(__dirname, '..'),
examplesDir = path.join(rootDir, 'examples');
describe.skip('http-proxy examples', function () {
describe('Before testing examples', function () {
// Set a timeout to avoid this error
this.timeout(30 * 1000);
it('should have installed dependencies', function (done) {
async.waterfall([
//
// 1. Read files in examples dir
//
async.apply(fs.readdir, examplesDir),
//
// 2. If node_modules exists, continue. Otherwise
// exec `npm` to install them
//
function checkNodeModules(files, next) {
if (files.indexOf('node_modules') !== -1) {
return next();
}
console.log('Warning: installing dependencies, this operation could take a while');
var child = spawn('npm', ['install', '-f'], {
cwd: examplesDir
});
child.on('exit', function (code) {
return code
? next(new Error('npm install exited with non-zero exit code'))
: next();
});
},
//
// 3. Read files in examples dir again to ensure the install
// worked as expected.
//
async.apply(fs.readdir, examplesDir),
], done);
})
});
describe('Requiring all the examples', function () {
it('should have no errors', function (done) {
async.each(['balancer', 'http', 'middleware', 'websocket'], function (dir, cb) {
var name = 'examples/' + dir,
files = fs.readdirSync(path.join(rootDir, 'examples', dir));
async.each(files, function (file, callback) {
var example;
expect(function () { example = require(path.join(examplesDir, dir, file)); }).to.not.throwException();
expect(example).to.be.an('object');
callback();
}, cb);
}, done);
})
})
})
\ No newline at end of file
-----BEGIN CERTIFICATE-----
MIIB7DCCAZYCCQC7gs0MDNn6MTANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJV
UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO
BgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEgMB4GCSqGSIb3DQEJARYR
cnlAdGlueWNsb3Vkcy5vcmcwHhcNMTEwMzE0MTgyOTEyWhcNMzgwNzI5MTgyOTEy
WjB9MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYD
VQQKEwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEg
MB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwXDANBgkqhkiG9w0BAQEF
AANLADBIAkEAyXb8FrRdKbhrKLgLSsn61i1C7w7fVVVd7OQsmV/7p9WB2lWFiDlC
WKGU9SiIz/A6wNZDUAuc2E+VwtpCT561AQIDAQABMA0GCSqGSIb3DQEBBQUAA0EA
C8HzpuNhFLCI3A5KkBS5zHAQax6TFUOhbpBCR0aTDbJ6F1liDTK1lmU/BjvPoj+9
1LHwrmh29rK8kBPEjmymCQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE REQUEST-----
MIIBXTCCAQcCAQAwfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQH
EwJTRjEPMA0GA1UEChMGSm95ZW50MRAwDgYDVQQLEwdOb2RlLmpzMQ8wDQYDVQQD
EwZhZ2VudDIxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMFwwDQYJ
KoZIhvcNAQEBBQADSwAwSAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf
+6fVgdpVhYg5QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAaAlMCMGCSqG
SIb3DQEJBzEWExRBIGNoYWxsZW5nZSBwYXNzd29yZDANBgkqhkiG9w0BAQUFAANB
AJnll2pt5l0pzskQSpjjLVTlFDFmJr/AZ3UK8v0WxBjYjCe5Jx4YehkChpxIyDUm
U3J9q9MDUf0+Y2+EGkssFfk=
-----END CERTIFICATE REQUEST-----
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf+6fVgdpVhYg5
QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAQJBAMT6Bf34+UHKY1ObpsbH
9u2jsVblFq1rWvs8GPMY6oertzvwm3DpuSUp7PTgOB1nLTLYtCERbQ4ovtN8tn3p
OHUCIQDzIEGsoCr5vlxXvy2zJwu+fxYuhTZWMVuo1397L0VyhwIhANQh+yzqUgaf
WRtSB4T2W7ADtJI35ET61jKBty3CqJY3AiAIwju7dVW3A5WeD6Qc1SZGKZvp9yCb
AFI2BfVwwaY11wIgXF3PeGcvACMyMWsuSv7aPXHfliswAbkWuzcwA4TW01ECIGWa
cgsDvVFxmfM5NPSuT/UDTa6R5BFISB5ea0N0AR3I
-----END RSA PRIVATE KEY-----
[ req ]
default_bits = 1024
days = 999
distinguished_name = req_distinguished_name
attributes = req_attributes
prompt = no
[ req_distinguished_name ]
C = US
ST = CA
L = SF
O = Joyent
OU = Node.js
CN = agent2
emailAddress = ry@tinyclouds.org
[ req_attributes ]
challengePassword = A challenge password
var common = require('../lib/http-proxy/common'),
expect = require('expect.js');
describe('lib/http-proxy/common.js', function () {
describe('#setupOutgoing', function () {
it('should setup the correct headers', function () {
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent : '?',
target: {
host : 'hey',
hostname : 'how',
socketPath: 'are',
port : 'you',
},
headers: {'fizz': 'bang', 'overwritten':true},
},
{
method : 'i',
url : 'am',
headers : {'pro':'xy','overwritten':false}
});
expect(outgoing.host).to.eql('hey');
expect(outgoing.hostname).to.eql('how');
expect(outgoing.socketPath).to.eql('are');
expect(outgoing.port).to.eql('you');
expect(outgoing.agent).to.eql('?');
expect(outgoing.method).to.eql('i');
expect(outgoing.path).to.eql('am');
expect(outgoing.headers.pro).to.eql('xy');
expect(outgoing.headers.fizz).to.eql('bang');
expect(outgoing.headers.overwritten).to.eql(true);
});
it('should set the agent to false if none is given', function () {
var outgoing = {};
common.setupOutgoing(outgoing, {target:
'http://localhost'
}, { url: '/' });
expect(outgoing.agent).to.eql(false);
});
it('set the port according to the protocol', function () {
var outgoing = {};
common.setupOutgoing(outgoing,
{
agent : '?',
target: {
host : 'how',
hostname : 'are',
socketPath: 'you',
protocol: 'https:'
}
},
{
method : 'i',
url : 'am',
headers : 'proxy'
});
expect(outgoing.host).to.eql('how');
expect(outgoing.hostname).to.eql('are');
expect(outgoing.socketPath).to.eql('you');
expect(outgoing.agent).to.eql('?');
expect(outgoing.method).to.eql('i');
expect(outgoing.path).to.eql('am');
expect(outgoing.headers).to.eql('proxy')
expect(outgoing.port).to.eql(443);
});
});
describe('#setupSocket', function () {
it('should setup a socket', function () {
var socketConfig = {
timeout: null,
nodelay: false,
keepalive: false
},
stubSocket = {
setTimeout: function (num) {
socketConfig.timeout = num;
},
setNoDelay: function (bol) {
socketConfig.nodelay = bol;
},
setKeepAlive: function (bol) {
socketConfig.keepalive = bol;
}
}
returnValue = common.setupSocket(stubSocket);
expect(socketConfig.timeout).to.eql(0);
expect(socketConfig.nodelay).to.eql(true);
expect(socketConfig.keepalive).to.eql(true);
});
});
});
\ No newline at end of file
var webPasses = require('../lib/http-proxy/passes/web-incoming'),
httpProxy = require('../lib/http-proxy'),
expect = require('expect.js'),
http = require('http');
describe('lib/http-proxy/passes/web.js', function() {
describe('#deleteLength', function() {
it('should change `content-length`', function() {
var stubRequest = {
method: 'DELETE',
headers: {}
};
webPasses.deleteLength(stubRequest, {}, {});
expect(stubRequest.headers['content-length']).to.eql('0');
})
});
describe('#timeout', function() {
it('should set timeout on the socket', function() {
var done = false, stubRequest = {
socket: {
setTimeout: function(value) { done = value; }
}
}
webPasses.timeout(stubRequest, {}, { timeout: 5000});
expect(done).to.eql(5000);
});
});
describe('#XHeaders', function () {
var stubRequest = {
connection: {
remoteAddress: '192.168.1.2',
remotePort: '8080'
},
headers: {
host: '192.168.1.2:8080'
}
}
it('set the correct x-forwarded-* headers', function () {
webPasses.XHeaders(stubRequest, {}, { xfwd: true });
expect(stubRequest.headers['x-forwarded-for']).to.be('192.168.1.2');
expect(stubRequest.headers['x-forwarded-port']).to.be('8080');
expect(stubRequest.headers['x-forwarded-proto']).to.be('http');
});
});
});
describe('#createProxyServer.web() using own http server', function () {
it('should proxy the request using the web proxy handler', function (done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080'
});
function requestHandler(req, res) {
proxy.web(req, res);
}
var proxyServer = http.createServer(requestHandler);
var source = http.createServer(function(req, res) {
source.close();
proxyServer.close();
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql('8081');
done();
});
proxyServer.listen('8081');
source.listen('8080');
http.request('http://127.0.0.1:8081', function() {}).end();
});
it('should proxy the request and handle error via callback', function(done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080'
});
var proxyServer = http.createServer(requestHandler);
function requestHandler(req, res) {
proxy.web(req, res, function (err) {
proxyServer.close();
expect(err).to.be.an(Error);
expect(err.code).to.be('ECONNREFUSED');
done();
});
}
proxyServer.listen('8082');
http.request({
hostname: '127.0.0.1',
port: '8082',
method: 'GET',
}, function() {}).end();
});
it('should proxy the request and handle error via event listener', function(done) {
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:8080'
});
var proxyServer = http.createServer(requestHandler);
function requestHandler(req, res) {
proxy.once('error', function (err, errReq, errRes) {
proxyServer.close();
expect(err).to.be.an(Error);
expect(errReq).to.be.equal(req);
expect(errRes).to.be.equal(res);
expect(err.code).to.be('ECONNREFUSED');
done();
});
proxy.web(req, res);
}
proxyServer.listen('8083');
http.request({
hostname: '127.0.0.1',
port: '8083',
method: 'GET',
}, function() {}).end();
});
});
\ No newline at end of file
var httpProxy = require('../lib/http-proxy/passes/web-outgoing'),
expect = require('expect.js');
describe('lib/http-proxy/passes/web-outgoing.js', function () {
describe('#setConnection', function () {
it('set the right connection with 1.0 - `close`', function() {
var proxyRes = { headers: {} };
httpProxy.setConnection({
httpVersion: '1.0',
headers: {
connection: null
}
}, {}, proxyRes);
expect(proxyRes.headers.connection).to.eql('close');
});
it('set the right connection with 1.0 - req.connection', function() {
var proxyRes = { headers: {} };
httpProxy.setConnection({
httpVersion: '1.0',
headers: {
connection: 'hey'
}
}, {}, proxyRes);
expect(proxyRes.headers.connection).to.eql('hey');
});
it('set the right connection - req.connection', function() {
var proxyRes = { headers: {} };
httpProxy.setConnection({
httpVersion: null,
headers: {
connection: 'hola'
}
}, {}, proxyRes);
expect(proxyRes.headers.connection).to.eql('hola');
});
it('set the right connection - `keep-alive`', function() {
var proxyRes = { headers: {} };
httpProxy.setConnection({
httpVersion: null,
headers: {
connection: null
}
}, {}, proxyRes);
expect(proxyRes.headers.connection).to.eql('keep-alive');
});
});
describe('#writeStatusCode', function () {
it('should write status code', function() {
var res = {
writeHead: function(n) {
expect(n).to.eql(200);
}
}
httpProxy.writeStatusCode({}, res, { statusCode: 200 });
});
});
describe('#writeHeaders', function() {
var proxyRes = {
headers: {
hey: 'hello',
how: 'are you?'
}
};
var res = {
setHeader: function(k, v) {
this.headers[k] = v;
},
headers: {}
};
httpProxy.writeHeaders({}, res, proxyRes);
expect(res.headers.hey).to.eql('hello');
expect(res.headers.how).to.eql('are you?');
});
describe('#removeChunked', function() {
var proxyRes = {
headers: {
'transfer-encoding': 'hello'
}
};
httpProxy.removeChunked({ httpVersion: '1.0' }, {}, proxyRes);
expect(proxyRes.headers['transfer-encoding']).to.eql(undefined);
});
});
var httpProxy = require('../lib/http-proxy/passes/ws-incoming'),
expect = require('expect.js');
describe('lib/http-proxy/passes/ws-incoming.js', function () {
describe('#checkMethodAndHeader', function () {
it('should drop non-GET connections', function () {
var destroyCalled = false,
stubRequest = {
method: 'DELETE',
headers: {}
},
stubSocket = {
destroy: function () {
// Simulate Socket.destroy() method when call
destroyCalled = true;
}
}
returnValue = httpProxy.checkMethodAndHeader(stubRequest, stubSocket);
expect(returnValue).to.be(true);
expect(destroyCalled).to.be(true);
})
it('should drop connections when no upgrade header', function () {
var destroyCalled = false,
stubRequest = {
method: 'GET',
headers: {}
},
stubSocket = {
destroy: function () {
// Simulate Socket.destroy() method when call
destroyCalled = true;
}
}
returnValue = httpProxy.checkMethodAndHeader(stubRequest, stubSocket);
expect(returnValue).to.be(true);
expect(destroyCalled).to.be(true);
})
it('should drop connections when upgrade header is different of `websocket`', function () {
var destroyCalled = false,
stubRequest = {
method: 'GET',
headers: {
upgrade: 'anotherprotocol'
}
},
stubSocket = {
destroy: function () {
// Simulate Socket.destroy() method when call
destroyCalled = true;
}
}
returnValue = httpProxy.checkMethodAndHeader(stubRequest, stubSocket);
expect(returnValue).to.be(true);
expect(destroyCalled).to.be(true);
})
it('should return nothing when all is ok', function () {
var destroyCalled = false,
stubRequest = {
method: 'GET',
headers: {
upgrade: 'websocket'
}
},
stubSocket = {
destroy: function () {
// Simulate Socket.destroy() method when call
destroyCalled = true;
}
}
returnValue = httpProxy.checkMethodAndHeader(stubRequest, stubSocket);
expect(returnValue).to.be(undefined);
expect(destroyCalled).to.be(false);
})
});
describe('#XHeaders', function () {
it('return if no forward request', function () {
var returnValue = httpProxy.XHeaders({}, {}, {});
expect(returnValue).to.be(undefined);
});
it('set the correct x-forwarded-* headers from req.connection', function () {
var stubRequest = {
connection: {
remoteAddress: '192.168.1.2',
remotePort: '8080'
},
headers: {
host: '192.168.1.2:8080'
}
}
httpProxy.XHeaders(stubRequest, {}, { xfwd: true });
expect(stubRequest.headers['x-forwarded-for']).to.be('192.168.1.2');
expect(stubRequest.headers['x-forwarded-port']).to.be('8080');
expect(stubRequest.headers['x-forwarded-proto']).to.be('ws');
});
it('set the correct x-forwarded-* headers from req.socket', function () {
var stubRequest = {
socket: {
remoteAddress: '192.168.1.3',
remotePort: '8181'
},
connection: {
pair: true
},
headers: {
host: '192.168.1.3:8181'
}
};
httpProxy.XHeaders(stubRequest, {}, { xfwd: true });
expect(stubRequest.headers['x-forwarded-for']).to.be('192.168.1.3');
expect(stubRequest.headers['x-forwarded-port']).to.be('8181');
expect(stubRequest.headers['x-forwarded-proto']).to.be('wss');
});
});
});
var httpProxy = require('../lib/http-proxy'),
expect = require('expect.js'),
http = require('http'),
ws = require('ws')
io = require('socket.io'),
ioClient = require('socket.io-client');
//
// Expose a port number generator.
// thanks to @3rd-Eden
//
var initialPort = 1024, gen = {};
Object.defineProperty(gen, 'port', {
get: function get() {
return initialPort++;
}
});
describe('lib/http-proxy.js', function() {
describe('#createProxyServer', function() {
it.skip('should throw without options', function() {
var error;
try {
httpProxy.createProxyServer();
} catch(e) {
error = e;
}
expect(error).to.be.an(Error);
})
it('should return an object otherwise', function() {
var obj = httpProxy.createProxyServer({
target: 'http://www.google.com:80'
});
expect(obj.web).to.be.a(Function);
expect(obj.ws).to.be.a(Function);
expect(obj.listen).to.be.a(Function);
});
});
describe('#createProxyServer with forward options and using web-incoming passes', function () {
it('should pipe the request using web-incoming#stream method', function (done) {
var ports = { source: gen.port, proxy: gen.port };
var proxy = httpProxy.createProxyServer({
forward: 'http://127.0.0.1:' + ports.source
}).listen(ports.proxy);
var source = http.createServer(function(req, res) {
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql(ports.proxy);
source.close();
proxy._server.close();
done();
});
source.listen(ports.source);
http.request('http://127.0.0.1:' + ports.proxy, function() {}).end();
})
});
describe('#createProxyServer using the web-incoming passes', function () {
it('should make the request on pipe and finish it', function(done) {
var ports = { source: gen.port, proxy: gen.port };
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:' + ports.source
}).listen(ports.proxy);
var source = http.createServer(function(req, res) {
expect(req.method).to.eql('POST');
expect(req.headers['x-forwarded-for']).to.eql('127.0.0.1');
expect(req.headers.host.split(':')[1]).to.eql(ports.proxy);
source.close();
proxy._server.close();
done();
});
source.listen(ports.source);
http.request({
hostname: '127.0.0.1',
port: ports.proxy,
method: 'POST',
headers: {
'x-forwarded-for': '127.0.0.1'
}
}, function() {}).end();
});
});
describe('#createProxyServer using the web-incoming passes', function () {
it('should make the request, handle response and finish it', function(done) {
var ports = { source: gen.port, proxy: gen.port };
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:' + ports.source
}).listen(ports.proxy);
var source = http.createServer(function(req, res) {
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql(ports.proxy);
res.writeHead(200, {'Content-Type': 'text/plain'})
res.end('Hello from ' + source.address().port);
});
source.listen(ports.source);
http.request({
hostname: '127.0.0.1',
port: ports.proxy,
method: 'GET'
}, function(res) {
expect(res.statusCode).to.eql(200);
res.on('data', function (data) {
expect(data.toString()).to.eql('Hello from ' + ports.source);
});
res.on('end', function () {
source.close();
proxy._server.close();
done();
});
}).end();
});
});
describe('#createProxyServer() method with error response', function () {
it('should make the request and emit the error event', function(done) {
var ports = { source: gen.port, proxy: gen.port };
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:' + ports.source
});
proxy.on('error', function (err) {
expect(err).to.be.an(Error);
expect(err.code).to.be('ECONNREFUSED');
proxy._server.close();
done();
})
proxy.listen(ports.proxy);
http.request({
hostname: '127.0.0.1',
port: ports.proxy,
method: 'GET',
}, function() {}).end();
});
});
describe('#createProxyServer setting the correct timeout value', function () {
it('should hang up the socket at the timeout', function (done) {
this.timeout(30);
var ports = { source: gen.port, proxy: gen.port };
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:' + ports.source,
timeout: 3
}).listen(ports.proxy);
var source = http.createServer(function(req, res) {
setTimeout(function () {
res.end('At this point the socket should be closed');
}, 5)
});
source.listen(ports.source);
var testReq = http.request({
hostname: '127.0.0.1',
port: ports.proxy,
method: 'GET',
}, function() {});
testReq.on('error', function (e) {
expect(e).to.be.an(Error);
expect(e.code).to.be.eql('ECONNRESET');
proxy._server.close();
source.close();
done();
});
testReq.end();
})
})
// describe('#createProxyServer using the web-incoming passes', function () {
// it('should emit events correclty', function(done) {
// var proxy = httpProxy.createProxyServer({
// target: 'http://127.0.0.1:8080'
// }),
// proxyServer = proxy.listen('8081'),
// source = http.createServer(function(req, res) {
// expect(req.method).to.eql('GET');
// expect(req.headers.host.split(':')[1]).to.eql('8081');
// res.writeHead(200, {'Content-Type': 'text/plain'})
// res.end('Hello from ' + source.address().port);
// }),
// events = [];
// source.listen('8080');
// proxy.ee.on('http-proxy:**', function (uno, dos, tres) {
// events.push(this.event);
// })
// http.request({
// hostname: '127.0.0.1',
// port: '8081',
// method: 'GET',
// }, function(res) {
// expect(res.statusCode).to.eql(200);
// res.on('data', function (data) {
// expect(data.toString()).to.eql('Hello from 8080');
// });
// res.on('end', function () {
// expect(events).to.contain('http-proxy:outgoing:web:begin');
// expect(events).to.contain('http-proxy:outgoing:web:end');
// source.close();
// proxyServer._server.close();
// done();
// });
// }).end();
// });
// });
describe('#createProxyServer using the ws-incoming passes', function () {
it('should proxy the websockets stream', function (done) {
var ports = { source: gen.port, proxy: gen.port };
var proxy = httpProxy.createProxyServer({
target: 'ws://127.0.0.1:' + ports.source,
ws: true
}),
proxyServer = proxy.listen(ports.proxy),
destiny = new ws.Server({ port: ports.source }, function () {
var client = new ws('ws://127.0.0.1:' + ports.proxy);
client.on('open', function () {
client.send('hello there');
});
client.on('message', function (msg) {
expect(msg).to.be('Hello over websockets');
client.close();
proxyServer._server.close();
destiny.close();
done();
});
});
destiny.on('connection', function (socket) {
socket.on('message', function (msg) {
expect(msg).to.be('hello there');
socket.send('Hello over websockets');
});
});
});
it('should emit error on proxy error', function (done) {
var ports = { source: gen.port, proxy: gen.port };
var proxy = httpProxy.createProxyServer({
// note: we don't ever listen on this port
target: 'ws://127.0.0.1:' + ports.source,
ws: true
}),
proxyServer = proxy.listen(ports.proxy),
client = new ws('ws://127.0.0.1:' + ports.proxy);
client.on('open', function () {
client.send('hello there');
});
proxy.on('error', function (err) {
expect(err).to.be.an(Error);
expect(err.code).to.be('ECONNREFUSED');
proxyServer._server.close();
done();
});
});
it('should proxy a socket.io stream', function (done) {
var ports = { source: gen.port, proxy: gen.port };
var proxy = httpProxy.createProxyServer({
target: 'ws://127.0.0.1:' + ports.source,
ws: true
}),
proxyServer = proxy.listen(ports.proxy),
destiny = io.listen(ports.source, function () {
var client = ioClient.connect('ws://127.0.0.1:' + ports.proxy);
client.on('connect', function () {
client.emit('incoming', 'hello there');
});
client.on('outgoing', function (data) {
expect(data).to.be('Hello over websockets');
proxyServer._server.close();
destiny.server.close();
done();
});
});
destiny.sockets.on('connection', function (socket) {
socket.on('incoming', function (msg) {
expect(msg).to.be('hello there');
socket.emit('outgoing', 'Hello over websockets');
});
})
});
})
});
\ No newline at end of file
var httpProxy = require('../lib/http-proxy'),
expect = require('expect.js'),
http = require('http')
https = require('https'),
path = require('path'),
fs = require('fs');
//
// Expose a port number generator.
// thanks to @3rd-Eden
//
var initialPort = 1024, gen = {};
Object.defineProperty(gen, 'port', {
get: function get() {
return initialPort++;
}
});
describe('lib/http-proxy.js', function() {
describe('HTTPS #createProxyServer', function() {
describe('HTTPS to HTTP', function () {
it('should proxy the request en send back the response', function (done) {
var ports = { source: gen.port, proxy: gen.port };
var source = http.createServer(function(req, res) {
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql(ports.proxy);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from ' + ports.source);
});
source.listen(ports.source);
var proxy = httpProxy.createProxyServer({
target: 'http://127.0.0.1:' + ports.source,
ssl: {
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')),
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')),
}
}).listen(ports.proxy);
https.request({
host: 'localhost',
port: ports.proxy,
path: '/',
method: 'GET',
rejectUnauthorized: false
}, function(res) {
expect(res.statusCode).to.eql(200);
res.on('data', function (data) {
expect(data.toString()).to.eql('Hello from ' + ports.source);
});
res.on('end', function () {
source.close();
proxy._server.close();
done();
})
}).end();
})
});
describe('HTTP to HTTPS', function () {
it('should proxy the request en send back the response', function (done) {
var ports = { source: gen.port, proxy: gen.port };
var source = https.createServer({
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')),
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')),
}, function (req, res) {
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql(ports.proxy);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from ' + ports.source);
});
source.listen(ports.source);
var proxy = httpProxy.createProxyServer({
target: 'https://127.0.0.1:' + ports.source,
// Allow to use SSL self signed
secure: false
}).listen(ports.proxy);
http.request({
hostname: '127.0.0.1',
port: ports.proxy,
method: 'GET'
}, function(res) {
expect(res.statusCode).to.eql(200);
res.on('data', function (data) {
expect(data.toString()).to.eql('Hello from ' + ports.source);
});
res.on('end', function () {
source.close();
proxy._server.close();
done();
});
}).end();
})
})
describe('HTTPS to HTTPS', function () {
it('should proxy the request en send back the response', function (done) {
var ports = { source: gen.port, proxy: gen.port };
var source = https.createServer({
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')),
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')),
}, function(req, res) {
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql(ports.proxy);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from ' + ports.source);
});
source.listen(ports.source);
var proxy = httpProxy.createProxyServer({
target: 'https://127.0.0.1:' + ports.source,
ssl: {
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')),
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')),
},
secure: false
}).listen(ports.proxy);
https.request({
host: 'localhost',
port: ports.proxy,
path: '/',
method: 'GET',
rejectUnauthorized: false
}, function(res) {
expect(res.statusCode).to.eql(200);
res.on('data', function (data) {
expect(data.toString()).to.eql('Hello from ' + ports.source);
});
res.on('end', function () {
source.close();
proxy._server.close();
done();
})
}).end();
})
});
describe('HTTPS not allow SSL self signed', function () {
it('should fail with error', function (done) {
var ports = { source: gen.port, proxy: gen.port };
var source = https.createServer({
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')),
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')),
}).listen(ports.source);
var proxy = httpProxy.createProxyServer({
target: 'https://127.0.0.1:' + ports.source,
secure: true
});
proxy.listen(ports.proxy);
proxy.on('error', function (err, req, res) {
expect(err).to.be.an(Error);
expect(err.toString()).to.be('Error: DEPTH_ZERO_SELF_SIGNED_CERT')
done();
})
http.request({
hostname: '127.0.0.1',
port: ports.proxy,
method: 'GET'
}).end();
})
})
describe('HTTPS to HTTP using own server', function () {
it('should proxy the request en send back the response', function (done) {
var ports = { source: gen.port, proxy: gen.port };
var source = http.createServer(function(req, res) {
expect(req.method).to.eql('GET');
expect(req.headers.host.split(':')[1]).to.eql(ports.proxy);
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from ' + ports.source);
});
source.listen(ports.source);
var proxy = httpProxy.createServer({
agent: new http.Agent({ maxSockets: 2 })
});
var ownServer = https.createServer({
key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')),
cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')),
}, function (req, res) {
proxy.web(req, res, {
target: 'http://127.0.0.1:' + ports.source
})
}).listen(ports.proxy);
https.request({
host: 'localhost',
port: ports.proxy,
path: '/',
method: 'GET',
rejectUnauthorized: false
}, function(res) {
expect(res.statusCode).to.eql(200);
res.on('data', function (data) {
expect(data.toString()).to.eql('Hello from ' + ports.source);
});
res.on('end', function () {
source.close();
ownServer.close();
done();
})
}).end();
})
})
});
});
\ No newline at end of file
{
"name": "debomatic-proxy"
, "version": "0.0.1"
, "private": true
, "dependencies": {
"http-proxy" : "*"
}
}
This diff is collapsed.
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