diff --git a/README.md b/README.md index 68215a81f..e618926df 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,17 @@ ###features - reverse-proxies incoming http.Server requests +- can be used as a CommonJS module in node.js - can handled malformed http requests - uses event buffering to support application latency in proxied requests - minimal request overhead and latency - fully-tested - battled-hardened through production usage @ nodejitsu.com - +- written entirely in javascript +- easy to use api ###when to use node-http-proxy let's suppose you were running multiple http application servers, but you only wanted to expose one machine to the internet. you could setup node-http-proxy on that one machine and then reverse-proxy the incoming http requests to locally running services which were not exposed to the outside network. ### how to use node-http-proxy - diff --git a/demo.js b/demo.js new file mode 100644 index 000000000..1e96bb5c1 --- /dev/null +++ b/demo.js @@ -0,0 +1,130 @@ +/* + * node-proxy-test.js: Tests for node-proxy. Reverse proxy for node.js + * + * (C) 2010 Charlie Robbins + * MIT LICENSE + * + */ + +var vows = require('vows'), + sys = require('sys'), + colors = require('./vendor/colors') + assert = require('assert'), + http = require('http'); + +require.paths.unshift(require('path').join(__dirname, '../lib/')); + + +sys.puts('node-http-proxy has started!'.rainbow); + + +var NodeProxy = require('./lib/node-proxy').NodeProxy; +var testServers = {}; + +// +// Simple 'hello world' response for test purposes +// +var helloWorld = function(req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.write('hello world') + res.end(); +}; + +// +// Creates the reverse proxy server +// +var startProxyServer = function (server, port, proxy) { + var proxyServer = http.createServer(function (req, res){ + // Initialize the nodeProxy and start proxying the request + proxy.init(req, res); + proxy.proxyRequest(server, port, req, res); + }); + + proxyServer.listen(8080); + return proxyServer; +}; + +// +// Creates the reverse proxy server with a specified latency +// +var startLatentProxyServer = function (server, port, proxy, latency) { + var proxyServer = http.createServer(function (req, res){ + // Initialize the nodeProxy and start proxying the request + proxy.init(req, res); + setTimeout(function () { + proxy.proxyRequest(server, port, req, res); + }, latency); + }); + + proxyServer.listen(8081); + return proxyServer; +}; + +// +// Creates the 'hellonode' server +// +var startTargetServer = function (port) { + var targetServer = http.createServer(function (req, res) { + helloWorld(req, res); + }) + + targetServer.listen(port); + return targetServer; +}; + +// +// The default test bootstrapper with no latency +// +var startTest = function (proxy, port) { + testServers.noLatency = []; + testServers.noLatency.push(startProxyServer('127.0.0.1', port, proxy)); + testServers.noLatency.push(startTargetServer(port)); +}; + +// +// The test bootstrapper with some latency +// +var startTestWithLatency = function (proxy, port) { + testServers.latency = []; + testServers.latency.push(startLatentProxyServer('127.0.0.1', port, proxy, 2000)); + testServers.latency.push(startTargetServer(port)); +}; + +vows.describe('node-proxy').addBatch({ + "When an incoming request is proxied to the helloNode server" : { + "with no latency" : { + topic: function () { + var proxy = new (NodeProxy); + startTest(proxy, 8082); + proxy.emitter.addListener('end', this.callback); + + var client = http.createClient(8080, '127.0.0.1'); + var request = client.request('GET', '/'); + request.end(); + }, + "it should received 'hello world'": function (err, body) { + assert.equal(body, 'hello world'); + testServers.noLatency.forEach(function (server) { + server.close(); + }) + } + }, + "with latency": { + topic: function () { + var proxy = new (NodeProxy); + startTestWithLatency(proxy, 8083); + proxy.emitter.addListener('end', this.callback); + + var client = http.createClient(8081, '127.0.0.1'); + var request = client.request('GET', '/'); + request.end(); + }, + "it should receive 'hello world'": function (err, body) { + assert.equal(body, 'hello world'); + testServers.latency.forEach(function (server) { + server.close(); + }) + } + } + } +}).export(module); \ No newline at end of file diff --git a/lib/asciimo.js b/lib/asciimo.js new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/asciimo b/vendor/asciimo new file mode 160000 index 000000000..00f324d5e --- /dev/null +++ b/vendor/asciimo @@ -0,0 +1 @@ +Subproject commit 00f324d5e70a3c29321b48af04852e6b2b476d12 diff --git a/vendor/colors.js b/vendor/colors.js new file mode 100644 index 000000000..c56ff20e4 --- /dev/null +++ b/vendor/colors.js @@ -0,0 +1,75 @@ +/* +colors.js + +Copyright (c) 2010 Alexis Sellier (cloudhead) , Marak Squires + +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. + +*/ + +// prototypes the string object to have additional method calls that add terminal colors +['bold', 'underline', 'italic', 'inverse', 'grey', 'yellow', 'red', 'green', 'blue', 'white', 'cyan', 'magenta'].forEach(function (style) { + Object.defineProperty(String.prototype, style, { + get: function () { + return stylize(this, style); + } + }); +}); + +// prototypes string with method "rainbow" +// rainbow will apply a the color spectrum to a string, changing colors every letter +Object.defineProperty(String.prototype, 'rainbow', { + get: function () { + var rainbowcolors = ['red','yellow','green','blue','magenta']; //RoY G BiV + var exploded = this.split(""); + var i=0; + exploded = exploded.map(function(letter) { + if (letter==" ") { + return letter; + } + else { + return stylize(letter,rainbowcolors[i++ % rainbowcolors.length]); + } + }); + return exploded.join(""); + } +}); + +function stylize(str, style) { + var styles = { + //styles + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + //grayscale + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [90, 39], + //colors + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] + }; + return '\033[' + styles[style][0] + 'm' + str + + '\033[' + styles[style][1] + 'm'; +}; \ No newline at end of file