/* * helpers.js: Helpers for node-http-proxy tests. * * (C) 2010, Charlie Robbins * */ var fs = require('fs'), http = require('http'), https = require('https'), path = require('path'), vows = require('vows'), assert = require('assert'), request = require('request'), websocket = require('./../vendor/websocket'), httpProxy = require('./../lib/node-http-proxy'); var loadHttps = exports.loadHttps = function () { return { key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem'), 'utf8'), cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem'), 'utf8') }; }; var TestRunner = exports.TestRunner = function (source, target) { this.source = { protocol: source }, this.target = { protocol: target }; this.testServers = []; if (source === 'https') { this.source.https = loadHttps(); } if (target === 'https') { this.target.https = loadHttps(); } }; TestRunner.prototype.assertProxied = function (host, proxyPort, port, createProxy) { var self = this, assertion = "should receive 'hello " + host + "'", output = 'hello ' + host; var test = { topic: function () { var that = this, options; options = { method: 'GET', uri: self.source.protocol + '://localhost:' + proxyPort, headers: { host: host } }; function startTest () { if (port) { return self.startTargetServer(port, output, function () { request(options, that.callback); }); } request(options, this.callback); } return createProxy ? createProxy(startTest) : startTest(); } }; test[assertion] = function (err, res, body) { assert.isNull(err); assert.equal(body, output); }; return test; }; TestRunner.prototype.assertResponseCode = function (proxyPort, statusCode, createProxy) { var assertion = "should receive " + statusCode + " responseCode", protocol = this.source.protocol; var test = { topic: function () { var that = this, options = { method: 'GET', uri: protocol + '://localhost:' + proxyPort, headers: { host: 'unknown.com' } }; if (createProxy) { return createProxy(function () { request(options, that.callback); }); } request(options, this.callback); } }; test[assertion] = function (err, res, body) { assert.isNull(err); assert.equal(res.statusCode, statusCode); }; return test; }; // // WebSocketTest // TestRunner.prototype.webSocketTest = function (options) { var self = this; this.startTargetServer(options.ports.target, 'hello websocket', function (err, target) { var socket = options.io.listen(target); if (options.onListen) { options.onListen(socket); } self.startProxyServer( options.ports.proxy, options.ports.target, options.host, function (err, proxy) { if (options.onServer) { options.onServer(proxy) } // // Setup the web socket against our proxy // var uri = options.wsprotocol + '://' + options.host + ':' + options.ports.proxy; var ws = new websocket.WebSocket(uri + '/socket.io/websocket/', 'borf', { origin: options.protocol + '://' + options.host }); if (options.onWsupgrade) { ws.on('wsupgrade', options.onWsupgrade) } if (options.onMessage) { ws.on('message', options.onMessage) } if (options.onOpen) { ws.on('open', function () { options.onOpen(ws) }) } } ); }); } // // WebSocketTestWithTable // TestRunner.prototype.webSocketTestWithTable = function (options) { var self = this; this.startTargetServer(options.ports.target, 'hello websocket', function (err, target) { var socket = options.io.listen(target); if (options.onListen) { options.onListen(socket); } self.startProxyServerWithTable( options.ports.proxy, { router: options.router }, function (err, proxy) { if (options.onServer) { options.onServer(proxy) } // // Setup the web socket against our proxy // var uri = options.wsprotocol + '://' + options.host + ':' + options.ports.proxy; var ws = new websocket.WebSocket(uri + '/socket.io/websocket/', 'borf', { origin: options.protocol + '://' + options.host }); if (options.onWsupgrade) { ws.on('wsupgrade', options.onWsupgrade) } if (options.onMessage) { ws.on('message', options.onMessage) } if (options.onOpen) { ws.on('open', function () { options.onOpen(ws) }) } } ); }); } // // Creates the reverse proxy server // TestRunner.prototype.startProxyServer = function (port, targetPort, host, callback) { var that = this, proxyServer = httpProxy.createServer(host, targetPort, this.getOptions()); proxyServer.listen(port, function () { that.testServers.push(proxyServer); callback(null, proxyServer); }); }; // // Creates the reverse proxy server with a specified latency // TestRunner.prototype.startLatentProxyServer = function (port, targetPort, host, latency, callback) { // // Initialize the nodeProxy and start proxying the request // var that = this, proxyServer; proxyServer = httpProxy.createServer(host, targetPort, function (req, res, proxy) { var buffer = httpProxy.buffer(req); setTimeout(function () { proxy.proxyRequest(req, res, buffer); }, latency); }, this.getOptions()); proxyServer.listen(port, function () { that.testServers.push(proxyServer); callback(); }); }; // // Creates the reverse proxy server with a ProxyTable // TestRunner.prototype.startProxyServerWithTable = function (port, options, callback) { var that = this, proxyServer = httpProxy.createServer(merge({}, options, this.getOptions())); proxyServer.listen(port, function () { that.testServers.push(proxyServer); callback(); }); return proxyServer; }; // // Creates a latent reverse proxy server using a ProxyTable // TestRunner.prototype.startProxyServerWithTableAndLatency = function (port, latency, options, callback) { // // Initialize the nodeProxy and start proxying the request // var that = this, proxy = new httpProxy.HttpProxy(merge({}, options, this.getOptions())), proxyServer; var handler = function (req, res) { var buffer = proxy.buffer(req); setTimeout(function () { proxy.proxyRequest(req, res, { buffer: buffer }); }, latency); }; proxyServer = that.options.https ? https.createServer(that.options.https, handler, that.options) : http.createServer(handler, that.options); proxyServer.listen(port, function () { that.testServers.push(proxyServer); callback(); }); return proxyServer; }; // // Creates proxy server forwarding to the specified options // TestRunner.prototype.startProxyServerWithForwarding = function (port, targetPort, host, options, callback) { var that = this, proxyServer = httpProxy.createServer(targetPort, host, merge({}, options, this.getOptions())); proxyServer.listen(port, function () { that.testServers.push(proxyServer); callback(null, proxyServer); }); }; // // Creates the 'hellonode' server // TestRunner.prototype.startTargetServer = function (port, output, callback) { var that = this, targetServer, handler; handler = function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write(output); res.end(); }; targetServer = this.target.https ? https.createServer(this.target.https, handler) : http.createServer(handler); targetServer.listen(port, function () { that.testServers.push(targetServer); callback(null, targetServer); }); }; // // Close all of the testServers // TestRunner.prototype.closeServers = function () { this.testServers.forEach(function (server) { server.close(); }); return this.testServers; }; // // Creates a new instance of the options to // pass to `httpProxy.createServer()` // TestRunner.prototype.getOptions = function () { return { https: clone(this.source.https), target: { https: clone(this.target.https) } }; }; // // ### @private function clone (object) // #### @object {Object} Object to clone // Shallow clones the specified object. // function clone (object) { if (!object) { return null } return Object.keys(object).reduce(function (obj, k) { obj[k] = object[k]; return obj; }, {}); } function merge (target) { var objs = Array.prototype.slice.call(arguments, 1); objs.forEach(function(o) { Object.keys(o).forEach(function (attr) { if (! o.__lookupGetter__(attr)) { target[attr] = o[attr]; } }); }); return target; }