From 1b867a7f594f7dfe49fc17ff53451a353ec509d9 Mon Sep 17 00:00:00 2001 From: srossross Date: Sun, 15 Sep 2013 15:20:51 -0700 Subject: [PATCH 1/6] ENH: added error events --- lib/caronte/passes/web-incoming.js | 8 ++++++++ lib/caronte/passes/ws-incoming.js | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/lib/caronte/passes/web-incoming.js b/lib/caronte/passes/web-incoming.js index 6906ae873..66beb011c 100644 --- a/lib/caronte/passes/web-incoming.js +++ b/lib/caronte/passes/web-incoming.js @@ -102,6 +102,14 @@ function stream(req, res, options) { common.setupOutgoing(options.ssl || {}, options, req) ); + proxyReq.on('error', function(err){ + var ev = 'caronte:outgoing:web:'; + if (options.ee.listeners(ev + 'error').length == 0){ + throw err; + } + options.ee.emit(ev + 'error', err, req, res); + }); + req.pipe(proxyReq); proxyReq.on('response', function(proxyRes) { diff --git a/lib/caronte/passes/ws-incoming.js b/lib/caronte/passes/ws-incoming.js index 1fd3fd780..3b5e1f525 100644 --- a/lib/caronte/passes/ws-incoming.js +++ b/lib/caronte/passes/ws-incoming.js @@ -78,6 +78,13 @@ function stream(req, socket, options, head) { var proxyReq = (~['https:', 'wss:'].indexOf(options.target.protocol) ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req) ); + proxyReq.on('error', function(err){ + var ev = 'caronte:outgoing:ws:'; + if (options.ee.listeners(ev + 'error').length == 0){ + throw err; + } + options.ee.emit(ev + 'error', err, req, res); + }); proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { common.setupSocket(proxySocket); From 268afe34bb51448d511c9cd73c03e97d1c1baee0 Mon Sep 17 00:00:00 2001 From: srossross Date: Mon, 16 Sep 2013 10:37:11 -0700 Subject: [PATCH 2/6] ENH: updated `ws` and `web` functions to use the global options object as a base even if request options is specified. request options will over write any global options in a conflict --- lib/caronte/index.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 30db143f5..8a7e83742 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -1,5 +1,6 @@ var caronte = exports, - web = require('./passes/web-incoming'); + extend = require('util')._extend, + web = require('./passes/web-incoming'), ws = require('./passes/ws-incoming'); caronte.createWebProxy = createRightProxy('web'); @@ -41,7 +42,11 @@ function createRightProxy(type) { !(args[cntr] instanceof Buffer) && args[cntr] !== res ) { - options = args[cntr]; + //Copy global options + options = extend({}, options); + //Overwrite with request options + extend(options, args[cntr]); + cntr--; } From ef946a7697b38b13178881b3d1ebde63681dd4a1 Mon Sep 17 00:00:00 2001 From: srossross Date: Mon, 16 Sep 2013 10:49:53 -0700 Subject: [PATCH 3/6] ENH: updated target and forward options so that a string may be specified --- lib/caronte/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 8a7e83742..ef0187fa9 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -1,5 +1,6 @@ var caronte = exports, extend = require('util')._extend, + parse_url = require('url').parse, web = require('./passes/web-incoming'), ws = require('./passes/ws-incoming'); @@ -56,7 +57,12 @@ function createRightProxy(type) { options.ee.emit(ev + 'begin', req, res); - + ['target', 'forward'].forEach( + function(e) { + if (typeof options[e] === 'string') + options[e] = parse_url(options[e]); + }); + passes.some(function(pass) { var evnt = ev + pass.name.toLowerCase() + ':'; From edd8e2f04e4b39391b062fa6437d61b4ebde8748 Mon Sep 17 00:00:00 2001 From: srossross Date: Mon, 16 Sep 2013 11:01:34 -0700 Subject: [PATCH 4/6] ENH: updated readme with an example --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 86e7ff746..ea381d2e5 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,25 @@ You can easily add a `pass` (stages) into both the pipelines (XXX: ADD API). In addition, every stage emits a corresponding event so introspection during the process is always available. +#### Setup a stand-alone proxy server with custom server logic + +``` js +var http = require('http'), + caronte = require('caronte'); + +// +// Create a proxy server with custom application logic +// +var proxy = caronte.createProxyServer({}); + +var server = require('http').createServer(function(req, res) { + proxy.web(req, res, { target: 'http://127.0.0.1:5060' }); +}); + +console.log("listening on port 5050") +server.listen(5050); +``` + ### Contributing and Issues * Search on Google/Github From 07091b5077a40dfee29f6fd33ecb38d3fa25b801 Mon Sep 17 00:00:00 2001 From: srossross Date: Mon, 16 Sep 2013 11:21:20 -0700 Subject: [PATCH 5/6] ENH: updated README and added examples file. --- README.md | 29 +++++++++++++++++++++++++++++ examples/stand-alone.js | 15 +++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 examples/stand-alone.js diff --git a/README.md b/README.md index ea381d2e5..dcede4515 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,24 @@ You can easily add a `pass` (stages) into both the pipelines (XXX: ADD API). In addition, every stage emits a corresponding event so introspection during the process is always available. +#### Setup a basic stand-alone proxy server + +var http = require('http'), + caronte = require('caronte'); +// +// Create your proxy server +// +caronte.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 ``` js @@ -72,6 +90,17 @@ server.listen(5050); * Commit to your local branch (which must be different from `master`) * Submit your Pull Request (be sure to include tests and update documentation) +### Options + +`caronte.createProxyServer` supports the following options: + + * **target**: + * **forward**: + * **ssl**: object to be passed to https.createServer() + * **ws**: true/false, if you want to proxy websockets + * **xfwd**: true/false, adds x-forward headers + * **maxSock**: maximum number of sockets + ### Test ``` diff --git a/examples/stand-alone.js b/examples/stand-alone.js new file mode 100644 index 000000000..d3848abf4 --- /dev/null +++ b/examples/stand-alone.js @@ -0,0 +1,15 @@ +var http = require('http'), + caronte = require('caronte'); +// +// Create your proxy server +// +caronte.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); \ No newline at end of file From bd106d69f074a1c7018e685a4e144e23a17beb8c Mon Sep 17 00:00:00 2001 From: srossross Date: Mon, 16 Sep 2013 11:24:00 -0700 Subject: [PATCH 6/6] Updated readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dcede4515..e5b38566b 100644 --- a/README.md +++ b/README.md @@ -94,8 +94,8 @@ server.listen(5050); `caronte.createProxyServer` supports the following options: - * **target**: - * **forward**: + * **target**: url string to be parsed with the url module + * **forward**: url string to be parsed with the url module * **ssl**: object to be passed to https.createServer() * **ws**: true/false, if you want to proxy websockets * **xfwd**: true/false, adds x-forward headers