From 985025c90f3b2fafede64d8b17c318326f2423d9 Mon Sep 17 00:00:00 2001 From: Ivan Jaramillo Date: Mon, 8 Apr 2013 11:06:27 -0500 Subject: [PATCH 001/556] Add headers on 'handshake' The headers in the 'handshake' event were not written to the socket, the client received data but not the headers. --- lib/node-http-proxy/http-proxy.js | 45 +++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index 9ac8fa6fb..e44abaa0a 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -698,6 +698,15 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, socket: socket, head: head }; + + // + // Here we set the handshake `headers` and `statusCode` data to the outgoing + // request so that we can reuse this data later. + // + reverseProxy.handshake = { + headers: {}, + statusCode: null, + } // // If the agent for this particular `host` and `port` combination @@ -707,7 +716,16 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, // In addition, it's important to note the closure scope here. Since // there is no mapping of the socket to the request bound to it. // - reverseProxy.on('upgrade', function (_, remoteSocket, head) { + reverseProxy.on('upgrade', function ( res, remoteSocket, head) { + + // + // Prepare handshake response 'headers' and 'statusCode'. + // + reverseProxy.handshake = { + headers: res.headers, + statusCode: res.statusCode, + } + // // Prepare the socket for the reverseProxy request and begin to // stream data between the two sockets. Here it is important to @@ -723,6 +741,28 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, // reverseProxy.once('socket', function (revSocket) { revSocket.on('data', function handshake (data) { + + // Set empty headers + var headers = ''; + + // + // If the handshake statusCode 101, concat headers. + // + if(reverseProxy.handshake.statusCode && reverseProxy.handshake.statusCode == 101){ + + headers = [ + 'HTTP/1.1 101 Switching Protocols' + , 'Upgrade: websocket' + , 'Connection: Upgrade' + , 'Sec-WebSocket-Accept: ' + reverseProxy.handshake.headers['sec-websocket-accept'] + ]; + + headers = headers.concat('', '').join('\r\n'); + + } + + + // // Ok, kind of harmfull part of code. Socket.IO sends a hash // at the end of handshake if protocol === 76, but we need @@ -752,7 +792,8 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, // from the original incoming request. // self.emit('websocket:handshake', req, socket, head, sdata, data); - socket.write(sdata); + // add headers to the socket + socket.write(headers+sdata); var flushed = socket.write(data); if (!flushed) { revSocket.pause(); From 59b71c033f1bb3f38767f38eba8d6967ef0c8825 Mon Sep 17 00:00:00 2001 From: indexzero Date: Sun, 21 Apr 2013 17:01:20 -0400 Subject: [PATCH 002/556] [minor] Style compliance. Fixes #402. --- lib/node-http-proxy/http-proxy.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index e44abaa0a..351b795ac 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -716,8 +716,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, // In addition, it's important to note the closure scope here. Since // there is no mapping of the socket to the request bound to it. // - reverseProxy.on('upgrade', function ( res, remoteSocket, head) { - + reverseProxy.on('upgrade', function (res, remoteSocket, head) { // // Prepare handshake response 'headers' and 'statusCode'. // @@ -741,27 +740,22 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, // reverseProxy.once('socket', function (revSocket) { revSocket.on('data', function handshake (data) { - // Set empty headers var headers = ''; // // If the handshake statusCode 101, concat headers. // - if(reverseProxy.handshake.statusCode && reverseProxy.handshake.statusCode == 101){ - + if (reverseProxy.handshake.statusCode && reverseProxy.handshake.statusCode == 101) { headers = [ - 'HTTP/1.1 101 Switching Protocols' - , 'Upgrade: websocket' - , 'Connection: Upgrade' - , 'Sec-WebSocket-Accept: ' + reverseProxy.handshake.headers['sec-websocket-accept'] + 'HTTP/1.1 101 Switching Protocols', + 'Upgrade: websocket', + 'Connection: Upgrade', + 'Sec-WebSocket-Accept: ' + reverseProxy.handshake.headers['sec-websocket-accept'] ]; headers = headers.concat('', '').join('\r\n'); - } - - // // Ok, kind of harmfull part of code. Socket.IO sends a hash @@ -793,7 +787,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, // self.emit('websocket:handshake', req, socket, head, sdata, data); // add headers to the socket - socket.write(headers+sdata); + socket.write(headers + sdata); var flushed = socket.write(data); if (!flushed) { revSocket.pause(); From 7fc39d77f47311b82c24ab05f8e1a45a2733305c Mon Sep 17 00:00:00 2001 From: indexzero Date: Sun, 21 Apr 2013 17:02:18 -0400 Subject: [PATCH 003/556] [minor] Strip trailing whitespace. --- lib/node-http-proxy.js | 62 ++++++++++++++-------------- lib/node-http-proxy/http-proxy.js | 18 ++++---- lib/node-http-proxy/proxy-table.js | 4 +- lib/node-http-proxy/routing-proxy.js | 2 +- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/lib/node-http-proxy.js b/lib/node-http-proxy.js index 24c110831..956a5f3d3 100644 --- a/lib/node-http-proxy.js +++ b/lib/node-http-proxy.js @@ -82,7 +82,7 @@ exports.createServer = function () { case 'function': callback = arg; handlers.push(callback); break; }; }); - + // // Helper function to create intelligent error message(s) // for the very liberal arguments parsing performed by @@ -91,32 +91,32 @@ exports.createServer = function () { function validArguments() { var conditions = { 'port and host': function () { - return port && host; + return port && host; }, 'options.target or options.router': function () { - return options && (options.router || + return options && (options.router || (options.target && options.target.host && options.target.port)); }, 'or proxy handlers': function () { return handlers && handlers.length; } } - + var missing = Object.keys(conditions).filter(function (name) { return !conditions[name](); }); - + if (missing.length === 3) { message = 'Cannot proxy without ' + missing.join(', '); return false; } - + return true; - } - + } + if (!validArguments()) { // - // If `host`, `port` and `options` are all not passed (with valid + // If `host`, `port` and `options` are all not passed (with valid // options) then this server is improperly configured. // throw new Error(message); @@ -131,7 +131,7 @@ exports.createServer = function () { options.target = options.target || {}; options.target.port = options.target.port || port; options.target.host = options.target.host || host; - + if (options.target && options.target.host && options.target.port) { // // If an explicit `host` and `port` combination has been passed @@ -149,31 +149,31 @@ exports.createServer = function () { // we have to assume that this is a "go-anywhere" Proxy (i.e. a `RoutingProxy`). // proxy = new RoutingProxy(options); - + if (options.router) { // - // If a routing table has been supplied than we assume + // If a routing table has been supplied than we assume // the user intends us to add the "proxy" middleware layer - // for them + // for them // handlers.push(function (req, res) { proxy.proxyRequest(req, res); }); - + proxy.on('routes', function (routes) { server.emit('routes', routes); }); - } + } } - + // // Create the `http[s].Server` instance which will use // an instance of `httpProxy.HttpProxy`. // - handler = handlers.length > 1 + handler = handlers.length > 1 ? exports.stack(handlers, proxy) : function (req, res) { handlers[0](req, res, proxy) }; - + server = options.https ? https.createServer(options.https, handler) : http.createServer(handler); @@ -185,8 +185,8 @@ exports.createServer = function () { if (!callback) { // // If an explicit callback has not been supplied then - // automagically proxy the request using the `HttpProxy` - // instance we have created. + // automagically proxy the request using the `HttpProxy` + // instance we have created. // server.on('upgrade', function (req, socket, head) { proxy.proxyWebSocketRequest(req, socket, head); @@ -223,7 +223,7 @@ exports.createServer = function () { // exports.buffer = function (obj) { var events = [], - onData, + onData, onEnd; obj.on('data', onData = function (data, encoding) { @@ -244,7 +244,7 @@ exports.buffer = function (obj) { this.resume = function () { console.error("Cannot resume buffer after destroying it."); }; - + onData = onEnd = events = obj = null; }, resume: function () { @@ -279,10 +279,10 @@ exports.setMaxSockets = function (value) { // // ### function stack (middlewares, proxy) // #### @middlewares {Array} Array of functions to stack. -// #### @proxy {HttpProxy|RoutingProxy} Proxy instance to +// #### @proxy {HttpProxy|RoutingProxy} Proxy instance to // Iteratively build up a single handler to the `http.Server` // `request` event (i.e. `function (req, res)`) by wrapping -// each middleware `layer` into a `child` middleware which +// each middleware `layer` into a `child` middleware which // is in invoked by the parent (i.e. predecessor in the Array). // // adapted from https://github.com/creationix/stack @@ -296,17 +296,17 @@ exports.stack = function stack (middlewares, proxy) { if (err) { if (res._headerSent) { res.destroy(); - } + } else { res.statusCode = 500; res.setHeader('Content-Type', 'text/plain'); res.end('Internal Server Error'); } - + console.error('Error in middleware(s): %s', err.stack); return; } - + if (child) { child(req, res); } @@ -345,7 +345,7 @@ exports._getAgent = function _getAgent (options) { if (!options || !options.host) { throw new Error('`options.host` is required to create an Agent.'); } - + if (!options.port) { options.port = options.https ? 443 : 80; } @@ -364,8 +364,8 @@ exports._getAgent = function _getAgent (options) { // // ### function _getProtocol (options) // #### @options {Object} Options for the proxy target. -// Returns the appropriate node.js core protocol module (i.e. `http` or `https`) -// based on the `options` supplied. +// Returns the appropriate node.js core protocol module (i.e. `http` or `https`) +// based on the `options` supplied. // exports._getProtocol = function _getProtocol (options) { return options.https ? https : http; @@ -381,7 +381,7 @@ exports._getProtocol = function _getProtocol (options) { // exports._getBase = function _getBase (options) { var result = function () {}; - + if (options.https && typeof options.https === 'object') { ['ca', 'cert', 'key'].forEach(function (key) { if (options.https[key]) { diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index 351b795ac..0efb2fa3c 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -239,7 +239,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { if (this.changeOrigin) { outgoing.headers.host = this.target.host + ':' + this.target.port; } - + // // Open new HTTP request to internal resource with will act // as a reverse proxy pass @@ -366,7 +366,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { socket.setTimeout(self.timeout); } }); - + // // Handle 'error' events from the `req` (e.g. `Parse Error`). // @@ -448,7 +448,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, CRLF = '\r\n', //copy upgradeHead to avoid retention of large slab buffers used in node core head = new Buffer(upgradeHead.length); - upgradeHead.copy(head); + upgradeHead.copy(head); // // WebSocket requests must have the `GET` method and @@ -615,16 +615,16 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, detach(); // Emit the `end` event now that we have completed proxying - self.emit('websocket:end', req, socket, head); + self.emit('websocket:end', req, socket, head); } // // If the `reverseProxy` socket closes, then detach all // event listeners. - // + // listeners.onOutgoingClose = function () { proxySocket.destroy(); - detach(); + detach(); } proxySocket.on('end', listeners.onIncomingClose); @@ -698,7 +698,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, socket: socket, head: head }; - + // // Here we set the handshake `headers` and `statusCode` data to the outgoing // request so that we can reuse this data later. @@ -724,7 +724,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, headers: res.headers, statusCode: res.statusCode, } - + // // Prepare the socket for the reverseProxy request and begin to // stream data between the two sockets. Here it is important to @@ -756,7 +756,7 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, headers = headers.concat('', '').join('\r\n'); } - + // // Ok, kind of harmfull part of code. Socket.IO sends a hash // at the end of handshake if protocol === 76, but we need diff --git a/lib/node-http-proxy/proxy-table.js b/lib/node-http-proxy/proxy-table.js index 84b17a306..320396fe8 100644 --- a/lib/node-http-proxy/proxy-table.js +++ b/lib/node-http-proxy/proxy-table.js @@ -213,9 +213,9 @@ ProxyTable.prototype.getProxyLocation = function (req) { var target = req.url; for (var i in this.routes) { var route = this.routes[i]; - // + // // If we are matching pathname only, we remove the matched pattern. - // + // // IE /wiki/heartbeat // is redirected to // /heartbeat diff --git a/lib/node-http-proxy/routing-proxy.js b/lib/node-http-proxy/routing-proxy.js index a8d0eade5..72a0507f1 100644 --- a/lib/node-http-proxy/routing-proxy.js +++ b/lib/node-http-proxy/routing-proxy.js @@ -178,7 +178,7 @@ RoutingProxy.prototype.close = function () { // RoutingProxy.prototype.proxyRequest = function (req, res, options) { options = options || {}; - + var location; // From de0928f616dd62165e8a22c00d091cabf31e1e87 Mon Sep 17 00:00:00 2001 From: indexzero Date: Sun, 21 Apr 2013 17:06:54 -0400 Subject: [PATCH 004/556] [dist] Version bump. 0.10.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e1b9839d7..009702a85 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "0.10.1", + "version": "0.10.2", "description": "A full-featured http reverse proxy for node.js", "author": "Nodejitsu Inc. ", "maintainers": [ From 0c753234c0c85333f909bdbef034ffb6e192bad5 Mon Sep 17 00:00:00 2001 From: Emilien Kenler Date: Sat, 4 May 2013 22:48:50 +0200 Subject: [PATCH 005/556] Send path in req.path and not the url Signed-off-by: Emilien Kenler --- lib/node-http-proxy/http-proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index 0efb2fa3c..50eb88a46 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -228,7 +228,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { outgoing.socketPath = this.target.socketPath; outgoing.agent = this.target.agent; outgoing.method = req.method; - outgoing.path = req.url; + outgoing.path = url.parse(req.url).path; outgoing.headers = req.headers; // From f5e1844abd6f7a62d196025e126b6c3fbdbf34ac Mon Sep 17 00:00:00 2001 From: Raynos Date: Fri, 10 May 2013 17:55:01 -0600 Subject: [PATCH 006/556] Pass default certs to SNICallback example Using only SNICallback to create a HTTPS / TLS server is bad. It means all non SNI clients can't do anything because there are no certs. in v0.10 of node TLS server was updated to throw if you forgot to supply certs. Which means that every HTTPS server needs to supply certs as a fallback for when SNI is not available. - closes #399 --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 770a033ee..a7a8328c0 100644 --- a/README.md +++ b/README.md @@ -345,7 +345,10 @@ var options = { https: { SNICallback: function (hostname) { return certs[hostname]; - } + }, + cert: myCert, + key: myKey, + ca: [myCa] }, hostnameOnly: true, router: { From e1d384e769e9f4adc5a06c516cfb721ff24b4b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Ma=C5=82ecki?= Date: Thu, 20 Jun 2013 15:28:47 +0200 Subject: [PATCH 007/556] [fix] Respect `maxSockets` from `target` options in `RoutingProxy` --- lib/node-http-proxy/routing-proxy.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/node-http-proxy/routing-proxy.js b/lib/node-http-proxy/routing-proxy.js index 72a0507f1..b294fb15d 100644 --- a/lib/node-http-proxy/routing-proxy.js +++ b/lib/node-http-proxy/routing-proxy.js @@ -42,6 +42,7 @@ var RoutingProxy = exports.RoutingProxy = function (options) { // this.target = {}; this.target.https = options.target && options.target.https; + this.target.maxSockets = options.target && options.target.maxSockets; // // Setup other default options to be used for instances of @@ -91,6 +92,7 @@ RoutingProxy.prototype.add = function (options) { options.target.socketPath = options.target.socketPath || options.socketPath; options.target.https = this.target && this.target.https || options.target && options.target.https; + options.target.maxSockets = this.target && this.target.maxSockets; // // Setup options to pass-thru to the new `HttpProxy` instance From 2fd748fb61dac7de0daa50aabbface7033c6a222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Ma=C5=82ecki?= Date: Thu, 20 Jun 2013 15:29:14 +0200 Subject: [PATCH 008/556] [dist] Bump version to 0.10.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 009702a85..a2c31a02a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "0.10.2", + "version": "0.10.3", "description": "A full-featured http reverse proxy for node.js", "author": "Nodejitsu Inc. ", "maintainers": [ From ebbba73eda49563ade09f38bdc8aef13d1cf6c00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Ma=C5=82ecki?= Date: Thu, 20 Jun 2013 15:37:48 +0200 Subject: [PATCH 009/556] [test] Test on newer version of node --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fb8c9bb9c..efd470846 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: node_js node_js: - - 0.6 - 0.8 + - "0.10" + - "0.11" notifications: email: From 4d131567211bcefc6ef0b0592d374fef7bd5abd8 Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 1 Aug 2013 10:50:39 +0200 Subject: [PATCH 010/556] [dist] first --- .gitignore | 2 ++ index.js | 1 + lib/caronte.js | 61 ++++++++++++++++++++++++++++++++++ lib/caronte/index.js | 4 +++ lib/caronte/streams/forward.js | 3 ++ lib/caronte/streams/proxy.js | 3 ++ lib/caronte/web.js | 25 ++++++++++++++ lib/caronte/web/index.js | 56 +++++++++++++++++++++++++++++++ package.json | 22 ++++++++++++ 9 files changed, 177 insertions(+) create mode 100644 .gitignore create mode 100644 index.js create mode 100644 lib/caronte.js create mode 100644 lib/caronte/index.js create mode 100644 lib/caronte/streams/forward.js create mode 100644 lib/caronte/streams/proxy.js create mode 100644 lib/caronte/web.js create mode 100644 lib/caronte/web/index.js create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..1bd722694 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +*.swp diff --git a/index.js b/index.js new file mode 100644 index 000000000..7007beda1 --- /dev/null +++ b/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/caronte'); \ No newline at end of file diff --git a/lib/caronte.js b/lib/caronte.js new file mode 100644 index 000000000..97e2411b6 --- /dev/null +++ b/lib/caronte.js @@ -0,0 +1,61 @@ +var http = require('http'), + https = require('https'), + url = require('url'), + caronte = require('./caronte'), + events = require('eventemitter2'), + proxy = exports; + +/** + * Creates the proxy server. + * + * Examples: + * + * caronte.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 + */ + +proxy.createProxyServer = function createProxyServer(options) { + if(!options) { + throw new Error([ + "`options` is needed and it must have the following layout:", + " ", + " { ", + " target : ", + " forward: ", + " ssl : ", + " ws : ", + " xfwd : ", + " } ", + " ", + "NOTE: `options.ws` and `options.ssl` are optional ", + " either one or both `options.target` and ", + " `options.forward` must exist " + ].join("\n")); + } + + ['target', 'forward'].forEach(function(key) { + options[key] = url.parse(options[key]); + }); + + return { + __proto__: new events.EventEmitter2({ wildcard: true, delimiter: ':' }), + web : caronte.createWebProxy(options), + ws : caronte.createWsProxy(options), + listen : function listen(port) { + var server = options.ssl ? http.createServer(this.web) : https.createServer(options.ssl, this.web); + + if(options.ws) { + server.on('upgrade', this.ws); + } + + return server; + } + }; +}; + diff --git a/lib/caronte/index.js b/lib/caronte/index.js new file mode 100644 index 000000000..25b4984c8 --- /dev/null +++ b/lib/caronte/index.js @@ -0,0 +1,4 @@ +var caronte = exports; + +caronte.createWebProxy = require('./web'); +caronte.createWsProxy = require('./ws'); \ No newline at end of file diff --git a/lib/caronte/streams/forward.js b/lib/caronte/streams/forward.js new file mode 100644 index 000000000..d813e1cc6 --- /dev/null +++ b/lib/caronte/streams/forward.js @@ -0,0 +1,3 @@ +function ForwardStream() { + +} \ No newline at end of file diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js new file mode 100644 index 000000000..8d1f0672f --- /dev/null +++ b/lib/caronte/streams/proxy.js @@ -0,0 +1,3 @@ +function ProxyStream() { + +} \ No newline at end of file diff --git a/lib/caronte/web.js b/lib/caronte/web.js new file mode 100644 index 000000000..3c76b3ab1 --- /dev/null +++ b/lib/caronte/web.js @@ -0,0 +1,25 @@ +var passes = require('./web/'); + +module.exports = createWebProxy; + +function createWebProxy(options) { + passes = Object.keys(passes).map(function(pass) { + return passes[pass]; + }); + + return function(req, res) { + var self = this; + + self.emit('caronte:web:begin', req, res); + + passes.forEach(function(pass) { + var event = 'caronte:web:' + pass.name.toLowerCase(); + + self.emit(event + ':begin', req, res); + pass(req, res, options); + self.emit(event + ':end'); + }); + + self.emit('caronte:web:end'); + }; +}; \ No newline at end of file diff --git a/lib/caronte/web/index.js b/lib/caronte/web/index.js new file mode 100644 index 000000000..f0d9426ea --- /dev/null +++ b/lib/caronte/web/index.js @@ -0,0 +1,56 @@ +var ForwardStream = require('../streams/forward'), + ProxyStream = require('../streams/proxy'), + passes = exports; + +/*! + * List 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. + * + */ + +passes.XHeaders = XHeaders; +passes.deleteLength = deleteLength; +passes.timeout = timeout; +passes.stream = stream; + +function deleteLength(req, res, options) { + if(req.method === 'DELETE' && !req.headers['content-length']) { + req.headers['content-length'] = '0'; + } +} + +function timeout(req, res, options) { + if(options.timeout) { + req.socket.setTimeout(options.timeout); + } +} + +function XHeaders(req, res, options) { + var values = { + for : req.connection.remoteAddress || req.socket.remoteAddress, + port : req.connection.remotePort || req.socket.remotePort, + 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] + }); +} + +function stream(req, res, options) { + if(options.forward) { + req.pipe(new ForwardStream(options.forward)); + } + + if(options.target) { + return req.pipe(new ProxyStream(res, options)).pipe(res); + } + + res.end(); +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 000000000..67ab1fd14 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name" : "caronte", + "version" : "0.0.0", + "description" : "HTTP proxying for the masses", + "author" : "yawnt ", + + "main" : "index.js", + + "dependencies" : { + "eventemitter2": "*" + }, + "devDependencies": { + "mocha" : "*", + "expect.js": "*", + "dox" : "*" + }, + "scripts" : { + "test" : "mocha -t 20000 -R spec -r expect test/*-test.js" + }, + + "license" : "MIT" +} From 8273cb6461e4d33f36e583b0354d1bea038d0a56 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 3 Aug 2013 08:47:07 +0200 Subject: [PATCH 011/556] [refactor] move to leaner architecture --- index.js | 9 ++++++ lib/caronte.js | 6 ++-- lib/caronte/index.js | 36 +++++++++++++++++++-- lib/caronte/{web/index.js => passes/web.js} | 15 +++++---- lib/caronte/web.js | 25 -------------- 5 files changed, 53 insertions(+), 38 deletions(-) rename lib/caronte/{web/index.js => passes/web.js} (89%) delete mode 100644 lib/caronte/web.js diff --git a/index.js b/index.js index 7007beda1..5c73968f3 100644 --- a/index.js +++ b/index.js @@ -1 +1,10 @@ +/*! + * + * 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/caronte'); \ No newline at end of file diff --git a/lib/caronte.js b/lib/caronte.js index 97e2411b6..a06306008 100644 --- a/lib/caronte.js +++ b/lib/caronte.js @@ -33,9 +33,9 @@ proxy.createProxyServer = function createProxyServer(options) { " xfwd : ", " } ", " ", - "NOTE: `options.ws` and `options.ssl` are optional ", - " either one or both `options.target` and ", - " `options.forward` must exist " + "NOTE: `options.ws` and `options.ssl` are optional. ", + " `options.target and `options.forward` cannot be ", + " both missing " ].join("\n")); } diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 25b4984c8..7304850d1 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -1,4 +1,34 @@ -var caronte = exports; +var caronte = exports, + web = require('./passes/web'); + ws = require('./passes/ws'); + +caronte.createWebProxy = createRightProxy('web'); +caronte.createWsProxy = createRightProxy('ws'); + +function createRightProxy(type) { + passes = type === 'ws' ? ws : web; + return function(options) { + + passes = Object.keys(passes).map(function(pass) { + return passes[pass]; + }); + + return function(req, res) { + var self = this, + ev = 'caronte:' + type + ':'; + + self.emit(ev + 'begin', req, res); + + passes.forEach(function(pass) { + var event = ev + pass.name.toLowerCase(); + + self.emit(event + 'begin', req, res); + pass(req, res, options); + self.emit(event + 'end'); + }); + + self.emit(ev + 'end'); + }; + }; +} -caronte.createWebProxy = require('./web'); -caronte.createWsProxy = require('./ws'); \ No newline at end of file diff --git a/lib/caronte/web/index.js b/lib/caronte/passes/web.js similarity index 89% rename from lib/caronte/web/index.js rename to lib/caronte/passes/web.js index f0d9426ea..be6753ccc 100644 --- a/lib/caronte/web/index.js +++ b/lib/caronte/passes/web.js @@ -3,18 +3,14 @@ var ForwardStream = require('../streams/forward'), passes = exports; /*! - * List of passes. + * 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. - * */ -passes.XHeaders = XHeaders; -passes.deleteLength = deleteLength; -passes.timeout = timeout; -passes.stream = stream; +[ // <-- function deleteLength(req, res, options) { if(req.method === 'DELETE' && !req.headers['content-length']) { @@ -53,4 +49,9 @@ function stream(req, res, options) { } res.end(); -} \ No newline at end of file +} + +] // <-- + .forEach(function(func) { + passes[func.name] = func; + }); \ No newline at end of file diff --git a/lib/caronte/web.js b/lib/caronte/web.js deleted file mode 100644 index 3c76b3ab1..000000000 --- a/lib/caronte/web.js +++ /dev/null @@ -1,25 +0,0 @@ -var passes = require('./web/'); - -module.exports = createWebProxy; - -function createWebProxy(options) { - passes = Object.keys(passes).map(function(pass) { - return passes[pass]; - }); - - return function(req, res) { - var self = this; - - self.emit('caronte:web:begin', req, res); - - passes.forEach(function(pass) { - var event = 'caronte:web:' + pass.name.toLowerCase(); - - self.emit(event + ':begin', req, res); - pass(req, res, options); - self.emit(event + ':end'); - }); - - self.emit('caronte:web:end'); - }; -}; \ No newline at end of file From d05af4af60a5f3d308aa68bf09ab0cf9e5528c52 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 3 Aug 2013 15:45:07 +0200 Subject: [PATCH 012/556] [refactor docs] add descriptions --- lib/caronte/common.js | 32 ++++++++++++++ lib/caronte/index.js | 16 +++++++ lib/caronte/passes/web.js | 44 +++++++++++++++++++ lib/caronte/streams/forward.js | 80 +++++++++++++++++++++++++++++++++- 4 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 lib/caronte/common.js diff --git a/lib/caronte/common.js b/lib/caronte/common.js new file mode 100644 index 000000000..7028bb171 --- /dev/null +++ b/lib/caronte/common.js @@ -0,0 +1,32 @@ +var common = exports; + +/** + * 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 + *  + * @return {Object} Outgoing Object with all required properties set + * + * @api private + */ + +common.setupOutgoing = function(outgoing, options, req) { + ['host', 'hostname', 'port', 'socketPath', 'agent'].forEach( + function(e) { outgoing[e] = options[e]; } + ); + + ['method', 'path', 'headers'].forEach( + function(e) { outgoing[e] = req[e]; } + ); + + return outgoing; +}; \ No newline at end of file diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 7304850d1..0b9f544c0 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -5,6 +5,22 @@ var caronte = exports, caronte.createWebProxy = createRightProxy('web'); caronte.createWsProxy = createRightProxy('ws'); +/** + * Returns a function that creates the loader for + * either `ws` or `web`'s passes. + * + * Examples: + * + * caronte.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) { passes = type === 'ws' ? ws : web; return function(options) { diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web.js index be6753ccc..c15f4e192 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web.js @@ -12,19 +12,51 @@ var ForwardStream = require('../streams/forward'), [ // <-- +/** + * 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 : req.connection.remotePort || req.socket.remotePort, @@ -39,6 +71,18 @@ function XHeaders(req, res, options) { }); } +/** + * 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) { if(options.forward) { req.pipe(new ForwardStream(options.forward)); diff --git a/lib/caronte/streams/forward.js b/lib/caronte/streams/forward.js index d813e1cc6..640c75d01 100644 --- a/lib/caronte/streams/forward.js +++ b/lib/caronte/streams/forward.js @@ -1,3 +1,79 @@ +var Writable = require('stream').Writable, + common = require('../common'), + http = require('http'), + https = require('https'); + +module.exports = ForwardStream; + +/** + * Forwards the request to the external target specified in options + * + * Examples: + * + * new ForwardStream(options) + * // => { ... } + * + * @param {Object} Options Config object passed to the proxy + *  + * @return {ForwardStream} Stream A clone of ForwardStream + * + * @api private + */ + function ForwardStream() { - -} \ No newline at end of file + Writable.call(this); + + this.once('pipe', this.onPipe); + this.once('finish', this.onFinish); +} + +/** + * Fires up the request to the external target + * + * Examples: + * + * (new ForwardStream(options)).onPipe(req) + * // => undefined + * + * @param {HttpRequest} Req Request object + * + * @api private + */ + +ForwardStream.prototype.onPipe = function(request) { + this.forwardReq = (options.ssl ? https : http).request( + common.setupOutgoing(options.ssl || {}, options, request); + ); +}; + +/** + * Closes forwarded request when `pipe` is finished + * + * Examples: + * + * (new ForwardStream(options)).onFinish() + * // => undefined + * + * @api private + */ + +ForwardStream.prototype.onFinish = function() { + this.forwardReq.end(); +}; + +/** + * Implements `stream.Writable`, writes to the forwarded request + * + * Examples: + * + * (new ForwardStream(options))._write(chunk, encoding, clb) + * // => undefined + * + * @api private + */ + +ForwardStream.prototype._write = function(chunk, encoding, clb) { + this.forwardReq.write(chunk, encoding, clb); +}; + +require('util').inherits(ForwardStream, Writable); \ No newline at end of file From 34f16e74647095199f84ab61e10c8dafd60b505a Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 3 Aug 2013 15:56:05 +0200 Subject: [PATCH 013/556] [fix] making @stoke a happy camper --- index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 5c73968f3..68de922bd 100644 --- a/index.js +++ b/index.js @@ -1,10 +1,13 @@ /*! + * 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/caronte'); \ No newline at end of file From 004a46c09df2f0f7b15d8e8f7119bc6039e0c01c Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 3 Aug 2013 16:44:23 +0200 Subject: [PATCH 014/556] [test] COVERAGE --- package.json | 15 ++++++++++----- test/truth-test.js | 8 ++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 test/truth-test.js diff --git a/package.json b/package.json index 67ab1fd14..8cef91a7f 100644 --- a/package.json +++ b/package.json @@ -7,15 +7,20 @@ "main" : "index.js", "dependencies" : { - "eventemitter2": "*" + "eventemitter2" : "*" }, "devDependencies": { - "mocha" : "*", - "expect.js": "*", - "dox" : "*" + "mocha" : "*", + "expect.js" : "*", + "dox" : "*", + "coveralls" : "*", + "mocha-lcov-reporter": "*", + "blanket" : "*" }, "scripts" : { - "test" : "mocha -t 20000 -R spec -r expect test/*-test.js" + "blanket" : { "pattern": "caronte/lib" }, + "test" : "mocha -R spec test/*-test.js && npm run-script test-cov", + "test-cov" : "mocha --require blanket -R html-cov > cov/coverage.html" }, "license" : "MIT" diff --git a/test/truth-test.js b/test/truth-test.js new file mode 100644 index 000000000..437df3432 --- /dev/null +++ b/test/truth-test.js @@ -0,0 +1,8 @@ +var caronte = require('../'), + expect = require('expect.js'); + +describe('the truthness', function() { + it('should be true', function() { + expect(true).to.be(true); + }) +}); From 16eacfa961d2a2d80534e95eba83010ed6ab01b4 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 3 Aug 2013 16:54:48 +0200 Subject: [PATCH 015/556] [test] started writing tests --- test/lib-caronte-test.js | 27 +++++++++++++++++++++++++++ test/truth-test.js | 8 -------- 2 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 test/lib-caronte-test.js delete mode 100644 test/truth-test.js diff --git a/test/lib-caronte-test.js b/test/lib-caronte-test.js new file mode 100644 index 000000000..8358c5f99 --- /dev/null +++ b/test/lib-caronte-test.js @@ -0,0 +1,27 @@ +var caronte = require('../lib/caronte'), + expect = require('expect.js'); + +describe('lib/caronte.js', function() { + describe('#createProxyServer', function() { + it('should throw without options', function() { + var error; + try { + caronte.createProxyServer(); + } catch(e) { + error = e; + } + + expect(error).to.be.an(Error); + }) + + it('should return an object otherwise', function() { + var obj = caronte.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); + }); + }); +}); diff --git a/test/truth-test.js b/test/truth-test.js deleted file mode 100644 index 437df3432..000000000 --- a/test/truth-test.js +++ /dev/null @@ -1,8 +0,0 @@ -var caronte = require('../'), - expect = require('expect.js'); - -describe('the truthness', function() { - it('should be true', function() { - expect(true).to.be(true); - }) -}); From a255f984fecf24c9290f3ad58d1b68e54a7509eb Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 9 Aug 2013 18:58:56 +0200 Subject: [PATCH 016/556] [fix] tests --- cov/coverage.html | 341 +++++++++++++++++++++++++++++++++ lib/caronte.js | 3 +- lib/caronte/passes/web.js | 6 +- lib/caronte/passes/ws.js | 1 + lib/caronte/streams/forward.js | 2 +- 5 files changed, 348 insertions(+), 5 deletions(-) create mode 100644 cov/coverage.html create mode 100644 lib/caronte/passes/ws.js diff --git a/cov/coverage.html b/cov/coverage.html new file mode 100644 index 000000000..edbc970e0 --- /dev/null +++ b/cov/coverage.html @@ -0,0 +1,341 @@ +Coverage +

Coverage

44%
67
30
37

/Users/yawnt/Codes/caronte/lib/caronte.js

66%
12
8
4
LineHitsSource
11var http = require('http'),
2 https = require('https'),
3 url = require('url'),
4 caronte = require('./caronte/'),
5 events = require('eventemitter2'),
6 proxy = exports;
7
8/**
9 * Creates the proxy server.
10 *
11 * Examples:
12 *
13 * caronte.createProxyServer({ .. }, 8000)
14 * // => '{ web: [Function], ws: [Function] ... }'
15 *
16 * @param {Object} Options Config object passed to the proxy
17 *
18 * @return {Object} Proxy Proxy object with handlers for `ws` and `web` requests
19 *
20 * @api public
21 */
22
231proxy.createProxyServer = function createProxyServer(options) {
242 if(!options) {
251 throw new Error([
26 "`options` is needed and it must have the following layout:",
27 " ",
28 " { ",
29 " target : <url string to be parsed with the url module> ",
30 " forward: <url string to be parsed with the url module> ",
31 " ssl : <object to be passed to https.createServer()> ",
32 " ws : <true/false, if you want to proxy websockets> ",
33 " xfwd : <true/false, adds x-forward headers> ",
34 " } ",
35 " ",
36 "NOTE: `options.ws` and `options.ssl` are optional. ",
37 " `options.target and `options.forward` cannot be ",
38 " both missing "
39 ].join("\n"));
40 }
41
421 ['target', 'forward'].forEach(function(key) {
433 if(!options[key]) return;
441 options[key] = url.parse(options[key]);
45 });
46
471 return {
48 __proto__: new events.EventEmitter2({ wildcard: true, delimiter: ':' }),
49 web : caronte.createWebProxy(options),
50 ws : caronte.createWsProxy(options),
51 listen : function listen(port) {
520 var server = options.ssl ? http.createServer(this.web) : https.createServer(options.ssl, this.web);
53
540 if(options.ws) {
550 server.on('upgrade', this.ws);
56 }
57
580 return server;
59 }
60 };
61};
62
63

/Users/yawnt/Codes/caronte/lib/caronte/common.js

28%
7
2
5
LineHitsSource
11var common = exports;
2
3/**
4 * Copies the right headers from `options` and `req` to
5 * `outgoing` which is then used to fire the proxied
6 * request.
7 *
8 * Examples:
9 *
10 * common.setupOutgoing(outgoing, options, req)
11 * // => { host: ..., hostname: ...}
12 *
13 * @param {Object} Outgoing Base object to be filled with required properties
14 * @param {Object} Options Config object passed to the proxy
15 * @param {ClientRequest} Req Request Object
16
17 * @return {Object} Outgoing Object with all required properties set
18 *
19 * @api private
20 */
21
221common.setupOutgoing = function(outgoing, options, req) {
230 ['host', 'hostname', 'port', 'socketPath', 'agent'].forEach(
240 function(e) { outgoing[e] = options[e]; }
25 );
26
270 ['method', 'path', 'headers'].forEach(
280 function(e) { outgoing[e] = req[e]; }
29 );
30
310 return outgoing;
32};

/Users/yawnt/Codes/caronte/lib/caronte/index.js

50%
18
9
9
LineHitsSource
11var caronte = exports,
2 web = require('./passes/web');
31 ws = require('./passes/ws');
4
51caronte.createWebProxy = createRightProxy('web');
61caronte.createWsProxy = createRightProxy('ws');
7
8/**
9 * Returns a function that creates the loader for
10 * either `ws` or `web`'s passes.
11 *
12 * Examples:
13 *
14 * caronte.createRightProxy('ws')
15 * // => [Function]
16 *
17 * @param {String} Type Either 'ws' or 'web'
18
19 * @return {Function} Loader Function that when called returns an iterator for the right passes
20 *
21 * @api private
22 */
23
241function createRightProxy(type) {
252 passes = type === 'ws' ? ws : web;
262 return function(options) {
27
282 passes = Object.keys(passes).map(function(pass) {
290 return passes[pass];
30 });
31
322 return function(req, res) {
330 var self = this,
34 ev = 'caronte:' + type + ':';
35
360 self.emit(ev + 'begin', req, res);
37
380 passes.forEach(function(pass) {
390 var event = ev + pass.name.toLowerCase();
40
410 self.emit(event + 'begin', req, res);
420 pass(req, res, options);
430 self.emit(event + 'end');
44 });
45
460 self.emit(ev + 'end');
47 };
48 };
49}
50
51

/Users/yawnt/Codes/caronte/lib/caronte/passes/web.js

18%
16
3
13
LineHitsSource
11var ForwardStream = require('../streams/forward'),
2 ProxyStream = require('../streams/proxy'),
3 passes = exports;
4
5/*!
6 * Array of passes.
7 *
8 * A `pass` is just a function that is executed on `req, res, options`
9 * so that you can easily add new checks while still keeping the base
10 * flexible.
11 */
12
131[ // <--
14
15/**
16 * Sets `content-length` to '0' if request is of DELETE type.
17 *
18 * @param {ClientRequest} Req Request object
19 * @param {IncomingMessage} Res Response object
20 * @param {Object} Options Config object passed to the proxy
21 *
22 * @api private
23 */
24
25function deleteLength(req, res, options) {
260 if(req.method === 'DELETE' && !req.headers['content-length']) {
270 req.headers['content-length'] = '0';
28 }
29},
30
31/**
32 * Sets timeout in request socket if it was specified in options.
33 *
34 * @param {ClientRequest} Req Request object
35 * @param {IncomingMessage} Res Response object
36 * @param {Object} Options Config object passed to the proxy
37 *
38 * @api private
39 */
40
41function timeout(req, res, options) {
420 if(options.timeout) {
430 req.socket.setTimeout(options.timeout);
44 }
45},
46
47/**
48 * Sets `x-forwarded-*` headers if specified in config.
49 *
50 * @param {ClientRequest} Req Request object
51 * @param {IncomingMessage} Res Response object
52 * @param {Object} Options Config object passed to the proxy
53 *
54 * @api private
55 */
56
57function XHeaders(req, res, options) {
580 if(!options.xfwd) return;
59
600 var values = {
61 for : req.connection.remoteAddress || req.socket.remoteAddress,
62 port : req.connection.remotePort || req.socket.remotePort,
63 proto: req.isSpdy ? 'https' : (req.connection.pair ? 'https' : 'http')
64 };
65
660 ['for', 'port', 'proto'].forEach(function(header) {
670 req.headers['x-forwarded-' + header] =
68 (req.headers['x-forwarded-' + header] || '') +
69 (req.headers['x-forwarded-' + header] ? ',' : '') +
70 values[header]
71 });
72},
73
74/**
75 * Does the actual proxying. If `forward` is enabled fires up
76 * a ForwardStream, same happens for ProxyStream. The request
77 * just dies otherwise.
78 *
79 * @param {ClientRequest} Req Request object
80 * @param {IncomingMessage} Res Response object
81 * @param {Object} Options Config object passed to the proxy
82 *
83 * @api private
84 */
85
86function stream(req, res, options) {
870 if(options.forward) {
880 req.pipe(new ForwardStream(options.forward));
89 }
90
910 if(options.target) {
920 return req.pipe(new ProxyStream(res, options)).pipe(res);
93 }
94
950 res.end();
96}
97
98] // <--
99 .forEach(function(func) {
1004 passes[func.name] = func;
101 });

/Users/yawnt/Codes/caronte/lib/caronte/passes/ws.js

0%
0
0
0
LineHitsSource
1// ws

/Users/yawnt/Codes/caronte/lib/caronte/streams/forward.js

53%
13
7
6
LineHitsSource
11var Writable = require('stream').Writable,
2 common = require('../common'),
3 http = require('http'),
4 https = require('https');
5
61module.exports = ForwardStream;
7
8/**
9 * Forwards the request to the external target specified in options
10 *
11 * Examples:
12 *
13 * new ForwardStream(options)
14 * // => { ... }
15 *
16 * @param {Object} Options Config object passed to the proxy
17
18 * @return {ForwardStream} Stream A clone of ForwardStream
19 *
20 * @api private
21 */
22
231function ForwardStream() {
240 Writable.call(this);
25
260 this.once('pipe', this.onPipe);
270 this.once('finish', this.onFinish);
28}
29
30/**
31 * Fires up the request to the external target
32 *
33 * Examples:
34 *
35 * (new ForwardStream(options)).onPipe(req)
36 * // => undefined
37 *
38 * @param {HttpRequest} Req Request object
39 *
40 * @api private
41 */
42
431ForwardStream.prototype.onPipe = function(request) {
440 this.forwardReq = (options.ssl ? https : http).request(
45 common.setupOutgoing(options.ssl || {}, options, request)
46 );
47};
48
49/**
50 * Closes forwarded request when `pipe` is finished
51 *
52 * Examples:
53 *
54 * (new ForwardStream(options)).onFinish()
55 * // => undefined
56 *
57 * @api private
58 */
59
601ForwardStream.prototype.onFinish = function() {
610 this.forwardReq.end();
62};
63
64/**
65 * Implements `stream.Writable`, writes to the forwarded request
66 *
67 * Examples:
68 *
69 * (new ForwardStream(options))._write(chunk, encoding, clb)
70 * // => undefined
71 *
72 * @api private
73 */
74
751ForwardStream.prototype._write = function(chunk, encoding, clb) {
760 this.forwardReq.write(chunk, encoding, clb);
77};
78
791require('util').inherits(ForwardStream, Writable);

/Users/yawnt/Codes/caronte/lib/caronte/streams/proxy.js

100%
1
1
0
LineHitsSource
11function ProxyStream() {
2
3}
\ No newline at end of file diff --git a/lib/caronte.js b/lib/caronte.js index a06306008..c05701c91 100644 --- a/lib/caronte.js +++ b/lib/caronte.js @@ -1,7 +1,7 @@ var http = require('http'), https = require('https'), url = require('url'), - caronte = require('./caronte'), + caronte = require('./caronte/'), events = require('eventemitter2'), proxy = exports; @@ -40,6 +40,7 @@ proxy.createProxyServer = function createProxyServer(options) { } ['target', 'forward'].forEach(function(key) { + if(!options[key]) return; options[key] = url.parse(options[key]); }); diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web.js index c15f4e192..ea9e2d91b 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web.js @@ -26,7 +26,7 @@ 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. @@ -42,7 +42,7 @@ function timeout(req, res, options) { if(options.timeout) { req.socket.setTimeout(options.timeout); } -} +}, /** * Sets `x-forwarded-*` headers if specified in config. @@ -69,7 +69,7 @@ function XHeaders(req, res, options) { (req.headers['x-forwarded-' + header] ? ',' : '') + values[header] }); -} +}, /** * Does the actual proxying. If `forward` is enabled fires up diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js new file mode 100644 index 000000000..54e117ba5 --- /dev/null +++ b/lib/caronte/passes/ws.js @@ -0,0 +1 @@ +// ws \ No newline at end of file diff --git a/lib/caronte/streams/forward.js b/lib/caronte/streams/forward.js index 640c75d01..7ab802864 100644 --- a/lib/caronte/streams/forward.js +++ b/lib/caronte/streams/forward.js @@ -42,7 +42,7 @@ function ForwardStream() { ForwardStream.prototype.onPipe = function(request) { this.forwardReq = (options.ssl ? https : http).request( - common.setupOutgoing(options.ssl || {}, options, request); + common.setupOutgoing(options.ssl || {}, options, request) ); }; From 335af81d0244e62ecb501690bd15bc5a04ec51a3 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 9 Aug 2013 18:59:20 +0200 Subject: [PATCH 017/556] [minor] remove coverage --- .gitignore | 1 + cov/coverage.html | 341 ---------------------------------------------- 2 files changed, 1 insertion(+), 341 deletions(-) delete mode 100644 cov/coverage.html diff --git a/.gitignore b/.gitignore index 1bd722694..1a07e33df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules *.swp +cov diff --git a/cov/coverage.html b/cov/coverage.html deleted file mode 100644 index edbc970e0..000000000 --- a/cov/coverage.html +++ /dev/null @@ -1,341 +0,0 @@ -Coverage -

Coverage

44%
67
30
37

/Users/yawnt/Codes/caronte/lib/caronte.js

66%
12
8
4
LineHitsSource
11var http = require('http'),
2 https = require('https'),
3 url = require('url'),
4 caronte = require('./caronte/'),
5 events = require('eventemitter2'),
6 proxy = exports;
7
8/**
9 * Creates the proxy server.
10 *
11 * Examples:
12 *
13 * caronte.createProxyServer({ .. }, 8000)
14 * // => '{ web: [Function], ws: [Function] ... }'
15 *
16 * @param {Object} Options Config object passed to the proxy
17 *
18 * @return {Object} Proxy Proxy object with handlers for `ws` and `web` requests
19 *
20 * @api public
21 */
22
231proxy.createProxyServer = function createProxyServer(options) {
242 if(!options) {
251 throw new Error([
26 "`options` is needed and it must have the following layout:",
27 " ",
28 " { ",
29 " target : <url string to be parsed with the url module> ",
30 " forward: <url string to be parsed with the url module> ",
31 " ssl : <object to be passed to https.createServer()> ",
32 " ws : <true/false, if you want to proxy websockets> ",
33 " xfwd : <true/false, adds x-forward headers> ",
34 " } ",
35 " ",
36 "NOTE: `options.ws` and `options.ssl` are optional. ",
37 " `options.target and `options.forward` cannot be ",
38 " both missing "
39 ].join("\n"));
40 }
41
421 ['target', 'forward'].forEach(function(key) {
433 if(!options[key]) return;
441 options[key] = url.parse(options[key]);
45 });
46
471 return {
48 __proto__: new events.EventEmitter2({ wildcard: true, delimiter: ':' }),
49 web : caronte.createWebProxy(options),
50 ws : caronte.createWsProxy(options),
51 listen : function listen(port) {
520 var server = options.ssl ? http.createServer(this.web) : https.createServer(options.ssl, this.web);
53
540 if(options.ws) {
550 server.on('upgrade', this.ws);
56 }
57
580 return server;
59 }
60 };
61};
62
63

/Users/yawnt/Codes/caronte/lib/caronte/common.js

28%
7
2
5
LineHitsSource
11var common = exports;
2
3/**
4 * Copies the right headers from `options` and `req` to
5 * `outgoing` which is then used to fire the proxied
6 * request.
7 *
8 * Examples:
9 *
10 * common.setupOutgoing(outgoing, options, req)
11 * // => { host: ..., hostname: ...}
12 *
13 * @param {Object} Outgoing Base object to be filled with required properties
14 * @param {Object} Options Config object passed to the proxy
15 * @param {ClientRequest} Req Request Object
16
17 * @return {Object} Outgoing Object with all required properties set
18 *
19 * @api private
20 */
21
221common.setupOutgoing = function(outgoing, options, req) {
230 ['host', 'hostname', 'port', 'socketPath', 'agent'].forEach(
240 function(e) { outgoing[e] = options[e]; }
25 );
26
270 ['method', 'path', 'headers'].forEach(
280 function(e) { outgoing[e] = req[e]; }
29 );
30
310 return outgoing;
32};

/Users/yawnt/Codes/caronte/lib/caronte/index.js

50%
18
9
9
LineHitsSource
11var caronte = exports,
2 web = require('./passes/web');
31 ws = require('./passes/ws');
4
51caronte.createWebProxy = createRightProxy('web');
61caronte.createWsProxy = createRightProxy('ws');
7
8/**
9 * Returns a function that creates the loader for
10 * either `ws` or `web`'s passes.
11 *
12 * Examples:
13 *
14 * caronte.createRightProxy('ws')
15 * // => [Function]
16 *
17 * @param {String} Type Either 'ws' or 'web'
18
19 * @return {Function} Loader Function that when called returns an iterator for the right passes
20 *
21 * @api private
22 */
23
241function createRightProxy(type) {
252 passes = type === 'ws' ? ws : web;
262 return function(options) {
27
282 passes = Object.keys(passes).map(function(pass) {
290 return passes[pass];
30 });
31
322 return function(req, res) {
330 var self = this,
34 ev = 'caronte:' + type + ':';
35
360 self.emit(ev + 'begin', req, res);
37
380 passes.forEach(function(pass) {
390 var event = ev + pass.name.toLowerCase();
40
410 self.emit(event + 'begin', req, res);
420 pass(req, res, options);
430 self.emit(event + 'end');
44 });
45
460 self.emit(ev + 'end');
47 };
48 };
49}
50
51

/Users/yawnt/Codes/caronte/lib/caronte/passes/web.js

18%
16
3
13
LineHitsSource
11var ForwardStream = require('../streams/forward'),
2 ProxyStream = require('../streams/proxy'),
3 passes = exports;
4
5/*!
6 * Array of passes.
7 *
8 * A `pass` is just a function that is executed on `req, res, options`
9 * so that you can easily add new checks while still keeping the base
10 * flexible.
11 */
12
131[ // <--
14
15/**
16 * Sets `content-length` to '0' if request is of DELETE type.
17 *
18 * @param {ClientRequest} Req Request object
19 * @param {IncomingMessage} Res Response object
20 * @param {Object} Options Config object passed to the proxy
21 *
22 * @api private
23 */
24
25function deleteLength(req, res, options) {
260 if(req.method === 'DELETE' && !req.headers['content-length']) {
270 req.headers['content-length'] = '0';
28 }
29},
30
31/**
32 * Sets timeout in request socket if it was specified in options.
33 *
34 * @param {ClientRequest} Req Request object
35 * @param {IncomingMessage} Res Response object
36 * @param {Object} Options Config object passed to the proxy
37 *
38 * @api private
39 */
40
41function timeout(req, res, options) {
420 if(options.timeout) {
430 req.socket.setTimeout(options.timeout);
44 }
45},
46
47/**
48 * Sets `x-forwarded-*` headers if specified in config.
49 *
50 * @param {ClientRequest} Req Request object
51 * @param {IncomingMessage} Res Response object
52 * @param {Object} Options Config object passed to the proxy
53 *
54 * @api private
55 */
56
57function XHeaders(req, res, options) {
580 if(!options.xfwd) return;
59
600 var values = {
61 for : req.connection.remoteAddress || req.socket.remoteAddress,
62 port : req.connection.remotePort || req.socket.remotePort,
63 proto: req.isSpdy ? 'https' : (req.connection.pair ? 'https' : 'http')
64 };
65
660 ['for', 'port', 'proto'].forEach(function(header) {
670 req.headers['x-forwarded-' + header] =
68 (req.headers['x-forwarded-' + header] || '') +
69 (req.headers['x-forwarded-' + header] ? ',' : '') +
70 values[header]
71 });
72},
73
74/**
75 * Does the actual proxying. If `forward` is enabled fires up
76 * a ForwardStream, same happens for ProxyStream. The request
77 * just dies otherwise.
78 *
79 * @param {ClientRequest} Req Request object
80 * @param {IncomingMessage} Res Response object
81 * @param {Object} Options Config object passed to the proxy
82 *
83 * @api private
84 */
85
86function stream(req, res, options) {
870 if(options.forward) {
880 req.pipe(new ForwardStream(options.forward));
89 }
90
910 if(options.target) {
920 return req.pipe(new ProxyStream(res, options)).pipe(res);
93 }
94
950 res.end();
96}
97
98] // <--
99 .forEach(function(func) {
1004 passes[func.name] = func;
101 });

/Users/yawnt/Codes/caronte/lib/caronte/passes/ws.js

0%
0
0
0
LineHitsSource
1// ws

/Users/yawnt/Codes/caronte/lib/caronte/streams/forward.js

53%
13
7
6
LineHitsSource
11var Writable = require('stream').Writable,
2 common = require('../common'),
3 http = require('http'),
4 https = require('https');
5
61module.exports = ForwardStream;
7
8/**
9 * Forwards the request to the external target specified in options
10 *
11 * Examples:
12 *
13 * new ForwardStream(options)
14 * // => { ... }
15 *
16 * @param {Object} Options Config object passed to the proxy
17
18 * @return {ForwardStream} Stream A clone of ForwardStream
19 *
20 * @api private
21 */
22
231function ForwardStream() {
240 Writable.call(this);
25
260 this.once('pipe', this.onPipe);
270 this.once('finish', this.onFinish);
28}
29
30/**
31 * Fires up the request to the external target
32 *
33 * Examples:
34 *
35 * (new ForwardStream(options)).onPipe(req)
36 * // => undefined
37 *
38 * @param {HttpRequest} Req Request object
39 *
40 * @api private
41 */
42
431ForwardStream.prototype.onPipe = function(request) {
440 this.forwardReq = (options.ssl ? https : http).request(
45 common.setupOutgoing(options.ssl || {}, options, request)
46 );
47};
48
49/**
50 * Closes forwarded request when `pipe` is finished
51 *
52 * Examples:
53 *
54 * (new ForwardStream(options)).onFinish()
55 * // => undefined
56 *
57 * @api private
58 */
59
601ForwardStream.prototype.onFinish = function() {
610 this.forwardReq.end();
62};
63
64/**
65 * Implements `stream.Writable`, writes to the forwarded request
66 *
67 * Examples:
68 *
69 * (new ForwardStream(options))._write(chunk, encoding, clb)
70 * // => undefined
71 *
72 * @api private
73 */
74
751ForwardStream.prototype._write = function(chunk, encoding, clb) {
760 this.forwardReq.write(chunk, encoding, clb);
77};
78
791require('util').inherits(ForwardStream, Writable);

/Users/yawnt/Codes/caronte/lib/caronte/streams/proxy.js

100%
1
1
0
LineHitsSource
11function ProxyStream() {
2
3}
\ No newline at end of file From cedc5c4bd2059585e1222ec4f03f09e8bcc808fc Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 9 Aug 2013 19:13:44 +0200 Subject: [PATCH 018/556] [tests] add more tests --- lib/caronte/streams/forward.js | 12 +++++++----- package.json | 2 +- test/lib-caronte-common-test.js | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 test/lib-caronte-common-test.js diff --git a/lib/caronte/streams/forward.js b/lib/caronte/streams/forward.js index 7ab802864..b7e8ccd03 100644 --- a/lib/caronte/streams/forward.js +++ b/lib/caronte/streams/forward.js @@ -21,12 +21,16 @@ module.exports = ForwardStream; */ function ForwardStream() { + var self = this; + Writable.call(this); - this.once('pipe', this.onPipe); - this.once('finish', this.onFinish); + this.once('pipe', function() { self.onPipe() }); + this.once('finish', function() { self.onFinish() }); } +require('util').inherits(ForwardStream, Writable); + /** * Fires up the request to the external target * @@ -74,6 +78,4 @@ ForwardStream.prototype.onFinish = function() { ForwardStream.prototype._write = function(chunk, encoding, clb) { this.forwardReq.write(chunk, encoding, clb); -}; - -require('util').inherits(ForwardStream, Writable); \ No newline at end of file +}; \ No newline at end of file diff --git a/package.json b/package.json index 8cef91a7f..e2b3f25d1 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "scripts" : { "blanket" : { "pattern": "caronte/lib" }, - "test" : "mocha -R spec test/*-test.js && npm run-script test-cov", + "test" : "mocha -R landing test/*-test.js", "test-cov" : "mocha --require blanket -R html-cov > cov/coverage.html" }, diff --git a/test/lib-caronte-common-test.js b/test/lib-caronte-common-test.js new file mode 100644 index 000000000..b489c9ff7 --- /dev/null +++ b/test/lib-caronte-common-test.js @@ -0,0 +1,33 @@ +var common = require('../lib/caronte/common'), + expect = require('expect.js'); + +describe('lib/caronte/common.js', function() { + describe('#setupOutgoing', function() { + it('should setup the right headers', function() { + var outgoing = {}; + common.setupOutgoing(outgoing, + { + host : 'hey', + hostname : 'how', + socketPath: 'are', + port : 'you', + agent : '?' + }, + { + method : 'i', + path : 'am', + headers : 'proxy' + }); + + 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).to.eql('proxy') + }); + }); +}); \ No newline at end of file From 4f24664e8a50aa9b9a3ea155d067b85f94a8c81b Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 9 Aug 2013 19:37:58 +0200 Subject: [PATCH 019/556] [api] add draft for proxystream --- lib/caronte/streams/forward.js | 2 +- lib/caronte/streams/proxy.js | 39 +++++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/caronte/streams/forward.js b/lib/caronte/streams/forward.js index b7e8ccd03..f1f85c7e5 100644 --- a/lib/caronte/streams/forward.js +++ b/lib/caronte/streams/forward.js @@ -25,7 +25,7 @@ function ForwardStream() { Writable.call(this); - this.once('pipe', function() { self.onPipe() }); + this.once('pipe', function(pipe) { self.onPipe(pipe) }); this.once('finish', function() { self.onFinish() }); } diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js index 8d1f0672f..713550c84 100644 --- a/lib/caronte/streams/proxy.js +++ b/lib/caronte/streams/proxy.js @@ -1,3 +1,40 @@ +var Duplex = require('stream').Duplex, + common = require('../common'), + http = require('http'), + https = require('https'); + function ProxyStream() { + var self = this; + + Duplex.call(this); + + this.once('pipe', function(pipe) { self.onPipe(pipe); }); + this.once('finish', function() { self.onFinish(); }); +} + +ProxyStream.prototype.onPipe = function(request) { + var self = this; + + this.proxyReq = (options.ssl ? https : http).request( + common.setupOutgoing(options.ssl || {}, options, request) + ); + + this.proxyReq.once('response', function(response) { + self.onResponse(response); + }) + this.proxyReq.on('error', function() {}); // XXX TODO: add error handling +} + +ProxyStream.prototype.onFinish = function() { -} \ No newline at end of file +} + +ProxyStream.prototype.onResponse = function() { + +} + +ProxyStream.prototype._read = function() {} + +ProxyStream.prototype._write = function() {} + +require('util').inherits(ForwardStream, Duplex); \ No newline at end of file From 6a4294cbdfe85fa162969b1393032adc9d418441 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 9 Aug 2013 19:40:40 +0200 Subject: [PATCH 020/556] [feature] implement _write and _read --- lib/caronte/streams/proxy.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js index 713550c84..c6b75c498 100644 --- a/lib/caronte/streams/proxy.js +++ b/lib/caronte/streams/proxy.js @@ -29,12 +29,18 @@ ProxyStream.prototype.onFinish = function() { } -ProxyStream.prototype.onResponse = function() { - +ProxyStream.prototype.onResponse = function(proxyRes) { + this.proxyRes = proxyRes; } -ProxyStream.prototype._read = function() {} +ProxyStream.prototype._write = function(chunk, encoding, callback) { + this.proxyReq.write(chunk, encoding, callback); +}; + +ProxyStream.prototype._read = function(size) { + var chunk = (this.proxyRes ? this.proxyRes.read(size) : '') || ''; -ProxyStream.prototype._write = function() {} + this.push(chunk); +}; require('util').inherits(ForwardStream, Duplex); \ No newline at end of file From 2e7343d728a3187d48821b88ec2e2d4699bb2afe Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 9 Aug 2013 20:52:21 +0200 Subject: [PATCH 021/556] [fix] making @jcrugzz a happy camper --- lib/caronte/streams/proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js index c6b75c498..10afdaec1 100644 --- a/lib/caronte/streams/proxy.js +++ b/lib/caronte/streams/proxy.js @@ -21,7 +21,7 @@ ProxyStream.prototype.onPipe = function(request) { this.proxyReq.once('response', function(response) { self.onResponse(response); - }) + }); this.proxyReq.on('error', function() {}); // XXX TODO: add error handling } From bd3df45010f282997cae3a699c7ecb885c01bdf8 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 9 Aug 2013 20:52:55 +0200 Subject: [PATCH 022/556] [fix] woops --- lib/caronte/streams/proxy.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js index 10afdaec1..5112b436e 100644 --- a/lib/caronte/streams/proxy.js +++ b/lib/caronte/streams/proxy.js @@ -12,6 +12,8 @@ function ProxyStream() { this.once('finish', function() { self.onFinish(); }); } +require('util').inherits(ProxyStream, Duplex); + ProxyStream.prototype.onPipe = function(request) { var self = this; @@ -43,4 +45,3 @@ ProxyStream.prototype._read = function(size) { this.push(chunk); }; -require('util').inherits(ForwardStream, Duplex); \ No newline at end of file From 9ab8749a9bec33b49c495975e8364336ad7be1a3 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 10 Aug 2013 20:41:25 +0200 Subject: [PATCH 023/556] [feature] started working on error propagation, kinda sucks, gotta think it over --- lib/caronte/index.js | 2 +- lib/caronte/passes/web.js | 7 ++++--- lib/caronte/streams/forward.js | 9 +++++++-- lib/caronte/streams/proxy.js | 33 ++++++++++++++++++++++++--------- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 0b9f544c0..88f7368a7 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -39,7 +39,7 @@ function createRightProxy(type) { var event = ev + pass.name.toLowerCase(); self.emit(event + 'begin', req, res); - pass(req, res, options); + pass(req, res, options, self); self.emit(event + 'end'); }); diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web.js index ea9e2d91b..97c69afb2 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web.js @@ -79,17 +79,18 @@ function XHeaders(req, res, options) { * @param {ClientRequest} Req Request object * @param {IncomingMessage} Res Response object * @param {Object} Options Config object passed to the proxy + * @param {Object} Instance Proxy object that emits events * * @api private */ -function stream(req, res, options) { +function stream(req, res, options, instance) { if(options.forward) { - req.pipe(new ForwardStream(options.forward)); + req.pipe(new ForwardStream(options, instance)); } if(options.target) { - return req.pipe(new ProxyStream(res, options)).pipe(res); + return req.pipe(new ProxyStream(options, res, instance)).pipe(res); } res.end(); diff --git a/lib/caronte/streams/forward.js b/lib/caronte/streams/forward.js index f1f85c7e5..a3fe955b4 100644 --- a/lib/caronte/streams/forward.js +++ b/lib/caronte/streams/forward.js @@ -20,9 +20,12 @@ module.exports = ForwardStream; * @api private */ -function ForwardStream() { +function ForwardStream(options) { var self = this; + self.options = options; + self.res = res; + Writable.call(this); this.once('pipe', function(pipe) { self.onPipe(pipe) }); @@ -48,10 +51,12 @@ ForwardStream.prototype.onPipe = function(request) { this.forwardReq = (options.ssl ? https : http).request( common.setupOutgoing(options.ssl || {}, options, request) ); + + this.forwardReq.on('error', function() {}); /** Fire and forget */ }; /** - * Closes forwarded request when `pipe` is finished + * Closes forwarded request when `pipe` is finished. * * Examples: * diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js index 5112b436e..dad221639 100644 --- a/lib/caronte/streams/proxy.js +++ b/lib/caronte/streams/proxy.js @@ -3,7 +3,11 @@ var Duplex = require('stream').Duplex, http = require('http'), https = require('https'); -function ProxyStream() { +function ProxyStream(options, res, instance) { + this.options = options; + this.res = res; + this.instance = instance; + var self = this; Duplex.call(this); @@ -14,26 +18,37 @@ function ProxyStream() { require('util').inherits(ProxyStream, Duplex); -ProxyStream.prototype.onPipe = function(request) { +ProxyStream.prototype.onPipe = function(req) { + this.req = req; + var self = this; this.proxyReq = (options.ssl ? https : http).request( - common.setupOutgoing(options.ssl || {}, options, request) + common.setupOutgoing(options.ssl || {}, options, req) ); - this.proxyReq.once('response', function(response) { - self.onResponse(response); + this.proxyReq.once('response', function(proxyRes) { + self.onResponse(proxyRes); }); - this.proxyReq.on('error', function() {}); // XXX TODO: add error handling -} + this.proxyReq.on('error', function(e) { + self.onError(e); + }); +}; ProxyStream.prototype.onFinish = function() { -} +}; ProxyStream.prototype.onResponse = function(proxyRes) { this.proxyRes = proxyRes; -} +}; + +ProxyStream.prototype.onError = function(e) { + if(this.instance.emit('error', this.req, this.res, e)) return; + + this.res.writeHead(500, { 'Content-Type': 'text/plain' }); + this.res.end('Internal Server Error'); +}; ProxyStream.prototype._write = function(chunk, encoding, callback) { this.proxyReq.write(chunk, encoding, callback); From d4f0da898e5e8a2d6740e50a7fc34576435e1132 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 20 Aug 2013 16:09:37 +0200 Subject: [PATCH 024/556] [fix] some stuff start debugging proxystream --- .gitignore | 1 + lib/caronte.js | 8 ++++- lib/caronte/common.js | 4 +-- lib/caronte/index.js | 13 ++++---- lib/caronte/streams/proxy.js | 59 +++++++++++++++++++++++++++++++----- 5 files changed, 68 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 1a07e33df..9ace78b32 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules *.swp cov +ttest.js diff --git a/lib/caronte.js b/lib/caronte.js index c05701c91..81a25e469 100644 --- a/lib/caronte.js +++ b/lib/caronte.js @@ -31,6 +31,7 @@ proxy.createProxyServer = function createProxyServer(options) { " ssl : ", " ws : ", " xfwd : ", + " maxSock: ", " } ", " ", "NOTE: `options.ws` and `options.ssl` are optional. ", @@ -42,6 +43,9 @@ proxy.createProxyServer = function createProxyServer(options) { ['target', 'forward'].forEach(function(key) { if(!options[key]) return; options[key] = url.parse(options[key]); + + options[key].maxSockets = options.maxSock; + options[key].agent = new (options.ssl ? https.Agent : http.Agent)(options[key]); }); return { @@ -49,12 +53,14 @@ proxy.createProxyServer = function createProxyServer(options) { web : caronte.createWebProxy(options), ws : caronte.createWsProxy(options), listen : function listen(port) { - var server = options.ssl ? http.createServer(this.web) : https.createServer(options.ssl, this.web); + var server = options.ssl ? https.createServer(options.ssl, this.web) : http.createServer(this.web); if(options.ws) { server.on('upgrade', this.ws); } + server.listen(port); + return server; } }; diff --git a/lib/caronte/common.js b/lib/caronte/common.js index 7028bb171..59a1cf94b 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -20,8 +20,8 @@ var common = exports; */ common.setupOutgoing = function(outgoing, options, req) { - ['host', 'hostname', 'port', 'socketPath', 'agent'].forEach( - function(e) { outgoing[e] = options[e]; } + ['host', 'hostname', 'port', 'socketPath'/*, 'agent'*/].forEach( + function(e) { outgoing[e] = options.target[e]; } ); ['method', 'path', 'headers'].forEach( diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 88f7368a7..bf6160976 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -22,7 +22,8 @@ caronte.createWsProxy = createRightProxy('ws'); */ function createRightProxy(type) { - passes = type === 'ws' ? ws : web; + var passes = (type === 'ws') ? ws : web; + return function(options) { passes = Object.keys(passes).map(function(pass) { @@ -33,17 +34,17 @@ function createRightProxy(type) { var self = this, ev = 'caronte:' + type + ':'; - self.emit(ev + 'begin', req, res); + //self.emit(ev + 'begin', req, res); passes.forEach(function(pass) { - var event = ev + pass.name.toLowerCase(); + var evnt = ev + pass.name.toLowerCase(); - self.emit(event + 'begin', req, res); + //self.emit(evnt + 'begin', req, res); pass(req, res, options, self); - self.emit(event + 'end'); + //self.emit(evnt + 'end'); }); - self.emit(ev + 'end'); + //self.emit(ev + 'end'); }; }; } diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js index dad221639..6d67218f0 100644 --- a/lib/caronte/streams/proxy.js +++ b/lib/caronte/streams/proxy.js @@ -4,14 +4,14 @@ var Duplex = require('stream').Duplex, https = require('https'); function ProxyStream(options, res, instance) { + Duplex.call(this); + this.options = options; this.res = res; this.instance = instance; var self = this; - Duplex.call(this); - this.once('pipe', function(pipe) { self.onPipe(pipe); }); this.once('finish', function() { self.onFinish(); }); } @@ -23,11 +23,12 @@ ProxyStream.prototype.onPipe = function(req) { var self = this; - this.proxyReq = (options.ssl ? https : http).request( - common.setupOutgoing(options.ssl || {}, options, req) + this.proxyReq = (self.options.ssl ? https : http).request( + common.setupOutgoing(self.options.ssl || {}, self.options, req) ); - + //console.log(common.setupOutgoing(self.options.ssl || {}, self.options, req)); this.proxyReq.once('response', function(proxyRes) { + console.log(proxyRes); self.onResponse(proxyRes); }); this.proxyReq.on('error', function(e) { @@ -36,16 +37,57 @@ ProxyStream.prototype.onPipe = function(req) { }; ProxyStream.prototype.onFinish = function() { - + this.proxyReq.end(); }; ProxyStream.prototype.onResponse = function(proxyRes) { this.proxyRes = proxyRes; + + // rewrite + if(req.httpVersion === '1.0') { + res.headers.connection = req.headers.connection || 'close'; + } + else if(!res.headers.connection) { + res.headers.connection = req.headers.connection || 'keep-alive'; + } + + if(req.httpVersion === '1.0' || (req.method === 'DELETE' && !req.headers['content-length'])) { + delete res.headers['transfer-encoding']; + } + + if(~[301,302].indexOf(res.statusCode) && typeof res.headers.location !== 'undefined') { + var location = url.parse(res.headers.location); + if ( + location.host === req.headers.host && + ( + source.https && !target.https || + target.https && !source.https + ) + ) { + res.headers.location = res.headers.location.replace(/^https\:/, 'http:'); + } + } + + self.emit('proxyResponse', req, response, res); + + Object.keys(res.headers).forEach(function (key) { + response.setHeader(key, res.headers[key]); + }); + response.writeHead(response.statusCode); + + res.on('readable', function() { + self.read(0); + }); + + res.on('end', function() { + self.push(null); + }); + self.emit('readable'); }; ProxyStream.prototype.onError = function(e) { - if(this.instance.emit('error', this.req, this.res, e)) return; - + if(this.instance.emit('proxyError', this.req, this.res, e)) return; + this.res.writeHead(500, { 'Content-Type': 'text/plain' }); this.res.end('Internal Server Error'); }; @@ -60,3 +102,4 @@ ProxyStream.prototype._read = function(size) { this.push(chunk); }; +module.exports = ProxyStream; \ No newline at end of file From 356f43d719998d135e0fc404ac8508e330cf1e5b Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 20 Aug 2013 17:32:29 +0200 Subject: [PATCH 025/556] [fix] ProxyStraem now works --- lib/caronte/streams/proxy.js | 82 ++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js index 6d67218f0..2903c07c6 100644 --- a/lib/caronte/streams/proxy.js +++ b/lib/caronte/streams/proxy.js @@ -28,7 +28,6 @@ ProxyStream.prototype.onPipe = function(req) { ); //console.log(common.setupOutgoing(self.options.ssl || {}, self.options, req)); this.proxyReq.once('response', function(proxyRes) { - console.log(proxyRes); self.onResponse(proxyRes); }); this.proxyReq.on('error', function(e) { @@ -43,46 +42,47 @@ ProxyStream.prototype.onFinish = function() { ProxyStream.prototype.onResponse = function(proxyRes) { this.proxyRes = proxyRes; - // rewrite - if(req.httpVersion === '1.0') { - res.headers.connection = req.headers.connection || 'close'; - } - else if(!res.headers.connection) { - res.headers.connection = req.headers.connection || 'keep-alive'; - } - - if(req.httpVersion === '1.0' || (req.method === 'DELETE' && !req.headers['content-length'])) { - delete res.headers['transfer-encoding']; - } - - if(~[301,302].indexOf(res.statusCode) && typeof res.headers.location !== 'undefined') { - var location = url.parse(res.headers.location); - if ( - location.host === req.headers.host && - ( - source.https && !target.https || - target.https && !source.https - ) - ) { - res.headers.location = res.headers.location.replace(/^https\:/, 'http:'); - } - } - - self.emit('proxyResponse', req, response, res); - - Object.keys(res.headers).forEach(function (key) { - response.setHeader(key, res.headers[key]); - }); - response.writeHead(response.statusCode); - - res.on('readable', function() { - self.read(0); - }); - - res.on('end', function() { - self.push(null); - }); - self.emit('readable'); + var self = this; + + if(this.req.httpVersion === '1.0') { + proxyRes.headers.connection = this.req.headers.connection || 'close'; + } + else if(!proxyRes.headers.connection) { + proxyRes.headers.connection = this.req.headers.connection || 'keep-alive'; + } + + if(this.req.httpVersion === '1.0' || (this.req.method === 'DELETE' && !this.req.headers['content-length'])) { + delete proxyRes.headers['transfer-encoding']; + } + + /*if(~[301,302].indexOf(this.res.statusCode) && typeof this.res.headers.location !== 'undefined') { + var location = url.parse(this.res.headers.location); + if ( + location.host === this.req.headers.host && + ( + source.https && !target.https || + target.https && !source.https + ) + ) { + this.res.headers.location = this.res.headers.location.replace(/^https\:/, 'http:'); + } + }*/ + + Object.keys(proxyRes.headers).forEach(function (key) { + self.res.setHeader(key, proxyRes.headers[key]); + }); + + this.res.writeHead(proxyRes.statusCode); + + proxyRes.on('readable', function() { + self.read(0); + }); + + proxyRes.on('end', function() { + self.push(null); + }); + + self.emit('readable'); }; ProxyStream.prototype.onError = function(e) { From d40e4beb62381b962b6cf3254451de0a39f182b1 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 21 Aug 2013 17:37:38 +0200 Subject: [PATCH 026/556] [test] passes/web.js (first 2 funcs) --- .gitignore | 1 + test/lib-caronte-common-test.js | 14 ++++++++------ test/lib-caronte-passes-web-test.js | 28 ++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 test/lib-caronte-passes-web-test.js diff --git a/.gitignore b/.gitignore index 9ace78b32..52241f829 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules *.swp cov ttest.js +notes diff --git a/test/lib-caronte-common-test.js b/test/lib-caronte-common-test.js index b489c9ff7..3c2ccd109 100644 --- a/test/lib-caronte-common-test.js +++ b/test/lib-caronte-common-test.js @@ -7,11 +7,13 @@ describe('lib/caronte/common.js', function() { var outgoing = {}; common.setupOutgoing(outgoing, { - host : 'hey', - hostname : 'how', - socketPath: 'are', - port : 'you', - agent : '?' + target: { + host : 'hey', + hostname : 'how', + socketPath: 'are', + port : 'you', + agent : '?' + } }, { method : 'i', @@ -23,7 +25,7 @@ describe('lib/caronte/common.js', function() { 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.agent).to.eql('?'); expect(outgoing.method).to.eql('i'); expect(outgoing.path).to.eql('am'); diff --git a/test/lib-caronte-passes-web-test.js b/test/lib-caronte-passes-web-test.js new file mode 100644 index 000000000..b814612ed --- /dev/null +++ b/test/lib-caronte-passes-web-test.js @@ -0,0 +1,28 @@ +var caronte = require('../lib/caronte/passes/web'), + expect = require('expect.js'); + +describe('lib/caronte/passes/web.js', function() { + describe('#deleteLength', function() { + it('should change `content-length`', function() { + var stubRequest = { + method: 'DELETE', + headers: {} + }; + caronte.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; } + } + } + + caronte.timeout(stubRequest, {}, { timeout: 5000}); + expect(done).to.eql(5000); + }); + }); +}); From c02b721321c455bc287c3fed6b9b21392ce2fc70 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 26 Aug 2013 00:21:30 -0500 Subject: [PATCH 027/556] [test] passes/web.js XHeaders func --- test/lib-caronte-passes-web-test.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/lib-caronte-passes-web-test.js b/test/lib-caronte-passes-web-test.js index b814612ed..4ec5ca1a2 100644 --- a/test/lib-caronte-passes-web-test.js +++ b/test/lib-caronte-passes-web-test.js @@ -25,4 +25,21 @@ describe('lib/caronte/passes/web.js', function() { expect(done).to.eql(5000); }); }); + + describe('#XHeaders', function () { + var stubRequest = { + connection: { + remoteAddress: '192.168.1.2', + remotePort: '8080' + }, + headers: {} + } + + it('set the correct x-forwarded-* headers', function () { + caronte.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'); + }); + }); }); From 2fac7b9b009b12a940efb22de3af6db55ee686a9 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 26 Aug 2013 16:34:32 -0500 Subject: [PATCH 028/556] [test] added the lib/caronte/streams/forward.js initial test, one test pending --- lib/caronte/streams/forward.js | 4 ++- test/lib-caronte-streams-forward-test.js | 37 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 test/lib-caronte-streams-forward-test.js diff --git a/lib/caronte/streams/forward.js b/lib/caronte/streams/forward.js index a3fe955b4..665a91927 100644 --- a/lib/caronte/streams/forward.js +++ b/lib/caronte/streams/forward.js @@ -24,7 +24,9 @@ function ForwardStream(options) { var self = this; self.options = options; - self.res = res; + // To uncomment the line below, please see + // https://github.com/yawnt/caronte/commit/9ab8749a9bec33b49c495975e8364336ad7be1a3#commitcomment-3947117 + //self.res = res; Writable.call(this); diff --git a/test/lib-caronte-streams-forward-test.js b/test/lib-caronte-streams-forward-test.js new file mode 100644 index 000000000..5e74a1efd --- /dev/null +++ b/test/lib-caronte-streams-forward-test.js @@ -0,0 +1,37 @@ +var ForwardStream = require('../lib/caronte/streams/forward'), + expect = require('expect.js'), + Writable = require('stream').Writable, + http = require('http'); + + +describe('lib/caronte/passes/web.js', function () { + describe('forward stream constructor', function () { + it('should be an instance of Writable stream and get the correct options and methods', function () { + var stubOptions = { + key: 'value' + }; + var forwardProxy = new ForwardStream(stubOptions); + + expect(forwardProxy).to.be.a(Writable); + expect(forwardProxy.options).to.eql({ key: 'value' }); + expect(forwardProxy.onPipe).to.be.a('function'); + expect(forwardProxy.onFinish).to.be.a('function'); + expect(forwardProxy._events).to.have.property('pipe'); + expect(forwardProxy._events).to.have.property('finish'); + }); + }); + + describe('should pipe the request and finish it', function () { + it('should make the request on pipe and finish it'); + var stubOptions = { + target: { + hostname : 'www.google.com', + port : '80', + path : '/' + } + }; + + var forwardProxy = new ForwardStream({}); + + }); +}); \ No newline at end of file From 8fc33893672d26013c2b2ff396b777bcf1751527 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 28 Aug 2013 14:49:27 +0200 Subject: [PATCH 029/556] [test] add test for forwardstream --- lib/caronte/common.js | 5 ++-- lib/caronte/index.js | 1 - lib/caronte/streams/forward.js | 6 ++--- test/lib-caronte-streams-forward-test.js | 30 +++++++++++++++--------- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/lib/caronte/common.js b/lib/caronte/common.js index 59a1cf94b..78b45864e 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -13,15 +13,16 @@ var common = exports; * @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) { +common.setupOutgoing = function(outgoing, options, req, forward) { ['host', 'hostname', 'port', 'socketPath'/*, 'agent'*/].forEach( - function(e) { outgoing[e] = options.target[e]; } + function(e) { outgoing[e] = options[forward || 'target'][e]; } ); ['method', 'path', 'headers'].forEach( diff --git a/lib/caronte/index.js b/lib/caronte/index.js index bf6160976..6700a4396 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -33,7 +33,6 @@ function createRightProxy(type) { return function(req, res) { var self = this, ev = 'caronte:' + type + ':'; - //self.emit(ev + 'begin', req, res); passes.forEach(function(pass) { diff --git a/lib/caronte/streams/forward.js b/lib/caronte/streams/forward.js index 665a91927..b1bb58f3b 100644 --- a/lib/caronte/streams/forward.js +++ b/lib/caronte/streams/forward.js @@ -50,8 +50,8 @@ require('util').inherits(ForwardStream, Writable); */ ForwardStream.prototype.onPipe = function(request) { - this.forwardReq = (options.ssl ? https : http).request( - common.setupOutgoing(options.ssl || {}, options, request) + this.forwardReq = (this.options.ssl ? https : http).request( + common.setupOutgoing(this.options.ssl || {}, this.options, request, 'forward') ); this.forwardReq.on('error', function() {}); /** Fire and forget */ @@ -85,4 +85,4 @@ ForwardStream.prototype.onFinish = function() { ForwardStream.prototype._write = function(chunk, encoding, clb) { this.forwardReq.write(chunk, encoding, clb); -}; \ No newline at end of file +}; diff --git a/test/lib-caronte-streams-forward-test.js b/test/lib-caronte-streams-forward-test.js index 5e74a1efd..8de2afe6d 100644 --- a/test/lib-caronte-streams-forward-test.js +++ b/test/lib-caronte-streams-forward-test.js @@ -1,4 +1,5 @@ -var ForwardStream = require('../lib/caronte/streams/forward'), +var caronte = require('../'), + ForwardStream = require('../lib/caronte/streams/forward'); expect = require('expect.js'), Writable = require('stream').Writable, http = require('http'); @@ -22,16 +23,23 @@ describe('lib/caronte/passes/web.js', function () { }); describe('should pipe the request and finish it', function () { - it('should make the request on pipe and finish it'); - var stubOptions = { - target: { - hostname : 'www.google.com', - port : '80', - path : '/' - } - }; + it('should make the request on pipe and finish it', function(done) { + var result; + + var p = caronte.createProxyServer({ + forward: 'http://127.0.0.1:8080' + }).listen('8081') - var forwardProxy = new ForwardStream({}); + var s = http.createServer(function(req, res) { + expect(req.method).to.eql('GET'); + s.close(); + p.close(); + done(); + }); + s.listen('8080'); + + http.request('http://127.0.0.1:8081', function() {}).end(); + }); }); -}); \ No newline at end of file +}); From c9612798f1207a4c40b616608bf6274d79ad0e4d Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 28 Aug 2013 14:58:57 +0200 Subject: [PATCH 030/556] [test] proxystream test --- test/lib-caronte-streams-forward-test.js | 2 +- test/lib-caronte-streams-proxy-test.js | 52 ++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 test/lib-caronte-streams-proxy-test.js diff --git a/test/lib-caronte-streams-forward-test.js b/test/lib-caronte-streams-forward-test.js index 8de2afe6d..5289856cc 100644 --- a/test/lib-caronte-streams-forward-test.js +++ b/test/lib-caronte-streams-forward-test.js @@ -5,7 +5,7 @@ var caronte = require('../'), http = require('http'); -describe('lib/caronte/passes/web.js', function () { +describe('lib/caronte/streams/forward.js', function () { describe('forward stream constructor', function () { it('should be an instance of Writable stream and get the correct options and methods', function () { var stubOptions = { diff --git a/test/lib-caronte-streams-proxy-test.js b/test/lib-caronte-streams-proxy-test.js new file mode 100644 index 000000000..0c0debb8a --- /dev/null +++ b/test/lib-caronte-streams-proxy-test.js @@ -0,0 +1,52 @@ +var caronte = require('../'), + ProxyStream = require('../lib/caronte/streams/proxy'); + expect = require('expect.js'), + Duplex = require('stream').Duplex, + http = require('http'); + + +describe('lib/caronte/streams/proxy.js', function () { + describe('proxy stream constructor', function () { + it('should be an instance of Duplex stream and get the correct options and methods', function () { + var stubOptions = { + key: 'value' + }; + var proxyStream = new ProxyStream(stubOptions); + + expect(proxyStream).to.be.a(Duplex); + expect(proxyStream.options).to.eql({ key: 'value' }); + expect(proxyStream.onPipe).to.be.a('function'); + expect(proxyStream.onFinish).to.be.a('function'); + expect(proxyStream._events).to.have.property('pipe'); + expect(proxyStream._events).to.have.property('finish'); + }); + }); + + describe('should pipe the request and finish it', function () { + it('should make the request on pipe and finish it', function(done) { + var result; + + var p = caronte.createProxyServer({ + target: 'http://127.0.0.1:8080' + }).listen('8081'); + + var s = http.createServer(function(req, res) { + expect(req.headers['x-forwarded-for']).to.eql('127.0.0.1'); + s.close(); + p.close(); + done(); + }); + + s.listen('8080'); + + http.request({ + hostname: '127.0.0.1', + port: '8081', + method: 'POST', + headers: { + 'x-forwarded-for': '127.0.0.1' + } + }, function() {}).end(); + }); + }); +}); From abf1d90fdf05a17ebe05a3e90d464a592e0aee69 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 28 Aug 2013 15:22:04 +0200 Subject: [PATCH 031/556] [fix] use agent pool --- lib/caronte.js | 2 +- lib/caronte/common.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/caronte.js b/lib/caronte.js index 81a25e469..3ccd2517a 100644 --- a/lib/caronte.js +++ b/lib/caronte.js @@ -45,7 +45,7 @@ proxy.createProxyServer = function createProxyServer(options) { options[key] = url.parse(options[key]); options[key].maxSockets = options.maxSock; - options[key].agent = new (options.ssl ? https.Agent : http.Agent)(options[key]); + options[key].agent = new (options.ssl ? https.Agent : http.Agent)(options[key].maxSockets || 100); }); return { diff --git a/lib/caronte/common.js b/lib/caronte/common.js index 78b45864e..68f4a9292 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -21,7 +21,7 @@ var common = exports; */ common.setupOutgoing = function(outgoing, options, req, forward) { - ['host', 'hostname', 'port', 'socketPath'/*, 'agent'*/].forEach( + ['host', 'hostname', 'port', 'socketPath', 'agent'].forEach( function(e) { outgoing[e] = options[forward || 'target'][e]; } ); From 27df8d72ad86d02cfce00a6e5c183d93dd50f97e Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 28 Aug 2013 13:45:09 -0500 Subject: [PATCH 032/556] [test] testing the onResponse proxy method --- test/lib-caronte-streams-proxy-test.js | 48 +++++++++++++++++++++----- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/test/lib-caronte-streams-proxy-test.js b/test/lib-caronte-streams-proxy-test.js index 0c0debb8a..a68f99141 100644 --- a/test/lib-caronte-streams-proxy-test.js +++ b/test/lib-caronte-streams-proxy-test.js @@ -22,22 +22,20 @@ describe('lib/caronte/streams/proxy.js', function () { }); }); - describe('should pipe the request and finish it', function () { + describe('caronte createProxyServer() method', function () { it('should make the request on pipe and finish it', function(done) { - var result; - - var p = caronte.createProxyServer({ + var proxy = caronte.createProxyServer({ target: 'http://127.0.0.1:8080' }).listen('8081'); - var s = http.createServer(function(req, res) { + var source = http.createServer(function(req, res) { expect(req.headers['x-forwarded-for']).to.eql('127.0.0.1'); - s.close(); - p.close(); + source.close(); + proxy.close(); done(); }); - s.listen('8080'); + source.listen('8080'); http.request({ hostname: '127.0.0.1', @@ -49,4 +47,38 @@ describe('lib/caronte/streams/proxy.js', function () { }, function() {}).end(); }); }); + + describe('caronte createProxyServer() method with response', function () { + it('should make the request, handle response and finish it', function(done) { + var proxy = caronte.createProxyServer({ + target: 'http://127.0.0.1:8080' + }).listen('8081'); + + var source = http.createServer(function(req, res) { + expect(req.method).to.eql('GET'); + res.writeHead(200, {'Content-Type': 'text/plain'}) + res.end('Hello from ' + source.address().port); + }); + + source.listen('8080'); + + 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 () { + source.close(); + proxy.close(); + done(); + }); + }).end(); + }); + }); }); From b85aa16e75401a223a947cde444d42cf7eeafb67 Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 28 Aug 2013 14:01:55 -0500 Subject: [PATCH 033/556] [test] test onError part, proxying to no where --- test/lib-caronte-streams-proxy-test.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/lib-caronte-streams-proxy-test.js b/test/lib-caronte-streams-proxy-test.js index a68f99141..671f80cc0 100644 --- a/test/lib-caronte-streams-proxy-test.js +++ b/test/lib-caronte-streams-proxy-test.js @@ -81,4 +81,29 @@ describe('lib/caronte/streams/proxy.js', function () { }).end(); }); }); + + describe('caronte createProxyServer() method with error response', function () { + it('should make the request and response with error', function(done) { + var proxy = caronte.createProxyServer({ + target: 'http://127.0.0.1:8080' + }).listen('8081'); + + http.request({ + hostname: '127.0.0.1', + port: '8081', + method: 'GET', + }, function(res) { + expect(res.statusCode).to.eql(500); + + res.on('data', function (data) { + expect(data.toString()).to.eql('Internal Server Error'); + }); + + res.on('end', function () { + proxy.close(); + done(); + }); + }).end(); + }); + }); }); From a6256cac1df1739e3da78fe5f0cf122ef7ce6b14 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 3 Sep 2013 20:56:18 +0200 Subject: [PATCH 034/556] [fix] short circuit --- lib/caronte/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 6700a4396..eaa55872d 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -35,12 +35,14 @@ function createRightProxy(type) { ev = 'caronte:' + type + ':'; //self.emit(ev + 'begin', req, res); - passes.forEach(function(pass) { + + passes.every(function(pass) { var evnt = ev + pass.name.toLowerCase(); //self.emit(evnt + 'begin', req, res); - pass(req, res, options, self); + var val = pass(req, res, options, self); //self.emit(evnt + 'end'); + return val; }); //self.emit(ev + 'end'); From 4480699d3a2a5080c051e7b8a100689fd1f58657 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 3 Sep 2013 20:57:22 +0200 Subject: [PATCH 035/556] [fix] use some --- lib/caronte/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index eaa55872d..21da74481 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -36,7 +36,7 @@ function createRightProxy(type) { //self.emit(ev + 'begin', req, res); - passes.every(function(pass) { + passes.some(function(pass) { var evnt = ev + pass.name.toLowerCase(); //self.emit(evnt + 'begin', req, res); From 79f7f99528661162ae4153856888f078f666e017 Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 3 Sep 2013 14:09:35 -0500 Subject: [PATCH 036/556] [lib] initial draft to websockets passes --- lib/caronte/passes/ws.js | 53 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index 54e117ba5..e91002e46 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -1 +1,52 @@ -// ws \ No newline at end of file +/*! + * 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. + */ + +/* + * Websockets Passes + * + */ + +var passes = exports; + +[ + /* + * WebSocket requests must have the `GET` method and + * the `upgrade:websocket` header + */ + function checkMethodAndHeader (req, res, options) { + if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') { + req.end(); + // Return true to prevent the next passes to be executed + return true; + } + }, + + /** + * Sets `x-forwarded-*` headers if specified in config. + * + */ + + function XHeaders(req, res, options) { + if(!options.xfwd) return; + + var values = { + for : req.connection.remoteAddress || req.socket.remoteAddress, + port : req.connection.remotePort || req.socket.remotePort, + 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] + }); + } +].forEach(function(func) { + passes[func.name] = func; +}); \ No newline at end of file From 07551c63e428551e5d6e52362efd9620a14c71b4 Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 5 Sep 2013 17:28:25 +0200 Subject: [PATCH 037/556] websocket draft --- lib/caronte/passes/ws.js | 81 ++++++++++++++++++-------------- lib/caronte/streams/websocket.js | 60 +++++++++++++++++++++++ 2 files changed, 106 insertions(+), 35 deletions(-) create mode 100644 lib/caronte/streams/websocket.js diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index e91002e46..d89f752a1 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -14,39 +14,50 @@ var passes = exports; [ - /* - * WebSocket requests must have the `GET` method and - * the `upgrade:websocket` header - */ - function checkMethodAndHeader (req, res, options) { - if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') { - req.end(); - // Return true to prevent the next passes to be executed - return true; - } - }, - - /** - * Sets `x-forwarded-*` headers if specified in config. - * - */ - - function XHeaders(req, res, options) { - if(!options.xfwd) return; - - var values = { - for : req.connection.remoteAddress || req.socket.remoteAddress, - port : req.connection.remotePort || req.socket.remotePort, - 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] - }); +/** + * WebSocket requests must have the `GET` method and + * the `upgrade:websocket` header + */ + +function checkMethodAndHeader (req, res, options) { + if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') { + req.end(); + + return true; } -].forEach(function(func) { - passes[func.name] = func; -}); \ No newline at end of file +}, + +/** + * Sets `x-forwarded-*` headers if specified in config. + * + */ + +function XHeaders(req, res, options) { + if(!options.xfwd) return; + + var values = { + for : req.connection.remoteAddress || req.socket.remoteAddress, + port : req.connection.remotePort || req.socket.remotePort, + 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] + }); +}, + +/** + * + * + */ +function stream(req, res, options, instance) { + req.pipe(new WebsocketStream(options, instance)).pipe(res); +} + +] // <-- + .forEach(function(func) { + passes[func.name] = func; + }); diff --git a/lib/caronte/streams/websocket.js b/lib/caronte/streams/websocket.js new file mode 100644 index 000000000..aa9a8cfd8 --- /dev/null +++ b/lib/caronte/streams/websocket.js @@ -0,0 +1,60 @@ +var Duplex = require('stream').Duplex, + common = require('common'), + http = require('http'), + https = require('https'); + +function WebsocketStream(options, res, instance) { + Duplex.call(this); + + this.options = options; + this.res = res; + this.instance = intance; + + var self = this; + + this.once('pipe', function(pipe) { self.onPipe(pipe); }); + this.once('finish', function() { self.onFinish(); }); +} + +require('util').inherits(WebsocketStream, Duplex); + +WebsocketStream.prototype.onPipe = function(req) { + this.req = req; + + var self = this; + + this.proxyReq = (self.options.ssl ? https : http).request( + common.setupOutgoing(self.options.ssl || {}, self.options, req) + ); + + this.proxyReq.once('response', function(proxyRes) { + self.onResponse(proxyRes); + }); + this.proxyReq.on('error', function(e) { + self.onError(e); + }); +}; + +WebsocketStream.prototye.onFinish = function() { + +}; + +WebsocketStream.prototype.onResponse = function(proxyRes) { + +}; + +WebsocketStream.prototype.onError = function(e) { + +}; + + +WebsocketStream.prototype._write = function(chunk, encoding, callback) { + +}; + +WebsocketStream.prototype._read = function(size) { + +}; + + +WebsocketStream.prototype From 3a39e444ff68a74f6b586f0736bbd3f8a2511ca5 Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 5 Sep 2013 17:44:23 +0200 Subject: [PATCH 038/556] new error propagation --- lib/caronte.js | 6 +++++- lib/caronte/index.js | 11 ++++++----- lib/caronte/passes/web.js | 9 ++++----- lib/caronte/streams/proxy.js | 7 +++---- lib/caronte/streams/websocket.js | 4 +++- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/lib/caronte.js b/lib/caronte.js index 3ccd2517a..ed5e4253a 100644 --- a/lib/caronte.js +++ b/lib/caronte.js @@ -48,8 +48,9 @@ proxy.createProxyServer = function createProxyServer(options) { options[key].agent = new (options.ssl ? https.Agent : http.Agent)(options[key].maxSockets || 100); }); + options.ee = new events.EventEmitter2({ wildcard: true, delimiter: ':' }); + return { - __proto__: new events.EventEmitter2({ wildcard: true, delimiter: ':' }), web : caronte.createWebProxy(options), ws : caronte.createWsProxy(options), listen : function listen(port) { @@ -62,6 +63,9 @@ proxy.createProxyServer = function createProxyServer(options) { server.listen(port); return server; + }, + emitter : function() { + return options.ee; } }; }; diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 21da74481..747a64bab 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -33,19 +33,20 @@ function createRightProxy(type) { return function(req, res) { var self = this, ev = 'caronte:' + type + ':'; - //self.emit(ev + 'begin', req, res); + options.ee.emit(ev + 'begin', req, res); passes.some(function(pass) { var evnt = ev + pass.name.toLowerCase(); - //self.emit(evnt + 'begin', req, res); - var val = pass(req, res, options, self); - //self.emit(evnt + 'end'); + options.ee.emit(evnt + 'begin', req, res); + var val = pass(req, res, options); + options.ee.emit(evnt + 'end'); + return val; }); - //self.emit(ev + 'end'); + options.ee.emit(ev + 'end'); }; }; } diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web.js index 97c69afb2..dc815abd0 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web.js @@ -79,18 +79,17 @@ function XHeaders(req, res, options) { * @param {ClientRequest} Req Request object * @param {IncomingMessage} Res Response object * @param {Object} Options Config object passed to the proxy - * @param {Object} Instance Proxy object that emits events * * @api private */ -function stream(req, res, options, instance) { +function stream(req, res, options) { if(options.forward) { - req.pipe(new ForwardStream(options, instance)); + req.pipe(new ForwardStream(options)); } if(options.target) { - return req.pipe(new ProxyStream(options, res, instance)).pipe(res); + return req.pipe(new ProxyStream(options, res)).pipe(res); } res.end(); @@ -99,4 +98,4 @@ function stream(req, res, options, instance) { ] // <-- .forEach(function(func) { passes[func.name] = func; - }); \ No newline at end of file + }); diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js index 2903c07c6..2f939876e 100644 --- a/lib/caronte/streams/proxy.js +++ b/lib/caronte/streams/proxy.js @@ -3,12 +3,11 @@ var Duplex = require('stream').Duplex, http = require('http'), https = require('https'); -function ProxyStream(options, res, instance) { +function ProxyStream(options, res) { Duplex.call(this); this.options = options; this.res = res; - this.instance = instance; var self = this; @@ -86,7 +85,7 @@ ProxyStream.prototype.onResponse = function(proxyRes) { }; ProxyStream.prototype.onError = function(e) { - if(this.instance.emit('proxyError', this.req, this.res, e)) return; + if(this.options.ee.emit('proxyError', this.req, this.res, e)) return; this.res.writeHead(500, { 'Content-Type': 'text/plain' }); this.res.end('Internal Server Error'); @@ -102,4 +101,4 @@ ProxyStream.prototype._read = function(size) { this.push(chunk); }; -module.exports = ProxyStream; \ No newline at end of file +module.exports = ProxyStream; diff --git a/lib/caronte/streams/websocket.js b/lib/caronte/streams/websocket.js index aa9a8cfd8..2d2dc69d6 100644 --- a/lib/caronte/streams/websocket.js +++ b/lib/caronte/streams/websocket.js @@ -36,10 +36,12 @@ WebsocketStream.prototype.onPipe = function(req) { }; WebsocketStream.prototye.onFinish = function() { - + this.proxyReq.end(); }; WebsocketStream.prototype.onResponse = function(proxyRes) { + this.proxyRes = proxyRes; + }; From 1993faf8a4227acda3423d46cf2cf13b4d9861e7 Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 5 Sep 2013 17:45:03 +0200 Subject: [PATCH 039/556] new error propagation - follows --- lib/caronte/streams/websocket.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/caronte/streams/websocket.js b/lib/caronte/streams/websocket.js index 2d2dc69d6..3f073ab1f 100644 --- a/lib/caronte/streams/websocket.js +++ b/lib/caronte/streams/websocket.js @@ -3,12 +3,11 @@ var Duplex = require('stream').Duplex, http = require('http'), https = require('https'); -function WebsocketStream(options, res, instance) { +function WebsocketStream(options, res) { Duplex.call(this); this.options = options; this.res = res; - this.instance = intance; var self = this; From e0faaaf81152203b96f0313c68706468e7ee7357 Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 10 Sep 2013 19:31:47 -0500 Subject: [PATCH 040/556] [fix] minor and short fixes --- lib/caronte/passes/ws.js | 10 ++++++---- lib/caronte/streams/proxy.js | 4 ++-- lib/caronte/streams/websocket.js | 11 +++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index d89f752a1..a99277f65 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -20,10 +20,12 @@ var passes = exports; */ function checkMethodAndHeader (req, res, options) { - if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') { - req.end(); - - return true; + if (req.method !== 'GET' || !req.headers.upgrade) { + req.end(); return true; + } + + if (req.headers.upgrade.toLowerCase() !== 'websocket') { + req.end(); return true; } }, diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js index 2f939876e..29c2fa78f 100644 --- a/lib/caronte/streams/proxy.js +++ b/lib/caronte/streams/proxy.js @@ -3,6 +3,8 @@ var Duplex = require('stream').Duplex, http = require('http'), https = require('https'); +module.exports = ProxyStream; + function ProxyStream(options, res) { Duplex.call(this); @@ -100,5 +102,3 @@ ProxyStream.prototype._read = function(size) { this.push(chunk); }; - -module.exports = ProxyStream; diff --git a/lib/caronte/streams/websocket.js b/lib/caronte/streams/websocket.js index 3f073ab1f..dc43daf04 100644 --- a/lib/caronte/streams/websocket.js +++ b/lib/caronte/streams/websocket.js @@ -1,8 +1,10 @@ var Duplex = require('stream').Duplex, - common = require('common'), + common = require('../common'), http = require('http'), https = require('https'); +module.exports = WebsocketStream; + function WebsocketStream(options, res) { Duplex.call(this); @@ -34,7 +36,7 @@ WebsocketStream.prototype.onPipe = function(req) { }); }; -WebsocketStream.prototye.onFinish = function() { +WebsocketStream.prototype.onFinish = function() { this.proxyReq.end(); }; @@ -55,7 +57,4 @@ WebsocketStream.prototype._write = function(chunk, encoding, callback) { WebsocketStream.prototype._read = function(size) { -}; - - -WebsocketStream.prototype +}; \ No newline at end of file From 8b3fe32f6ae60ae067bc5e40cdc43015e689467f Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 10 Sep 2013 19:36:19 -0500 Subject: [PATCH 041/556] [tests] added the ws passes test and the streams webscokets test --- test/lib-caronte-passes-ws-test.js | 87 ++++++++++++++++ test/lib-caronte-streams-websockets-test.js | 109 ++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 test/lib-caronte-passes-ws-test.js create mode 100644 test/lib-caronte-streams-websockets-test.js diff --git a/test/lib-caronte-passes-ws-test.js b/test/lib-caronte-passes-ws-test.js new file mode 100644 index 000000000..f794cca3e --- /dev/null +++ b/test/lib-caronte-passes-ws-test.js @@ -0,0 +1,87 @@ +var caronte = require('../lib/caronte/passes/ws'), + expect = require('expect.js'); + +describe('lib/caronte/passes/ws.js', function () { + describe('#checkMethodAndHeader', function () { + it('should drop non-GET connections', function () { + var endCalled = false, + stubRequest = { + method: 'DELETE', + headers: {}, + end: function () { + // Simulate Stream.end() method when call + endCalled = true; + } + }, + returnValue = caronte.checkMethodAndHeader(stubRequest, {}, {}); + expect(returnValue).to.be(true); + expect(endCalled).to.be(true); + }) + + it('should drop connections when no upgrade header', function () { + var endCalled = false, + stubRequest = { + method: 'GET', + headers: {}, + end: function () { + // Simulate Stream.end() method when call + endCalled = true; + } + }, + returnValue = caronte.checkMethodAndHeader(stubRequest, {}, {}); + expect(returnValue).to.be(true); + expect(endCalled).to.be(true); + }) + + it('should drop connections when upgrade header is different of `websocket`', function () { + var endCalled = false, + stubRequest = { + method: 'GET', + headers: { + upgrade: 'anotherprotocol' + }, + end: function () { + // Simulate Stream.end() method when call + endCalled = true; + } + }, + returnValue = caronte.checkMethodAndHeader(stubRequest, {}, {}); + expect(returnValue).to.be(true); + expect(endCalled).to.be(true); + }) + + it('should return nothing when all is ok', function () { + var endCalled = false, + stubRequest = { + method: 'GET', + headers: { + upgrade: 'websocket' + }, + end: function () { + // Simulate Stream.end() method when call + endCalled = true; + } + }, + returnValue = caronte.checkMethodAndHeader(stubRequest, {}, {}); + expect(returnValue).to.be(undefined); + expect(endCalled).to.be(false); + }) + }); + + describe('#XHeaders', function () { + // var stubRequest = { + // connection: { + // remoteAddress: '192.168.1.2', + // remotePort: '8080' + // }, + // headers: {} + // } + + // it('set the correct x-forwarded-* headers', function () { + // caronte.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'); + // }); + }); +}); diff --git a/test/lib-caronte-streams-websockets-test.js b/test/lib-caronte-streams-websockets-test.js new file mode 100644 index 000000000..74248e7b3 --- /dev/null +++ b/test/lib-caronte-streams-websockets-test.js @@ -0,0 +1,109 @@ +var caronte = require('../'), + WebSocket = require('../lib/caronte/streams/websocket'); + expect = require('expect.js'), + Duplex = require('stream').Duplex, + http = require('http'); + + +describe('lib/caronte/streams/websocket.js', function () { + describe('WebSocket stream constructor', function () { + it('should be an instance of Duplex stream and get the correct options and methods', function () { + var stubOptions = { + key: 'value' + }; + var WebSocketStream = new WebSocket(stubOptions); + + expect(WebSocketStream).to.be.a(Duplex); + expect(WebSocketStream.options).to.eql({ key: 'value' }); + expect(WebSocketStream.onPipe).to.be.a('function'); + expect(WebSocketStream.onFinish).to.be.a('function'); + expect(WebSocketStream._events).to.have.property('pipe'); + expect(WebSocketStream._events).to.have.property('finish'); + }); + }); + + describe('caronte createWebSocketServer() method', function () { + // it('should make the request on pipe and finish it', function(done) { + // var proxy = caronte.createProxyServer({ + // target: 'http://127.0.0.1:8080' + // }).listen('8081'); + + // var source = http.createServer(function(req, res) { + // expect(req.headers['x-forwarded-for']).to.eql('127.0.0.1'); + // source.close(); + // proxy.close(); + // done(); + // }); + + // source.listen('8080'); + + // http.request({ + // hostname: '127.0.0.1', + // port: '8081', + // method: 'POST', + // headers: { + // 'x-forwarded-for': '127.0.0.1' + // } + // }, function() {}).end(); + // }); + }); + + describe('caronte createProxyServer() method with response', function () { + // it('should make the request, handle response and finish it', function(done) { + // var proxy = caronte.createProxyServer({ + // target: 'http://127.0.0.1:8080' + // }).listen('8081'); + + // var source = http.createServer(function(req, res) { + // expect(req.method).to.eql('GET'); + // res.writeHead(200, {'Content-Type': 'text/plain'}) + // res.end('Hello from ' + source.address().port); + // }); + + // source.listen('8080'); + + // 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 () { + // source.close(); + // proxy.close(); + // done(); + // }); + // }).end(); + // }); + }); + + describe('caronte createProxyServer() method with error response', function () { + // it('should make the request and response with error', function(done) { + // var proxy = caronte.createProxyServer({ + // target: 'http://127.0.0.1:8080' + // }).listen('8081'); + + // http.request({ + // hostname: '127.0.0.1', + // port: '8081', + // method: 'GET', + // }, function(res) { + // expect(res.statusCode).to.eql(500); + + // res.on('data', function (data) { + // expect(data.toString()).to.eql('Internal Server Error'); + // }); + + // res.on('end', function () { + // proxy.close(); + // done(); + // }); + // }).end(); + // }); + }); +}); From c9cd6d2ad324e0e6222932c8f29f27621071e045 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 13 Sep 2013 19:07:34 +0200 Subject: [PATCH 042/556] [fix] make @mmalecki a happy camper --- lib/caronte.js | 4 +--- lib/caronte/index.js | 5 ++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/caronte.js b/lib/caronte.js index ed5e4253a..444e8fd25 100644 --- a/lib/caronte.js +++ b/lib/caronte.js @@ -51,6 +51,7 @@ proxy.createProxyServer = function createProxyServer(options) { options.ee = new events.EventEmitter2({ wildcard: true, delimiter: ':' }); return { + ee : options.ee, web : caronte.createWebProxy(options), ws : caronte.createWsProxy(options), listen : function listen(port) { @@ -63,9 +64,6 @@ proxy.createProxyServer = function createProxyServer(options) { server.listen(port); return server; - }, - emitter : function() { - return options.ee; } }; }; diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 747a64bab..194676e8b 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -30,9 +30,12 @@ function createRightProxy(type) { return passes[pass]; }); - return function(req, res) { + return function(req, res, opts) { var self = this, ev = 'caronte:' + type + ':'; + + if(typeof opts !== 'undefined') { options = opts; } + options.ee.emit(ev + 'begin', req, res); From 4a4607d075a912746386d1751fd6b0fc98cf6b20 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 13 Sep 2013 20:06:51 +0200 Subject: [PATCH 043/556] support websockets --- lib/caronte/index.js | 19 ++++++++++++++++--- lib/caronte/passes/ws.js | 3 +++ package.json | 3 ++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 194676e8b..8339faee6 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -30,11 +30,24 @@ function createRightProxy(type) { return passes[pass]; }); - return function(req, res, opts) { + return function(req, res /*, [head], [opts] */) { var self = this, - ev = 'caronte:' + type + ':'; + args = [].slice.call(arguments), + cntr = args.length - 1, + ev = 'caronte:' + type + ':', + head; - if(typeof opts !== 'undefined') { options = opts; } + if( + !(args[cntr] instanceof Buffer) && + args[cntr] !== res + ) { + options = opts; + cntr--; + } + + if(args[cntr] instanceof Buffer) { + head = args[cntr]; + } options.ee.emit(ev + 'begin', req, res); diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index a99277f65..827617b47 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -1,3 +1,6 @@ +var WebsocketStream = require('../streams/websocket'), + passes = exports; + /*! * Array of passes. * diff --git a/package.json b/package.json index e2b3f25d1..9968b65b0 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "dox" : "*", "coveralls" : "*", "mocha-lcov-reporter": "*", - "blanket" : "*" + "blanket" : "*", + "ws" : "*" }, "scripts" : { "blanket" : { "pattern": "caronte/lib" }, From a74cd85c8a5aae2851acf7139648fefd6a02a57b Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 13 Sep 2013 20:49:52 +0200 Subject: [PATCH 044/556] socket.io stuff --- lib/caronte/index.js | 2 +- lib/caronte/passes/ws.js | 18 ++++++-- lib/caronte/streams/websocket.js | 73 ++++++++++++++++++++++++++++---- 3 files changed, 80 insertions(+), 13 deletions(-) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 8339faee6..586ed3f60 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -56,7 +56,7 @@ function createRightProxy(type) { var evnt = ev + pass.name.toLowerCase(); options.ee.emit(evnt + 'begin', req, res); - var val = pass(req, res, options); + var val = pass(req, res, options, head); options.ee.emit(evnt + 'end'); return val; diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index 827617b47..8a3515537 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -28,10 +28,22 @@ function checkMethodAndHeader (req, res, options) { } if (req.headers.upgrade.toLowerCase() !== 'websocket') { - req.end(); return true; + res.destroy(); return true; } }, +/** + * Setup socket + * + */ + +function setupSocket(req, res) { + res.setTimeout(0); + res.setNoDelay(true); + + res.setKeepAlive(true, 0); +}, + /** * Sets `x-forwarded-*` headers if specified in config. * @@ -58,8 +70,8 @@ function XHeaders(req, res, options) { * * */ -function stream(req, res, options, instance) { - req.pipe(new WebsocketStream(options, instance)).pipe(res); +function stream(req, res, options, head) { + req.pipe(new WebsocketStream(options, head)).pipe(res); } ] // <-- diff --git a/lib/caronte/streams/websocket.js b/lib/caronte/streams/websocket.js index dc43daf04..e7c71b31c 100644 --- a/lib/caronte/streams/websocket.js +++ b/lib/caronte/streams/websocket.js @@ -8,8 +8,9 @@ module.exports = WebsocketStream; function WebsocketStream(options, res) { Duplex.call(this); - this.options = options; - this.res = res; + this.options = options; + this.res = res; + this.handshakeDone = false; var self = this; @@ -28,9 +29,13 @@ WebsocketStream.prototype.onPipe = function(req) { common.setupOutgoing(self.options.ssl || {}, self.options, req) ); - this.proxyReq.once('response', function(proxyRes) { - self.onResponse(proxyRes); + this.proxyReq.once('socket', function(proxySocket) { + self.onSocket(proxySocket); }); + this.proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { + self.onUpgrade(proxyRes, proxySocket, proxyHead); + }); + this.proxyReq.on('error', function(e) { self.onError(e); }); @@ -40,8 +45,25 @@ WebsocketStream.prototype.onFinish = function() { this.proxyReq.end(); }; -WebsocketStream.prototype.onResponse = function(proxyRes) { - this.proxyRes = proxyRes; +WebsocketStream.prototype.onSocket = function(proxySocket) { + + +}; + +WebsocketStream.prototype.onUpgrade = function(proxyRes, proxySocket, proxyHead) { + this.handshake = { + headers : proxyRes.headers, + statusCode : proxyRes.statusCode + }; + + this.proxyRes = proxyRes; + this.proxySocket = proxySocket; + this.proxyHead = proxyHead; + + proxySocket.setTimeout(0); + proxySocket.setNoDelay(true); + + proxySocket.setKeepAlive(true, 0); }; @@ -52,9 +74,42 @@ WebsocketStream.prototype.onError = function(e) { WebsocketStream.prototype._write = function(chunk, encoding, callback) { - + this.proxySocket.write(chunk, encoding, callback); }; WebsocketStream.prototype._read = function(size) { - -}; \ No newline at end of file + var chunk = (this.proxySocket ? this.proxySocket.read(size) : '') || ''; + + if(chunk && !this.handshakeDone) { + var headers = ''; + + if (this.handshake.statusCode && this.handshake.statusCode == 101) { + headers = [ + 'HTTP/1.1 101 Switching Protocols', + 'Upgrade: websocket', + 'Connection: Upgrade', + 'Sec-WebSocket-Accept: ' + this.handshake.headers['sec-websocket-accept'] + ]; + + headers = headers.concat('', '').join('\r\n'); + } + + /* + * Socket.IO specific code + */ + + var sdata = chunk.toString(); + sdata = sdata.substr(0, sdata.search(CRLF + CRLF)); + chunk = data.slice(Buffer.byteLength(sdata), data.length); + + if (self.source.https && !self.target.https) { sdata = sdata.replace('ws:', 'wss:'); } + + this.push(headers + sdata); + this.push(data); + + this.handshakeDone = true; + return; + } + + this.push(chunk); +}; From e45bfd66a21a2470c5a4a4cc1d6095494bbc0f6b Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 13 Sep 2013 23:38:12 +0200 Subject: [PATCH 045/556] stuff --- .gitignore | 2 +- lib/caronte/passes/ws.js | 24 ++++++------- lib/caronte/streams/websocket.js | 22 +++++++++--- ttest.js | 58 ++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 ttest.js diff --git a/.gitignore b/.gitignore index 52241f829..517f9cee0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules *.swp cov -ttest.js +!ttest.js notes diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index 8a3515537..a4303304d 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -4,7 +4,7 @@ var WebsocketStream = require('../streams/websocket'), /*! * Array of passes. * - * A `pass` is just a function that is executed on `req, res, options` + * 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. */ @@ -22,13 +22,13 @@ var passes = exports; * the `upgrade:websocket` header */ -function checkMethodAndHeader (req, res, options) { +function checkMethodAndHeader (req, socket) { if (req.method !== 'GET' || !req.headers.upgrade) { - req.end(); return true; + socket.destroy(); return true; } if (req.headers.upgrade.toLowerCase() !== 'websocket') { - res.destroy(); return true; + socket.destroy(); return true; } }, @@ -37,11 +37,11 @@ function checkMethodAndHeader (req, res, options) { * */ -function setupSocket(req, res) { - res.setTimeout(0); - res.setNoDelay(true); +function setupSocket(req, socket) { + socket.setTimeout(0); + socket.setNoDelay(true); - res.setKeepAlive(true, 0); + socket.setKeepAlive(true, 0); }, /** @@ -49,11 +49,11 @@ function setupSocket(req, res) { * */ -function XHeaders(req, res, options) { +function XHeaders(req, socket, options) { if(!options.xfwd) return; var values = { - for : req.connection.remoteAddress || req.socket.remoteAddress, + for : req.connection.remoteAddsockets || req.socket.remoteAddsockets, port : req.connection.remotePort || req.socket.remotePort, proto: req.connection.pair ? 'wss' : 'ws' }; @@ -70,8 +70,8 @@ function XHeaders(req, res, options) { * * */ -function stream(req, res, options, head) { - req.pipe(new WebsocketStream(options, head)).pipe(res); +function stream(req, socket, options, head) { + req.pipe(new WebsocketStream(options, head)).pipe(socket); } ] // <-- diff --git a/lib/caronte/streams/websocket.js b/lib/caronte/streams/websocket.js index e7c71b31c..4d24f5bf5 100644 --- a/lib/caronte/streams/websocket.js +++ b/lib/caronte/streams/websocket.js @@ -47,10 +47,11 @@ WebsocketStream.prototype.onFinish = function() { WebsocketStream.prototype.onSocket = function(proxySocket) { - }; WebsocketStream.prototype.onUpgrade = function(proxyRes, proxySocket, proxyHead) { + var self = this; + this.handshake = { headers : proxyRes.headers, statusCode : proxyRes.statusCode @@ -63,9 +64,17 @@ WebsocketStream.prototype.onUpgrade = function(proxyRes, proxySocket, proxyHead) proxySocket.setTimeout(0); proxySocket.setNoDelay(true); - proxySocket.setKeepAlive(true, 0); + proxySocket.setKeepAlive(true, 0); + + proxySocket.on('readable', function() { + self.read(0); + }); + proxySocket.on('end', function() { + self.push(null); + }); + self.emit('readable'); }; WebsocketStream.prototype.onError = function(e) { @@ -98,8 +107,8 @@ WebsocketStream.prototype._read = function(size) { * Socket.IO specific code */ - var sdata = chunk.toString(); - sdata = sdata.substr(0, sdata.search(CRLF + CRLF)); + /*var sdata = chunk.toString(); + sdata = sdata.substr(0, sdata.search('\r\n\r\n')); chunk = data.slice(Buffer.byteLength(sdata), data.length); if (self.source.https && !self.target.https) { sdata = sdata.replace('ws:', 'wss:'); } @@ -108,7 +117,10 @@ WebsocketStream.prototype._read = function(size) { this.push(data); this.handshakeDone = true; - return; + return; + */ + this.push(headers); + this.push(chunk); } this.push(chunk); diff --git a/ttest.js b/ttest.js new file mode 100644 index 000000000..d06df539c --- /dev/null +++ b/ttest.js @@ -0,0 +1,58 @@ +var caronte = require('./'), + http = require('http'), + ws = require('ws'); + +var proxyTo = new ws.Server({ port: 9090 }); + +proxyTo.on('connection', function(ws) { + console.log('connection!'); + ws.on('message', function(msg) { + console.log('received: ' + msg); + }); + ws.send('derpity?'); +}); + +/*caronte.createProxyServer({ + ws : true, + target: 'http://127.0.0.1:9090' +}).listen(8000);*/ + + +var client = new ws('ws://127.0.0.1:8000'); +client.on('open', function() { + client.send('baaaka'); + console.log('sent: baaaaka'); +}); + + +var srv = http.createServer(function(req, res) { + res.end('1'); +}).listen(8000); + +srv.on('upgrade', function(req, socket, head) { + var options = { + port: 9090, + hostname: '127.0.0.1', + headers: req.headers + } + var req = http.request(options); + req.end(); + socket.on('data', function(d) { + console.log('yoo'); + console.log(d); + }); + var s; + req.on('socket', function(ss) { + s = ss; + }); + req.on('upgrade', function(res, sock, hd) { + /*console.log(hd.toString('utf-8')); + var str = Object.keys(res.headers).map(function(i) { + return i + ": " + res.headers[i]; + }).join('\r\n'); + socket.write("HTTP/1.1 101 Switching Protocols\r\n" + str); + + socket.write(hd); + socket.pipe(sock).pipe(socket);*/ + }); +}); From 1a7bef0cda58243416a263075dc6eb51f22b6dec Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 10:06:03 +0200 Subject: [PATCH 046/556] mm test file --- ttest.js | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/ttest.js b/ttest.js index d06df539c..33da443e3 100644 --- a/ttest.js +++ b/ttest.js @@ -29,30 +29,25 @@ var srv = http.createServer(function(req, res) { res.end('1'); }).listen(8000); +srv.on('connection', function(s) { + s.pipe(process.stdout); +}); + srv.on('upgrade', function(req, socket, head) { + var options = { port: 9090, hostname: '127.0.0.1', headers: req.headers } - var req = http.request(options); - req.end(); - socket.on('data', function(d) { - console.log('yoo'); - console.log(d); - }); - var s; - req.on('socket', function(ss) { - s = ss; - }); - req.on('upgrade', function(res, sock, hd) { - /*console.log(hd.toString('utf-8')); - var str = Object.keys(res.headers).map(function(i) { - return i + ": " + res.headers[i]; - }).join('\r\n'); - socket.write("HTTP/1.1 101 Switching Protocols\r\n" + str); - - socket.write(hd); - socket.pipe(sock).pipe(socket);*/ + var r = http.request(options); + + r.on('upgrade', function(res, sock, hd) { + if (hd && hd.length) sock.unshift(hd); + + + socket.pipe(sock).pipe(socket); }); + + r.end(); }); From f97c0c6167371c5ff92e6361b1df02e3fd5506d7 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 10:22:31 +0200 Subject: [PATCH 047/556] write --- ttest.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ttest.js b/ttest.js index 33da443e3..ca9334434 100644 --- a/ttest.js +++ b/ttest.js @@ -47,6 +47,15 @@ srv.on('upgrade', function(req, socket, head) { socket.pipe(sock).pipe(socket); + //req.pipe(r).pipe(socket); + /*console.log(hd.toString('utf-8')); + var str = Object.keys(res.headers).map(function(i) { + return i + ": " + res.headers[i]; + }).join('\r\n'); + socket.write("HTTP/1.1 101 Switching Protocols\r\n" + str); + + socket.write(hd); + socket.pipe(sock).pipe(socket);*/ }); r.end(); From 79a14acfd2b2bf03f5ae2b334e7a37e619da6bb9 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 12:48:53 +0200 Subject: [PATCH 048/556] [feature] websocket support --- lib/caronte/passes/ws.js | 21 ++++++++++++++++++- ttest.js | 44 +++++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index a4303304d..aa2ce1aaf 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -1,4 +1,6 @@ var WebsocketStream = require('../streams/websocket'), + http = require('http'), + common = require('../common'), passes = exports; /*! @@ -71,7 +73,24 @@ function XHeaders(req, socket, options) { * */ function stream(req, socket, options, head) { - req.pipe(new WebsocketStream(options, head)).pipe(socket); + var r = http.request( + common.setupOutgoing(options.ssl || {}, options, req) + ); + + r.on('upgrade', function(res, proxySock, hd) { + if (hd && hd.length) proxySock.unshift(hd); + + socket.write('HTTP/1.1 101 Switching Protocols\r\n'); + socket.write(Object.keys(res.headers).map(function(i) { + return i + ": " + res.headers[i]; + }).join('\r\n') + '\r\n\r\n'); + proxySock.pipe(socket).pipe(proxySock); + }); + + r.end(); + + + //req.pipe(new WebsocketStream(options, head)).pipe(socket); } ] // <-- diff --git a/ttest.js b/ttest.js index ca9334434..ee34ed61e 100644 --- a/ttest.js +++ b/ttest.js @@ -1,3 +1,4 @@ +'use strict'; /* jshint node:true */ var caronte = require('./'), http = require('http'), ws = require('ws'); @@ -7,33 +8,38 @@ var proxyTo = new ws.Server({ port: 9090 }); proxyTo.on('connection', function(ws) { console.log('connection!'); ws.on('message', function(msg) { - console.log('received: ' + msg); + ws.send('ohai: ' + msg); + setTimeout(function() { + ws.send('HAHAHHA'); + }, 10000); }); ws.send('derpity?'); }); -/*caronte.createProxyServer({ +caronte.createProxyServer({ ws : true, target: 'http://127.0.0.1:9090' -}).listen(8000);*/ +}).listen(8000); var client = new ws('ws://127.0.0.1:8000'); client.on('open', function() { client.send('baaaka'); console.log('sent: baaaaka'); + setTimeout(function() { + client.send('cacca'); + }, 5000); + client.on('message', function(msg) { + console.log('server said: ' + msg); + }); }); -var srv = http.createServer(function(req, res) { +/*var srv = http.createServer(function(req, res) { res.end('1'); }).listen(8000); -srv.on('connection', function(s) { - s.pipe(process.stdout); -}); - -srv.on('upgrade', function(req, socket, head) { +srv.on('upgrade', function(req, sock, head) { var options = { port: 9090, @@ -42,21 +48,17 @@ srv.on('upgrade', function(req, socket, head) { } var r = http.request(options); - r.on('upgrade', function(res, sock, hd) { - if (hd && hd.length) sock.unshift(hd); + r.on('upgrade', function(res, proxySock, hd) { + if (hd && hd.length) proxySock.unshift(hd); - - socket.pipe(sock).pipe(socket); - //req.pipe(r).pipe(socket); - /*console.log(hd.toString('utf-8')); - var str = Object.keys(res.headers).map(function(i) { + sock.write('HTTP/1.1 101 Switching Protocols\r\n'); + sock.write(Object.keys(res.headers).map(function(i) { return i + ": " + res.headers[i]; - }).join('\r\n'); - socket.write("HTTP/1.1 101 Switching Protocols\r\n" + str); - - socket.write(hd); - socket.pipe(sock).pipe(socket);*/ + }).join('\r\n') + '\r\n\r\n'); + proxySock.pipe(sock).pipe(proxySock); }); r.end(); }); + +*/ From 893100972c22febbf133134394bc0bcef47d9e12 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 13:01:53 +0200 Subject: [PATCH 049/556] [fix] naming --- lib/caronte/passes/ws.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index aa2ce1aaf..90ab609f3 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -77,14 +77,14 @@ function stream(req, socket, options, head) { common.setupOutgoing(options.ssl || {}, options, req) ); - r.on('upgrade', function(res, proxySock, hd) { - if (hd && hd.length) proxySock.unshift(hd); + r.on('upgrade', function(proxyRes, proxySocket, proxyHead) { + if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead); socket.write('HTTP/1.1 101 Switching Protocols\r\n'); - socket.write(Object.keys(res.headers).map(function(i) { - return i + ": " + res.headers[i]; + socket.write(Object.keys(proxyRes.headers).map(function(i) { + return i + ": " + proxyRes.headers[i]; }).join('\r\n') + '\r\n\r\n'); - proxySock.pipe(socket).pipe(proxySock); + proxySocket.pipe(socket).pipe(proxySocket); }); r.end(); From 2a593664a5768c90d9b2edf4c298460416b38926 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 13:02:28 +0200 Subject: [PATCH 050/556] [fix] naming --- lib/caronte/passes/ws.js | 7 +- lib/caronte/streams/websocket.js | 127 ------------------------------- 2 files changed, 3 insertions(+), 131 deletions(-) delete mode 100644 lib/caronte/streams/websocket.js diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index 90ab609f3..11e85c67e 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -1,7 +1,6 @@ -var WebsocketStream = require('../streams/websocket'), - http = require('http'), - common = require('../common'), - passes = exports; +var http = require('http'), + common = require('../common'), + passes = exports; /*! * Array of passes. diff --git a/lib/caronte/streams/websocket.js b/lib/caronte/streams/websocket.js deleted file mode 100644 index 4d24f5bf5..000000000 --- a/lib/caronte/streams/websocket.js +++ /dev/null @@ -1,127 +0,0 @@ -var Duplex = require('stream').Duplex, - common = require('../common'), - http = require('http'), - https = require('https'); - -module.exports = WebsocketStream; - -function WebsocketStream(options, res) { - Duplex.call(this); - - this.options = options; - this.res = res; - this.handshakeDone = false; - - var self = this; - - this.once('pipe', function(pipe) { self.onPipe(pipe); }); - this.once('finish', function() { self.onFinish(); }); -} - -require('util').inherits(WebsocketStream, Duplex); - -WebsocketStream.prototype.onPipe = function(req) { - this.req = req; - - var self = this; - - this.proxyReq = (self.options.ssl ? https : http).request( - common.setupOutgoing(self.options.ssl || {}, self.options, req) - ); - - this.proxyReq.once('socket', function(proxySocket) { - self.onSocket(proxySocket); - }); - this.proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { - self.onUpgrade(proxyRes, proxySocket, proxyHead); - }); - - this.proxyReq.on('error', function(e) { - self.onError(e); - }); -}; - -WebsocketStream.prototype.onFinish = function() { - this.proxyReq.end(); -}; - -WebsocketStream.prototype.onSocket = function(proxySocket) { - -}; - -WebsocketStream.prototype.onUpgrade = function(proxyRes, proxySocket, proxyHead) { - var self = this; - - this.handshake = { - headers : proxyRes.headers, - statusCode : proxyRes.statusCode - }; - - this.proxyRes = proxyRes; - this.proxySocket = proxySocket; - this.proxyHead = proxyHead; - - proxySocket.setTimeout(0); - proxySocket.setNoDelay(true); - - proxySocket.setKeepAlive(true, 0); - - proxySocket.on('readable', function() { - self.read(0); - }); - - proxySocket.on('end', function() { - self.push(null); - }); - - self.emit('readable'); -}; - -WebsocketStream.prototype.onError = function(e) { - -}; - - -WebsocketStream.prototype._write = function(chunk, encoding, callback) { - this.proxySocket.write(chunk, encoding, callback); -}; - -WebsocketStream.prototype._read = function(size) { - var chunk = (this.proxySocket ? this.proxySocket.read(size) : '') || ''; - - if(chunk && !this.handshakeDone) { - var headers = ''; - - if (this.handshake.statusCode && this.handshake.statusCode == 101) { - headers = [ - 'HTTP/1.1 101 Switching Protocols', - 'Upgrade: websocket', - 'Connection: Upgrade', - 'Sec-WebSocket-Accept: ' + this.handshake.headers['sec-websocket-accept'] - ]; - - headers = headers.concat('', '').join('\r\n'); - } - - /* - * Socket.IO specific code - */ - - /*var sdata = chunk.toString(); - sdata = sdata.substr(0, sdata.search('\r\n\r\n')); - chunk = data.slice(Buffer.byteLength(sdata), data.length); - - if (self.source.https && !self.target.https) { sdata = sdata.replace('ws:', 'wss:'); } - - this.push(headers + sdata); - this.push(data); - - this.handshakeDone = true; - return; - */ - this.push(headers); - this.push(chunk); - } - - this.push(chunk); -}; From 6a03e5f7cf356416ea13584e279f5bfa3791c058 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 13:04:59 +0200 Subject: [PATCH 051/556] [fix] remove stuff --- lib/caronte/passes/ws.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index 11e85c67e..3f44e5daa 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -87,9 +87,6 @@ function stream(req, socket, options, head) { }); r.end(); - - - //req.pipe(new WebsocketStream(options, head)).pipe(socket); } ] // <-- From 7d71a867a8bdc375f7577cec3905cca89bbf415c Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 13:06:00 +0200 Subject: [PATCH 052/556] [fix] naming convention --- lib/caronte/passes/ws.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index 3f44e5daa..821cb2eb0 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -72,11 +72,11 @@ function XHeaders(req, socket, options) { * */ function stream(req, socket, options, head) { - var r = http.request( + var proxyReq = http.request( common.setupOutgoing(options.ssl || {}, options, req) ); - r.on('upgrade', function(proxyRes, proxySocket, proxyHead) { + proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead); socket.write('HTTP/1.1 101 Switching Protocols\r\n'); @@ -86,7 +86,7 @@ function stream(req, socket, options, head) { proxySocket.pipe(socket).pipe(proxySocket); }); - r.end(); + proxyReq.end(); } ] // <-- From 07cfa6b981ff54d8d96eea6c9aa4b560ee3867ec Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 13:17:45 +0200 Subject: [PATCH 053/556] [experiment] new api for proxying --- lib/caronte/passes/web.js | 17 +++++++++++++++-- ttest.js | 22 ++++++++++++---------- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web.js index dc815abd0..363d8ff5e 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web.js @@ -1,5 +1,8 @@ var ForwardStream = require('../streams/forward'), ProxyStream = require('../streams/proxy'), + http = require('http'), + https = require('https'), + common = require('../common'), passes = exports; /*! @@ -84,7 +87,17 @@ function XHeaders(req, res, options) { */ function stream(req, res, options) { - if(options.forward) { + var proxyReq = (options.ssl ? https : http).request( + common.setupOutgoing(options.ssl || {}, options, req) + ); + + proxyReq.on('response', function(proxyRes) { + req.pipe(proxyRes).pipe(res); + }); + + proxyReq.end(); + + /*if(options.forward) { req.pipe(new ForwardStream(options)); } @@ -92,7 +105,7 @@ function stream(req, res, options) { return req.pipe(new ProxyStream(options, res)).pipe(res); } - res.end(); + res.end();*/ } ] // <-- diff --git a/ttest.js b/ttest.js index ee34ed61e..2101db6d4 100644 --- a/ttest.js +++ b/ttest.js @@ -3,7 +3,7 @@ var caronte = require('./'), http = require('http'), ws = require('ws'); -var proxyTo = new ws.Server({ port: 9090 }); +/*var proxyTo = new ws.Server({ port: 9090 }); proxyTo.on('connection', function(ws) { console.log('connection!'); @@ -16,12 +16,6 @@ proxyTo.on('connection', function(ws) { ws.send('derpity?'); }); -caronte.createProxyServer({ - ws : true, - target: 'http://127.0.0.1:9090' -}).listen(8000); - - var client = new ws('ws://127.0.0.1:8000'); client.on('open', function() { client.send('baaaka'); @@ -33,12 +27,20 @@ client.on('open', function() { console.log('server said: ' + msg); }); }); +*/ + + +caronte.createProxyServer({ + ws : true, + target: 'http://127.0.0.1:9090' +}).listen(8080); -/*var srv = http.createServer(function(req, res) { - res.end('1'); -}).listen(8000); +var srv = http.createServer(function(req, res) { + res.end('ciao proxy'); +}).listen(9090); +/* srv.on('upgrade', function(req, sock, head) { var options = { From 031aa0fbf30bd377696c4efa508f6fc769bf1070 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 13:33:38 +0200 Subject: [PATCH 054/556] [fix] slimmer proxying --- lib/caronte/passes/web.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web.js index 363d8ff5e..33da58575 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web.js @@ -91,8 +91,10 @@ function stream(req, res, options) { common.setupOutgoing(options.ssl || {}, options, req) ); + req.pipe(proxyReq); + proxyReq.on('response', function(proxyRes) { - req.pipe(proxyRes).pipe(res); + proxyRes.pipe(res); }); proxyReq.end(); From 8c8c455541f21ad9a9ac7ca19d1f37368206a2e2 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 14:00:31 +0200 Subject: [PATCH 055/556] support forward --- lib/caronte/passes/web.js | 18 ++++++++++++------ ttest.js | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web.js index 33da58575..6f82da22e 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web.js @@ -1,9 +1,7 @@ -var ForwardStream = require('../streams/forward'), - ProxyStream = require('../streams/proxy'), - http = require('http'), - https = require('https'), - common = require('../common'), - passes = exports; +var http = require('http'), + https = require('https'), + common = require('../common'), + passes = exports; /*! * Array of passes. @@ -87,6 +85,14 @@ function XHeaders(req, res, options) { */ function stream(req, res, options) { + if(options.forward) { + var forwardReq = (options.ssl ? https : http).request( + common.setupOutgoing(options.ssl || {}, options, req, 'forward') + ); + req.pipe(forwardReq); + return res.end(); + } + var proxyReq = (options.ssl ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req) ); diff --git a/ttest.js b/ttest.js index 2101db6d4..3f945e4aa 100644 --- a/ttest.js +++ b/ttest.js @@ -32,13 +32,14 @@ client.on('open', function() { caronte.createProxyServer({ ws : true, - target: 'http://127.0.0.1:9090' + forward: 'http://127.0.0.1:9090' }).listen(8080); var srv = http.createServer(function(req, res) { res.end('ciao proxy'); + console.log('suca'); }).listen(9090); /* srv.on('upgrade', function(req, sock, head) { From 886a8707078f59d0467b34686455bb5bdfadbc0c Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 18:44:39 +0200 Subject: [PATCH 056/556] [docs] readme --- .gitignore | 2 +- README.md | 46 +++++++++++++++++++++++++++++++++++++ ttest.js | 67 ------------------------------------------------------ 3 files changed, 47 insertions(+), 68 deletions(-) create mode 100644 README.md delete mode 100644 ttest.js diff --git a/.gitignore b/.gitignore index 517f9cee0..d1ae71570 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules *.swp cov -!ttest.js +atest.js notes diff --git a/README.md b/README.md new file mode 100644 index 000000000..cf7e59a72 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +Caronte +======= + +Caronte is an HTTP programmable proxying library that supports +websockets. It is suitable for implementing components such as +proxies and load balancers. + +### 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) + +### Test + +``` +$ npm test +``` + +### License + +``` +The MIT License (MIT) + +Copyright (c) 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. +``` diff --git a/ttest.js b/ttest.js deleted file mode 100644 index 3f945e4aa..000000000 --- a/ttest.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; /* jshint node:true */ -var caronte = require('./'), - http = require('http'), - ws = require('ws'); - -/*var proxyTo = new ws.Server({ port: 9090 }); - -proxyTo.on('connection', function(ws) { - console.log('connection!'); - ws.on('message', function(msg) { - ws.send('ohai: ' + msg); - setTimeout(function() { - ws.send('HAHAHHA'); - }, 10000); - }); - ws.send('derpity?'); -}); - -var client = new ws('ws://127.0.0.1:8000'); -client.on('open', function() { - client.send('baaaka'); - console.log('sent: baaaaka'); - setTimeout(function() { - client.send('cacca'); - }, 5000); - client.on('message', function(msg) { - console.log('server said: ' + msg); - }); -}); -*/ - - -caronte.createProxyServer({ - ws : true, - forward: 'http://127.0.0.1:9090' -}).listen(8080); - - - -var srv = http.createServer(function(req, res) { - res.end('ciao proxy'); - console.log('suca'); -}).listen(9090); -/* -srv.on('upgrade', function(req, sock, head) { - - var options = { - port: 9090, - hostname: '127.0.0.1', - headers: req.headers - } - var r = http.request(options); - - r.on('upgrade', function(res, proxySock, hd) { - if (hd && hd.length) proxySock.unshift(hd); - - sock.write('HTTP/1.1 101 Switching Protocols\r\n'); - sock.write(Object.keys(res.headers).map(function(i) { - return i + ": " + res.headers[i]; - }).join('\r\n') + '\r\n\r\n'); - proxySock.pipe(sock).pipe(proxySock); - }); - - r.end(); -}); - -*/ From c4ddc4edd324d9910a11eea14561a0e3b953f29c Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 18:46:13 +0200 Subject: [PATCH 057/556] [fix] quote --- README.md | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index cf7e59a72..932822d72 100644 --- a/README.md +++ b/README.md @@ -21,26 +21,25 @@ $ npm test ### License -``` -The MIT License (MIT) - -Copyright (c) 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. -``` +>The MIT License (MIT) +> +>Copyright (c) 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. + From ec981c5b74bf43dd36c8ca89833b751f59f01d38 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 19:10:33 +0200 Subject: [PATCH 058/556] [fix] docs --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index 932822d72..9a2db2273 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,42 @@ Caronte is an HTTP programmable proxying library that supports websockets. It is suitable for implementing components such as proxies and load balancers. +### Core Concept + +A new proxy is created by calling `createProxyServer` and passing +an `options` object as argument ([valid properties are available here](https://github.com/yawnt/caronte/blob/master/lib/caronte.js#L26-L39)) + +```javascript +var caronte = require('caronte'); + +var proxy = caronte.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) +* ee (an EventEmitter2 that emits events, you can hook into them to customize behaviour) +* 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' }); +}); +``` + +When a request is proxied it follows two different pipelines ([available here](https://github.com/yawnt/caronte/tree/master/lib/caronte/passes)) +which apply trasformations 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 datas +to the client. + +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. + ### Contributing and Issues * Search on Google/Github From 63b016c8ef7ba4520a4b4ab171b145585e5d30eb Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 22:03:00 +0200 Subject: [PATCH 059/556] [fix] yawnt baaaka .. fixes #8 --- lib/caronte/common.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/caronte/common.js b/lib/caronte/common.js index 68f4a9292..52b776716 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -25,9 +25,11 @@ common.setupOutgoing = function(outgoing, options, req, forward) { function(e) { outgoing[e] = options[forward || 'target'][e]; } ); - ['method', 'path', 'headers'].forEach( + ['method', 'headers'].forEach( function(e) { outgoing[e] = req[e]; } ); + outgoing.path = req.url; + return outgoing; -}; \ No newline at end of file +}; From dad211e71c9ac3b32eba1ea3755edb688053b9d3 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 22:52:22 +0200 Subject: [PATCH 060/556] keepalive sockets --- .gitignore | 1 + lib/caronte/common.js | 9 ++++++++ lib/caronte/passes/ws.js | 4 ++++ primus-proxy.js | 50 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 primus-proxy.js diff --git a/.gitignore b/.gitignore index d1ae71570..0e8f9c134 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules cov atest.js notes +prismus-proxy.js diff --git a/lib/caronte/common.js b/lib/caronte/common.js index 52b776716..2a2954bb5 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -33,3 +33,12 @@ common.setupOutgoing = function(outgoing, options, req, forward) { return outgoing; }; + +common.setupSocket = function(socket) { + socket.setTimeout(0); + socket.setNoDelay(true); + + socket.setKeepAlive(true, 0); + + return socket; +}; diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index 821cb2eb0..1c9215b84 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -72,11 +72,15 @@ function XHeaders(req, socket, options) { * */ function stream(req, socket, options, head) { + common.setupSocket(socket); + var proxyReq = http.request( common.setupOutgoing(options.ssl || {}, options, req) ); proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { + common.setupSocket(proxySocket); + if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead); socket.write('HTTP/1.1 101 Switching Protocols\r\n'); diff --git a/primus-proxy.js b/primus-proxy.js new file mode 100644 index 000000000..9a23276a0 --- /dev/null +++ b/primus-proxy.js @@ -0,0 +1,50 @@ +var http = require('http'); +var caronte = require('./'); +var Primus = require('primus'); + +var server = http.createServer(function (req, res) { + res.writeHead(500); + res.end('Not Implemented\n'); +}); + +var primus = new Primus(server, { transformer: 'engine.io' }); +var Socket = primus.Socket; + +primus.on('error', function (err) { + console.log('Primus ' + err); +}); + +primus.on('connection', function (spark) { + spark.write({ from: 'server', to: 'client' }); + + spark.on('data', function (data) { + console.dir(data); + }); +}); + +primus.on('disconnection', function (spark) { + console.log('disconnected'); +}); + +server.listen(9000); + +var proxy = caronte.createProxyServer({ + ws: true, + target: 'http://localhost:9000' +}); + +var srv = proxy.listen(3000); + +var socket = new Socket('http://localhost:3000'); + +socket.on('reconnecting', function () { + console.log('reconnecting'); +}); + +socket.on('open', function () { + socket.write({ from: 'client', to: 'server' }) +}); + +socket.on('data', function (data) { + console.dir(data); +}); From 7599cee3fd03a5ce645e313f35557a41c9ac1aee Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 14 Sep 2013 22:52:45 +0200 Subject: [PATCH 061/556] [fix] minor --- .gitignore | 2 +- primus-proxy.js | 50 ------------------------------------------------- 2 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 primus-proxy.js diff --git a/.gitignore b/.gitignore index 0e8f9c134..a39b4e147 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ node_modules cov atest.js notes -prismus-proxy.js +primus-proxy.js diff --git a/primus-proxy.js b/primus-proxy.js deleted file mode 100644 index 9a23276a0..000000000 --- a/primus-proxy.js +++ /dev/null @@ -1,50 +0,0 @@ -var http = require('http'); -var caronte = require('./'); -var Primus = require('primus'); - -var server = http.createServer(function (req, res) { - res.writeHead(500); - res.end('Not Implemented\n'); -}); - -var primus = new Primus(server, { transformer: 'engine.io' }); -var Socket = primus.Socket; - -primus.on('error', function (err) { - console.log('Primus ' + err); -}); - -primus.on('connection', function (spark) { - spark.write({ from: 'server', to: 'client' }); - - spark.on('data', function (data) { - console.dir(data); - }); -}); - -primus.on('disconnection', function (spark) { - console.log('disconnected'); -}); - -server.listen(9000); - -var proxy = caronte.createProxyServer({ - ws: true, - target: 'http://localhost:9000' -}); - -var srv = proxy.listen(3000); - -var socket = new Socket('http://localhost:3000'); - -socket.on('reconnecting', function () { - console.log('reconnecting'); -}); - -socket.on('open', function () { - socket.write({ from: 'client', to: 'server' }) -}); - -socket.on('data', function (data) { - console.dir(data); -}); From 6e77cd390929842088ae9f6deb922a6627ddfecd Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 00:43:01 +0200 Subject: [PATCH 062/556] [fix] do not call .end --- lib/caronte/passes/web.js | 2 +- lib/caronte/passes/ws.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web.js index 6f82da22e..64ee2875c 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web.js @@ -103,7 +103,7 @@ function stream(req, res, options) { proxyRes.pipe(res); }); - proxyReq.end(); + //proxyReq.end(); /*if(options.forward) { req.pipe(new ForwardStream(options)); diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index 1c9215b84..63a4deeaf 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -90,7 +90,7 @@ function stream(req, socket, options, head) { proxySocket.pipe(socket).pipe(proxySocket); }); - proxyReq.end(); + proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT } ] // <-- From 92de6a6f951a6a82e61cc34b5de9dc378d65e788 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sat, 14 Sep 2013 20:46:05 -0400 Subject: [PATCH 063/556] [fix] add ability to proxy websockets over HTTPS --- lib/caronte/passes/ws.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index 63a4deeaf..baf13a723 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -1,10 +1,11 @@ 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. @@ -60,7 +61,7 @@ function XHeaders(req, socket, options) { }; ['for', 'port', 'proto'].forEach(function(header) { - req.headers['x-forwarded-' + header] = + req.headers['x-forwarded-' + header] = (req.headers['x-forwarded-' + header] || '') + (req.headers['x-forwarded-' + header] ? ',' : '') + values[header] @@ -74,10 +75,10 @@ function XHeaders(req, socket, options) { function stream(req, socket, options, head) { common.setupSocket(socket); - var proxyReq = http.request( + var proxyReq = (options.ssl ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req) ); - + proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { common.setupSocket(proxySocket); @@ -95,5 +96,5 @@ function stream(req, socket, options, head) { ] // <-- .forEach(function(func) { - passes[func.name] = func; + passes[func.name] = func; }); From 3c91ed3d26d9af640d0c7a09fb9cdaf80ad673ca Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 13:03:51 +0200 Subject: [PATCH 064/556] [fix] proxy to http(s) --- lib/caronte/passes/ws.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index baf13a723..1fd3fd780 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -75,7 +75,7 @@ function XHeaders(req, socket, options) { function stream(req, socket, options, head) { common.setupSocket(socket); - var proxyReq = (options.ssl ? https : http).request( + var proxyReq = (~['https:', 'wss:'].indexOf(options.target.protocol) ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req) ); From 26c4c43a06263ec6721bc0e8a90644297d0cf217 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 13:06:39 +0200 Subject: [PATCH 065/556] [fix] proxying to https --- lib/caronte/passes/web.js | 4 ++-- lib/caronte/passes/ws.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web.js index 64ee2875c..8c70a6e1a 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web.js @@ -86,14 +86,14 @@ function XHeaders(req, res, options) { function stream(req, res, options) { if(options.forward) { - var forwardReq = (options.ssl ? https : http).request( + var forwardReq = (options.target.protocol === 'https:' ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req, 'forward') ); req.pipe(forwardReq); return res.end(); } - var proxyReq = (options.ssl ? https : http).request( + var proxyReq = (options.target.protocol === 'https:' ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req) ); diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index 1fd3fd780..a14386666 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -74,7 +74,7 @@ function XHeaders(req, socket, options) { */ function stream(req, socket, options, head) { common.setupSocket(socket); - + console.log(options.target.protocol); var proxyReq = (~['https:', 'wss:'].indexOf(options.target.protocol) ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req) ); From 18341d559717e0a86f5ee4da024109e4b5a595a7 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 13:07:24 +0200 Subject: [PATCH 066/556] [fix] console --- lib/caronte/passes/ws.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws.js index a14386666..1fd3fd780 100644 --- a/lib/caronte/passes/ws.js +++ b/lib/caronte/passes/ws.js @@ -74,7 +74,7 @@ function XHeaders(req, socket, options) { */ function stream(req, socket, options, head) { common.setupSocket(socket); - console.log(options.target.protocol); + var proxyReq = (~['https:', 'wss:'].indexOf(options.target.protocol) ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req) ); From d1663549ec070e7ae8bc45ffb148f40ee903192f Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 13:18:21 +0200 Subject: [PATCH 067/556] [fix] default port --- lib/caronte/common.js | 5 +- lib/caronte/streams/forward.js | 88 ---------------------------- lib/caronte/streams/proxy.js | 104 --------------------------------- 3 files changed, 4 insertions(+), 193 deletions(-) delete mode 100644 lib/caronte/streams/forward.js delete mode 100644 lib/caronte/streams/proxy.js diff --git a/lib/caronte/common.js b/lib/caronte/common.js index 2a2954bb5..6b75c6f47 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -21,7 +21,10 @@ var common = exports; */ common.setupOutgoing = function(outgoing, options, req, forward) { - ['host', 'hostname', 'port', 'socketPath', 'agent'].forEach( + outgoing.port = options[forward || 'target'].port || + (~['https:', 'wss:'].indexOf(options[forward || 'target'].protocol) ? 443 : 80); + + ['host', 'hostname', 'socketPath', 'agent'].forEach( function(e) { outgoing[e] = options[forward || 'target'][e]; } ); diff --git a/lib/caronte/streams/forward.js b/lib/caronte/streams/forward.js deleted file mode 100644 index b1bb58f3b..000000000 --- a/lib/caronte/streams/forward.js +++ /dev/null @@ -1,88 +0,0 @@ -var Writable = require('stream').Writable, - common = require('../common'), - http = require('http'), - https = require('https'); - -module.exports = ForwardStream; - -/** - * Forwards the request to the external target specified in options - * - * Examples: - * - * new ForwardStream(options) - * // => { ... } - * - * @param {Object} Options Config object passed to the proxy - *  - * @return {ForwardStream} Stream A clone of ForwardStream - * - * @api private - */ - -function ForwardStream(options) { - var self = this; - - self.options = options; - // To uncomment the line below, please see - // https://github.com/yawnt/caronte/commit/9ab8749a9bec33b49c495975e8364336ad7be1a3#commitcomment-3947117 - //self.res = res; - - Writable.call(this); - - this.once('pipe', function(pipe) { self.onPipe(pipe) }); - this.once('finish', function() { self.onFinish() }); -} - -require('util').inherits(ForwardStream, Writable); - -/** - * Fires up the request to the external target - * - * Examples: - * - * (new ForwardStream(options)).onPipe(req) - * // => undefined - * - * @param {HttpRequest} Req Request object - * - * @api private - */ - -ForwardStream.prototype.onPipe = function(request) { - this.forwardReq = (this.options.ssl ? https : http).request( - common.setupOutgoing(this.options.ssl || {}, this.options, request, 'forward') - ); - - this.forwardReq.on('error', function() {}); /** Fire and forget */ -}; - -/** - * Closes forwarded request when `pipe` is finished. - * - * Examples: - * - * (new ForwardStream(options)).onFinish() - * // => undefined - * - * @api private - */ - -ForwardStream.prototype.onFinish = function() { - this.forwardReq.end(); -}; - -/** - * Implements `stream.Writable`, writes to the forwarded request - * - * Examples: - * - * (new ForwardStream(options))._write(chunk, encoding, clb) - * // => undefined - * - * @api private - */ - -ForwardStream.prototype._write = function(chunk, encoding, clb) { - this.forwardReq.write(chunk, encoding, clb); -}; diff --git a/lib/caronte/streams/proxy.js b/lib/caronte/streams/proxy.js deleted file mode 100644 index 29c2fa78f..000000000 --- a/lib/caronte/streams/proxy.js +++ /dev/null @@ -1,104 +0,0 @@ -var Duplex = require('stream').Duplex, - common = require('../common'), - http = require('http'), - https = require('https'); - -module.exports = ProxyStream; - -function ProxyStream(options, res) { - Duplex.call(this); - - this.options = options; - this.res = res; - - var self = this; - - this.once('pipe', function(pipe) { self.onPipe(pipe); }); - this.once('finish', function() { self.onFinish(); }); -} - -require('util').inherits(ProxyStream, Duplex); - -ProxyStream.prototype.onPipe = function(req) { - this.req = req; - - var self = this; - - this.proxyReq = (self.options.ssl ? https : http).request( - common.setupOutgoing(self.options.ssl || {}, self.options, req) - ); - //console.log(common.setupOutgoing(self.options.ssl || {}, self.options, req)); - this.proxyReq.once('response', function(proxyRes) { - self.onResponse(proxyRes); - }); - this.proxyReq.on('error', function(e) { - self.onError(e); - }); -}; - -ProxyStream.prototype.onFinish = function() { - this.proxyReq.end(); -}; - -ProxyStream.prototype.onResponse = function(proxyRes) { - this.proxyRes = proxyRes; - - var self = this; - - if(this.req.httpVersion === '1.0') { - proxyRes.headers.connection = this.req.headers.connection || 'close'; - } - else if(!proxyRes.headers.connection) { - proxyRes.headers.connection = this.req.headers.connection || 'keep-alive'; - } - - if(this.req.httpVersion === '1.0' || (this.req.method === 'DELETE' && !this.req.headers['content-length'])) { - delete proxyRes.headers['transfer-encoding']; - } - - /*if(~[301,302].indexOf(this.res.statusCode) && typeof this.res.headers.location !== 'undefined') { - var location = url.parse(this.res.headers.location); - if ( - location.host === this.req.headers.host && - ( - source.https && !target.https || - target.https && !source.https - ) - ) { - this.res.headers.location = this.res.headers.location.replace(/^https\:/, 'http:'); - } - }*/ - - Object.keys(proxyRes.headers).forEach(function (key) { - self.res.setHeader(key, proxyRes.headers[key]); - }); - - this.res.writeHead(proxyRes.statusCode); - - proxyRes.on('readable', function() { - self.read(0); - }); - - proxyRes.on('end', function() { - self.push(null); - }); - - self.emit('readable'); -}; - -ProxyStream.prototype.onError = function(e) { - if(this.options.ee.emit('proxyError', this.req, this.res, e)) return; - - this.res.writeHead(500, { 'Content-Type': 'text/plain' }); - this.res.end('Internal Server Error'); -}; - -ProxyStream.prototype._write = function(chunk, encoding, callback) { - this.proxyReq.write(chunk, encoding, callback); -}; - -ProxyStream.prototype._read = function(size) { - var chunk = (this.proxyRes ? this.proxyRes.read(size) : '') || ''; - - this.push(chunk); -}; From 58238421945bcc4236e280ebca7799b831ae29a4 Mon Sep 17 00:00:00 2001 From: sateffen Date: Sun, 15 Sep 2013 13:39:38 +0200 Subject: [PATCH 068/556] [Fix] 2 spelling mistakes --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9a2db2273..6b4637c56 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,9 @@ require('http').createServer(function(req, res) { ``` When a request is proxied it follows two different pipelines ([available here](https://github.com/yawnt/caronte/tree/master/lib/caronte/passes)) -which apply trasformations to both the `req` and `res` object. +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 datas +The second pipeline (outgoing) is responsible for the creation and manipulation of the stream that, from your target, returns data to the client. You can easily add a `pass` (stages) into both the pipelines (XXX: ADD API). From 4c2f2f3b9a5ba65f97403e778a670f14301d52c1 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 14:57:19 +0200 Subject: [PATCH 069/556] [logo] --- doc/logo.png | Bin 0 -> 48744 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/logo.png diff --git a/doc/logo.png b/doc/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..412de186b2ea95b4d34c5ec4a1dc178c8f7bd252 GIT binary patch literal 48744 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

?lwdFnp@9#ccGq@gLZS| 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 Date: Sun, 15 Sep 2013 14:59:55 +0200 Subject: [PATCH 070/556] [docs] add logo --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 6b4637c56..c067d83a8 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,11 @@ Caronte is an HTTP programmable proxying library that supports websockets. It is suitable for implementing components such as proxies and load balancers. +

+ logo +

+ + ### Core Concept A new proxy is created by calling `createProxyServer` and passing From 57abb7f26c14e281c3be07a8b84e3c79e066f59f Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 15:00:53 +0200 Subject: [PATCH 071/556] [fix] move logo --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c067d83a8..c18fea1fe 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,13 @@ Caronte ======= -Caronte is an HTTP programmable proxying library that supports -websockets. It is suitable for implementing components such as -proxies and load balancers. -

logo

+Caronte is an HTTP programmable proxying library that supports +websockets. It is suitable for implementing components such as +proxies and load balancers. ### Core Concept From aaff1966e4e2eb42c9890e57737f57a64e8d964a Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 15:01:30 +0200 Subject: [PATCH 072/556] [fix] move logo --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c18fea1fe..9c30f9c69 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -Caronte -======= -

logo

+Caronte +======= + Caronte is an HTTP programmable proxying library that supports websockets. It is suitable for implementing components such as proxies and load balancers. From ee3cc380665a31ec6af28ddb73dfc543f430d3f8 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 15:05:22 +0200 Subject: [PATCH 073/556] [fix] new logo --- README.md | 6 +++++- doc/logo.png | Bin 48744 -> 47464 bytes 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c30f9c69..842d59cee 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- logo + Logo by DiegoPQ

Caronte @@ -59,6 +59,10 @@ In addition, every stage emits a corresponding event so introspection during the $ npm test ``` +### Logo + +Logo created by [Diego Pasquali](http://dribbble.com/diegopq) + ### License >The MIT License (MIT) diff --git a/doc/logo.png b/doc/logo.png index 412de186b2ea95b4d34c5ec4a1dc178c8f7bd252..a36bdcf2aa5a926166b3d3797025a420ab155132 100644 GIT binary patch delta 32813 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 Vq%`yL0x0mGqO6KcvDEW`{{{a$t(^b> delta 34118 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+!Hmn+6lnWVGC??|X_PWaxFk#vxsMWhux1D_Fg{ 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
vcMUfF%YLH4i>v8){W>}uLfl-DVzU7@o-pR- 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 Date: Sun, 15 Sep 2013 15:07:09 +0200 Subject: [PATCH 074/556] [fix] layout --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 842d59cee..f66f59abd 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Logo by DiegoPQ +

Caronte From dd0f7b8876ae5b57fffab8857735b25b159f2bdb Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 15:07:39 +0200 Subject: [PATCH 075/556] [docs] logo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f66f59abd..eb1c779a7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

Caronte From 4d3a4e1ee7370347898d1863ab73aa68ed345d8d Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 15:30:05 +0200 Subject: [PATCH 076/556] [fix] readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eb1c779a7..b8c4196fa 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

Caronte @@ -12,7 +12,7 @@ proxies and load balancers. ### Core Concept A new proxy is created by calling `createProxyServer` and passing -an `options` object as argument ([valid properties are available here](https://github.com/yawnt/caronte/blob/master/lib/caronte.js#L26-L39)) +an `options` object as argument ([valid properties are available here](tree/master/lib/caronte.js#L26-L39)) ```javascript var caronte = require('caronte'); @@ -35,7 +35,7 @@ require('http').createServer(function(req, res) { }); ``` -When a request is proxied it follows two different pipelines ([available here](https://github.com/yawnt/caronte/tree/master/lib/caronte/passes)) +When a request is proxied it follows two different pipelines ([available here](tree/master/lib/caronte/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 From 0637322d96e54bbcf5a14bf009dd73314cada4ce Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 15:33:48 +0200 Subject: [PATCH 077/556] [fix] url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b8c4196fa..86e7ff746 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

Caronte From adc5be020c7fff09a1c05ac771d5c5ab61002c23 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 17:19:07 +0200 Subject: [PATCH 078/556] [fix] opts --- lib/caronte/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 586ed3f60..ca3e64395 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -41,7 +41,7 @@ function createRightProxy(type) { !(args[cntr] instanceof Buffer) && args[cntr] !== res ) { - options = opts; + options = args[cntr]; cntr--; } From 60de543d04eaddec018a09634edc427a87cb6b68 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 17:55:41 +0200 Subject: [PATCH 079/556] [fix] headers, fixes #467 --- lib/caronte/index.js | 4 ++-- lib/caronte/passes/web-outgoing.js | 20 +++++++++++++++++++ lib/caronte/passes/web.js | 32 ++++++++++++++++++++---------- 3 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 lib/caronte/passes/web-outgoing.js diff --git a/lib/caronte/index.js b/lib/caronte/index.js index ca3e64395..4f4139d61 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -34,7 +34,7 @@ function createRightProxy(type) { var self = this, args = [].slice.call(arguments), cntr = args.length - 1, - ev = 'caronte:' + type + ':', + ev = 'caronte:' + type + ':incoming:', head; if( @@ -53,7 +53,7 @@ function createRightProxy(type) { passes.some(function(pass) { - var evnt = ev + pass.name.toLowerCase(); + var evnt = ev + pass.name.toLowerCase() + ':'; options.ee.emit(evnt + 'begin', req, res); var val = pass(req, res, options, head); diff --git a/lib/caronte/passes/web-outgoing.js b/lib/caronte/passes/web-outgoing.js new file mode 100644 index 000000000..b0f86ce4d --- /dev/null +++ b/lib/caronte/passes/web-outgoing.js @@ -0,0 +1,20 @@ +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. + */ + +[ // <-- + function writeHeaders(res, proxyRes) { + Object.keys(proxyRes.headers).forEach(function(key) { + res.setHeader(key, proxyRes.headers[key]); + }); + } +] // <-- + .forEach(function(func) { + passes[func.name] = func; + }); diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web.js index 8c70a6e1a..c7a925d2e 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web.js @@ -1,8 +1,13 @@ 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. * @@ -100,20 +105,27 @@ function stream(req, res, options) { req.pipe(proxyReq); proxyReq.on('response', function(proxyRes) { + var ev = 'caronte:outgoing:web:'; + + options.ee.emit(ev + 'begin', req, res); + + web_o.some(function(pass) { + var evnt = ev + pass.name.toLowerCase() + ':'; + + options.ee.emit(evnt + 'begin', req, res); + var val = pass(res, proxyRes); + options.ee.emit(evnt + 'end'); + + return val; + }); + + options.ee.emit(ev + 'end'); + + proxyRes.pipe(res); }); //proxyReq.end(); - - /*if(options.forward) { - req.pipe(new ForwardStream(options)); - } - - if(options.target) { - return req.pipe(new ProxyStream(options, res)).pipe(res); - } - - res.end();*/ } ] // <-- From e08d4edad339d0f7f55900b3e6e6a0e770960215 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 18:02:00 +0200 Subject: [PATCH 080/556] [fix] write status --- lib/caronte/index.js | 4 ++-- lib/caronte/passes/{web.js => web-incoming.js} | 2 +- lib/caronte/passes/web-outgoing.js | 6 ++++++ lib/caronte/passes/{ws.js => ws-incoming.js} | 0 4 files changed, 9 insertions(+), 3 deletions(-) rename lib/caronte/passes/{web.js => web-incoming.js} (97%) rename lib/caronte/passes/{ws.js => ws-incoming.js} (100%) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 4f4139d61..30db143f5 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -1,6 +1,6 @@ var caronte = exports, - web = require('./passes/web'); - ws = require('./passes/ws'); + web = require('./passes/web-incoming'); + ws = require('./passes/ws-incoming'); caronte.createWebProxy = createRightProxy('web'); caronte.createWsProxy = createRightProxy('ws'); diff --git a/lib/caronte/passes/web.js b/lib/caronte/passes/web-incoming.js similarity index 97% rename from lib/caronte/passes/web.js rename to lib/caronte/passes/web-incoming.js index c7a925d2e..6906ae873 100644 --- a/lib/caronte/passes/web.js +++ b/lib/caronte/passes/web-incoming.js @@ -91,7 +91,7 @@ function XHeaders(req, res, options) { function stream(req, res, options) { if(options.forward) { - var forwardReq = (options.target.protocol === 'https:' ? https : http).request( + var forwardReq = (options.forward.protocol === 'https:' ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req, 'forward') ); req.pipe(forwardReq); diff --git a/lib/caronte/passes/web-outgoing.js b/lib/caronte/passes/web-outgoing.js index b0f86ce4d..4e981518b 100644 --- a/lib/caronte/passes/web-outgoing.js +++ b/lib/caronte/passes/web-outgoing.js @@ -9,11 +9,17 @@ var passes = exports; */ [ // <-- + + function writeStatusCode(res, proxyRes) { + res.writeHead(proxyRes.statusCode); + }, + function writeHeaders(res, proxyRes) { Object.keys(proxyRes.headers).forEach(function(key) { res.setHeader(key, proxyRes.headers[key]); }); } + ] // <-- .forEach(function(func) { passes[func.name] = func; diff --git a/lib/caronte/passes/ws.js b/lib/caronte/passes/ws-incoming.js similarity index 100% rename from lib/caronte/passes/ws.js rename to lib/caronte/passes/ws-incoming.js From 29afab4488e098b1554441797f6a4e3dc450c21f Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 15 Sep 2013 22:07:19 +0200 Subject: [PATCH 081/556] [fix] headers, closes #469 --- lib/caronte/passes/web-outgoing.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/caronte/passes/web-outgoing.js b/lib/caronte/passes/web-outgoing.js index 4e981518b..941bc6001 100644 --- a/lib/caronte/passes/web-outgoing.js +++ b/lib/caronte/passes/web-outgoing.js @@ -9,15 +9,15 @@ var passes = exports; */ [ // <-- - - function writeStatusCode(res, proxyRes) { - res.writeHead(proxyRes.statusCode); - }, - + function writeHeaders(res, proxyRes) { Object.keys(proxyRes.headers).forEach(function(key) { res.setHeader(key, proxyRes.headers[key]); }); + }, + + function writeStatusCode(res, proxyRes) { + res.writeHead(proxyRes.statusCode); } ] // <-- From 1b867a7f594f7dfe49fc17ff53451a353ec509d9 Mon Sep 17 00:00:00 2001 From: srossross Date: Sun, 15 Sep 2013 15:20:51 -0700 Subject: [PATCH 082/556] 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 083/556] 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 084/556] 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 085/556] 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 086/556] 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 087/556] 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 From dfdedf23b71dc4c5cbeb034422c9214bd18401ae Mon Sep 17 00:00:00 2001 From: David Glasser Date: Mon, 16 Sep 2013 11:33:57 -0700 Subject: [PATCH 088/556] Fix accidental write to global variable. --- lib/caronte/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 30db143f5..5defa0e9b 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -1,5 +1,5 @@ var caronte = exports, - web = require('./passes/web-incoming'); + web = require('./passes/web-incoming'), ws = require('./passes/ws-incoming'); caronte.createWebProxy = createRightProxy('web'); From 469b0d4e9f065b94acf1f9e4a05a73b5efe48368 Mon Sep 17 00:00:00 2001 From: yawnt Date: Mon, 16 Sep 2013 21:36:09 +0200 Subject: [PATCH 089/556] [fix] add 0.10 compatibily.. closes #474 --- .gitignore | 1 + package.json | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index a39b4e147..099c4d9df 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ cov atest.js notes primus-proxy.js +tes.js diff --git a/package.json b/package.json index 9968b65b0..0f556b14e 100644 --- a/package.json +++ b/package.json @@ -24,5 +24,9 @@ "test-cov" : "mocha --require blanket -R html-cov > cov/coverage.html" }, + "engines" : { + "node" : ">=0.10.0" + }, + "license" : "MIT" } From da9de7034a452d1281217a349bc9403fddcc2b7f Mon Sep 17 00:00:00 2001 From: yawnt Date: Mon, 16 Sep 2013 22:12:52 +0200 Subject: [PATCH 090/556] [docs] fix syntax highlighting --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e5b38566b..c710504cc 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ In addition, every stage emits a corresponding event so introspection during the #### Setup a basic stand-alone proxy server +```js var http = require('http'), caronte = require('caronte'); // @@ -62,6 +63,7 @@ http.createServer(function (req, res) { 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 From f1aeb0500cde39b63e570323e0e478530d1222ab Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 15:26:44 -0500 Subject: [PATCH 091/556] [misc] use the local mocha instead the global --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0f556b14e..f11557c6d 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ }, "scripts" : { "blanket" : { "pattern": "caronte/lib" }, - "test" : "mocha -R landing test/*-test.js", - "test-cov" : "mocha --require blanket -R html-cov > cov/coverage.html" + "test" : "./node_modules/.bin/mocha -R landing test/*-test.js", + "test-cov" : "./node_modules/.bin/mocha --require blanket -R html-cov > cov/coverage.html" }, "engines" : { From 275a5192fa257f78287a954b347e65023795487d Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 16:49:51 -0500 Subject: [PATCH 092/556] [fix] typo --- lib/caronte/passes/ws-incoming.js | 2 +- ...sses-web-test.js => lib-caronte-passes-web-incoming-test.js} | 0 ...passes-ws-test.js => lib-caronte-passes-ws-incoming-test.js} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename test/{lib-caronte-passes-web-test.js => lib-caronte-passes-web-incoming-test.js} (100%) rename test/{lib-caronte-passes-ws-test.js => lib-caronte-passes-ws-incoming-test.js} (100%) diff --git a/lib/caronte/passes/ws-incoming.js b/lib/caronte/passes/ws-incoming.js index 3b5e1f525..0adab3db8 100644 --- a/lib/caronte/passes/ws-incoming.js +++ b/lib/caronte/passes/ws-incoming.js @@ -55,7 +55,7 @@ function XHeaders(req, socket, options) { if(!options.xfwd) return; var values = { - for : req.connection.remoteAddsockets || req.socket.remoteAddsockets, + for : req.connection.remoteAddress || req.socket.remoteAddress, port : req.connection.remotePort || req.socket.remotePort, proto: req.connection.pair ? 'wss' : 'ws' }; diff --git a/test/lib-caronte-passes-web-test.js b/test/lib-caronte-passes-web-incoming-test.js similarity index 100% rename from test/lib-caronte-passes-web-test.js rename to test/lib-caronte-passes-web-incoming-test.js diff --git a/test/lib-caronte-passes-ws-test.js b/test/lib-caronte-passes-ws-incoming-test.js similarity index 100% rename from test/lib-caronte-passes-ws-test.js rename to test/lib-caronte-passes-ws-incoming-test.js From 5bb83b967edb514402698eecfe3db7ab5fe60b06 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 16:50:30 -0500 Subject: [PATCH 093/556] [tests] make the tests run with the last refactor --- test/lib-caronte-passes-web-incoming-test.js | 2 +- test/lib-caronte-passes-ws-incoming-test.js | 148 +++++++++++++------ 2 files changed, 104 insertions(+), 46 deletions(-) diff --git a/test/lib-caronte-passes-web-incoming-test.js b/test/lib-caronte-passes-web-incoming-test.js index 4ec5ca1a2..cc0a760a7 100644 --- a/test/lib-caronte-passes-web-incoming-test.js +++ b/test/lib-caronte-passes-web-incoming-test.js @@ -1,4 +1,4 @@ -var caronte = require('../lib/caronte/passes/web'), +var caronte = require('../lib/caronte/passes/web-incoming'), expect = require('expect.js'); describe('lib/caronte/passes/web.js', function() { diff --git a/test/lib-caronte-passes-ws-incoming-test.js b/test/lib-caronte-passes-ws-incoming-test.js index f794cca3e..2c077d4df 100644 --- a/test/lib-caronte-passes-ws-incoming-test.js +++ b/test/lib-caronte-passes-ws-incoming-test.js @@ -1,87 +1,145 @@ -var caronte = require('../lib/caronte/passes/ws'), +var caronte = require('../lib/caronte/passes/ws-incoming'), expect = require('expect.js'); -describe('lib/caronte/passes/ws.js', function () { +describe('lib/caronte/passes/ws-incoming.js', function () { describe('#checkMethodAndHeader', function () { it('should drop non-GET connections', function () { - var endCalled = false, + var destroyCalled = false, stubRequest = { method: 'DELETE', - headers: {}, - end: function () { - // Simulate Stream.end() method when call - endCalled = true; - } + headers: {} }, - returnValue = caronte.checkMethodAndHeader(stubRequest, {}, {}); + stubSocket = { + destroy: function () { + // Simulate Socket.destroy() method when call + destroyCalled = true; + } + } + returnValue = caronte.checkMethodAndHeader(stubRequest, stubSocket); expect(returnValue).to.be(true); - expect(endCalled).to.be(true); + expect(destroyCalled).to.be(true); }) it('should drop connections when no upgrade header', function () { - var endCalled = false, + var destroyCalled = false, stubRequest = { method: 'GET', - headers: {}, - end: function () { - // Simulate Stream.end() method when call - endCalled = true; - } + headers: {} }, - returnValue = caronte.checkMethodAndHeader(stubRequest, {}, {}); + stubSocket = { + destroy: function () { + // Simulate Socket.destroy() method when call + destroyCalled = true; + } + } + returnValue = caronte.checkMethodAndHeader(stubRequest, stubSocket); expect(returnValue).to.be(true); - expect(endCalled).to.be(true); + expect(destroyCalled).to.be(true); }) it('should drop connections when upgrade header is different of `websocket`', function () { - var endCalled = false, + var destroyCalled = false, stubRequest = { method: 'GET', headers: { upgrade: 'anotherprotocol' - }, - end: function () { - // Simulate Stream.end() method when call - endCalled = true; } }, - returnValue = caronte.checkMethodAndHeader(stubRequest, {}, {}); + stubSocket = { + destroy: function () { + // Simulate Socket.destroy() method when call + destroyCalled = true; + } + } + returnValue = caronte.checkMethodAndHeader(stubRequest, stubSocket); expect(returnValue).to.be(true); - expect(endCalled).to.be(true); + expect(destroyCalled).to.be(true); }) it('should return nothing when all is ok', function () { - var endCalled = false, + var destroyCalled = false, stubRequest = { method: 'GET', headers: { upgrade: 'websocket' - }, - end: function () { - // Simulate Stream.end() method when call - endCalled = true; } }, - returnValue = caronte.checkMethodAndHeader(stubRequest, {}, {}); + stubSocket = { + destroy: function () { + // Simulate Socket.destroy() method when call + destroyCalled = true; + } + } + returnValue = caronte.checkMethodAndHeader(stubRequest, stubSocket); expect(returnValue).to.be(undefined); - expect(endCalled).to.be(false); + expect(destroyCalled).to.be(false); }) }); + describe('#setupSocket', function () { + it('Set the correct config to the socket', function () { + var stubSocket = { + setTimeout: function (num) { + // Simulate Socket.setTimeout() + socketConfig.timeout = num; + }, + setNoDelay: function (bol) { + // Simulate Socket.setNoDelay() + socketConfig.nodelay = bol; + }, + setKeepAlive: function (bol) { + // Simulate Socket.setKeepAlive() + socketConfig.keepalive = bol; + } + }, + socketConfig = { + timeout: null, + nodelay: false, + keepalive: false + }, + returnValue = caronte.setupSocket({}, stubSocket); + expect(returnValue).to.be(undefined); + expect(socketConfig.timeout).to.eql(0); + expect(socketConfig.nodelay).to.eql(true); + expect(socketConfig.keepalive).to.eql(true); + }); + }); + describe('#XHeaders', function () { - // var stubRequest = { - // connection: { - // remoteAddress: '192.168.1.2', - // remotePort: '8080' - // }, - // headers: {} - // } + it('return if no forward request', function () { + var returnValue = caronte.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: {} + } + caronte.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', function () { - // caronte.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'); - // }); + 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: {} + }; + caronte.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'); + }); }); }); From 1cb967b90aaa5b9da57727b8acbd95108437797a Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 17:27:06 -0500 Subject: [PATCH 094/556] [tests] fixed according new refactor and added test to common.setupSocket() --- test/lib-caronte-common-test.js | 66 ++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/test/lib-caronte-common-test.js b/test/lib-caronte-common-test.js index 3c2ccd109..1523cffd8 100644 --- a/test/lib-caronte-common-test.js +++ b/test/lib-caronte-common-test.js @@ -1,9 +1,9 @@ var common = require('../lib/caronte/common'), expect = require('expect.js'); -describe('lib/caronte/common.js', function() { - describe('#setupOutgoing', function() { - it('should setup the right headers', function() { +describe('lib/caronte/common.js', function () { + describe('#setupOutgoing', function () { + it('should setup the correct headers', function () { var outgoing = {}; common.setupOutgoing(outgoing, { @@ -17,7 +17,7 @@ describe('lib/caronte/common.js', function() { }, { method : 'i', - path : 'am', + url : 'am', headers : 'proxy' }); @@ -25,11 +25,67 @@ describe('lib/caronte/common.js', function() { 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.agent).to.eql('?'); expect(outgoing.method).to.eql('i'); expect(outgoing.path).to.eql('am'); expect(outgoing.headers).to.eql('proxy') }); + + it('set the port according to the protocol', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, + { + target: { + host : 'how', + hostname : 'are', + socketPath: 'you', + agent : '?', + 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 From 7b9169c8c58962b5f7c7a37d0da6847beac3b121 Mon Sep 17 00:00:00 2001 From: srossross Date: Mon, 16 Sep 2013 15:59:19 -0700 Subject: [PATCH 095/556] FIX: ws error event --- lib/caronte/passes/ws-incoming.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/caronte/passes/ws-incoming.js b/lib/caronte/passes/ws-incoming.js index 3b5e1f525..5fb99b609 100644 --- a/lib/caronte/passes/ws-incoming.js +++ b/lib/caronte/passes/ws-incoming.js @@ -83,7 +83,7 @@ function stream(req, socket, options, head) { if (options.ee.listeners(ev + 'error').length == 0){ throw err; } - options.ee.emit(ev + 'error', err, req, res); + options.ee.emit(ev + 'error', err, req, socket, head); }); proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { From dc9d7e5452c7d39ae1d242cb8021ca75e4f736d4 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 18:59:48 -0500 Subject: [PATCH 096/556] [tests] drop the test of own streams, moved the usable tests --- test/lib-caronte-streams-forward-test.js | 45 ------- test/lib-caronte-test.js | 154 ++++++++++++++++++++++- 2 files changed, 153 insertions(+), 46 deletions(-) delete mode 100644 test/lib-caronte-streams-forward-test.js diff --git a/test/lib-caronte-streams-forward-test.js b/test/lib-caronte-streams-forward-test.js deleted file mode 100644 index 5289856cc..000000000 --- a/test/lib-caronte-streams-forward-test.js +++ /dev/null @@ -1,45 +0,0 @@ -var caronte = require('../'), - ForwardStream = require('../lib/caronte/streams/forward'); - expect = require('expect.js'), - Writable = require('stream').Writable, - http = require('http'); - - -describe('lib/caronte/streams/forward.js', function () { - describe('forward stream constructor', function () { - it('should be an instance of Writable stream and get the correct options and methods', function () { - var stubOptions = { - key: 'value' - }; - var forwardProxy = new ForwardStream(stubOptions); - - expect(forwardProxy).to.be.a(Writable); - expect(forwardProxy.options).to.eql({ key: 'value' }); - expect(forwardProxy.onPipe).to.be.a('function'); - expect(forwardProxy.onFinish).to.be.a('function'); - expect(forwardProxy._events).to.have.property('pipe'); - expect(forwardProxy._events).to.have.property('finish'); - }); - }); - - describe('should pipe the request and finish it', function () { - it('should make the request on pipe and finish it', function(done) { - var result; - - var p = caronte.createProxyServer({ - forward: 'http://127.0.0.1:8080' - }).listen('8081') - - var s = http.createServer(function(req, res) { - expect(req.method).to.eql('GET'); - s.close(); - p.close(); - done(); - }); - - s.listen('8080'); - - http.request('http://127.0.0.1:8081', function() {}).end(); - }); - }); -}); diff --git a/test/lib-caronte-test.js b/test/lib-caronte-test.js index 8358c5f99..dbb278f71 100644 --- a/test/lib-caronte-test.js +++ b/test/lib-caronte-test.js @@ -1,5 +1,6 @@ var caronte = require('../lib/caronte'), - expect = require('expect.js'); + expect = require('expect.js'), + http = require('http'); describe('lib/caronte.js', function() { describe('#createProxyServer', function() { @@ -24,4 +25,155 @@ describe('lib/caronte.js', 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 proxy = caronte.createProxyServer({ + forward: 'http://127.0.0.1:8080' + }).listen('8081') + + var source = http.createServer(function(req, res) { + expect(req.method).to.eql('GET'); + expect(req.headers.host.split(':')[1]).to.eql('8081'); + source.close(); + proxy.close(); + done(); + }); + + source.listen('8080'); + + http.request('http://127.0.0.1:8081', function() {}).end(); + }) + }); + + describe('#createProxyServer using the web-incoming passes', function () { + it('should make the request on pipe and finish it', function(done) { + var proxy = caronte.createProxyServer({ + target: 'http://127.0.0.1:8080' + }).listen('8081'); + + 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('8081'); + source.close(); + proxy.close(); + done(); + }); + + source.listen('8080'); + + http.request({ + hostname: '127.0.0.1', + port: '8081', + 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 proxy = caronte.createProxyServer({ + target: 'http://127.0.0.1:8080' + }).listen('8081'); + + var 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); + }); + + source.listen('8080'); + + 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 () { + source.close(); + proxy.close(); + done(); + }); + }).end(); + }); + }); + + describe('#createProxyServer() method with error response', function () { + it('should make the request and emit the error event', function(done) { + var proxy = caronte.createProxyServer({ + target: 'http://127.0.0.1:8080' + }); + + proxy.ee.on('caronte:outgoing:web:error', function (err) { + expect(err).to.be.an(Error); + expect(err.code).to.be('ECONNREFUSED'); + proxyServer.close(); + done(); + }) + + var proxyServer = proxy.listen('8081'); + + http.request({ + hostname: '127.0.0.1', + port: '8081', + method: 'GET', + }, function() {}).end(); + }); + }); + + describe('#createProxyServer using the web-incoming passes', function () { + it('should emit events correclty', function(done) { + var proxy = caronte.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('caronte:**', 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('caronte:outgoing:web:begin'); + expect(events).to.contain('caronte:outgoing:web:end'); + source.close(); + proxyServer.close(); + done(); + }); + }).end(); + }); + }); }); From 7e25bded27effc1b3d47121ce21465a4e2ec7c0b Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 19:04:49 -0500 Subject: [PATCH 097/556] [tests] removed unused tests --- test/lib-caronte-streams-proxy-test.js | 109 -------------------- test/lib-caronte-streams-websockets-test.js | 109 -------------------- 2 files changed, 218 deletions(-) delete mode 100644 test/lib-caronte-streams-proxy-test.js delete mode 100644 test/lib-caronte-streams-websockets-test.js diff --git a/test/lib-caronte-streams-proxy-test.js b/test/lib-caronte-streams-proxy-test.js deleted file mode 100644 index 671f80cc0..000000000 --- a/test/lib-caronte-streams-proxy-test.js +++ /dev/null @@ -1,109 +0,0 @@ -var caronte = require('../'), - ProxyStream = require('../lib/caronte/streams/proxy'); - expect = require('expect.js'), - Duplex = require('stream').Duplex, - http = require('http'); - - -describe('lib/caronte/streams/proxy.js', function () { - describe('proxy stream constructor', function () { - it('should be an instance of Duplex stream and get the correct options and methods', function () { - var stubOptions = { - key: 'value' - }; - var proxyStream = new ProxyStream(stubOptions); - - expect(proxyStream).to.be.a(Duplex); - expect(proxyStream.options).to.eql({ key: 'value' }); - expect(proxyStream.onPipe).to.be.a('function'); - expect(proxyStream.onFinish).to.be.a('function'); - expect(proxyStream._events).to.have.property('pipe'); - expect(proxyStream._events).to.have.property('finish'); - }); - }); - - describe('caronte createProxyServer() method', function () { - it('should make the request on pipe and finish it', function(done) { - var proxy = caronte.createProxyServer({ - target: 'http://127.0.0.1:8080' - }).listen('8081'); - - var source = http.createServer(function(req, res) { - expect(req.headers['x-forwarded-for']).to.eql('127.0.0.1'); - source.close(); - proxy.close(); - done(); - }); - - source.listen('8080'); - - http.request({ - hostname: '127.0.0.1', - port: '8081', - method: 'POST', - headers: { - 'x-forwarded-for': '127.0.0.1' - } - }, function() {}).end(); - }); - }); - - describe('caronte createProxyServer() method with response', function () { - it('should make the request, handle response and finish it', function(done) { - var proxy = caronte.createProxyServer({ - target: 'http://127.0.0.1:8080' - }).listen('8081'); - - var source = http.createServer(function(req, res) { - expect(req.method).to.eql('GET'); - res.writeHead(200, {'Content-Type': 'text/plain'}) - res.end('Hello from ' + source.address().port); - }); - - source.listen('8080'); - - 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 () { - source.close(); - proxy.close(); - done(); - }); - }).end(); - }); - }); - - describe('caronte createProxyServer() method with error response', function () { - it('should make the request and response with error', function(done) { - var proxy = caronte.createProxyServer({ - target: 'http://127.0.0.1:8080' - }).listen('8081'); - - http.request({ - hostname: '127.0.0.1', - port: '8081', - method: 'GET', - }, function(res) { - expect(res.statusCode).to.eql(500); - - res.on('data', function (data) { - expect(data.toString()).to.eql('Internal Server Error'); - }); - - res.on('end', function () { - proxy.close(); - done(); - }); - }).end(); - }); - }); -}); diff --git a/test/lib-caronte-streams-websockets-test.js b/test/lib-caronte-streams-websockets-test.js deleted file mode 100644 index 74248e7b3..000000000 --- a/test/lib-caronte-streams-websockets-test.js +++ /dev/null @@ -1,109 +0,0 @@ -var caronte = require('../'), - WebSocket = require('../lib/caronte/streams/websocket'); - expect = require('expect.js'), - Duplex = require('stream').Duplex, - http = require('http'); - - -describe('lib/caronte/streams/websocket.js', function () { - describe('WebSocket stream constructor', function () { - it('should be an instance of Duplex stream and get the correct options and methods', function () { - var stubOptions = { - key: 'value' - }; - var WebSocketStream = new WebSocket(stubOptions); - - expect(WebSocketStream).to.be.a(Duplex); - expect(WebSocketStream.options).to.eql({ key: 'value' }); - expect(WebSocketStream.onPipe).to.be.a('function'); - expect(WebSocketStream.onFinish).to.be.a('function'); - expect(WebSocketStream._events).to.have.property('pipe'); - expect(WebSocketStream._events).to.have.property('finish'); - }); - }); - - describe('caronte createWebSocketServer() method', function () { - // it('should make the request on pipe and finish it', function(done) { - // var proxy = caronte.createProxyServer({ - // target: 'http://127.0.0.1:8080' - // }).listen('8081'); - - // var source = http.createServer(function(req, res) { - // expect(req.headers['x-forwarded-for']).to.eql('127.0.0.1'); - // source.close(); - // proxy.close(); - // done(); - // }); - - // source.listen('8080'); - - // http.request({ - // hostname: '127.0.0.1', - // port: '8081', - // method: 'POST', - // headers: { - // 'x-forwarded-for': '127.0.0.1' - // } - // }, function() {}).end(); - // }); - }); - - describe('caronte createProxyServer() method with response', function () { - // it('should make the request, handle response and finish it', function(done) { - // var proxy = caronte.createProxyServer({ - // target: 'http://127.0.0.1:8080' - // }).listen('8081'); - - // var source = http.createServer(function(req, res) { - // expect(req.method).to.eql('GET'); - // res.writeHead(200, {'Content-Type': 'text/plain'}) - // res.end('Hello from ' + source.address().port); - // }); - - // source.listen('8080'); - - // 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 () { - // source.close(); - // proxy.close(); - // done(); - // }); - // }).end(); - // }); - }); - - describe('caronte createProxyServer() method with error response', function () { - // it('should make the request and response with error', function(done) { - // var proxy = caronte.createProxyServer({ - // target: 'http://127.0.0.1:8080' - // }).listen('8081'); - - // http.request({ - // hostname: '127.0.0.1', - // port: '8081', - // method: 'GET', - // }, function(res) { - // expect(res.statusCode).to.eql(500); - - // res.on('data', function (data) { - // expect(data.toString()).to.eql('Internal Server Error'); - // }); - - // res.on('end', function () { - // proxy.close(); - // done(); - // }); - // }).end(); - // }); - }); -}); From 40902506af3361b642b8798350b48404fe0a4e78 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 19:37:28 -0500 Subject: [PATCH 098/556] [tests] fix code coverage, changed pattern on blanket options --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f11557c6d..bc8c4c0ad 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "ws" : "*" }, "scripts" : { - "blanket" : { "pattern": "caronte/lib" }, + "blanket" : { "pattern": "lib/caronte" }, "test" : "./node_modules/.bin/mocha -R landing test/*-test.js", "test-cov" : "./node_modules/.bin/mocha --require blanket -R html-cov > cov/coverage.html" }, From 02007ed0fb38f798436ae5669bb18d4f27496667 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 20:59:10 -0500 Subject: [PATCH 099/556] [tests] added tests for websockets --- test/lib-caronte-test.js | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/test/lib-caronte-test.js b/test/lib-caronte-test.js index dbb278f71..06ab11e1f 100644 --- a/test/lib-caronte-test.js +++ b/test/lib-caronte-test.js @@ -1,6 +1,7 @@ var caronte = require('../lib/caronte'), expect = require('expect.js'), - http = require('http'); + http = require('http'), + ws = require('ws'); describe('lib/caronte.js', function() { describe('#createProxyServer', function() { @@ -176,4 +177,35 @@ describe('lib/caronte.js', function() { }).end(); }); }); + + describe('#createProxyServer using the ws-incoming passes', function () { + it('should proxy the websockets stream', function (done) { + var proxy = caronte.createProxyServer({ + target: 'ws://127.0.0.1:8080', + ws: true + }), + proxyServer = proxy.listen('8081'), + destiny = new ws.Server({ port: 8080 }, function () { + var client = new ws('ws://127.0.0.1:8081'); + + client.on('open', function () { + client.send('hello there'); + }); + + client.on('message', function (msg) { + expect(msg).to.be('Hello over websockets'); + proxyServer.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'); + }); + }); + }); + }); }); From 06025002303f351f71d9e5f78a93895257f0d283 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 21:00:34 -0500 Subject: [PATCH 100/556] [tests] added .travis.yml file --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..87fb96432 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: node_js +node_js: + - 0.8 + - "0.10" + - "0.11" + +notifications: + email: + - travis@nodejitsu.com + irc: "irc.freenode.org#nodejitsu" \ No newline at end of file From 10a0db4f0dd4594839f9098b9d67130085a067bc Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 21:37:49 -0500 Subject: [PATCH 101/556] [tests] added test for socket.io proxying --- package.json | 4 +++- test/lib-caronte-test.js | 43 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bc8c4c0ad..c0b741774 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,9 @@ "coveralls" : "*", "mocha-lcov-reporter": "*", "blanket" : "*", - "ws" : "*" + "ws" : "*", + "socket.io" : "*", + "socket.io-client" : "*" }, "scripts" : { "blanket" : { "pattern": "lib/caronte" }, diff --git a/test/lib-caronte-test.js b/test/lib-caronte-test.js index 06ab11e1f..0558ef934 100644 --- a/test/lib-caronte-test.js +++ b/test/lib-caronte-test.js @@ -1,7 +1,10 @@ -var caronte = require('../lib/caronte'), - expect = require('expect.js'), - http = require('http'), - ws = require('ws'); +var caronte = require('../lib/caronte'), + expect = require('expect.js'), + http = require('http'), + ws = require('ws') + io = require('socket.io'), + ioClient = require('socket.io-client'); + describe('lib/caronte.js', function() { describe('#createProxyServer', function() { @@ -194,6 +197,7 @@ describe('lib/caronte.js', function() { client.on('message', function (msg) { expect(msg).to.be('Hello over websockets'); + client.close(); proxyServer.close(); destiny.close(); done(); @@ -208,4 +212,35 @@ describe('lib/caronte.js', function() { }); }); }); + + describe('#createProxyServer using the ws-incoming passes', function () { + it('should proxy a socket.io stream', function (done) { + var proxy = caronte.createProxyServer({ + target: 'ws://127.0.0.1:8080', + ws: true + }), + proxyServer = proxy.listen('8081'), + destiny = io.listen(8080, function () { + var client = ioClient.connect('ws://127.0.0.1:8081'); + + client.on('connect', function () { + client.emit('incoming', 'hello there'); + }); + + client.on('outgoing', function (data) { + expect(data).to.be('Hello over websockets'); + proxyServer.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'); + }); + }) + }); + }) }); From 8eff1a1f26bb739dfc5a1ad90b140ff2a18921d5 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 16 Sep 2013 21:40:42 -0500 Subject: [PATCH 102/556] [test][misc] remove node@0.8 to test on travis --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 87fb96432..835fed5ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,9 @@ language: node_js node_js: - - 0.8 - "0.10" - "0.11" notifications: email: - travis@nodejitsu.com - irc: "irc.freenode.org#nodejitsu" \ No newline at end of file + irc: "irc.freenode.org#nodejitsu" From 031452e4007f1084a760e78be6908319c12c2c1c Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 10:31:52 +0200 Subject: [PATCH 103/556] [fix] closes #473 --- lib/caronte/passes/ws-incoming.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/caronte/passes/ws-incoming.js b/lib/caronte/passes/ws-incoming.js index ef88de35a..e5bdcf60e 100644 --- a/lib/caronte/passes/ws-incoming.js +++ b/lib/caronte/passes/ws-incoming.js @@ -75,6 +75,9 @@ function XHeaders(req, socket, options) { function stream(req, socket, options, head) { 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) ); From 611a1b196154b083450a940d27dd3a94be2a3bf3 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 10:38:25 +0200 Subject: [PATCH 104/556] [fix] add 0.10 link, fixes #459 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index a7a8328c0..9c0ca04df 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ * Written entirely in Javascript * Easy to use API + +node-http-proxy is `<= 0.8.x` compatible, if you're looking for a `>= 0.10` compatible version please check [caronte](https://github.com/nodejitsu/node-http-proxy/tree/caronte) + ### 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. From 2c10f256b658bc0e906c20f29d94ab7eaf653055 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 10:59:45 +0200 Subject: [PATCH 105/556] [fix] write connection header --- lib/caronte/passes/web-incoming.js | 2 +- lib/caronte/passes/web-outgoing.js | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/caronte/passes/web-incoming.js b/lib/caronte/passes/web-incoming.js index 66beb011c..ce494feb5 100644 --- a/lib/caronte/passes/web-incoming.js +++ b/lib/caronte/passes/web-incoming.js @@ -121,7 +121,7 @@ function stream(req, res, options) { var evnt = ev + pass.name.toLowerCase() + ':'; options.ee.emit(evnt + 'begin', req, res); - var val = pass(res, proxyRes); + var val = pass(req, res, proxyRes); options.ee.emit(evnt + 'end'); return val; diff --git a/lib/caronte/passes/web-outgoing.js b/lib/caronte/passes/web-outgoing.js index 941bc6001..7d4ff9405 100644 --- a/lib/caronte/passes/web-outgoing.js +++ b/lib/caronte/passes/web-outgoing.js @@ -9,14 +9,29 @@ var passes = exports; */ [ // <-- - - function writeHeaders(res, proxyRes) { + + function setConnection(req, res, proxyRes) { + if (req.httpVersion === '1.0') { + if (req.headers.connection) { + proxyRes.headers.connection = req.headers.connection + } else { + proxyRes.headers.connection = 'close' + } + } else if (!proxyRes.headers.connection) { + if (req.headers.connection) { proxyRes.headers.connection = req.headers.connection } + else { + proxyRes.headers.connection = 'keep-alive' + } + } + }, + + function writeHeaders(req, res, proxyRes) { Object.keys(proxyRes.headers).forEach(function(key) { res.setHeader(key, proxyRes.headers[key]); }); }, - function writeStatusCode(res, proxyRes) { + function writeStatusCode(req, res, proxyRes) { res.writeHead(proxyRes.statusCode); } From 16a4d9da1136b79f40ad80482d3fd17dc74274b1 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 11:20:18 +0200 Subject: [PATCH 106/556] [test] added tests for web-outgoing.js --- test/lib-caronte-passes-web-outgoing-test.js | 90 ++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 test/lib-caronte-passes-web-outgoing-test.js diff --git a/test/lib-caronte-passes-web-outgoing-test.js b/test/lib-caronte-passes-web-outgoing-test.js new file mode 100644 index 000000000..b51e17b74 --- /dev/null +++ b/test/lib-caronte-passes-web-outgoing-test.js @@ -0,0 +1,90 @@ +var caronte = require('../lib/caronte/passes/web-outgoing'), + expect = require('expect.js'); + +describe('lib/caronte/passes/web-outgoing.js', function () { + describe('#setConnection', function () { + it('set the right connection with 1.0 - `close`', function() { + var proxyRes = { headers: {} }; + caronte.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: {} }; + caronte.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: {} }; + caronte.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: {} }; + caronte.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); + } + } + + caronte.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: {} + }; + + caronte.writeHeaders({}, res, proxyRes); + + expect(res.headers.hey).to.eql('hello'); + expect(res.headers.how).to.eql('are you?'); + }); + +}); + From 6b618787598a2a37850898dbdb3b4fe8f3c3414d Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 11:24:35 +0200 Subject: [PATCH 107/556] [docs] add travis build status --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index c710504cc..3a4bc0244 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,12 @@ Caronte is an HTTP programmable proxying library that supports websockets. It is suitable for implementing components such as proxies and load balancers. +### Build Status + +

+ +

+ ### Core Concept A new proxy is created by calling `createProxyServer` and passing From afc4d0931fa1bc73ef797e2b59570e2f8145d447 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 12:14:52 +0200 Subject: [PATCH 108/556] [fix] pooled connections, closes #478 --- lib/caronte.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/caronte.js b/lib/caronte.js index 444e8fd25..78d7bd4f3 100644 --- a/lib/caronte.js +++ b/lib/caronte.js @@ -32,6 +32,7 @@ proxy.createProxyServer = function createProxyServer(options) { " ws : ", " xfwd : ", " maxSock: ", + " agent : ", " } ", " ", "NOTE: `options.ws` and `options.ssl` are optional. ", @@ -45,7 +46,7 @@ proxy.createProxyServer = function createProxyServer(options) { options[key] = url.parse(options[key]); options[key].maxSockets = options.maxSock; - options[key].agent = new (options.ssl ? https.Agent : http.Agent)(options[key].maxSockets || 100); + options[key].agent = options.agent || false // new (options.ssl ? https.Agent : http.Agent)(options[key].maxSockets || 100); }); options.ee = new events.EventEmitter2({ wildcard: true, delimiter: ':' }); From 8663ac1c43505f0081d906c3cd8e702d4b5ddeb0 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 16:28:54 +0200 Subject: [PATCH 109/556] [fix] do not send chunked responses to http1.0 clients --- lib/caronte/passes/web-outgoing.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/caronte/passes/web-outgoing.js b/lib/caronte/passes/web-outgoing.js index 7d4ff9405..48ff12dd6 100644 --- a/lib/caronte/passes/web-outgoing.js +++ b/lib/caronte/passes/web-outgoing.js @@ -10,6 +10,12 @@ var passes = exports; [ // <-- + function removeChunked(req, res, proxyRes) { + if(req.httpVersion === '1.0') { + delete proxyRes.headers['transfer-encoding']; + } + }, + function setConnection(req, res, proxyRes) { if (req.httpVersion === '1.0') { if (req.headers.connection) { From ca092635e7ac4d967b554e3b94a16a931946d464 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 16:32:55 +0200 Subject: [PATCH 110/556] [test] remove chunked on http1.0 --- test/lib-caronte-passes-web-outgoing-test.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/lib-caronte-passes-web-outgoing-test.js b/test/lib-caronte-passes-web-outgoing-test.js index b51e17b74..64fc7ead9 100644 --- a/test/lib-caronte-passes-web-outgoing-test.js +++ b/test/lib-caronte-passes-web-outgoing-test.js @@ -86,5 +86,19 @@ describe('lib/caronte/passes/web-outgoing.js', function () { expect(res.headers.how).to.eql('are you?'); }); + + describe('#removeChunked', function() { + var proxyRes = { + headers: { + 'transfer-encoding': 'hello' + } + }; + + + caronte.removeChunked({ httpVersion: '1.0' }, {}, proxyRes); + + expect(proxyRes.headers['transfer-encoding']).to.eql(undefined); + }); + }); From f36cb4d5a110fc86272e878278f103f313c86f56 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 19:30:59 +0200 Subject: [PATCH 111/556] [fix] coveralls.. will it work? --- .travis.yml | 3 +++ package.json | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 835fed5ff..d7eeacc3f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,3 +7,6 @@ notifications: email: - travis@nodejitsu.com irc: "irc.freenode.org#nodejitsu" + +script: + npm run-script coveralls diff --git a/package.json b/package.json index c0b741774..22406ba23 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,12 @@ "blanket" : "*", "ws" : "*", "socket.io" : "*", - "socket.io-client" : "*" + "socket.io-client" : "*", + "coveralls" : "*", + "mocha-lcov-reporter": "*" }, "scripts" : { + "coveralls" : "mocha --require blanket --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js", "blanket" : { "pattern": "lib/caronte" }, "test" : "./node_modules/.bin/mocha -R landing test/*-test.js", "test-cov" : "./node_modules/.bin/mocha --require blanket -R html-cov > cov/coverage.html" From 1ceea3e5f9b6232d60d673946bbccb7d8ccb4beb Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 20:11:03 +0200 Subject: [PATCH 112/556] [docs] test badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3a4bc0244..2df118fb5 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ proxies and load balancers.

+

### Core Concept From 72a89eab8bafef3742d78e8de8631094f961f427 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 20:14:16 +0200 Subject: [PATCH 113/556] [fix] link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2df118fb5..bb5eacaf4 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ proxies and load balancers.

- +

### Core Concept From 69f126b34cbd190be8541a854d21f13bfb5a61bf Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 17 Sep 2013 20:15:34 +0200 Subject: [PATCH 114/556] [fix] space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bb5eacaf4..f58bbbab8 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ proxies and load balancers. ### Build Status

- +   

From 13741a823f1c1c884d4a37e597e4b188598b0e25 Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Sep 2013 11:03:23 -0700 Subject: [PATCH 115/556] ENH: updated https and agent option Removed logic from createProxyServer and put it into setupOutgoing. Conflicts: lib/caronte.js --- lib/caronte.js | 9 +-------- lib/caronte/common.js | 14 +++++++++++++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/caronte.js b/lib/caronte.js index 78d7bd4f3..ed0280cfa 100644 --- a/lib/caronte.js +++ b/lib/caronte.js @@ -28,6 +28,7 @@ proxy.createProxyServer = function createProxyServer(options) { " { ", " target : ", " forward: ", + " agent : ", " ssl : ", " ws : ", " xfwd : ", @@ -41,14 +42,6 @@ proxy.createProxyServer = function createProxyServer(options) { ].join("\n")); } - ['target', 'forward'].forEach(function(key) { - if(!options[key]) return; - options[key] = url.parse(options[key]); - - options[key].maxSockets = options.maxSock; - options[key].agent = options.agent || false // new (options.ssl ? https.Agent : http.Agent)(options[key].maxSockets || 100); - }); - options.ee = new events.EventEmitter2({ wildcard: true, delimiter: ':' }); return { diff --git a/lib/caronte/common.js b/lib/caronte/common.js index 6b75c6f47..a2728580b 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -1,4 +1,7 @@ -var common = exports; +var common = exports + , http = require('http') + , https = require('https') + ; /** * Copies the right headers from `options` and `req` to @@ -32,6 +35,15 @@ common.setupOutgoing = function(outgoing, options, req, forward) { function(e) { outgoing[e] = req[e]; } ); + if (options.agent){ + outgoing.agent = options.agent; + } + + if (!outgoing.agent){ + var Agent = (~['https:', 'wss:'].indexOf(options[forward || 'target'].protocol) ? https.Agent : http.Agent); + outgoing.agent = new Agent(options.maxSock || 100); + } + outgoing.path = req.url; return outgoing; From 427d8d85369b0cd1d38afa0dd0f28ac98fa16001 Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Sep 2013 11:44:09 -0700 Subject: [PATCH 116/556] ENH: added new https example, needs to be simplified before merge updated existing example with log output --- examples/https.js | 54 +++++++++++++++++++++++++++++++++++++++++ examples/stand-alone.js | 2 ++ 2 files changed, 56 insertions(+) create mode 100644 examples/https.js diff --git a/examples/https.js b/examples/https.js new file mode 100644 index 000000000..cab220653 --- /dev/null +++ b/examples/https.js @@ -0,0 +1,54 @@ +var http = require('http') + , https = require('https') + , caronte = require('caronte') + ; +// +// Create your proxy server +// +var options = {target:'https://google.com', + agent: new https.Agent({rejectUnauthorized:false}), + }; + +var proxyServer = caronte.createProxyServer(options); + +proxyServer.ee.on('*:error', function(err, req, res){ + res.end('There was an error proxying your request'); +}); + +console.log("Proxy server listening on port 8000"); +proxyServer.listen(8000); + + +// +// Create your proxy server +// +var options2 = {target:'https://google.com', + headers: {'host':'google.com'}, + }; + +var proxyServer2 = caronte.createProxyServer(options2); + +proxyServer2.ee.on('*:error', function(err, req, res){ + res.end('There was an error proxying your request'); +}); + +console.log("Proxy server 2 listening on port 8001"); +proxyServer2.listen(8001); + +// +// Create your proxy server +// +var options3 = {target:'https://google.com'}; + +var proxyServer3 = caronte.createProxyServer(options3); + +proxyServer3.ee.on('*:error', function(err, req, res){ + res.end('There was an error proxying your request'); +}); + +console.log("Proxy server 3 listening on port 8002"); +proxyServer3.listen(8002); + + + + diff --git a/examples/stand-alone.js b/examples/stand-alone.js index d3848abf4..081134e6b 100644 --- a/examples/stand-alone.js +++ b/examples/stand-alone.js @@ -3,11 +3,13 @@ var http = require('http'), // // Create your proxy server // +console.log("Proxy server listening on port 8000"); caronte.createProxyServer({target:'http://localhost:9000'}).listen(8000); // // Create your target server // +console.log("Web server listening on port 9000"); http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2)); From 7d840d35151be1aac612798754af47368594781d Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Sep 2013 11:45:41 -0700 Subject: [PATCH 117/556] ENH: added 'headers' to available options, to add or overwrite existing headers --- lib/caronte/common.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/caronte/common.js b/lib/caronte/common.js index a2728580b..47ada1b6a 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -1,6 +1,7 @@ -var common = exports +var common = exports , http = require('http') , https = require('https') + , extend = require('util')._extend ; /** @@ -35,6 +36,10 @@ common.setupOutgoing = function(outgoing, options, req, forward) { function(e) { outgoing[e] = req[e]; } ); + if (options.headers){ + extend(outgoing.headers, options.headers); + } + if (options.agent){ outgoing.agent = options.agent; } From 1c7ace26c5a36fb63497f1ab67793c5b75495063 Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Sep 2013 11:50:04 -0700 Subject: [PATCH 118/556] ENH: updated example --- examples/https.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/https.js b/examples/https.js index cab220653..8e3410dc2 100644 --- a/examples/https.js +++ b/examples/https.js @@ -38,7 +38,8 @@ proxyServer2.listen(8001); // // Create your proxy server // -var options3 = {target:'https://google.com'}; +var options3 = {target:'https://google.com', + xfwd:true}; var proxyServer3 = caronte.createProxyServer(options3); From f566a42e511f4a6a8f3620f64e05df209e61b64f Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Sep 2013 14:51:56 -0700 Subject: [PATCH 119/556] ENH: updated examples --- examples/https-secure.js | 15 +++++++++++ examples/https.js | 55 ++++------------------------------------ 2 files changed, 20 insertions(+), 50 deletions(-) create mode 100644 examples/https-secure.js diff --git a/examples/https-secure.js b/examples/https-secure.js new file mode 100644 index 000000000..b6d7bb759 --- /dev/null +++ b/examples/https-secure.js @@ -0,0 +1,15 @@ +var caronte = require('caronte'), + https = require('https'); +/* + * Create your proxy server pointing to a secure domain + * Enable ssl validation + */ +var options = {target : 'https://google.com', + agent : https.globalAgent, + headers: {host: 'google.com'} + }; + +var proxyServer = caronte.createProxyServer(options); +console.log("Proxy server listening on port 8000"); +proxyServer.listen(8000); + diff --git a/examples/https.js b/examples/https.js index 8e3410dc2..b64e3cf2f 100644 --- a/examples/https.js +++ b/examples/https.js @@ -1,55 +1,10 @@ -var http = require('http') - , https = require('https') - , caronte = require('caronte') - ; -// -// Create your proxy server -// -var options = {target:'https://google.com', - agent: new https.Agent({rejectUnauthorized:false}), - }; +var caronte = require('caronte'); +/* + * Create your proxy server pointing to a secure domain + */ +var options = {target:'https://google.com'}; var proxyServer = caronte.createProxyServer(options); - -proxyServer.ee.on('*:error', function(err, req, res){ - res.end('There was an error proxying your request'); -}); - console.log("Proxy server listening on port 8000"); proxyServer.listen(8000); - -// -// Create your proxy server -// -var options2 = {target:'https://google.com', - headers: {'host':'google.com'}, - }; - -var proxyServer2 = caronte.createProxyServer(options2); - -proxyServer2.ee.on('*:error', function(err, req, res){ - res.end('There was an error proxying your request'); -}); - -console.log("Proxy server 2 listening on port 8001"); -proxyServer2.listen(8001); - -// -// Create your proxy server -// -var options3 = {target:'https://google.com', - xfwd:true}; - -var proxyServer3 = caronte.createProxyServer(options3); - -proxyServer3.ee.on('*:error', function(err, req, res){ - res.end('There was an error proxying your request'); -}); - -console.log("Proxy server 3 listening on port 8002"); -proxyServer3.listen(8002); - - - - From 12cda561afe534427a5f84da9d7e0beb64a8ecbc Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Sep 2013 14:52:53 -0700 Subject: [PATCH 120/556] ENH: updated agent options in `common.setupOutgoing` --- lib/caronte.js | 4 +--- lib/caronte/common.js | 21 +++++---------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/lib/caronte.js b/lib/caronte.js index ed0280cfa..337fac94d 100644 --- a/lib/caronte.js +++ b/lib/caronte.js @@ -28,12 +28,10 @@ proxy.createProxyServer = function createProxyServer(options) { " { ", " target : ", " forward: ", - " agent : ", + " agent : ", " ssl : ", " ws : ", " xfwd : ", - " maxSock: ", - " agent : ", " } ", " ", "NOTE: `options.ws` and `options.ssl` are optional. ", diff --git a/lib/caronte/common.js b/lib/caronte/common.js index 47ada1b6a..e84f36ca5 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -1,8 +1,5 @@ -var common = exports - , http = require('http') - , https = require('https') - , extend = require('util')._extend - ; +var common = exports, + extend = require('util')._extend; /** * Copies the right headers from `options` and `req` to @@ -28,7 +25,7 @@ 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', 'agent'].forEach( + ['host', 'hostname', 'socketPath'].forEach( function(e) { outgoing[e] = options[forward || 'target'][e]; } ); @@ -39,16 +36,8 @@ common.setupOutgoing = function(outgoing, options, req, forward) { if (options.headers){ extend(outgoing.headers, options.headers); } - - if (options.agent){ - outgoing.agent = options.agent; - } - - if (!outgoing.agent){ - var Agent = (~['https:', 'wss:'].indexOf(options[forward || 'target'].protocol) ? https.Agent : http.Agent); - outgoing.agent = new Agent(options.maxSock || 100); - } - + + outgoing.agent = options.agent || false; outgoing.path = req.url; return outgoing; From 1b5fb1d8fc21421b8383919d93e4149b586b211b Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Sep 2013 15:00:28 -0700 Subject: [PATCH 121/556] DOC: updated readme with options --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f58bbbab8..c4296136a 100644 --- a/README.md +++ b/README.md @@ -105,10 +105,14 @@ server.listen(5050); * **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][0] and [http agent][1] agent objects) + +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 - * **maxSock**: maximum number of sockets + ### Test @@ -144,3 +148,5 @@ Logo created by [Diego Pasquali](http://dribbble.com/diegopq) >OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN >THE SOFTWARE. +[0]: http://nodejs.org/api/https.html#https_class_https_agent +[1]: http://nodejs.org/api/http.html#http_class_http_agent From a350fadea6bace293131581487f8c66948009449 Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Sep 2013 15:06:22 -0700 Subject: [PATCH 122/556] FIX: tests. still need to add more tests tho --- test/lib-caronte-common-test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/lib-caronte-common-test.js b/test/lib-caronte-common-test.js index 1523cffd8..88536e2c1 100644 --- a/test/lib-caronte-common-test.js +++ b/test/lib-caronte-common-test.js @@ -7,12 +7,12 @@ describe('lib/caronte/common.js', function () { var outgoing = {}; common.setupOutgoing(outgoing, { + agent : '?', target: { host : 'hey', hostname : 'how', socketPath: 'are', port : 'you', - agent : '?' } }, { @@ -35,12 +35,12 @@ describe('lib/caronte/common.js', function () { it('set the port according to the protocol', function () { var outgoing = {}; common.setupOutgoing(outgoing, - { + { + agent : '?', target: { host : 'how', hostname : 'are', socketPath: 'you', - agent : '?', protocol: 'https:' } }, From 39b0c46a6967fda5329760ad93a8ec01bc4a6f14 Mon Sep 17 00:00:00 2001 From: srossross Date: Tue, 17 Sep 2013 15:29:48 -0700 Subject: [PATCH 123/556] TEST: added agent and header tests --- test/lib-caronte-common-test.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/lib-caronte-common-test.js b/test/lib-caronte-common-test.js index 88536e2c1..ac79867c5 100644 --- a/test/lib-caronte-common-test.js +++ b/test/lib-caronte-common-test.js @@ -13,12 +13,13 @@ describe('lib/caronte/common.js', function () { hostname : 'how', socketPath: 'are', port : 'you', - } + }, + headers: {'fizz': 'bang', 'overwritten':true}, }, { method : 'i', url : 'am', - headers : 'proxy' + headers : {'pro':'xy','overwritten':false} }); expect(outgoing.host).to.eql('hey'); @@ -29,7 +30,16 @@ describe('lib/caronte/common.js', function () { expect(outgoing.method).to.eql('i'); expect(outgoing.path).to.eql('am'); - expect(outgoing.headers).to.eql('proxy') + + 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: {},}, {}); + expect(outgoing.agent).to.eql(false); }); it('set the port according to the protocol', function () { From 7ad5c0f993294c9e2e7650e15fbc62d11a2cb062 Mon Sep 17 00:00:00 2001 From: srossross Date: Wed, 18 Sep 2013 09:07:56 -0700 Subject: [PATCH 124/556] DOC: updated readme @yawnt I think it is good to go. If you have any other tests in mind let me know. --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c4296136a..b53985aa6 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ server.listen(5050); * **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][0] and [http agent][1] agent objects) + * **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) If you are using the `proxyServer.listen` method, the following options are also applicable: @@ -148,5 +148,4 @@ Logo created by [Diego Pasquali](http://dribbble.com/diegopq) >OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN >THE SOFTWARE. -[0]: http://nodejs.org/api/https.html#https_class_https_agent -[1]: http://nodejs.org/api/http.html#http_class_http_agent + From 5dcdf2b36c24a9584f044b7529265b9ac861d8c7 Mon Sep 17 00:00:00 2001 From: cronopio Date: Fri, 20 Sep 2013 19:28:53 -0500 Subject: [PATCH 125/556] [doc] added some documentation to functions and comments to understand better the code --- lib/caronte/common.js | 17 +++++++++++++ lib/caronte/index.js | 9 +++++++ lib/caronte/passes/web-incoming.js | 11 ++++++++- lib/caronte/passes/web-outgoing.js | 38 ++++++++++++++++++++++++++++++ lib/caronte/passes/ws-incoming.js | 27 ++++++++++++++++++++- 5 files changed, 100 insertions(+), 2 deletions(-) diff --git a/lib/caronte/common.js b/lib/caronte/common.js index 6b75c6f47..2b9d43675 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -37,6 +37,23 @@ common.setupOutgoing = function(outgoing, options, req, forward) { 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); diff --git a/lib/caronte/index.js b/lib/caronte/index.js index ef0187fa9..c3bb69fb7 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -65,6 +65,15 @@ function createRightProxy(type) { passes.some(function(pass) { var evnt = ev + pass.name.toLowerCase() + ':'; + + /** + * 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) + */ options.ee.emit(evnt + 'begin', req, res); var val = pass(req, res, options, head); diff --git a/lib/caronte/passes/web-incoming.js b/lib/caronte/passes/web-incoming.js index ce494feb5..1c1a6b9eb 100644 --- a/lib/caronte/passes/web-incoming.js +++ b/lib/caronte/passes/web-incoming.js @@ -91,6 +91,7 @@ function XHeaders(req, res, options) { function stream(req, res, options) { 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') ); @@ -98,15 +99,19 @@ function stream(req, res, options) { 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){ var ev = 'caronte:outgoing:web:'; + // If no error listeners, so throw the error. if (options.ee.listeners(ev + 'error').length == 0){ throw err; } + // Also emit the error events options.ee.emit(ev + 'error', err, req, res); }); @@ -117,10 +122,14 @@ function stream(req, res, options) { options.ee.emit(ev + 'begin', req, res); + // When the previous request respond, we apply the + // outgoing passes to the response web_o.some(function(pass) { var evnt = ev + pass.name.toLowerCase() + ':'; - options.ee.emit(evnt + 'begin', req, res); + options.ee.emit(evnt + 'begin', req, res); + // Call the pass with the proxy response + // pass(ClientRequest, IncomingMessage, proxyResponse) var val = pass(req, res, proxyRes); options.ee.emit(evnt + 'end'); diff --git a/lib/caronte/passes/web-outgoing.js b/lib/caronte/passes/web-outgoing.js index 48ff12dd6..abdaec925 100644 --- a/lib/caronte/passes/web-outgoing.js +++ b/lib/caronte/passes/web-outgoing.js @@ -10,12 +10,31 @@ var passes = exports; [ // <-- + /** + * 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') { if (req.headers.connection) { @@ -31,12 +50,31 @@ var passes = exports; } }, + /** + * 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); } diff --git a/lib/caronte/passes/ws-incoming.js b/lib/caronte/passes/ws-incoming.js index e5bdcf60e..ca2b668c8 100644 --- a/lib/caronte/passes/ws-incoming.js +++ b/lib/caronte/passes/ws-incoming.js @@ -22,6 +22,11 @@ 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) { @@ -35,8 +40,14 @@ function checkMethodAndHeader (req, socket) { }, /** - * Setup socket + * Set the proper configuration for sockets, + * set no delay and set keep alive, also set + * the timeout to 0. * + * @param {ClientRequest} Req Request object + * @param {Socket} Websocket + * + * @api private */ function setupSocket(req, socket) { @@ -49,6 +60,11 @@ function setupSocket(req, socket) { /** * 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) { @@ -69,8 +85,14 @@ function XHeaders(req, socket, options) { }, /** + * 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) { common.setupSocket(socket); @@ -81,11 +103,14 @@ function stream(req, socket, options, head) { var proxyReq = (~['https:', 'wss:'].indexOf(options.target.protocol) ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req) ); + // Error Handler proxyReq.on('error', function(err){ var ev = 'caronte:outgoing:ws:'; + // If no error listeners, so throw the error. if (options.ee.listeners(ev + 'error').length == 0){ throw err; } + // Also emit the error events options.ee.emit(ev + 'error', err, req, socket, head); }); From 4a517fbe6e621d77e7be35c07d19e60f61faaae4 Mon Sep 17 00:00:00 2001 From: cronopio Date: Fri, 20 Sep 2013 20:47:02 -0500 Subject: [PATCH 126/556] [readme] add links to badges on readme, fix #483 --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f58bbbab8..5ef7f3887 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,10 @@ proxies and load balancers. ### Build Status

-    - + +    + +

### Core Concept From 32a40889cedfd6b0d92224aa921700a7b7271c68 Mon Sep 17 00:00:00 2001 From: srossross Date: Sat, 21 Sep 2013 13:15:34 -0700 Subject: [PATCH 127/556] DOC: Added error handling example --- examples/error-handling.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 examples/error-handling.js diff --git a/examples/error-handling.js b/examples/error-handling.js new file mode 100644 index 000000000..06b126eb3 --- /dev/null +++ b/examples/error-handling.js @@ -0,0 +1,26 @@ +var caronte = require('../index'); +/* + * Create your proxy server + */ +var proxyServer = caronte.createProxyServer({target:'http://localhost:30404', ws:true}); + +// Register an error handler for web requests +proxyServer.ee.on("caronte:outgoing:web:error", function(err, req, res){ + res.writeHead(502); + res.end("There was an error proxying your request"); +}); + +// Register an error handler for web-socket requests +proxyServer.ee.on("caronte:outgoing:ws:error", function(err, req, socket, head){ + socket.close(); +}); + +// You may also use a wild card +proxyServer.ee.on("*:*:*:error", function(err, req){ + console.log("The error event '" + this.event + "' happened errno: " + err.errno); +}); + + +console.log("Proxy server is listening on port 8000"); +proxyServer.listen(8000); + From 0aeaba7fe6c51f150d0322eb90a77c1701ed88f5 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 25 Sep 2013 14:58:59 +0200 Subject: [PATCH 128/556] [fix] remove trailing whitespaces --- lib/caronte.js | 10 +++++----- lib/caronte/common.js | 10 +++++----- lib/caronte/index.js | 28 ++++++++++++++-------------- lib/caronte/passes/web-incoming.js | 30 +++++++++++++++--------------- lib/caronte/passes/web-outgoing.js | 12 ++++++------ 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/lib/caronte.js b/lib/caronte.js index 337fac94d..0bda8cd18 100644 --- a/lib/caronte.js +++ b/lib/caronte.js @@ -7,15 +7,15 @@ var http = require('http'), /** * Creates the proxy server. - * + * * Examples: - * + * * caronte.createProxyServer({ .. }, 8000) * // => '{ web: [Function], ws: [Function] ... }' * - * @param {Object} Options Config object passed to the proxy + * @param {Object} Options Config object passed to the proxy * - * @return {Object} Proxy Proxy object with handlers for `ws` and `web` requests + * @return {Object} Proxy Proxy object with handlers for `ws` and `web` requests * * @api public */ @@ -40,7 +40,7 @@ proxy.createProxyServer = function createProxyServer(options) { ].join("\n")); } - options.ee = new events.EventEmitter2({ wildcard: true, delimiter: ':' }); + options.ee = new events.EventEmitter2({ wildcard: true, delimiter: ':' }); return { ee : options.ee, diff --git a/lib/caronte/common.js b/lib/caronte/common.js index 88a20c185..ed18aa418 100644 --- a/lib/caronte/common.js +++ b/lib/caronte/common.js @@ -2,8 +2,8 @@ var common = exports, extend = require('util')._extend; /** - * Copies the right headers from `options` and `req` to - * `outgoing` which is then used to fire the proxied + * Copies the right headers from `options` and `req` to + * `outgoing` which is then used to fire the proxied * request. * * Examples: @@ -22,9 +22,9 @@ var common = exports, */ common.setupOutgoing = function(outgoing, options, req, forward) { - outgoing.port = options[forward || 'target'].port || + 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]; } ); @@ -36,7 +36,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { if (options.headers){ extend(outgoing.headers, options.headers); } - + outgoing.agent = options.agent || false; outgoing.path = req.url; diff --git a/lib/caronte/index.js b/lib/caronte/index.js index c3bb69fb7..214de9780 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -8,7 +8,7 @@ caronte.createWebProxy = createRightProxy('web'); caronte.createWsProxy = createRightProxy('ws'); /** - * Returns a function that creates the loader for + * Returns a function that creates the loader for * either `ws` or `web`'s passes. * * Examples: @@ -26,7 +26,7 @@ caronte.createWsProxy = createRightProxy('ws'); function createRightProxy(type) { var passes = (type === 'ws') ? ws : web; - return function(options) { + return function(options) { passes = Object.keys(passes).map(function(pass) { return passes[pass]; @@ -42,25 +42,25 @@ function createRightProxy(type) { 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]; } - options.ee.emit(ev + 'begin', req, res); + options.ee.emit(ev + 'begin', req, res); ['target', 'forward'].forEach( - function(e) { + function(e) { if (typeof options[e] === 'string') - options[e] = parse_url(options[e]); + options[e] = parse_url(options[e]); }); passes.some(function(pass) { @@ -74,16 +74,16 @@ function createRightProxy(type) { * refer to the connection socket * pass(req, socket, options, head) */ - - options.ee.emit(evnt + 'begin', req, res); - var val = pass(req, res, options, head); + + options.ee.emit(evnt + 'begin', req, res); + var val = pass(req, res, options, head); options.ee.emit(evnt + 'end'); - + return val; }); options.ee.emit(ev + 'end'); - }; + }; }; } diff --git a/lib/caronte/passes/web-incoming.js b/lib/caronte/passes/web-incoming.js index 1c1a6b9eb..eb6bbd8d8 100644 --- a/lib/caronte/passes/web-incoming.js +++ b/lib/caronte/passes/web-incoming.js @@ -10,7 +10,7 @@ web_o = Object.keys(web_o).map(function(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. @@ -22,7 +22,7 @@ web_o = Object.keys(web_o).map(function(pass) { * Sets `content-length` to '0' if request is of DELETE type. * * @param {ClientRequest} Req Request object - * @param {IncomingMessage} Res Response object + * @param {IncomingMessage} Res Response object * @param {Object} Options Config object passed to the proxy * * @api private @@ -38,7 +38,7 @@ function deleteLength(req, res, options) { * Sets timeout in request socket if it was specified in options. * * @param {ClientRequest} Req Request object - * @param {IncomingMessage} Res Response object + * @param {IncomingMessage} Res Response object * @param {Object} Options Config object passed to the proxy * * @api private @@ -54,7 +54,7 @@ function timeout(req, res, options) { * Sets `x-forwarded-*` headers if specified in config. * * @param {ClientRequest} Req Request object - * @param {IncomingMessage} Res Response object + * @param {IncomingMessage} Res Response object * @param {Object} Options Config object passed to the proxy * * @api private @@ -70,7 +70,7 @@ function XHeaders(req, res, options) { }; ['for', 'port', 'proto'].forEach(function(header) { - req.headers['x-forwarded-' + header] = + req.headers['x-forwarded-' + header] = (req.headers['x-forwarded-' + header] || '') + (req.headers['x-forwarded-' + header] ? ',' : '') + values[header] @@ -83,7 +83,7 @@ function XHeaders(req, res, options) { * just dies otherwise. * * @param {ClientRequest} Req Request object - * @param {IncomingMessage} Res Response object + * @param {IncomingMessage} Res Response object * @param {Object} Options Config object passed to the proxy * * @api private @@ -112,34 +112,34 @@ function stream(req, res, options) { throw err; } // Also emit the error events - options.ee.emit(ev + 'error', err, req, res); + options.ee.emit(ev + 'error', err, req, res); }); - + req.pipe(proxyReq); proxyReq.on('response', function(proxyRes) { var ev = 'caronte:outgoing:web:'; - options.ee.emit(ev + 'begin', req, res); - + options.ee.emit(ev + 'begin', req, res); + // When the previous request respond, we apply the // outgoing passes to the response web_o.some(function(pass) { var evnt = ev + pass.name.toLowerCase() + ':'; - + options.ee.emit(evnt + 'begin', req, res); // Call the pass with the proxy response // pass(ClientRequest, IncomingMessage, proxyResponse) - var val = pass(req, res, proxyRes); + var val = pass(req, res, proxyRes); options.ee.emit(evnt + 'end'); - + return val; }); options.ee.emit(ev + 'end'); - proxyRes.pipe(res); + proxyRes.pipe(res); }); //proxyReq.end(); @@ -147,5 +147,5 @@ function stream(req, res, options) { ] // <-- .forEach(function(func) { - passes[func.name] = func; + passes[func.name] = func; }); diff --git a/lib/caronte/passes/web-outgoing.js b/lib/caronte/passes/web-outgoing.js index abdaec925..20f94fdae 100644 --- a/lib/caronte/passes/web-outgoing.js +++ b/lib/caronte/passes/web-outgoing.js @@ -2,7 +2,7 @@ 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. @@ -14,7 +14,7 @@ var passes = exports; * If is a HTTP 1.0 request, remove chunk headers * * @param {ClientRequest} Req Request object - * @param {IncomingMessage} Res Response object + * @param {IncomingMessage} Res Response object * @param {proxyResponse} Res Response object from the proxy request * * @api private @@ -30,7 +30,7 @@ var passes = exports; * or if connection header not present, then use `keep-alive` * * @param {ClientRequest} Req Request object - * @param {IncomingMessage} Res Response object + * @param {IncomingMessage} Res Response object * @param {proxyResponse} Res Response object from the proxy request * * @api private @@ -55,7 +55,7 @@ var passes = exports; * set each header in response object. * * @param {ClientRequest} Req Request object - * @param {IncomingMessage} Res Response object + * @param {IncomingMessage} Res Response object * @param {proxyResponse} Res Response object from the proxy request * * @api private @@ -70,7 +70,7 @@ var passes = exports; * Set the statusCode from the proxyResponse * * @param {ClientRequest} Req Request object - * @param {IncomingMessage} Res Response object + * @param {IncomingMessage} Res Response object * @param {proxyResponse} Res Response object from the proxy request * * @api private @@ -81,5 +81,5 @@ var passes = exports; ] // <-- .forEach(function(func) { - passes[func.name] = func; + passes[func.name] = func; }); From 17399e7c3ef9addf9dd8f7c628b273e693f128a1 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 25 Sep 2013 15:08:27 +0200 Subject: [PATCH 129/556] [fix] more jshint intendation --- lib/caronte/passes/web-incoming.js | 224 ++++++++++++++--------------- lib/caronte/passes/web-outgoing.js | 11 +- lib/caronte/passes/ws-incoming.js | 208 ++++++++++++++------------- 3 files changed, 219 insertions(+), 224 deletions(-) diff --git a/lib/caronte/passes/web-incoming.js b/lib/caronte/passes/web-incoming.js index eb6bbd8d8..40eb345c7 100644 --- a/lib/caronte/passes/web-incoming.js +++ b/lib/caronte/passes/web-incoming.js @@ -18,132 +18,132 @@ web_o = Object.keys(web_o).map(function(pass) { [ // <-- -/** - * 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 : req.connection.remotePort || req.socket.remotePort, - 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 - */ + /** + * 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 : req.connection.remotePort || req.socket.remotePort, + 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) { + 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') + ); + req.pipe(forwardReq); + return res.end(); + } -function stream(req, res, options) { - 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') + // Request initalization + var proxyReq = (options.target.protocol === 'https:' ? https : http).request( + common.setupOutgoing(options.ssl || {}, options, req) ); - req.pipe(forwardReq); - 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){ - var ev = 'caronte:outgoing:web:'; - // If no error listeners, so throw the error. - if (options.ee.listeners(ev + 'error').length == 0){ + // Error Handler + proxyReq.on('error', function(err){ + var ev = 'caronte:outgoing:web:'; + // If no error listeners, so throw the error. + if (!options.ee.listeners(ev + 'error').length){ throw err; - } - // Also emit the error events - options.ee.emit(ev + 'error', err, req, res); - }); + } + // Also emit the error events + options.ee.emit(ev + 'error', err, req, res); + }); - req.pipe(proxyReq); + req.pipe(proxyReq); - proxyReq.on('response', function(proxyRes) { - var ev = 'caronte:outgoing:web:'; + proxyReq.on('response', function(proxyRes) { + var ev = 'caronte:outgoing:web:'; - options.ee.emit(ev + 'begin', req, res); + options.ee.emit(ev + 'begin', req, res); - // When the previous request respond, we apply the - // outgoing passes to the response - web_o.some(function(pass) { - var evnt = ev + pass.name.toLowerCase() + ':'; + // When the previous request respond, we apply the + // outgoing passes to the response + web_o.some(function(pass) { + var evnt = ev + pass.name.toLowerCase() + ':', val; - options.ee.emit(evnt + 'begin', req, res); - // Call the pass with the proxy response - // pass(ClientRequest, IncomingMessage, proxyResponse) - var val = pass(req, res, proxyRes); - options.ee.emit(evnt + 'end'); + options.ee.emit(evnt + 'begin', req, res); + // Call the pass with the proxy response + // pass(ClientRequest, IncomingMessage, proxyResponse) + val = pass(req, res, proxyRes); + options.ee.emit(evnt + 'end'); - return val; - }); + return val; + }); - options.ee.emit(ev + 'end'); + options.ee.emit(ev + 'end'); - proxyRes.pipe(res); - }); + proxyRes.pipe(res); + }); - //proxyReq.end(); -} + //proxyReq.end(); + } ] // <-- .forEach(function(func) { diff --git a/lib/caronte/passes/web-outgoing.js b/lib/caronte/passes/web-outgoing.js index 20f94fdae..9281c4a45 100644 --- a/lib/caronte/passes/web-outgoing.js +++ b/lib/caronte/passes/web-outgoing.js @@ -37,16 +37,9 @@ var passes = exports; */ function setConnection(req, res, proxyRes) { if (req.httpVersion === '1.0') { - if (req.headers.connection) { - proxyRes.headers.connection = req.headers.connection - } else { - proxyRes.headers.connection = 'close' - } + proxyRes.headers.connection = req.headers.connection || 'close'; } else if (!proxyRes.headers.connection) { - if (req.headers.connection) { proxyRes.headers.connection = req.headers.connection } - else { - proxyRes.headers.connection = 'keep-alive' - } + proxyRes.headers.connection = req.headers.connection || 'keep-alive'; } }, diff --git a/lib/caronte/passes/ws-incoming.js b/lib/caronte/passes/ws-incoming.js index ca2b668c8..2afec8f55 100644 --- a/lib/caronte/passes/ws-incoming.js +++ b/lib/caronte/passes/ws-incoming.js @@ -19,115 +19,117 @@ var http = require('http'), 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; - } -}, - -/** - * Set the proper configuration for sockets, - * set no delay and set keep alive, also set - * the timeout to 0. - * - * @param {ClientRequest} Req Request object - * @param {Socket} Websocket - * - * @api private - */ - -function setupSocket(req, socket) { - socket.setTimeout(0); - socket.setNoDelay(true); - - socket.setKeepAlive(true, 0); -}, - -/** - * 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 : req.connection.remotePort || req.socket.remotePort, - 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) { - common.setupSocket(socket); - - if (head && head.length) socket.unshift(head); - + /** + * 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; + } - var proxyReq = (~['https:', 'wss:'].indexOf(options.target.protocol) ? https : http).request( - common.setupOutgoing(options.ssl || {}, options, req) - ); - // Error Handler - proxyReq.on('error', function(err){ - var ev = 'caronte:outgoing:ws:'; - // If no error listeners, so throw the error. - if (options.ee.listeners(ev + 'error').length == 0){ - throw err; + if (req.headers.upgrade.toLowerCase() !== 'websocket') { + socket.destroy(); + return true; } - // Also emit the error events - options.ee.emit(ev + 'error', err, req, socket, head); - }); + }, + + /** + * Set the proper configuration for sockets, + * set no delay and set keep alive, also set + * the timeout to 0. + * + * @param {ClientRequest} Req Request object + * @param {Socket} Websocket + * + * @api private + */ + + function setupSocket(req, socket) { + socket.setTimeout(0); + socket.setNoDelay(true); + + socket.setKeepAlive(true, 0); + }, + + /** + * 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 : req.connection.remotePort || req.socket.remotePort, + 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) { + 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', function(err){ + var ev = 'caronte:outgoing:ws:'; + // If no error listeners, so throw the error. + if (!options.ee.listeners(ev + 'error').length){ + throw err; + } + // Also emit the error events + options.ee.emit(ev + 'error', err, req, socket, head); + }); - proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { - common.setupSocket(proxySocket); + proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { + common.setupSocket(proxySocket); - if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead); + 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); - }); + 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); + }); - proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT -} + proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT + } ] // <-- .forEach(function(func) { From 455f97e14cb4929e0a3a5c746471e9c5e76436fc Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 25 Sep 2013 15:11:04 +0200 Subject: [PATCH 130/556] [fix] finished jshint fixes --- lib/caronte/index.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/caronte/index.js b/lib/caronte/index.js index 214de9780..86b79a45f 100644 --- a/lib/caronte/index.js +++ b/lib/caronte/index.js @@ -57,14 +57,13 @@ 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]); + ['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() + ':'; + var evnt = ev + pass.name.toLowerCase() + ':', val; /** * Call of passes functions @@ -76,7 +75,7 @@ function createRightProxy(type) { */ options.ee.emit(evnt + 'begin', req, res); - var val = pass(req, res, options, head); + val = pass(req, res, options, head); options.ee.emit(evnt + 'end'); return val; From f7f5fa727e8f1d3f4946e61ad03830dab1da01a5 Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 26 Sep 2013 03:27:55 -0400 Subject: [PATCH 131/556] [dist doc] Added documentation for consistent benchmarking of node-http-proxy --- benchmark/README.md | 33 ++++++++ benchmark/scripts/hello.js | 3 + benchmark/scripts/proxy.js | 6 ++ benchmark/scripts/websockets-throughput.js | 88 ++++++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 benchmark/README.md create mode 100644 benchmark/scripts/hello.js create mode 100644 benchmark/scripts/proxy.js create mode 100644 benchmark/scripts/websockets-throughput.js diff --git a/benchmark/README.md b/benchmark/README.md new file mode 100644 index 000000000..2a852d14e --- /dev/null +++ b/benchmark/README.md @@ -0,0 +1,33 @@ +# 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: + -c, --connections Connections to keep open + -r, --requests Total requests to make + -t, --threads Number of threads to use + + -H, --header 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 diff --git a/benchmark/scripts/hello.js b/benchmark/scripts/hello.js new file mode 100644 index 000000000..be09b6388 --- /dev/null +++ b/benchmark/scripts/hello.js @@ -0,0 +1,3 @@ +require('http').createServer(function(req, res) { + res.end('Hello world!'); +}).listen(9000); \ No newline at end of file diff --git a/benchmark/scripts/proxy.js b/benchmark/scripts/proxy.js new file mode 100644 index 000000000..a70c55817 --- /dev/null +++ b/benchmark/scripts/proxy.js @@ -0,0 +1,6 @@ +var http = require('http'), + httpProxy = require('../../'); +// +// Create your proxy server +// +httpProxy.createProxyServer({ target: 'http://localhost:9000' }).listen(8000); \ No newline at end of file diff --git a/benchmark/scripts/websockets-throughput.js b/benchmark/scripts/websockets-throughput.js new file mode 100644 index 000000000..866e42461 --- /dev/null +++ b/benchmark/scripts/websockets-throughput.js @@ -0,0 +1,88 @@ +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); From bb0d28c58729e2cc70e8446f7fbf1113a6fa9310 Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 26 Sep 2013 03:37:08 -0400 Subject: [PATCH 132/556] [refactor minor] s/caronte/http-proxy/ or s/caronte/httpProxy/ where appropriate. --- README.md | 24 +++++------ examples/error-handling.js | 8 ++-- examples/https-secure.js | 4 +- examples/https.js | 4 +- examples/stand-alone.js | 4 +- index.js | 2 +- lib/{caronte.js => http-proxy.js} | 20 +++++----- lib/{caronte => http-proxy}/common.js | 0 lib/{caronte => http-proxy}/index.js | 16 ++++---- .../passes/web-incoming.js | 4 +- .../passes/web-outgoing.js | 0 .../passes/ws-incoming.js | 2 +- package.json | 14 ++++--- test/lib-caronte-common-test.js | 4 +- test/lib-caronte-passes-web-incoming-test.js | 10 ++--- test/lib-caronte-passes-web-outgoing-test.js | 18 ++++----- test/lib-caronte-passes-ws-incoming-test.js | 20 +++++----- test/lib-caronte-test.js | 40 +++++++++---------- 18 files changed, 99 insertions(+), 95 deletions(-) rename lib/{caronte.js => http-proxy.js} (79%) rename lib/{caronte => http-proxy}/common.js (100%) rename lib/{caronte => http-proxy}/index.js (83%) rename lib/{caronte => http-proxy}/passes/web-incoming.js (97%) rename lib/{caronte => http-proxy}/passes/web-outgoing.js (100%) rename lib/{caronte => http-proxy}/passes/ws-incoming.js (98%) diff --git a/README.md b/README.md index bc64e4226..c44fcd6d7 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@

-Caronte +node-http-proxy ======= -Caronte is an HTTP programmable proxying library that supports +`node-http-proxy` is an HTTP programmable proxying library that supports websockets. It is suitable for implementing components such as proxies and load balancers. @@ -21,12 +21,12 @@ proxies and load balancers. ### Core Concept A new proxy is created by calling `createProxyServer` and passing -an `options` object as argument ([valid properties are available here](tree/master/lib/caronte.js#L26-L39)) +an `options` object as argument ([valid properties are available here](tree/master/lib/http-proxy.js#L26-L39)) ```javascript -var caronte = require('caronte'); +var httpProxy = require('http-proxy'); -var proxy = caronte.createProxyServer(options); +var proxy = httpProxy.createProxyServer(options); ``` An object will be returned with four values: @@ -44,7 +44,7 @@ require('http').createServer(function(req, res) { }); ``` -When a request is proxied it follows two different pipelines ([available here](tree/master/lib/caronte/passes)) +When a request is proxied it follows two different pipelines ([available here](tree/master/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 @@ -58,11 +58,11 @@ In addition, every stage emits a corresponding event so introspection during the ```js var http = require('http'), - caronte = require('caronte'); + httpProxy = require('http-proxy'); // // Create your proxy server // -caronte.createProxyServer({target:'http://localhost:9000'}).listen(8000); +httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); // // Create your target server @@ -78,12 +78,12 @@ http.createServer(function (req, res) { ``` js var http = require('http'), - caronte = require('caronte'); + httpProxy = require('http-proxy'); // // Create a proxy server with custom application logic // -var proxy = caronte.createProxyServer({}); +var proxy = httpProxy.createProxyServer({}); var server = require('http').createServer(function(req, res) { proxy.web(req, res, { target: 'http://127.0.0.1:5060' }); @@ -103,7 +103,7 @@ server.listen(5050); ### Options -`caronte.createProxyServer` supports the following 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 @@ -130,7 +130,7 @@ Logo created by [Diego Pasquali](http://dribbble.com/diegopq) >The MIT License (MIT) > ->Copyright (c) 2013 Nodejitsu Inc. +>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 diff --git a/examples/error-handling.js b/examples/error-handling.js index 06b126eb3..f646a8de4 100644 --- a/examples/error-handling.js +++ b/examples/error-handling.js @@ -1,17 +1,17 @@ -var caronte = require('../index'); +var httpProxy = require('../index'); /* * Create your proxy server */ -var proxyServer = caronte.createProxyServer({target:'http://localhost:30404', ws:true}); +var proxyServer = httpProxy.createProxyServer({target:'http://localhost:30404', ws:true}); // Register an error handler for web requests -proxyServer.ee.on("caronte:outgoing:web:error", function(err, req, res){ +proxyServer.ee.on("http-proxy:outgoing:web:error", function(err, req, res){ res.writeHead(502); res.end("There was an error proxying your request"); }); // Register an error handler for web-socket requests -proxyServer.ee.on("caronte:outgoing:ws:error", function(err, req, socket, head){ +proxyServer.ee.on("http-proxy:outgoing:ws:error", function(err, req, socket, head){ socket.close(); }); diff --git a/examples/https-secure.js b/examples/https-secure.js index b6d7bb759..4ddbe8d23 100644 --- a/examples/https-secure.js +++ b/examples/https-secure.js @@ -1,4 +1,4 @@ -var caronte = require('caronte'), +var httpProxy = require('http-proxy'), https = require('https'); /* * Create your proxy server pointing to a secure domain @@ -9,7 +9,7 @@ var options = {target : 'https://google.com', headers: {host: 'google.com'} }; -var proxyServer = caronte.createProxyServer(options); +var proxyServer = httpProxy.createProxyServer(options); console.log("Proxy server listening on port 8000"); proxyServer.listen(8000); diff --git a/examples/https.js b/examples/https.js index b64e3cf2f..7f0aed3e2 100644 --- a/examples/https.js +++ b/examples/https.js @@ -1,10 +1,10 @@ -var caronte = require('caronte'); +var httpProxy = require('http-proxy'); /* * Create your proxy server pointing to a secure domain */ var options = {target:'https://google.com'}; -var proxyServer = caronte.createProxyServer(options); +var proxyServer = httpProxy.createProxyServer(options); console.log("Proxy server listening on port 8000"); proxyServer.listen(8000); diff --git a/examples/stand-alone.js b/examples/stand-alone.js index 081134e6b..3bf6ddccf 100644 --- a/examples/stand-alone.js +++ b/examples/stand-alone.js @@ -1,10 +1,10 @@ var http = require('http'), - caronte = require('caronte'); + httpProxy = require('http-proxy'); // // Create your proxy server // console.log("Proxy server listening on port 8000"); -caronte.createProxyServer({target:'http://localhost:9000'}).listen(8000); +httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); // // Create your target server diff --git a/index.js b/index.js index 68de922bd..e6fac8584 100644 --- a/index.js +++ b/index.js @@ -10,4 +10,4 @@ * Dante - The Divine Comedy (Canto III) */ -module.exports = require('./lib/caronte'); \ No newline at end of file +module.exports = require('./lib/http-proxy'); \ No newline at end of file diff --git a/lib/caronte.js b/lib/http-proxy.js similarity index 79% rename from lib/caronte.js rename to lib/http-proxy.js index 0bda8cd18..8cabc6fa1 100644 --- a/lib/caronte.js +++ b/lib/http-proxy.js @@ -1,16 +1,16 @@ -var http = require('http'), - https = require('https'), - url = require('url'), - caronte = require('./caronte/'), - events = require('eventemitter2'), - proxy = exports; +var http = require('http'), + https = require('https'), + url = require('url'), + httpProxy = require('./http-proxy'), + events = require('eventemitter2'), + proxy = exports; /** * Creates the proxy server. * * Examples: * - * caronte.createProxyServer({ .. }, 8000) + * httpProxy.createProxyServer({ .. }, 8000) * // => '{ web: [Function], ws: [Function] ... }' * * @param {Object} Options Config object passed to the proxy @@ -20,7 +20,7 @@ var http = require('http'), * @api public */ -proxy.createProxyServer = function createProxyServer(options) { +proxy.createProxyServer = proxy.createServer = function createProxyServer(options) { if(!options) { throw new Error([ "`options` is needed and it must have the following layout:", @@ -44,8 +44,8 @@ proxy.createProxyServer = function createProxyServer(options) { return { ee : options.ee, - web : caronte.createWebProxy(options), - ws : caronte.createWsProxy(options), + web : httpProxy.createWebProxy(options), + ws : httpProxy.createWsProxy(options), listen : function listen(port) { var server = options.ssl ? https.createServer(options.ssl, this.web) : http.createServer(this.web); diff --git a/lib/caronte/common.js b/lib/http-proxy/common.js similarity index 100% rename from lib/caronte/common.js rename to lib/http-proxy/common.js diff --git a/lib/caronte/index.js b/lib/http-proxy/index.js similarity index 83% rename from lib/caronte/index.js rename to lib/http-proxy/index.js index 86b79a45f..22d2d5c9b 100644 --- a/lib/caronte/index.js +++ b/lib/http-proxy/index.js @@ -1,11 +1,11 @@ -var caronte = exports, - extend = require('util')._extend, +var httpProxy = exports, + extend = require('util')._extend, parse_url = require('url').parse, - web = require('./passes/web-incoming'), - ws = require('./passes/ws-incoming'); + web = require('./passes/web-incoming'), + ws = require('./passes/ws-incoming'); -caronte.createWebProxy = createRightProxy('web'); -caronte.createWsProxy = createRightProxy('ws'); +httpProxy.createWebProxy = createRightProxy('web'); +httpProxy.createWsProxy = createRightProxy('ws'); /** * Returns a function that creates the loader for @@ -13,7 +13,7 @@ caronte.createWsProxy = createRightProxy('ws'); * * Examples: * - * caronte.createRightProxy('ws') + * httpProxy.createRightProxy('ws') * // => [Function] * * @param {String} Type Either 'ws' or 'web' @@ -36,7 +36,7 @@ function createRightProxy(type) { var self = this, args = [].slice.call(arguments), cntr = args.length - 1, - ev = 'caronte:' + type + ':incoming:', + ev = 'http-proxy:' + type + ':incoming:', head; if( diff --git a/lib/caronte/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js similarity index 97% rename from lib/caronte/passes/web-incoming.js rename to lib/http-proxy/passes/web-incoming.js index 40eb345c7..8f5afae9d 100644 --- a/lib/caronte/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -106,7 +106,7 @@ web_o = Object.keys(web_o).map(function(pass) { // Error Handler proxyReq.on('error', function(err){ - var ev = 'caronte:outgoing:web:'; + var ev = 'http-proxy:outgoing:web:'; // If no error listeners, so throw the error. if (!options.ee.listeners(ev + 'error').length){ throw err; @@ -118,7 +118,7 @@ web_o = Object.keys(web_o).map(function(pass) { req.pipe(proxyReq); proxyReq.on('response', function(proxyRes) { - var ev = 'caronte:outgoing:web:'; + var ev = 'http-proxy:outgoing:web:'; options.ee.emit(ev + 'begin', req, res); diff --git a/lib/caronte/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js similarity index 100% rename from lib/caronte/passes/web-outgoing.js rename to lib/http-proxy/passes/web-outgoing.js diff --git a/lib/caronte/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js similarity index 98% rename from lib/caronte/passes/ws-incoming.js rename to lib/http-proxy/passes/ws-incoming.js index 2afec8f55..070cefbb9 100644 --- a/lib/caronte/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -107,7 +107,7 @@ var passes = exports; ); // Error Handler proxyReq.on('error', function(err){ - var ev = 'caronte:outgoing:ws:'; + var ev = 'http-proxy:outgoing:ws:'; // If no error listeners, so throw the error. if (!options.ee.listeners(ev + 'error').length){ throw err; diff --git a/package.json b/package.json index 22406ba23..a4f653b5d 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,13 @@ { - "name" : "caronte", - "version" : "0.0.0", + "name" : "http-proxy", + "version" : "1.0.0", "description" : "HTTP proxying for the masses", - "author" : "yawnt ", - + "author": "Nodejitsu Inc. ", + "maintainers" : [ + "yawnt ", + "indexzero " + ], + "main" : "index.js", "dependencies" : { @@ -24,7 +28,7 @@ }, "scripts" : { "coveralls" : "mocha --require blanket --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js", - "blanket" : { "pattern": "lib/caronte" }, + "blanket" : { "pattern": "lib/http-proxy" }, "test" : "./node_modules/.bin/mocha -R landing test/*-test.js", "test-cov" : "./node_modules/.bin/mocha --require blanket -R html-cov > cov/coverage.html" }, diff --git a/test/lib-caronte-common-test.js b/test/lib-caronte-common-test.js index ac79867c5..2f9fa1ed8 100644 --- a/test/lib-caronte-common-test.js +++ b/test/lib-caronte-common-test.js @@ -1,7 +1,7 @@ -var common = require('../lib/caronte/common'), +var common = require('../lib/http-proxy/common'), expect = require('expect.js'); -describe('lib/caronte/common.js', function () { +describe('lib/http-proxy/common.js', function () { describe('#setupOutgoing', function () { it('should setup the correct headers', function () { var outgoing = {}; diff --git a/test/lib-caronte-passes-web-incoming-test.js b/test/lib-caronte-passes-web-incoming-test.js index cc0a760a7..4269d5f8b 100644 --- a/test/lib-caronte-passes-web-incoming-test.js +++ b/test/lib-caronte-passes-web-incoming-test.js @@ -1,14 +1,14 @@ -var caronte = require('../lib/caronte/passes/web-incoming'), +var httpProxy = require('../lib/http-proxy/passes/web-incoming'), expect = require('expect.js'); -describe('lib/caronte/passes/web.js', function() { +describe('lib/http-proxy/passes/web.js', function() { describe('#deleteLength', function() { it('should change `content-length`', function() { var stubRequest = { method: 'DELETE', headers: {} }; - caronte.deleteLength(stubRequest, {}, {}); + httpProxy.deleteLength(stubRequest, {}, {}); expect(stubRequest.headers['content-length']).to.eql('0'); }) }); @@ -21,7 +21,7 @@ describe('lib/caronte/passes/web.js', function() { } } - caronte.timeout(stubRequest, {}, { timeout: 5000}); + httpProxy.timeout(stubRequest, {}, { timeout: 5000}); expect(done).to.eql(5000); }); }); @@ -36,7 +36,7 @@ describe('lib/caronte/passes/web.js', function() { } it('set the correct x-forwarded-* headers', function () { - caronte.XHeaders(stubRequest, {}, { xfwd: true }); + 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('http'); diff --git a/test/lib-caronte-passes-web-outgoing-test.js b/test/lib-caronte-passes-web-outgoing-test.js index 64fc7ead9..0ae0bda6f 100644 --- a/test/lib-caronte-passes-web-outgoing-test.js +++ b/test/lib-caronte-passes-web-outgoing-test.js @@ -1,11 +1,11 @@ -var caronte = require('../lib/caronte/passes/web-outgoing'), +var httpProxy = require('../lib/http-proxy/passes/web-outgoing'), expect = require('expect.js'); -describe('lib/caronte/passes/web-outgoing.js', function () { +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: {} }; - caronte.setConnection({ + httpProxy.setConnection({ httpVersion: '1.0', headers: { connection: null @@ -17,7 +17,7 @@ describe('lib/caronte/passes/web-outgoing.js', function () { it('set the right connection with 1.0 - req.connection', function() { var proxyRes = { headers: {} }; - caronte.setConnection({ + httpProxy.setConnection({ httpVersion: '1.0', headers: { connection: 'hey' @@ -29,7 +29,7 @@ describe('lib/caronte/passes/web-outgoing.js', function () { it('set the right connection - req.connection', function() { var proxyRes = { headers: {} }; - caronte.setConnection({ + httpProxy.setConnection({ httpVersion: null, headers: { connection: 'hola' @@ -41,7 +41,7 @@ describe('lib/caronte/passes/web-outgoing.js', function () { it('set the right connection - `keep-alive`', function() { var proxyRes = { headers: {} }; - caronte.setConnection({ + httpProxy.setConnection({ httpVersion: null, headers: { connection: null @@ -61,7 +61,7 @@ describe('lib/caronte/passes/web-outgoing.js', function () { } } - caronte.writeStatusCode({}, res, { statusCode: 200 }); + httpProxy.writeStatusCode({}, res, { statusCode: 200 }); }); }); @@ -80,7 +80,7 @@ describe('lib/caronte/passes/web-outgoing.js', function () { headers: {} }; - caronte.writeHeaders({}, res, proxyRes); + httpProxy.writeHeaders({}, res, proxyRes); expect(res.headers.hey).to.eql('hello'); expect(res.headers.how).to.eql('are you?'); @@ -95,7 +95,7 @@ describe('lib/caronte/passes/web-outgoing.js', function () { }; - caronte.removeChunked({ httpVersion: '1.0' }, {}, proxyRes); + httpProxy.removeChunked({ httpVersion: '1.0' }, {}, proxyRes); expect(proxyRes.headers['transfer-encoding']).to.eql(undefined); }); diff --git a/test/lib-caronte-passes-ws-incoming-test.js b/test/lib-caronte-passes-ws-incoming-test.js index 2c077d4df..87dfcef94 100644 --- a/test/lib-caronte-passes-ws-incoming-test.js +++ b/test/lib-caronte-passes-ws-incoming-test.js @@ -1,7 +1,7 @@ -var caronte = require('../lib/caronte/passes/ws-incoming'), +var httpProxy = require('../lib/http-proxy/passes/ws-incoming'), expect = require('expect.js'); -describe('lib/caronte/passes/ws-incoming.js', function () { +describe('lib/http-proxy/passes/ws-incoming.js', function () { describe('#checkMethodAndHeader', function () { it('should drop non-GET connections', function () { var destroyCalled = false, @@ -15,7 +15,7 @@ describe('lib/caronte/passes/ws-incoming.js', function () { destroyCalled = true; } } - returnValue = caronte.checkMethodAndHeader(stubRequest, stubSocket); + returnValue = httpProxy.checkMethodAndHeader(stubRequest, stubSocket); expect(returnValue).to.be(true); expect(destroyCalled).to.be(true); }) @@ -32,7 +32,7 @@ describe('lib/caronte/passes/ws-incoming.js', function () { destroyCalled = true; } } - returnValue = caronte.checkMethodAndHeader(stubRequest, stubSocket); + returnValue = httpProxy.checkMethodAndHeader(stubRequest, stubSocket); expect(returnValue).to.be(true); expect(destroyCalled).to.be(true); }) @@ -51,7 +51,7 @@ describe('lib/caronte/passes/ws-incoming.js', function () { destroyCalled = true; } } - returnValue = caronte.checkMethodAndHeader(stubRequest, stubSocket); + returnValue = httpProxy.checkMethodAndHeader(stubRequest, stubSocket); expect(returnValue).to.be(true); expect(destroyCalled).to.be(true); }) @@ -70,7 +70,7 @@ describe('lib/caronte/passes/ws-incoming.js', function () { destroyCalled = true; } } - returnValue = caronte.checkMethodAndHeader(stubRequest, stubSocket); + returnValue = httpProxy.checkMethodAndHeader(stubRequest, stubSocket); expect(returnValue).to.be(undefined); expect(destroyCalled).to.be(false); }) @@ -97,7 +97,7 @@ describe('lib/caronte/passes/ws-incoming.js', function () { nodelay: false, keepalive: false }, - returnValue = caronte.setupSocket({}, stubSocket); + returnValue = httpProxy.setupSocket({}, stubSocket); expect(returnValue).to.be(undefined); expect(socketConfig.timeout).to.eql(0); expect(socketConfig.nodelay).to.eql(true); @@ -107,7 +107,7 @@ describe('lib/caronte/passes/ws-incoming.js', function () { describe('#XHeaders', function () { it('return if no forward request', function () { - var returnValue = caronte.XHeaders({}, {}, {}); + var returnValue = httpProxy.XHeaders({}, {}, {}); expect(returnValue).to.be(undefined); }); @@ -119,7 +119,7 @@ describe('lib/caronte/passes/ws-incoming.js', function () { }, headers: {} } - caronte.XHeaders(stubRequest, {}, { xfwd: true }); + 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'); @@ -136,7 +136,7 @@ describe('lib/caronte/passes/ws-incoming.js', function () { }, headers: {} }; - caronte.XHeaders(stubRequest, {}, { xfwd: true }); + 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'); diff --git a/test/lib-caronte-test.js b/test/lib-caronte-test.js index 0558ef934..b9aa8af7f 100644 --- a/test/lib-caronte-test.js +++ b/test/lib-caronte-test.js @@ -1,17 +1,17 @@ -var caronte = require('../lib/caronte'), - expect = require('expect.js'), - http = require('http'), - ws = require('ws') - io = require('socket.io'), - ioClient = require('socket.io-client'); +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'); -describe('lib/caronte.js', function() { +describe('lib/http-proxy.js', function() { describe('#createProxyServer', function() { it('should throw without options', function() { var error; try { - caronte.createProxyServer(); + httpProxy.createProxyServer(); } catch(e) { error = e; } @@ -20,7 +20,7 @@ describe('lib/caronte.js', function() { }) it('should return an object otherwise', function() { - var obj = caronte.createProxyServer({ + var obj = httpProxy.createProxyServer({ target: 'http://www.google.com:80' }); @@ -32,7 +32,7 @@ describe('lib/caronte.js', 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 proxy = caronte.createProxyServer({ + var proxy = httpProxy.createProxyServer({ forward: 'http://127.0.0.1:8080' }).listen('8081') @@ -52,7 +52,7 @@ describe('lib/caronte.js', function() { describe('#createProxyServer using the web-incoming passes', function () { it('should make the request on pipe and finish it', function(done) { - var proxy = caronte.createProxyServer({ + var proxy = httpProxy.createProxyServer({ target: 'http://127.0.0.1:8080' }).listen('8081'); @@ -80,7 +80,7 @@ describe('lib/caronte.js', function() { describe('#createProxyServer using the web-incoming passes', function () { it('should make the request, handle response and finish it', function(done) { - var proxy = caronte.createProxyServer({ + var proxy = httpProxy.createProxyServer({ target: 'http://127.0.0.1:8080' }).listen('8081'); @@ -115,11 +115,11 @@ describe('lib/caronte.js', function() { describe('#createProxyServer() method with error response', function () { it('should make the request and emit the error event', function(done) { - var proxy = caronte.createProxyServer({ + var proxy = httpProxy.createProxyServer({ target: 'http://127.0.0.1:8080' }); - proxy.ee.on('caronte:outgoing:web:error', function (err) { + proxy.ee.on('http-proxy:outgoing:web:error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNREFUSED'); proxyServer.close(); @@ -138,7 +138,7 @@ describe('lib/caronte.js', function() { describe('#createProxyServer using the web-incoming passes', function () { it('should emit events correclty', function(done) { - var proxy = caronte.createProxyServer({ + var proxy = httpProxy.createProxyServer({ target: 'http://127.0.0.1:8080' }), @@ -155,7 +155,7 @@ describe('lib/caronte.js', function() { source.listen('8080'); - proxy.ee.on('caronte:**', function (uno, dos, tres) { + proxy.ee.on('http-proxy:**', function (uno, dos, tres) { events.push(this.event); }) @@ -171,8 +171,8 @@ describe('lib/caronte.js', function() { }); res.on('end', function () { - expect(events).to.contain('caronte:outgoing:web:begin'); - expect(events).to.contain('caronte:outgoing:web:end'); + expect(events).to.contain('http-proxy:outgoing:web:begin'); + expect(events).to.contain('http-proxy:outgoing:web:end'); source.close(); proxyServer.close(); done(); @@ -183,7 +183,7 @@ describe('lib/caronte.js', function() { describe('#createProxyServer using the ws-incoming passes', function () { it('should proxy the websockets stream', function (done) { - var proxy = caronte.createProxyServer({ + var proxy = httpProxy.createProxyServer({ target: 'ws://127.0.0.1:8080', ws: true }), @@ -215,7 +215,7 @@ describe('lib/caronte.js', function() { describe('#createProxyServer using the ws-incoming passes', function () { it('should proxy a socket.io stream', function (done) { - var proxy = caronte.createProxyServer({ + var proxy = httpProxy.createProxyServer({ target: 'ws://127.0.0.1:8080', ws: true }), From 8269eca2bb34d08336b8889e06e53d3522fa79fe Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 26 Sep 2013 11:13:16 +0200 Subject: [PATCH 133/556] [fix] tests --- lib/http-proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 8cabc6fa1..2fe565e86 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -1,7 +1,7 @@ var http = require('http'), https = require('https'), url = require('url'), - httpProxy = require('./http-proxy'), + httpProxy = require('./http-proxy/'), events = require('eventemitter2'), proxy = exports; From a51b0622780f48160001f9e74340f7d720cbfce6 Mon Sep 17 00:00:00 2001 From: 3rd-Eden Date: Tue, 1 Oct 2013 09:14:37 +0200 Subject: [PATCH 134/556] [minor] Remove duplicate dependencies and cleanup of the scripts --- package.json | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index a4f653b5d..770b97801 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "yawnt ", "indexzero " ], - - "main" : "index.js", + + "main" : "index.js", "dependencies" : { "eventemitter2" : "*" @@ -22,19 +22,17 @@ "blanket" : "*", "ws" : "*", "socket.io" : "*", - "socket.io-client" : "*", - "coveralls" : "*", - "mocha-lcov-reporter": "*" + "socket.io-client" : "*" }, "scripts" : { "coveralls" : "mocha --require blanket --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js", "blanket" : { "pattern": "lib/http-proxy" }, - "test" : "./node_modules/.bin/mocha -R landing test/*-test.js", - "test-cov" : "./node_modules/.bin/mocha --require blanket -R html-cov > cov/coverage.html" + "test" : "mocha -R landing test/*-test.js", + "test-cov" : "mocha --require blanket -R html-cov > cov/coverage.html" }, - "engines" : { - "node" : ">=0.10.0" + "engines" : { + "node" : ">=0.10.0" }, "license" : "MIT" From b79bd29d5e984f34b9c07fbdc803aed83b3fd0bb Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 8 Oct 2013 22:24:16 +0200 Subject: [PATCH 135/556] [feature] start working on the new server --- lib/http-proxy.js | 24 +++------------------ lib/http-proxy/index.js | 48 +++++++++++++++++++++++++++++------------ package.json | 2 +- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 2fe565e86..d84772a10 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -21,7 +21,7 @@ var http = require('http'), */ proxy.createProxyServer = proxy.createServer = function createProxyServer(options) { - if(!options) { + /* if(!options) { throw new Error([ "`options` is needed and it must have the following layout:", " ", @@ -38,25 +38,7 @@ proxy.createProxyServer = proxy.createServer = function createProxyServer(option " `options.target and `options.forward` cannot be ", " both missing " ].join("\n")); - } + } */ - options.ee = new events.EventEmitter2({ wildcard: true, delimiter: ':' }); - - return { - ee : options.ee, - web : httpProxy.createWebProxy(options), - ws : httpProxy.createWsProxy(options), - listen : function listen(port) { - var server = options.ssl ? https.createServer(options.ssl, this.web) : http.createServer(this.web); - - if(options.ws) { - server.on('upgrade', this.ws); - } - - server.listen(port); - - return server; - } - }; + return new ProxyServer(options, httpProxy.createWebProxy(options), httpProxy.createWsProxy(options)); }; - diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 22d2d5c9b..9a2798fd6 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -1,11 +1,13 @@ var httpProxy = exports, extend = require('util')._extend, parse_url = require('url').parse, + EE3 = require('eventemitter3').EventEmitter, web = require('./passes/web-incoming'), ws = require('./passes/ws-incoming'); httpProxy.createWebProxy = createRightProxy('web'); httpProxy.createWsProxy = createRightProxy('ws'); +httpProxy.Server = ProxyServer; /** * Returns a function that creates the loader for @@ -36,7 +38,6 @@ function createRightProxy(type) { var self = this, args = [].slice.call(arguments), cntr = args.length - 1, - ev = 'http-proxy:' + type + ':incoming:', head; if( @@ -55,16 +56,13 @@ function createRightProxy(type) { head = args[cntr]; } - 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() + ':', val; + for(var i=0; i < passes.length; i++) { /** * Call of passes functions * pass(req, res, options, head) @@ -73,16 +71,38 @@ function createRightProxy(type) { * refer to the connection socket * pass(req, socket, options, head) */ - - options.ee.emit(evnt + 'begin', req, res); - val = pass(req, res, options, head); - options.ee.emit(evnt + 'end'); - - return val; - }); - - options.ee.emit(ev + 'end'); + if(passes[i](req, res, this, head)) { // passes can return a truthy value to halt the loop + break; + } + } }; }; } + +function ProxyServer(options, web, ws) { + this.web = web; + this.ws = ws; + this.options = options; +} + +ProxyServer.prototype.listen = function(port) { + var self = this, + closure = function(req, res) { self.web(req, res); }, + server = options.ssl ? + https.createServer(this.options.ssl, closure) : + http.createServer(closure); + + if(options.ws) { + server.on('upgrade', function(req, socket, head) { self.ws(req, socket, head); }); + } + + server.listen(port); + + return server; +}; + +ProxyServer.prototype.before = function() {}; +ProxyServer.prototype.after = function() {}; + +require('util').inherits(ProxyServer, EE); diff --git a/package.json b/package.json index 770b97801..98cd9b5d4 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "main" : "index.js", "dependencies" : { - "eventemitter2" : "*" + "eventemitter3" : "*" }, "devDependencies": { "mocha" : "*", From 601dbcbfe929af31995568b4f36b877245809058 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 9 Oct 2013 16:59:03 +0200 Subject: [PATCH 136/556] [fix] refactor error handling --- lib/http-proxy.js | 2 +- lib/http-proxy/index.js | 10 +++---- lib/http-proxy/passes/web-incoming.js | 41 ++++++--------------------- lib/http-proxy/passes/ws-incoming.js | 14 +++------ 4 files changed, 19 insertions(+), 48 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index d84772a10..945644372 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -2,7 +2,6 @@ var http = require('http'), https = require('https'), url = require('url'), httpProxy = require('./http-proxy/'), - events = require('eventemitter2'), proxy = exports; /** @@ -42,3 +41,4 @@ proxy.createProxyServer = proxy.createServer = function createProxyServer(option return new ProxyServer(options, httpProxy.createWebProxy(options), httpProxy.createWsProxy(options)); }; + diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 9a2798fd6..5c6e7e045 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -89,20 +89,20 @@ function ProxyServer(options, web, ws) { ProxyServer.prototype.listen = function(port) { var self = this, closure = function(req, res) { self.web(req, res); }, - server = options.ssl ? + this._server = options.ssl ? https.createServer(this.options.ssl, closure) : http.createServer(closure); if(options.ws) { - server.on('upgrade', function(req, socket, head) { self.ws(req, socket, head); }); + this._server.on('upgrade', function(req, socket, head) { self.ws(req, socket, head); }); } - server.listen(port); + this._server.listen(port); - return server; + return this; }; ProxyServer.prototype.before = function() {}; ProxyServer.prototype.after = function() {}; -require('util').inherits(ProxyServer, EE); +require('util').inherits(ProxyServer, EE3); diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 8f5afae9d..13d1c0164 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -89,55 +89,32 @@ web_o = Object.keys(web_o).map(function(pass) { * @api private */ - function stream(req, res, options) { + function stream(req, res, server) { 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') + var forwardReq = (server.options.forward.protocol === 'https:' ? https : http).request( + common.setupOutgoing(server.options.ssl || {}, server.options, req, 'forward') ); req.pipe(forwardReq); return res.end(); } // Request initalization - var proxyReq = (options.target.protocol === 'https:' ? https : http).request( - common.setupOutgoing(options.ssl || {}, options, req) + var proxyReq = (server.options.target.protocol === 'https:' ? https : http).request( + common.setupOutgoing(server.options.ssl || {}, server.options, req) ); // Error Handler proxyReq.on('error', function(err){ - var ev = 'http-proxy:outgoing:web:'; - // If no error listeners, so throw the error. - if (!options.ee.listeners(ev + 'error').length){ - throw err; - } - // Also emit the error events - options.ee.emit(ev + 'error', err, req, res); + server.emit('error', err); }); req.pipe(proxyReq); proxyReq.on('response', function(proxyRes) { - var ev = 'http-proxy:outgoing:web:'; - - options.ee.emit(ev + 'begin', req, res); - - // When the previous request respond, we apply the - // outgoing passes to the response - web_o.some(function(pass) { - var evnt = ev + pass.name.toLowerCase() + ':', val; - - options.ee.emit(evnt + 'begin', req, res); - // Call the pass with the proxy response - // pass(ClientRequest, IncomingMessage, proxyResponse) - val = pass(req, res, proxyRes); - options.ee.emit(evnt + 'end'); - - return val; - }); - - options.ee.emit(ev + 'end'); - + for(var i=0; i < web_o.length; i++) { + if(web_o[i](req, res, proxyRes)) { break; } + } proxyRes.pipe(res); }); diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 070cefbb9..47ed638fc 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -96,24 +96,18 @@ var passes = exports; * * @api private */ - function stream(req, socket, options, head) { + function stream(req, socket, server, head) { 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) + var proxyReq = (~['https:', 'wss:'].indexOf(server.options.target.protocol) ? https : http).request( + common.setupOutgoing(server.options.ssl || {}, server.options, req) ); // Error Handler proxyReq.on('error', function(err){ - var ev = 'http-proxy:outgoing:ws:'; - // If no error listeners, so throw the error. - if (!options.ee.listeners(ev + 'error').length){ - throw err; - } - // Also emit the error events - options.ee.emit(ev + 'error', err, req, socket, head); + server.emit('error', err); }); proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { From c7924e01f92aeec07333273f0882c1dd5e9521ae Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 9 Oct 2013 17:23:44 +0200 Subject: [PATCH 137/556] [fix] callback as optional error handler --- lib/http-proxy/index.js | 41 +++++++++++++++++++++++---- lib/http-proxy/passes/web-incoming.js | 11 +++++-- lib/http-proxy/passes/ws-incoming.js | 9 ++++-- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 5c6e7e045..83e1993de 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -35,10 +35,17 @@ function createRightProxy(type) { }); return function(req, res /*, [head], [opts] */) { - var self = this, + var passes = this.passes || passes, args = [].slice.call(arguments), cntr = args.length - 1, - head; + head, cbl; + + /* optional args parse begin */ + if(typeof args[cntr] === 'function') { + cbl = args[cntr]; + + cntr--; + } if( !(args[cntr] instanceof Buffer) && @@ -56,6 +63,8 @@ function createRightProxy(type) { head = args[cntr]; } + /* optional args parse end */ + ['target', 'forward'].forEach(function(e) { if (typeof options[e] === 'string') options[e] = parse_url(options[e]); @@ -71,7 +80,7 @@ function createRightProxy(type) { * refer to the connection socket * pass(req, socket, options, head) */ - if(passes[i](req, res, this, head)) { // passes can return a truthy value to halt the loop + if(passes[i](req, res, cbl ? this : false, head, cbl)) { // passes can return a truthy value to halt the loop break; } } @@ -84,6 +93,10 @@ function ProxyServer(options, web, ws) { this.web = web; this.ws = ws; this.options = options; + + this.passes = Object.keys(passes).map(function(pass) { + return passes[pass]; + }); } ProxyServer.prototype.listen = function(port) { @@ -102,7 +115,25 @@ ProxyServer.prototype.listen = function(port) { return this; }; -ProxyServer.prototype.before = function() {}; -ProxyServer.prototype.after = function() {}; +ProxyServer.prototype.before = function(passName, callback) { + var i = false; + this.passes.forEach(function(v, idx) { + if(v.name === passName) i = idx; + }) + + if(!i) throw new Error('No such pass'); + + this.passes.splice(i, 0, callback); +}; +ProxyServer.prototype.after = function(passName, callback) { + var i = false; + this.passes.forEach(function(v, idx) { + if(v.name === passName) i = idx; + }) + + if(!i) throw new Error('No such pass'); + + this.passes.splice(i++, 0, callback); +}; require('util').inherits(ProxyServer, EE3); diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 13d1c0164..b8f936d51 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -89,8 +89,8 @@ web_o = Object.keys(web_o).map(function(pass) { * @api private */ - function stream(req, res, server) { - if(options.forward) { + function stream(req, res, server, _, clb) { + if(server.options.forward) { // If forward enable, so just pipe the request var forwardReq = (server.options.forward.protocol === 'https:' ? https : http).request( common.setupOutgoing(server.options.ssl || {}, server.options, req, 'forward') @@ -106,7 +106,12 @@ web_o = Object.keys(web_o).map(function(pass) { // Error Handler proxyReq.on('error', function(err){ - server.emit('error', err); + if(server) { + server.emit('error', err); + } + else {  + clb(err); + } }); req.pipe(proxyReq); diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 47ed638fc..66c75d506 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -96,7 +96,7 @@ var passes = exports; * * @api private */ - function stream(req, socket, server, head) { + function stream(req, socket, server, head, clb) { common.setupSocket(socket); if (head && head.length) socket.unshift(head); @@ -107,7 +107,12 @@ var passes = exports; ); // Error Handler proxyReq.on('error', function(err){ - server.emit('error', err); + if(server) { + server.emit('error', err); + } + else { + clb(err); + } }); proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { From 5a1504f0764b7747b53cc0d92a69ff3093e85ade Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 9 Oct 2013 17:28:39 +0200 Subject: [PATCH 138/556] [fix] minor typo --- lib/http-proxy/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 83e1993de..c4b043cac 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -90,6 +90,8 @@ function createRightProxy(type) { function ProxyServer(options, web, ws) { + EE3.call(this); + this.web = web; this.ws = ws; this.options = options; From 3d8e5383cd9d527825f95d9071a87865fcebca05 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 9 Oct 2013 17:31:02 +0200 Subject: [PATCH 139/556] [fix] better code --- lib/http-proxy.js | 2 +- lib/http-proxy/index.js | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 945644372..f17217864 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -39,6 +39,6 @@ proxy.createProxyServer = proxy.createServer = function createProxyServer(option ].join("\n")); } */ - return new ProxyServer(options, httpProxy.createWebProxy(options), httpProxy.createWsProxy(options)); + return new ProxyServer(options); }; diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index c4b043cac..4faa3956b 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -4,10 +4,8 @@ var httpProxy = exports, EE3 = require('eventemitter3').EventEmitter, web = require('./passes/web-incoming'), ws = require('./passes/ws-incoming'); - -httpProxy.createWebProxy = createRightProxy('web'); -httpProxy.createWsProxy = createRightProxy('ws'); -httpProxy.Server = ProxyServer; + +httpProxy.Server = ProxyServer; /** * Returns a function that creates the loader for @@ -89,11 +87,11 @@ function createRightProxy(type) { } -function ProxyServer(options, web, ws) { +function ProxyServer(options) { EE3.call(this); - this.web = web; - this.ws = ws; + this.web = createRightProxy('web')(options); + this.ws = reateRightProxy('ws')(options); this.options = options; this.passes = Object.keys(passes).map(function(pass) { From a9f9e21eda2f8e912523e6b62abb0101c0353505 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 9 Oct 2013 17:37:20 +0200 Subject: [PATCH 140/556] [fix] --- lib/http-proxy/index.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 4faa3956b..7528f46e6 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -101,10 +101,11 @@ function ProxyServer(options) { ProxyServer.prototype.listen = function(port) { var self = this, - closure = function(req, res) { self.web(req, res); }, - this._server = options.ssl ? - https.createServer(this.options.ssl, closure) : - http.createServer(closure); + closure = function(req, res) { self.web(req, res); }; + + this._server = options.ssl ? + https.createServer(this.options.ssl, closure) : + http.createServer(closure); if(options.ws) { this._server.on('upgrade', function(req, socket, head) { self.ws(req, socket, head); }); From c9f5772fc18226aca31471bc96c44a6dbff5cbea Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 9 Oct 2013 10:49:13 -0500 Subject: [PATCH 141/556] [tests] remove caronte and use http-proxy for file names --- .../{lib-caronte-common-test.js => lib-http-proxy-common-test.js} | 0 ...ncoming-test.js => lib-http-proxy-passes-web-incoming-test.js} | 0 ...utgoing-test.js => lib-http-proxy-passes-web-outgoing-test.js} | 0 ...incoming-test.js => lib-http-proxy-passes-ws-incoming-test.js} | 0 test/{lib-caronte-test.js => lib-http-proxy-test.js} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename test/{lib-caronte-common-test.js => lib-http-proxy-common-test.js} (100%) rename test/{lib-caronte-passes-web-incoming-test.js => lib-http-proxy-passes-web-incoming-test.js} (100%) rename test/{lib-caronte-passes-web-outgoing-test.js => lib-http-proxy-passes-web-outgoing-test.js} (100%) rename test/{lib-caronte-passes-ws-incoming-test.js => lib-http-proxy-passes-ws-incoming-test.js} (100%) rename test/{lib-caronte-test.js => lib-http-proxy-test.js} (100%) diff --git a/test/lib-caronte-common-test.js b/test/lib-http-proxy-common-test.js similarity index 100% rename from test/lib-caronte-common-test.js rename to test/lib-http-proxy-common-test.js diff --git a/test/lib-caronte-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js similarity index 100% rename from test/lib-caronte-passes-web-incoming-test.js rename to test/lib-http-proxy-passes-web-incoming-test.js diff --git a/test/lib-caronte-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js similarity index 100% rename from test/lib-caronte-passes-web-outgoing-test.js rename to test/lib-http-proxy-passes-web-outgoing-test.js diff --git a/test/lib-caronte-passes-ws-incoming-test.js b/test/lib-http-proxy-passes-ws-incoming-test.js similarity index 100% rename from test/lib-caronte-passes-ws-incoming-test.js rename to test/lib-http-proxy-passes-ws-incoming-test.js diff --git a/test/lib-caronte-test.js b/test/lib-http-proxy-test.js similarity index 100% rename from test/lib-caronte-test.js rename to test/lib-http-proxy-test.js From b333e63648aa67ea1b1aaf17ba684e5fc6f751a6 Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 9 Oct 2013 11:04:41 -0500 Subject: [PATCH 142/556] [tests] fixing minor typos --- lib/http-proxy.js | 2 +- lib/http-proxy/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index f17217864..bcaa36e9e 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -39,6 +39,6 @@ proxy.createProxyServer = proxy.createServer = function createProxyServer(option ].join("\n")); } */ - return new ProxyServer(options); + return new httpProxy.Server(options); }; diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 7528f46e6..1678d1959 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -91,7 +91,7 @@ function ProxyServer(options) { EE3.call(this); this.web = createRightProxy('web')(options); - this.ws = reateRightProxy('ws')(options); + this.ws = createRightProxy('ws')(options); this.options = options; this.passes = Object.keys(passes).map(function(pass) { From a7042132c881656dd32f915d9b0b962f0ef92efb Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 9 Oct 2013 12:00:42 -0500 Subject: [PATCH 143/556] [tests] fixing tests, fixed some typos and changed how passes are stored --- lib/http-proxy/index.js | 27 +++++++++++++-------------- test/lib-http-proxy-test.js | 14 +++++++------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 1678d1959..9776c65d2 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -2,6 +2,8 @@ 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'); @@ -24,16 +26,9 @@ httpProxy.Server = ProxyServer; */ function createRightProxy(type) { - var passes = (type === 'ws') ? ws : web; - return function(options) { - - passes = Object.keys(passes).map(function(pass) { - return passes[pass]; - }); - return function(req, res /*, [head], [opts] */) { - var passes = this.passes || passes, + var passes = (type === 'ws') ? this.wsPasses : this.webPasses, args = [].slice.call(arguments), cntr = args.length - 1, head, cbl; @@ -78,7 +73,7 @@ function createRightProxy(type) { * refer to the connection socket * pass(req, socket, options, head) */ - if(passes[i](req, res, cbl ? this : false, head, cbl)) { // passes can return a truthy value to halt the loop + if(passes[i](req, res, cbl ? false : this, head, cbl)) { // passes can return a truthy value to halt the loop break; } } @@ -94,8 +89,12 @@ function ProxyServer(options) { this.ws = createRightProxy('ws')(options); this.options = options; - this.passes = Object.keys(passes).map(function(pass) { - return passes[pass]; + this.webPasses = Object.keys(web).map(function(pass) { + return web[pass]; + }); + + this.wsPasses = Object.keys(ws).map(function(pass) { + return ws[pass]; }); } @@ -103,11 +102,11 @@ ProxyServer.prototype.listen = function(port) { var self = this, closure = function(req, res) { self.web(req, res); }; - this._server = options.ssl ? + this._server = this.options.ssl ? https.createServer(this.options.ssl, closure) : http.createServer(closure); - if(options.ws) { + if(this.options.ws) { this._server.on('upgrade', function(req, socket, head) { self.ws(req, socket, head); }); } @@ -137,4 +136,4 @@ ProxyServer.prototype.after = function(passName, callback) { this.passes.splice(i++, 0, callback); }; -require('util').inherits(ProxyServer, EE3); +//require('util').inherits(ProxyServer, EE3); diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index b9aa8af7f..dd3136e5e 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -40,7 +40,7 @@ describe('lib/http-proxy.js', function() { expect(req.method).to.eql('GET'); expect(req.headers.host.split(':')[1]).to.eql('8081'); source.close(); - proxy.close(); + proxy._server.close(); done(); }); @@ -61,7 +61,7 @@ describe('lib/http-proxy.js', function() { expect(req.headers['x-forwarded-for']).to.eql('127.0.0.1'); expect(req.headers.host.split(':')[1]).to.eql('8081'); source.close(); - proxy.close(); + proxy._server.close(); done(); }); @@ -106,7 +106,7 @@ describe('lib/http-proxy.js', function() { res.on('end', function () { source.close(); - proxy.close(); + proxy._server.close(); done(); }); }).end(); @@ -122,7 +122,7 @@ describe('lib/http-proxy.js', function() { proxy.ee.on('http-proxy:outgoing:web:error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNREFUSED'); - proxyServer.close(); + proxyServer._server.close(); done(); }) @@ -174,7 +174,7 @@ describe('lib/http-proxy.js', function() { expect(events).to.contain('http-proxy:outgoing:web:begin'); expect(events).to.contain('http-proxy:outgoing:web:end'); source.close(); - proxyServer.close(); + proxyServer._server.close(); done(); }); }).end(); @@ -198,7 +198,7 @@ describe('lib/http-proxy.js', function() { client.on('message', function (msg) { expect(msg).to.be('Hello over websockets'); client.close(); - proxyServer.close(); + proxyServer._server.close(); destiny.close(); done(); }); @@ -229,7 +229,7 @@ describe('lib/http-proxy.js', function() { client.on('outgoing', function (data) { expect(data).to.be('Hello over websockets'); - proxyServer.close(); + proxyServer._server.close(); destiny.server.close(); done(); }); From c65ffbb976467dc1768983dcffe111d18e8f2db1 Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 9 Oct 2013 12:40:05 -0500 Subject: [PATCH 144/556] [tests] fixed inherits problem and listen for the correct event --- lib/http-proxy/index.js | 4 +- test/lib-http-proxy-test.js | 78 ++++++++++++++++++------------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 9776c65d2..17c96cf07 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -98,6 +98,8 @@ function ProxyServer(options) { }); } +require('util').inherits(ProxyServer, EE3); + ProxyServer.prototype.listen = function(port) { var self = this, closure = function(req, res) { self.web(req, res); }; @@ -135,5 +137,3 @@ ProxyServer.prototype.after = function(passName, callback) { this.passes.splice(i++, 0, callback); }; - -//require('util').inherits(ProxyServer, EE3); diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index dd3136e5e..9bb882d9b 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -119,7 +119,7 @@ describe('lib/http-proxy.js', function() { target: 'http://127.0.0.1:8080' }); - proxy.ee.on('http-proxy:outgoing:web:error', function (err) { + proxy.on('error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNREFUSED'); proxyServer._server.close(); @@ -136,50 +136,50 @@ describe('lib/http-proxy.js', function() { }); }); - 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' - }), + // 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'), + // 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); - }), + // 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 = []; + // events = []; - source.listen('8080'); + // source.listen('8080'); - proxy.ee.on('http-proxy:**', function (uno, dos, tres) { - events.push(this.event); - }) + // 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(); - }); - }); + // 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) { From 86750c7e594c419dfae957aaf7e44e61e1d480e8 Mon Sep 17 00:00:00 2001 From: cronopio Date: Thu, 10 Oct 2013 11:04:17 -0500 Subject: [PATCH 145/556] [tests] throw error when no options, ALL TESTS PASSING! YAY --- lib/http-proxy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index bcaa36e9e..24efb4687 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -20,7 +20,7 @@ var http = require('http'), */ proxy.createProxyServer = proxy.createServer = function createProxyServer(options) { - /* if(!options) { + if(!options) { throw new Error([ "`options` is needed and it must have the following layout:", " ", @@ -37,7 +37,7 @@ proxy.createProxyServer = proxy.createServer = function createProxyServer(option " `options.target and `options.forward` cannot be ", " both missing " ].join("\n")); - } */ + } return new httpProxy.Server(options); }; From bbe2b2788a7ee3c74fd44fe88b6dcf213264436f Mon Sep 17 00:00:00 2001 From: James Manning Date: Sat, 19 Oct 2013 23:43:22 -0400 Subject: [PATCH 146/556] attempting to fix link to valid options properties Current link for 'valid properties are available here' goes to url: https://github.com/nodejitsu/node-http-proxy/blob/caronte/tree/master/lib/http-proxy.js#L26-L39 The url works fine if 'tree/master/' is removed, so this is trying to remove that part of the relative path. The same removal of 'tree/master/' is being made for the 'available here' link that is preceded by "When a request is proxied it follows two different pipelines" since it suffers the same issue. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c44fcd6d7..344d6c32c 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ proxies and load balancers. ### Core Concept A new proxy is created by calling `createProxyServer` and passing -an `options` object as argument ([valid properties are available here](tree/master/lib/http-proxy.js#L26-L39)) +an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L26-L39)) ```javascript var httpProxy = require('http-proxy'); @@ -44,7 +44,7 @@ require('http').createServer(function(req, res) { }); ``` -When a request is proxied it follows two different pipelines ([available here](tree/master/lib/http-proxy/passes)) +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 From 1d1ee8858283d7c8984f1c1d6c5185b6822f9235 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 03:25:47 -0500 Subject: [PATCH 147/556] [tests] the options got a problem and this test probe that timeout is not being set --- test/lib-http-proxy-test.js | 38 ++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 9bb882d9b..73ee11345 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -126,7 +126,7 @@ describe('lib/http-proxy.js', function() { done(); }) - var proxyServer = proxy.listen('8081'); + proxy.listen('8081'); http.request({ hostname: '127.0.0.1', @@ -136,6 +136,38 @@ describe('lib/http-proxy.js', function() { }); }); + describe('#createProxyServer setting the correct timeout value', function () { + it('should hang up the socket at the timeout', function (done) { + this.timeout(30); + var proxy = httpProxy.createProxyServer({ + target: 'http://127.0.0.1:8080', + timeout: 3 + }).listen('8081'); + + var source = http.createServer(function(req, res) { + setTimeout(function () { + res.end('At this point the socket should be closed'); + }, 5) + }); + + source.listen('8080'); + + var testReq = http.request({ + hostname: '127.0.0.1', + port: '8081', + method: 'GET', + }, function() {}); + + testReq.on('error', function (e) { + expect(e).to.be.an(Error); + expect(e.code).to.be.eql('ECONNRESET'); + done(); + }); + + testReq.end(); + }) + }) + // describe('#createProxyServer using the web-incoming passes', function () { // it('should emit events correclty', function(done) { // var proxy = httpProxy.createProxyServer({ @@ -244,3 +276,7 @@ describe('lib/http-proxy.js', function() { }); }) }); + +describe('#createProxyServer using the ws-incoming passes', function () { + it('should call the callback with the error'); +}) \ No newline at end of file From 90fb01d38ac5af7ef395547b24e985b6f63b4abc Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 03:26:54 -0500 Subject: [PATCH 148/556] [fix] fixed options and server reference to can access them from passes functions --- lib/http-proxy/index.js | 2 +- lib/http-proxy/passes/web-incoming.js | 31 ++++++++++++++++----------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 17c96cf07..ba3425eca 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -73,7 +73,7 @@ function createRightProxy(type) { * refer to the connection socket * pass(req, socket, options, head) */ - if(passes[i](req, res, cbl ? false : this, head, cbl)) { // passes can return a truthy value to halt the loop + if(passes[i].call(this, req, res, head, cbl)) { // passes can return a truthy value to halt the loop break; } } diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index b8f936d51..03725710f 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -23,12 +23,13 @@ web_o = Object.keys(web_o).map(function(pass) { * * @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) { + function deleteLength(req, res) { + // Now the options are stored on this + var options = this.options; if(req.method === 'DELETE' && !req.headers['content-length']) { req.headers['content-length'] = '0'; } @@ -39,12 +40,13 @@ web_o = Object.keys(web_o).map(function(pass) { * * @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) { + function timeout(req, res) { + // Now the options are stored on this + var options = this.options; if(options.timeout) { req.socket.setTimeout(options.timeout); } @@ -55,12 +57,13 @@ web_o = Object.keys(web_o).map(function(pass) { * * @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) { + function XHeaders(req, res) { + // Now the options are stored on this + var options = this.options; if(!options.xfwd) return; var values = { @@ -84,24 +87,26 @@ web_o = Object.keys(web_o).map(function(pass) { * * @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, server, _, clb) { - if(server.options.forward) { + function stream(req, res, head, clb) { + var server = this; + // Now the options are stored on this + var options = this.options; + if(options.forward) { // If forward enable, so just pipe the request - var forwardReq = (server.options.forward.protocol === 'https:' ? https : http).request( - common.setupOutgoing(server.options.ssl || {}, server.options, req, 'forward') + var forwardReq = (options.forward.protocol === 'https:' ? https : http).request( + common.setupOutgoing(options.ssl || {}, options, req, 'forward') ); req.pipe(forwardReq); return res.end(); } // Request initalization - var proxyReq = (server.options.target.protocol === 'https:' ? https : http).request( - common.setupOutgoing(server.options.ssl || {}, server.options, req) + var proxyReq = (options.target.protocol === 'https:' ? https : http).request( + common.setupOutgoing(options.ssl || {}, options, req) ); // Error Handler From 9b3e1eb247df29d18ea299ff4ebb2f10eeb71269 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 03:46:30 -0500 Subject: [PATCH 149/556] [fix] fixed passes functions, now 'this' can be used and options are stored on 'this.options' --- lib/http-proxy/passes/ws-incoming.js | 9 +++++---- test/lib-http-proxy-test.js | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 66c75d506..3e715c902 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -64,12 +64,13 @@ var passes = exports; * * @param {ClientRequest} Req Request object * @param {Socket} Websocket - * @param {Object} Options Config object passed to the proxy * * @api private */ - function XHeaders(req, socket, options) { + function XHeaders(req, socket) { + // Now the options are stored on this + var options = this.options; if(!options.xfwd) return; var values = { @@ -92,11 +93,11 @@ var passes = exports; * * @param {ClientRequest} Req Request object * @param {Socket} Websocket - * @param {Object} Options Config object passed to the proxy * * @api private */ - function stream(req, socket, server, head, clb) { + function stream(req, socket, head, clb) { + var server = this; common.setupSocket(socket); if (head && head.length) socket.unshift(head); diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 73ee11345..a74276e82 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -122,7 +122,7 @@ describe('lib/http-proxy.js', function() { proxy.on('error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNREFUSED'); - proxyServer._server.close(); + proxy._server.close(); done(); }) @@ -148,9 +148,7 @@ describe('lib/http-proxy.js', function() { setTimeout(function () { res.end('At this point the socket should be closed'); }, 5) - }); - - source.listen('8080'); + }).listen('8080'); var testReq = http.request({ hostname: '127.0.0.1', @@ -161,6 +159,8 @@ describe('lib/http-proxy.js', 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(); }); From 52ecd52ee5aa78603e44ba8d5ff9187410351622 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 03:59:14 -0500 Subject: [PATCH 150/556] [tests] fix test to use the new way to pass options --- lib/http-proxy/passes/web-incoming.js | 2 -- test/lib-http-proxy-passes-web-incoming-test.js | 6 +++--- test/lib-http-proxy-passes-ws-incoming-test.js | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 03725710f..ca74bfff1 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -28,8 +28,6 @@ web_o = Object.keys(web_o).map(function(pass) { */ function deleteLength(req, res) { - // Now the options are stored on this - var options = this.options; if(req.method === 'DELETE' && !req.headers['content-length']) { req.headers['content-length'] = '0'; } diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 4269d5f8b..cd2bacd85 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -8,7 +8,7 @@ describe('lib/http-proxy/passes/web.js', function() { method: 'DELETE', headers: {} }; - httpProxy.deleteLength(stubRequest, {}, {}); + httpProxy.deleteLength(stubRequest, {}); expect(stubRequest.headers['content-length']).to.eql('0'); }) }); @@ -21,7 +21,7 @@ describe('lib/http-proxy/passes/web.js', function() { } } - httpProxy.timeout(stubRequest, {}, { timeout: 5000}); + httpProxy.timeout.call({ options: { timeout: 5000 }}, stubRequest, {}); expect(done).to.eql(5000); }); }); @@ -36,7 +36,7 @@ describe('lib/http-proxy/passes/web.js', function() { } it('set the correct x-forwarded-* headers', function () { - httpProxy.XHeaders(stubRequest, {}, { xfwd: true }); + httpProxy.XHeaders.call({ options: { xfwd: true }}, stubRequest, {}); 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'); diff --git a/test/lib-http-proxy-passes-ws-incoming-test.js b/test/lib-http-proxy-passes-ws-incoming-test.js index 87dfcef94..ee61234c6 100644 --- a/test/lib-http-proxy-passes-ws-incoming-test.js +++ b/test/lib-http-proxy-passes-ws-incoming-test.js @@ -107,7 +107,7 @@ describe('lib/http-proxy/passes/ws-incoming.js', function () { describe('#XHeaders', function () { it('return if no forward request', function () { - var returnValue = httpProxy.XHeaders({}, {}, {}); + var returnValue = httpProxy.XHeaders.call({ options: {}}, {}, {}); expect(returnValue).to.be(undefined); }); @@ -119,7 +119,7 @@ describe('lib/http-proxy/passes/ws-incoming.js', function () { }, headers: {} } - httpProxy.XHeaders(stubRequest, {}, { xfwd: true }); + httpProxy.XHeaders.call({ options: { xfwd: true }}, stubRequest, {}); 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'); @@ -136,7 +136,7 @@ describe('lib/http-proxy/passes/ws-incoming.js', function () { }, headers: {} }; - httpProxy.XHeaders(stubRequest, {}, { xfwd: true }); + httpProxy.XHeaders.call({ options: { xfwd: true }}, stubRequest, {}); 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'); From 2bf20d61d53201e9820c5f9215e641fcf88f5172 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 14:44:49 -0500 Subject: [PATCH 151/556] Revert "[tests] fix test to use the new way to pass options" This reverts commit 52ecd52ee5aa78603e44ba8d5ff9187410351622. --- lib/http-proxy/passes/web-incoming.js | 2 ++ test/lib-http-proxy-passes-web-incoming-test.js | 6 +++--- test/lib-http-proxy-passes-ws-incoming-test.js | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index ca74bfff1..03725710f 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -28,6 +28,8 @@ web_o = Object.keys(web_o).map(function(pass) { */ function deleteLength(req, res) { + // Now the options are stored on this + var options = this.options; if(req.method === 'DELETE' && !req.headers['content-length']) { req.headers['content-length'] = '0'; } diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index cd2bacd85..4269d5f8b 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -8,7 +8,7 @@ describe('lib/http-proxy/passes/web.js', function() { method: 'DELETE', headers: {} }; - httpProxy.deleteLength(stubRequest, {}); + httpProxy.deleteLength(stubRequest, {}, {}); expect(stubRequest.headers['content-length']).to.eql('0'); }) }); @@ -21,7 +21,7 @@ describe('lib/http-proxy/passes/web.js', function() { } } - httpProxy.timeout.call({ options: { timeout: 5000 }}, stubRequest, {}); + httpProxy.timeout(stubRequest, {}, { timeout: 5000}); expect(done).to.eql(5000); }); }); @@ -36,7 +36,7 @@ describe('lib/http-proxy/passes/web.js', function() { } it('set the correct x-forwarded-* headers', function () { - httpProxy.XHeaders.call({ options: { xfwd: true }}, stubRequest, {}); + 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('http'); diff --git a/test/lib-http-proxy-passes-ws-incoming-test.js b/test/lib-http-proxy-passes-ws-incoming-test.js index ee61234c6..87dfcef94 100644 --- a/test/lib-http-proxy-passes-ws-incoming-test.js +++ b/test/lib-http-proxy-passes-ws-incoming-test.js @@ -107,7 +107,7 @@ describe('lib/http-proxy/passes/ws-incoming.js', function () { describe('#XHeaders', function () { it('return if no forward request', function () { - var returnValue = httpProxy.XHeaders.call({ options: {}}, {}, {}); + var returnValue = httpProxy.XHeaders({}, {}, {}); expect(returnValue).to.be(undefined); }); @@ -119,7 +119,7 @@ describe('lib/http-proxy/passes/ws-incoming.js', function () { }, headers: {} } - httpProxy.XHeaders.call({ options: { xfwd: true }}, stubRequest, {}); + 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'); @@ -136,7 +136,7 @@ describe('lib/http-proxy/passes/ws-incoming.js', function () { }, headers: {} }; - httpProxy.XHeaders.call({ options: { xfwd: true }}, stubRequest, {}); + 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'); From babdf531fecd32f9af0963902909fcfa2cd374f1 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 14:45:03 -0500 Subject: [PATCH 152/556] Revert "[fix] fixed options and server reference to can access them from passes functions" This reverts commit 90fb01d38ac5af7ef395547b24e985b6f63b4abc. --- lib/http-proxy/index.js | 2 +- lib/http-proxy/passes/web-incoming.js | 31 +++++++++++---------------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index ba3425eca..17c96cf07 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -73,7 +73,7 @@ function createRightProxy(type) { * refer to the connection socket * pass(req, socket, options, head) */ - if(passes[i].call(this, req, res, head, cbl)) { // passes can return a truthy value to halt the loop + if(passes[i](req, res, cbl ? false : this, head, cbl)) { // passes can return a truthy value to halt the loop break; } } diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 03725710f..b8f936d51 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -23,13 +23,12 @@ web_o = Object.keys(web_o).map(function(pass) { * * @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) { - // Now the options are stored on this - var options = this.options; + function deleteLength(req, res, options) { if(req.method === 'DELETE' && !req.headers['content-length']) { req.headers['content-length'] = '0'; } @@ -40,13 +39,12 @@ web_o = Object.keys(web_o).map(function(pass) { * * @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) { - // Now the options are stored on this - var options = this.options; + function timeout(req, res, options) { if(options.timeout) { req.socket.setTimeout(options.timeout); } @@ -57,13 +55,12 @@ web_o = Object.keys(web_o).map(function(pass) { * * @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) { - // Now the options are stored on this - var options = this.options; + function XHeaders(req, res, options) { if(!options.xfwd) return; var values = { @@ -87,26 +84,24 @@ web_o = Object.keys(web_o).map(function(pass) { * * @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, head, clb) { - var server = this; - // Now the options are stored on this - var options = this.options; - if(options.forward) { + function stream(req, res, server, _, clb) { + if(server.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') + var forwardReq = (server.options.forward.protocol === 'https:' ? https : http).request( + common.setupOutgoing(server.options.ssl || {}, server.options, req, 'forward') ); req.pipe(forwardReq); return res.end(); } // Request initalization - var proxyReq = (options.target.protocol === 'https:' ? https : http).request( - common.setupOutgoing(options.ssl || {}, options, req) + var proxyReq = (server.options.target.protocol === 'https:' ? https : http).request( + common.setupOutgoing(server.options.ssl || {}, server.options, req) ); // Error Handler From 5e130de8548ad41b821da49299b4fd1c9536c5f0 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 14:49:39 -0500 Subject: [PATCH 153/556] Revert "[fix] fixed passes functions, now 'this' can be used and options are stored on 'this.options'" This reverts commit 9b3e1eb247df29d18ea299ff4ebb2f10eeb71269. --- lib/http-proxy/passes/ws-incoming.js | 9 ++++----- test/lib-http-proxy-test.js | 8 ++++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 3e715c902..66c75d506 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -64,13 +64,12 @@ var passes = exports; * * @param {ClientRequest} Req Request object * @param {Socket} Websocket + * @param {Object} Options Config object passed to the proxy * * @api private */ - function XHeaders(req, socket) { - // Now the options are stored on this - var options = this.options; + function XHeaders(req, socket, options) { if(!options.xfwd) return; var values = { @@ -93,11 +92,11 @@ var passes = exports; * * @param {ClientRequest} Req Request object * @param {Socket} Websocket + * @param {Object} Options Config object passed to the proxy * * @api private */ - function stream(req, socket, head, clb) { - var server = this; + function stream(req, socket, server, head, clb) { common.setupSocket(socket); if (head && head.length) socket.unshift(head); diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index a74276e82..73ee11345 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -122,7 +122,7 @@ describe('lib/http-proxy.js', function() { proxy.on('error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNREFUSED'); - proxy._server.close(); + proxyServer._server.close(); done(); }) @@ -148,7 +148,9 @@ describe('lib/http-proxy.js', function() { setTimeout(function () { res.end('At this point the socket should be closed'); }, 5) - }).listen('8080'); + }); + + source.listen('8080'); var testReq = http.request({ hostname: '127.0.0.1', @@ -159,8 +161,6 @@ describe('lib/http-proxy.js', 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(); }); From 5d66ce11bb7eef7e704a2de2c0ef3b5f754843e9 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 14:51:45 -0500 Subject: [PATCH 154/556] [fix] minor typo --- test/lib-http-proxy-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 73ee11345..c592728d1 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -122,7 +122,7 @@ describe('lib/http-proxy.js', function() { proxy.on('error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNREFUSED'); - proxyServer._server.close(); + proxy._server.close(); done(); }) From 0bfb9be418926f2113489e92504038127d4c04bb Mon Sep 17 00:00:00 2001 From: mmoulton Date: Mon, 21 Oct 2013 10:05:06 -0700 Subject: [PATCH 155/556] Fixed issue where error callback would not invoke, including new test cases. Added req/res values to error events. Conflicts: lib/http-proxy/passes/web-incoming.js --- lib/http-proxy/passes/web-incoming.js | 9 ++- test/lib-http-proxy-integration-test.js | 92 +++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 test/lib-http-proxy-integration-test.js diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index b8f936d51..eceb1636e 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -106,11 +106,10 @@ web_o = Object.keys(web_o).map(function(pass) { // Error Handler proxyReq.on('error', function(err){ - if(server) { - server.emit('error', err); - } - else {  - clb(err); + if (clb) { + clb(err); + } else { + server.emit('error', err, req, res); } }); diff --git a/test/lib-http-proxy-integration-test.js b/test/lib-http-proxy-integration-test.js new file mode 100644 index 000000000..f6ea70693 --- /dev/null +++ b/test/lib-http-proxy-integration-test.js @@ -0,0 +1,92 @@ +var httpProxy = require('../lib/http-proxy'), + expect = require('expect.js'), + http = require('http'); + + +describe('lib/http-proxy.js', function() { + + describe('#createProxyServer with target options for integration into existing 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('8082'); + done(); + }); + + proxyServer.listen('8082'); + source.listen('8080'); + + http.request('http://127.0.0.1:8082', function() {}).end(); + }); + }); + + describe('#createProxyServer() for integration into existing server with error response', function () { + 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 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('8082'); + + http.request({ + hostname: '127.0.0.1', + port: '8082', + method: 'GET', + }, function() {}).end(); + }); + + }); + +}); \ No newline at end of file From 7c72f3b407a084a896e420c23ababc3e9357feca Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 21:11:19 -0500 Subject: [PATCH 156/556] [tests] move contributions of @mmoulton to correct place --- ...lib-http-proxy-passes-web-incoming-test.js | 93 ++++++++++++++++++- 1 file changed, 88 insertions(+), 5 deletions(-) diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 4269d5f8b..19fa669b7 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -1,5 +1,7 @@ -var httpProxy = require('../lib/http-proxy/passes/web-incoming'), - expect = require('expect.js'); +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() { @@ -8,7 +10,7 @@ describe('lib/http-proxy/passes/web.js', function() { method: 'DELETE', headers: {} }; - httpProxy.deleteLength(stubRequest, {}, {}); + webPasses.deleteLength(stubRequest, {}, {}); expect(stubRequest.headers['content-length']).to.eql('0'); }) }); @@ -21,7 +23,7 @@ describe('lib/http-proxy/passes/web.js', function() { } } - httpProxy.timeout(stubRequest, {}, { timeout: 5000}); + webPasses.timeout(stubRequest, {}, { timeout: 5000}); expect(done).to.eql(5000); }); }); @@ -36,10 +38,91 @@ describe('lib/http-proxy/passes/web.js', function() { } it('set the correct x-forwarded-* headers', function () { - httpProxy.XHeaders(stubRequest, {}, { xfwd: true }); + 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('8081'); + + http.request({ + hostname: '127.0.0.1', + port: '8081', + 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('8081'); + + http.request({ + hostname: '127.0.0.1', + port: '8081', + method: 'GET', + }, function() {}).end(); + }); +}); \ No newline at end of file From cc09ae6a345cfde1689e1d8731c5822675c59d4d Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 21:19:29 -0500 Subject: [PATCH 157/556] [fix] use the correct arguments order --- lib/http-proxy/index.js | 2 +- lib/http-proxy/passes/web-incoming.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 17c96cf07..7861503dc 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -73,7 +73,7 @@ function createRightProxy(type) { * refer to the connection socket * pass(req, socket, options, head) */ - if(passes[i](req, res, cbl ? false : this, head, cbl)) { // passes can return a truthy value to halt the loop + if(passes[i](req, res, this.options, head, cbl ? false : this, cbl)) { // passes can return a truthy value to halt the loop break; } } diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index eceb1636e..a3516aba1 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -89,19 +89,19 @@ web_o = Object.keys(web_o).map(function(pass) { * @api private */ - function stream(req, res, server, _, clb) { - if(server.options.forward) { + function stream(req, res, options, head, server, clb) { + if(options.forward) { // If forward enable, so just pipe the request - var forwardReq = (server.options.forward.protocol === 'https:' ? https : http).request( - common.setupOutgoing(server.options.ssl || {}, server.options, req, 'forward') + var forwardReq = (options.forward.protocol === 'https:' ? https : http).request( + common.setupOutgoing(options.ssl || {}, options, req, 'forward') ); req.pipe(forwardReq); return res.end(); } // Request initalization - var proxyReq = (server.options.target.protocol === 'https:' ? https : http).request( - common.setupOutgoing(server.options.ssl || {}, server.options, req) + var proxyReq = (options.target.protocol === 'https:' ? https : http).request( + common.setupOutgoing(options.ssl || {}, options, req) ); // Error Handler From 881c7e62e0bef7b4b9f81b6fd121f7ad6641bd77 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 21:22:39 -0500 Subject: [PATCH 158/556] [tests] this file is not necessary anymore --- test/lib-http-proxy-integration-test.js | 92 ------------------------- 1 file changed, 92 deletions(-) delete mode 100644 test/lib-http-proxy-integration-test.js diff --git a/test/lib-http-proxy-integration-test.js b/test/lib-http-proxy-integration-test.js deleted file mode 100644 index f6ea70693..000000000 --- a/test/lib-http-proxy-integration-test.js +++ /dev/null @@ -1,92 +0,0 @@ -var httpProxy = require('../lib/http-proxy'), - expect = require('expect.js'), - http = require('http'); - - -describe('lib/http-proxy.js', function() { - - describe('#createProxyServer with target options for integration into existing 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('8082'); - done(); - }); - - proxyServer.listen('8082'); - source.listen('8080'); - - http.request('http://127.0.0.1:8082', function() {}).end(); - }); - }); - - describe('#createProxyServer() for integration into existing server with error response', function () { - 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 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('8082'); - - http.request({ - hostname: '127.0.0.1', - port: '8082', - method: 'GET', - }, function() {}).end(); - }); - - }); - -}); \ No newline at end of file From 02df9a33c5cce17ea32a892017acbe5ce57ab2e5 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 23:22:32 -0500 Subject: [PATCH 159/556] [fix] fix the correct order of arguments in ws-incoming passes --- lib/http-proxy/passes/ws-incoming.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 66c75d506..ebdbe2ab0 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -96,22 +96,21 @@ var passes = exports; * * @api private */ - function stream(req, socket, server, head, clb) { + function stream(req, socket, options, server, head, clb) { common.setupSocket(socket); if (head && head.length) socket.unshift(head); - var proxyReq = (~['https:', 'wss:'].indexOf(server.options.target.protocol) ? https : http).request( - common.setupOutgoing(server.options.ssl || {}, server.options, req) + var proxyReq = (~['https:', 'wss:'].indexOf(options.target.protocol) ? https : http).request( + common.setupOutgoing(options.ssl || {}, options, req) ); // Error Handler proxyReq.on('error', function(err){ - if(server) { - server.emit('error', err); - } - else { + if (clb) { clb(err); + } else { + server.emit('error', err, req, res); } }); From d60353f80bbbcba128a2c51066e107365270e878 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 21 Oct 2013 23:22:59 -0500 Subject: [PATCH 160/556] [tests] tests fixed --- test/lib-http-proxy-test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index c592728d1..cc772b863 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -161,6 +161,8 @@ describe('lib/http-proxy.js', 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(); }); From c75d06c5f92eb7c814deb49bb33cf9fffc632d97 Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 22 Oct 2013 15:57:52 -0500 Subject: [PATCH 161/556] [tests] now each test use a different port to avoid some slow opening and closing ports --- test/lib-http-proxy-test.js | 83 ++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index cc772b863..83e8c5d6f 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -5,6 +5,17 @@ var httpProxy = require('../lib/http-proxy'), 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() { @@ -32,44 +43,45 @@ describe('lib/http-proxy.js', 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:8080' - }).listen('8081') + 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('8081'); + expect(req.headers.host.split(':')[1]).to.eql(ports.proxy); source.close(); proxy._server.close(); done(); }); - source.listen('8080'); - - http.request('http://127.0.0.1:8081', function() {}).end(); + 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:8080' - }).listen('8081'); + 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('8081'); + expect(req.headers.host.split(':')[1]).to.eql(ports.proxy); source.close(); proxy._server.close(); done(); }); - source.listen('8080'); + source.listen(ports.source); http.request({ hostname: '127.0.0.1', - port: '8081', + port: ports.proxy, method: 'POST', headers: { 'x-forwarded-for': '127.0.0.1' @@ -80,28 +92,29 @@ describe('lib/http-proxy.js', function() { 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:8080' - }).listen('8081'); + 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('8081'); + 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('8080'); + source.listen(ports.source); http.request({ hostname: '127.0.0.1', - port: '8081', - method: 'GET', + 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 8080'); + expect(data.toString()).to.eql('Hello from ' + ports.source); }); res.on('end', function () { @@ -115,8 +128,9 @@ describe('lib/http-proxy.js', function() { 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:8080' + target: 'http://127.0.0.1:' + ports.source }); proxy.on('error', function (err) { @@ -126,11 +140,11 @@ describe('lib/http-proxy.js', function() { done(); }) - proxy.listen('8081'); + proxy.listen(ports.proxy); http.request({ hostname: '127.0.0.1', - port: '8081', + port: ports.proxy, method: 'GET', }, function() {}).end(); }); @@ -139,10 +153,11 @@ describe('lib/http-proxy.js', function() { 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:8080', + target: 'http://127.0.0.1:' + ports.source, timeout: 3 - }).listen('8081'); + }).listen(ports.proxy); var source = http.createServer(function(req, res) { setTimeout(function () { @@ -150,11 +165,11 @@ describe('lib/http-proxy.js', function() { }, 5) }); - source.listen('8080'); + source.listen(ports.source); var testReq = http.request({ hostname: '127.0.0.1', - port: '8081', + port: ports.proxy, method: 'GET', }, function() {}); @@ -217,13 +232,14 @@ describe('lib/http-proxy.js', function() { 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:8080', + target: 'ws://127.0.0.1:' + ports.source, ws: true }), - proxyServer = proxy.listen('8081'), - destiny = new ws.Server({ port: 8080 }, function () { - var client = new ws('ws://127.0.0.1:8081'); + 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'); @@ -249,13 +265,14 @@ describe('lib/http-proxy.js', function() { describe('#createProxyServer using the ws-incoming passes', function () { 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:8080', + target: 'ws://127.0.0.1:' + ports.source, ws: true }), - proxyServer = proxy.listen('8081'), - destiny = io.listen(8080, function () { - var client = ioClient.connect('ws://127.0.0.1:8081'); + 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'); From 920f1e7707aa1751577533cd368529f8a704d7af Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 22 Oct 2013 16:09:11 -0500 Subject: [PATCH 162/556] [tests] this test is already in web-incoming tests --- test/lib-http-proxy-test.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 83e8c5d6f..26f9d34b5 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -294,8 +294,4 @@ describe('lib/http-proxy.js', function() { }) }); }) -}); - -describe('#createProxyServer using the ws-incoming passes', function () { - it('should call the callback with the error'); -}) \ No newline at end of file +}); \ No newline at end of file From a1b25a123b4ff71e731f9beb27c5e078acfead65 Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 22 Oct 2013 17:04:18 -0500 Subject: [PATCH 163/556] [examples] update the error-handling example using the new error handle way --- examples/error-handling.js | 43 ++++++++++++++++++++++---------------- examples/stand-alone.js | 2 +- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/examples/error-handling.js b/examples/error-handling.js index f646a8de4..76a09d955 100644 --- a/examples/error-handling.js +++ b/examples/error-handling.js @@ -1,26 +1,33 @@ -var httpProxy = require('../index'); +var httpProxy = require('../lib/http-proxy'), + http = require('http'); /* * Create your proxy server */ -var proxyServer = httpProxy.createProxyServer({target:'http://localhost:30404', ws:true}); +var proxy = httpProxy.createProxyServer({target:'http://localhost:30404', ws:true}); -// Register an error handler for web requests -proxyServer.ee.on("http-proxy:outgoing:web:error", function(err, req, res){ - res.writeHead(502); - res.end("There was an error proxying your request"); -}); +var proxyServer = http.createServer(requestHandler); -// Register an error handler for web-socket requests -proxyServer.ee.on("http-proxy:outgoing:ws:error", function(err, req, socket, head){ - socket.close(); -}); - -// You may also use a wild card -proxyServer.ee.on("*:*:*:error", function(err, req){ - console.log("The error event '" + this.event + "' happened errno: " + err.errno); -}); +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(); + }) + }) +} console.log("Proxy server is listening on port 8000"); -proxyServer.listen(8000); - +proxyServer.listen(8000) \ No newline at end of file diff --git a/examples/stand-alone.js b/examples/stand-alone.js index 3bf6ddccf..e5239c460 100644 --- a/examples/stand-alone.js +++ b/examples/stand-alone.js @@ -1,5 +1,5 @@ var http = require('http'), - httpProxy = require('http-proxy'); + httpProxy = require('../lib/http-proxy'); // // Create your proxy server // From e3f8d5fdbe1ebc4f04188d95bbef768d09718d2c Mon Sep 17 00:00:00 2001 From: yawnt Date: Sat, 26 Oct 2013 17:20:30 +0200 Subject: [PATCH 164/556] [feature] add buffer support --- lib/http-proxy/passes/web-incoming.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index a3516aba1..97329348a 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -106,6 +106,7 @@ web_o = Object.keys(web_o).map(function(pass) { // Error Handler proxyReq.on('error', function(err){ + if(options.buffer) { options.buffer.destroy(); } if (clb) { clb(err); } else { @@ -123,6 +124,10 @@ web_o = Object.keys(web_o).map(function(pass) { proxyRes.pipe(res); }); + if(options.buffer) { + options.buffer.resume(); + } + //proxyReq.end(); } From 33a2462d28c7d1fa26b03bcf290242ff7cd83e7a Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 28 Oct 2013 13:18:21 -0500 Subject: [PATCH 165/556] [wip] Initial HTTPS->HTTP test, updated https-secure example. Work in progress, need to add more https tests --- examples/https-secure.js | 2 +- test/fixtures/agent2-cert.pem | 13 +++++++ test/fixtures/agent2-csr.pem | 10 ++++++ test/fixtures/agent2-key.pem | 9 +++++ test/fixtures/agent2.cnf | 19 ++++++++++ test/lib-https-proxy-test.js | 65 +++++++++++++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/agent2-cert.pem create mode 100644 test/fixtures/agent2-csr.pem create mode 100644 test/fixtures/agent2-key.pem create mode 100644 test/fixtures/agent2.cnf create mode 100644 test/lib-https-proxy-test.js diff --git a/examples/https-secure.js b/examples/https-secure.js index 4ddbe8d23..72bcbb625 100644 --- a/examples/https-secure.js +++ b/examples/https-secure.js @@ -1,4 +1,4 @@ -var httpProxy = require('http-proxy'), +var httpProxy = require('../lib/http-proxy'), https = require('https'); /* * Create your proxy server pointing to a secure domain diff --git a/test/fixtures/agent2-cert.pem b/test/fixtures/agent2-cert.pem new file mode 100644 index 000000000..8e4354db4 --- /dev/null +++ b/test/fixtures/agent2-cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB7DCCAZYCCQC7gs0MDNn6MTANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJV +UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO +BgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEgMB4GCSqGSIb3DQEJARYR +cnlAdGlueWNsb3Vkcy5vcmcwHhcNMTEwMzE0MTgyOTEyWhcNMzgwNzI5MTgyOTEy +WjB9MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYD +VQQKEwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEg +MB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwXDANBgkqhkiG9w0BAQEF +AANLADBIAkEAyXb8FrRdKbhrKLgLSsn61i1C7w7fVVVd7OQsmV/7p9WB2lWFiDlC +WKGU9SiIz/A6wNZDUAuc2E+VwtpCT561AQIDAQABMA0GCSqGSIb3DQEBBQUAA0EA +C8HzpuNhFLCI3A5KkBS5zHAQax6TFUOhbpBCR0aTDbJ6F1liDTK1lmU/BjvPoj+9 +1LHwrmh29rK8kBPEjmymCQ== +-----END CERTIFICATE----- diff --git a/test/fixtures/agent2-csr.pem b/test/fixtures/agent2-csr.pem new file mode 100644 index 000000000..a670c4c63 --- /dev/null +++ b/test/fixtures/agent2-csr.pem @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIBXTCCAQcCAQAwfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQH +EwJTRjEPMA0GA1UEChMGSm95ZW50MRAwDgYDVQQLEwdOb2RlLmpzMQ8wDQYDVQQD +EwZhZ2VudDIxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMFwwDQYJ +KoZIhvcNAQEBBQADSwAwSAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf ++6fVgdpVhYg5QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAaAlMCMGCSqG +SIb3DQEJBzEWExRBIGNoYWxsZW5nZSBwYXNzd29yZDANBgkqhkiG9w0BAQUFAANB +AJnll2pt5l0pzskQSpjjLVTlFDFmJr/AZ3UK8v0WxBjYjCe5Jx4YehkChpxIyDUm +U3J9q9MDUf0+Y2+EGkssFfk= +-----END CERTIFICATE REQUEST----- diff --git a/test/fixtures/agent2-key.pem b/test/fixtures/agent2-key.pem new file mode 100644 index 000000000..522903c63 --- /dev/null +++ b/test/fixtures/agent2-key.pem @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBOgIBAAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf+6fVgdpVhYg5 +QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAQJBAMT6Bf34+UHKY1ObpsbH +9u2jsVblFq1rWvs8GPMY6oertzvwm3DpuSUp7PTgOB1nLTLYtCERbQ4ovtN8tn3p +OHUCIQDzIEGsoCr5vlxXvy2zJwu+fxYuhTZWMVuo1397L0VyhwIhANQh+yzqUgaf +WRtSB4T2W7ADtJI35ET61jKBty3CqJY3AiAIwju7dVW3A5WeD6Qc1SZGKZvp9yCb +AFI2BfVwwaY11wIgXF3PeGcvACMyMWsuSv7aPXHfliswAbkWuzcwA4TW01ECIGWa +cgsDvVFxmfM5NPSuT/UDTa6R5BFISB5ea0N0AR3I +-----END RSA PRIVATE KEY----- diff --git a/test/fixtures/agent2.cnf b/test/fixtures/agent2.cnf new file mode 100644 index 000000000..0a9f2c737 --- /dev/null +++ b/test/fixtures/agent2.cnf @@ -0,0 +1,19 @@ +[ 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 + diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js new file mode 100644 index 000000000..6a544bf4d --- /dev/null +++ b/test/lib-https-proxy-test.js @@ -0,0 +1,65 @@ +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('#createProxyServer using HTTPS', 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) { + console.log('Request:', req.headers); + 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({ + forward: '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); + + var req = https.request({ + host: 'localhost', + port: ports.proxy, + path: '/', + method: 'GET', + localAddress: '127.0.0.1', + rejectUnauthorized: false + }, function(res) { + console.log(res); + res.on('data', function (ch) { + console.log('Chunks', ch) + }) + console.log('Response:', res.statusCode); + source.close(); + proxy._server.close(); + done(); + }); + + req.on('error', function (err) { console.log('Erroring', err); }); + req.end(); + }) + }) + }); +}); \ No newline at end of file From 1204a35e467c6c1855ba0dac8f55d79f899148a6 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 29 Oct 2013 18:12:23 +0100 Subject: [PATCH 166/556] [fix] support buffer --- lib/http-proxy/passes/web-incoming.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 97329348a..92737525f 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -95,7 +95,7 @@ web_o = Object.keys(web_o).map(function(pass) { var forwardReq = (options.forward.protocol === 'https:' ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req, 'forward') ); - req.pipe(forwardReq); + (options.buffer || req).pipe(forwardReq); return res.end(); } @@ -114,7 +114,7 @@ web_o = Object.keys(web_o).map(function(pass) { } }); - req.pipe(proxyReq); + (options.buffer || req).pipe(proxyReq); proxyReq.on('response', function(proxyRes) { for(var i=0; i < web_o.length; i++) { @@ -124,10 +124,6 @@ web_o = Object.keys(web_o).map(function(pass) { proxyRes.pipe(res); }); - if(options.buffer) { - options.buffer.resume(); - } - //proxyReq.end(); } From 8085178dc2c24567adfb872a583863709ce60b5b Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 29 Oct 2013 16:46:27 -0500 Subject: [PATCH 167/556] [tests] Using target field, tests now pass. We are missing the tests using forward field --- test/lib-https-proxy-test.js | 61 +++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js index 6a544bf4d..e4a250f89 100644 --- a/test/lib-https-proxy-test.js +++ b/test/lib-https-proxy-test.js @@ -22,7 +22,6 @@ describe('lib/http-proxy.js', 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) { - console.log('Request:', req.headers); expect(req.method).to.eql('GET'); expect(req.headers.host.split(':')[1]).to.eql(ports.proxy); res.writeHead(200, { 'Content-Type': 'text/plain' }); @@ -32,7 +31,7 @@ describe('lib/http-proxy.js', function() { source.listen(ports.source); var proxy = httpProxy.createProxyServer({ - forward: 'http://127.0.0.1:' + ports.source, + 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')), @@ -44,22 +43,62 @@ describe('lib/http-proxy.js', function() { port: ports.proxy, path: '/', method: 'GET', - localAddress: '127.0.0.1', rejectUnauthorized: false }, function(res) { - console.log(res); - res.on('data', function (ch) { - console.log('Chunks', ch) + 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(); }) - console.log('Response:', res.statusCode); - source.close(); - proxy._server.close(); - done(); }); req.on('error', function (err) { console.log('Erroring', err); }); req.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, + }).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(); + }) + }) }); }); \ No newline at end of file From dda6f7a45a46d2bf63e482d0b47b7c36ae548546 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 5 Nov 2013 17:44:04 +0100 Subject: [PATCH 168/556] [feature] add emit proxyRes --- lib/http-proxy/passes/web-incoming.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 92737525f..c3bc063dd 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -117,6 +117,7 @@ web_o = Object.keys(web_o).map(function(pass) { (options.buffer || req).pipe(proxyReq); proxyReq.on('response', function(proxyRes) { + server.emit('proxyRes', proxyRes); for(var i=0; i < web_o.length; i++) { if(web_o[i](req, res, proxyRes)) { break; } } From b8c6397a9415e1ba1e8dda89cd2aea971a186713 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 5 Nov 2013 16:30:39 -0500 Subject: [PATCH 169/556] [fix] pass proper options object that extend the global options and parse the per proxy args into options. fixes #510 --- lib/http-proxy/index.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 7861503dc..c02735b02 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -6,7 +6,7 @@ var httpProxy = exports, https = require('https'), web = require('./passes/web-incoming'), ws = require('./passes/ws-incoming'); - + httpProxy.Server = ProxyServer; /** @@ -33,7 +33,7 @@ function createRightProxy(type) { cntr = args.length - 1, head, cbl; - /* optional args parse begin */ + /* optional args parse begin */ if(typeof args[cntr] === 'function') { cbl = args[cntr]; @@ -64,7 +64,7 @@ function createRightProxy(type) { }); - for(var i=0; i < passes.length; i++) { + for(var i=0; i < passes.length; i++) { /** * Call of passes functions * pass(req, res, options, head) @@ -73,7 +73,7 @@ function createRightProxy(type) { * refer to the connection socket * pass(req, socket, options, head) */ - if(passes[i](req, res, this.options, head, cbl ? false : this, cbl)) { // passes can return a truthy value to halt the loop + if(passes[i](req, res, options, head, cbl ? false : this, cbl)) { // passes can return a truthy value to halt the loop break; } } @@ -103,9 +103,9 @@ require('util').inherits(ProxyServer, EE3); ProxyServer.prototype.listen = function(port) { var self = this, closure = function(req, res) { self.web(req, res); }; - - this._server = this.options.ssl ? - https.createServer(this.options.ssl, closure) : + + this._server = this.options.ssl ? + https.createServer(this.options.ssl, closure) : http.createServer(closure); if(this.options.ws) { @@ -119,7 +119,7 @@ ProxyServer.prototype.listen = function(port) { ProxyServer.prototype.before = function(passName, callback) { var i = false; - this.passes.forEach(function(v, idx) { + this.passes.forEach(function(v, idx) { if(v.name === passName) i = idx; }) @@ -129,7 +129,7 @@ ProxyServer.prototype.before = function(passName, callback) { }; ProxyServer.prototype.after = function(passName, callback) { var i = false; - this.passes.forEach(function(v, idx) { + this.passes.forEach(function(v, idx) { if(v.name === passName) i = idx; }) From 590bb604dae11223a0ae80469b59d6d341488f1f Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 7 Nov 2013 19:00:01 +0100 Subject: [PATCH 170/556] [fix] _ because it is unused --- lib/http-proxy/passes/web-incoming.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index c3bc063dd..efcdc396a 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -89,7 +89,7 @@ web_o = Object.keys(web_o).map(function(pass) { * @api private */ - function stream(req, res, options, head, server, clb) { + 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( From cde08fb2ee2df03c9457678d8e6776a5d89165b2 Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 7 Nov 2013 19:05:59 +0100 Subject: [PATCH 171/556] [fix] closes number #487 --- lib/http-proxy.js | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 24efb4687..9620b7050 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -20,24 +20,23 @@ var http = require('http'), */ proxy.createProxyServer = proxy.createServer = function createProxyServer(options) { - if(!options) { - throw new Error([ - "`options` is needed and it must have the following layout:", - " ", - " { ", - " target : ", - " forward: ", - " agent : ", - " ssl : ", - " ws : ", - " xfwd : ", - " } ", - " ", - "NOTE: `options.ws` and `options.ssl` are optional. ", - " `options.target and `options.forward` cannot be ", - " both missing " - ].join("\n")); - } + /* + * `options` is needed and it must have the following layout: + * + * { + * target : + * forward: + * agent : + * ssl : + * ws : + * xfwd : + * } + * + * NOTE: `options.ws` and `options.ssl` are optional. + * `options.target and `options.forward` cannot be + * both missing + * } + */ return new httpProxy.Server(options); }; From d0862aff0c693366dcb11649b6abe1d011268953 Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 7 Nov 2013 19:13:09 +0100 Subject: [PATCH 172/556] [fix] merge #495, thanks @glasser --- lib/http-proxy.js | 2 +- lib/http-proxy/passes/ws-incoming.js | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 9620b7050..bef543fe3 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -36,7 +36,7 @@ proxy.createProxyServer = proxy.createServer = function createProxyServer(option * `options.target and `options.forward` cannot be * both missing * } - */ + */ return new httpProxy.Server(options); }; diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index ebdbe2ab0..e51c397e5 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -106,15 +106,11 @@ var passes = exports; common.setupOutgoing(options.ssl || {}, options, req) ); // Error Handler - proxyReq.on('error', function(err){ - if (clb) { - clb(err); - } else { - server.emit('error', err, req, res); - } - }); + proxyReq.on('error', onError); proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { + proxySocket.on('error', onError); + common.setupSocket(proxySocket); if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead); @@ -126,7 +122,15 @@ var passes = exports; proxySocket.pipe(socket).pipe(proxySocket); }); - proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT + return proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT + + function onError(err) { + if (clb) { + clb(err); + } else { + server.emit('error', err, req, res); + } + } } ] // <-- From a2b1f0a4c9079342db6255c5f92db4a0cb992707 Mon Sep 17 00:00:00 2001 From: cronopio Date: Thu, 7 Nov 2013 15:06:45 -0500 Subject: [PATCH 173/556] [tests] disable test, by now is not throwing without options --- test/lib-http-proxy-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 26f9d34b5..6b2ce035e 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -19,7 +19,7 @@ Object.defineProperty(gen, 'port', { describe('lib/http-proxy.js', function() { describe('#createProxyServer', function() { - it('should throw without options', function() { + it.skip('should throw without options', function() { var error; try { httpProxy.createProxyServer(); From fd42dcef01fec5aeeb4fdcbf0bd7cdb1d48e78f7 Mon Sep 17 00:00:00 2001 From: cronopio Date: Thu, 7 Nov 2013 15:09:37 -0500 Subject: [PATCH 174/556] [tests] https test pass, fix #511. Exposed the rejectUnauthorized flag --- lib/http-proxy.js | 1 + lib/http-proxy/common.js | 5 +++++ test/lib-https-proxy-test.js | 32 +++++++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index bef543fe3..36589b39f 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -30,6 +30,7 @@ proxy.createProxyServer = proxy.createServer = function createProxyServer(option * ssl : * ws : * xfwd : + * secure : * } * * NOTE: `options.ws` and `options.ssl` are optional. diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index ed18aa418..58c520317 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -37,6 +37,11 @@ common.setupOutgoing = function(outgoing, options, req, forward) { 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 = req.url; diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js index e4a250f89..a9209b026 100644 --- a/test/lib-https-proxy-test.js +++ b/test/lib-https-proxy-test.js @@ -17,7 +17,7 @@ Object.defineProperty(gen, 'port', { }); describe('lib/http-proxy.js', function() { - describe('#createProxyServer using HTTPS', 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 }; @@ -79,6 +79,8 @@ describe('lib/http-proxy.js', function() { 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({ @@ -100,5 +102,33 @@ describe('lib/http-proxy.js', function() { }).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(); + }) + }) }); }); \ No newline at end of file From a467b7b4a9614a7cbfdc256524e1495616e3d4d9 Mon Sep 17 00:00:00 2001 From: cronopio Date: Thu, 7 Nov 2013 17:20:28 -0500 Subject: [PATCH 175/556] [examples] fixed https examples --- examples/https-secure.js | 8 ++++---- examples/https.js | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/https-secure.js b/examples/https-secure.js index 72bcbb625..1027cd40f 100644 --- a/examples/https-secure.js +++ b/examples/https-secure.js @@ -4,10 +4,10 @@ var httpProxy = require('../lib/http-proxy'), * Create your proxy server pointing to a secure domain * Enable ssl validation */ -var options = {target : 'https://google.com', - agent : https.globalAgent, - headers: {host: 'google.com'} - }; +var options = { target : 'https://google.com', + agent : https.globalAgent, + headers: {host: 'google.com'} + }; var proxyServer = httpProxy.createProxyServer(options); console.log("Proxy server listening on port 8000"); diff --git a/examples/https.js b/examples/https.js index 7f0aed3e2..cccc24683 100644 --- a/examples/https.js +++ b/examples/https.js @@ -1,8 +1,10 @@ -var httpProxy = require('http-proxy'); +var httpProxy = require('../lib/http-proxy'); /* * Create your proxy server pointing to a secure domain */ -var options = {target:'https://google.com'}; +var options = { target:'https://google.com', + headers: {host: 'google.com'} + }; var proxyServer = httpProxy.createProxyServer(options); console.log("Proxy server listening on port 8000"); From 6a6dfbb79dc156679f75dd519344d19a5b61613b Mon Sep 17 00:00:00 2001 From: cronopio Date: Thu, 7 Nov 2013 18:06:12 -0500 Subject: [PATCH 176/556] [examples] fix styling and bad spaces --- examples/https-secure.js | 9 +++++---- examples/https.js | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/examples/https-secure.js b/examples/https-secure.js index 1027cd40f..83b87eb7c 100644 --- a/examples/https-secure.js +++ b/examples/https-secure.js @@ -4,10 +4,11 @@ var httpProxy = require('../lib/http-proxy'), * Create your proxy server pointing to a secure domain * Enable ssl validation */ -var options = { target : 'https://google.com', - agent : https.globalAgent, - headers: {host: 'google.com'} - }; +var options = { + target : 'https://google.com', + agent : https.globalAgent, + headers: {host: 'google.com'} +}; var proxyServer = httpProxy.createProxyServer(options); console.log("Proxy server listening on port 8000"); diff --git a/examples/https.js b/examples/https.js index cccc24683..364d7cb2f 100644 --- a/examples/https.js +++ b/examples/https.js @@ -2,9 +2,10 @@ var httpProxy = require('../lib/http-proxy'); /* * Create your proxy server pointing to a secure domain */ -var options = { target:'https://google.com', - headers: {host: 'google.com'} - }; +var options = { + target:'https://google.com', + headers: {host: 'google.com'} +}; var proxyServer = httpProxy.createProxyServer(options); console.log("Proxy server listening on port 8000"); From 31d919b0a3d0b7f574e88fc5eed093c6b1a53548 Mon Sep 17 00:00:00 2001 From: cronopio Date: Thu, 7 Nov 2013 18:06:51 -0500 Subject: [PATCH 177/556] [tests] added HTTPS to HTTPS test --- test/lib-https-proxy-test.js | 52 ++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js index a9209b026..78da72d4e 100644 --- a/test/lib-https-proxy-test.js +++ b/test/lib-https-proxy-test.js @@ -38,7 +38,7 @@ describe('lib/http-proxy.js', function() { } }).listen(ports.proxy); - var req = https.request({ + https.request({ host: 'localhost', port: ports.proxy, path: '/', @@ -56,10 +56,7 @@ describe('lib/http-proxy.js', function() { proxy._server.close(); done(); }) - }); - - req.on('error', function (err) { console.log('Erroring', err); }); - req.end(); + }).end(); }) }); describe('HTTP to HTTPS', function () { @@ -102,6 +99,51 @@ describe('lib/http-proxy.js', function() { }).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 }; From bbe3bfdf98255b82a185a798ff9f29e74615b6ca Mon Sep 17 00:00:00 2001 From: cronopio Date: Thu, 7 Nov 2013 21:27:50 -0500 Subject: [PATCH 178/556] [tests] added test HTTPS to HTTP using own server --- test/lib-https-proxy-test.js | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js index 78da72d4e..192504921 100644 --- a/test/lib-https-proxy-test.js +++ b/test/lib-https-proxy-test.js @@ -172,5 +172,51 @@ describe('lib/http-proxy.js', function() { }).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 From 961d2f9400b4cfd236c3c8ccbf401d37f8e871b8 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 8 Nov 2013 20:56:26 +0100 Subject: [PATCH 179/556] [fix] support target and forward --- lib/http-proxy/passes/web-incoming.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index efcdc396a..68d4e1db7 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -96,7 +96,7 @@ web_o = Object.keys(web_o).map(function(pass) { common.setupOutgoing(options.ssl || {}, options, req, 'forward') ); (options.buffer || req).pipe(forwardReq); - return res.end(); + if(!options.target) { return res.end(); } } // Request initalization From 04c10113f7a3b568fb95b18f30e4aca3e059d961 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 11 Nov 2013 11:14:42 -0500 Subject: [PATCH 180/556] [examples] added concurrent proxy example --- examples/concurrent-proxy.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 examples/concurrent-proxy.js diff --git a/examples/concurrent-proxy.js b/examples/concurrent-proxy.js new file mode 100644 index 000000000..0d1889f89 --- /dev/null +++ b/examples/concurrent-proxy.js @@ -0,0 +1,36 @@ +var http = require('http'), + httpProxy = require('../lib/http-proxy'); + +var connections = [], + go; + + +// +// Target Http Server +// +// to check apparent problems with concurrent connections +// make a server which only responds when there is a given nubmer on connections +// +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 > 10 || go) { + go = true; + while (connections.length) { + connections.shift()(); + } + } +}).listen(9000); +console.log("Web server listening on port 9000"); + +// +// Basic Http Proxy Server +// +httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); +console.log("Proxy server listening on port 8000"); \ No newline at end of file From 7a3f6dfbcc80ba32fa81004438c637e8d29eb029 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 11 Nov 2013 11:22:04 -0500 Subject: [PATCH 181/556] [examples] added forward example --- examples/forward-proxy.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 examples/forward-proxy.js diff --git a/examples/forward-proxy.js b/examples/forward-proxy.js new file mode 100644 index 000000000..4cb516f50 --- /dev/null +++ b/examples/forward-proxy.js @@ -0,0 +1,33 @@ +var http = require('http'), + httpProxy = require('../lib/http-proxy'); + +// +// 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(9000); +console.log("Web server listening on port 9000"); + +// +// Target Http Forwarding Server +// +http.createServer(function (req, res) { + console.log('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(9001); + +// +// Basic Http Proxy Server +// Forward example: send requests without care about response +// +httpProxy.createServer({ + target: 'http://localhost:9000', + forward: 'http://localhost:9001' +}).listen(8000) +console.log("Proxy server listening on port 8000"); + From dcb873ad9992b1534615d59b8a0a70e8b87d7884 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 13 Nov 2013 18:29:15 +0100 Subject: [PATCH 182/556] [doc] update README.md --- README.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 344d6c32c..904b77905 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,6 @@ 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) -* ee (an EventEmitter2 that emits events, you can hook into them to customize behaviour) * 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 @@ -44,15 +43,26 @@ require('http').createServer(function(req, res) { }); ``` +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. -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 From cb7af4f4d76744cd3348297ce8284e97d17c9304 Mon Sep 17 00:00:00 2001 From: Ben Firshman Date: Mon, 18 Nov 2013 23:04:51 +0000 Subject: [PATCH 183/556] Fix websocket error handing Websockets have sockets, not responses. --- lib/http-proxy/passes/ws-incoming.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index e51c397e5..ab99aa2cb 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -128,7 +128,7 @@ var passes = exports; if (clb) { clb(err); } else { - server.emit('error', err, req, res); + server.emit('error', err, req, socket); } } } From 10c0f11b68e39552051e508c7bf20d65d2d59177 Mon Sep 17 00:00:00 2001 From: yawnt Date: Tue, 19 Nov 2013 20:05:46 +0100 Subject: [PATCH 184/556] [fix] remove duplicate --- lib/http-proxy/passes/ws-incoming.js | 18 ------------ .../lib-http-proxy-passes-ws-incoming-test.js | 29 ------------------- 2 files changed, 47 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index ab99aa2cb..99a6f8711 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -41,24 +41,6 @@ var passes = exports; } }, - /** - * Set the proper configuration for sockets, - * set no delay and set keep alive, also set - * the timeout to 0. - * - * @param {ClientRequest} Req Request object - * @param {Socket} Websocket - * - * @api private - */ - - function setupSocket(req, socket) { - socket.setTimeout(0); - socket.setNoDelay(true); - - socket.setKeepAlive(true, 0); - }, - /** * Sets `x-forwarded-*` headers if specified in config. * diff --git a/test/lib-http-proxy-passes-ws-incoming-test.js b/test/lib-http-proxy-passes-ws-incoming-test.js index 87dfcef94..2f696c7be 100644 --- a/test/lib-http-proxy-passes-ws-incoming-test.js +++ b/test/lib-http-proxy-passes-ws-incoming-test.js @@ -76,35 +76,6 @@ describe('lib/http-proxy/passes/ws-incoming.js', function () { }) }); - describe('#setupSocket', function () { - it('Set the correct config to the socket', function () { - var stubSocket = { - setTimeout: function (num) { - // Simulate Socket.setTimeout() - socketConfig.timeout = num; - }, - setNoDelay: function (bol) { - // Simulate Socket.setNoDelay() - socketConfig.nodelay = bol; - }, - setKeepAlive: function (bol) { - // Simulate Socket.setKeepAlive() - socketConfig.keepalive = bol; - } - }, - socketConfig = { - timeout: null, - nodelay: false, - keepalive: false - }, - returnValue = httpProxy.setupSocket({}, stubSocket); - expect(returnValue).to.be(undefined); - expect(socketConfig.timeout).to.eql(0); - expect(socketConfig.nodelay).to.eql(true); - expect(socketConfig.keepalive).to.eql(true); - }); - }); - describe('#XHeaders', function () { it('return if no forward request', function () { var returnValue = httpProxy.XHeaders({}, {}, {}); From 584ce76e7576c906e25cdd04a2e079f97bcf86ff Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 19 Nov 2013 20:03:23 -0500 Subject: [PATCH 185/556] [misc] add a LICENSE file --- LICENSE | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..2bab4b9b1 --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ + + 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 From ef8150af95956f30e915637f9e2bc2fb41c2e7f8 Mon Sep 17 00:00:00 2001 From: derekdreery Date: Thu, 21 Nov 2013 17:33:19 +0000 Subject: [PATCH 186/556] Update README.md I struggled to get the section about using https to http with two certificates to work, because I didn't understand where the myCert etc. came from. Once I realised they had to be created by the user I could get it working. I want to save someone else the time it took me. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 9c0ca04df..86de9cf9b 100644 --- a/README.md +++ b/README.md @@ -344,6 +344,10 @@ var certs = { // // Proxy options // +// This section assumes that myCert, myKey and myCa are defined (they are not +// in this example). With a SNICallback, the proxy needs a default set of +// certificates to use. +// var options = { https: { SNICallback: function (hostname) { From ae0faef5aa0080d742a9740f9cb38bfd54b7d97e Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 9 Dec 2013 12:33:16 -0500 Subject: [PATCH 187/556] [docs] Update readme with more how to --- README.md | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 904b77905..e95b2d6fa 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ to the client. var http = require('http'), httpProxy = require('http-proxy'); // -// Create your proxy server +// Create your proxy server and set the target in the options. // httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); @@ -85,6 +85,9 @@ http.createServer(function (req, res) { ``` #### 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 hanlde the request. This example +could show how to proxy requests within another http server. ``` js var http = require('http'), @@ -95,7 +98,14 @@ var http = require('http'), // 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' }); }); @@ -103,6 +113,40 @@ console.log("listening on port 5050") server.listen(5050); ``` +#### Setup a stand-alone proxy server with latency + +``` +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); +``` + ### Contributing and Issues * Search on Google/Github @@ -118,6 +162,7 @@ server.listen(5050); * **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: From 0393b5da990bb45e873bb80d87a0bc9e4dd6a477 Mon Sep 17 00:00:00 2001 From: cronopio Date: Fri, 13 Dec 2013 12:58:37 -0500 Subject: [PATCH 188/556] [docs] more short examples to the Readme --- README.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e95b2d6fa..c9943566c 100644 --- a/README.md +++ b/README.md @@ -86,10 +86,9 @@ http.createServer(function (req, res) { #### 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 hanlde the request. This example -could show how to proxy requests within another http server. +and also you can put your own logic to hanlde the request. -``` js +```js var http = require('http'), httpProxy = require('http-proxy'); @@ -147,6 +146,122 @@ http.createServer(function (req, res) { }).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' +}); + +// +// 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.'); +}); + +// +// Listen for the `proxyRes` event on `proxy`. +// +proxy.on('proxyRes', function (res) { + console.log('RAW Response from the target', res.headers); +}); + +``` + +#### 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 From 03880d8d069e9e17ca7d7aea6eb760f6626a869c Mon Sep 17 00:00:00 2001 From: cronopio Date: Fri, 13 Dec 2013 13:06:19 -0500 Subject: [PATCH 189/556] [docs] typos, typos everywhere... --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c9943566c..ed25eb240 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ http.createServer(function (req, res) { #### 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 hanlde the request. +and also you can put your own logic to handle the request. ```js var http = require('http'), @@ -114,7 +114,7 @@ server.listen(5050); #### Setup a stand-alone proxy server with latency -``` +```js var http = require('http'), httpProxy = require('http-proxy'); @@ -161,9 +161,6 @@ var proxy = httpProxy.createServer({ target:'http://localhost:9005' }); -// -// Tell the proxy to listen on port 8000 -// proxy.listen(8005); // @@ -180,7 +177,7 @@ proxy.on('error', function (err, req, res) { // Listen for the `proxyRes` event on `proxy`. // proxy.on('proxyRes', function (res) { - console.log('RAW Response from the target', res.headers); + console.log('RAW Response from the target', JSON.stringify(res.headers, true, 2)); }); ``` From 97e4600e944b1de3e3984e8e29d09658c02de606 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 18 Dec 2013 12:33:23 +0100 Subject: [PATCH 190/556] [fix] fixes #341 --- lib/http-proxy/common.js | 7 +++++++ lib/http-proxy/passes/web-incoming.js | 2 +- lib/http-proxy/passes/ws-incoming.js | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 58c520317..1698c1ade 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -73,3 +73,10 @@ common.setupSocket = function(socket) { return socket; }; + +common.getPort = function(req) { + var res = req.headers.host.match(/:(\d+)/); + return res ? + res[1] : + req.connection.pair ? '443' : '80' ; +} diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 68d4e1db7..2b14c874c 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -65,7 +65,7 @@ web_o = Object.keys(web_o).map(function(pass) { var values = { for : req.connection.remoteAddress || req.socket.remoteAddress, - port : req.connection.remotePort || req.socket.remotePort, + port : common.getPort(req), proto: req.isSpdy ? 'https' : (req.connection.pair ? 'https' : 'http') }; diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 99a6f8711..720ac2745 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -56,7 +56,7 @@ var passes = exports; var values = { for : req.connection.remoteAddress || req.socket.remoteAddress, - port : req.connection.remotePort || req.socket.remotePort, + port : common.getPort(req), proto: req.connection.pair ? 'wss' : 'ws' }; From 9e74a633a75d466cf266b1c57c68edd20a883f69 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 18 Dec 2013 12:45:20 +0100 Subject: [PATCH 191/556] [fix] closes #529 --- lib/http-proxy/common.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 1698c1ade..789757880 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -1,4 +1,5 @@ var common = exports, + url = require('url'), extend = require('util')._extend; /** @@ -43,8 +44,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { outgoing.agent = options.agent || false; - outgoing.path = req.url; - + outgoing.path = url.parse(req.url).path; return outgoing; }; From 4d65280ea313438a94589bacf55f7a09cc107888 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 18 Dec 2013 13:30:02 +0100 Subject: [PATCH 192/556] [fix] remove old reminescence --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 9c0ca04df..845c4f023 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ * Reverse proxies incoming http.ServerRequest streams * Can be used as a CommonJS module in node.js -* Uses event buffering to support application latency in proxied requests * Reverse or Forward Proxy based on simple JSON-based configuration * Supports [WebSockets][1] * Supports [HTTPS][2] From c4d56a5faf1e89cdeb911f0ece0efe065eb58c45 Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 18 Dec 2013 11:50:49 -0500 Subject: [PATCH 193/556] [tests] fix test using undefined url --- test/lib-http-proxy-common-test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 2f9fa1ed8..7398a0ebe 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -38,7 +38,9 @@ describe('lib/http-proxy/common.js', function () { it('should set the agent to false if none is given', function () { var outgoing = {}; - common.setupOutgoing(outgoing, {target: {},}, {}); + common.setupOutgoing(outgoing, {target: + 'http://localhost' + }, { url: '/' }); expect(outgoing.agent).to.eql(false); }); From cfd417de2352b0f05535b979dc15abff60c1fb96 Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 18 Dec 2013 12:17:41 -0500 Subject: [PATCH 194/556] [tests] fix tests set correct host headers --- test/lib-http-proxy-passes-web-incoming-test.js | 12 +++++++----- test/lib-http-proxy-passes-ws-incoming-test.js | 8 ++++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 19fa669b7..b25ad6e12 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -34,7 +34,9 @@ describe('lib/http-proxy/passes/web.js', function() { remoteAddress: '192.168.1.2', remotePort: '8080' }, - headers: {} + headers: { + host: '192.168.1.2:8080' + } } it('set the correct x-forwarded-* headers', function () { @@ -88,11 +90,11 @@ describe('#createProxyServer.web() using own http server', function () { }); } - proxyServer.listen('8081'); + proxyServer.listen('8082'); http.request({ hostname: '127.0.0.1', - port: '8081', + port: '8082', method: 'GET', }, function() {}).end(); }); @@ -117,11 +119,11 @@ describe('#createProxyServer.web() using own http server', function () { proxy.web(req, res); } - proxyServer.listen('8081'); + proxyServer.listen('8083'); http.request({ hostname: '127.0.0.1', - port: '8081', + port: '8083', method: 'GET', }, function() {}).end(); }); diff --git a/test/lib-http-proxy-passes-ws-incoming-test.js b/test/lib-http-proxy-passes-ws-incoming-test.js index 2f696c7be..bfed888c0 100644 --- a/test/lib-http-proxy-passes-ws-incoming-test.js +++ b/test/lib-http-proxy-passes-ws-incoming-test.js @@ -88,7 +88,9 @@ describe('lib/http-proxy/passes/ws-incoming.js', function () { remoteAddress: '192.168.1.2', remotePort: '8080' }, - headers: {} + headers: { + host: '192.168.1.2:8080' + } } httpProxy.XHeaders(stubRequest, {}, { xfwd: true }); expect(stubRequest.headers['x-forwarded-for']).to.be('192.168.1.2'); @@ -105,7 +107,9 @@ describe('lib/http-proxy/passes/ws-incoming.js', function () { connection: { pair: true }, - headers: {} + headers: { + host: '192.168.1.3:8181' + } }; httpProxy.XHeaders(stubRequest, {}, { xfwd: true }); expect(stubRequest.headers['x-forwarded-for']).to.be('192.168.1.3'); From bdeabb767a537bcb9f98ef74f6efe9762a9b1c34 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 18 Nov 2013 15:21:25 -0500 Subject: [PATCH 195/556] [examples] deleted this examples --- examples/concurrent-proxy.js | 36 ------------------------------------ examples/error-handling.js | 33 --------------------------------- examples/forward-proxy.js | 33 --------------------------------- examples/https-secure.js | 16 ---------------- examples/https.js | 13 ------------- examples/stand-alone.js | 17 ----------------- 6 files changed, 148 deletions(-) delete mode 100644 examples/concurrent-proxy.js delete mode 100644 examples/error-handling.js delete mode 100644 examples/forward-proxy.js delete mode 100644 examples/https-secure.js delete mode 100644 examples/https.js delete mode 100644 examples/stand-alone.js diff --git a/examples/concurrent-proxy.js b/examples/concurrent-proxy.js deleted file mode 100644 index 0d1889f89..000000000 --- a/examples/concurrent-proxy.js +++ /dev/null @@ -1,36 +0,0 @@ -var http = require('http'), - httpProxy = require('../lib/http-proxy'); - -var connections = [], - go; - - -// -// Target Http Server -// -// to check apparent problems with concurrent connections -// make a server which only responds when there is a given nubmer on connections -// -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 > 10 || go) { - go = true; - while (connections.length) { - connections.shift()(); - } - } -}).listen(9000); -console.log("Web server listening on port 9000"); - -// -// Basic Http Proxy Server -// -httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); -console.log("Proxy server listening on port 8000"); \ No newline at end of file diff --git a/examples/error-handling.js b/examples/error-handling.js deleted file mode 100644 index 76a09d955..000000000 --- a/examples/error-handling.js +++ /dev/null @@ -1,33 +0,0 @@ -var httpProxy = require('../lib/http-proxy'), - http = require('http'); -/* - * Create your proxy server - */ -var proxy = httpProxy.createProxyServer({target:'http://localhost:30404', ws:true}); - -var proxyServer = http.createServer(requestHandler); - -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(); - }) - }) -} - -console.log("Proxy server is listening on port 8000"); -proxyServer.listen(8000) \ No newline at end of file diff --git a/examples/forward-proxy.js b/examples/forward-proxy.js deleted file mode 100644 index 4cb516f50..000000000 --- a/examples/forward-proxy.js +++ /dev/null @@ -1,33 +0,0 @@ -var http = require('http'), - httpProxy = require('../lib/http-proxy'); - -// -// 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(9000); -console.log("Web server listening on port 9000"); - -// -// Target Http Forwarding Server -// -http.createServer(function (req, res) { - console.log('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(9001); - -// -// Basic Http Proxy Server -// Forward example: send requests without care about response -// -httpProxy.createServer({ - target: 'http://localhost:9000', - forward: 'http://localhost:9001' -}).listen(8000) -console.log("Proxy server listening on port 8000"); - diff --git a/examples/https-secure.js b/examples/https-secure.js deleted file mode 100644 index 83b87eb7c..000000000 --- a/examples/https-secure.js +++ /dev/null @@ -1,16 +0,0 @@ -var httpProxy = require('../lib/http-proxy'), - https = require('https'); -/* - * Create your proxy server pointing to a secure domain - * Enable ssl validation - */ -var options = { - target : 'https://google.com', - agent : https.globalAgent, - headers: {host: 'google.com'} -}; - -var proxyServer = httpProxy.createProxyServer(options); -console.log("Proxy server listening on port 8000"); -proxyServer.listen(8000); - diff --git a/examples/https.js b/examples/https.js deleted file mode 100644 index 364d7cb2f..000000000 --- a/examples/https.js +++ /dev/null @@ -1,13 +0,0 @@ -var httpProxy = require('../lib/http-proxy'); -/* - * Create your proxy server pointing to a secure domain - */ -var options = { - target:'https://google.com', - headers: {host: 'google.com'} -}; - -var proxyServer = httpProxy.createProxyServer(options); -console.log("Proxy server listening on port 8000"); -proxyServer.listen(8000); - diff --git a/examples/stand-alone.js b/examples/stand-alone.js deleted file mode 100644 index e5239c460..000000000 --- a/examples/stand-alone.js +++ /dev/null @@ -1,17 +0,0 @@ -var http = require('http'), - httpProxy = require('../lib/http-proxy'); -// -// Create your proxy server -// -console.log("Proxy server listening on port 8000"); -httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); - -// -// Create your target server -// -console.log("Web server listening on port 9000"); -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 7e44d3669bbd1b13e6452f265d52b22396f68b5d Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 18 Nov 2013 15:37:34 -0500 Subject: [PATCH 196/556] [examples] update old examples --- examples/http/basic-proxy.js | 60 +++++++++++++++++++++++++++ examples/http/concurrent-proxy.js | 68 +++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 examples/http/basic-proxy.js create mode 100644 examples/http/concurrent-proxy.js diff --git a/examples/http/basic-proxy.js b/examples/http/basic-proxy.js new file mode 100644 index 000000000..8d781604d --- /dev/null +++ b/examples/http/basic-proxy.js @@ -0,0 +1,60 @@ +/* + basic-proxy.js: Basic example of proxying over HTTP + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +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:9000' +}).listen(8000); + +// +// 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(9000); + +util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); +util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/http/concurrent-proxy.js b/examples/http/concurrent-proxy.js new file mode 100644 index 000000000..fd05442e3 --- /dev/null +++ b/examples/http/concurrent-proxy.js @@ -0,0 +1,68 @@ +/* + concurrent-proxy.js: check levelof concurrency through proxy. + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +var util = require('util'), + colors = require('colors'), + http = require('http'), + httpProxy = require('../../lib/http-proxy'); + +// +// Basic Http Proxy Server +// +httpProxy.createServer({ + target:'http://localhost:9000' +}).listen(8000); + +// +// 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(9000); + +util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); +util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); From b7261161343c3471201d6de36ba1030aced26425 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 18 Nov 2013 15:58:44 -0500 Subject: [PATCH 197/556] [examples] update forward and custom error examples --- examples/http/custom-proxy-error.js | 55 +++++++++++++++++++ examples/http/forward-and-target-proxy.js | 67 +++++++++++++++++++++++ examples/http/forward-proxy.js | 53 ++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 examples/http/custom-proxy-error.js create mode 100644 examples/http/forward-and-target-proxy.js create mode 100644 examples/http/forward-proxy.js diff --git a/examples/http/custom-proxy-error.js b/examples/http/custom-proxy-error.js new file mode 100644 index 000000000..5835e881c --- /dev/null +++ b/examples/http/custom-proxy-error.js @@ -0,0 +1,55 @@ +/* + custom-proxy-error.js: Example of using the custom `proxyError` event. + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +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:9000' +}); + +// +// Tell the proxy to listen on port 8000 +// +proxy.listen(8000); + +// +// 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 + '8000 '.yellow + 'with custom error message'.magenta.underline); \ No newline at end of file diff --git a/examples/http/forward-and-target-proxy.js b/examples/http/forward-and-target-proxy.js new file mode 100644 index 000000000..9ecf4dcec --- /dev/null +++ b/examples/http/forward-and-target-proxy.js @@ -0,0 +1,67 @@ +/* + forward-and-target-proxy.js: Example of proxying over HTTP with additional forward proxy + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +var util = require('util'), + colors = require('colors'), + http = require('http'), + httpProxy = require('../../lib/http-proxy'); + +// +// Setup proxy server with forwarding +// +httpProxy.createServer({ + target: { + port: 9000, + host: 'localhost' + }, + forward: { + port: 9001, + host: 'localhost' + } +}).listen(8000); + +// +// 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(9000); + +// +// 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(9001); + +util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow + 'with forward proxy'.magenta.underline); +util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); +util.puts('http forward server '.blue + 'started '.green.bold + 'on port '.blue + '9001 '.yellow); \ No newline at end of file diff --git a/examples/http/forward-proxy.js b/examples/http/forward-proxy.js new file mode 100644 index 000000000..d10a40208 --- /dev/null +++ b/examples/http/forward-proxy.js @@ -0,0 +1,53 @@ +/* + forward-proxy.js: Example of proxying over HTTP with additional forward proxy + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +var util = require('util'), + colors = require('colors'), + http = require('http'), + httpProxy = require('../../lib/http-proxy'); + +// +// Setup proxy server with forwarding +// +httpProxy.createServer({ + forward: { + port: 9000, + host: 'localhost' + } +}).listen(8000); + +// +// 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(9000); + +util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow + 'with forward proxy'.magenta.underline); +util.puts('http forward server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); \ No newline at end of file From e02317ce86ff2dabd496cf7e2741e219a22ac817 Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 19 Nov 2013 11:06:06 -0500 Subject: [PATCH 198/556] [examples] updated old proxy examples --- examples/http/proxy-https-to-http.js | 60 +++++++++++++++++++++++++++ examples/http/proxy-https-to-https.js | 59 ++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 examples/http/proxy-https-to-http.js create mode 100644 examples/http/proxy-https-to-https.js diff --git a/examples/http/proxy-https-to-http.js b/examples/http/proxy-https-to-http.js new file mode 100644 index 000000000..7c9d1fd93 --- /dev/null +++ b/examples/http/proxy-https-to-http.js @@ -0,0 +1,60 @@ +/* + proxy-https-to-http.js: Basic example of proxying over HTTPS to a target HTTP server + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +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(9000); + +// +// Create the HTTPS proxy server listening on port 8000 +// +httpProxy.createServer({ + target: { + host: 'localhost', + port: 9000 + }, + ssl: { + key: fs.readFileSync(path.join(fixturesDir, 'agent2-key.pem'), 'utf8'), + cert: fs.readFileSync(path.join(fixturesDir, 'agent2-cert.pem'), 'utf8') + } +}).listen(8000); + +util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); +util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/http/proxy-https-to-https.js b/examples/http/proxy-https-to-https.js new file mode 100644 index 000000000..2ff9151e2 --- /dev/null +++ b/examples/http/proxy-https-to-https.js @@ -0,0 +1,59 @@ +/* + proxy-https-to-https.js: Basic example of proxying over HTTPS to a target HTTPS server + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +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(9000); + +// +// Create the proxy server listening on port 443 +// +httpProxy.createServer({ + ssl: httpsOpts, + target: 'https://localhost:9000', + secure: false +}).listen(8000); + +util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); +util.puts('https server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); From 588327c2c4392618b515164989f08ef20a30842b Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 19 Nov 2013 11:29:06 -0500 Subject: [PATCH 199/556] [examples] updated old examples --- examples/http/latent-proxy.js | 54 +++++++++++++++++++++++++++++++ examples/http/standalone-proxy.js | 54 +++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 examples/http/latent-proxy.js create mode 100644 examples/http/standalone-proxy.js diff --git a/examples/http/latent-proxy.js b/examples/http/latent-proxy.js new file mode 100644 index 000000000..e2aef9b72 --- /dev/null +++ b/examples/http/latent-proxy.js @@ -0,0 +1,54 @@ +/* + latent-proxy.js: Example of proxying over HTTP with latency + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +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:9000' + }); + }, 500); +}).listen(8000); + +// +// 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(9000); + +util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow + 'with latency'.magenta.underline); +util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/http/standalone-proxy.js b/examples/http/standalone-proxy.js new file mode 100644 index 000000000..05c440698 --- /dev/null +++ b/examples/http/standalone-proxy.js @@ -0,0 +1,54 @@ +/* + standalone-proxy.js: Example of proxying over HTTP with a standalone HTTP server. + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +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:9000' + }); + }, 200); +}).listen(8000); + +// +// 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(9000); + +util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow + 'with proxy.web() handler'.cyan.underline + ' and latency'.magenta); +util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); From ed8c9eeba99d60f39f5c36c4f34ed1a781d2cfd8 Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 19 Nov 2013 11:42:26 -0500 Subject: [PATCH 200/556] [examples] updated websockets examples --- examples/websocket/latent-websocket-proxy.js | 91 +++++++++++++++++++ .../websocket/standalone-websocket-proxy.js | 88 ++++++++++++++++++ examples/websocket/websocket-proxy.js | 70 ++++++++++++++ 3 files changed, 249 insertions(+) create mode 100644 examples/websocket/latent-websocket-proxy.js create mode 100644 examples/websocket/standalone-websocket-proxy.js create mode 100644 examples/websocket/websocket-proxy.js diff --git a/examples/websocket/latent-websocket-proxy.js b/examples/websocket/latent-websocket-proxy.js new file mode 100644 index 000000000..06569bf5f --- /dev/null +++ b/examples/websocket/latent-websocket-proxy.js @@ -0,0 +1,91 @@ +/* + standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server. + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +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(9000); +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: 9000 + } +}); + +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(8000); + +// +// Setup the socket.io client against our proxy +// +var ws = client.connect('ws://localhost:8000'); + +ws.on('message', function (msg) { + util.debug('Got message: ' + msg); + ws.send('I am the client'); +}); diff --git a/examples/websocket/standalone-websocket-proxy.js b/examples/websocket/standalone-websocket-proxy.js new file mode 100644 index 000000000..e844ab097 --- /dev/null +++ b/examples/websocket/standalone-websocket-proxy.js @@ -0,0 +1,88 @@ +/* + standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server. + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +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(9000); +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: 9000 + } +}); +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(8000); + +// +// Setup the socket.io client against our proxy +// +var ws = client.connect('ws://localhost:8000'); + +ws.on('message', function (msg) { + util.debug('Got message: ' + msg); + ws.send('I am the client'); +}); diff --git a/examples/websocket/websocket-proxy.js b/examples/websocket/websocket-proxy.js new file mode 100644 index 000000000..767f58c00 --- /dev/null +++ b/examples/websocket/websocket-proxy.js @@ -0,0 +1,70 @@ +/* + web-socket-proxy.js: Example of proxying over HTTP and WebSockets. + + Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. + +*/ + +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(9000); +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:9000', ws: true }).listen(8000); + +// +// Setup the socket.io client against our proxy +// +var ws = client.connect('ws://localhost:8000'); + +ws.on('message', function (msg) { + util.debug('Got message: ' + msg); + ws.send('I am the client'); +}); From 831a44b3c8c3acf6c046c47703a07cd6362a0d1c Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 19 Nov 2013 12:13:10 -0500 Subject: [PATCH 201/556] [examples] updated balancer examples --- .../simple-balancer-with-websockets.js | 58 +++++++++++++++++++ examples/balancer/simple-balancer.js | 38 ++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 examples/balancer/simple-balancer-with-websockets.js create mode 100644 examples/balancer/simple-balancer.js diff --git a/examples/balancer/simple-balancer-with-websockets.js b/examples/balancer/simple-balancer-with-websockets.js new file mode 100644 index 000000000..ffe54ec56 --- /dev/null +++ b/examples/balancer/simple-balancer-with-websockets.js @@ -0,0 +1,58 @@ +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(8080); + \ No newline at end of file diff --git a/examples/balancer/simple-balancer.js b/examples/balancer/simple-balancer.js new file mode 100644 index 000000000..5660fbc29 --- /dev/null +++ b/examples/balancer/simple-balancer.js @@ -0,0 +1,38 @@ +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(8000); + +// Rinse; repeat; enjoy. \ No newline at end of file From d85ccdd333edcfc7551bcf8e0ffd7dc166e38e61 Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 19 Nov 2013 12:38:20 -0500 Subject: [PATCH 202/556] [examples] added package.json with the dependencies needed by examples --- examples/package.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 examples/package.json diff --git a/examples/package.json b/examples/package.json new file mode 100644 index 000000000..be054638e --- /dev/null +++ b/examples/package.json @@ -0,0 +1,10 @@ +{ + "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" + } +} From e592c53d1a23b7920d603a9e9ac294fc0e841f6d Mon Sep 17 00:00:00 2001 From: cronopio Date: Tue, 19 Nov 2013 19:58:28 -0500 Subject: [PATCH 203/556] [examples] fix the copyright header of example files --- .../simple-balancer-with-websockets.js | 26 +++++++++++++++++++ examples/balancer/simple-balancer.js | 26 +++++++++++++++++++ examples/http/basic-proxy.js | 2 +- examples/http/concurrent-proxy.js | 2 +- examples/http/custom-proxy-error.js | 2 +- examples/http/forward-and-target-proxy.js | 2 +- examples/http/forward-proxy.js | 2 +- examples/http/latent-proxy.js | 2 +- examples/http/proxy-https-to-http.js | 2 +- examples/http/proxy-https-to-https.js | 2 +- examples/http/standalone-proxy.js | 2 +- examples/websocket/latent-websocket-proxy.js | 2 +- .../websocket/standalone-websocket-proxy.js | 2 +- examples/websocket/websocket-proxy.js | 2 +- 14 files changed, 64 insertions(+), 12 deletions(-) diff --git a/examples/balancer/simple-balancer-with-websockets.js b/examples/balancer/simple-balancer-with-websockets.js index ffe54ec56..b17afc772 100644 --- a/examples/balancer/simple-balancer-with-websockets.js +++ b/examples/balancer/simple-balancer-with-websockets.js @@ -1,3 +1,29 @@ +/* + 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'); diff --git a/examples/balancer/simple-balancer.js b/examples/balancer/simple-balancer.js index 5660fbc29..80b91760c 100644 --- a/examples/balancer/simple-balancer.js +++ b/examples/balancer/simple-balancer.js @@ -1,3 +1,29 @@ +/* + 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'); // diff --git a/examples/http/basic-proxy.js b/examples/http/basic-proxy.js index 8d781604d..640318c11 100644 --- a/examples/http/basic-proxy.js +++ b/examples/http/basic-proxy.js @@ -1,7 +1,7 @@ /* basic-proxy.js: Basic example of proxying over HTTP - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/http/concurrent-proxy.js b/examples/http/concurrent-proxy.js index fd05442e3..5ca1054b8 100644 --- a/examples/http/concurrent-proxy.js +++ b/examples/http/concurrent-proxy.js @@ -1,7 +1,7 @@ /* concurrent-proxy.js: check levelof concurrency through proxy. - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/http/custom-proxy-error.js b/examples/http/custom-proxy-error.js index 5835e881c..dd62273a7 100644 --- a/examples/http/custom-proxy-error.js +++ b/examples/http/custom-proxy-error.js @@ -1,7 +1,7 @@ /* custom-proxy-error.js: Example of using the custom `proxyError` event. - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/http/forward-and-target-proxy.js b/examples/http/forward-and-target-proxy.js index 9ecf4dcec..0d5acd1f6 100644 --- a/examples/http/forward-and-target-proxy.js +++ b/examples/http/forward-and-target-proxy.js @@ -1,7 +1,7 @@ /* forward-and-target-proxy.js: Example of proxying over HTTP with additional forward proxy - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/http/forward-proxy.js b/examples/http/forward-proxy.js index d10a40208..5f93c49f6 100644 --- a/examples/http/forward-proxy.js +++ b/examples/http/forward-proxy.js @@ -1,7 +1,7 @@ /* forward-proxy.js: Example of proxying over HTTP with additional forward proxy - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/http/latent-proxy.js b/examples/http/latent-proxy.js index e2aef9b72..85de6338f 100644 --- a/examples/http/latent-proxy.js +++ b/examples/http/latent-proxy.js @@ -1,7 +1,7 @@ /* latent-proxy.js: Example of proxying over HTTP with latency - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/http/proxy-https-to-http.js b/examples/http/proxy-https-to-http.js index 7c9d1fd93..1b6ac92bd 100644 --- a/examples/http/proxy-https-to-http.js +++ b/examples/http/proxy-https-to-http.js @@ -1,7 +1,7 @@ /* proxy-https-to-http.js: Basic example of proxying over HTTPS to a target HTTP server - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/http/proxy-https-to-https.js b/examples/http/proxy-https-to-https.js index 2ff9151e2..f0d06e8e4 100644 --- a/examples/http/proxy-https-to-https.js +++ b/examples/http/proxy-https-to-https.js @@ -1,7 +1,7 @@ /* proxy-https-to-https.js: Basic example of proxying over HTTPS to a target HTTPS server - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/http/standalone-proxy.js b/examples/http/standalone-proxy.js index 05c440698..7fc97b3d7 100644 --- a/examples/http/standalone-proxy.js +++ b/examples/http/standalone-proxy.js @@ -1,7 +1,7 @@ /* standalone-proxy.js: Example of proxying over HTTP with a standalone HTTP server. - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/websocket/latent-websocket-proxy.js b/examples/websocket/latent-websocket-proxy.js index 06569bf5f..a80a16edd 100644 --- a/examples/websocket/latent-websocket-proxy.js +++ b/examples/websocket/latent-websocket-proxy.js @@ -1,7 +1,7 @@ /* standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server. - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/websocket/standalone-websocket-proxy.js b/examples/websocket/standalone-websocket-proxy.js index e844ab097..a78ecedbc 100644 --- a/examples/websocket/standalone-websocket-proxy.js +++ b/examples/websocket/standalone-websocket-proxy.js @@ -1,7 +1,7 @@ /* standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server. - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 diff --git a/examples/websocket/websocket-proxy.js b/examples/websocket/websocket-proxy.js index 767f58c00..dfd46e064 100644 --- a/examples/websocket/websocket-proxy.js +++ b/examples/websocket/websocket-proxy.js @@ -1,7 +1,7 @@ /* web-socket-proxy.js: Example of proxying over HTTP and WebSockets. - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & Marak Squires. + 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 From 2142c506e08f56d52e1995da5506c3e032f19c3c Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 27 Nov 2013 09:42:56 -0500 Subject: [PATCH 204/556] [examples] add example of gzip using the connect.compress() middleware --- examples/middleware/gzip-middleware.js | 65 ++++++++++++++++++++++++++ examples/package.json | 3 +- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 examples/middleware/gzip-middleware.js diff --git a/examples/middleware/gzip-middleware.js b/examples/middleware/gzip-middleware.js new file mode 100644 index 000000000..ec8725940 --- /dev/null +++ b/examples/middleware/gzip-middleware.js @@ -0,0 +1,65 @@ +/* + 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(8000); + +// +// Basic HTTP Proxy +// +var proxy = httpProxy.createProxyServer({ + target: 'http://localhost:9000' +}); + +// +// 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(9000); + +util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); +util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/package.json b/examples/package.json index be054638e..7db2ae68a 100644 --- a/examples/package.json +++ b/examples/package.json @@ -5,6 +5,7 @@ "dependencies": { "colors": "~0.6.2", "socket.io": "~0.9.16", - "socket.io-client": "~0.9.16" + "socket.io-client": "~0.9.16", + "connect": "~2.11.0" } } From de3ff11656b4a847de3a63b28feed39b6c816480 Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 27 Nov 2013 09:56:35 -0500 Subject: [PATCH 205/556] [examples] updated the modifyResponse-middleware example --- examples/middleware/gzip-middleware.js | 2 +- .../middleware/modifyResponse-middleware.js | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 examples/middleware/modifyResponse-middleware.js diff --git a/examples/middleware/gzip-middleware.js b/examples/middleware/gzip-middleware.js index ec8725940..ee32e445b 100644 --- a/examples/middleware/gzip-middleware.js +++ b/examples/middleware/gzip-middleware.js @@ -46,7 +46,7 @@ connect.createServer( ).listen(8000); // -// Basic HTTP Proxy +// Basic Http Proxy Server // var proxy = httpProxy.createProxyServer({ target: 'http://localhost:9000' diff --git a/examples/middleware/modifyResponse-middleware.js b/examples/middleware/modifyResponse-middleware.js new file mode 100644 index 000000000..c4a59a2f0 --- /dev/null +++ b/examples/middleware/modifyResponse-middleware.js @@ -0,0 +1,67 @@ +/* + 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(8000); + +// +// Basic Http Proxy Server +// +var proxy = httpProxy.createProxyServer({ + target: 'http://localhost:9000' +}); + +// +// Target Http Server +// +http.createServer(function (req, res) { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('Hello, I know Ruby\n'); +}).listen(9000); + +util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); +util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); + From d7064f2e1e149fe870cbb158932cb99f9f192fce Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 27 Nov 2013 16:35:38 -0500 Subject: [PATCH 206/556] [examples] added error-handling using callbacks and HTTP-to-HTTPS examples --- examples/http/error-handling.js | 63 ++++++++++++++++++++++++++++ examples/http/proxy-http-to-https.js | 46 ++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 examples/http/error-handling.js create mode 100644 examples/http/proxy-http-to-https.js diff --git a/examples/http/error-handling.js b/examples/http/error-handling.js new file mode 100644 index 000000000..292fb6144 --- /dev/null +++ b/examples/http/error-handling.js @@ -0,0 +1,63 @@ +/* + 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); diff --git a/examples/http/proxy-http-to-https.js b/examples/http/proxy-http-to-https.js new file mode 100644 index 000000000..ffaa6fa04 --- /dev/null +++ b/examples/http/proxy-http-to-https.js @@ -0,0 +1,46 @@ +/* + 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(8000); + +util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); \ No newline at end of file From c82ff2c3c0c0165421fbc4e7e94fa3f59d59aa38 Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 27 Nov 2013 17:02:06 -0500 Subject: [PATCH 207/556] [examples] updated bodyDecoder middleware example --- examples/helpers/store.js | 64 ++++++++++ examples/middleware/bodyDecoder-middleware.js | 119 ++++++++++++++++++ examples/package.json | 4 +- 3 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 examples/helpers/store.js create mode 100644 examples/middleware/bodyDecoder-middleware.js diff --git a/examples/helpers/store.js b/examples/helpers/store.js new file mode 100644 index 000000000..e2860573f --- /dev/null +++ b/examples/helpers/store.js @@ -0,0 +1,64 @@ + +// +// 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}) + }) + } + } + } +} diff --git a/examples/middleware/bodyDecoder-middleware.js b/examples/middleware/bodyDecoder-middleware.js new file mode 100644 index 000000000..555c3d154 --- /dev/null +++ b/examples/middleware/bodyDecoder-middleware.js @@ -0,0 +1,119 @@ +/* + 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 diff --git a/examples/package.json b/examples/package.json index 7db2ae68a..3daede1f1 100644 --- a/examples/package.json +++ b/examples/package.json @@ -6,6 +6,8 @@ "colors": "~0.6.2", "socket.io": "~0.9.16", "socket.io-client": "~0.9.16", - "connect": "~2.11.0" + "connect": "~2.11.0", + "request": "~2.27.0", + "connect-restreamer": "~1.0.0" } } From bc236d7e95ef10bc17cf551eea2cd2fb9bf265eb Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 27 Nov 2013 17:58:00 -0500 Subject: [PATCH 208/556] [tests] Added a test case for run all the examples * I changed all the ports across examples to be different and can run at same time --- .../simple-balancer-with-websockets.js | 2 +- examples/balancer/simple-balancer.js | 2 +- examples/http/basic-proxy.js | 10 +-- examples/http/concurrent-proxy.js | 10 +-- examples/http/custom-proxy-error.js | 6 +- examples/http/forward-and-target-proxy.js | 16 ++--- examples/http/forward-proxy.js | 10 +-- examples/http/latent-proxy.js | 10 +-- examples/http/proxy-http-to-https.js | 4 +- examples/http/proxy-https-to-http.js | 10 +-- examples/http/proxy-https-to-https.js | 10 +-- examples/http/standalone-proxy.js | 10 +-- examples/middleware/gzip-middleware.js | 10 +-- .../middleware/modifyResponse-middleware.js | 10 +-- examples/websocket/latent-websocket-proxy.js | 8 +-- .../websocket/standalone-websocket-proxy.js | 8 +-- examples/websocket/websocket-proxy.js | 6 +- package.json | 3 +- test/examples-test.js | 71 +++++++++++++++++++ 19 files changed, 144 insertions(+), 72 deletions(-) create mode 100644 test/examples-test.js diff --git a/examples/balancer/simple-balancer-with-websockets.js b/examples/balancer/simple-balancer-with-websockets.js index b17afc772..cc13f4b5c 100644 --- a/examples/balancer/simple-balancer-with-websockets.js +++ b/examples/balancer/simple-balancer-with-websockets.js @@ -80,5 +80,5 @@ server.on('upgrade', function (req, socket, head) { nextProxy().ws(req, socket, head); }); -server.listen(8080); +server.listen(8001); \ No newline at end of file diff --git a/examples/balancer/simple-balancer.js b/examples/balancer/simple-balancer.js index 80b91760c..3f53cc63d 100644 --- a/examples/balancer/simple-balancer.js +++ b/examples/balancer/simple-balancer.js @@ -59,6 +59,6 @@ http.createServer(function (req, res) { // ...and then the server you just used becomes the last item in the list. // addresses.push(target); -}).listen(8000); +}).listen(8021); // Rinse; repeat; enjoy. \ No newline at end of file diff --git a/examples/http/basic-proxy.js b/examples/http/basic-proxy.js index 640318c11..e9be0d79b 100644 --- a/examples/http/basic-proxy.js +++ b/examples/http/basic-proxy.js @@ -44,8 +44,8 @@ util.puts(welcome.rainbow.bold); // Basic Http Proxy Server // httpProxy.createServer({ - target:'http://localhost:9000' -}).listen(8000); + target:'http://localhost:9003' +}).listen(8003); // // Target Http Server @@ -54,7 +54,7 @@ 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(9000); +}).listen(9003); -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); +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); diff --git a/examples/http/concurrent-proxy.js b/examples/http/concurrent-proxy.js index 5ca1054b8..30aa53dd6 100644 --- a/examples/http/concurrent-proxy.js +++ b/examples/http/concurrent-proxy.js @@ -33,8 +33,8 @@ var util = require('util'), // Basic Http Proxy Server // httpProxy.createServer({ - target:'http://localhost:9000' -}).listen(8000); + target:'http://localhost:9004' +}).listen(8004); // // Target Http Server @@ -62,7 +62,7 @@ http.createServer(function (req, res) { connections.shift()(); } } -}).listen(9000); +}).listen(9004); -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); +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); diff --git a/examples/http/custom-proxy-error.js b/examples/http/custom-proxy-error.js index dd62273a7..1c54b5ab8 100644 --- a/examples/http/custom-proxy-error.js +++ b/examples/http/custom-proxy-error.js @@ -33,13 +33,13 @@ var util = require('util'), // Http Proxy Server with bad target // var proxy = httpProxy.createServer({ - target:'http://localhost:9000' + target:'http://localhost:9005' }); // // Tell the proxy to listen on port 8000 // -proxy.listen(8000); +proxy.listen(8005); // // Listen for the `error` event on `proxy`. @@ -52,4 +52,4 @@ proxy.on('error', function (err, req, res) { }); -util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow + 'with custom error message'.magenta.underline); \ No newline at end of file +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 diff --git a/examples/http/forward-and-target-proxy.js b/examples/http/forward-and-target-proxy.js index 0d5acd1f6..c564bfbbd 100644 --- a/examples/http/forward-and-target-proxy.js +++ b/examples/http/forward-and-target-proxy.js @@ -34,14 +34,14 @@ var util = require('util'), // httpProxy.createServer({ target: { - port: 9000, + port: 9006, host: 'localhost' }, forward: { - port: 9001, + port: 9007, host: 'localhost' } -}).listen(8000); +}).listen(8006); // // Target Http Server @@ -50,7 +50,7 @@ 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(9000); +}).listen(9006); // // Target Http Forwarding Server @@ -60,8 +60,8 @@ http.createServer(function (req, res) { 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(9001); +}).listen(9007); -util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow + 'with forward proxy'.magenta.underline); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); -util.puts('http forward server '.blue + 'started '.green.bold + 'on port '.blue + '9001 '.yellow); \ No newline at end of file +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 diff --git a/examples/http/forward-proxy.js b/examples/http/forward-proxy.js index 5f93c49f6..d94f48414 100644 --- a/examples/http/forward-proxy.js +++ b/examples/http/forward-proxy.js @@ -34,10 +34,10 @@ var util = require('util'), // httpProxy.createServer({ forward: { - port: 9000, + port: 9019, host: 'localhost' } -}).listen(8000); +}).listen(8019); // // Target Http Forwarding Server @@ -47,7 +47,7 @@ http.createServer(function (req, res) { 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(9000); +}).listen(9019); -util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow + 'with forward proxy'.magenta.underline); -util.puts('http forward server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); \ No newline at end of file +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 diff --git a/examples/http/latent-proxy.js b/examples/http/latent-proxy.js index 85de6338f..01ec93cc7 100644 --- a/examples/http/latent-proxy.js +++ b/examples/http/latent-proxy.js @@ -36,10 +36,10 @@ var proxy = httpProxy.createProxyServer(); http.createServer(function (req, res) { setTimeout(function () { proxy.web(req, res, { - target: 'http://localhost:9000' + target: 'http://localhost:9008' }); }, 500); -}).listen(8000); +}).listen(8008); // // Target Http Server @@ -48,7 +48,7 @@ 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(9000); +}).listen(9008); -util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow + 'with latency'.magenta.underline); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); +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); diff --git a/examples/http/proxy-http-to-https.js b/examples/http/proxy-http-to-https.js index ffaa6fa04..ba5c83816 100644 --- a/examples/http/proxy-http-to-https.js +++ b/examples/http/proxy-http-to-https.js @@ -41,6 +41,6 @@ httpProxy.createProxyServer({ headers: { host: 'google.com' } -}).listen(8000); +}).listen(8011); -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); \ No newline at end of file +util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8011'.yellow); \ No newline at end of file diff --git a/examples/http/proxy-https-to-http.js b/examples/http/proxy-https-to-http.js index 1b6ac92bd..d2a2d5c0d 100644 --- a/examples/http/proxy-https-to-http.js +++ b/examples/http/proxy-https-to-http.js @@ -40,7 +40,7 @@ http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('hello http over https\n'); res.end(); -}).listen(9000); +}).listen(9009); // // Create the HTTPS proxy server listening on port 8000 @@ -48,13 +48,13 @@ http.createServer(function (req, res) { httpProxy.createServer({ target: { host: 'localhost', - port: 9000 + port: 9009 }, ssl: { key: fs.readFileSync(path.join(fixturesDir, 'agent2-key.pem'), 'utf8'), cert: fs.readFileSync(path.join(fixturesDir, 'agent2-cert.pem'), 'utf8') } -}).listen(8000); +}).listen(8009); -util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); +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); diff --git a/examples/http/proxy-https-to-https.js b/examples/http/proxy-https-to-https.js index f0d06e8e4..e543f98a7 100644 --- a/examples/http/proxy-https-to-https.js +++ b/examples/http/proxy-https-to-https.js @@ -44,16 +44,16 @@ https.createServer(httpsOpts, function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('hello https\n'); res.end(); -}).listen(9000); +}).listen(9010); // // Create the proxy server listening on port 443 // httpProxy.createServer({ ssl: httpsOpts, - target: 'https://localhost:9000', + target: 'https://localhost:9010', secure: false -}).listen(8000); +}).listen(8010); -util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('https server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); +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); diff --git a/examples/http/standalone-proxy.js b/examples/http/standalone-proxy.js index 7fc97b3d7..410d70b31 100644 --- a/examples/http/standalone-proxy.js +++ b/examples/http/standalone-proxy.js @@ -36,10 +36,10 @@ var proxy = new httpProxy.createProxyServer(); http.createServer(function (req, res) { setTimeout(function () { proxy.web(req, res, { - target: 'http://localhost:9000' + target: 'http://localhost:9002' }); }, 200); -}).listen(8000); +}).listen(8002); // // Target Http Server @@ -48,7 +48,7 @@ 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(9000); +}).listen(9002); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow + 'with proxy.web() handler'.cyan.underline + ' and latency'.magenta); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); +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); diff --git a/examples/middleware/gzip-middleware.js b/examples/middleware/gzip-middleware.js index ee32e445b..756b68fa3 100644 --- a/examples/middleware/gzip-middleware.js +++ b/examples/middleware/gzip-middleware.js @@ -43,13 +43,13 @@ connect.createServer( function (req, res) { proxy.web(req, res); } -).listen(8000); +).listen(8012); // // Basic Http Proxy Server // var proxy = httpProxy.createProxyServer({ - target: 'http://localhost:9000' + target: 'http://localhost:9012' }); // @@ -59,7 +59,7 @@ 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(9000); +}).listen(9012); -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); +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); diff --git a/examples/middleware/modifyResponse-middleware.js b/examples/middleware/modifyResponse-middleware.js index c4a59a2f0..fdd7e6596 100644 --- a/examples/middleware/modifyResponse-middleware.js +++ b/examples/middleware/modifyResponse-middleware.js @@ -45,13 +45,13 @@ connect.createServer( function (req, res) { proxy.web(req, res); } -).listen(8000); +).listen(8013); // // Basic Http Proxy Server // var proxy = httpProxy.createProxyServer({ - target: 'http://localhost:9000' + target: 'http://localhost:9013' }); // @@ -60,8 +60,8 @@ var proxy = httpProxy.createProxyServer({ http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello, I know Ruby\n'); -}).listen(9000); +}).listen(9013); -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); +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); diff --git a/examples/websocket/latent-websocket-proxy.js b/examples/websocket/latent-websocket-proxy.js index a80a16edd..64d3d7ce0 100644 --- a/examples/websocket/latent-websocket-proxy.js +++ b/examples/websocket/latent-websocket-proxy.js @@ -43,7 +43,7 @@ catch (ex) { // Create the target HTTP server and setup // socket.io on it. // -var server = io.listen(9000); +var server = io.listen(9016); server.sockets.on('connection', function (client) { util.debug('Got websocket connection'); @@ -60,7 +60,7 @@ server.sockets.on('connection', function (client) { var proxy = new httpProxy.createProxyServer({ target: { host: 'localhost', - port: 9000 + port: 9016 } }); @@ -78,12 +78,12 @@ proxyServer.on('upgrade', function (req, socket, head) { }, 1000); }); -proxyServer.listen(8000); +proxyServer.listen(8016); // // Setup the socket.io client against our proxy // -var ws = client.connect('ws://localhost:8000'); +var ws = client.connect('ws://localhost:8016'); ws.on('message', function (msg) { util.debug('Got message: ' + msg); diff --git a/examples/websocket/standalone-websocket-proxy.js b/examples/websocket/standalone-websocket-proxy.js index a78ecedbc..81d019650 100644 --- a/examples/websocket/standalone-websocket-proxy.js +++ b/examples/websocket/standalone-websocket-proxy.js @@ -43,7 +43,7 @@ catch (ex) { // Create the target HTTP server and setup // socket.io on it. // -var server = io.listen(9000); +var server = io.listen(9015); server.sockets.on('connection', function (client) { util.debug('Got websocket connection'); @@ -60,7 +60,7 @@ server.sockets.on('connection', function (client) { var proxy = new httpProxy.createProxyServer({ target: { host: 'localhost', - port: 9000 + port: 9015 } }); var proxyServer = http.createServer(function (req, res) { @@ -75,12 +75,12 @@ proxyServer.on('upgrade', function (req, socket, head) { proxy.ws(req, socket, head); }); -proxyServer.listen(8000); +proxyServer.listen(8015); // // Setup the socket.io client against our proxy // -var ws = client.connect('ws://localhost:8000'); +var ws = client.connect('ws://localhost:8015'); ws.on('message', function (msg) { util.debug('Got message: ' + msg); diff --git a/examples/websocket/websocket-proxy.js b/examples/websocket/websocket-proxy.js index dfd46e064..33d78c675 100644 --- a/examples/websocket/websocket-proxy.js +++ b/examples/websocket/websocket-proxy.js @@ -43,7 +43,7 @@ catch (ex) { // Create the target HTTP server and setup // socket.io on it. // -var server = io.listen(9000); +var server = io.listen(9014); server.sockets.on('connection', function (client) { util.debug('Got websocket connection'); @@ -57,12 +57,12 @@ server.sockets.on('connection', function (client) { // // Create a proxy server with node-http-proxy // -httpProxy.createServer({ target: 'ws://localhost:9000', ws: true }).listen(8000); +httpProxy.createServer({ target: 'ws://localhost:9014', ws: true }).listen(8014); // // Setup the socket.io client against our proxy // -var ws = client.connect('ws://localhost:8000'); +var ws = client.connect('ws://localhost:8014'); ws.on('message', function (msg) { util.debug('Got message: ' + msg); diff --git a/package.json b/package.json index 98cd9b5d4..5c7c3a1eb 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "blanket" : "*", "ws" : "*", "socket.io" : "*", - "socket.io-client" : "*" + "socket.io-client" : "*", + "async" : "*" }, "scripts" : { "coveralls" : "mocha --require blanket --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js", diff --git a/test/examples-test.js b/test/examples-test.js new file mode 100644 index 000000000..234587bcb --- /dev/null +++ b/test/examples-test.js @@ -0,0 +1,71 @@ +/* + 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('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 From d83fdf69a1121bfcfba72bbffcd3105ae5852c56 Mon Sep 17 00:00:00 2001 From: cronopio Date: Mon, 9 Dec 2013 12:34:28 -0500 Subject: [PATCH 209/556] [tests] disabled the examples-test by now --- test/examples-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/examples-test.js b/test/examples-test.js index 234587bcb..8464e3fe5 100644 --- a/test/examples-test.js +++ b/test/examples-test.js @@ -13,7 +13,7 @@ var path = require('path'), var rootDir = path.join(__dirname, '..'), examplesDir = path.join(rootDir, 'examples'); -describe('http-proxy examples', function () { +describe.skip('http-proxy examples', function () { describe('Before testing examples', function () { // Set a timeout to avoid this error this.timeout(30 * 1000); From e2a5d513cac3ebceff446787fa106c7f00caf785 Mon Sep 17 00:00:00 2001 From: cronopio Date: Wed, 18 Dec 2013 11:19:17 -0500 Subject: [PATCH 210/556] Set travis to run `npm test` while we fix coveralss.io integration --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d7eeacc3f..ba5be4174 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,4 +9,4 @@ notifications: irc: "irc.freenode.org#nodejitsu" script: - npm run-script coveralls + npm test From db12f6c24e22c034c698457cc28ff60c990b55a5 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 20 Dec 2013 20:22:40 +0100 Subject: [PATCH 211/556] [docs] add UPGRADING.md --- README.md | 2 ++ UPGRADING.md | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 UPGRADING.md diff --git a/README.md b/README.md index ed25eb240..4c6f95751 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ proxies and load balancers.

+## Looking to Upgrade from 0.8.x ? Click [here](UPGRADING.md) + ### Core Concept A new proxy is created by calling `createProxyServer` and passing diff --git a/UPGRADING.md b/UPGRADING.md new file mode 100644 index 000000000..8fb525c61 --- /dev/null +++ b/UPGRADING.md @@ -0,0 +1,26 @@ +`caronte` is a from-scratch implementation of `http-proxy` and, as such +brings some breaking changes to APIs. + +## Server creation + +Available through `.createServer()` or `.createProxyServer()`. +Check the README.md for a more detailed explanation of the parameters. + +## Proxying + +Web proying is done by calling the `.web()` method on a Proxy instance. Websockets +are proxied by the `.ws()` method. + +## 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. + +## 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 "user-land" modules. + +- Middleware API +- ProxyTable API + From 9243444ac006f73c00b0f1f78c4a77f342b0b4e4 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 20 Dec 2013 20:24:49 +0100 Subject: [PATCH 212/556] fix docs --- CHANGELOG.md | 4 ++++ README.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..21d6bb03c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +### v 1.0.0-alpha + +- Complete refactor with new API + diff --git a/README.md b/README.md index 4c6f95751..3ec4ed54d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ proxies and load balancers.

-## Looking to Upgrade from 0.8.x ? Click [here](UPGRADING.md) +### Looking to Upgrade from 0.8.x ? Click [here](UPGRADING.md) ### Core Concept From 162a42f58f515c5418ccfac0b68f4c928103b1e1 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 20 Dec 2013 21:33:49 +0100 Subject: [PATCH 213/556] [fix] legacy --- lib/http-proxy/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index c02735b02..eb1c5dddb 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -85,8 +85,8 @@ function createRightProxy(type) { function ProxyServer(options) { EE3.call(this); - this.web = createRightProxy('web')(options); - this.ws = createRightProxy('ws')(options); + 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) { From 781c038f2b4d14a01cc9297e1e0dba6ce39dd6cb Mon Sep 17 00:00:00 2001 From: Jan Jongboom Date: Sun, 15 Sep 2013 11:38:50 +0200 Subject: [PATCH 214/556] Fix for #458. Host header may cause some sites not to be proxyable with changeOrigin enabled --- lib/node-http-proxy/http-proxy.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index 50eb88a46..890b6b04a 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -237,7 +237,14 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { // don't revert this without documenting it! // if (this.changeOrigin) { - outgoing.headers.host = this.target.host + ':' + this.target.port; + outgoing.headers.host = this.target.host; + // Only add port information to the header if not default port + // for this protocol. + // See https://github.com/nodejitsu/node-http-proxy/issues/458 + if (this.target.port !== 443 && this.target.https || + this.target.port !== 80 && !this.target.https) { + outgoing.headers.host += ':' + this.target.port; + } } // From bc12ca39394f9aeed3e3047f59035ba48afa2885 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 10 Sep 2013 15:16:06 +0100 Subject: [PATCH 215/556] Emit middlewareError when on middleware error. Now it's possible to pass an Error object to next() and have it handled in a custom way that's suitable to your application. --- lib/node-http-proxy.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/node-http-proxy.js b/lib/node-http-proxy.js index 956a5f3d3..c1275ab39 100644 --- a/lib/node-http-proxy.js +++ b/lib/node-http-proxy.js @@ -294,6 +294,10 @@ exports.stack = function stack (middlewares, proxy) { handle = function (req, res) { var next = function (err) { if (err) { + if (! proxy.emit('middlewareError', err, res, req)) { + console.error('Error in middleware(s): %s', err.stack); + } + if (res._headerSent) { res.destroy(); } @@ -303,7 +307,6 @@ exports.stack = function stack (middlewares, proxy) { res.end('Internal Server Error'); } - console.error('Error in middleware(s): %s', err.stack); return; } From 25bb3bfa7012e0f975e10f0311cae8c39183fa41 Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 10 Sep 2013 15:17:52 +0100 Subject: [PATCH 216/556] Update the README to describe middleware err handler. --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index bf19ceabb..2b4d44259 100644 --- a/README.md +++ b/README.md @@ -441,6 +441,17 @@ A regular request we receive is to support the modification of html/xml content [Harmon](https://github.com/No9/harmon/) is a stream based middleware plugin that is designed to solve that problem in the most effective way possible. +If you would like to handle errors passed to `next()` then attach a listener to the proxy: + + server = httpProxy.createServer( + myMiddleWare, + 9000, 'localhost' + ).listen(8000); + + server.proxy.on('middlewareError', function (err, res, req) { + // handle the error here and call res.end() + }); + ## Proxying WebSockets Websockets are handled automatically when using `httpProxy.createServer()`, however, if you supply a callback inside the createServer call, you will need to handle the 'upgrade' proxy event yourself. Here's how: From 7c8ecc8ea85b59fc16b55b9a142372b6ac168b2a Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 10 Sep 2013 23:41:09 +0100 Subject: [PATCH 217/556] Put the arguments the right way around in emitter. --- lib/node-http-proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/node-http-proxy.js b/lib/node-http-proxy.js index c1275ab39..b5de6bb66 100644 --- a/lib/node-http-proxy.js +++ b/lib/node-http-proxy.js @@ -294,7 +294,7 @@ exports.stack = function stack (middlewares, proxy) { handle = function (req, res) { var next = function (err) { if (err) { - if (! proxy.emit('middlewareError', err, res, req)) { + if (! proxy.emit('middlewareError', err, req, res)) { console.error('Error in middleware(s): %s', err.stack); } From 145798062e332ac2aed7f8e8e3240e38464c870a Mon Sep 17 00:00:00 2001 From: Phil Jackson Date: Tue, 10 Sep 2013 23:42:41 +0100 Subject: [PATCH 218/556] Put the arguments the right way around in the README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b4d44259..594d02ad1 100644 --- a/README.md +++ b/README.md @@ -448,7 +448,7 @@ If you would like to handle errors passed to `next()` then attach a listener to 9000, 'localhost' ).listen(8000); - server.proxy.on('middlewareError', function (err, res, req) { + server.proxy.on('middlewareError', function (err, req, res) { // handle the error here and call res.end() }); From 8332e744202ed9de94288d8f1c822cd9fe788983 Mon Sep 17 00:00:00 2001 From: Sam Alba Date: Thu, 21 Mar 2013 16:44:32 -0700 Subject: [PATCH 219/556] Prevent headers to be sent twice --- lib/node-http-proxy/http-proxy.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index 890b6b04a..e4a0c86f5 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -333,10 +333,12 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { } // Set the headers of the client response - Object.keys(response.headers).forEach(function (key) { - res.setHeader(key, response.headers[key]); - }); - res.writeHead(response.statusCode); + if (res.sentHeaders !== true) { + Object.keys(response.headers).forEach(function (key) { + res.setHeader(key, response.headers[key]); + }); + res.writeHead(response.statusCode); + } function ondata(chunk) { if (res.writable) { From 7e8041d2b687b8375a1d0fe45270029c6e8ddee6 Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 26 Dec 2013 23:50:19 -0800 Subject: [PATCH 220/556] [dist minor] 2 space indents next time @samalba --- lib/node-http-proxy/http-proxy.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index e4a0c86f5..494b8a9ed 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -239,7 +239,7 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { if (this.changeOrigin) { outgoing.headers.host = this.target.host; // Only add port information to the header if not default port - // for this protocol. + // for this protocol. // See https://github.com/nodejitsu/node-http-proxy/issues/458 if (this.target.port !== 443 && this.target.https || this.target.port !== 80 && !this.target.https) { @@ -334,10 +334,10 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { // Set the headers of the client response if (res.sentHeaders !== true) { - Object.keys(response.headers).forEach(function (key) { - res.setHeader(key, response.headers[key]); - }); - res.writeHead(response.statusCode); + Object.keys(response.headers).forEach(function (key) { + res.setHeader(key, response.headers[key]); + }); + res.writeHead(response.statusCode); } function ondata(chunk) { From d4e91ebc33292a6da9057b7cb93443f10250481e Mon Sep 17 00:00:00 2001 From: blahed Date: Tue, 14 May 2013 03:10:11 -0400 Subject: [PATCH 221/556] determine x-forwarded-port from host header `req.remotePort' returns the ephemeral port, which is not useful. node v0.10.0 added `req.localPort' which returns what we want, but we want to maintain backwards compatibility. Fixes #341 & #227 --- lib/node-http-proxy/http-proxy.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index 494b8a9ed..f453db855 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -149,11 +149,11 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { } if (req.headers['x-forwarded-port']) { - var portToAppend = "," + req.connection.remotePort || req.socket.remotePort; + var portToAppend = "," + getPortFromHostHeader(req); req.headers['x-forwarded-port'] += portToAppend; } else { - req.headers['x-forwarded-port'] = req.connection.remotePort || req.socket.remotePort; + req.headers['x-forwarded-port'] = getPortFromHostHeader(req); } if (req.headers['x-forwarded-proto']) { @@ -489,11 +489,11 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, } if (req.headers['x-forwarded-port']) { - var portToAppend = "," + req.connection.remotePort || socket.remotePort; + var portToAppend = "," + getPortFromHostHeader(req); req.headers['x-forwarded-port'] += portToAppend; } else { - req.headers['x-forwarded-port'] = req.connection.remotePort || socket.remotePort; + req.headers['x-forwarded-port'] = getPortFromHostHeader(req); } if (req.headers['x-forwarded-proto']) { @@ -956,6 +956,17 @@ HttpProxy.prototype._forwardRequest = function (req) { }); }; +function getPortFromHostHeader(req) { + var portMatch = req.headers.host.match(/:(\d+)$/); + + if(portMatch) { + return parseInt(portMatch[1]); + } + else { + return getProto(req) === 'https' ? 443 : 80; + } +} + function getProto(req) { return req.isSpdy ? 'https' : (req.connection.pair ? 'https' : 'http'); } From 2d42709c3283637de16a49e815b03e63432bbd29 Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 26 Dec 2013 23:59:48 -0800 Subject: [PATCH 222/556] [fix] Optimize fix for `x-forwarded-for-port`. --- lib/node-http-proxy/http-proxy.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index f453db855..43a64894f 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -30,6 +30,13 @@ var events = require('events'), url = require('url'), httpProxy = require('../node-http-proxy'); +// +// @private {RegExp} extractPort +// Reusable regular expression for getting the +// port from a host string. +// +var extractPort = /:(\d+)$/; + // // ### function HttpProxy (options) // #### @options {Object} Options for this instance. @@ -957,14 +964,12 @@ HttpProxy.prototype._forwardRequest = function (req) { }; function getPortFromHostHeader(req) { - var portMatch = req.headers.host.match(/:(\d+)$/); - - if(portMatch) { - return parseInt(portMatch[1]); - } - else { - return getProto(req) === 'https' ? 443 : 80; + var match; + if ((match = extractPort.exec(req.headers.host))) { + return parseInt(match[1]); } + + return getProto(req) === 'https' ? 443 : 80; } function getProto(req) { From 1333c0cc62e7b590843f9b00326fe80137163c5e Mon Sep 17 00:00:00 2001 From: vinodsr Date: Fri, 31 May 2013 06:49:27 +0530 Subject: [PATCH 223/556] added unlimited listeners to the reverproxy event obj. --- lib/node-http-proxy/http-proxy.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index 43a64894f..6590ed9d1 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -371,6 +371,10 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { res.on('drain', ondrain); }); + + // allow unlimited listeners ... + reverseProxy.setMaxListeners(0); + // // Handle 'error' events from the `reverseProxy`. Setup timeout override if needed // From 8eb6780f8705caff13a5375446539b0621d497d7 Mon Sep 17 00:00:00 2001 From: vinodsr Date: Fri, 31 May 2013 07:02:32 +0530 Subject: [PATCH 224/556] added option for eventlistenerCount(max) --- lib/node-http-proxy/http-proxy.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js index 6590ed9d1..92541baec 100644 --- a/lib/node-http-proxy/http-proxy.js +++ b/lib/node-http-proxy/http-proxy.js @@ -103,6 +103,9 @@ var HttpProxy = exports.HttpProxy = function (options) { ? this.enable.xforward : true; + // if event listener is set then use it else unlimited. + this.eventListenerCount = typeof options.eventListenerCount === 'number'? options.eventListenerCount : 0 ; + // // Setup additional options for WebSocket proxying. When forcing // the WebSocket handshake to change the `sec-websocket-location` @@ -371,10 +374,9 @@ HttpProxy.prototype.proxyRequest = function (req, res, buffer) { res.on('drain', ondrain); }); - // allow unlimited listeners ... - reverseProxy.setMaxListeners(0); - + reverseProxy.setMaxListeners(this.eventListenerCount); + // // Handle 'error' events from the `reverseProxy`. Setup timeout override if needed // From a81dd8d53e1595cba9acf5cc3ca9517165dcc4aa Mon Sep 17 00:00:00 2001 From: indexzero Date: Fri, 27 Dec 2013 00:04:25 -0800 Subject: [PATCH 225/556] [dist] Bump dependencies. --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index a2c31a02a..cc23d4ee0 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,9 @@ ], "dependencies": { "colors": "0.x.x", - "optimist": "0.3.x", - "pkginfo": "0.2.x", - "utile": "~0.1.7" + "optimist": "0.6.x", + "pkginfo": "0.3.x", + "utile": "~0.2.1" }, "devDependencies": { "request": "2.14.x", From 840f6d8d29dffc11d3726123c2d400940ca2bdda Mon Sep 17 00:00:00 2001 From: indexzero Date: Fri, 27 Dec 2013 00:05:18 -0800 Subject: [PATCH 226/556] [dist] Version bump. 0.10.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cc23d4ee0..cd3ff0add 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "0.10.3", + "version": "0.10.4", "description": "A full-featured http reverse proxy for node.js", "author": "Nodejitsu Inc. ", "maintainers": [ From e5991519dbc7838aa4b8aeb5077d1c1ec5a13813 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 27 Dec 2013 23:38:48 +0100 Subject: [PATCH 227/556] [docs] upgrade UPGRADING.md --- UPGRADING.md | 80 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/UPGRADING.md b/UPGRADING.md index 8fb525c61..8c0db431c 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,26 +1,96 @@ -`caronte` is a from-scratch implementation of `http-proxy` and, as such +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()`. -Check the README.md for a more detailed explanation of the parameters. + +```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. Websockets -are proxied by the `.ws()` method. +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 "user-land" modules. +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) + + + From 182c76cd2322d4d4c041c2a964d51db396c5c96b Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Fri, 27 Dec 2013 19:01:28 -0500 Subject: [PATCH 228/556] [api] export the httpProxy.Server as the main export but preserve the createServer factory --- lib/http-proxy.js | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 36589b39f..f59aca8b4 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -1,8 +1,14 @@ var http = require('http'), https = require('https'), url = require('url'), - httpProxy = require('./http-proxy/'), - proxy = exports; + httpProxy = require('./http-proxy/'); + +/** + * Export the "Server" so we can have an intuitive api for just creating + * a proxy + * + */ +module.exports = httpProxy.Server; /** * Creates the proxy server. @@ -19,23 +25,23 @@ var http = require('http'), * @api public */ -proxy.createProxyServer = proxy.createServer = function createProxyServer(options) { +module.exports.createProxyServer = module.exports.createServer = function createProxyServer(options) { /* * `options` is needed and it must have the following layout: - * - * { - * target : - * forward: - * agent : - * ssl : + * + * { + * target : + * forward: + * agent : + * ssl : * ws : - * xfwd : + * xfwd : * secure : - * } - * - * NOTE: `options.ws` and `options.ssl` are optional. - * `options.target and `options.forward` cannot be - * both missing + * } + * + * NOTE: `options.ws` and `options.ssl` are optional. + * `options.target and `options.forward` cannot be + * both missing * } */ From 6fa23e11f6dc0b9c09766b268611ade919bfaa08 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Fri, 27 Dec 2013 19:04:44 -0500 Subject: [PATCH 229/556] [fix] comments --- lib/http-proxy.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index f59aca8b4..196dded44 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -4,9 +4,7 @@ var http = require('http'), httpProxy = require('./http-proxy/'); /** - * Export the "Server" so we can have an intuitive api for just creating - * a proxy - * + * Export the the proxy "Server" as the main export */ module.exports = httpProxy.Server; From c47adac391ca2f80ac1adad52e4fd652d85ac2a4 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sun, 29 Dec 2013 15:59:33 -0500 Subject: [PATCH 230/556] [fix] add `type` to before and after to grab correct `passes`, fixes #537 --- lib/http-proxy/index.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index eb1c5dddb..bd8b8a991 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -117,23 +117,33 @@ ProxyServer.prototype.listen = function(port) { return this; }; -ProxyServer.prototype.before = function(passName, callback) { - var i = false; - this.passes.forEach(function(v, idx) { +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'); - this.passes.splice(i, 0, callback); + passes.splice(i, 0, callback); }; -ProxyServer.prototype.after = function(passName, callback) { - var i = false; - this.passes.forEach(function(v, idx) { +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'); - this.passes.splice(i++, 0, callback); + passes.splice(i++, 0, callback); }; From a4ee8f9d82f71ef423c401b1f5e9f712b13cbc98 Mon Sep 17 00:00:00 2001 From: yawnt Date: Wed, 8 Jan 2014 10:19:06 +0100 Subject: [PATCH 231/556] [nuke] old files --- .gitignore | 3 - .travis.yml | 10 - CHANGELOG.md | 97 -- LICENSE | 23 - README.md | 646 ------------ benchmark/websockets-throughput.js | 88 -- bin/node-http-proxy | 113 -- config.sample.json | 10 - .../simple-balancer-with-websockets.js | 58 -- examples/balancer/simple-balancer.js | 36 - examples/helpers/store.js | 64 -- examples/http/basic-proxy.js | 58 -- examples/http/concurrent-proxy.js | 66 -- examples/http/custom-proxy-error.js | 54 - examples/http/forward-proxy.js | 63 -- examples/http/latent-proxy.js | 56 - examples/http/proxy-https-to-http.js | 51 - examples/http/proxy-https-to-https.js | 55 - examples/http/proxy-table.js | 51 - examples/http/standalone-proxy.js | 57 - examples/middleware/bodyDecoder-middleware.js | 87 -- .../middleware/gzip-middleware-proxytable.js | 54 - examples/middleware/gzip-middleware.js | 50 - examples/middleware/jsonp-middleware.js | 30 - .../middleware/modifyResponse-middleware.js | 57 - examples/middleware/url-middleware.js | 58 -- examples/middleware/url-middleware2.js | 30 - examples/package.json | 12 - examples/websocket/latent-websocket-proxy.js | 92 -- .../websocket/standalone-websocket-proxy.js | 87 -- examples/websocket/websocket-proxy.js | 69 -- lib/node-http-proxy.js | 397 ------- lib/node-http-proxy/http-proxy.js | 983 ------------------ lib/node-http-proxy/proxy-table.js | 282 ----- lib/node-http-proxy/routing-proxy.js | 322 ------ package.json | 47 - test/core/README.md | 10 - test/core/common.js | 190 ---- test/core/pummel/test-http-upload-timeout.js | 69 -- test/core/run | 90 -- test/core/run-single | 70 -- test/core/simple/test-http-chunked.js | 63 -- test/core/simple/test-http-client-abort.js | 80 -- test/core/simple/test-http-client-abort2.js | 41 - .../simple/test-http-client-upload-buf.js | 74 -- test/core/simple/test-http-client-upload.js | 77 -- test/core/simple/test-http-contentLength0.js | 42 - test/core/simple/test-http-eof-on-connect.js | 40 - test/core/simple/test-http-extra-response.js | 86 -- test/core/simple/test-http-head-request.js | 56 - ...test-http-head-response-has-no-body-end.js | 61 -- .../test-http-head-response-has-no-body.js | 58 -- test/core/simple/test-http-host-headers.js | 101 -- .../test-http-many-keep-alive-connections.js | 68 -- .../simple/test-http-multi-line-headers.js | 59 -- test/core/simple/test-http-proxy.js | 109 -- test/core/simple/test-http-response-close.js | 55 - .../simple/test-http-server-multiheaders.js | 59 -- test/core/simple/test-http-set-cookies.js | 84 -- test/core/simple/test-http-status-code.js | 69 -- test/core/simple/test-http-upgrade-server2.js | 72 -- test/core/simple/test-http.js | 108 -- test/examples-test.js | 26 - test/fixtures/agent2-cert.pem | 13 - test/fixtures/agent2-csr.pem | 10 - test/fixtures/agent2-key.pem | 9 - test/fixtures/agent2.cnf | 19 - test/helpers/http.js | 182 ---- test/helpers/index.js | 105 -- test/helpers/ws.js | 112 -- test/http/http-test.js | 102 -- test/http/routing-table-test.js | 107 -- test/macros/examples.js | 101 -- test/macros/http.js | 531 ---------- test/macros/index.js | 11 - test/macros/ws.js | 232 ----- test/ws/routing-table-test.js | 25 - test/ws/socket.io-test.js | 20 - test/ws/ws-test.js | 23 - 79 files changed, 7835 deletions(-) delete mode 100644 .gitignore delete mode 100644 .travis.yml delete mode 100644 CHANGELOG.md delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 benchmark/websockets-throughput.js delete mode 100755 bin/node-http-proxy delete mode 100644 config.sample.json delete mode 100644 examples/balancer/simple-balancer-with-websockets.js delete mode 100644 examples/balancer/simple-balancer.js delete mode 100644 examples/helpers/store.js delete mode 100644 examples/http/basic-proxy.js delete mode 100644 examples/http/concurrent-proxy.js delete mode 100644 examples/http/custom-proxy-error.js delete mode 100644 examples/http/forward-proxy.js delete mode 100644 examples/http/latent-proxy.js delete mode 100644 examples/http/proxy-https-to-http.js delete mode 100644 examples/http/proxy-https-to-https.js delete mode 100644 examples/http/proxy-table.js delete mode 100644 examples/http/standalone-proxy.js delete mode 100644 examples/middleware/bodyDecoder-middleware.js delete mode 100644 examples/middleware/gzip-middleware-proxytable.js delete mode 100644 examples/middleware/gzip-middleware.js delete mode 100644 examples/middleware/jsonp-middleware.js delete mode 100644 examples/middleware/modifyResponse-middleware.js delete mode 100644 examples/middleware/url-middleware.js delete mode 100644 examples/middleware/url-middleware2.js delete mode 100644 examples/package.json delete mode 100644 examples/websocket/latent-websocket-proxy.js delete mode 100644 examples/websocket/standalone-websocket-proxy.js delete mode 100644 examples/websocket/websocket-proxy.js delete mode 100644 lib/node-http-proxy.js delete mode 100644 lib/node-http-proxy/http-proxy.js delete mode 100644 lib/node-http-proxy/proxy-table.js delete mode 100644 lib/node-http-proxy/routing-proxy.js delete mode 100644 package.json delete mode 100644 test/core/README.md delete mode 100644 test/core/common.js delete mode 100644 test/core/pummel/test-http-upload-timeout.js delete mode 100755 test/core/run delete mode 100755 test/core/run-single delete mode 100644 test/core/simple/test-http-chunked.js delete mode 100644 test/core/simple/test-http-client-abort.js delete mode 100644 test/core/simple/test-http-client-abort2.js delete mode 100644 test/core/simple/test-http-client-upload-buf.js delete mode 100644 test/core/simple/test-http-client-upload.js delete mode 100644 test/core/simple/test-http-contentLength0.js delete mode 100644 test/core/simple/test-http-eof-on-connect.js delete mode 100644 test/core/simple/test-http-extra-response.js delete mode 100644 test/core/simple/test-http-head-request.js delete mode 100644 test/core/simple/test-http-head-response-has-no-body-end.js delete mode 100644 test/core/simple/test-http-head-response-has-no-body.js delete mode 100644 test/core/simple/test-http-host-headers.js delete mode 100644 test/core/simple/test-http-many-keep-alive-connections.js delete mode 100644 test/core/simple/test-http-multi-line-headers.js delete mode 100644 test/core/simple/test-http-proxy.js delete mode 100644 test/core/simple/test-http-response-close.js delete mode 100644 test/core/simple/test-http-server-multiheaders.js delete mode 100644 test/core/simple/test-http-set-cookies.js delete mode 100644 test/core/simple/test-http-status-code.js delete mode 100644 test/core/simple/test-http-upgrade-server2.js delete mode 100644 test/core/simple/test-http.js delete mode 100644 test/examples-test.js delete mode 100644 test/fixtures/agent2-cert.pem delete mode 100644 test/fixtures/agent2-csr.pem delete mode 100644 test/fixtures/agent2-key.pem delete mode 100644 test/fixtures/agent2.cnf delete mode 100644 test/helpers/http.js delete mode 100644 test/helpers/index.js delete mode 100644 test/helpers/ws.js delete mode 100644 test/http/http-test.js delete mode 100644 test/http/routing-table-test.js delete mode 100644 test/macros/examples.js delete mode 100644 test/macros/http.js delete mode 100644 test/macros/index.js delete mode 100644 test/macros/ws.js delete mode 100644 test/ws/routing-table-test.js delete mode 100644 test/ws/socket.io-test.js delete mode 100644 test/ws/ws-test.js diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 468b525c9..000000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -config.json -node_modules/ -npm-debug.log diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index efd470846..000000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: node_js -node_js: - - 0.8 - - "0.10" - - "0.11" - -notifications: - email: - - travis@nodejitsu.com - irc: "irc.freenode.org#nodejitsu" diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 2205ee874..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,97 +0,0 @@ -## ChangeLog for: node-http-proxy - -## Version 0.10.0 - 3/18/2013 - -- Breaking change: `proxyResponse` events are emitted on the `HttpProxy` or `RoutingProxy` instances as originally was intended in `0.9.x`. - -## Version 0.9.1 - 3/9/2013 - -- Ensure that `webSocketProxyError` and `proxyError` both receive the error (indexzero). - -## Version 0.9.0 - 3/9/2013 -- Fix #276 Ensure response.headers.location is defined (indexzero) -- Fix #248 Make options immutable in RoutingProxy (indexzero) -- Fix #359 Do not modify the protocol in redirect request for external sites. (indexzero) -- Fix #373 Do not use "Transfer-Encoding: chunked" header for proxied DELETE requests with no "Content-Length" header. (indexzero) -- Fix #338 Set "content-length" header to "0" if it is not already set on DELETE requests. (indexzero) -- Updates to README.md and Examples (ramitos, jamie-stackhouse, oost, indexzero) -- Fixes to ProxyTable and Routing Proxy (adjohnson916, otavoijr) -- New API for ProxyTable (mikkel, tglines) -- Add `options.timeout` for specifying socket timeouts (pdoran) -- Improve bin/node-http-proxy (niallo) -- Don't emit `proxyError` twice (erasmospunk) -- Fix memory leaks in WebSocket proxying -- Support UNIX Sockets (yosefd) -- Fix truncated chunked respones (jpetazzo) -- Allow upstream listeners to get `proxyResponse` (colinmollenhour) - -## Version 0.8.1 - 6/5/2012 -- Fix re-emitting of events in RoutingProxy (coderarity) -- New load balancer and middleware examples (marak) -- Docs updated including changelog (lot of gently people) - -## Version 0.8.0 - 12/23/2011 -- Improve support and tests for url segment routing (maxogden) -- Fix aborting connections when request close (c4milo) -- Avoid 'Transfer-Encoding' on HTTP/1.0 clients (koichik). -- Support for Node.js 0.6.x (mmalecki) - -## Version 0.7.3 - 10/4/2011 -- Fix setting x-forwarded headers (jesusabdullah) -- Updated examples (AvianFlu) - -## Version 0.7.0 - 9/10/2011 -- Handles to every throw-able resume() call (isaacs) -- Updated tests, README and package.json (indexzero) -- Added HttpProxy.close() method (indexzero) - -## Version 0.6.6 - 8/31/2011 -- Add more examples (dominictarr) -- Use of 'pkginfo' (indexzero) -- Handle cases where res.write throws (isaacs) -- Handles to every throw-able res.end call (isaacs) - -## Version 0.5.11 - 6/21/2011 -- Add more examples with WebSockets (indexzero) -- Update the documentation (indexzero) - -## Version 0.5.7 - 5/19/2011 -- Fix to README related to markup and fix some examples (benatkin) -- Improve WebSockets handling (indexzero) -- Improve WebSockets tests (indexzero) -- Improve https tests (olauzon) -- Add devDependencies to package.json (olauzon) -- Add 'proxyError' event (indexzero) -- Add 'x-forwarded-{port|proto}' headers support (indexzero) -- Keep-Alive connection supported (indexzero) - -## Version 0.5.0 - 4/15/2011 -- Remove winston in favor of custom events (indexzero) -- Add x-forwarded-for Header (indexzero) -- Fix WebSocket support (indexzero) -- Add tests / examples for WebSocket support (indexzero) -- Update .proxyRequest() and .proxyWebSocketRequest() APIs (indexzero) -- Add HTTPS support (indexzero) -- Add tests / examples for HTTPS support (indexzero) - -## Version 0.4.1 - 3/20/2011 -- Include missing dependency in package.json (indexzero) - -## Version 0.4.0 - 3/20/2011 -- Update for node.js 0.4.0 (indexzero) -- Remove pool dependency in favor of http.Agent (indexzero) -- Store buffered data using `.buffer()` instead of on the HttpProxy instance (indexzero) -- Change the ProxyTable to be a lookup table instead of actively proxying (indexzero) -- Allow for pure host-only matching in ProxyTable (indexzero) -- Use winston for logging (indexzero) -- Improve tests with async setup and more coverage (indexzero) -- Improve code documentation (indexzero) - -### Version 0.3.1 - 11/22/2010 -- Added node-http-proxy binary script (indexzero) -- Added experimental WebSocket support (indutny) -- Added forward proxy functionality (indexzero) -- Added proxy table for multiple target lookup (indexzero) -- Simplified tests using helpers.js (indexzero) -- Fixed uncaughtException bug with invalid proxy target (indutny) -- Added configurable logging for HttpProxy and ProxyTable (indexzero) \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index db9b0b1ed..000000000 --- a/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ - - node-http-proxy - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 594d02ad1..000000000 --- a/README.md +++ /dev/null @@ -1,646 +0,0 @@ -# node-http-proxy [![Build Status](https://secure.travis-ci.org/nodejitsu/node-http-proxy.png)](http://travis-ci.org/nodejitsu/node-http-proxy) - - - -## Battle-hardened node.js http proxy - -### Features - -* Reverse proxies incoming http.ServerRequest streams -* Can be used as a CommonJS module in node.js -* Reverse or Forward Proxy based on simple JSON-based configuration -* Supports [WebSockets][1] -* Supports [HTTPS][2] -* Minimal request overhead and latency -* Full suite of functional tests -* Battled-hardened through __production usage__ @ [nodejitsu.com][0] -* Written entirely in Javascript -* Easy to use API - - -node-http-proxy is `<= 0.8.x` compatible, if you're looking for a `>= 0.10` compatible version please check [caronte](https://github.com/nodejitsu/node-http-proxy/tree/caronte) - -### 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. - -### Installing npm (node package manager) - -``` -curl https://npmjs.org/install.sh | sh -``` - -### Installing node-http-proxy - -``` -npm install http-proxy -``` - -## Using node-http-proxy - -There are several ways to use node-http-proxy; the library is designed to be flexible so that it can be used by itself, or in conjunction with other node.js libraries / tools: - -1. Standalone HTTP Proxy server -2. Inside of another HTTP server (like Connect) -3. In conjunction with a Proxy Routing Table -4. As a forward-proxy with a reverse proxy -5. From the command-line as a long running process -6. customized with 3rd party middleware. - -In each of these scenarios node-http-proxy can handle any of these types of requests: - -1. HTTP Requests (http://) -2. HTTPS Requests (https://) -3. WebSocket Requests (ws://) -4. Secure WebSocket Requests (wss://) - -See the [examples][3] for more working sample code. - -### Setup a basic stand-alone proxy server - -``` js -var http = require('http'), - httpProxy = require('http-proxy'); -// -// Create your proxy server -// -httpProxy.createServer(9000, 'localhost').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 -var http = require('http'), - httpProxy = require('http-proxy'); - -// -// Create a proxy server with custom application logic -// -httpProxy.createServer(function (req, res, proxy) { - // - // Put your custom server logic here - // - proxy.proxyRequest(req, res, { - host: 'localhost', - port: 9000 - }); -}).listen(8000); - -http.createServer(function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2)); - res.end(); -}).listen(9000); -``` - -### Setup a stand-alone proxy server with latency (e.g. IO, etc) - -``` js -var http = require('http'), - httpProxy = require('http-proxy'); - -// -// Create a proxy server with custom application logic -// -httpProxy.createServer(function (req, res, proxy) { - // - // Buffer the request so that `data` and `end` events - // are not lost during async operation(s). - // - var buffer = httpProxy.buffer(req); - - // - // Wait for two seconds then respond: this simulates - // performing async actions before proxying a request - // - setTimeout(function () { - proxy.proxyRequest(req, res, { - host: 'localhost', - port: 9000, - buffer: buffer - }); - }, 2000); -}).listen(8000); - -http.createServer(function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2)); - res.end(); -}).listen(9000); -``` - -### Proxy requests within another http server - -``` js -var http = require('http'), - httpProxy = require('http-proxy'); - -// -// Create a new instance of HttProxy to use in your server -// -var proxy = new httpProxy.RoutingProxy(); - -// -// Create a regular http server and proxy its handler -// -http.createServer(function (req, res) { - // - // Put your custom server logic here, then proxy - // - proxy.proxyRequest(req, res, { - host: 'localhost', - port: 9000 - }); -}).listen(8001); - -http.createServer(function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('request successfully proxied: ' + req.url +'\n' + JSON.stringify(req.headers, true, 2)); - res.end(); -}).listen(9000); -``` - -### Proxy requests using a ProxyTable -A Proxy Table is a simple lookup table that maps incoming requests to proxy target locations. Take a look at an example of the options you need to pass to httpProxy.createServer: - -``` js -var options = { - router: { - 'foo.com/baz': '127.0.0.1:8001', - 'foo.com/buz': '127.0.0.1:8002', - 'bar.com/buz': '127.0.0.1:8003' - } -}; -``` - -The above route table will take incoming requests to 'foo.com/baz' and forward them to '127.0.0.1:8001'. Likewise it will take incoming requests to 'foo.com/buz' and forward them to '127.0.0.1:8002'. The routes themselves are later converted to regular expressions to enable more complex matching functionality. We can create a proxy server with these options by using the following code: - -``` js -var proxyServer = httpProxy.createServer(options); -proxyServer.listen(80); -``` - -### Proxy requests using a 'Hostname Only' ProxyTable -As mentioned in the previous section, all routes passes to the ProxyTable are by default converted to regular expressions that are evaluated at proxy-time. This is good for complex URL rewriting of proxy requests, but less efficient when one simply wants to do pure hostname routing based on the HTTP 'Host' header. If you are only concerned with hostname routing, you change the lookup used by the internal ProxyTable: - -``` js -var options = { - hostnameOnly: true, - router: { - 'foo.com': '127.0.0.1:8001', - 'bar.com': '127.0.0.1:8002' - } -} -``` - -Notice here that I have not included paths on the individual domains because this is not possible when using only the HTTP 'Host' header. Care to learn more? See [RFC2616: HTTP/1.1, Section 14.23, "Host"][4]. - -### Proxy requests using a 'Pathname Only' ProxyTable - -If you dont care about forwarding to different hosts, you can redirect based on the request path. - -``` js -var options = { - pathnameOnly: true, - router: { - '/wiki': '127.0.0.1:8001', - '/blog': '127.0.0.1:8002', - '/api': '127.0.0.1:8003' - } -} -``` - -This comes in handy if you are running separate services or applications on separate paths. Note, using this option disables routing by hostname entirely. - - -### Proxy requests with an additional forward proxy -Sometimes in addition to a reverse proxy, you may want your front-facing server to forward traffic to another location. For example, if you wanted to load test your staging environment. This is possible when using node-http-proxy using similar JSON-based configuration to a proxy table: - -``` js -var proxyServerWithForwarding = httpProxy.createServer(9000, 'localhost', { - forward: { - port: 9000, - host: 'staging.com' - } -}); -proxyServerWithForwarding.listen(80); -``` - -The forwarding option can be used in conjunction with the proxy table options by simply including both the 'forward' and 'router' properties in the options passed to 'createServer'. - -### Listening for proxy events -Sometimes you want to listen to an event on a proxy. For example, you may want to listen to the 'end' event, which represents when the proxy has finished proxying a request. - -``` js -var httpProxy = require('http-proxy'); - -var server = httpProxy.createServer(function (req, res, proxy) { - var buffer = httpProxy.buffer(req); - - proxy.proxyRequest(req, res, { - host: '127.0.0.1', - port: 9000, - buffer: buffer - }); -}); - -server.proxy.on('end', function () { - console.log("The request was proxied."); -}); - -server.listen(8000); -``` - -It's important to remember not to listen for events on the proxy object in the function passed to `httpProxy.createServer`. Doing so would add a new listener on every request, which would end up being a disaster. - -## Using HTTPS -You have all the full flexibility of node-http-proxy offers in HTTPS as well as HTTP. The two basic scenarios are: with a stand-alone proxy server or in conjunction with another HTTPS server. - -### Proxying to HTTP from HTTPS -This is probably the most common use-case for proxying in conjunction with HTTPS. You have some front-facing HTTPS server, but all of your internal traffic is HTTP. In this way, you can reduce the number of servers to which your CA and other important security files are deployed and reduce the computational overhead from HTTPS traffic. - -Using HTTPS in `node-http-proxy` is relatively straight-forward: - -``` js -var fs = require('fs'), - http = require('http'), - https = require('https'), - httpProxy = require('http-proxy'); - -var options = { - https: { - key: fs.readFileSync('path/to/your/key.pem', 'utf8'), - cert: fs.readFileSync('path/to/your/cert.pem', 'utf8') - } -}; - -// -// Create a standalone HTTPS proxy server -// -httpProxy.createServer(8000, 'localhost', options).listen(8001); - -// -// Create an instance of HttpProxy to use with another HTTPS server -// -var proxy = new httpProxy.HttpProxy({ - target: { - host: 'localhost', - port: 8000 - } -}); -https.createServer(options.https, function (req, res) { - proxy.proxyRequest(req, res) -}).listen(8002); - -// -// Create the target HTTPS server for both cases -// -http.createServer(function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('hello https\n'); - res.end(); -}).listen(8000); -``` - -### Using two certificates - -Suppose that your reverse proxy will handle HTTPS traffic for two different domains `fobar.com` and `barbaz.com`. -If you need to use two different certificates you can take advantage of [Server Name Indication](http://en.wikipedia.org/wiki/Server_Name_Indication). - -``` js -var https = require('https'), - path = require("path"), - fs = require("fs"), - crypto = require("crypto"); - -// -// generic function to load the credentials context from disk -// -function getCredentialsContext (cer) { - return crypto.createCredentials({ - key: fs.readFileSync(path.join(__dirname, 'certs', cer + '.key')), - cert: fs.readFileSync(path.join(__dirname, 'certs', cer + '.crt')) - }).context; -} - -// -// A certificate per domain hash -// -var certs = { - "fobar.com": getCredentialsContext("foobar"), - "barbaz.com": getCredentialsContext("barbaz") -}; - -// -// Proxy options -// -// This section assumes that myCert, myKey and myCa are defined (they are not -// in this example). With a SNICallback, the proxy needs a default set of -// certificates to use. -// -var options = { - https: { - SNICallback: function (hostname) { - return certs[hostname]; - }, - cert: myCert, - key: myKey, - ca: [myCa] - }, - hostnameOnly: true, - router: { - 'fobar.com': '127.0.0.1:8001', - 'barbaz.com': '127.0.0.1:8002' - } -}; - -// -// Create a standalone HTTPS proxy server -// -httpProxy.createServer(options).listen(8001); - -// -// Create the target HTTPS server -// -http.createServer(function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('hello https\n'); - res.end(); -}).listen(8000); - -``` - -### Proxying to HTTPS from HTTPS -Proxying from HTTPS to HTTPS is essentially the same as proxying from HTTPS to HTTP, but you must include the `target` option in when calling `httpProxy.createServer` or instantiating a new instance of `HttpProxy`. - -``` js -var fs = require('fs'), - https = require('https'), - httpProxy = require('http-proxy'); - -var options = { - https: { - key: fs.readFileSync('path/to/your/key.pem', 'utf8'), - cert: fs.readFileSync('path/to/your/cert.pem', 'utf8') - }, - target: { - https: true // This could also be an Object with key and cert properties - } -}; - -// -// Create a standalone HTTPS proxy server -// -httpProxy.createServer(8000, 'localhost', options).listen(8001); - -// -// Create an instance of HttpProxy to use with another HTTPS server -// -var proxy = new httpProxy.HttpProxy({ - target: { - host: 'localhost', - port: 8000, - https: true - } -}); - -https.createServer(options.https, function (req, res) { - proxy.proxyRequest(req, res); -}).listen(8002); - -// -// Create the target HTTPS server for both cases -// -https.createServer(options.https, function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('hello https\n'); - res.end(); -}).listen(8000); -``` -## Middleware - -`node-http-proxy` now supports connect middleware. Add middleware functions to your createServer call: - -``` js -httpProxy.createServer( - require('connect-gzip').gzip(), - 9000, 'localhost' -).listen(8000); -``` - -A regular request we receive is to support the modification of html/xml content that is returned in the response from an upstream server. - -[Harmon](https://github.com/No9/harmon/) is a stream based middleware plugin that is designed to solve that problem in the most effective way possible. - -If you would like to handle errors passed to `next()` then attach a listener to the proxy: - - server = httpProxy.createServer( - myMiddleWare, - 9000, 'localhost' - ).listen(8000); - - server.proxy.on('middlewareError', function (err, req, res) { - // handle the error here and call res.end() - }); - -## Proxying WebSockets -Websockets are handled automatically when using `httpProxy.createServer()`, however, if you supply a callback inside the createServer call, you will need to handle the 'upgrade' proxy event yourself. Here's how: - -```js - -var options = { - .... -}; - -var server = httpProxy.createServer( - callback/middleware, - options -); - -server.listen(port, function () { ... }); -server.on('upgrade', function (req, socket, head) { - server.proxy.proxyWebSocketRequest(req, socket, head); -}); -``` - -If you would rather not use createServer call, and create the server that proxies yourself, see below: - -``` js -var http = require('http'), - httpProxy = require('http-proxy'); - -// -// Create an instance of node-http-proxy -// -var proxy = new httpProxy.HttpProxy({ - target: { - host: 'localhost', - port: 8000 - } -}); - -var server = http.createServer(function (req, res) { - // - // Proxy normal HTTP requests - // - proxy.proxyRequest(req, res); -}); - -server.on('upgrade', function (req, socket, head) { - // - // Proxy websocket requests too - // - proxy.proxyWebSocketRequest(req, socket, head); -}); - -server.listen(8080); -``` - -### with custom server logic - -``` js -var httpProxy = require('http-proxy') - -var server = httpProxy.createServer(function (req, res, proxy) { - // - // Put your custom server logic here - // - proxy.proxyRequest(req, res, { - host: 'localhost', - port: 9000 - }); -}) - -server.on('upgrade', function (req, socket, head) { - // - // Put your custom server logic here - // - server.proxy.proxyWebSocketRequest(req, socket, head, { - host: 'localhost', - port: 9000 - }); -}); - -server.listen(8080); -``` - -### Configuring your Socket limits - -By default, `node-http-proxy` will set a 100 socket limit for all `host:port` proxy targets. You can change this in two ways: - -1. By passing the `maxSockets` option to `httpProxy.createServer()` -2. By calling `httpProxy.setMaxSockets(n)`, where `n` is the number of sockets you with to use. - -## POST requests and buffering - -express.bodyParser will interfere with proxying of POST requests (and other methods that have a request -body). With bodyParser active, proxied requests will never send anything to the upstream server, and -the original client will just hang. See https://github.com/nodejitsu/node-http-proxy/issues/180 for options. - -## Using node-http-proxy from the command line -When you install this package with npm, a node-http-proxy binary will become available to you. Using this binary is easy with some simple options: - -``` js -usage: node-http-proxy [options] - -All options should be set with the syntax --option=value - -options: - --port PORT Port that the proxy server should run on - --target HOST:PORT Location of the server the proxy will target - --config OUTFILE Location of the configuration file for the proxy server - --silent Silence the log output from the proxy server - -h, --help You're staring at it -``` - -
-## Why doesn't node-http-proxy have more advanced features like x, y, or z? - -If you have a suggestion for a feature currently not supported, feel free to open a [support issue][6]. node-http-proxy is designed to just proxy http requests from one server to another, but we will be soon releasing many other complimentary projects that can be used in conjunction with node-http-proxy. - -## Options - -### Http Proxy - -`createServer()` supports the following options - -```javascript -{ - forward: { // options for forward-proxy - port: 8000, - host: 'staging.com' - }, - target : { // options for proxy target - port : 8000, - host : 'localhost', - }; - source : { // additional options for websocket proxying - host : 'localhost', - port : 8000, - https: true - }, - enable : { - xforward: true // enables X-Forwarded-For - }, - changeOrigin: false, // changes the origin of the host header to the target URL - timeout: 120000 // override the default 2 minute http socket timeout value in milliseconds -} -``` - -## Run Tests -The test suite is designed to fully cover the combinatoric possibilities of HTTP and HTTPS proxying: - -1. HTTP --> HTTP -2. HTTPS --> HTTP -3. HTTPS --> HTTPS -4. HTTP --> HTTPS - -``` -vows test/*-test.js --spec -vows test/*-test.js --spec --https -vows test/*-test.js --spec --https --target=https -vows test/*-test.js --spec --target=https -``` - -
-### License - -(The MIT License) - -Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -[0]: http://nodejitsu.com -[1]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/websocket/websocket-proxy.js -[2]: https://github.com/nodejitsu/node-http-proxy/blob/master/examples/http/proxy-https-to-http.js -[3]: https://github.com/nodejitsu/node-http-proxy/tree/master/examples -[4]: http://www.ietf.org/rfc/rfc2616.txt -[5]: http://socket.io -[6]: http://github.com/nodejitsu/node-http-proxy/issues diff --git a/benchmark/websockets-throughput.js b/benchmark/websockets-throughput.js deleted file mode 100644 index 6787385ad..000000000 --- a/benchmark/websockets-throughput.js +++ /dev/null @@ -1,88 +0,0 @@ -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); diff --git a/bin/node-http-proxy b/bin/node-http-proxy deleted file mode 100755 index 07d199ca6..000000000 --- a/bin/node-http-proxy +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env node - -var path = require('path'), - fs = require('fs'), - util = require('util'), - argv = require('optimist').argv, - httpProxy = require('../lib/node-http-proxy'); - -var help = [ - "usage: node-http-proxy [options] ", - "", - "Starts a node-http-proxy server using the specified command-line options", - "", - "options:", - " --port PORT Port that the proxy server should run on", - " --host HOST Host that the proxy server should run on", - " --target HOST:PORT Location of the server the proxy will target", - " --config OUTFILE Location of the configuration file for the proxy server", - " --silent Silence the log output from the proxy server", - " --user USER User to drop privileges to once server socket is bound", - " -h, --help You're staring at it" -].join('\n'); - -if (argv.h || argv.help || Object.keys(argv).length === 2) { - return util.puts(help); -} - -var location, config = {}, - port = argv.port || 80, - host = argv.host || undefined, - target = argv.target; - user = argv.user; - -// -// If we were passed a config, parse it -// -if (argv.config) { - try { - var data = fs.readFileSync(argv.config); - config = JSON.parse(data.toString()); - } catch (ex) { - util.puts('Error starting node-http-proxy: ' + ex); - process.exit(1); - } -} - -// -// If `config.https` is set, then load the required file contents into the config options. -// -if (config.https) { - Object.keys(config.https).forEach(function (key) { - // If CA certs are specified, load those too. - if (key === "ca") { - for (var i=0; i < config.https.ca.length; i++) { - if (config.https.ca === undefined) { - config.https.ca = []; - } - config.https.ca[i] = fs.readFileSync(config.https[key][i], 'utf8'); - } - } else { - config.https[key] = fs.readFileSync(config.https[key], 'utf8'); - } - }); -} - -// -// Check to see if we should silence the logs -// -config.silent = typeof argv.silent !== 'undefined' ? argv.silent : config.silent; - -// -// If we were passed a target, parse the url string -// -if (typeof target === 'string') location = target.split(':'); - -// -// Create the server with the specified options -// -var server; -if (location) { - var targetPort = location.length === 1 ? 80 : parseInt(location[1]); - server = httpProxy.createServer(targetPort, location[0], config); -} -else if (config.router) { - server = httpProxy.createServer(config); -} -else { - return util.puts(help); -} - -// -// Start the server -// -if (host) { - server.listen(port, host); -} else { - server.listen(port); -} - - -// -// Drop privileges if requested -// -if (typeof user === 'string') { - process.setuid(user); -} - -// -// Notify that the server is started -// -if (!config.silent) { - util.puts('node-http-proxy server now listening on port: ' + port); -} diff --git a/config.sample.json b/config.sample.json deleted file mode 100644 index 8f15f882b..000000000 --- a/config.sample.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "silent": false, - "router": { - "localhost": "localhost:9000" - }, - "forward": { - "port": 9001, - "host": "localhost" - } -} \ No newline at end of file diff --git a/examples/balancer/simple-balancer-with-websockets.js b/examples/balancer/simple-balancer-with-websockets.js deleted file mode 100644 index 04564cef2..000000000 --- a/examples/balancer/simple-balancer-with-websockets.js +++ /dev/null @@ -1,58 +0,0 @@ -var http = require('http'), - httpProxy = require('../../lib/node-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.HttpProxy({ - 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().proxyRequest(req, res); -}); - -// -// Get the 'next' proxy and send the upgrade request -// - -server.on('upgrade', function (req, socket, head) { - nextProxy().proxyWebSocketRequest(req, socket, head); -}); - -server.listen(8080); - \ No newline at end of file diff --git a/examples/balancer/simple-balancer.js b/examples/balancer/simple-balancer.js deleted file mode 100644 index f1fa0c06b..000000000 --- a/examples/balancer/simple-balancer.js +++ /dev/null @@ -1,36 +0,0 @@ -var httpProxy = require('../../lib/node-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 - } -]; - -httpProxy.createServer(function (req, res, proxy) { - // - // On each request, get the first location from the list... - // - var target = addresses.shift(); - - // - // ...then proxy to the server whose 'turn' it is... - // - console.log('balancing request to: ', target); - proxy.proxyRequest(req, res, target); - - // - // ...and then the server you just used becomes the last item in the list. - // - addresses.push(target); -}).listen(8000); - -// Rinse; repeat; enjoy. \ No newline at end of file diff --git a/examples/helpers/store.js b/examples/helpers/store.js deleted file mode 100644 index e2860573f..000000000 --- a/examples/helpers/store.js +++ /dev/null @@ -1,64 +0,0 @@ - -// -// 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}) - }) - } - } - } -} diff --git a/examples/http/basic-proxy.js b/examples/http/basic-proxy.js deleted file mode 100644 index b890e69a0..000000000 --- a/examples/http/basic-proxy.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - basic-proxy.js: Basic example of proxying over HTTP - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - colors = require('colors'), - http = require('http'), - httpProxy = require('../../lib/node-http-proxy'); - -var welcome = [ - '# # ##### ##### ##### ##### ##### #### # # # #', - '# # # # # # # # # # # # # # # # ', - '###### # # # # ##### # # # # # # ## # ', - '# # # # ##### ##### ##### # # ## # ', - '# # # # # # # # # # # # # ', - '# # # # # # # # #### # # # ' -].join('\n'); - -util.puts(welcome.rainbow.bold); - -// -// Basic Http Proxy Server -// -httpProxy.createServer(9000, 'localhost').listen(8000); - -// -// 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(9000); - -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/http/concurrent-proxy.js b/examples/http/concurrent-proxy.js deleted file mode 100644 index 230dfc651..000000000 --- a/examples/http/concurrent-proxy.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - concurrent-proxy.js: check levelof concurrency through proxy. - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - colors = require('colors'), - http = require('http'), - httpProxy = require('../../lib/node-http-proxy'); - -// -// Basic Http Proxy Server -// -httpProxy.createServer(9000, 'localhost').listen(8000); - -// -// 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(9000); - -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/http/custom-proxy-error.js b/examples/http/custom-proxy-error.js deleted file mode 100644 index dc439ea19..000000000 --- a/examples/http/custom-proxy-error.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - custom-proxy-error.js: Example of using the custom `proxyError` event. - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - colors = require('colors'), - http = require('http'), - httpProxy = require('../../lib/node-http-proxy'); - -// -// Http Proxy Server with Latency -// -var server = httpProxy.createServer(9000, 'localhost'); - -// -// Tell the server to listen on port 8002 -// -server.listen(8002); - -// -// Listen for the `proxyError` event on `server.proxy`. _It will not -// be raised on the server itself._ -server.proxy.on('proxyError', 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 + '8002 '.yellow + 'with custom error message'.magenta.underline); \ No newline at end of file diff --git a/examples/http/forward-proxy.js b/examples/http/forward-proxy.js deleted file mode 100644 index ecc20fd4c..000000000 --- a/examples/http/forward-proxy.js +++ /dev/null @@ -1,63 +0,0 @@ -/* - forward-proxy.js: Example of proxying over HTTP with additional forward proxy - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - colors = require('colors'), - http = require('http'), - httpProxy = require('../../lib/node-http-proxy'); - -// -// Setup proxy server with forwarding -// -httpProxy.createServer(9000, 'localhost', { - forward: { - port: 9001, - host: 'localhost' - } -}).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(9000); - -// -// 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(9001); - -util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8003 '.yellow + 'with forward proxy'.magenta.underline); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); -util.puts('http forward server '.blue + 'started '.green.bold + 'on port '.blue + '9001 '.yellow); \ No newline at end of file diff --git a/examples/http/latent-proxy.js b/examples/http/latent-proxy.js deleted file mode 100644 index 2063d0e5b..000000000 --- a/examples/http/latent-proxy.js +++ /dev/null @@ -1,56 +0,0 @@ -/* - latent-proxy.js: Example of proxying over HTTP with latency - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - colors = require('colors'), - http = require('http'), - httpProxy = require('../../lib/node-http-proxy'); - -// -// Http Proxy Server with Latency -// -httpProxy.createServer(function (req, res, proxy) { - var buffer = httpProxy.buffer(req); - setTimeout(function () { - proxy.proxyRequest(req, res, { - port: 9000, - host: 'localhost', - buffer: buffer - }); - }, 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(9000); - -util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8002 '.yellow + 'with latency'.magenta.underline); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/http/proxy-https-to-http.js b/examples/http/proxy-https-to-http.js deleted file mode 100644 index 378de0362..000000000 --- a/examples/http/proxy-https-to-http.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - proxy-https-to-http.js: Basic example of proxying over HTTPS to a target HTTP server - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var https = require('https'), - http = require('http'), - util = require('util'), - colors = require('colors'), - httpProxy = require('../../lib/node-http-proxy'), - helpers = require('../../test/helpers'); - -// -// Create the target HTTPS server -// -http.createServer(function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('hello http over https\n'); - res.end(); -}).listen(8000); - -// -// Create the proxy server listening on port 443 -// -httpProxy.createServer(8000, 'localhost', { - https: helpers.https -}).listen(8080); - -util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8080'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow); diff --git a/examples/http/proxy-https-to-https.js b/examples/http/proxy-https-to-https.js deleted file mode 100644 index af0d92275..000000000 --- a/examples/http/proxy-https-to-https.js +++ /dev/null @@ -1,55 +0,0 @@ -/* - proxy-https-to-https.js: Basic example of proxying over HTTPS to a target HTTPS server - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var https = require('https'), - http = require('http'), - util = require('util'), - colors = require('colors'), - httpProxy = require('../../lib/node-http-proxy'), - helpers = require('../../test/helpers'); - -// -// Create the target HTTPS server -// -https.createServer(helpers.https, function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write('hello https\n'); - res.end(); -}).listen(8000); - -// -// Create the proxy server listening on port 443 -// -httpProxy.createServer(8000, 'localhost', { - https: helpers.https, - target: { - https: true, - rejectUnauthorized: false - } -}).listen(8080); - -util.puts('https proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8080'.yellow); -util.puts('https server '.blue + 'started '.green.bold + 'on port '.blue + '8000 '.yellow); diff --git a/examples/http/proxy-table.js b/examples/http/proxy-table.js deleted file mode 100644 index 55d97aed5..000000000 --- a/examples/http/proxy-table.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - proxy-table.js: Example of proxying over HTTP with proxy table - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - colors = require('colors'), - http = require('http'), - httpProxy = require('../../lib/node-http-proxy'); - -// -// Http Proxy Server with Proxy Table -// -httpProxy.createServer({ - router: { - 'localhost': 'localhost:9000' - } -}).listen(8001); - -// -// 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(9000); - -util.puts('http proxy server '.blue + 'started '.green.bold + 'on port '.blue + '8001 '.yellow + 'with proxy table'.magenta.underline); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/http/standalone-proxy.js b/examples/http/standalone-proxy.js deleted file mode 100644 index e1b1011c5..000000000 --- a/examples/http/standalone-proxy.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - standalone-proxy.js: Example of proxying over HTTP with a standalone HTTP server. - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - colors = require('colors'), - http = require('http'), - httpProxy = require('../../lib/node-http-proxy'); - -// -// Http Server with proxyRequest Handler and Latency -// -var proxy = new httpProxy.RoutingProxy(); -http.createServer(function (req, res) { - var buffer = httpProxy.buffer(req); - setTimeout(function () { - proxy.proxyRequest(req, res, { - port: 9000, - host: 'localhost', - buffer: buffer - }); - }, 200); -}).listen(8004); - -// -// 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(9000); - -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '8004 '.yellow + 'with proxyRequest handler'.cyan.underline + ' and latency'.magenta); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/middleware/bodyDecoder-middleware.js b/examples/middleware/bodyDecoder-middleware.js deleted file mode 100644 index d889548a0..000000000 --- a/examples/middleware/bodyDecoder-middleware.js +++ /dev/null @@ -1,87 +0,0 @@ - -var Store = require('../helpers/store') - , http = require('http') - -http.createServer(new Store().handler()).listen(7531, function () { -//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 () { - - //greetings -> 7531, insults-> 2600 - - // now, start a proxy server. - - var bodyParser = require('connect/lib/middleware/bodyParser') - //don't worry about incoming contont type - //bodyParser.parse[''] = JSON.parse - - require('../../lib/node-http-proxy').createServer( - //refactor the body parser and re-streamer into a separate package - 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, proxy) { - //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.proxyRequest(req, res, {host: 'localhost', port: port}) - } - ).listen(1337, function () { - var request = require('request') - //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"] - - }) - }) -}) diff --git a/examples/middleware/gzip-middleware-proxytable.js b/examples/middleware/gzip-middleware-proxytable.js deleted file mode 100644 index 527d3d7b8..000000000 --- a/examples/middleware/gzip-middleware-proxytable.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - gzip-middleware-proxytable.js: Basic example of `connect-gzip` middleware in node-http-proxy - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, Marak Squires, & Dominic Tarr. - - 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/node-http-proxy'); - -// -// Basic Http Proxy Server -// -httpProxy.createServer( - require('connect-gzip').gzip({ matchType: /.?/ }), - { - router: { - "localhost/fun": "localhost:9000" - } - } -).listen(8000); - -// -// 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(9000); - -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/middleware/gzip-middleware.js b/examples/middleware/gzip-middleware.js deleted file mode 100644 index 29097ecd3..000000000 --- a/examples/middleware/gzip-middleware.js +++ /dev/null @@ -1,50 +0,0 @@ -/* - gzip-middleware.js: Basic example of `connect-gzip` middleware in node-http-proxy - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, Marak Squires, & Dominic Tarr. - - 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/node-http-proxy'); - -// -// Basic Http Proxy Server -// -httpProxy.createServer( - require('connect-gzip').gzip({ matchType: /.?/ }), - 9000, 'localhost' -).listen(8000); - -// -// 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(9000); - -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/middleware/jsonp-middleware.js b/examples/middleware/jsonp-middleware.js deleted file mode 100644 index 15ab9ee05..000000000 --- a/examples/middleware/jsonp-middleware.js +++ /dev/null @@ -1,30 +0,0 @@ -var Store = require('../helpers/store') - , http = require('http') - -// -// jsonp is a handy technique for getting around the limitations of the same-origin policy. -// (http://en.wikipedia.org/wiki/Same_origin_policy) -// -// normally, to dynamically update a page you use an XmlHttpRequest. this has flakey support -// is some browsers and is restricted by the same origin policy. you cannot perform XHR requests to -// someone else's server. one way around this would be to proxy requests to all the servers you want -// to xhr to, and your core server - so that everything has the same port and host. -// -// another way, is to turn json into javascript. (which is exempt from the same origin policy) -// this is done by wrapping the json object in a function call, and then including a script tag. -// -// here we're proxing our own JSON returning server, but we could proxy any server on the internet, -// and our client side app would be slurping down JSONP from anywhere. -// -// curl localhost:1337/whatever?callback=alert -// alert([]) //which is valid javascript! -// -// also see http://en.wikipedia.org/wiki/JSONP#JSONP -// - -http.createServer(new Store().handler()).listen(7531) - -require('../../lib/node-http-proxy').createServer( - require('connect-jsonp')(true), - 'localhost', 7531 -).listen(1337) diff --git a/examples/middleware/modifyResponse-middleware.js b/examples/middleware/modifyResponse-middleware.js deleted file mode 100644 index af21236ef..000000000 --- a/examples/middleware/modifyResponse-middleware.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - modifyBody-middleware.js: Example of middleware which modifies response - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, Marak Squires, & Dominic Tarr. - - 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/node-http-proxy'); - -// -// Basic Http Proxy Server -// -httpProxy.createServer( - function (req, res, next) { - var _write = res.write; - - res.write = function (data) { - _write.call(res, data.toString().replace("Ruby", "nodejitsu")); - } - next(); - }, - 9000, 'localhost' -).listen(8000); - -// -// Target Http Server -// -http.createServer(function (req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.end('Hello, I know Ruby\n'); -}).listen(9000); - -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); - diff --git a/examples/middleware/url-middleware.js b/examples/middleware/url-middleware.js deleted file mode 100644 index b4f304562..000000000 --- a/examples/middleware/url-middleware.js +++ /dev/null @@ -1,58 +0,0 @@ -/* - url-middleware.js: Example of a simple url routing middleware for node-http-proxy - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - colors = require('colors'), - http = require('http'), - httpProxy = require('../../lib/node-http-proxy'); - -// -// Now we set up our proxy. -// -httpProxy.createServer( - // - // This is where our middlewares go, with any options desired - in this case, - // the list of routes/URLs and their destinations. - // - require('proxy-by-url')({ - '/hello': { port: 9000, host: 'localhost' }, - '/charlie': { port: 80, host: 'charlieistheman.com' }, - '/google': { port: 80, host: 'google.com' } - }) -).listen(8000); - -// -// Target Http Server (to listen for requests on 'localhost') -// -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(9000); - -// And finally, some colored startup output. -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/middleware/url-middleware2.js b/examples/middleware/url-middleware2.js deleted file mode 100644 index 2c894e1af..000000000 --- a/examples/middleware/url-middleware2.js +++ /dev/null @@ -1,30 +0,0 @@ -var util = require('util'), - colors = require('colors'), - http = require('http'), - httpProxy = require('../../lib/node-http-proxy'), - Store = require('../helpers/store') - -http.createServer(new Store().handler()).listen(7531) - -// Now we set up our proxy. -httpProxy.createServer( - // This is where our middlewares go, with any options desired - in this case, - // the list of routes/URLs and their destinations. - require('proxy-by-url')({ - '/store': { port: 7531, host: 'localhost' }, - '/': { port: 9000, host: 'localhost' } - }) -).listen(8000); - -// -// Target Http Server (to listen for requests on 'localhost') -// -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(9000); - -// And finally, some colored startup output. -util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8000'.yellow); -util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow); diff --git a/examples/package.json b/examples/package.json deleted file mode 100644 index ca95fd8cf..000000000 --- a/examples/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "http-proxy-examples", - "description": "packages required to run the examples", - "version": "0.0.0", - "dependencies": { - "connect": "1.6", - "connect-gzip": "0.1", - "connect-jsonp": "0.0.5", - "connect-restreamer": "1", - "proxy-by-url": ">= 0.0.1" - } -} \ No newline at end of file diff --git a/examples/websocket/latent-websocket-proxy.js b/examples/websocket/latent-websocket-proxy.js deleted file mode 100644 index 99a07281e..000000000 --- a/examples/websocket/latent-websocket-proxy.js +++ /dev/null @@ -1,92 +0,0 @@ -/* - standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server. - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - http = require('http'), - colors = require('colors'), - httpProxy = require('../../lib/node-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(8080); -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.HttpProxy({ - target: { - host: 'localhost', - port: 8080 - } -}); - -var proxyServer = http.createServer(function (req, res) { - proxy.proxyRequest(req, res); -}); - -// -// Listen to the `upgrade` event and proxy the -// WebSocket requests as well. -// -proxyServer.on('upgrade', function (req, socket, head) { - var buffer = httpProxy.buffer(socket); - - setTimeout(function () { - proxy.proxyWebSocketRequest(req, socket, head, buffer); - }, 1000); -}); - -proxyServer.listen(8081); - -// -// Setup the socket.io client against our proxy -// -var ws = client.connect('ws://localhost:8081'); - -ws.on('message', function (msg) { - util.debug('Got message: ' + msg); -}); diff --git a/examples/websocket/standalone-websocket-proxy.js b/examples/websocket/standalone-websocket-proxy.js deleted file mode 100644 index acf43b979..000000000 --- a/examples/websocket/standalone-websocket-proxy.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server. - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - http = require('http'), - colors = require('colors'), - httpProxy = require('../../lib/node-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(8080); -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.HttpProxy({ - target: { - host: 'localhost', - port: 8080 - } -}); -var proxyServer = http.createServer(function (req, res) { - proxy.proxyRequest(req, res); -}); - -// -// Listen to the `upgrade` event and proxy the -// WebSocket requests as well. -// -proxyServer.on('upgrade', function (req, socket, head) { - proxy.proxyWebSocketRequest(req, socket, head); -}); - -proxyServer.listen(8081); - -// -// Setup the socket.io client against our proxy -// -var ws = client.connect('ws://localhost:8081'); - -ws.on('message', function (msg) { - util.debug('Got message: ' + msg); -}); diff --git a/examples/websocket/websocket-proxy.js b/examples/websocket/websocket-proxy.js deleted file mode 100644 index 4e3cf6fd1..000000000 --- a/examples/websocket/websocket-proxy.js +++ /dev/null @@ -1,69 +0,0 @@ -/* - web-socket-proxy.js: Example of proxying over HTTP and WebSockets. - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Fedor Indutny, & 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. - -*/ - -var util = require('util'), - http = require('http'), - colors = require('colors'), - httpProxy = require('../../lib/node-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(8080); -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(8080, 'localhost').listen(8081); - -// -// Setup the socket.io client against our proxy -// -var ws = client.connect('ws://localhost:8081'); - -ws.on('message', function (msg) { - util.debug('Got message: ' + msg); -}); diff --git a/lib/node-http-proxy.js b/lib/node-http-proxy.js deleted file mode 100644 index b5de6bb66..000000000 --- a/lib/node-http-proxy.js +++ /dev/null @@ -1,397 +0,0 @@ -/* - node-http-proxy.js: http proxy for node.js - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Marak Squires, Fedor Indutny - - 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'), - https = require('https'), - events = require('events'), - maxSockets = 100; - -// -// Expose version information through `pkginfo`. -// -require('pkginfo')(module, 'version'); - -// -// ### Export the relevant objects exposed by `node-http-proxy` -// -var HttpProxy = exports.HttpProxy = require('./node-http-proxy/http-proxy').HttpProxy, - ProxyTable = exports.ProxyTable = require('./node-http-proxy/proxy-table').ProxyTable, - RoutingProxy = exports.RoutingProxy = require('./node-http-proxy/routing-proxy').RoutingProxy; - -// -// ### function createServer ([port, host, options, handler]) -// #### @port {number} **Optional** Port to use on the proxy target host. -// #### @host {string} **Optional** Host of the proxy target. -// #### @options {Object} **Optional** Options for the HttpProxy instance used -// #### @handler {function} **Optional** Request handler for the server -// Returns a server that manages an instance of HttpProxy. Flexible arguments allow for: -// -// * `httpProxy.createServer(9000, 'localhost')` -// * `httpProxy.createServer(9000, 'localhost', options) -// * `httpPRoxy.createServer(function (req, res, proxy) { ... })` -// -exports.createServer = function () { - var args = Array.prototype.slice.call(arguments), - handlers = [], - callback, - options = {}, - message, - handler, - server, - proxy, - host, - port; - - // - // Liberally parse arguments of the form: - // - // httpProxy.createServer('localhost', 9000, callback); - // httpProxy.createServer({ host: 'localhost', port: 9000 }, callback); - // **NEED MORE HERE!!!** - // - args.forEach(function (arg) { - arg = Number(arg) || arg; - switch (typeof arg) { - case 'string': host = arg; break; - case 'number': port = arg; break; - case 'object': options = arg || {}; break; - case 'function': callback = arg; handlers.push(callback); break; - }; - }); - - // - // Helper function to create intelligent error message(s) - // for the very liberal arguments parsing performed by - // `require('http-proxy').createServer()`. - // - function validArguments() { - var conditions = { - 'port and host': function () { - return port && host; - }, - 'options.target or options.router': function () { - return options && (options.router || - (options.target && options.target.host && options.target.port)); - }, - 'or proxy handlers': function () { - return handlers && handlers.length; - } - } - - var missing = Object.keys(conditions).filter(function (name) { - return !conditions[name](); - }); - - if (missing.length === 3) { - message = 'Cannot proxy without ' + missing.join(', '); - return false; - } - - return true; - } - - if (!validArguments()) { - // - // If `host`, `port` and `options` are all not passed (with valid - // options) then this server is improperly configured. - // - throw new Error(message); - return; - } - - // - // Hoist up any explicit `host` or `port` arguments - // that have been passed in to the options we will - // pass to the `httpProxy.HttpProxy` constructor. - // - options.target = options.target || {}; - options.target.port = options.target.port || port; - options.target.host = options.target.host || host; - - if (options.target && options.target.host && options.target.port) { - // - // If an explicit `host` and `port` combination has been passed - // to `.createServer()` then instantiate a hot-path optimized - // `HttpProxy` object and add the "proxy" middleware layer. - // - proxy = new HttpProxy(options); - handlers.push(function (req, res) { - proxy.proxyRequest(req, res); - }); - } - else { - // - // If no explicit `host` or `port` combination has been passed then - // we have to assume that this is a "go-anywhere" Proxy (i.e. a `RoutingProxy`). - // - proxy = new RoutingProxy(options); - - if (options.router) { - // - // If a routing table has been supplied than we assume - // the user intends us to add the "proxy" middleware layer - // for them - // - handlers.push(function (req, res) { - proxy.proxyRequest(req, res); - }); - - proxy.on('routes', function (routes) { - server.emit('routes', routes); - }); - } - } - - // - // Create the `http[s].Server` instance which will use - // an instance of `httpProxy.HttpProxy`. - // - handler = handlers.length > 1 - ? exports.stack(handlers, proxy) - : function (req, res) { handlers[0](req, res, proxy) }; - - server = options.https - ? https.createServer(options.https, handler) - : http.createServer(handler); - - server.on('close', function () { - proxy.close(); - }); - - if (!callback) { - // - // If an explicit callback has not been supplied then - // automagically proxy the request using the `HttpProxy` - // instance we have created. - // - server.on('upgrade', function (req, socket, head) { - proxy.proxyWebSocketRequest(req, socket, head); - }); - } - - // - // Set the proxy on the server so it is available - // to the consumer of the server - // - server.proxy = proxy; - return server; -}; - -// -// ### function buffer (obj) -// #### @obj {Object} Object to pause events from -// Buffer `data` and `end` events from the given `obj`. -// Consumers of HttpProxy performing async tasks -// __must__ utilize this utility, to re-emit data once -// the async operation has completed, otherwise these -// __events will be lost.__ -// -// var buffer = httpProxy.buffer(req); -// fs.readFile(path, function () { -// httpProxy.proxyRequest(req, res, host, port, buffer); -// }); -// -// __Attribution:__ This approach is based heavily on -// [Connect](https://github.com/senchalabs/connect/blob/master/lib/utils.js#L157). -// However, this is not a big leap from the implementation in node-http-proxy < 0.4.0. -// This simply chooses to manage the scope of the events on a new Object literal as opposed to -// [on the HttpProxy instance](https://github.com/nodejitsu/node-http-proxy/blob/v0.3.1/lib/node-http-proxy.js#L154). -// -exports.buffer = function (obj) { - var events = [], - onData, - onEnd; - - obj.on('data', onData = function (data, encoding) { - events.push(['data', data, encoding]); - }); - - obj.on('end', onEnd = function (data, encoding) { - events.push(['end', data, encoding]); - }); - - return { - end: function () { - obj.removeListener('data', onData); - obj.removeListener('end', onEnd); - }, - destroy: function () { - this.end(); - this.resume = function () { - console.error("Cannot resume buffer after destroying it."); - }; - - onData = onEnd = events = obj = null; - }, - resume: function () { - this.end(); - for (var i = 0, len = events.length; i < len; ++i) { - obj.emit.apply(obj, events[i]); - } - } - }; -}; - -// -// ### function getMaxSockets () -// Returns the maximum number of sockets -// allowed on __every__ outgoing request -// made by __all__ instances of `HttpProxy` -// -exports.getMaxSockets = function () { - return maxSockets; -}; - -// -// ### function setMaxSockets () -// Sets the maximum number of sockets -// allowed on __every__ outgoing request -// made by __all__ instances of `HttpProxy` -// -exports.setMaxSockets = function (value) { - maxSockets = value; -}; - -// -// ### function stack (middlewares, proxy) -// #### @middlewares {Array} Array of functions to stack. -// #### @proxy {HttpProxy|RoutingProxy} Proxy instance to -// Iteratively build up a single handler to the `http.Server` -// `request` event (i.e. `function (req, res)`) by wrapping -// each middleware `layer` into a `child` middleware which -// is in invoked by the parent (i.e. predecessor in the Array). -// -// adapted from https://github.com/creationix/stack -// -exports.stack = function stack (middlewares, proxy) { - var handle; - middlewares.reverse().forEach(function (layer) { - var child = handle; - handle = function (req, res) { - var next = function (err) { - if (err) { - if (! proxy.emit('middlewareError', err, req, res)) { - console.error('Error in middleware(s): %s', err.stack); - } - - if (res._headerSent) { - res.destroy(); - } - else { - res.statusCode = 500; - res.setHeader('Content-Type', 'text/plain'); - res.end('Internal Server Error'); - } - - return; - } - - if (child) { - child(req, res); - } - }; - - // - // Set the prototype of the `next` function to the instance - // of the `proxy` so that in can be used interchangably from - // a `connect` style callback and a true `HttpProxy` object. - // - // e.g. `function (req, res, next)` vs. `function (req, res, proxy)` - // - next.__proto__ = proxy; - layer(req, res, next); - }; - }); - - return handle; -}; - -// -// ### function _getAgent (host, port, secure) -// #### @options {Object} Options to use when creating the agent. -// -// { -// host: 'localhost', -// port: 9000, -// https: true, -// maxSockets: 100 -// } -// -// Createsan agent from the `http` or `https` module -// and sets the `maxSockets` property appropriately. -// -exports._getAgent = function _getAgent (options) { - if (!options || !options.host) { - throw new Error('`options.host` is required to create an Agent.'); - } - - if (!options.port) { - options.port = options.https ? 443 : 80; - } - - var Agent = options.https ? https.Agent : http.Agent, - agent; - - // require('http-proxy').setMaxSockets() should override http's default - // configuration value (which is pretty low). - options.maxSockets = options.maxSockets || maxSockets; - agent = new Agent(options); - - return agent; -} - -// -// ### function _getProtocol (options) -// #### @options {Object} Options for the proxy target. -// Returns the appropriate node.js core protocol module (i.e. `http` or `https`) -// based on the `options` supplied. -// -exports._getProtocol = function _getProtocol (options) { - return options.https ? https : http; -}; - - -// -// ### function _getBase (options) -// #### @options {Object} Options for the proxy target. -// Returns the relevate base object to create on outgoing proxy request. -// If `options.https` are supplied, this function respond with an object -// containing the relevant `ca`, `key`, and `cert` properties. -// -exports._getBase = function _getBase (options) { - var result = function () {}; - - if (options.https && typeof options.https === 'object') { - ['ca', 'cert', 'key'].forEach(function (key) { - if (options.https[key]) { - result.prototype[key] = options.https[key]; - } - }); - } - - return result; -}; diff --git a/lib/node-http-proxy/http-proxy.js b/lib/node-http-proxy/http-proxy.js deleted file mode 100644 index 92541baec..000000000 --- a/lib/node-http-proxy/http-proxy.js +++ /dev/null @@ -1,983 +0,0 @@ -/* - node-http-proxy.js: http proxy for node.js - - Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Marak Squires, Fedor Indutny - - 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 events = require('events'), - http = require('http'), - util = require('util'), - url = require('url'), - httpProxy = require('../node-http-proxy'); - -// -// @private {RegExp} extractPort -// Reusable regular expression for getting the -// port from a host string. -// -var extractPort = /:(\d+)$/; - -// -// ### function HttpProxy (options) -// #### @options {Object} Options for this instance. -// Constructor function for new instances of HttpProxy responsible -// for managing the life-cycle of streaming reverse proxyied HTTP requests. -// -// Example options: -// -// { -// target: { -// host: 'localhost', -// port: 9000 -// }, -// forward: { -// host: 'localhost', -// port: 9001 -// } -// } -// -var HttpProxy = exports.HttpProxy = function (options) { - if (!options || !options.target) { - throw new Error('Both `options` and `options.target` are required.'); - } - - events.EventEmitter.call(this); - - var self = this; - - // - // Setup basic proxying options: - // - // * forward {Object} Options for a forward-proxy (if-any) - // * target {Object} Options for the **sole** proxy target of this instance - // - this.forward = options.forward; - this.target = options.target; - this.timeout = options.timeout; - - // - // Setup the necessary instances instance variables for - // the `target` and `forward` `host:port` combinations - // used by this instance. - // - // * agent {http[s].Agent} Agent to be used by this instance. - // * protocol {http|https} Core node.js module to make requests with. - // * base {Object} Base object to create when proxying containing any https settings. - // - function setupProxy (key) { - self[key].agent = httpProxy._getAgent(self[key]); - self[key].protocol = httpProxy._getProtocol(self[key]); - self[key].base = httpProxy._getBase(self[key]); - } - - setupProxy('target'); - if (this.forward) { - setupProxy('forward'); - } - - // - // Setup opt-in features - // - this.enable = options.enable || {}; - this.enable.xforward = typeof this.enable.xforward === 'boolean' - ? this.enable.xforward - : true; - - // if event listener is set then use it else unlimited. - this.eventListenerCount = typeof options.eventListenerCount === 'number'? options.eventListenerCount : 0 ; - - // - // Setup additional options for WebSocket proxying. When forcing - // the WebSocket handshake to change the `sec-websocket-location` - // and `sec-websocket-origin` headers `options.source` **MUST** - // be provided or the operation will fail with an `origin mismatch` - // by definition. - // - this.source = options.source || { host: 'localhost', port: 80 }; - this.source.https = this.source.https || options.https; - this.changeOrigin = options.changeOrigin || false; -}; - -// Inherit from events.EventEmitter -util.inherits(HttpProxy, events.EventEmitter); - -// -// ### function proxyRequest (req, res, buffer) -// #### @req {ServerRequest} Incoming HTTP Request to proxy. -// #### @res {ServerResponse} Outgoing HTTP Request to write proxied data to. -// #### @buffer {Object} Result from `httpProxy.buffer(req)` -// -HttpProxy.prototype.proxyRequest = function (req, res, buffer) { - var self = this, - errState = false, - outgoing = new(this.target.base), - reverseProxy, - location; - - // If this is a DELETE request then set the "content-length" - // header (if it is not already set) - if (req.method === 'DELETE') { - req.headers['content-length'] = req.headers['content-length'] || '0'; - } - - // - // Add common proxy headers to the request so that they can - // be availible to the proxy target server. If the proxy is - // part of proxy chain it will append the address: - // - // * `x-forwarded-for`: IP Address of the original request - // * `x-forwarded-proto`: Protocol of the original request - // * `x-forwarded-port`: Port of the original request. - // - if (this.enable.xforward && req.connection && req.socket) { - if (req.headers['x-forwarded-for']) { - var addressToAppend = "," + req.connection.remoteAddress || req.socket.remoteAddress; - req.headers['x-forwarded-for'] += addressToAppend; - } - else { - req.headers['x-forwarded-for'] = req.connection.remoteAddress || req.socket.remoteAddress; - } - - if (req.headers['x-forwarded-port']) { - var portToAppend = "," + getPortFromHostHeader(req); - req.headers['x-forwarded-port'] += portToAppend; - } - else { - req.headers['x-forwarded-port'] = getPortFromHostHeader(req); - } - - if (req.headers['x-forwarded-proto']) { - var protoToAppend = "," + getProto(req); - req.headers['x-forwarded-proto'] += protoToAppend; - } - else { - req.headers['x-forwarded-proto'] = getProto(req); - } - } - - if (this.timeout) { - req.socket.setTimeout(this.timeout); - } - - // - // Emit the `start` event indicating that we have begun the proxy operation. - // - this.emit('start', req, res, this.target); - - // - // If forwarding is enabled for this instance, foward proxy the - // specified request to the address provided in `this.forward` - // - if (this.forward) { - this.emit('forward', req, res, this.forward); - this._forwardRequest(req); - } - - // - // #### function proxyError (err) - // #### @err {Error} Error contacting the proxy target - // Short-circuits `res` in the event of any error when - // contacting the proxy target at `host` / `port`. - // - function proxyError(err) { - errState = true; - - // - // Emit an `error` event, allowing the application to use custom - // error handling. The error handler should end the response. - // - if (self.emit('proxyError', err, req, res)) { - return; - } - - res.writeHead(500, { 'Content-Type': 'text/plain' }); - - if (req.method !== 'HEAD') { - // - // This NODE_ENV=production behavior is mimics Express and - // Connect. - // - if (process.env.NODE_ENV === 'production') { - res.write('Internal Server Error'); - } - else { - res.write('An error has occurred: ' + JSON.stringify(err)); - } - } - - try { res.end() } - catch (ex) { console.error("res.end error: %s", ex.message) } - } - - // - // Setup outgoing proxy with relevant properties. - // - outgoing.host = this.target.host; - outgoing.hostname = this.target.hostname; - outgoing.port = this.target.port; - outgoing.socketPath = this.target.socketPath; - outgoing.agent = this.target.agent; - outgoing.method = req.method; - outgoing.path = url.parse(req.url).path; - outgoing.headers = req.headers; - - // - // If the changeOrigin option is specified, change the - // origin of the host header to the target URL! Please - // don't revert this without documenting it! - // - if (this.changeOrigin) { - outgoing.headers.host = this.target.host; - // Only add port information to the header if not default port - // for this protocol. - // See https://github.com/nodejitsu/node-http-proxy/issues/458 - if (this.target.port !== 443 && this.target.https || - this.target.port !== 80 && !this.target.https) { - outgoing.headers.host += ':' + this.target.port; - } - } - - // - // Open new HTTP request to internal resource with will act - // as a reverse proxy pass - // - reverseProxy = this.target.protocol.request(outgoing, function (response) { - // - // Process the `reverseProxy` `response` when it's received. - // - if (req.httpVersion === '1.0') { - if (req.headers.connection) { - response.headers.connection = req.headers.connection - } else { - response.headers.connection = 'close' - } - } else if (!response.headers.connection) { - if (req.headers.connection) { response.headers.connection = req.headers.connection } - else { - response.headers.connection = 'keep-alive' - } - } - - // Remove `Transfer-Encoding` header if client's protocol is HTTP/1.0 - // or if this is a DELETE request with no content-length header. - // See: https://github.com/nodejitsu/node-http-proxy/pull/373 - if (req.httpVersion === '1.0' || (req.method === 'DELETE' - && !req.headers['content-length'])) { - delete response.headers['transfer-encoding']; - } - - if ((response.statusCode === 301 || response.statusCode === 302) - && typeof response.headers.location !== 'undefined') { - location = url.parse(response.headers.location); - if (location.host === req.headers.host) { - if (self.source.https && !self.target.https) { - response.headers.location = response.headers.location.replace(/^http\:/, 'https:'); - } - if (self.target.https && !self.source.https) { - response.headers.location = response.headers.location.replace(/^https\:/, 'http:'); - } - } - } - - // - // When the `reverseProxy` `response` ends, end the - // corresponding outgoing `res` unless we have entered - // an error state. In which case, assume `res.end()` has - // already been called and the 'error' event listener - // removed. - // - var ended = false; - response.on('close', function () { - if (!ended) { response.emit('end') } - }); - - // - // After reading a chunked response, the underlying socket - // will hit EOF and emit a 'end' event, which will abort - // the request. If the socket was paused at that time, - // pending data gets discarded, truncating the response. - // This code makes sure that we flush pending data. - // - response.connection.on('end', function () { - if (response.readable && response.resume) { - response.resume(); - } - }); - - response.on('end', function () { - ended = true; - if (!errState) { - try { res.end() } - catch (ex) { console.error("res.end error: %s", ex.message) } - - // Emit the `end` event now that we have completed proxying - self.emit('end', req, res, response); - } - }); - - // Allow observer to modify headers or abort response - try { self.emit('proxyResponse', req, res, response) } - catch (ex) { - errState = true; - return; - } - - // Set the headers of the client response - if (res.sentHeaders !== true) { - Object.keys(response.headers).forEach(function (key) { - res.setHeader(key, response.headers[key]); - }); - res.writeHead(response.statusCode); - } - - function ondata(chunk) { - if (res.writable) { - // Only pause if the underlying buffers are full, - // *and* the connection is not in 'closing' state. - // Otherwise, the pause will cause pending data to - // be discarded and silently lost. - if (false === res.write(chunk) && response.pause - && response.connection.readable) { - response.pause(); - } - } - } - - response.on('data', ondata); - - function ondrain() { - if (response.readable && response.resume) { - response.resume(); - } - } - - res.on('drain', ondrain); - }); - - // allow unlimited listeners ... - reverseProxy.setMaxListeners(this.eventListenerCount); - - // - // Handle 'error' events from the `reverseProxy`. Setup timeout override if needed - // - reverseProxy.once('error', proxyError); - - // Set a timeout on the socket if `this.timeout` is specified. - reverseProxy.once('socket', function (socket) { - if (self.timeout) { - socket.setTimeout(self.timeout); - } - }); - - // - // Handle 'error' events from the `req` (e.g. `Parse Error`). - // - req.on('error', proxyError); - - // - // If `req` is aborted, we abort our `reverseProxy` request as well. - // - req.on('aborted', function () { - reverseProxy.abort(); - }); - - // - // For each data `chunk` received from the incoming - // `req` write it to the `reverseProxy` request. - // - req.on('data', function (chunk) { - if (!errState) { - var flushed = reverseProxy.write(chunk); - if (!flushed) { - req.pause(); - reverseProxy.once('drain', function () { - try { req.resume() } - catch (er) { console.error("req.resume error: %s", er.message) } - }); - - // - // Force the `drain` event in 100ms if it hasn't - // happened on its own. - // - setTimeout(function () { - reverseProxy.emit('drain'); - }, 100); - } - } - }); - - // - // When the incoming `req` ends, end the corresponding `reverseProxy` - // request unless we have entered an error state. - // - req.on('end', function () { - if (!errState) { - reverseProxy.end(); - } - }); - - //Aborts reverseProxy if client aborts the connection. - req.on('close', function () { - if (!errState) { - reverseProxy.abort(); - } - }); - - // - // If we have been passed buffered data, resume it. - // - if (buffer) { - return !errState - ? buffer.resume() - : buffer.destroy(); - } -}; - -// -// ### function proxyWebSocketRequest (req, socket, head, buffer) -// #### @req {ServerRequest} Websocket request to proxy. -// #### @socket {net.Socket} Socket for the underlying HTTP request -// #### @head {string} Headers for the Websocket request. -// #### @buffer {Object} Result from `httpProxy.buffer(req)` -// Performs a WebSocket proxy operation to the location specified by -// `this.target`. -// -HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, upgradeHead, buffer) { - var self = this, - outgoing = new(this.target.base), - listeners = {}, - errState = false, - CRLF = '\r\n', - //copy upgradeHead to avoid retention of large slab buffers used in node core - head = new Buffer(upgradeHead.length); - upgradeHead.copy(head); - - // - // WebSocket requests must have the `GET` method and - // the `upgrade:websocket` header - // - if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') { - // - // This request is not WebSocket request - // - return socket.destroy(); - } - - // - // Add common proxy headers to the request so that they can - // be availible to the proxy target server. If the proxy is - // part of proxy chain it will append the address: - // - // * `x-forwarded-for`: IP Address of the original request - // * `x-forwarded-proto`: Protocol of the original request - // * `x-forwarded-port`: Port of the original request. - // - if (this.enable.xforward && req.connection) { - if (req.headers['x-forwarded-for']) { - var addressToAppend = "," + req.connection.remoteAddress || socket.remoteAddress; - req.headers['x-forwarded-for'] += addressToAppend; - } - else { - req.headers['x-forwarded-for'] = req.connection.remoteAddress || socket.remoteAddress; - } - - if (req.headers['x-forwarded-port']) { - var portToAppend = "," + getPortFromHostHeader(req); - req.headers['x-forwarded-port'] += portToAppend; - } - else { - req.headers['x-forwarded-port'] = getPortFromHostHeader(req); - } - - if (req.headers['x-forwarded-proto']) { - var protoToAppend = "," + (req.connection.pair ? 'wss' : 'ws'); - req.headers['x-forwarded-proto'] += protoToAppend; - } - else { - req.headers['x-forwarded-proto'] = req.connection.pair ? 'wss' : 'ws'; - } - } - - self.emit('websocket:start', req, socket, head, this.target); - - // - // Helper function for setting appropriate socket values: - // 1. Turn of all bufferings - // 2. For server set KeepAlive - // - function _socket(socket, keepAlive) { - socket.setTimeout(0); - socket.setNoDelay(true); - - if (keepAlive) { - if (socket.setKeepAlive) { - socket.setKeepAlive(true, 0); - } - else if (socket.pair.cleartext.socket.setKeepAlive) { - socket.pair.cleartext.socket.setKeepAlive(true, 0); - } - } - } - - // - // Setup the incoming client socket. - // - _socket(socket, true); - - // - // On `upgrade` from the Agent socket, listen to - // the appropriate events. - // - function onUpgrade (reverseProxy, proxySocket) { - if (!reverseProxy) { - proxySocket.end(); - socket.end(); - return; - } - - // - // Any incoming data on this WebSocket to the proxy target - // will be written to the `reverseProxy` socket. - // - proxySocket.on('data', listeners.onIncoming = function (data) { - if (reverseProxy.incoming.socket.writable) { - try { - self.emit('websocket:outgoing', req, socket, head, data); - var flushed = reverseProxy.incoming.socket.write(data); - if (!flushed) { - proxySocket.pause(); - reverseProxy.incoming.socket.once('drain', function () { - try { proxySocket.resume() } - catch (er) { console.error("proxySocket.resume error: %s", er.message) } - }); - - // - // Force the `drain` event in 100ms if it hasn't - // happened on its own. - // - setTimeout(function () { - reverseProxy.incoming.socket.emit('drain'); - }, 100); - } - } - catch (ex) { - detach(); - } - } - }); - - // - // Any outgoing data on this Websocket from the proxy target - // will be written to the `proxySocket` socket. - // - reverseProxy.incoming.socket.on('data', listeners.onOutgoing = function (data) { - try { - self.emit('websocket:incoming', reverseProxy, reverseProxy.incoming, head, data); - var flushed = proxySocket.write(data); - if (!flushed) { - reverseProxy.incoming.socket.pause(); - proxySocket.once('drain', function () { - try { reverseProxy.incoming.socket.resume() } - catch (er) { console.error("reverseProxy.incoming.socket.resume error: %s", er.message) } - }); - - // - // Force the `drain` event in 100ms if it hasn't - // happened on its own. - // - setTimeout(function () { - proxySocket.emit('drain'); - }, 100); - } - } - catch (ex) { - detach(); - } - }); - - // - // Helper function to detach all event listeners - // from `reverseProxy` and `proxySocket`. - // - function detach() { - proxySocket.destroySoon(); - proxySocket.removeListener('end', listeners.onIncomingClose); - proxySocket.removeListener('data', listeners.onIncoming); - reverseProxy.incoming.socket.destroySoon(); - reverseProxy.incoming.socket.removeListener('end', listeners.onOutgoingClose); - reverseProxy.incoming.socket.removeListener('data', listeners.onOutgoing); - } - - // - // If the incoming `proxySocket` socket closes, then - // detach all event listeners. - // - listeners.onIncomingClose = function () { - reverseProxy.incoming.socket.destroy(); - detach(); - - // Emit the `end` event now that we have completed proxying - self.emit('websocket:end', req, socket, head); - } - - // - // If the `reverseProxy` socket closes, then detach all - // event listeners. - // - listeners.onOutgoingClose = function () { - proxySocket.destroy(); - detach(); - } - - proxySocket.on('end', listeners.onIncomingClose); - proxySocket.on('close', listeners.onIncomingClose); - reverseProxy.incoming.socket.on('end', listeners.onOutgoingClose); - reverseProxy.incoming.socket.on('close', listeners.onOutgoingClose); - } - - function getPort (port) { - port = port || 80; - return port - 80 === 0 ? '' : ':' + port; - } - - // - // Get the protocol, and host for this request and create an instance - // of `http.Agent` or `https.Agent` from the pool managed by `node-http-proxy`. - // - var agent = this.target.agent, - protocolName = this.target.https ? 'https' : 'http', - portUri = getPort(this.source.port), - remoteHost = this.target.host + portUri; - - // - // Change headers (if requested). - // - if (this.changeOrigin) { - req.headers.host = remoteHost; - req.headers.origin = protocolName + '://' + remoteHost; - } - - // - // Make the outgoing WebSocket request - // - outgoing.host = this.target.host; - outgoing.port = this.target.port; - outgoing.agent = agent; - outgoing.method = 'GET'; - outgoing.path = req.url; - outgoing.headers = req.headers; - outgoing.agent = agent; - - var reverseProxy = this.target.protocol.request(outgoing); - - // - // On any errors from the `reverseProxy` emit the - // `webSocketProxyError` and close the appropriate - // connections. - // - function proxyError (err) { - reverseProxy.destroy(); - - process.nextTick(function () { - // - // Destroy the incoming socket in the next tick, in case the error handler - // wants to write to it. - // - socket.destroy(); - }); - - self.emit('webSocketProxyError', err, req, socket, head); - } - - // - // Here we set the incoming `req`, `socket` and `head` data to the outgoing - // request so that we can reuse this data later on in the closure scope - // available to the `upgrade` event. This bookkeeping is not tracked anywhere - // in nodejs core and is **very** specific to proxying WebSockets. - // - reverseProxy.incoming = { - request: req, - socket: socket, - head: head - }; - - // - // Here we set the handshake `headers` and `statusCode` data to the outgoing - // request so that we can reuse this data later. - // - reverseProxy.handshake = { - headers: {}, - statusCode: null, - } - - // - // If the agent for this particular `host` and `port` combination - // is not already listening for the `upgrade` event, then do so once. - // This will force us not to disconnect. - // - // In addition, it's important to note the closure scope here. Since - // there is no mapping of the socket to the request bound to it. - // - reverseProxy.on('upgrade', function (res, remoteSocket, head) { - // - // Prepare handshake response 'headers' and 'statusCode'. - // - reverseProxy.handshake = { - headers: res.headers, - statusCode: res.statusCode, - } - - // - // Prepare the socket for the reverseProxy request and begin to - // stream data between the two sockets. Here it is important to - // note that `remoteSocket._httpMessage === reverseProxy`. - // - _socket(remoteSocket, true); - onUpgrade(remoteSocket._httpMessage, remoteSocket); - }); - - // - // If the reverseProxy connection has an underlying socket, - // then execute the WebSocket handshake. - // - reverseProxy.once('socket', function (revSocket) { - revSocket.on('data', function handshake (data) { - // Set empty headers - var headers = ''; - - // - // If the handshake statusCode 101, concat headers. - // - if (reverseProxy.handshake.statusCode && reverseProxy.handshake.statusCode == 101) { - headers = [ - 'HTTP/1.1 101 Switching Protocols', - 'Upgrade: websocket', - 'Connection: Upgrade', - 'Sec-WebSocket-Accept: ' + reverseProxy.handshake.headers['sec-websocket-accept'] - ]; - - headers = headers.concat('', '').join('\r\n'); - } - - // - // Ok, kind of harmfull part of code. Socket.IO sends a hash - // at the end of handshake if protocol === 76, but we need - // to replace 'host' and 'origin' in response so we split - // data to printable data and to non-printable. (Non-printable - // will come after double-CRLF). - // - var sdata = data.toString(); - - // Get the Printable data - sdata = sdata.substr(0, sdata.search(CRLF + CRLF)); - - // Get the Non-Printable data - data = data.slice(Buffer.byteLength(sdata), data.length); - - if (self.source.https && !self.target.https) { - // - // If the proxy server is running HTTPS but the client is running - // HTTP then replace `ws` with `wss` in the data sent back to the client. - // - sdata = sdata.replace('ws:', 'wss:'); - } - - try { - // - // Write the printable and non-printable data to the socket - // from the original incoming request. - // - self.emit('websocket:handshake', req, socket, head, sdata, data); - // add headers to the socket - socket.write(headers + sdata); - var flushed = socket.write(data); - if (!flushed) { - revSocket.pause(); - socket.once('drain', function () { - try { revSocket.resume() } - catch (er) { console.error("reverseProxy.socket.resume error: %s", er.message) } - }); - - // - // Force the `drain` event in 100ms if it hasn't - // happened on its own. - // - setTimeout(function () { - socket.emit('drain'); - }, 100); - } - } - catch (ex) { - // - // Remove data listener on socket error because the - // 'handshake' has failed. - // - revSocket.removeListener('data', handshake); - return proxyError(ex); - } - - // - // Remove data listener now that the 'handshake' is complete - // - revSocket.removeListener('data', handshake); - }); - }); - - // - // Handle 'error' events from the `reverseProxy`. - // - reverseProxy.on('error', proxyError); - - // - // Handle 'error' events from the `req` (e.g. `Parse Error`). - // - req.on('error', proxyError); - - try { - // - // Attempt to write the upgrade-head to the reverseProxy - // request. This is small, and there's only ever one of - // it; no need for pause/resume. - // - // XXX This is very wrong and should be fixed in node's core - // - reverseProxy.write(head); - if (head && head.length === 0) { - reverseProxy._send(''); - } - } - catch (ex) { - return proxyError(ex); - } - - // - // If we have been passed buffered data, resume it. - // - if (buffer) { - return !errState - ? buffer.resume() - : buffer.destroy(); - } -}; - -// -// ### function close() -// Closes all sockets associated with the Agents -// belonging to this instance. -// -HttpProxy.prototype.close = function () { - [this.forward, this.target].forEach(function (proxy) { - if (proxy && proxy.agent) { - for (var host in proxy.agent.sockets) { - proxy.agent.sockets[host].forEach(function (socket) { - socket.end(); - }); - } - } - }); -}; - -// -// ### @private function _forwardRequest (req) -// #### @req {ServerRequest} Incoming HTTP Request to proxy. -// Forwards the specified `req` to the location specified -// by `this.forward` ignoring errors and the subsequent response. -// -HttpProxy.prototype._forwardRequest = function (req) { - var self = this, - outgoing = new(this.forward.base), - forwardProxy; - - // - // Setup outgoing proxy with relevant properties. - // - outgoing.host = this.forward.host; - outgoing.port = this.forward.port, - outgoing.agent = this.forward.agent; - outgoing.method = req.method; - outgoing.path = req.url; - outgoing.headers = req.headers; - - // - // Open new HTTP request to internal resource with will - // act as a reverse proxy pass. - // - forwardProxy = this.forward.protocol.request(outgoing, function (response) { - // - // Ignore the response from the forward proxy since this is a 'fire-and-forget' proxy. - // Remark (indexzero): We will eventually emit a 'forward' event here for performance tuning. - // - }); - - // - // Add a listener for the connection timeout event. - // - // Remark: Ignoring this error in the event - // forward target doesn't exist. - // - forwardProxy.once('error', function (err) { }); - - // - // Chunk the client request body as chunks from - // the proxied request come in - // - req.on('data', function (chunk) { - var flushed = forwardProxy.write(chunk); - if (!flushed) { - req.pause(); - forwardProxy.once('drain', function () { - try { req.resume() } - catch (er) { console.error("req.resume error: %s", er.message) } - }); - - // - // Force the `drain` event in 100ms if it hasn't - // happened on its own. - // - setTimeout(function () { - forwardProxy.emit('drain'); - }, 100); - } - }); - - // - // At the end of the client request, we are going to - // stop the proxied request - // - req.on('end', function () { - forwardProxy.end(); - }); -}; - -function getPortFromHostHeader(req) { - var match; - if ((match = extractPort.exec(req.headers.host))) { - return parseInt(match[1]); - } - - return getProto(req) === 'https' ? 443 : 80; -} - -function getProto(req) { - return req.isSpdy ? 'https' : (req.connection.pair ? 'https' : 'http'); -} diff --git a/lib/node-http-proxy/proxy-table.js b/lib/node-http-proxy/proxy-table.js deleted file mode 100644 index 320396fe8..000000000 --- a/lib/node-http-proxy/proxy-table.js +++ /dev/null @@ -1,282 +0,0 @@ -/* - node-http-proxy.js: Lookup table for proxy targets in node.js - - Copyright (c) 2010 Charlie Robbins - - 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'), - events = require('events'), - fs = require('fs'), - url = require('url'); - -// -// ### function ProxyTable (router, silent) -// #### @router {Object} Object containing the host based routes -// #### @silent {Boolean} Value indicating whether we should suppress logs -// #### @hostnameOnly {Boolean} Value indicating if we should route based on __hostname string only__ -// #### @pathnameOnly {Boolean} Value indicating if we should route based on only the pathname. __This causes hostnames to be ignored.__. Using this along with hostnameOnly wont work at all. -// Constructor function for the ProxyTable responsible for getting -// locations of proxy targets based on ServerRequest headers; specifically -// the HTTP host header. -// -var ProxyTable = exports.ProxyTable = function (options) { - events.EventEmitter.call(this); - - this.silent = options.silent || options.silent !== true; - this.target = options.target || {}; - this.pathnameOnly = options.pathnameOnly === true; - this.hostnameOnly = options.hostnameOnly === true; - - if (typeof options.router === 'object') { - // - // If we are passed an object literal setup - // the routes with RegExps from the router - // - this.setRoutes(options.router); - } - else if (typeof options.router === 'string') { - // - // If we are passed a string then assume it is a - // file path, parse that file and watch it for changes - // - var self = this; - this.routeFile = options.router; - this.setRoutes(JSON.parse(fs.readFileSync(options.router)).router); - - fs.watchFile(this.routeFile, function () { - fs.readFile(self.routeFile, function (err, data) { - if (err) { - self.emit('error', err); - } - - self.setRoutes(JSON.parse(data).router); - self.emit('routes', self.hostnameOnly === false ? self.routes : self.router); - }); - }); - } - else { - throw new Error('Cannot parse router with unknown type: ' + typeof router); - } -}; - -// -// Inherit from `events.EventEmitter` -// -util.inherits(ProxyTable, events.EventEmitter); - -// -// ### function addRoute (route, target) -// #### @route {String} String containing route coming in -// #### @target {String} String containing the target -// Adds a host-based route to this instance. -// -ProxyTable.prototype.addRoute = function (route, target) { - if (!this.router) { - throw new Error('Cannot update ProxyTable routes without router.'); - } - - this.router[route] = target; - this.setRoutes(this.router); -}; - -// -// ### function removeRoute (route) -// #### @route {String} String containing route to remove -// Removes a host-based route from this instance. -// -ProxyTable.prototype.removeRoute = function (route) { - if (!this.router) { - throw new Error('Cannot update ProxyTable routes without router.'); - } - - delete this.router[route]; - this.setRoutes(this.router); -}; - -// -// ### function setRoutes (router) -// #### @router {Object} Object containing the host based routes -// Sets the host-based routes to be used by this instance. -// -ProxyTable.prototype.setRoutes = function (router) { - if (!router) { - throw new Error('Cannot update ProxyTable routes without router.'); - } - - var self = this; - this.router = router; - - if (this.hostnameOnly === false) { - this.routes = []; - - Object.keys(router).forEach(function (path) { - if (!/http[s]?/.test(router[path])) { - router[path] = (self.target.https ? 'https://' : 'http://') - + router[path]; - } - - var target = url.parse(router[path]), - defaultPort = self.target.https ? 443 : 80; - - // - // Setup a robust lookup table for the route: - // - // { - // source: { - // regexp: /^foo.com/i, - // sref: 'foo.com', - // url: { - // protocol: 'http:', - // slashes: true, - // host: 'foo.com', - // hostname: 'foo.com', - // href: 'http://foo.com/', - // pathname: '/', - // path: '/' - // } - // }, - // { - // target: { - // sref: '127.0.0.1:8000/', - // url: { - // protocol: 'http:', - // slashes: true, - // host: '127.0.0.1:8000', - // hostname: '127.0.0.1', - // href: 'http://127.0.0.1:8000/', - // pathname: '/', - // path: '/' - // } - // }, - // - self.routes.push({ - source: { - regexp: new RegExp('^' + path, 'i'), - sref: path, - url: url.parse('http://' + path) - }, - target: { - sref: target.hostname + ':' + (target.port || defaultPort) + target.path, - url: target - } - }); - }); - } -}; - -// -// ### function getProxyLocation (req) -// #### @req {ServerRequest} The incoming server request to get proxy information about. -// Returns the proxy location based on the HTTP Headers in the ServerRequest `req` -// available to this instance. -// -ProxyTable.prototype.getProxyLocation = function (req) { - if (!req || !req.headers || !req.headers.host) { - return null; - } - - var targetHost = req.headers.host.split(':')[0]; - if (this.hostnameOnly === true) { - var target = targetHost; - if (this.router.hasOwnProperty(target)) { - var location = this.router[target].split(':'), - host = location[0], - port = location.length === 1 ? 80 : location[1]; - - return { - port: port, - host: host - }; - } - } - else if (this.pathnameOnly === true) { - var target = req.url; - for (var i in this.routes) { - var route = this.routes[i]; - // - // If we are matching pathname only, we remove the matched pattern. - // - // IE /wiki/heartbeat - // is redirected to - // /heartbeat - // - // for the route "/wiki" : "127.0.0.1:8020" - // - if (target.match(route.source.regexp)) { - req.url = url.format(target.replace(route.source.regexp, '')); - return { - protocol: route.target.url.protocol.replace(':', ''), - host: route.target.url.hostname, - port: route.target.url.port - || (this.target.https ? 443 : 80) - }; - } - } - - } - else { - var target = targetHost + req.url; - for (var i in this.routes) { - var route = this.routes[i]; - if (target.match(route.source.regexp)) { - // - // Attempt to perform any path replacement for differences - // between the source path and the target path. This replaces the - // path's part of the URL to the target's part of the URL. - // - // 1. Parse the request URL - // 2. Replace any portions of the source path with the target path - // 3. Set the request URL to the formatted URL with replacements. - // - var parsed = url.parse(req.url); - - parsed.pathname = parsed.pathname.replace( - route.source.url.pathname, - route.target.url.pathname - ); - - req.url = url.format(parsed); - - return { - protocol: route.target.url.protocol.replace(':', ''), - host: route.target.url.hostname, - port: route.target.url.port - || (this.target.https ? 443 : 80) - }; - } - } - } - - return null; -}; - -// -// ### close function () -// Cleans up the event listeneners maintained -// by this instance. -// -ProxyTable.prototype.close = function () { - if (typeof this.routeFile === 'string') { - fs.unwatchFile(this.routeFile); - } -}; diff --git a/lib/node-http-proxy/routing-proxy.js b/lib/node-http-proxy/routing-proxy.js deleted file mode 100644 index b294fb15d..000000000 --- a/lib/node-http-proxy/routing-proxy.js +++ /dev/null @@ -1,322 +0,0 @@ -/* - * routing-proxy.js: A routing proxy consuming a RoutingTable and multiple HttpProxy instances - * - * (C) 2011 Nodejitsu Inc. - * MIT LICENCE - * - */ - -var events = require('events'), - utile = require('utile'), - HttpProxy = require('./http-proxy').HttpProxy, - ProxyTable = require('./proxy-table').ProxyTable; - -// -// ### function RoutingProxy (options) -// #### @options {Object} Options for this instance -// Constructor function for the RoutingProxy object, a higher level -// reverse proxy Object which can proxy to multiple hosts and also interface -// easily with a RoutingTable instance. -// -var RoutingProxy = exports.RoutingProxy = function (options) { - events.EventEmitter.call(this); - - var self = this; - options = options || {}; - - if (options.router) { - this.proxyTable = new ProxyTable(options); - this.proxyTable.on('routes', function (routes) { - self.emit('routes', routes); - }); - } - - // - // Create a set of `HttpProxy` objects to be used later on calls - // to `.proxyRequest()` and `.proxyWebSocketRequest()`. - // - this.proxies = {}; - - // - // Setup default target options (such as `https`). - // - this.target = {}; - this.target.https = options.target && options.target.https; - this.target.maxSockets = options.target && options.target.maxSockets; - - // - // Setup other default options to be used for instances of - // `HttpProxy` created by this `RoutingProxy` instance. - // - this.source = options.source || { host: 'localhost', port: 8000 }; - this.https = this.source.https || options.https; - this.enable = options.enable; - this.forward = options.forward; - this.changeOrigin = options.changeOrigin || false; - - // - // Listen for 'newListener' events so that we can bind 'proxyError' - // listeners to each HttpProxy's 'proxyError' event. - // - this.on('newListener', function (evt) { - if (evt === 'proxyError' || evt === 'webSocketProxyError') { - Object.keys(self.proxies).forEach(function (key) { - self.proxies[key].on(evt, self.emit.bind(self, evt)); - }); - } - }); -}; - - -// -// Inherit from `events.EventEmitter`. -// -utile.inherits(RoutingProxy, events.EventEmitter); - -// -// ### function add (options) -// #### @options {Object} Options for the `HttpProxy` to add. -// Adds a new instance of `HttpProxy` to this `RoutingProxy` instance -// for the specified `options.host` and `options.port`. -// -RoutingProxy.prototype.add = function (options) { - var self = this, - key = this._getKey(options); - - // - // TODO: Consume properties in `options` related to the `ProxyTable`. - // - options.target = options.target || {}; - options.target.host = options.target.host || options.host; - options.target.port = options.target.port || options.port; - options.target.socketPath = options.target.socketPath || options.socketPath; - options.target.https = this.target && this.target.https || - options.target && options.target.https; - options.target.maxSockets = this.target && this.target.maxSockets; - - // - // Setup options to pass-thru to the new `HttpProxy` instance - // for the specified `options.host` and `options.port` pair. - // - ['https', 'enable', 'forward', 'changeOrigin'].forEach(function (key) { - if (options[key] !== false && self[key]) { - options[key] = self[key]; - } - }); - - this.proxies[key] = new HttpProxy(options); - - if (this.listeners('proxyError').length > 0) { - this.proxies[key].on('proxyError', this.emit.bind(this, 'proxyError')); - } - - if (this.listeners('webSocketProxyError').length > 0) { - this.proxies[key].on('webSocketProxyError', this.emit.bind(this, 'webSocketProxyError')); - } - - [ - 'start', - 'forward', - 'end', - 'proxyResponse', - 'websocket:start', - 'websocket:end', - 'websocket:incoming', - 'websocket:outgoing' - ].forEach(function (event) { - this.proxies[key].on(event, this.emit.bind(this, event)); - }, this); -}; - -// -// ### function remove (options) -// #### @options {Object} Options mapping to the `HttpProxy` to remove. -// Removes an instance of `HttpProxy` from this `RoutingProxy` instance -// for the specified `options.host` and `options.port` (if they exist). -// -RoutingProxy.prototype.remove = function (options) { - var key = this._getKey(options), - proxy = this.proxies[key]; - - delete this.proxies[key]; - return proxy; -}; - -// -// ### function close() -// Cleans up any state left behind (sockets, timeouts, etc) -// associated with this instance. -// -RoutingProxy.prototype.close = function () { - var self = this; - - if (this.proxyTable) { - // - // Close the `RoutingTable` associated with - // this instance (if any). - // - this.proxyTable.close(); - } - - // - // Close all sockets for all `HttpProxy` object(s) - // associated with this instance. - // - Object.keys(this.proxies).forEach(function (key) { - self.proxies[key].close(); - }); -}; - -// -// ### function proxyRequest (req, res, [port, host, paused]) -// #### @req {ServerRequest} Incoming HTTP Request to proxy. -// #### @res {ServerResponse} Outgoing HTTP Request to write proxied data to. -// #### @options {Object} Options for the outgoing proxy request. -// -// options.port {number} Port to use on the proxy target host. -// options.host {string} Host of the proxy target. -// options.buffer {Object} Result from `httpProxy.buffer(req)` -// options.https {Object|boolean} Settings for https. -// -RoutingProxy.prototype.proxyRequest = function (req, res, options) { - options = options || {}; - - var location; - - // - // Check the proxy table for this instance to see if we need - // to get the proxy location for the request supplied. We will - // always ignore the proxyTable if an explicit `port` and `host` - // arguments are supplied to `proxyRequest`. - // - if (this.proxyTable && !options.host) { - location = this.proxyTable.getProxyLocation(req); - - // - // If no location is returned from the ProxyTable instance - // then respond with `404` since we do not have a valid proxy target. - // - if (!location) { - try { - if (!this.emit('notFound', req, res)) { - res.writeHead(404); - res.end(); - } - } - catch (er) { - console.error("res.writeHead/res.end error: %s", er.message); - } - - return; - } - - // - // When using the ProxyTable in conjunction with an HttpProxy instance - // only the following arguments are valid: - // - // * `proxy.proxyRequest(req, res, { host: 'localhost' })`: This will be skipped - // * `proxy.proxyRequest(req, res, { buffer: buffer })`: Buffer will get updated appropriately - // * `proxy.proxyRequest(req, res)`: Options will be assigned appropriately. - // - options.port = location.port; - options.host = location.host; - } - - var key = this._getKey(options), - proxy; - - if ((this.target && this.target.https) - || (location && location.protocol === 'https')) { - options.target = options.target || {}; - options.target.https = true; - } - - if (!this.proxies[key]) { - this.add(utile.clone(options)); - } - - proxy = this.proxies[key]; - proxy.proxyRequest(req, res, options.buffer); -}; - -// -// ### function proxyWebSocketRequest (req, socket, head, options) -// #### @req {ServerRequest} Websocket request to proxy. -// #### @socket {net.Socket} Socket for the underlying HTTP request -// #### @head {string} Headers for the Websocket request. -// #### @options {Object} Options to use when proxying this request. -// -// options.port {number} Port to use on the proxy target host. -// options.host {string} Host of the proxy target. -// options.buffer {Object} Result from `httpProxy.buffer(req)` -// options.https {Object|boolean} Settings for https. -// -RoutingProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options) { - options = options || {}; - - var location, - proxy, - key; - - if (this.proxyTable && !options.host) { - location = this.proxyTable.getProxyLocation(req); - - if (!location) { - return socket.destroy(); - } - - options.port = location.port; - options.host = location.host; - } - - key = this._getKey(options); - - if (!this.proxies[key]) { - this.add(utile.clone(options)); - } - - proxy = this.proxies[key]; - proxy.proxyWebSocketRequest(req, socket, head, options.buffer); -}; - -// -// ### function addHost (host, target) -// #### @host {String} Host to add to proxyTable -// #### @target {String} Target to add to proxyTable -// Adds a host to proxyTable -// -RoutingProxy.prototype.addHost = function (host, target) { - if (this.proxyTable) { - this.proxyTable.addRoute(host, target); - } -}; - -// -// ### function removeHost (host) -// #### @host {String} Host to remove from proxyTable -// Removes a host to proxyTable -// -RoutingProxy.prototype.removeHost = function (host) { - if (this.proxyTable) { - this.proxyTable.removeRoute(host); - } -}; - -// -// ### @private function _getKey (options) -// #### @options {Object} Options to extract the key from -// Ensures that the appropriate options are present in the `options` -// provided and responds with a string key representing the `host`, `port` -// combination contained within. -// -RoutingProxy.prototype._getKey = function (options) { - if (!options || ((!options.host || !options.port) - && (!options.target || !options.target.host || !options.target.port))) { - throw new Error('options.host and options.port or options.target are required.'); - } - - return [ - options.host || options.target.host, - options.port || options.target.port - ].join(':'); -}; diff --git a/package.json b/package.json deleted file mode 100644 index cd3ff0add..000000000 --- a/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "http-proxy", - "version": "0.10.4", - "description": "A full-featured http reverse proxy for node.js", - "author": "Nodejitsu Inc. ", - "maintainers": [ - "indexzero ", - "AvianFlu " - ], - "repository": { - "type": "git", - "url": "http://github.com/nodejitsu/node-http-proxy.git" - }, - "keywords": [ - "reverse", - "proxy", - "http" - ], - "dependencies": { - "colors": "0.x.x", - "optimist": "0.6.x", - "pkginfo": "0.3.x", - "utile": "~0.2.1" - }, - "devDependencies": { - "request": "2.14.x", - "vows": "0.7.x", - "async": "0.2.x", - "socket.io": "0.9.11", - "socket.io-client": "0.9.11", - "ws": "0.4.23" - }, - "main": "./lib/node-http-proxy", - "bin": { - "node-http-proxy": "./bin/node-http-proxy" - }, - "scripts": { - "test": "npm run-script test-http && npm run-script test-https && npm run-script test-core", - "test-http": "vows --spec && vows --spec --target=https", - "test-https": "vows --spec --proxy=https && vows --spec --proxy=https --target=https", - "test-core": "test/core/run" - }, - "engines": { - "node": ">= 0.6.6" - } -} - diff --git a/test/core/README.md b/test/core/README.md deleted file mode 100644 index 152e5c668..000000000 --- a/test/core/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# `test/core` - -`test/core` directory is a place where tests from node.js core go. They are -here to ensure that node-http-proxy works just fine with all kinds of -different situations, which are covered in core tests, but are not covered in -our tests. - -All these tests require little modifications to make them test node-http-proxy, -but we try to keep them as vanilla as possible. - diff --git a/test/core/common.js b/test/core/common.js deleted file mode 100644 index 3f584a543..000000000 --- a/test/core/common.js +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 path = require('path'); -var assert = require('assert'); - -exports.testDir = path.dirname(__filename); -exports.fixturesDir = path.join(exports.testDir, 'fixtures'); -exports.libDir = path.join(exports.testDir, '../lib'); -exports.tmpDir = path.join(exports.testDir, 'tmp'); -exports.PORT = 12346; -exports.PROXY_PORT = 1234567; - -if (process.platform === 'win32') { - exports.PIPE = '\\\\.\\pipe\\libuv-test'; -} else { - exports.PIPE = exports.tmpDir + '/test.sock'; -} - -var util = require('util'); -for (var i in util) exports[i] = util[i]; -//for (var i in exports) global[i] = exports[i]; - -function protoCtrChain(o) { - var result = []; - for (; o; o = o.__proto__) { result.push(o.constructor); } - return result.join(); -} - -exports.indirectInstanceOf = function (obj, cls) { - if (obj instanceof cls) { return true; } - var clsChain = protoCtrChain(cls.prototype); - var objChain = protoCtrChain(obj); - return objChain.slice(-clsChain.length) === clsChain; -}; - - -exports.ddCommand = function (filename, kilobytes) { - if (process.platform === 'win32') { - var p = path.resolve(exports.fixturesDir, 'create-file.js'); - return '"' + process.argv[0] + '" "' + p + '" "' + - filename + '" ' + (kilobytes * 1024); - } else { - return 'dd if=/dev/zero of="' + filename + '" bs=1024 count=' + kilobytes; - } -}; - - -exports.spawnPwd = function (options) { - var spawn = require('child_process').spawn; - - if (process.platform === 'win32') { - return spawn('cmd.exe', ['/c', 'cd'], options); - } else { - return spawn('pwd', [], options); - } -}; - - -// Turn this off if the test should not check for global leaks. -exports.globalCheck = true; - -process.on('exit', function () { - if (!exports.globalCheck) return; - var knownGlobals = [setTimeout, - setInterval, - clearTimeout, - clearInterval, - console, - Buffer, - process, - global]; - - if (global.setImmediate) { - knownGlobals.push(setImmediate); - knownGlobals.push(clearImmediate); - } - - if (global.errno) { - knownGlobals.push(errno); - } - - if (global.gc) { - knownGlobals.push(gc); - } - - if (global.DTRACE_HTTP_SERVER_RESPONSE) { - knownGlobals.push(DTRACE_HTTP_SERVER_RESPONSE); - knownGlobals.push(DTRACE_HTTP_SERVER_REQUEST); - knownGlobals.push(DTRACE_HTTP_CLIENT_RESPONSE); - knownGlobals.push(DTRACE_HTTP_CLIENT_REQUEST); - knownGlobals.push(DTRACE_NET_STREAM_END); - knownGlobals.push(DTRACE_NET_SERVER_CONNECTION); - knownGlobals.push(DTRACE_NET_SOCKET_READ); - knownGlobals.push(DTRACE_NET_SOCKET_WRITE); - } - - if (global.ArrayBuffer) { - knownGlobals.push(ArrayBuffer); - knownGlobals.push(Int8Array); - knownGlobals.push(Uint8Array); - knownGlobals.push(Int16Array); - knownGlobals.push(Uint16Array); - knownGlobals.push(Int32Array); - knownGlobals.push(Uint32Array); - knownGlobals.push(Float32Array); - knownGlobals.push(Float64Array); - knownGlobals.push(DataView); - - if (global.Uint8ClampedArray) { - knownGlobals.push(Uint8ClampedArray); - } - } - - for (var x in global) { - var found = false; - - for (var y in knownGlobals) { - if (global[x] === knownGlobals[y]) { - found = true; - break; - } - } - - if (!found) { - console.error('Unknown global: %s', x); - assert.ok(false, 'Unknown global found'); - } - } -}); - - -var mustCallChecks = []; - - -function runCallChecks() { - var failed = mustCallChecks.filter(function (context) { - return context.actual !== context.expected; - }); - - failed.forEach(function (context) { - console.log('Mismatched %s function calls. Expected %d, actual %d.', - context.name, - context.expected, - context.actual); - console.log(context.stack.split('\n').slice(2).join('\n')); - }); - - if (failed.length) process.exit(1); -} - - -exports.mustCall = function (fn, expected) { - if (typeof expected !== 'number') expected = 1; - - var context = { - expected: expected, - actual: 0, - stack: (new Error).stack, - name: fn.name || '' - }; - - // add the exit listener only once to avoid listener leak warnings - if (mustCallChecks.length === 0) process.on('exit', runCallChecks); - - mustCallChecks.push(context); - - return function () { - context.actual++; - return fn.apply(this, arguments); - }; -}; diff --git a/test/core/pummel/test-http-upload-timeout.js b/test/core/pummel/test-http-upload-timeout.js deleted file mode 100644 index 74b458f8b..000000000 --- a/test/core/pummel/test-http-upload-timeout.js +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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. - -// This tests setTimeout() by having multiple clients connecting and sending -// data in random intervals. Clients are also randomly disconnecting until there -// are no more clients left. If no false timeout occurs, this test has passed. -var common = require('../common'), - assert = require('assert'), - http = require('http'), - server = http.createServer(), - connections = 0; - -server.on('request', function (req, res) { - req.socket.setTimeout(1000); - req.socket.on('timeout', function () { - throw new Error('Unexpected timeout'); - }); - req.on('end', function () { - connections--; - res.writeHead(200); - res.end('done\n'); - if (connections == 0) { - server.close(); - } - }); -}); - -server.listen(common.PORT, '127.0.0.1', function () { - for (var i = 0; i < 10; i++) { - connections++; - - setTimeout(function () { - var request = http.request({ - port: common.PROXY_PORT, - method: 'POST', - path: '/' - }); - - function ping() { - var nextPing = (Math.random() * 900).toFixed(); - if (nextPing > 600) { - request.end(); - return; - } - request.write('ping'); - setTimeout(ping, nextPing); - } - ping(); - }, i * 50); - } -}); diff --git a/test/core/run b/test/core/run deleted file mode 100755 index adec53bab..000000000 --- a/test/core/run +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env node -/* - run.js: test runner for core tests - - Copyright (c) 2011 Nodejitsu - - 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 fs = require('fs'), - path = require('path'), - spawn = require('child_process').spawn, - async = require('async'), - colors = require('colors'), - optimist = require('optimist'); - -optimist.argv.color && (colors.mode = optimist.argv.color); - -var testTimeout = 15000; -var results = {}; - -function runTest(test, callback) { - var child = spawn(path.join(__dirname, 'run-single'), [ test ]); - - var killTimeout = setTimeout(function () { - child.kill(); - console.log(' ' + path.basename(test).yellow + ' timed out'.red); - }, testTimeout); - - child.on('exit', function (exitCode) { - clearTimeout(killTimeout); - - console.log(' ' + ((exitCode) ? '✘'.red : '✔'.green) + ' ' + - path.basename(test) + - (exitCode ? (' (exit code: ' + exitCode + ')') : '')); - results[test] = { exitCode: exitCode }; - callback(); - // - // We don't want tests to be stopped after first failure, and that's what - // async does when it receives truthy value in callback. - // - }); -}; - -var tests = process.argv.slice(2).filter(function (test) { - return test.substr(0, 2) != '--'; -}); - -if (!tests.length) { - var pathPrefix = path.join(__dirname, 'simple'); - tests = fs.readdirSync(pathPrefix).map(function (test) { - return path.join(pathPrefix, test); - }); - // - // We only run simple tests by default. - // -} - -console.log('Running tests:'.bold); -async.forEachSeries(tests, runTest, function () { - var failed = [], ok = []; - for (var test in results) { - (results[test].exitCode != 0 ? failed : ok).push(test); - } - - console.log('\nSummary:'.bold); - console.log((' ' + ok.length + '\tpassed tests').green); - console.log((' ' + failed.length + '\tfailed tests').red); -}); - -// vim:filetype=javascript - diff --git a/test/core/run-single b/test/core/run-single deleted file mode 100755 index ae53588af..000000000 --- a/test/core/run-single +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env node -/* - run-single.js: test runner for core tests - - Copyright (c) 2011 Nodejitsu - - 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. - -*/ - -// -// Basic idea behind core test runner is to modify core tests as little as -// possible. That's why we start up node-http-proxy here instead of embeeding -// this code in tests. -// -// In most cases only modification to core tests you'll need is changing port -// of http client to common.PROXY_PORT. -// - -var path = require('path'), - spawn = require('child_process').spawn, - httpProxy = require('../../'), - common = require('./common'); - -var test = process.argv[2], - testProcess; - -if (!test) { - return console.error('Need test to run'); -} - -console.log('Running test ' + test); - -var proxy = httpProxy.createServer(common.PORT, 'localhost'); -proxy.listen(common.PROXY_PORT); - -proxy.on('listening', function () { - console.log('Proxy server listening on ' + common.PROXY_PORT); - testProcess = spawn(process.argv[0], [ process.argv[2] ]); - testProcess.stdout.pipe(process.stdout); - testProcess.stderr.pipe(process.stderr); - - testProcess.on('exit', function (code) { - process.exit(code); - }); -}); - -process.on('SIGTERM', function () { - testProcess.kill(); - process.exit(1); -}); - -// vim:filetype=javascript diff --git a/test/core/simple/test-http-chunked.js b/test/core/simple/test-http-chunked.js deleted file mode 100644 index b1cbf0dbb..000000000 --- a/test/core/simple/test-http-chunked.js +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); - -var UTF8_STRING = '南越国是前203年至前111年存在于岭南地区的一个国家,' + - '国都位于番禺,疆域包括今天中国的广东、广西两省区的大部份地区,福建省、湖南、' + - '贵州、云南的一小部份地区和越南的北部。南越国是秦朝灭亡后,' + - '由南海郡尉赵佗于前203年起兵兼并桂林郡和象郡后建立。前196年和前179年,' + - '南越国曾先后两次名义上臣属于西汉,成为西汉的“外臣”。前112年,' + - '南越国末代君主赵建德与西汉发生战争,被汉武帝于前111年所灭。' + - '南越国共存在93年,历经五代君主。南越国是岭南地区的第一个有记载的政权国家,' + - '采用封建制和郡县制并存的制度,它的建立保证了秦末乱世岭南地区社会秩序的稳定,' + - '有效的改善了岭南地区落后的政治、经济现状。'; - -var server = http.createServer(function (req, res) { - res.writeHead(200, {'Content-Type': 'text/plain; charset=utf8'}); - res.end(UTF8_STRING, 'utf8'); -}); -server.listen(common.PORT, function () { - var data = ''; - var get = http.get({ - path: '/', - host: 'localhost', - port: common.PROXY_PORT - }, function (x) { - x.setEncoding('utf8'); - x.on('data', function (c) {data += c}); - x.on('error', function (e) { - throw e; - }); - x.on('end', function () { - assert.equal('string', typeof data); - console.log('here is the response:'); - assert.equal(UTF8_STRING, data); - console.log(data); - server.close(); - }); - }); - get.on('error', function (e) {throw e}); - get.end(); - -}); diff --git a/test/core/simple/test-http-client-abort.js b/test/core/simple/test-http-client-abort.js deleted file mode 100644 index 78d0a6f93..000000000 --- a/test/core/simple/test-http-client-abort.js +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); - -var clientAborts = 0; - -var server = http.Server(function (req, res) { - console.log('Got connection'); - res.writeHead(200); - res.write('Working on it...'); - - // I would expect an error event from req or res that the client aborted - // before completing the HTTP request / response cycle, or maybe a new - // event like "aborted" or something. - req.on('aborted', function () { - clientAborts++; - console.log('Got abort ' + clientAborts); - if (clientAborts === N) { - console.log('All aborts detected, you win.'); - server.close(); - } - }); - - // since there is already clientError, maybe that would be appropriate, - // since "error" is magical - req.on('clientError', function () { - console.log('Got clientError'); - }); -}); - -var responses = 0; -var N = http.Agent.defaultMaxSockets - 1; -var requests = []; - -server.listen(common.PORT, function () { - console.log('Server listening.'); - - for (var i = 0; i < N; i++) { - console.log('Making client ' + i); - var options = { port: common.PROXY_PORT, path: '/?id=' + i }; - var req = http.get(options, function (res) { - console.log('Client response code ' + res.statusCode); - - if (++responses == N) { - console.log('All clients connected, destroying.'); - requests.forEach(function (outReq) { - console.log('abort'); - outReq.abort(); - }); - } - }); - - requests.push(req); - } -}); - -process.on('exit', function () { - assert.equal(N, clientAborts); -}); diff --git a/test/core/simple/test-http-client-abort2.js b/test/core/simple/test-http-client-abort2.js deleted file mode 100644 index eef05fb46..000000000 --- a/test/core/simple/test-http-client-abort2.js +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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. - -// libuv-broken - - -var common = require('../common'); -var assert = require('assert'); -var http = require('http'); - -var server = http.createServer(function (req, res) { - res.end('Hello'); -}); - -server.listen(common.PORT, function () { - var req = http.get({port: common.PROXY_PORT}, function (res) { - res.on('data', function (data) { - req.abort(); - server.close(); - }); - }); -}); - diff --git a/test/core/simple/test-http-client-upload-buf.js b/test/core/simple/test-http-client-upload-buf.js deleted file mode 100644 index 3b8e9abce..000000000 --- a/test/core/simple/test-http-client-upload-buf.js +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); - -var N = 1024; -var bytesRecieved = 0; -var server_req_complete = false; -var client_res_complete = false; - -var server = http.createServer(function (req, res) { - assert.equal('POST', req.method); - - req.on('data', function (chunk) { - bytesRecieved += chunk.length; - }); - - req.on('end', function () { - server_req_complete = true; - console.log('request complete from server'); - res.writeHead(200, {'Content-Type': 'text/plain'}); - res.write('hello\n'); - res.end(); - }); -}); -server.listen(common.PORT); - -server.on('listening', function () { - var req = http.request({ - port: common.PROXY_PORT, - method: 'POST', - path: '/' - }, function (res) { - res.setEncoding('utf8'); - res.on('data', function (chunk) { - console.log(chunk); - }); - res.on('end', function () { - client_res_complete = true; - server.close(); - }); - }); - - req.write(new Buffer(N)); - req.end(); - - common.error('client finished sending request'); -}); - -process.on('exit', function () { - assert.equal(N, bytesRecieved); - assert.equal(true, server_req_complete); - assert.equal(true, client_res_complete); -}); diff --git a/test/core/simple/test-http-client-upload.js b/test/core/simple/test-http-client-upload.js deleted file mode 100644 index fef706f2a..000000000 --- a/test/core/simple/test-http-client-upload.js +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); - -var sent_body = ''; -var server_req_complete = false; -var client_res_complete = false; - -var server = http.createServer(function (req, res) { - assert.equal('POST', req.method); - req.setEncoding('utf8'); - - req.on('data', function (chunk) { - console.log('server got: ' + JSON.stringify(chunk)); - sent_body += chunk; - }); - - req.on('end', function () { - server_req_complete = true; - console.log('request complete from server'); - res.writeHead(200, {'Content-Type': 'text/plain'}); - res.write('hello\n'); - res.end(); - }); -}); -server.listen(common.PORT); - -server.on('listening', function () { - var req = http.request({ - port: common.PROXY_PORT, - method: 'POST', - path: '/' - }, function (res) { - res.setEncoding('utf8'); - res.on('data', function (chunk) { - console.log(chunk); - }); - res.on('end', function () { - client_res_complete = true; - server.close(); - }); - }); - - req.write('1\n'); - req.write('2\n'); - req.write('3\n'); - req.end(); - - common.error('client finished sending request'); -}); - -process.on('exit', function () { - assert.equal('1\n2\n3\n', sent_body); - assert.equal(true, server_req_complete); - assert.equal(true, client_res_complete); -}); diff --git a/test/core/simple/test-http-contentLength0.js b/test/core/simple/test-http-contentLength0.js deleted file mode 100644 index abc3747e1..000000000 --- a/test/core/simple/test-http-contentLength0.js +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var http = require('http'); - -// Simple test of Node's HTTP Client choking on a response -// with a 'Content-Length: 0 ' response header. -// I.E. a space character after the 'Content-Length' throws an `error` event. - - -var s = http.createServer(function (req, res) { - res.writeHead(200, {'Content-Length': '0 '}); - res.end(); -}); -s.listen(common.PORT, function () { - - var request = http.request({ port: common.PROXY_PORT }, function (response) { - console.log('STATUS: ' + response.statusCode); - s.close(); - }); - - request.end(); -}); diff --git a/test/core/simple/test-http-eof-on-connect.js b/test/core/simple/test-http-eof-on-connect.js deleted file mode 100644 index d02ee6d16..000000000 --- a/test/core/simple/test-http-eof-on-connect.js +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var net = require('net'); -var http = require('http'); - -// This is a regression test for http://github.com/ry/node/issues/#issue/44 -// It is separate from test-http-malformed-request.js because it is only -// reproduceable on the first packet on the first connection to a server. - -var server = http.createServer(function (req, res) {}); -server.listen(common.PORT); - -server.on('listening', function () { - net.createConnection(common.PROXY_PORT).on('connect', function () { - this.destroy(); - }).on('close', function () { - server.close(); - }); -}); diff --git a/test/core/simple/test-http-extra-response.js b/test/core/simple/test-http-extra-response.js deleted file mode 100644 index a3d27462f..000000000 --- a/test/core/simple/test-http-extra-response.js +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); -var net = require('net'); - -// If an HTTP server is broken and sends data after the end of the response, -// node should ignore it and drop the connection. -// Demos this bug: https://github.com/ry/node/issues/680 - -var body = 'hello world\r\n'; -var fullResponse = - 'HTTP/1.1 500 Internal Server Error\r\n' + - 'Content-Length: ' + body.length + '\r\n' + - 'Content-Type: text/plain\r\n' + - 'Date: Fri + 18 Feb 2011 06:22:45 GMT\r\n' + - 'Host: 10.20.149.2\r\n' + - 'Access-Control-Allow-Credentials: true\r\n' + - 'Server: badly broken/0.1 (OS NAME)\r\n' + - '\r\n' + - body; - -var gotResponse = false; - - -var server = net.createServer(function (socket) { - var postBody = ''; - - socket.setEncoding('utf8'); - - socket.on('data', function (chunk) { - postBody += chunk; - - if (postBody.indexOf('\r\n') > -1) { - socket.write(fullResponse); - // omg, I wrote the response twice, what a terrible HTTP server I am. - socket.end(fullResponse); - } - }); -}); - - -server.listen(common.PORT, function () { - http.get({ port: common.PROXY_PORT }, function (res) { - var buffer = ''; - console.log('Got res code: ' + res.statusCode); - - res.setEncoding('utf8'); - res.on('data', function (chunk) { - buffer += chunk; - }); - - res.on('end', function () { - console.log('Response ended, read ' + buffer.length + ' bytes'); - assert.equal(body, buffer); - server.close(); - gotResponse = true; - }); - }); -}); - - -process.on('exit', function () { - assert.ok(gotResponse); -}); - diff --git a/test/core/simple/test-http-head-request.js b/test/core/simple/test-http-head-request.js deleted file mode 100644 index e8c203ef9..000000000 --- a/test/core/simple/test-http-head-request.js +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); -var util = require('util'); - - -var body = 'hello world\n'; - -var server = http.createServer(function (req, res) { - common.error('req: ' + req.method); - res.writeHead(200, {'Content-Length': body.length}); - res.end(); - server.close(); -}); - -var gotEnd = false; - -server.listen(common.PORT, function () { - var request = http.request({ - port: common.PROXY_PORT, - method: 'HEAD', - path: '/' - }, function (response) { - common.error('response start'); - response.on('end', function () { - common.error('response end'); - gotEnd = true; - }); - }); - request.end(); -}); - -process.on('exit', function () { - assert.ok(gotEnd); -}); diff --git a/test/core/simple/test-http-head-response-has-no-body-end.js b/test/core/simple/test-http-head-response-has-no-body-end.js deleted file mode 100644 index 6d89bee9f..000000000 --- a/test/core/simple/test-http-head-response-has-no-body-end.js +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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. - -// libuv-broken - - -var common = require('../common'); -var assert = require('assert'); - -var http = require('http'); - -// This test is to make sure that when the HTTP server -// responds to a HEAD request with data to res.end, -// it does not send any body. - -var server = http.createServer(function (req, res) { - res.writeHead(200); - res.end('FAIL'); // broken: sends FAIL from hot path. -}); -server.listen(common.PORT); - -var responseComplete = false; - -server.on('listening', function () { - var req = http.request({ - port: common.PROXY_PORT, - method: 'HEAD', - path: '/' - }, function (res) { - common.error('response'); - res.on('end', function () { - common.error('response end'); - server.close(); - responseComplete = true; - }); - }); - common.error('req'); - req.end(); -}); - -process.on('exit', function () { - assert.ok(responseComplete); -}); diff --git a/test/core/simple/test-http-head-response-has-no-body.js b/test/core/simple/test-http-head-response-has-no-body.js deleted file mode 100644 index aa7a281b6..000000000 --- a/test/core/simple/test-http-head-response-has-no-body.js +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); - -var http = require('http'); - -// This test is to make sure that when the HTTP server -// responds to a HEAD request, it does not send any body. -// In this case it was sending '0\r\n\r\n' - -var server = http.createServer(function (req, res) { - res.writeHead(200); // broken: defaults to TE chunked - res.end(); -}); -server.listen(common.PORT); - -var responseComplete = false; - -server.on('listening', function () { - var req = http.request({ - port: common.PROXY_PORT, - method: 'HEAD', - path: '/' - }, function (res) { - common.error('response'); - res.on('end', function () { - common.error('response end'); - server.close(); - responseComplete = true; - }); - }); - common.error('req'); - req.end(); -}); - -process.on('exit', function () { - assert.ok(responseComplete); -}); diff --git a/test/core/simple/test-http-host-headers.js b/test/core/simple/test-http-host-headers.js deleted file mode 100644 index 2dae1182e..000000000 --- a/test/core/simple/test-http-host-headers.js +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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. - -// libuv-broken - - -var http = require('http'), - common = require('../common'), - assert = require('assert'), - httpServer = http.createServer(reqHandler); - -function reqHandler(req, res) { - console.log('Got request: ' + req.headers.host + ' ' + req.url); - if (req.url === '/setHostFalse5') { - assert.equal(req.headers.host, undefined); - } else { - assert.equal(req.headers.host, 'localhost:' + common.PROXY_PORT, - 'Wrong host header for req[' + req.url + ']: ' + - req.headers.host); - } - res.writeHead(200, {}); - //process.nextTick(function () { res.end('ok'); }); - res.end('ok'); -} - -function thrower(er) { - throw er; -} - -testHttp(); - -function testHttp() { - - console.log('testing http on port ' + common.PROXY_PORT + ' (proxied to ' + - common.PORT + ')'); - - var counter = 0; - - function cb() { - counter--; - console.log('back from http request. counter = ' + counter); - if (counter === 0) { - httpServer.close(); - } - } - - httpServer.listen(common.PORT, function (er) { - console.error('listening on ' + common.PORT); - - if (er) throw er; - - http.get({ method: 'GET', - path: '/' + (counter++), - host: 'localhost', - //agent: false, - port: common.PROXY_PORT }, cb).on('error', thrower); - - http.request({ method: 'GET', - path: '/' + (counter++), - host: 'localhost', - //agent: false, - port: common.PROXY_PORT }, cb).on('error', thrower).end(); - - http.request({ method: 'POST', - path: '/' + (counter++), - host: 'localhost', - //agent: false, - port: common.PROXY_PORT }, cb).on('error', thrower).end(); - - http.request({ method: 'PUT', - path: '/' + (counter++), - host: 'localhost', - //agent: false, - port: common.PROXY_PORT }, cb).on('error', thrower).end(); - - http.request({ method: 'DELETE', - path: '/' + (counter++), - host: 'localhost', - //agent: false, - port: common.PROXY_PORT }, cb).on('error', thrower).end(); - }); -} - diff --git a/test/core/simple/test-http-many-keep-alive-connections.js b/test/core/simple/test-http-many-keep-alive-connections.js deleted file mode 100644 index 6b79619bb..000000000 --- a/test/core/simple/test-http-many-keep-alive-connections.js +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); - -var expected = 10000; -var responses = 0; -var requests = 0; -var connection; - -var server = http.Server(function (req, res) { - requests++; - assert.equal(req.connection, connection); - res.writeHead(200); - res.end('hello world\n'); -}); - -server.once('connection', function (c) { - connection = c; -}); - -server.listen(common.PORT, function () { - var callee = arguments.callee; - var request = http.get({ - port: common.PROXY_PORT, - path: '/', - headers: { - 'Connection': 'Keep-alive' - } - }, function (res) { - res.on('end', function () { - if (++responses < expected) { - callee(); - } else { - process.exit(); - } - }); - }).on('error', function (e) { - console.log(e.message); - process.exit(1); - }); - request.agent.maxSockets = 1; -}); - -process.on('exit', function () { - assert.equal(expected, responses); - assert.equal(expected, requests); -}); diff --git a/test/core/simple/test-http-multi-line-headers.js b/test/core/simple/test-http-multi-line-headers.js deleted file mode 100644 index e0eeb2c18..000000000 --- a/test/core/simple/test-http-multi-line-headers.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); - -var http = require('http'); -var net = require('net'); - -var gotResponse = false; - -var server = net.createServer(function (conn) { - var body = 'Yet another node.js server.'; - - var response = - 'HTTP/1.1 200 OK\r\n' + - 'Connection: close\r\n' + - 'Content-Length: ' + body.length + '\r\n' + - 'Content-Type: text/plain;\r\n' + - ' x-unix-mode=0600;\r\n' + - ' name=\"hello.txt\"\r\n' + - '\r\n' + - body; - - conn.write(response, function () { - conn.destroy(); - server.close(); - }); -}); - -server.listen(common.PORT, function () { - http.get({host: '127.0.0.1', port: common.PROXY_PORT}, function (res) { - assert.equal(res.headers['content-type'], - 'text/plain;x-unix-mode=0600;name="hello.txt"'); - gotResponse = true; - }); -}); - -process.on('exit', function () { - assert.ok(gotResponse); -}); diff --git a/test/core/simple/test-http-proxy.js b/test/core/simple/test-http-proxy.js deleted file mode 100644 index fdddb3cdc..000000000 --- a/test/core/simple/test-http-proxy.js +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); -var url = require('url'); - -var PROXY_PORT = common.PORT; -var BACKEND_PORT = common.PORT + 1; - -var cookies = [ - 'session_token=; path=/; expires=Sun, 15-Sep-2030 13:48:52 GMT', - 'prefers_open_id=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT' -]; - -var headers = {'content-type': 'text/plain', - 'set-cookie': cookies, - 'hello': 'world' }; - -var backend = http.createServer(function (req, res) { - common.debug('backend request'); - res.writeHead(200, headers); - res.write('hello world\n'); - res.end(); -}); - -var proxy = http.createServer(function (req, res) { - common.debug('proxy req headers: ' + JSON.stringify(req.headers)); - var proxy_req = http.get({ - port: BACKEND_PORT, - path: url.parse(req.url).pathname - }, function (proxy_res) { - - common.debug('proxy res headers: ' + JSON.stringify(proxy_res.headers)); - - assert.equal('world', proxy_res.headers['hello']); - assert.equal('text/plain', proxy_res.headers['content-type']); - assert.deepEqual(cookies, proxy_res.headers['set-cookie']); - - res.writeHead(proxy_res.statusCode, proxy_res.headers); - - proxy_res.on('data', function (chunk) { - res.write(chunk); - }); - - proxy_res.on('end', function () { - res.end(); - common.debug('proxy res'); - }); - }); -}); - -var body = ''; - -var nlistening = 0; -function startReq() { - nlistening++; - if (nlistening < 2) return; - - var client = http.get({ - port: common.PROXY_PORT, - path: '/test' - }, function (res) { - common.debug('got res'); - assert.equal(200, res.statusCode); - - assert.equal('world', res.headers['hello']); - assert.equal('text/plain', res.headers['content-type']); - assert.deepEqual(cookies, res.headers['set-cookie']); - - res.setEncoding('utf8'); - res.on('data', function (chunk) { body += chunk; }); - res.on('end', function () { - proxy.close(); - backend.close(); - common.debug('closed both'); - }); - }); - common.debug('client req'); -} - -common.debug('listen proxy'); -proxy.listen(PROXY_PORT, startReq); - -common.debug('listen backend'); -backend.listen(BACKEND_PORT, startReq); - -process.on('exit', function () { - assert.equal(body, 'hello world\n'); -}); diff --git a/test/core/simple/test-http-response-close.js b/test/core/simple/test-http-response-close.js deleted file mode 100644 index b92abb011..000000000 --- a/test/core/simple/test-http-response-close.js +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); - -var gotEnd = false; - -var server = http.createServer(function (req, res) { - res.writeHead(200); - res.write('a'); - - req.on('close', function () { - console.error('aborted'); - gotEnd = true; - }); -}); -server.listen(common.PORT); - -server.on('listening', function () { - console.error('make req'); - http.get({ - port: common.PROXY_PORT - }, function (res) { - console.error('got res'); - res.on('data', function (data) { - console.error('destroy res'); - res.destroy(); - server.close(); - }); - }); -}); - -process.on('exit', function () { - assert.ok(gotEnd); -}); diff --git a/test/core/simple/test-http-server-multiheaders.js b/test/core/simple/test-http-server-multiheaders.js deleted file mode 100644 index 6a5b8be72..000000000 --- a/test/core/simple/test-http-server-multiheaders.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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. - -// Verify that the HTTP server implementation handles multiple instances -// of the same header as per RFC2616: joining the handful of fields by ', ' -// that support it, and dropping duplicates for other fields. - -var common = require('../common'); -var assert = require('assert'); -var http = require('http'); - -var srv = http.createServer(function (req, res) { - assert.equal(req.headers.accept, 'abc, def, ghijklmnopqrst'); - assert.equal(req.headers.host, 'foo'); - assert.equal(req.headers['x-foo'], 'bingo'); - assert.equal(req.headers['x-bar'], 'banjo, bango'); - - res.writeHead(200, {'Content-Type' : 'text/plain'}); - res.end('EOF'); - - srv.close(); -}); - -srv.listen(common.PORT, function () { - http.get({ - host: 'localhost', - port: common.PROXY_PORT, - path: '/', - headers: [ - ['accept', 'abc'], - ['accept', 'def'], - ['Accept', 'ghijklmnopqrst'], - ['host', 'foo'], - ['Host', 'bar'], - ['hOst', 'baz'], - ['x-foo', 'bingo'], - ['x-bar', 'banjo'], - ['x-bar', 'bango'] - ] - }); -}); diff --git a/test/core/simple/test-http-set-cookies.js b/test/core/simple/test-http-set-cookies.js deleted file mode 100644 index aac29940e..000000000 --- a/test/core/simple/test-http-set-cookies.js +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); - -var nresponses = 0; - -var server = http.createServer(function (req, res) { - if (req.url == '/one') { - res.writeHead(200, [['set-cookie', 'A'], - ['content-type', 'text/plain']]); - res.end('one\n'); - } else { - res.writeHead(200, [['set-cookie', 'A'], - ['set-cookie', 'B'], - ['content-type', 'text/plain']]); - res.end('two\n'); - } -}); -server.listen(common.PORT); - -server.on('listening', function () { - // - // one set-cookie header - // - http.get({ port: common.PROXY_PORT, path: '/one' }, function (res) { - // set-cookie headers are always return in an array. - // even if there is only one. - assert.deepEqual(['A'], res.headers['set-cookie']); - assert.equal('text/plain', res.headers['content-type']); - - res.on('data', function (chunk) { - console.log(chunk.toString()); - }); - - res.on('end', function () { - if (++nresponses == 2) { - server.close(); - } - }); - }); - - // two set-cookie headers - - http.get({ port: common.PROXY_PORT, path: '/two' }, function (res) { - assert.deepEqual(['A', 'B'], res.headers['set-cookie']); - assert.equal('text/plain', res.headers['content-type']); - - res.on('data', function (chunk) { - console.log(chunk.toString()); - }); - - res.on('end', function () { - if (++nresponses == 2) { - server.close(); - } - }); - }); - -}); - -process.on('exit', function () { - assert.equal(2, nresponses); -}); diff --git a/test/core/simple/test-http-status-code.js b/test/core/simple/test-http-status-code.js deleted file mode 100644 index dffbaf7c9..000000000 --- a/test/core/simple/test-http-status-code.js +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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. - -// libuv-broken - - -var common = require('../common'); -var assert = require('assert'); -var http = require('http'); - -// Simple test of Node's HTTP ServerResponse.statusCode -// ServerResponse.prototype.statusCode - -var testsComplete = 0; -var tests = [200, 202, 300, 404, 500]; -var testIdx = 0; - -var s = http.createServer(function (req, res) { - var t = tests[testIdx]; - res.writeHead(t, {'Content-Type': 'text/plain'}); - console.log('--\nserver: statusCode after writeHead: ' + res.statusCode); - assert.equal(res.statusCode, t); - res.end('hello world\n'); -}); - -s.listen(common.PORT, nextTest); - - -function nextTest() { - if (testIdx + 1 === tests.length) { - return s.close(); - } - var test = tests[testIdx]; - - http.get({ port: common.PROXY_PORT }, function (response) { - console.log('client: expected status: ' + test); - console.log('client: statusCode: ' + response.statusCode); - assert.equal(response.statusCode, test); - response.on('end', function () { - testsComplete++; - testIdx += 1; - nextTest(); - }); - }); -} - - -process.on('exit', function () { - assert.equal(4, testsComplete); -}); - diff --git a/test/core/simple/test-http-upgrade-server2.js b/test/core/simple/test-http-upgrade-server2.js deleted file mode 100644 index a52737618..000000000 --- a/test/core/simple/test-http-upgrade-server2.js +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); -var net = require('net'); - -var server = http.createServer(function (req, res) { - common.error('got req'); - throw new Error('This shouldn\'t happen.'); -}); - -server.on('upgrade', function (req, socket, upgradeHead) { - common.error('got upgrade event'); - // test that throwing an error from upgrade gets - // is uncaught - throw new Error('upgrade error'); -}); - -var gotError = false; - -process.on('uncaughtException', function (e) { - common.error('got \'clientError\' event'); - assert.equal('upgrade error', e.message); - gotError = true; - process.exit(0); -}); - - -server.listen(common.PORT, function () { - var c = net.createConnection(common.PROXY_PORT); - - c.on('connect', function () { - common.error('client wrote message'); - c.write('GET /blah HTTP/1.1\r\n' + - 'Upgrade: WebSocket\r\n' + - 'Connection: Upgrade\r\n' + - '\r\n\r\nhello world'); - }); - - c.on('end', function () { - c.end(); - }); - - c.on('close', function () { - common.error('client close'); - server.close(); - }); -}); - -process.on('exit', function () { - assert.ok(gotError); -}); diff --git a/test/core/simple/test-http.js b/test/core/simple/test-http.js deleted file mode 100644 index e082eb2ce..000000000 --- a/test/core/simple/test-http.js +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// 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 common = require('../common'); -var assert = require('assert'); -var http = require('http'); -var url = require('url'); - -function p(x) { - common.error(common.inspect(x)); -} - -var responses_sent = 0; -var responses_recvd = 0; -var body0 = ''; -var body1 = ''; - -var server = http.Server(function (req, res) { - if (responses_sent == 0) { - assert.equal('GET', req.method); - assert.equal('/hello', url.parse(req.url).pathname); - - console.dir(req.headers); - assert.equal(true, 'accept' in req.headers); - assert.equal('*/*', req.headers['accept']); - - assert.equal(true, 'foo' in req.headers); - assert.equal('bar', req.headers['foo']); - } - - if (responses_sent == 1) { - assert.equal('POST', req.method); - assert.equal('/world', url.parse(req.url).pathname); - this.close(); - } - - req.on('end', function () { - res.writeHead(200, {'Content-Type': 'text/plain'}); - res.write('The path was ' + url.parse(req.url).pathname); - res.end(); - responses_sent += 1; - }); - - //assert.equal('127.0.0.1', res.connection.remoteAddress); -}); -server.listen(common.PORT); - -server.on('listening', function () { - var agent = new http.Agent({ port: common.PROXY_PORT, maxSockets: 1 }); - http.get({ - port: common.PROXY_PORT, - path: '/hello', - headers: {'Accept': '*/*', 'Foo': 'bar'}, - agent: agent - }, function (res) { - assert.equal(200, res.statusCode); - responses_recvd += 1; - res.setEncoding('utf8'); - res.on('data', function (chunk) { body0 += chunk; }); - common.debug('Got /hello response'); - }); - - setTimeout(function () { - var req = http.request({ - port: common.PROXY_PORT, - method: 'POST', - path: '/world', - agent: agent - }, function (res) { - assert.equal(200, res.statusCode); - responses_recvd += 1; - res.setEncoding('utf8'); - res.on('data', function (chunk) { body1 += chunk; }); - common.debug('Got /world response'); - }); - req.end(); - }, 1); -}); - -process.on('exit', function () { - common.debug('responses_recvd: ' + responses_recvd); - assert.equal(2, responses_recvd); - - common.debug('responses_sent: ' + responses_sent); - assert.equal(2, responses_sent); - - assert.equal('The path was /hello', body0); - assert.equal('The path was /world', body1); -}); - diff --git a/test/examples-test.js b/test/examples-test.js deleted file mode 100644 index 36beb89a9..000000000 --- a/test/examples-test.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - * examples.js: Tests which ensure all examples do not throw errors. - * - * (C) 2010, Charlie Robbins - * - */ - -var vows = require('vows') - macros = require('./macros'), - examples = macros.examples; - -// -// Suppress `EADDRINUSE` errors since -// we are just checking for require-time errors -// -process.on('uncaughtException', function (err) { - if (err.code !== 'EADDRINUSE') { - throw err; - } -}); - -vows.describe('node-http-proxy/examples').addBatch( - examples.shouldHaveDeps() -).addBatch( - examples.shouldHaveNoErrors() -).export(module); \ No newline at end of file diff --git a/test/fixtures/agent2-cert.pem b/test/fixtures/agent2-cert.pem deleted file mode 100644 index 8e4354db4..000000000 --- a/test/fixtures/agent2-cert.pem +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIB7DCCAZYCCQC7gs0MDNn6MTANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJV -UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO -BgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEgMB4GCSqGSIb3DQEJARYR -cnlAdGlueWNsb3Vkcy5vcmcwHhcNMTEwMzE0MTgyOTEyWhcNMzgwNzI5MTgyOTEy -WjB9MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYD -VQQKEwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEg -MB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwXDANBgkqhkiG9w0BAQEF -AANLADBIAkEAyXb8FrRdKbhrKLgLSsn61i1C7w7fVVVd7OQsmV/7p9WB2lWFiDlC -WKGU9SiIz/A6wNZDUAuc2E+VwtpCT561AQIDAQABMA0GCSqGSIb3DQEBBQUAA0EA -C8HzpuNhFLCI3A5KkBS5zHAQax6TFUOhbpBCR0aTDbJ6F1liDTK1lmU/BjvPoj+9 -1LHwrmh29rK8kBPEjmymCQ== ------END CERTIFICATE----- diff --git a/test/fixtures/agent2-csr.pem b/test/fixtures/agent2-csr.pem deleted file mode 100644 index a670c4c63..000000000 --- a/test/fixtures/agent2-csr.pem +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBXTCCAQcCAQAwfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQH -EwJTRjEPMA0GA1UEChMGSm95ZW50MRAwDgYDVQQLEwdOb2RlLmpzMQ8wDQYDVQQD -EwZhZ2VudDIxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMFwwDQYJ -KoZIhvcNAQEBBQADSwAwSAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf -+6fVgdpVhYg5QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAaAlMCMGCSqG -SIb3DQEJBzEWExRBIGNoYWxsZW5nZSBwYXNzd29yZDANBgkqhkiG9w0BAQUFAANB -AJnll2pt5l0pzskQSpjjLVTlFDFmJr/AZ3UK8v0WxBjYjCe5Jx4YehkChpxIyDUm -U3J9q9MDUf0+Y2+EGkssFfk= ------END CERTIFICATE REQUEST----- diff --git a/test/fixtures/agent2-key.pem b/test/fixtures/agent2-key.pem deleted file mode 100644 index 522903c63..000000000 --- a/test/fixtures/agent2-key.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIBOgIBAAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf+6fVgdpVhYg5 -QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAQJBAMT6Bf34+UHKY1ObpsbH -9u2jsVblFq1rWvs8GPMY6oertzvwm3DpuSUp7PTgOB1nLTLYtCERbQ4ovtN8tn3p -OHUCIQDzIEGsoCr5vlxXvy2zJwu+fxYuhTZWMVuo1397L0VyhwIhANQh+yzqUgaf -WRtSB4T2W7ADtJI35ET61jKBty3CqJY3AiAIwju7dVW3A5WeD6Qc1SZGKZvp9yCb -AFI2BfVwwaY11wIgXF3PeGcvACMyMWsuSv7aPXHfliswAbkWuzcwA4TW01ECIGWa -cgsDvVFxmfM5NPSuT/UDTa6R5BFISB5ea0N0AR3I ------END RSA PRIVATE KEY----- diff --git a/test/fixtures/agent2.cnf b/test/fixtures/agent2.cnf deleted file mode 100644 index 0a9f2c737..000000000 --- a/test/fixtures/agent2.cnf +++ /dev/null @@ -1,19 +0,0 @@ -[ 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 - diff --git a/test/helpers/http.js b/test/helpers/http.js deleted file mode 100644 index aaf7a8042..000000000 --- a/test/helpers/http.js +++ /dev/null @@ -1,182 +0,0 @@ -/* - * http.js: Top level include for node-http-proxy http helpers - * - * (C) 2010 Nodejitsu Inc. - * MIT LICENCE - * - */ - -var assert = require('assert'), - http = require('http'), - https = require('https'), - url = require('url'), - async = require('async'), - helpers = require('./index'), - protocols = helpers.protocols, - httpProxy = require('../../lib/node-http-proxy'); - -// -// ### function createServerPair (options, callback) -// #### @options {Object} Options to create target and proxy server. -// #### @callback {function} Continuation to respond to when complete. -// -// Creates http target and proxy servers -// -exports.createServerPair = function (options, callback) { - async.series([ - // - // 1. Create the target server - // - function createTarget(next) { - exports.createServer(options.target, next); - }, - // - // 2. Create the proxy server - // - function createTarget(next) { - exports.createProxyServer(options.proxy, next); - } - ], callback); -}; - -// -// ### function createServer (options, callback) -// #### @options {Object} Options for creatig an http server. -// #### @port {number} Port to listen on -// #### @output {string} String to write to each HTTP response -// #### @headers {Object} Headers to assert are sent by `node-http-proxy`. -// #### @callback {function} Continuation to respond to when complete. -// -// Creates a target server that the tests will proxy to. -// -exports.createServer = function (options, callback) { - // - // Request handler to use in either `http` - // or `https` server. - // - function requestHandler(req, res) { - if (options.headers) { - Object.keys(options.headers).forEach(function (key) { - assert.equal(req.headers[key], options.headers[key]); - }); - } - - if (options.outputHeaders) { - Object.keys(options.outputHeaders).forEach(function (header) { - res.setHeader(header, options.outputHeaders[header]); - }); - } - - setTimeout(function() { - res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.write(options.output || 'hello proxy'); - res.end(); - }, options.latency || 1); - } - - var server = protocols.target === 'https' - ? https.createServer(helpers.https, requestHandler) - : http.createServer(requestHandler); - - server.listen(options.port, function () { - callback(null, this); - }); -}; - -// -// ### function createProxyServer (options, callback) -// #### @options {Object} Options for creatig an http server. -// #### @port {number} Port to listen on -// #### @latency {number} Latency of this server in milliseconds -// #### @proxy {Object} Options to pass to the HttpProxy. -// #### @routing {boolean} Enables `httpProxy.RoutingProxy` -// #### @callback {function} Continuation to respond to when complete. -// -// Creates a proxy server that the tests will request against. -// -exports.createProxyServer = function (options, callback) { - if (!options.latency) { - if (protocols.proxy === 'https') { - options.proxy.https = helpers.https; - } - options.proxy.rejectUnauthorized = false; - - return httpProxy - .createServer(options.proxy) - .listen(options.port, function () { - callback(null, this); - }); - } - - var server, - proxy; - - proxy = options.routing - ? new httpProxy.RoutingProxy(options.proxy) - : new httpProxy.HttpProxy(options.proxy); - - // - // Request handler to use in either `http` - // or `https` server. - // - function requestHandler(req, res) { - var buffer = httpProxy.buffer(req); - - if (options.outputHeaders) { - Object.keys(options.outputHeaders).forEach(function (header) { - res.setHeader(header, options.outputHeaders[header]); - }); - } - setTimeout(function () { - // - // Setup options dynamically for `RoutingProxy.prototype.proxyRequest` - // or `HttpProxy.prototype.proxyRequest`. - // - buffer = options.routing ? { buffer: buffer } : buffer; - proxy.proxyRequest(req, res, buffer); - }, options.latency); - } - - server = protocols.proxy === 'https' - ? https.createServer(helpers.https, requestHandler) - : http.createServer(requestHandler); - - server.listen(options.port, function () { - callback(null, this); - }); -}; - -// -// ### function assignPortsToRoutes (routes) -// #### @routes {Object} Routing table to assign ports to -// -// Assigns dynamic ports to the `routes` for runtime testing. -// -exports.assignPortsToRoutes = function (routes) { - Object.keys(routes).forEach(function (source) { - routes[source] = routes[source].replace('{PORT}', helpers.nextPort); - }); - - return routes; -}; - -// -// ### function parseRoutes (options) -// #### @options {Object} Options to use when parsing routes -// #### @protocol {string} Protocol to use in the routes -// #### @routes {Object} Routes to parse. -// -// Returns an Array of fully-parsed URLs for the source and -// target of `options.routes`. -// -exports.parseRoutes = function (options) { - var protocol = options.protocol || 'http', - routes = options.routes; - - return Object.keys(routes).map(function (source) { - return { - source: url.parse(protocol + '://' + source), - target: url.parse(protocol + '://' + routes[source]) - }; - }); -}; diff --git a/test/helpers/index.js b/test/helpers/index.js deleted file mode 100644 index 7e3c3f488..000000000 --- a/test/helpers/index.js +++ /dev/null @@ -1,105 +0,0 @@ -/* - * index.js: Top level include for node-http-proxy helpers - * - * (C) 2010 Nodejitsu Inc. - * MIT LICENCE - * - */ - -var fs = require('fs'), - path = require('path'); - -var fixturesDir = path.join(__dirname, '..', 'fixtures'); - -// -// @https {Object} -// Returns the necessary `https` credentials. -// -Object.defineProperty(exports, 'https', { - get: function () { - delete this.https; - return this.https = { - key: fs.readFileSync(path.join(fixturesDir, 'agent2-key.pem'), 'utf8'), - cert: fs.readFileSync(path.join(fixturesDir, 'agent2-cert.pem'), 'utf8') - }; - } -}); - -// -// @protocols {Object} -// Returns an object representing the desired protocols -// for the `proxy` and `target` server. -// -Object.defineProperty(exports, 'protocols', { - get: function () { - delete this.protocols; - return this.protocols = { - target: exports.argv.target || 'http', - proxy: exports.argv.proxy || 'http' - }; - } -}); - -// -// @nextPort {number} -// Returns an auto-incrementing port for tests. -// -Object.defineProperty(exports, 'nextPort', { - get: function () { - var current = this.port || 9050; - this.port = current + 1; - return current; - } -}); - -// -// @nextPortPair {Object} -// Returns an auto-incrementing pair of ports for tests. -// -Object.defineProperty(exports, 'nextPortPair', { - get: function () { - return { - target: this.nextPort, - proxy: this.nextPort - }; - } -}); - -// -// ### function describe(prefix) -// #### @prefix {string} Prefix to use before the description -// -// Returns a string representing the protocols that this suite -// is testing based on CLI arguments. -// -exports.describe = function (prefix, base) { - prefix = prefix || ''; - base = base || 'http'; - - function protocol(endpoint) { - return exports.protocols[endpoint] === 'https' - ? base + 's' - : base; - } - - return [ - 'node-http-proxy', - prefix, - [ - protocol('proxy'), - '-to-', - protocol('target') - ].join('') - ].filter(Boolean).join('/'); -}; - -// -// Expose the CLI arguments -// -exports.argv = require('optimist').argv; - -// -// Export additional helpers for `http` and `websockets`. -// -exports.http = require('./http'); -exports.ws = require('./ws'); \ No newline at end of file diff --git a/test/helpers/ws.js b/test/helpers/ws.js deleted file mode 100644 index a4905227d..000000000 --- a/test/helpers/ws.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - * ws.js: Top level include for node-http-proxy websocket helpers - * - * (C) 2010 Nodejitsu Inc. - * MIT LICENCE - * - */ - -var assert = require('assert'), - https = require('https'), - async = require('async'), - io = require('socket.io'), - ws = require('ws'), - helpers = require('./index'), - protocols = helpers.protocols, - http = require('./http'); - -// -// ### function createServerPair (options, callback) -// #### @options {Object} Options to create target and proxy server. -// #### @target {Object} Options for the target server. -// #### @proxy {Object} Options for the proxy server. -// #### @callback {function} Continuation to respond to when complete. -// -// Creates http target and proxy servers -// -exports.createServerPair = function (options, callback) { - async.series([ - // - // 1. Create the target server - // - function createTarget(next) { - exports.createServer(options.target, next); - }, - // - // 2. Create the proxy server - // - function createTarget(next) { - http.createProxyServer(options.proxy, next); - } - ], callback); -}; - -// -// ### function createServer (options, callback) -// #### @options {Object} Options for creating the socket.io or ws server. -// #### @raw {boolean} Enables ws.Websocket server. -// -// Creates a socket.io or ws server using the specified `options`. -// -exports.createServer = function (options, callback) { - return options.raw - ? exports.createWsServer(options, callback) - : exports.createSocketIoServer(options, callback); -}; - -// -// ### function createSocketIoServer (options, callback) -// #### @options {Object} Options for creating the socket.io server -// #### @port {number} Port to listen on -// #### @input {string} Input to expect from the only socket -// #### @output {string} Output to send the only socket -// -// Creates a socket.io server on the specified `options.port` which -// will expect `options.input` and then send `options.output`. -// -exports.createSocketIoServer = function (options, callback) { - var server = protocols.target === 'https' - ? io.listen(options.port, helpers.https, callback) - : io.listen(options.port, callback); - - server.sockets.on('connection', function (socket) { - socket.on('incoming', function (data) { - assert.equal(data, options.input); - socket.emit('outgoing', options.output); - }); - }); -}; - -// -// ### function createWsServer (options, callback) -// #### @options {Object} Options for creating the ws.Server instance -// #### @port {number} Port to listen on -// #### @input {string} Input to expect from the only socket -// #### @output {string} Output to send the only socket -// -// Creates a ws.Server instance on the specified `options.port` which -// will expect `options.input` and then send `options.output`. -// -exports.createWsServer = function (options, callback) { - var server, - wss; - - if (protocols.target === 'https') { - server = https.createServer(helpers.https, function (req, res) { - req.writeHead(200); - req.end(); - }).listen(options.port, callback); - - wss = new ws.Server({ server: server }); - } - else { - wss = new ws.Server({ port: options.port }, callback); - } - - wss.on('connection', function (socket) { - socket.on('message', function (data) { - assert.equal(data, options.input); - socket.send(options.output); - }); - }); -}; \ No newline at end of file diff --git a/test/http/http-test.js b/test/http/http-test.js deleted file mode 100644 index 81f8726a7..000000000 --- a/test/http/http-test.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - node-http-proxy-test.js: http proxy for node.js - - Copyright (c) 2010 Charlie Robbins, Marak Squires and Fedor Indutny - - 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 assert = require('assert'), - fs = require('fs'), - path = require('path'), - async = require('async'), - request = require('request'), - vows = require('vows'), - macros = require('../macros'), - helpers = require('../helpers'); - -var routeFile = path.join(__dirname, 'config.json'); - -vows.describe(helpers.describe()).addBatch({ - "With a valid target server": { - "and no latency": { - "and no headers": macros.http.assertProxied(), - "and headers": macros.http.assertProxied({ - request: { headers: { host: 'unknown.com' } } - }), - "and request close connection header": macros.http.assertProxied({ - request: { headers: { connection: "close" } }, - outputHeaders: { connection: "close" } - }), - "and request keep alive connection header": macros.http.assertProxied({ - request: { headers: { connection: "keep-alive" } }, - outputHeaders: { connection: "keep-alive" } - }), - "and response close connection header": macros.http.assertProxied({ - request: { headers: { connection: "" } }, // Must explicitly set to "" because otherwise node will automatically add a "connection: keep-alive" header - targetHeaders: { connection: "close" }, - outputHeaders: { connection: "close" } - }), - "and response keep-alive connection header": macros.http.assertProxied({ - request: { headers: { connection: "" } }, // Must explicitly set to "" because otherwise node will automatically add a "connection: keep-alive" header - targetHeaders: { connection: "keep-alive" }, - outputHeaders: { connection: "keep-alive" } - }), - "and response keep-alive connection header from http 1.0 client": macros.http.assertRawHttpProxied({ - rawRequest: "GET / HTTP/1.0\r\n\r\n", - targetHeaders: { connection: "keep-alive" }, - match: /connection: close/i - }), - "and request keep alive from http 1.0 client": macros.http.assertRawHttpProxied({ - rawRequest: "GET / HTTP/1.0\r\nConnection: Keep-Alive\r\n\r\n", - targetHeaders: { connection: "keep-alive" }, - match: /connection: keep-alive/i - }), - "and no connection header": macros.http.assertProxied({ - request: { headers: { connection: "" } }, // Must explicitly set to "" because otherwise node will automatically add a "connection: keep-alive" header - outputHeaders: { connection: "keep-alive" } - }), - "and forwarding enabled": macros.http.assertForwardProxied() - }, - "and latency": { - "and no headers": macros.http.assertProxied({ - latency: 2000 - }), - "and response headers": macros.http.assertProxied({ - targetHeaders: { "x-testheader": "target" }, - proxyHeaders: { "X-TestHeader": "proxy" }, - outputHeaders: { "x-testheader": "target" }, - latency: 1000 - }) - }, - "and timeout set": macros.http.assertProxied({ - shouldFail: true, - timeout: 2000, - requestLatency: 4000 - }) - }, - "With a no valid target server": { - "and no latency": macros.http.assertInvalidProxy(), - "and latency": macros.http.assertInvalidProxy({ - latency: 2000 - }) - } -}).export(module); diff --git a/test/http/routing-table-test.js b/test/http/routing-table-test.js deleted file mode 100644 index f3dcf31e7..000000000 --- a/test/http/routing-table-test.js +++ /dev/null @@ -1,107 +0,0 @@ -/* - * routing-table-test.js: Tests for the proxying using the ProxyTable object. - * - * (C) 2010, Charlie Robbins - * - */ - -var assert = require('assert'), - fs = require('fs'), - path = require('path'), - async = require('async'), - request = require('request'), - vows = require('vows'), - macros = require('../macros'), - helpers = require('../helpers'); - -var routeFile = path.join(__dirname, 'config.json'); - -vows.describe(helpers.describe('routing-table')).addBatch({ - "With a routing table": { - "with latency": macros.http.assertProxiedToRoutes({ - latency: 2000, - routes: { - "icanhaz.com": "127.0.0.1:{PORT}", - "latency.com": "127.0.0.1:{PORT}" - } - }), - "addHost() / removeHost()": macros.http.assertDynamicProxy({ - hostnameOnly: true, - routes: { - "static.com": "127.0.0.1:{PORT}", - "removed.com": "127.0.0.1:{PORT}" - } - }, { - add: [{ host: 'dynamic1.com', target: '127.0.0.1:' }], - drop: ['removed.com'] - }), - "using RegExp": macros.http.assertProxiedToRoutes({ - routes: { - "foo.com": "127.0.0.1:{PORT}", - "bar.com": "127.0.0.1:{PORT}", - "baz.com/taco": "127.0.0.1:{PORT}", - "pizza.com/taco/muffins": "127.0.0.1:{PORT}", - "blah.com/me": "127.0.0.1:{PORT}/remapped", - "bleh.com/remap/this": "127.0.0.1:{PORT}/remap/remapped", - "test.com/double/tap": "127.0.0.1:{PORT}/remap" - } - }), - "using hostnameOnly": macros.http.assertProxiedToRoutes({ - hostnameOnly: true, - routes: { - "foo.com": "127.0.0.1:{PORT}", - "bar.com": "127.0.0.1:{PORT}" - } - }), - "using pathnameOnly": macros.http.assertProxiedToRoutes({ - pathnameOnly: true, - routes: { - "/foo": "127.0.0.1:{PORT}", - "/bar": "127.0.0.1:{PORT}", - "/pizza": "127.0.0.1:{PORT}" - } - }), - "using a routing file": macros.http.assertProxiedToRoutes({ - filename: routeFile, - routes: { - "foo.com": "127.0.0.1:{PORT}", - "bar.com": "127.0.0.1:{PORT}" - } - }, { - "after the file has been modified": { - topic: function () { - var config = JSON.parse(fs.readFileSync(routeFile, 'utf8')), - protocol = helpers.protocols.proxy, - port = helpers.nextPort, - that = this; - - config.router['dynamic.com'] = "127.0.0.1:" + port; - fs.writeFileSync(routeFile, JSON.stringify(config)); - - async.parallel([ - function waitForRoutes(next) { - that.proxyServer.on('routes', next); - }, - async.apply( - helpers.http.createServer, - { - port: port, - output: 'hello from dynamic.com' - } - ) - ], function () { - request({ - uri: protocol + '://127.0.0.1:' + that.port, - headers: { - host: 'dynamic.com' - } - }, that.callback); - }); - }, - "should receive 'hello from dynamic.com'": function (err, res, body) { - assert.equal(body, 'hello from dynamic.com'); - } - } - }) - } -}).export(module); diff --git a/test/macros/examples.js b/test/macros/examples.js deleted file mode 100644 index 9d4202e6a..000000000 --- a/test/macros/examples.js +++ /dev/null @@ -1,101 +0,0 @@ -/* - * examples.js: Macros for testing code in examples/ - * - * (C) 2010 Nodejitsu Inc. - * MIT LICENCE - * - */ - -var assert = require('assert'), - fs = require('fs'), - path = require('path'), - spawn = require('child_process').spawn, - async = require('async'); - -var rootDir = path.join(__dirname, '..', '..'), - examplesDir = path.join(rootDir, 'examples'); - -// -// ### function shouldHaveDeps () -// -// Ensures that all `npm` dependencies are installed in `/examples`. -// -exports.shouldHaveDeps = function () { - return { - "Before testing examples": { - topic: function () { - 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(); - } - - 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), - ], this.callback); - }, - "examples/node_modules should exist": function (err, files) { - assert.notEqual(files.indexOf('node_modules'), -1); - } - } - } -}; - -// -// ### function shouldRequire (file) -// #### @file {string} File to attempt to require -// -// Returns a test which attempts to require `file`. -// -exports.shouldRequire = function (file) { - return { - "should have no errors": function () { - try { assert.isObject(require(file)) } - catch (ex) { assert.isNull(ex) } - } - }; -}; - -// -// ### function shouldHaveNoErrors () -// -// Returns a vows context that attempts to require -// every relevant example file in `examples`. -// -exports.shouldHaveNoErrors = function () { - var context = {}; - - ['balancer', 'http', 'middleware', 'websocket'].forEach(function (dir) { - var name = 'examples/' + dir, - files = fs.readdirSync(path.join(rootDir, 'examples', dir)); - - files.forEach(function (file) { - context[name + '/' + file] = exports.shouldRequire(path.join( - examplesDir, dir, file - )); - }); - }); - - return context; -}; \ No newline at end of file diff --git a/test/macros/http.js b/test/macros/http.js deleted file mode 100644 index d3d83426a..000000000 --- a/test/macros/http.js +++ /dev/null @@ -1,531 +0,0 @@ -/* - * http.js: Macros for proxying HTTP requests - * - * (C) 2010 Nodejitsu Inc. - * MIT LICENCE - * - */ - -var assert = require('assert'), - fs = require('fs'), - async = require('async'), - net = require('net'), - request = require('request'), - helpers = require('../helpers/index'); - -// -// ### function assertRequest (options) -// #### @options {Object} Options for this request assertion. -// #### @request {Object} Options to use for `request`. -// #### @assert {Object} Test assertions against the response. -// -// Makes a request using `options.request` and then asserts the response -// and body against anything in `options.assert`. -// -exports.assertRequest = function (options) { - return { - topic: function () { - // - // Now make the HTTP request and assert. - // - options.request.rejectUnauthorized = false; - request(options.request, this.callback); - }, - "should succeed": function (err, res, body) { - assert.isNull(err); - if (options.assert.headers) { - Object.keys(options.assert.headers).forEach(function(header){ - assert.equal(res.headers[header], options.assert.headers[header]); - }); - } - - if (options.assert.body) { - assert.equal(body, options.assert.body); - } - - if (options.assert.statusCode) { - assert.equal(res.statusCode, options.assert.statusCode); - } - } - }; -}; - -// -// ### function assertFailedRequest (options) -// #### @options {Object} Options for this failed request assertion. -// #### @request {Object} Options to use for `request`. -// #### @assert {Object} Test assertions against the response. -// -// Makes a request using `options.request` and then asserts the response -// and body against anything in `options.assert`. -// -exports.assertFailedRequest = function (options) { - return { - topic: function () { - // - // Now make the HTTP request and assert. - // - options.request.rejectUnauthorized = false; - request(options.request, this.callback); - }, - "should not succeed": function (err, res, body) { - assert.notStrictEqual(err,null); - } - }; -}; - -// -// ### function assertProxied (options) -// #### @options {Object} Options for this test -// #### @latency {number} Latency in milliseconds for the proxy server. -// #### @ports {Object} Ports for the request (target, proxy). -// #### @output {string} Output to assert from. -// #### @forward {Object} Options for forward proxying. -// -// Creates a complete end-to-end test for requesting against an -// http proxy. -// -exports.assertProxied = function (options) { - options = options || {}; - - var ports = options.ports || helpers.nextPortPair, - output = options.output || 'hello world from ' + ports.target, - outputHeaders = options.outputHeaders, - targetHeaders = options.targetHeaders, - proxyHeaders = options.proxyHeaders, - protocol = helpers.protocols.proxy, - req = options.request || {}, - timeout = options.timeout || null, - assertFn = options.shouldFail - ? exports.assertFailedRequest - : exports.assertRequest; - - req.uri = req.uri || protocol + '://127.0.0.1:' + ports.proxy; - - return { - topic: function () { - // - // Create a target server and a proxy server - // using the `options` supplied. - // - helpers.http.createServerPair({ - target: { - output: output, - outputHeaders: targetHeaders, - port: ports.target, - headers: req.headers, - latency: options.requestLatency - }, - proxy: { - latency: options.latency, - port: ports.proxy, - outputHeaders: proxyHeaders, - proxy: { - forward: options.forward, - target: { - https: helpers.protocols.target === 'https', - host: '127.0.0.1', - port: ports.target - }, - timeout: timeout - } - } - }, this.callback); - }, - "the proxy request": assertFn({ - request: req, - assert: { - headers: outputHeaders, - body: output - } - }) - }; -}; - -// -// ### function assertRawHttpProxied (options) -// #### @options {Object} Options for this test -// #### @rawRequest {string} Raw HTTP request to perform. -// #### @match {RegExp} Output to match in the response. -// #### @latency {number} Latency in milliseconds for the proxy server. -// #### @ports {Object} Ports for the request (target, proxy). -// #### @output {string} Output to assert from. -// #### @forward {Object} Options for forward proxying. -// -// Creates a complete end-to-end test for requesting against an -// http proxy. -// -exports.assertRawHttpProxied = function (options) { - // Don't test raw requests over HTTPS since options.rawRequest won't be - // encrypted. - if(helpers.protocols.proxy == 'https') { - return true; - } - - options = options || {}; - - var ports = options.ports || helpers.nextPortPair, - output = options.output || 'hello world from ' + ports.target, - outputHeaders = options.outputHeaders, - targetHeaders = options.targetHeaders, - proxyHeaders = options.proxyHeaders, - protocol = helpers.protocols.proxy, - timeout = options.timeout || null, - assertFn = options.shouldFail - ? exports.assertFailedRequest - : exports.assertRequest; - - return { - topic: function () { - var topicCallback = this.callback; - - // - // Create a target server and a proxy server - // using the `options` supplied. - // - helpers.http.createServerPair({ - target: { - output: output, - outputHeaders: targetHeaders, - port: ports.target, - latency: options.requestLatency - }, - proxy: { - latency: options.latency, - port: ports.proxy, - outputHeaders: proxyHeaders, - proxy: { - forward: options.forward, - target: { - https: helpers.protocols.target === 'https', - host: '127.0.0.1', - port: ports.target - }, - timeout: timeout - } - } - }, function() { - var response = ''; - var client = net.connect(ports.proxy, '127.0.0.1', function() { - client.write(options.rawRequest); - }); - - client.on('data', function(data) { - response += data.toString(); - }); - - client.on('end', function() { - topicCallback(null, options.match, response); - }); - }); - }, - "should succeed": function(err, match, response) { - assert.match(response, match); - } - }; -}; - -// -// ### function assertInvalidProxy (options) -// #### @options {Object} Options for this test -// #### @latency {number} Latency in milliseconds for the proxy server -// #### @ports {Object} Ports for the request (target, proxy) -// -// Creates a complete end-to-end test for requesting against an -// http proxy with no target server. -// -exports.assertInvalidProxy = function (options) { - options = options || {}; - - var ports = options.ports || helpers.nextPortPair, - req = options.request || {}, - protocol = helpers.protocols.proxy; - - - req.uri = req.uri || protocol + '://127.0.0.1:' + ports.proxy; - - return { - topic: function () { - // - // Only create the proxy server, simulating a reverse-proxy - // to an invalid location. - // - helpers.http.createProxyServer({ - latency: options.latency, - port: ports.proxy, - proxy: { - target: { - host: '127.0.0.1', - port: ports.target - } - } - }, this.callback); - }, - "the proxy request": exports.assertRequest({ - request: req, - assert: { - statusCode: 500 - } - }) - }; -}; - -// -// ### function assertForwardProxied (options) -// #### @options {Object} Options for this test. -// -// Creates a complete end-to-end test for requesting against an -// http proxy with both a valid and invalid forward target. -// -exports.assertForwardProxied = function (options) { - var forwardPort = helpers.nextPort; - - return { - topic: function () { - helpers.http.createServer({ - output: 'hello from forward', - port: forwardPort - }, this.callback); - }, - "and a valid forward target": exports.assertProxied({ - forward: { - port: forwardPort, - host: '127.0.0.1' - } - }), - "and an invalid forward target": exports.assertProxied({ - forward: { - port: 9898, - host: '127.0.0.1' - } - }) - }; -}; - -// -// ### function assertProxiedtoRoutes (options, nested) -// #### @options {Object} Options for this ProxyTable-based test -// #### @routes {Object|string} Routes to use for the proxy. -// #### @hostnameOnly {boolean} Enables hostnameOnly routing. -// #### @nested {Object} Nested vows to add to the returned context. -// -// Creates a complete end-to-end test for requesting against an -// http proxy using `options.routes`: -// -// 1. Creates target servers for all routes in `options.routes.` -// 2. Creates a proxy server. -// 3. Ensure requests to the proxy server for all route targets -// returns the unique expected output. -// -exports.assertProxiedToRoutes = function (options, nested) { - // - // Assign dynamic ports to the routes to use. - // - options.routes = helpers.http.assignPortsToRoutes(options.routes); - - // - // Parse locations from routes for making assertion requests. - // - var locations = helpers.http.parseRoutes(options), - port = options.pport || helpers.nextPort, - protocol = helpers.protocols.proxy, - context, - proxy; - - if (options.filename) { - // - // If we've been passed a filename write the routes to it - // and setup the proxy options to use that file. - // - fs.writeFileSync(options.filename, JSON.stringify({ router: options.routes })); - proxy = { router: options.filename }; - } - else { - // - // Otherwise just use the routes themselves. - // - proxy = { - hostnameOnly: options.hostnameOnly, - pathnameOnly: options.pathnameOnly, - router: options.routes - }; - } - - // - // Set the https options if necessary - // - if (helpers.protocols.target === 'https') { - proxy.target = { https: true }; - } - - // - // Create the test context which creates all target - // servers for all routes and a proxy server. - // - context = { - topic: function () { - var that = this; - - async.waterfall([ - // - // 1. Create all the target servers - // - async.apply( - async.forEach, - locations, - function createRouteTarget(location, next) { - helpers.http.createServer({ - port: location.target.port, - output: 'hello from ' + location.source.href - }, next); - } - ), - // - // 2. Create the proxy server - // - async.apply( - helpers.http.createProxyServer, - { - port: port, - latency: options.latency, - routing: true, - proxy: proxy - } - ) - ], function (_, server) { - // - // 3. Set the proxy server for later use - // - that.proxyServer = server; - that.callback(); - }); - - // - // 4. Assign the port to the context for later use - // - this.port = port; - }, - // - // Add an extra assertion to a route which - // should respond with 404 - // - "a request to unknown.com": exports.assertRequest({ - assert: { statusCode: 404 }, - request: { - uri: protocol + '://127.0.0.1:' + port, - headers: { - host: 'unknown.com' - } - } - }) - }; - - // - // Add test assertions for each of the route locations. - // - locations.forEach(function (location) { - context[location.source.href] = exports.assertRequest({ - request: { - uri: protocol + '://127.0.0.1:' + port + location.source.path, - headers: { - host: location.source.hostname - } - }, - assert: { - body: 'hello from ' + location.source.href - } - }); - }); - - // - // If there are any nested vows to add to the context - // add them before returning the full context. - // - if (nested) { - Object.keys(nested).forEach(function (key) { - context[key] = nested[key]; - }); - } - - return context; -}; - -// -// ### function assertDynamicProxy (static, dynamic) -// Asserts that after the `static` routes have been tested -// and the `dynamic` routes are added / removed the appropriate -// proxy responses are received. -// -exports.assertDynamicProxy = function (static, dynamic) { - var proxyPort = helpers.nextPort, - protocol = helpers.protocols.proxy, - context; - - if (dynamic.add) { - dynamic.add = dynamic.add.map(function (dyn) { - dyn.port = helpers.nextPort; - dyn.target = dyn.target + dyn.port; - return dyn; - }); - } - - context = { - topic: function () { - var that = this; - - setTimeout(function () { - if (dynamic.drop) { - dynamic.drop.forEach(function (dropHost) { - that.proxyServer.proxy.removeHost(dropHost); - }); - } - - if (dynamic.add) { - async.forEachSeries(dynamic.add, function addOne (dyn, next) { - that.proxyServer.proxy.addHost(dyn.host, dyn.target); - helpers.http.createServer({ - port: dyn.port, - output: 'hello ' + dyn.host - }, next); - }, that.callback); - } - else { - that.callback(); - } - }, 200); - } - }; - - if (dynamic.drop) { - dynamic.drop.forEach(function (dropHost) { - context[dropHost] = exports.assertRequest({ - assert: { statusCode: 404 }, - request: { - uri: protocol + '://127.0.0.1:' + proxyPort, - headers: { - host: dropHost - } - } - }); - }); - } - - if (dynamic.add) { - dynamic.add.forEach(function (dyn) { - context[dyn.host] = exports.assertRequest({ - assert: { body: 'hello ' + dyn.host }, - request: { - uri: protocol + '://127.0.0.1:' + proxyPort, - headers: { - host: dyn.host - } - } - }); - }); - } - - static.pport = proxyPort; - return exports.assertProxiedToRoutes(static, { - "once the server has started": context - }); -}; diff --git a/test/macros/index.js b/test/macros/index.js deleted file mode 100644 index c01f962b0..000000000 --- a/test/macros/index.js +++ /dev/null @@ -1,11 +0,0 @@ -/* - * index.js: Top level include for node-http-proxy macros - * - * (C) 2010 Nodejitsu Inc. - * MIT LICENCE - * - */ - -exports.examples = require('./examples'); -exports.http = require('./http'); -exports.ws = require('./ws'); \ No newline at end of file diff --git a/test/macros/ws.js b/test/macros/ws.js deleted file mode 100644 index 508725a49..000000000 --- a/test/macros/ws.js +++ /dev/null @@ -1,232 +0,0 @@ -/* - * ws.js: Macros for proxying Websocket requests - * - * (C) 2010 Nodejitsu Inc. - * MIT LICENCE - * - */ - -var assert = require('assert'), - fs = require('fs'), - async = require('async'), - io = require('socket.io-client'), - WebSocket = require('ws'), - helpers = require('../helpers/index'); - -// -// ### function assertSendRecieve (options) -// #### @options {Object} Options for creating this assertion. -// #### @raw {boolean} Enables raw `ws.WebSocket`. -// #### @uri {string} URI of the proxy server. -// #### @input {string} Input to assert sent to the target ws server. -// #### @output {string} Output to assert from the taget ws server. -// -// Creates a `socket.io` or raw `WebSocket` connection and asserts that -// `options.input` is sent to and `options.output` is received from the -// connection. -// -exports.assertSendReceive = function (options) { - if (!options.raw) { - return { - topic: function () { - var socket = io.connect(options.uri); - socket.on('outgoing', this.callback.bind(this, null)); - socket.emit('incoming', options.input); - }, - "should send input and receive output": function (_, data) { - assert.equal(data, options.output); - } - }; - } - - return { - topic: function () { - var socket = new WebSocket(options.uri); - socket.on('message', this.callback.bind(this, null)); - socket.on('open', function () { - socket.send(options.input); - }); - }, - "should send input and recieve output": function (_, data, flags) { - assert.equal(data, options.output); - } - }; -}; - -// -// ### function assertProxied (options) -// #### @options {Object} Options for this test -// #### @latency {number} Latency in milliseconds for the proxy server. -// #### @ports {Object} Ports for the request (target, proxy). -// #### @input {string} Input to assert sent to the target ws server. -// #### @output {string} Output to assert from the taget ws server. -// #### @raw {boolean} Enables raw `ws.Server` usage. -// -// Creates a complete end-to-end test for requesting against an -// http proxy. -// -exports.assertProxied = function (options) { - options = options || {}; - - var ports = options.ports || helpers.nextPortPair, - input = options.input || 'hello world to ' + ports.target, - output = options.output || 'hello world from ' + ports.target, - protocol = helpers.protocols.proxy; - - if (options.raw) { - protocol = helpers.protocols.proxy === 'https' - ? 'wss' - : 'ws'; - } - - return { - topic: function () { - helpers.ws.createServerPair({ - target: { - input: input, - output: output, - port: ports.target, - raw: options.raw - }, - proxy: { - latency: options.latency, - port: ports.proxy, - proxy: { - target: { - https: helpers.protocols.target === 'https', - host: '127.0.0.1', - port: ports.target - } - } - } - }, this.callback); - }, - "the proxy Websocket connection": exports.assertSendReceive({ - uri: protocol + '://127.0.0.1:' + ports.proxy, - input: input, - output: output, - raw: options.raw - }) - }; -}; - -// -// ### function assertProxiedtoRoutes (options, nested) -// #### @options {Object} Options for this ProxyTable-based test -// #### @raw {boolean} Enables ws.Server usage. -// #### @routes {Object|string} Routes to use for the proxy. -// #### @hostnameOnly {boolean} Enables hostnameOnly routing. -// #### @nested {Object} Nested vows to add to the returned context. -// -// Creates a complete end-to-end test for requesting against an -// http proxy using `options.routes`: -// -// 1. Creates target servers for all routes in `options.routes.` -// 2. Creates a proxy server. -// 3. Ensure Websocket connections to the proxy server for all route targets -// can send input and recieve output. -// -exports.assertProxiedToRoutes = function (options, nested) { - // - // Assign dynamic ports to the routes to use. - // - options.routes = helpers.http.assignPortsToRoutes(options.routes); - - // - // Parse locations from routes for making assertion requests. - // - var locations = helpers.http.parseRoutes(options), - protocol = helpers.protocols.proxy, - port = helpers.nextPort, - context, - proxy; - - if (options.raw) { - protocol = helpers.protocols.proxy === 'https' - ? 'wss' - : 'ws'; - } - - if (options.filename) { - // - // If we've been passed a filename write the routes to it - // and setup the proxy options to use that file. - // - fs.writeFileSync(options.filename, JSON.stringify({ router: options.routes })); - proxy = { router: options.filename }; - } - else { - // - // Otherwise just use the routes themselves. - // - proxy = { - hostnameOnly: options.hostnameOnly, - router: options.routes - }; - } - - // - // Create the test context which creates all target - // servers for all routes and a proxy server. - // - context = { - topic: function () { - var that = this; - - async.waterfall([ - // - // 1. Create all the target servers - // - async.apply( - async.forEach, - locations, - function createRouteTarget(location, next) { - helpers.ws.createServer({ - raw: options.raw, - port: location.target.port, - output: 'hello from ' + location.source.href, - input: 'hello to ' + location.source.href - }, next); - } - ), - // - // 2. Create the proxy server - // - async.apply( - helpers.http.createProxyServer, - { - port: port, - latency: options.latency, - routing: true, - proxy: proxy - } - ) - ], function (_, server) { - // - // 3. Set the proxy server for later use - // - that.proxyServer = server; - that.callback(); - }); - - // - // 4. Assign the port to the context for later use - // - this.port = port; - } - }; - - // - // Add test assertions for each of the route locations. - // - locations.forEach(function (location) { - context[location.source.href] = exports.assertSendRecieve({ - uri: protocol + '://127.0.0.1:' + port + location.source.path, - output: 'hello from ' + location.source.href, - input: 'hello to ' + location.source.href, - raw: options.raw - }); - }); - - return context; -}; \ No newline at end of file diff --git a/test/ws/routing-table-test.js b/test/ws/routing-table-test.js deleted file mode 100644 index e04d64752..000000000 --- a/test/ws/routing-table-test.js +++ /dev/null @@ -1,25 +0,0 @@ -/* - * routing-tabletest.js: Test for proxying `socket.io` and raw `WebSocket` requests using a ProxyTable. - * - * (C) 2010 Nodejitsu Inc. - * MIT LICENCE - * - */ - -var vows = require('vows'), - macros = require('../macros'), - helpers = require('../helpers/index'); - -vows.describe(helpers.describe('routing-proxy', 'ws')).addBatch({ - "With a valid target server": { - "and no latency": { - "using ws": macros.ws.assertProxied(), - "using socket.io": macros.ws.assertProxied({ - raw: true - }), - }, - // "and latency": macros.websocket.assertProxied({ - // latency: 2000 - // }) - } -}).export(module); \ No newline at end of file diff --git a/test/ws/socket.io-test.js b/test/ws/socket.io-test.js deleted file mode 100644 index d833109e6..000000000 --- a/test/ws/socket.io-test.js +++ /dev/null @@ -1,20 +0,0 @@ -/* - * socket.io-test.js: Test for proxying `socket.io` requests. - * - * (C) 2010 Nodejitsu Inc. - * MIT LICENCE - * - */ - -var vows = require('vows'), - macros = require('../macros'), - helpers = require('../helpers/index'); - -vows.describe(helpers.describe('socket.io', 'ws')).addBatch({ - "With a valid target server": { - "and no latency": macros.ws.assertProxied(), - // "and latency": macros.ws.assertProxied({ - // latency: 2000 - // }) - } -}).export(module); \ No newline at end of file diff --git a/test/ws/ws-test.js b/test/ws/ws-test.js deleted file mode 100644 index f3549152f..000000000 --- a/test/ws/ws-test.js +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ws-test.js: Tests for proxying raw Websocket requests. - * - * (C) 2010 Nodejitsu Inc. - * MIT LICENCE - * - */ - -var vows = require('vows'), - macros = require('../macros'), - helpers = require('../helpers/index'); - -vows.describe(helpers.describe('websocket', 'ws')).addBatch({ - "With a valid target server": { - "and no latency": macros.ws.assertProxied({ - raw: true - }), - // "and latency": macros.ws.assertProxied({ - // raw: true, - // latency: 2000 - // }) - } -}).export(module); \ No newline at end of file From 969a623542030147e95d78fae164b3cdf061a77f Mon Sep 17 00:00:00 2001 From: Mike Moulton Date: Tue, 14 Jan 2014 00:45:42 -0700 Subject: [PATCH 232/556] Only emit response if a valid server is present --- lib/http-proxy/passes/web-incoming.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 2b14c874c..305365f7a 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -117,7 +117,7 @@ web_o = Object.keys(web_o).map(function(pass) { (options.buffer || req).pipe(proxyReq); proxyReq.on('response', function(proxyRes) { - server.emit('proxyRes', proxyRes); + if(server) { server.emit('proxyRes', proxyRes); } for(var i=0; i < web_o.length; i++) { if(web_o[i](req, res, proxyRes)) { break; } } From 4351ed1c86c8336b3a2d9f80098dcb2c9180685d Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 16 Jan 2014 15:03:44 +0100 Subject: [PATCH 233/556] [fix] closes #547 --- lib/http-proxy.js | 7 +++++++ lib/http-proxy/index.js | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 196dded44..34029e864 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -8,6 +8,13 @@ var http = require('http'), */ module.exports = httpProxy.Server; +module.exports.createProxy = function(options) { + return { + web: httpProxy.createRightProxy('web')(options), + ws: httpProxy.createRightProxy('ws')(options) + }; +} + /** * Creates the proxy server. * diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index bd8b8a991..95bc287b0 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -80,7 +80,7 @@ function createRightProxy(type) { }; }; } - +httpProxy.createRightProxy = createRightProxy; function ProxyServer(options) { EE3.call(this); From d23353d980d8aa1b2606e3d36a83d27432952bef Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 16 Jan 2014 15:05:52 +0100 Subject: [PATCH 234/556] [fix] ee3 error handling --- lib/http-proxy/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 95bc287b0..4436c1351 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -96,6 +96,10 @@ function ProxyServer(options) { this.wsPasses = Object.keys(ws).map(function(pass) { return ws[pass]; }); + + this.on('error', function(err) { + console.log(err); + }); } require('util').inherits(ProxyServer, EE3); From d6d2d0c8821bba9888eee7c3881fc408b3b2008e Mon Sep 17 00:00:00 2001 From: yawnt Date: Thu, 16 Jan 2014 16:28:08 +0100 Subject: [PATCH 235/556] [fix] remove caronte --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3ec4ed54d..4d68f3d5e 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ proxies and load balancers.

-    +    - +

### Looking to Upgrade from 0.8.x ? Click [here](UPGRADING.md) From 53a2653b5e92b6da4acd2d6732279f31ae4dcba9 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 17 Jan 2014 22:18:20 +0100 Subject: [PATCH 236/556] [fix] closes #553 --- lib/http-proxy/index.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 4436c1351..97f71a9ff 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -26,9 +26,15 @@ httpProxy.Server = ProxyServer; */ function createRightProxy(type) { + var webPasses = Object.keys(web).map(function(pass) { + return web[pass]; + }); + var wsPasses = Object.keys(ws).map(function(pass) { + return ws[pass]; + }); return function(options) { return function(req, res /*, [head], [opts] */) { - var passes = (type === 'ws') ? this.wsPasses : this.webPasses, + var passes = (type === 'ws') ? (this.wsPasses || wsPasses) : (this.webPasses || webPasses), args = [].slice.call(arguments), cntr = args.length - 1, head, cbl; @@ -62,7 +68,8 @@ function createRightProxy(type) { 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++) { /** From 689459fe46885a1b3b8e32a4df55f2d1339143e5 Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 17 Jan 2014 22:18:54 +0100 Subject: [PATCH 237/556] typo --- lib/http-proxy/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 97f71a9ff..3ba09cd47 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -69,7 +69,7 @@ function createRightProxy(type) { options[e] = parse_url(options[e]); }); - if(typeof this.emit == 'undefined' && !cbl) { throw new Error("You need to pass a callback to handle errors") } + 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++) { /** From 68c55123039369cdf8a55a64b36b719c96b672cf Mon Sep 17 00:00:00 2001 From: yawnt Date: Fri, 17 Jan 2014 22:19:42 +0100 Subject: [PATCH 238/556] [dist] bump v1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5c7c3a1eb..1e0867f85 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.0.0", + "version" : "1.0.1", "description" : "HTTP proxying for the masses", "author": "Nodejitsu Inc. ", "maintainers" : [ From e936d186b64fbbcd579dec0d49d7b6f8ec153493 Mon Sep 17 00:00:00 2001 From: yawnt Date: Sun, 19 Jan 2014 11:49:26 +0100 Subject: [PATCH 239/556] [fix] closes #555 --- lib/http-proxy/passes/web-incoming.js | 2 +- lib/http-proxy/passes/ws-incoming.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 305365f7a..1840d618b 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -108,7 +108,7 @@ web_o = Object.keys(web_o).map(function(pass) { proxyReq.on('error', function(err){ if(options.buffer) { options.buffer.destroy(); } if (clb) { - clb(err); + clb(err, req, res); } else { server.emit('error', err, req, res); } diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 720ac2745..057c54066 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -108,7 +108,7 @@ var passes = exports; function onError(err) { if (clb) { - clb(err); + clb(err, req, socket); } else { server.emit('error', err, req, socket); } From c5ec1836b283bd8fd411ef433492186a032f418b Mon Sep 17 00:00:00 2001 From: alevicki Date: Mon, 20 Jan 2014 10:24:53 -0600 Subject: [PATCH 240/556] Fix before and after type check --- lib/http-proxy/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 3ba09cd47..290569a3e 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -129,7 +129,7 @@ ProxyServer.prototype.listen = function(port) { }; ProxyServer.prototype.before = function(type, passName, callback) { - if (type !== 'ws' || type !== 'web') { + if (type !== 'ws' && type !== 'web') { throw new Error('type must be `web` or `ws`'); } var passes = (type === 'ws') ? this.wsPasses : this.webPasses, @@ -144,7 +144,7 @@ ProxyServer.prototype.before = function(type, passName, callback) { passes.splice(i, 0, callback); }; ProxyServer.prototype.after = function(type, passName, callback) { - if (type !== 'ws' || type !== 'web') { + if (type !== 'ws' && type !== 'web') { throw new Error('type must be `web` or `ws`'); } var passes = (type === 'ws') ? this.wsPasses : this.webPasses, From 96ea631fb6cb7267b625ded89f379a3ff487eeb9 Mon Sep 17 00:00:00 2001 From: p-a-c-o Date: Tue, 21 Jan 2014 20:35:49 +0100 Subject: [PATCH 241/556] Extend listen to enable IPv6 support. --- lib/http-proxy/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 290569a3e..994781a9b 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -111,7 +111,7 @@ function ProxyServer(options) { require('util').inherits(ProxyServer, EE3); -ProxyServer.prototype.listen = function(port) { +ProxyServer.prototype.listen = function(port, hostname) { var self = this, closure = function(req, res) { self.web(req, res); }; @@ -123,7 +123,7 @@ ProxyServer.prototype.listen = function(port) { this._server.on('upgrade', function(req, socket, head) { self.ws(req, socket, head); }); } - this._server.listen(port); + this._server.listen(port, hostname); return this; }; From 0b223abb65286e0844627c2791e98dc884dadf10 Mon Sep 17 00:00:00 2001 From: David Glasser Date: Wed, 22 Jan 2014 15:28:23 -0800 Subject: [PATCH 242/556] Fix argument order for ws stream pass head and error handling was broken before this commit. --- lib/http-proxy/passes/ws-incoming.js | 2 +- test/lib-http-proxy-test.js | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 057c54066..a9e879785 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -78,7 +78,7 @@ var passes = exports; * * @api private */ - function stream(req, socket, options, server, head, clb) { + function stream(req, socket, options, head, server, clb) { common.setupSocket(socket); if (head && head.length) socket.unshift(head); diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 6b2ce035e..d6231751b 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -261,9 +261,29 @@ describe('lib/http-proxy.js', function() { }); }); }); - }); - describe('#createProxyServer using the ws-incoming passes', function () { + 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({ From 8004f4e5fc0f535806e92ec4e1bd973a45367dac Mon Sep 17 00:00:00 2001 From: Arnout Kazemier <3rd-Eden@users.noreply.github.com> Date: Tue, 28 Jan 2014 11:25:24 +0100 Subject: [PATCH 243/556] [doc] Fix broken image in npm by using an absolute link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d68f3d5e..c40c00529 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- +

node-http-proxy From 4ecc6e26cef6c8264441353a4a6ad05379aa37a3 Mon Sep 17 00:00:00 2001 From: Sep Date: Tue, 28 Jan 2014 21:51:59 +0800 Subject: [PATCH 244/556] Update README.md Syntax error correction --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c40c00529..a86128592 100644 --- a/README.md +++ b/README.md @@ -199,8 +199,8 @@ httpProxy.createServer({ port: 9009 }, ssl: { - key: fs.readFileSync('valid-ssl-key.pem'), 'utf8'), - cert: fs.readFileSync('valid-ssl-cert.pem'), 'utf8') + key: fs.readFileSync('valid-ssl-key.pem', 'utf8'), + cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8') } }).listen(8009); ``` @@ -213,8 +213,8 @@ httpProxy.createServer({ // httpProxy.createServer({ ssl: { - key: fs.readFileSync('valid-ssl-key.pem'), 'utf8'), - cert: fs.readFileSync('valid-ssl-cert.pem'), 'utf8') + 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. From daad4703f3a80014936c89f4d67affdc3246f478 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 28 Jan 2014 12:32:43 -0500 Subject: [PATCH 245/556] [fix] replicate node core behavior and throw an error if the user does not add their own error listener --- lib/http-proxy/index.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 994781a9b..9ae68615d 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -68,7 +68,7 @@ function createRightProxy(type) { 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++) { @@ -104,13 +104,22 @@ function ProxyServer(options) { return ws[pass]; }); - this.on('error', function(err) { - console.log(err); - }); + 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); }; From 4c3ba74c4e99f03eed84f4d34844870845d96790 Mon Sep 17 00:00:00 2001 From: David Glasser Date: Wed, 22 Jan 2014 15:40:40 -0800 Subject: [PATCH 246/556] Close outgoing ws if incoming ws emits error Fixes #559, which contains a full reproduction recipe. --- lib/http-proxy/passes/ws-incoming.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index a9e879785..7673fe067 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -88,10 +88,16 @@ var passes = exports; common.setupOutgoing(options.ssl || {}, options, req) ); // Error Handler - proxyReq.on('error', onError); + proxyReq.on('error', onOutgoingError); proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { - proxySocket.on('error', onError); + 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); @@ -106,7 +112,7 @@ var passes = exports; return proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT - function onError(err) { + function onOutgoingError(err) { if (clb) { clb(err, req, socket); } else { From 4bdc3e4f455b2749c03961404db74e3112a3e9e8 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 28 Jan 2014 14:34:25 -0500 Subject: [PATCH 247/556] [dist] Version bump. 1.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1e0867f85..8402f6b51 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.0.1", + "version" : "1.0.2", "description" : "HTTP proxying for the masses", "author": "Nodejitsu Inc. ", "maintainers" : [ From 80f645c7c0c6cd7edc8e6e32688240feedd32453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=BE=85=E0=BC=BB=20=C7=AC=C9=80=C4=A7=20=E0=BC=84?= =?UTF-8?q?=E0=BC=86=E0=BD=89?= Date: Wed, 5 Feb 2014 15:03:36 +0100 Subject: [PATCH 248/556] Fix doc: option lines --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a86128592..caa63780c 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ proxies and load balancers. ### Core Concept A new proxy is created by calling `createProxyServer` and passing -an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L26-L39)) +an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L34-L51)) ```javascript var httpProxy = require('http-proxy'); From 7923cf3c6bb7a32cdefc3ee6060cd1070cf440c6 Mon Sep 17 00:00:00 2001 From: Topher Bullock Date: Fri, 7 Feb 2014 16:49:45 -0500 Subject: [PATCH 249/556] Add Repository field to package.json Seeing "npm WARN package.json http-proxy@1.0.2 No repository field." makes me anxious and its such an easy action to add a repo field to the package.json. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 8402f6b51..cf6bac4fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name" : "http-proxy", "version" : "1.0.2", + "repository" : "https://github.com/nodejitsu/node-http-proxy.git", "description" : "HTTP proxying for the masses", "author": "Nodejitsu Inc. ", "maintainers" : [ From 68fa17bbcaa73ae2d9539cba6f6ddff29f9e30d5 Mon Sep 17 00:00:00 2001 From: "@xtreme-topher-bullock / @xtreme-todd-ritchie" Date: Mon, 10 Feb 2014 10:07:00 -0500 Subject: [PATCH 250/556] @xtreme-topher-bullock - update package.json to have proper repository key and formatting --- package.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index cf6bac4fe..2193ce75d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,12 @@ { "name" : "http-proxy", "version" : "1.0.2", - "repository" : "https://github.com/nodejitsu/node-http-proxy.git", + + "repository" : { + "type" : "git", + "url" : "https://github.com/nodejitsu/node-http-proxy.git" + }, + "description" : "HTTP proxying for the masses", "author": "Nodejitsu Inc. ", "maintainers" : [ From e633b0f7e4fd719d809eaeb4725e589f79c271ab Mon Sep 17 00:00:00 2001 From: Sam Beran Date: Tue, 11 Feb 2014 15:01:03 -0600 Subject: [PATCH 251/556] Add support for localAddress When we make outgoing requests, we may want to bind to a specific local address. This change allows the localAddress property to be specified via the options object. --- lib/http-proxy.js | 1 + lib/http-proxy/common.js | 1 + test/lib-http-proxy-common-test.js | 2 ++ 3 files changed, 4 insertions(+) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 34029e864..b7bc7a657 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -42,6 +42,7 @@ module.exports.createProxyServer = module.exports.createServer = function create * ws : * xfwd : * secure : + * localAddress : * } * * NOTE: `options.ws` and `options.ssl` are optional. diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 789757880..1b981e238 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -45,6 +45,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { outgoing.agent = options.agent || false; outgoing.path = url.parse(req.url).path; + outgoing.localAddress = options.localAddress; return outgoing; }; diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 7398a0ebe..8cb9391dc 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -15,6 +15,7 @@ describe('lib/http-proxy/common.js', function () { port : 'you', }, headers: {'fizz': 'bang', 'overwritten':true}, + localAddress: 'local.address', }, { method : 'i', @@ -34,6 +35,7 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.headers.pro).to.eql('xy'); expect(outgoing.headers.fizz).to.eql('bang'); expect(outgoing.headers.overwritten).to.eql(true); + expect(outgoing.localAddress).to.eql('local.address'); }); it('should set the agent to false if none is given', function () { From 99f757251b42aeb5d26535a7363c96804ee057f0 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 26 Feb 2014 15:12:38 +0200 Subject: [PATCH 252/556] Fix for #591 Fix for proxy crash if `HOST` header is not defined bug https://github.com/nodejitsu/node-http-proxy/issues/591. --- lib/http-proxy/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 789757880..0646194de 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -75,7 +75,7 @@ common.setupSocket = function(socket) { }; common.getPort = function(req) { - var res = req.headers.host.match(/:(\d+)/); + var res = req.headers.host ? req.headers.host.match(/:(\d+)/) : ""; return res ? res[1] : req.connection.pair ? '443' : '80' ; From a7b16eb136f61b8695a3aa89a20882927355d29e Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 26 Mar 2014 21:58:58 -0400 Subject: [PATCH 253/556] [api] add toProxy method to allow absolute URLs to be sent when sending to another proxy fixes #603 --- lib/http-proxy.js | 1 + lib/http-proxy/common.js | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 34029e864..5b677fbf3 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -42,6 +42,7 @@ module.exports.createProxyServer = module.exports.createServer = function create * ws : * xfwd : * secure : + * toProxy: Date: Wed, 26 Mar 2014 22:07:09 -0400 Subject: [PATCH 254/556] [fix] set connection to CLOSE in cases where the agent is false. --- lib/http-proxy/common.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 1c838c931..51df1380e 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -45,6 +45,15 @@ common.setupOutgoing = function(outgoing, options, req, forward) { outgoing.agent = options.agent || false; + // + // Remark: If we are false set the connection: close. This is the right thing to do + // as node core doesn't handle this COMPLETELY properly yet. + // + if(!outgoing.agent) { + outgoing.headers = outgoing.headers || {}; + outgoing.headers.connection = 'close'; + } + // // Remark: Can we somehow not use url.parse as a perf optimization? // From ece85b4e1ba379b3ed084bd8f606e285c14d4db3 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 26 Mar 2014 22:36:59 -0400 Subject: [PATCH 255/556] [doc] update docs with toProxy option --- README.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index caa63780c..a5b9c7d4a 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ node-http-proxy ======= -`node-http-proxy` is an HTTP programmable proxying library that supports +`node-http-proxy` is an HTTP programmable proxying library that supports websockets. It is suitable for implementing components such as proxies and load balancers. @@ -23,7 +23,7 @@ proxies and load balancers. ### Core Concept A new proxy is created by calling `createProxyServer` and passing -an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L34-L51)) +an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L34-L51)) ```javascript var httpProxy = require('http-proxy'); @@ -48,7 +48,7 @@ require('http').createServer(function(req, res) { Errors can be listened on either using the Event Emitter API ```javascript -proxy.on('error', function(e) { +proxy.on('error', function(e) { ... }); ``` @@ -60,9 +60,9 @@ 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. +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 +The second pipeline (outgoing) is responsible for the creation and manipulation of the stream that, from your target, returns data to the client. @@ -93,14 +93,14 @@ 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 +// 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 // @@ -171,7 +171,7 @@ 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.'); }); @@ -251,7 +251,7 @@ var proxyServer = http.createServer(function (req, res) { }); // -// Listen to the `upgrade` event and proxy the +// Listen to the `upgrade` event and proxy the // WebSocket requests as well. // proxyServer.on('upgrade', function (req, socket, head) { @@ -263,8 +263,8 @@ proxyServer.listen(8015); ### Contributing and Issues -* Search on Google/Github -* If you can't find anything, open an issue +* 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) @@ -273,7 +273,7 @@ proxyServer.listen(8015); `httpProxy.createProxyServer` supports the following options: - * **target**: url string to be parsed with the url module + * **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 @@ -283,6 +283,7 @@ If you are using the `proxyServer.listen` method, the following options are also * **ssl**: object to be passed to https.createServer() * **ws**: true/false, if you want to proxy websockets * **xfwd**: true/false, adds x-forward headers + * **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies) ### Test From 07fceb7c7aed25a8991d0295db4b4a7e50d79cf9 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 26 Mar 2014 22:41:51 -0400 Subject: [PATCH 256/556] [dist] Version bump. 1.0.3 --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 2193ce75d..8068480d2 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name" : "http-proxy", - "version" : "1.0.2", - + "version" : "1.0.3", + "repository" : { "type" : "git", "url" : "https://github.com/nodejitsu/node-http-proxy.git" }, - + "description" : "HTTP proxying for the masses", "author": "Nodejitsu Inc. ", "maintainers" : [ From eca765a856164c077ff9128949019552cdaf9a67 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 26 Mar 2014 22:48:35 -0400 Subject: [PATCH 257/556] [minor] missing angle bracket --- lib/http-proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index df9972f78..5df69a948 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -42,7 +42,7 @@ module.exports.createProxyServer = module.exports.createServer = function create * ws : * xfwd : * secure : - * toProxy: * localAddress : * } * From d658c9fa39af169258cf53d65bb5513555e48942 Mon Sep 17 00:00:00 2001 From: hipstern Date: Sat, 5 Apr 2014 11:05:17 -0700 Subject: [PATCH 258/556] Update UPGRADING.md Fixing a typo --- UPGRADING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADING.md b/UPGRADING.md index 8c0db431c..c28bbfedf 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -16,7 +16,7 @@ Check the [README.md](https://github.com/nodejitsu/node-http-proxy/blob/caronte/ ## Proxying -Web proying is done by calling the `.web()` method on a Proxy instance. You can check among some use cases in the [examples folder](https://github.com/nodejitsu/node-http-proxy/tree/caronte/examples/http) +Web proxying is done by calling the `.web()` method on a Proxy instance. You can check among some use cases in the [examples folder](https://github.com/nodejitsu/node-http-proxy/tree/caronte/examples/http) ```javascript // From c6b7a7919f774d49e5d1d56990e9590e6a12e93c Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 9 Apr 2014 13:37:27 -0400 Subject: [PATCH 259/556] [fix] always be an eventemitter for consistency fixes #606 --- lib/http-proxy.js | 11 +++-------- lib/http-proxy/index.js | 9 ++------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 5df69a948..bea3fe105 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -8,13 +8,6 @@ var http = require('http'), */ module.exports = httpProxy.Server; -module.exports.createProxy = function(options) { - return { - web: httpProxy.createRightProxy('web')(options), - ws: httpProxy.createRightProxy('ws')(options) - }; -} - /** * Creates the proxy server. * @@ -30,7 +23,9 @@ module.exports.createProxy = function(options) { * @api public */ -module.exports.createProxyServer = module.exports.createServer = function createProxyServer(options) { +module.exports.createProxyServer = + module.exports.createServer = + module.exports.createProxy = function createProxyServer(options) { /* * `options` is needed and it must have the following layout: * diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 9ae68615d..01fce24ca 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -26,15 +26,10 @@ httpProxy.Server = ProxyServer; */ function createRightProxy(type) { - var webPasses = Object.keys(web).map(function(pass) { - return web[pass]; - }); - var wsPasses = Object.keys(ws).map(function(pass) { - return ws[pass]; - }); + return function(options) { return function(req, res /*, [head], [opts] */) { - var passes = (type === 'ws') ? (this.wsPasses || wsPasses) : (this.webPasses || webPasses), + var passes = (type === 'ws') ? this.wsPasses : this.webPasses, args = [].slice.call(arguments), cntr = args.length - 1, head, cbl; From 8b48a9fdab01624f7249c53f25919b1295eefb10 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 9 Apr 2014 13:38:13 -0400 Subject: [PATCH 260/556] [api] emit a start an an end event --- lib/http-proxy/passes/web-incoming.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 1840d618b..29ae30657 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -90,6 +90,13 @@ web_o = Object.keys(web_o).map(function(pass) { */ function stream(req, res, options, _, server, clb) { + + // + // And we begin! + // + if (!clb) { + server.emit('start', req, res, options.target) + } if(options.forward) { // If forward enable, so just pipe the request var forwardReq = (options.forward.protocol === 'https:' ? https : http).request( @@ -122,6 +129,15 @@ web_o = Object.keys(web_o).map(function(pass) { if(web_o[i](req, res, proxyRes)) { break; } } + // + // Allow us to listen when the proxy has completed + // + proxyRes.on('end', function () { + if (!clb) { + server.emit('end', req, res, proxyRes); + } + }) + proxyRes.pipe(res); }); From 97ceeb37d04e5d2195352365985165866323c4d7 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 9 Apr 2014 13:38:40 -0400 Subject: [PATCH 261/556] [dist] Version bump. 1.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8068480d2..ff9cbc86b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.0.3", + "version" : "1.1.0", "repository" : { "type" : "git", From 4f07dc220d700ac90bd8405f7cb0724bdae4b430 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 10 Apr 2014 20:02:46 -0400 Subject: [PATCH 262/556] [fix] let user make the decision on what to do with the buffer --- lib/http-proxy/passes/web-incoming.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 29ae30657..26f12c695 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -113,7 +113,6 @@ web_o = Object.keys(web_o).map(function(pass) { // Error Handler proxyReq.on('error', function(err){ - if(options.buffer) { options.buffer.destroy(); } if (clb) { clb(err, req, res); } else { From d908e2ad61013ed1f6e2f80c4b67a6dce7d0f504 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 10 Apr 2014 20:03:06 -0400 Subject: [PATCH 263/556] [dist] Version bump. 1.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ff9cbc86b..7a4a962c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.1.0", + "version" : "1.1.1", "repository" : { "type" : "git", From 77a1cff9bcf697eab27819eef054024bdc0a2ba3 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 14 Apr 2014 13:08:10 -0400 Subject: [PATCH 264/556] [fix] handle error on incoming request as well and properly abort proxy if client request is aborted --- lib/http-proxy/passes/web-incoming.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 26f12c695..a528c3689 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -91,9 +91,7 @@ web_o = Object.keys(web_o).map(function(pass) { function stream(req, res, options, _, server, clb) { - // // And we begin! - // if (!clb) { server.emit('start', req, res, options.target) } @@ -111,14 +109,24 @@ web_o = Object.keys(web_o).map(function(pass) { common.setupOutgoing(options.ssl || {}, options, req) ); + // Ensure we abort proxy if request is aborted + req.on('aborted', function () { + proxyReq.abort(); + }); + + // Handle errors on incoming request as well as it makes sense to + req.on('error', proxyError); + // Error Handler - proxyReq.on('error', function(err){ + proxyReq.on('error', proxyError); + + function proxyError (err){ if (clb) { clb(err, req, res); } else { server.emit('error', err, req, res); } - }); + } (options.buffer || req).pipe(proxyReq); @@ -128,9 +136,7 @@ web_o = Object.keys(web_o).map(function(pass) { if(web_o[i](req, res, proxyRes)) { break; } } - // // Allow us to listen when the proxy has completed - // proxyRes.on('end', function () { if (!clb) { server.emit('end', req, res, proxyRes); From 61c8734e8b1115fab0e0db23fd8eeccbae61eee0 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 14 Apr 2014 13:17:18 -0400 Subject: [PATCH 265/556] [fix test] handle proxy error since we are properly aborting the proxy Request --- test/lib-http-proxy-test.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index d6231751b..d6d5b31df 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -78,14 +78,14 @@ describe('lib/http-proxy.js', function() { }); 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(); }); }); @@ -105,7 +105,7 @@ describe('lib/http-proxy.js', function() { }); source.listen(ports.source); - + http.request({ hostname: '127.0.0.1', port: ports.proxy, @@ -117,7 +117,7 @@ describe('lib/http-proxy.js', function() { expect(data.toString()).to.eql('Hello from ' + ports.source); }); - res.on('end', function () { + res.on('end', function () { source.close(); proxy._server.close(); done(); @@ -141,7 +141,7 @@ describe('lib/http-proxy.js', function() { }) proxy.listen(ports.proxy); - + http.request({ hostname: '127.0.0.1', port: ports.proxy, @@ -159,6 +159,11 @@ describe('lib/http-proxy.js', function() { timeout: 3 }).listen(ports.proxy); + proxy.on('error', function (e) { + expect(e).to.be.an(Error); + expect(e.code).to.be.eql('ECONNRESET'); + }); + var source = http.createServer(function(req, res) { setTimeout(function () { res.end('At this point the socket should be closed'); @@ -207,7 +212,7 @@ describe('lib/http-proxy.js', function() { // proxy.ee.on('http-proxy:**', function (uno, dos, tres) { // events.push(this.event); // }) - + // http.request({ // hostname: '127.0.0.1', // port: '8081', @@ -314,4 +319,4 @@ describe('lib/http-proxy.js', function() { }) }); }) -}); \ No newline at end of file +}); From c54278bd3b00e82f4253393b6f6beb1d5a1b19e5 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 14 Apr 2014 13:17:58 -0400 Subject: [PATCH 266/556] [dist] Version bump. 1.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7a4a962c9..5a0bdc3b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.1.1", + "version" : "1.1.2", "repository" : { "type" : "git", From 4947484806f839d5e0a1b615b56a1bc847b8f534 Mon Sep 17 00:00:00 2001 From: Brett Kochendorfer Date: Sun, 20 Apr 2014 20:34:08 -0500 Subject: [PATCH 267/556] Update README.md for benchmarks Remove number of requests flag from `wrk` as it no longer exists. Swapped out for 5 minute duration. --- benchmark/README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/benchmark/README.md b/benchmark/README.md index 2a852d14e..e48e18e02 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -10,14 +10,18 @@ All benchmarking shall be done with [wrk](https://github.com/wg/wrk) which _is t $ wrk Usage: wrk Options: - -c, --connections Connections to keep open - -r, --requests Total requests to make - -t, --threads Number of threads to use + -c, --connections Connections to keep open + -d, --duration Duration of test + -t, --threads Number of threads to use - -H, --header Add header to request + -s, --script Load Lua script file + -H, --header Add header to request + --latency Print latency statistics + --timeout Socket/request timeout -v, --version Print version details - Numeric arguments may include a SI unit (2k, 2M, 2G) + Numeric arguments may include a SI unit (1k, 1M, 1G) + Time arguments may include a time unit (2s, 2m, 2h) ``` ## Benchmarks @@ -30,4 +34,4 @@ _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 +3. **A wrk process:** `wrk -c 20 -d5m -t 2 http://127.0.0.1:8000` From d637b964206c4267e5278c9e9ff5efa040819e0a Mon Sep 17 00:00:00 2001 From: Jay Harris Date: Fri, 9 May 2014 20:48:30 -0400 Subject: [PATCH 268/556] Don't override connection header if Upgrading --- lib/http-proxy/common.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index d682047c8..d4186f06f 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -47,12 +47,14 @@ common.setupOutgoing = function(outgoing, options, req, forward) { outgoing.localAddress = options.localAddress; // - // Remark: If we are false set the connection: close. This is the right thing to do + // Remark: If we are false and not upgrading, set the connection: close. This is the right thing to do // as node core doesn't handle this COMPLETELY properly yet. // if(!outgoing.agent) { outgoing.headers = outgoing.headers || {}; - outgoing.headers.connection = 'close'; + if(typeof outgoing.headers.connection !== 'string' || outgoing.headers.connection.toLowerCase() !== 'upgrade') { + outgoing.headers.connection = 'close'; + } } // From 8aa7c519b15f734af7db34d2102781adbeae10aa Mon Sep 17 00:00:00 2001 From: Jay Harris Date: Fri, 9 May 2014 22:49:23 -0400 Subject: [PATCH 269/556] Adding test cases on preventing upgrade override --- test/lib-http-proxy-common-test.js | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 8cb9391dc..dab2d26ac 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -38,6 +38,48 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.localAddress).to.eql('local.address'); }); + it('should not override agentless upgrade header', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, + { + agent: undefined, + target: { + host : 'hey', + hostname : 'how', + socketPath: 'are', + port : 'you', + }, + headers: {'connection': 'upgrade'}, + }, + { + method : 'i', + url : 'am', + headers : {'pro':'xy','overwritten':false} + }); + expect(outgoing.headers.connection).to.eql('upgrade'); + }); + + it('should override agentless non-upgrade header to close', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, + { + agent: undefined, + target: { + host : 'hey', + hostname : 'how', + socketPath: 'are', + port : 'you', + }, + headers: {'connection': 'xyz'}, + }, + { + method : 'i', + url : 'am', + headers : {'pro':'xy','overwritten':false} + }); + expect(outgoing.headers.connection).to.eql('close'); + }); + it('should set the agent to false if none is given', function () { var outgoing = {}; common.setupOutgoing(outgoing, {target: From ccad17795417de74bea2bcb6d6c559a4601af76d Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sun, 11 May 2014 01:02:35 -0400 Subject: [PATCH 270/556] [minor] style --- lib/http-proxy/common.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index d4186f06f..5d10647cf 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -50,11 +50,11 @@ common.setupOutgoing = function(outgoing, options, req, forward) { // Remark: If we are false and not upgrading, set the connection: close. This is the right thing to do // as node core doesn't handle this COMPLETELY properly yet. // - if(!outgoing.agent) { + if (!outgoing.agent) { outgoing.headers = outgoing.headers || {}; - if(typeof outgoing.headers.connection !== 'string' || outgoing.headers.connection.toLowerCase() !== 'upgrade') { - outgoing.headers.connection = 'close'; - } + if (typeof outgoing.headers.connection !== 'string' + || outgoing.headers.connection.toLowerCase() !== 'upgrade' + ) { outgoing.headers.connection = 'close'; } } // From c472527ea60da8b2f737d5742bc61ad2772b7e0b Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sun, 11 May 2014 01:03:39 -0400 Subject: [PATCH 271/556] [dist] Version bump. 1.1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5a0bdc3b3..dd1c8cbaf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.1.2", + "version" : "1.1.3", "repository" : { "type" : "git", From 1213e46b1b0975ad1d5c5d0aaeace40a0811118f Mon Sep 17 00:00:00 2001 From: Bryce Gibson Date: Thu, 8 May 2014 10:07:18 +1000 Subject: [PATCH 272/556] Add the req and res objects to the proxyRes event --- lib/http-proxy/passes/web-incoming.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index a528c3689..b127bc709 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -131,7 +131,7 @@ web_o = Object.keys(web_o).map(function(pass) { (options.buffer || req).pipe(proxyReq); proxyReq.on('response', function(proxyRes) { - if(server) { server.emit('proxyRes', proxyRes); } + if(server) { server.emit('proxyRes', proxyRes, req, res); } for(var i=0; i < web_o.length; i++) { if(web_o[i](req, res, proxyRes)) { break; } } From 1385635e18f081af759c8e088f2f6b0219df83db Mon Sep 17 00:00:00 2001 From: Bryce Gibson Date: Mon, 12 May 2014 08:44:02 +1000 Subject: [PATCH 273/556] Add a test for the proxyRes event --- ...lib-http-proxy-passes-web-incoming-test.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index b25ad6e12..49ffa9ef4 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -127,4 +127,32 @@ describe('#createProxyServer.web() using own http server', function () { method: 'GET', }, function() {}).end(); }); + + it('should proxy the request and provide a proxyRes event with the request and response parameters', function(done) { + var proxy = httpProxy.createProxyServer({ + target: 'http://127.0.0.1:8080' + }); + + function requestHandler(req, res) { + proxy.once('proxyRes', function (proxyRes, pReq, pRes) { + source.close(); + proxyServer.close(); + expect(pReq).to.be.equal(req); + expect(pRes).to.be.equal(res); + done(); + }); + + proxy.web(req, res); + } + + var proxyServer = http.createServer(requestHandler); + + var source = http.createServer(function(req, res) { + res.end('Response'); + }); + + proxyServer.listen('8084'); + source.listen('8080'); + http.request('http://127.0.0.1:8084', function() {}).end(); + }); }); \ No newline at end of file From 7cb98a4e417312f01cf4432b52dbb3773aca60a0 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sun, 11 May 2014 19:03:07 -0400 Subject: [PATCH 274/556] [dist] Version bump. 1.1.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd1c8cbaf..3b4cd363a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.1.3", + "version" : "1.1.4", "repository" : { "type" : "git", From 431aba79d8d521e228c1403aaf4fd4a26fba03c3 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 21 May 2014 14:10:52 -0700 Subject: [PATCH 275/556] Trimming contents of distributed npm package. https://www.npmjs.org/doc/developers.html#Keeping-files-out-of-your-package Keep deployments as small as they can be. --- .npmignore | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .npmignore diff --git a/.npmignore b/.npmignore new file mode 100644 index 000000000..081a48c64 --- /dev/null +++ b/.npmignore @@ -0,0 +1,7 @@ +test +examples +doc +benchmark +.travis.yml +CHANGELOG.md +UPGRADING.md \ No newline at end of file From 0f243516e1c6737b95fba220a5028439264b5de6 Mon Sep 17 00:00:00 2001 From: Damian Kaczmarek Date: Tue, 10 Jun 2014 01:35:53 +0200 Subject: [PATCH 276/556] Added targetTimeout option and two tests for timeout --- lib/http-proxy/passes/web-incoming.js | 8 ++ ...lib-http-proxy-passes-web-incoming-test.js | 85 ++++++++++++++++++- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index b127bc709..8d0fc479b 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -109,6 +109,14 @@ web_o = Object.keys(web_o).map(function(pass) { common.setupOutgoing(options.ssl || {}, options, req) ); + // allow outgoing socket to timeout so that we could + // show an error page at the initial request + if(options.targetTimeout) { + proxyReq.setTimeout(options.targetTimeout, function() { + proxyReq.abort(); + }); + } + // Ensure we abort proxy if request is aborted req.on('aborted', function () { proxyReq.abort(); diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 49ffa9ef4..8d2adfec4 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -128,6 +128,87 @@ describe('#createProxyServer.web() using own http server', function () { }, function() {}).end(); }); + it('should proxy the request and handle timeout error (targetTimeout)', function(done) { + var proxy = httpProxy.createProxyServer({ + target: 'http://127.0.0.1:45000', + targetTimeout: 100 + }); + + require('net').createServer().listen(45000); + + var proxyServer = http.createServer(requestHandler); + + var started = new Date().getTime(); + 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(new Date().getTime() - started).to.be.greaterThan(99); + expect(err.code).to.be('ECONNRESET'); + done(); + }); + + proxy.web(req, res); + } + + proxyServer.listen('8084'); + + http.request({ + hostname: '127.0.0.1', + port: '8084', + method: 'GET', + }, function() {}).end(); + }); + + it('should proxy the request and handle timeout error', function(done) { + var proxy = httpProxy.createProxyServer({ + target: 'http://127.0.0.1:45001', + timeout: 100 + }); + + require('net').createServer().listen(45001); + + var proxyServer = http.createServer(requestHandler); + + var cnt = 0; + var doneOne = function() { + cnt += 1; + if(cnt === 2) done(); + } + + var started = new Date().getTime(); + 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('ECONNRESET'); + doneOne(); + }); + + proxy.web(req, res); + } + + proxyServer.listen('8085'); + + var req = http.request({ + hostname: '127.0.0.1', + port: '8085', + method: 'GET', + }, function() {}); + + req.on('error', function(err) { + expect(err).to.be.an(Error); + expect(err.code).to.be('ECONNRESET'); + expect(new Date().getTime() - started).to.be.greaterThan(99); + doneOne(); + }); + req.end(); + }); + it('should proxy the request and provide a proxyRes event with the request and response parameters', function(done) { var proxy = httpProxy.createProxyServer({ target: 'http://127.0.0.1:8080' @@ -151,8 +232,8 @@ describe('#createProxyServer.web() using own http server', function () { res.end('Response'); }); - proxyServer.listen('8084'); + proxyServer.listen('8086'); source.listen('8080'); - http.request('http://127.0.0.1:8084', function() {}).end(); + http.request('http://127.0.0.1:8086', function() {}).end(); }); }); \ No newline at end of file From 159ca83652c1f9f42b469bd42ec1cce595f009b1 Mon Sep 17 00:00:00 2001 From: Damian Kaczmarek Date: Tue, 10 Jun 2014 01:49:16 +0200 Subject: [PATCH 277/556] Fix #657 --- test/lib-http-proxy-test.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index d6d5b31df..220d2f7e4 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -294,9 +294,11 @@ describe('lib/http-proxy.js', function() { 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 () { + }); + proxyServer = proxy.listen(ports.proxy); + var server = http.createServer(); + destiny = io.listen(server); + function startSocketIo() { var client = ioClient.connect('ws://127.0.0.1:' + ports.proxy); client.on('connect', function () { @@ -306,10 +308,12 @@ describe('lib/http-proxy.js', function() { client.on('outgoing', function (data) { expect(data).to.be('Hello over websockets'); proxyServer._server.close(); - destiny.server.close(); + server.close(); done(); }); - }); + } + server.listen(ports.source); + server.on('listening', startSocketIo); destiny.sockets.on('connection', function (socket) { socket.on('incoming', function (msg) { From 4193d3bd74e5ec02341707587b9832650d49a004 Mon Sep 17 00:00:00 2001 From: Damian Kaczmarek Date: Tue, 10 Jun 2014 01:49:16 +0200 Subject: [PATCH 278/556] Fix #657 --- test/lib-http-proxy-test.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index d6d5b31df..220d2f7e4 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -294,9 +294,11 @@ describe('lib/http-proxy.js', function() { 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 () { + }); + proxyServer = proxy.listen(ports.proxy); + var server = http.createServer(); + destiny = io.listen(server); + function startSocketIo() { var client = ioClient.connect('ws://127.0.0.1:' + ports.proxy); client.on('connect', function () { @@ -306,10 +308,12 @@ describe('lib/http-proxy.js', function() { client.on('outgoing', function (data) { expect(data).to.be('Hello over websockets'); proxyServer._server.close(); - destiny.server.close(); + server.close(); done(); }); - }); + } + server.listen(ports.source); + server.on('listening', startSocketIo); destiny.sockets.on('connection', function (socket) { socket.on('incoming', function (msg) { From 7b79a7409ade7a8c79b2ae5761abc4843529063a Mon Sep 17 00:00:00 2001 From: Damian Kaczmarek Date: Tue, 10 Jun 2014 19:04:12 +0200 Subject: [PATCH 279/556] Change name targetTimeout to proxyTimeout --- lib/http-proxy/passes/web-incoming.js | 4 ++-- test/lib-http-proxy-passes-web-incoming-test.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 8d0fc479b..056236e54 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -111,8 +111,8 @@ web_o = Object.keys(web_o).map(function(pass) { // allow outgoing socket to timeout so that we could // show an error page at the initial request - if(options.targetTimeout) { - proxyReq.setTimeout(options.targetTimeout, function() { + if(options.proxyTimeout) { + proxyReq.setTimeout(options.proxyTimeout, function() { proxyReq.abort(); }); } diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 8d2adfec4..93c76ca7a 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -128,10 +128,10 @@ describe('#createProxyServer.web() using own http server', function () { }, function() {}).end(); }); - it('should proxy the request and handle timeout error (targetTimeout)', function(done) { + it('should proxy the request and handle timeout error (proxyTimeout)', function(done) { var proxy = httpProxy.createProxyServer({ target: 'http://127.0.0.1:45000', - targetTimeout: 100 + proxyTimeout: 100 }); require('net').createServer().listen(45000); From 9df4bc1e1216a8e53675f0be16fb9081c11da225 Mon Sep 17 00:00:00 2001 From: Eirik Langholm Vullum Date: Fri, 4 Jul 2014 23:37:23 +0200 Subject: [PATCH 280/556] fix balancer example --- examples/balancer/simple-balancer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/balancer/simple-balancer.js b/examples/balancer/simple-balancer.js index 3f53cc63d..16612b1b1 100644 --- a/examples/balancer/simple-balancer.js +++ b/examples/balancer/simple-balancer.js @@ -58,7 +58,7 @@ http.createServer(function (req, res) { // // ...and then the server you just used becomes the last item in the list. // - addresses.push(target); + addresses.push(target.target); }).listen(8021); // Rinse; repeat; enjoy. \ No newline at end of file From d1baa3684e449610a2aae270816a7b8a907e588e Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 8 Jul 2014 16:12:42 -0400 Subject: [PATCH 281/556] [api] also emit the target on a proxy error --- lib/http-proxy/passes/web-incoming.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 056236e54..4f4c72c56 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -130,9 +130,9 @@ web_o = Object.keys(web_o).map(function(pass) { function proxyError (err){ if (clb) { - clb(err, req, res); + clb(err, req, res, options.target); } else { - server.emit('error', err, req, res); + server.emit('error', err, req, res, options.target); } } From 7104a7c023073a49091969f825738c79ae036123 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 9 Jul 2014 23:27:35 -0400 Subject: [PATCH 282/556] [dist] Version bump. 1.1.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3b4cd363a..74210a2aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.1.4", + "version" : "1.1.5", "repository" : { "type" : "git", From e336b52629276e647abeee300d7091db44e5b885 Mon Sep 17 00:00:00 2001 From: Eric Baer Date: Thu, 10 Jul 2014 11:59:43 -0400 Subject: [PATCH 283/556] Remove changelog - it was not maintained --- CHANGELOG.md | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 21d6bb03c..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,4 +0,0 @@ -### v 1.0.0-alpha - -- Complete refactor with new API - From 5f838541cb5fb08a6d8cb40a72726afb3ebb3d3b Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 17 Jul 2014 10:56:53 -0400 Subject: [PATCH 284/556] do proper checking for a pass not existing. fixes #671 --- lib/http-proxy/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 01fce24ca..2e8d212ae 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -143,7 +143,7 @@ ProxyServer.prototype.before = function(type, passName, callback) { if(v.name === passName) i = idx; }) - if(!i) throw new Error('No such pass'); + if(i === false) throw new Error('No such pass'); passes.splice(i, 0, callback); }; @@ -158,7 +158,7 @@ ProxyServer.prototype.after = function(type, passName, callback) { if(v.name === passName) i = idx; }) - if(!i) throw new Error('No such pass'); + if(i === false) throw new Error('No such pass'); passes.splice(i++, 0, callback); }; From ed9e12b0edb0fc206610e94bd696425619868474 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 17 Jul 2014 10:57:38 -0400 Subject: [PATCH 285/556] [dist] Version bump. 1.1.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74210a2aa..d7a94de35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.1.5", + "version" : "1.1.6", "repository" : { "type" : "git", From db5f2954b2b325818f7e52ed3cd68dab31d370ed Mon Sep 17 00:00:00 2001 From: Manu Sporny Date: Fri, 18 Jul 2014 11:00:33 -0400 Subject: [PATCH 286/556] [api] Add event-based ability to modify pre-flight proxy requests. --- README.md | 37 +++++++++++++++++++ lib/http-proxy/passes/web-incoming.js | 5 +++ ...lib-http-proxy-passes-web-incoming-test.js | 28 ++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/README.md b/README.md index a5b9c7d4a..4281dcf80 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,43 @@ console.log("listening on port 5050") server.listen(5050); ``` +#### Setup a stand-alone proxy server with proxy request header re-writing +This example shows how you can proxy a request using your own HTTP server that +modifies the outgoing proxy request by adding a special header. + +```js +var http = require('http'), + httpProxy = require('http-proxy'); + +// +// Create a proxy server with custom application logic +// +var proxy = httpProxy.createProxyServer({}); + +// To modify the proxy connection before data is sent, you can listen +// for the 'proxyReq' event. When the event is fired, you will receive +// the following arguments: +// (http.ClientRequest proxyReq, http.IncomingMessage req, +// http.ServerResponse res, Object options). This mechanism is useful when +// you need to modify the proxy request before the proxy connection +// is made to the target. +// +proxy.on('proxyReq', function(proxyReq, req, res, options) { + proxyReq.setHeader('X-Special-Proxy-Header', 'foobar'); +}); + +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 diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 4f4c72c56..c7805a4b0 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -109,6 +109,11 @@ web_o = Object.keys(web_o).map(function(pass) { common.setupOutgoing(options.ssl || {}, options, req) ); + // Enable developers to modify the proxyReq before headers are sent + proxyReq.on('socket', function(socket) { + if(server) { server.emit('proxyReq', proxyReq, req, res, options); } + }); + // allow outgoing socket to timeout so that we could // show an error page at the initial request if(options.proxyTimeout) { diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 93c76ca7a..2bd86d87b 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -74,6 +74,34 @@ describe('#createProxyServer.web() using own http server', function () { http.request('http://127.0.0.1:8081', function() {}).end(); }); + it('should detect a proxyReq event and modify headers', function (done) { + var proxy = httpProxy.createProxyServer({ + target: 'http://127.0.0.1:8080', + }); + + proxy.on('proxyReq', function(proxyReq, req, res, options) { + proxyReq.setHeader('X-Special-Proxy-Header', 'foobar'); + }); + + 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.headers['x-special-proxy-header']).to.eql('foobar'); + 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' From 63c53a177217283ec14e4f7c2e891db48842ab4b Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 5 Aug 2014 17:27:21 -0400 Subject: [PATCH 287/556] [dist] Version bump. 1.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d7a94de35..7f445fe6c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.1.6", + "version" : "1.2.0", "repository" : { "type" : "git", From a3d02196c5e62cd58bc0ebe8a66afcdb905d96b3 Mon Sep 17 00:00:00 2001 From: John Catron Date: Wed, 13 Aug 2014 20:22:38 +0000 Subject: [PATCH 288/556] Added close method to proxy server. Ensured server exists before closing. Updated tests to use new close function. Added documentation to README. --- README.md | 16 ++++++++++++++++ lib/http-proxy/index.js | 7 +++++++ test/lib-http-proxy-test.js | 18 +++++++++--------- test/lib-https-proxy-test.js | 8 ++++---- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 4281dcf80..2ea3d02ab 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ 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) +* close `[callback]` (a function that closes the inner webserver and stops listening on given port) Is it then possible to proxy requests by calling these functions @@ -322,6 +323,21 @@ If you are using the `proxyServer.listen` method, the following options are also * **xfwd**: true/false, adds x-forward headers * **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies) +### Shutdown + +* When testing or running server within another program it may be necessary to close the proxy. +* This will stop the proxy from accepting new connections. + +```js +var proxy = new httpProxy.createProxyServer({ + target: { + host: 'localhost', + port: 1337 + } +}); + +proxy.close(); +``` ### Test diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 2e8d212ae..a33084f83 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -132,6 +132,13 @@ ProxyServer.prototype.listen = function(port, hostname) { return this; }; +ProxyServer.prototype.close = function(callback) { + if (this._server) { + this._server.close(callback); + this._server = null; + } +}; + ProxyServer.prototype.before = function(type, passName, callback) { if (type !== 'ws' && type !== 'web') { throw new Error('type must be `web` or `ws`'); diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 220d2f7e4..e0b4eca92 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -52,7 +52,7 @@ describe('lib/http-proxy.js', function() { expect(req.method).to.eql('GET'); expect(req.headers.host.split(':')[1]).to.eql(ports.proxy); source.close(); - proxy._server.close(); + proxy.close(); done(); }); @@ -73,7 +73,7 @@ describe('lib/http-proxy.js', function() { 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(); + proxy.close(); done(); }); @@ -119,7 +119,7 @@ describe('lib/http-proxy.js', function() { res.on('end', function () { source.close(); - proxy._server.close(); + proxy.close(); done(); }); }).end(); @@ -136,7 +136,7 @@ describe('lib/http-proxy.js', function() { proxy.on('error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNREFUSED'); - proxy._server.close(); + proxy.close(); done(); }) @@ -181,7 +181,7 @@ describe('lib/http-proxy.js', function() { testReq.on('error', function (e) { expect(e).to.be.an(Error); expect(e.code).to.be.eql('ECONNRESET'); - proxy._server.close(); + proxy.close(); source.close(); done(); }); @@ -228,7 +228,7 @@ describe('lib/http-proxy.js', function() { // expect(events).to.contain('http-proxy:outgoing:web:begin'); // expect(events).to.contain('http-proxy:outgoing:web:end'); // source.close(); - // proxyServer._server.close(); + // proxyServer.close(); // done(); // }); // }).end(); @@ -253,7 +253,7 @@ describe('lib/http-proxy.js', function() { client.on('message', function (msg) { expect(msg).to.be('Hello over websockets'); client.close(); - proxyServer._server.close(); + proxyServer.close(); destiny.close(); done(); }); @@ -284,7 +284,7 @@ describe('lib/http-proxy.js', function() { proxy.on('error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNREFUSED'); - proxyServer._server.close(); + proxyServer.close(); done(); }); }); @@ -307,7 +307,7 @@ describe('lib/http-proxy.js', function() { client.on('outgoing', function (data) { expect(data).to.be('Hello over websockets'); - proxyServer._server.close(); + proxyServer.close(); server.close(); done(); }); diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js index 192504921..7a966f491 100644 --- a/test/lib-https-proxy-test.js +++ b/test/lib-https-proxy-test.js @@ -53,7 +53,7 @@ describe('lib/http-proxy.js', function() { res.on('end', function () { source.close(); - proxy._server.close(); + proxy.close(); done(); }) }).end(); @@ -93,7 +93,7 @@ describe('lib/http-proxy.js', function() { res.on('end', function () { source.close(); - proxy._server.close(); + proxy.close(); done(); }); }).end(); @@ -138,7 +138,7 @@ describe('lib/http-proxy.js', function() { res.on('end', function () { source.close(); - proxy._server.close(); + proxy.close(); done(); }) }).end(); @@ -219,4 +219,4 @@ describe('lib/http-proxy.js', function() { }) }) }); -}); \ No newline at end of file +}); From 37036dd32565f72ad5777e47509293db18b60ed3 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 14 Aug 2014 13:32:32 -0400 Subject: [PATCH 289/556] [fix] emit an error if proper URL is not passed in as a target --- lib/http-proxy/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 2e8d212ae..29533d170 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -64,7 +64,9 @@ function createRightProxy(type) { options[e] = parse_url(options[e]); }); - if(typeof this.emit === 'undefined' && !cbl) { throw new Error("You need to pass a callback to handle errors") } + if (!options.target && !options.forward) { + return this.emit('error', new Error('Must provide a proper URL as target')); + } for(var i=0; i < passes.length; i++) { /** From 0a6b424e2c3b6cef68362a71f0e56740b2605af7 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 14 Aug 2014 13:40:40 -0400 Subject: [PATCH 290/556] [dist] Version bump. 1.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7f445fe6c..5bbecdab1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.2.0", + "version" : "1.2.1", "repository" : { "type" : "git", From 8be9d945d03169056bbf84d702292b5763b015dc Mon Sep 17 00:00:00 2001 From: John Catron Date: Thu, 14 Aug 2014 20:12:20 +0000 Subject: [PATCH 291/556] updated close function for safety --- lib/http-proxy/index.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index a33084f83..070c6db51 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -134,8 +134,16 @@ ProxyServer.prototype.listen = function(port, hostname) { ProxyServer.prototype.close = function(callback) { if (this._server) { - this._server.close(callback); - this._server = null; + // Wrap callback to nullify server after all open connections are closed. + var callback_wrapper = function() { + this._server = null; + + if (callback) { + callback(arguments); + } + }; + + this._server.close(callback_wrapper); } }; From 261742a4295268ef93f45aa0f1e3a04208a2aed3 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 14 Aug 2014 17:16:56 -0400 Subject: [PATCH 292/556] [fix] cleanup and stylize close function --- lib/http-proxy/index.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 0555e5601..94b184994 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -135,18 +135,18 @@ ProxyServer.prototype.listen = function(port, hostname) { }; ProxyServer.prototype.close = function(callback) { + var self = this; if (this._server) { - // Wrap callback to nullify server after all open connections are closed. - var callback_wrapper = function() { - this._server = null; - - if (callback) { - callback(arguments); - } - }; - - this._server.close(callback_wrapper); + this._server.close(done); } + + // Wrap callback to nullify server after all open connections are closed. + function done() { + self._server = null; + if (callback) { + callback.apply(null, arguments); + } + }; }; ProxyServer.prototype.before = function(type, passName, callback) { From 05f0b891a610fb7779f90916fcd9ed750df818b2 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 14 Aug 2014 17:28:00 -0400 Subject: [PATCH 293/556] [dist] Version bump. 1.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5bbecdab1..e30f99f2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.2.1", + "version" : "1.3.0", "repository" : { "type" : "git", From 49a0de1e7cdcec9b555695605ab914038f99d66b Mon Sep 17 00:00:00 2001 From: Joe Esposito Date: Thu, 21 Aug 2014 17:02:30 -0400 Subject: [PATCH 294/556] Clarify usable parameters for proxyRes event. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2ea3d02ab..1c4f75b91 100644 --- a/README.md +++ b/README.md @@ -216,8 +216,8 @@ proxy.on('error', function (err, req, res) { // // 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)); +proxy.on('proxyRes', function (proxyRes, req, res) { + console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2)); }); ``` From 6b83ae47bbf2d5eab8ac94b4d6130e09a21ac85b Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 8 Sep 2014 16:28:51 -0400 Subject: [PATCH 295/556] [ci] remove 0.11.x to avoid failing builds caused by TLS errors --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ba5be4174..c29c96922 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: node_js node_js: - "0.10" - - "0.11" notifications: email: From 511b7b3d4743636de9d9fbe8ff409730d221d273 Mon Sep 17 00:00:00 2001 From: Domi Date: Sat, 31 May 2014 17:35:30 +0800 Subject: [PATCH 296/556] Fix proxy path This fix considers the actual target path again (which has been ignored). --- lib/http-proxy/common.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 5d10647cf..9de052e4b 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -57,10 +57,14 @@ common.setupOutgoing = function(outgoing, options, req, forward) { ) { outgoing.headers.connection = 'close'; } } + + // the final path is target path + relative path requested by user: + outgoing.path = options.target.path; + // // Remark: Can we somehow not use url.parse as a perf optimization? // - outgoing.path = !options.toProxy + outgoing.path += !options.toProxy ? url.parse(req.url).path : req.url; From a65021d52b0ee039486819b5a95f442229458776 Mon Sep 17 00:00:00 2001 From: Sean Massa Date: Mon, 8 Sep 2014 16:23:11 -0500 Subject: [PATCH 297/556] fix tests for maintaining proxy path --- lib/http-proxy/common.js | 12 +++++++++--- test/lib-http-proxy-common-test.js | 25 ++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 9de052e4b..196a890e9 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -1,4 +1,5 @@ var common = exports, + path = require('path'), url = require('url'), extend = require('util')._extend; @@ -57,17 +58,22 @@ common.setupOutgoing = function(outgoing, options, req, forward) { ) { outgoing.headers.connection = 'close'; } } - + // the final path is target path + relative path requested by user: - outgoing.path = options.target.path; + var target = options[forward || 'target']; + var targetPath = target + ? (target.path || '') + : ''; // // Remark: Can we somehow not use url.parse as a perf optimization? // - outgoing.path += !options.toProxy + var outgoingPath = !options.toProxy ? url.parse(req.url).path : req.url; + outgoing.path = path.join(targetPath, outgoingPath); + return outgoing; }; diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index dab2d26ac..86fee3300 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -117,6 +117,29 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.port).to.eql(443); }); + + it('should keep the original target path in the outgoing path', function(){ + var outgoing = {}; + common.setupOutgoing(outgoing, {target: + { path: 'some-path' } + }, { url : 'am' }); + + expect(outgoing.path).to.eql('some-path/am'); + }); + + it('should keep the original forward path in the outgoing path', function(){ + var outgoing = {}; + common.setupOutgoing(outgoing, { + target: {}, + forward: { + path: 'some-path' + } + }, { + url : 'am' + }, 'forward'); + + expect(outgoing.path).to.eql('some-path/am'); + }); }); describe('#setupSocket', function () { @@ -144,4 +167,4 @@ describe('lib/http-proxy/common.js', function () { expect(socketConfig.keepalive).to.eql(true); }); }); -}); \ No newline at end of file +}); From fc73828035baf3cea3664560f8964f2a2a200d0a Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 9 Sep 2014 13:22:17 -0400 Subject: [PATCH 298/556] [dist] Version bump. 1.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e30f99f2b..4a37b2d14 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.3.0", + "version" : "1.3.1", "repository" : { "type" : "git", From 0e64568b4e23cb8b391d5c02a5c3390e77771d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=ADaz?= Date: Thu, 11 Sep 2014 14:21:33 +0300 Subject: [PATCH 299/556] Removed duplicated imported dependencies --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1c4f75b91..49c6c1c84 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ An object will be returned with four values: Is it then possible to proxy requests by calling these functions ```javascript -require('http').createServer(function(req, res) { +http.createServer(function(req, res) { proxy.web(req, res, { target: 'http://mytarget.com:8080' }); }); ``` @@ -105,7 +105,7 @@ var proxy = httpProxy.createProxyServer({}); // 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) { +var server = 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' }); @@ -140,7 +140,7 @@ proxy.on('proxyReq', function(proxyReq, req, res, options) { proxyReq.setHeader('X-Special-Proxy-Header', 'foobar'); }); -var server = require('http').createServer(function(req, res) { +var server = 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, { From 9a534c6ff63d776140918bc839801d247affd18d Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 11 Sep 2014 18:42:47 -0400 Subject: [PATCH 300/556] [api] add prependPath option to go with path change --- lib/http-proxy.js | 1 + lib/http-proxy/common.js | 2 +- lib/http-proxy/index.js | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index bea3fe105..3fa80c8ba 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -38,6 +38,7 @@ module.exports.createProxyServer = * xfwd : * secure : * toProxy: + * prependPath: * localAddress : * } * diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 196a890e9..670a0e343 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -61,7 +61,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { // the final path is target path + relative path requested by user: var target = options[forward || 'target']; - var targetPath = target + var targetPath = target && options.prependPath !== false ? (target.path || '') : ''; diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 94b184994..8767dfb50 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -89,6 +89,9 @@ httpProxy.createRightProxy = createRightProxy; function ProxyServer(options) { EE3.call(this); + options = options || {}; + options.prependPath = options.prependPath === false ? false : true; + this.web = this.proxyRequest = createRightProxy('web')(options); this.ws = this.proxyWebsocketRequest = createRightProxy('ws')(options); this.options = options; From e44fabe58a233b367d42f26f15113e2022f71d7b Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 11 Sep 2014 18:44:28 -0400 Subject: [PATCH 301/556] [test] add test for prependPath option --- test/lib-http-proxy-common-test.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 86fee3300..2ac8a96be 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -20,7 +20,7 @@ describe('lib/http-proxy/common.js', function () { { method : 'i', url : 'am', - headers : {'pro':'xy','overwritten':false} + headers : {'pro':'xy','overwritten':false} }); expect(outgoing.host).to.eql('hey'); @@ -91,7 +91,7 @@ describe('lib/http-proxy/common.js', function () { it('set the port according to the protocol', function () { var outgoing = {}; common.setupOutgoing(outgoing, - { + { agent : '?', target: { host : 'how', @@ -103,7 +103,7 @@ describe('lib/http-proxy/common.js', function () { { method : 'i', url : 'am', - headers : 'proxy' + headers : 'proxy' }); expect(outgoing.host).to.eql('how'); @@ -140,6 +140,16 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('some-path/am'); }); + + it('should not prepend the target path to the outgoing path with prependPath = false', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, { + target: { path: 'hellothere' }, + prependPath: false + }, { url: 'hi' }); + + expect(outgoing.path).to.eql('hi'); + }) }); describe('#setupSocket', function () { From dceef407a1130033679e7e836c6753b76187ce5f Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 11 Sep 2014 18:51:35 -0400 Subject: [PATCH 302/556] [dist] Version bump. 1.4.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4a37b2d14..a927d532b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.3.1", + "version" : "1.4.0", "repository" : { "type" : "git", From d5c656bceb50dc9008ef223bc58b918adcf05352 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 11 Sep 2014 18:52:13 -0400 Subject: [PATCH 303/556] [dist] Version bump. 1.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a927d532b..d953ae7b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.4.0", + "version" : "1.4.1", "repository" : { "type" : "git", From ed73f06ed307ad2204e565781cc3154047941a8c Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Fri, 12 Sep 2014 07:50:16 -0400 Subject: [PATCH 304/556] [fix] ensure path works on windows because path.join doesnt like URLs --- lib/http-proxy/common.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 670a0e343..05ed6e168 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -1,5 +1,4 @@ var common = exports, - path = require('path'), url = require('url'), extend = require('util')._extend; @@ -72,7 +71,9 @@ common.setupOutgoing = function(outgoing, options, req, forward) { ? url.parse(req.url).path : req.url; - outgoing.path = path.join(targetPath, outgoingPath); + outgoing.path = targetPath + ? targetPath + '/' + outgoingPath + : outgoingPath; return outgoing; }; From df12aeb12de79de1157898d45f4347fd0037dd70 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Fri, 12 Sep 2014 07:50:36 -0400 Subject: [PATCH 305/556] [dist] Version bump. 1.4.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d953ae7b3..28a36e2cb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.4.1", + "version" : "1.4.2", "repository" : { "type" : "git", From 73d865bc9f8940f61c1ad4812f220920ead553b5 Mon Sep 17 00:00:00 2001 From: Samuel Reed Date: Fri, 12 Sep 2014 12:52:44 -0400 Subject: [PATCH 306/556] Fix breaking bug on url joining resulting in paths like `///path`. Added OS-agnostic url join helper. --- lib/http-proxy/common.js | 14 ++++++++++---- test/lib-http-proxy-common-test.js | 9 +++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 05ed6e168..abf182cc7 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -71,9 +71,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { ? url.parse(req.url).path : req.url; - outgoing.path = targetPath - ? targetPath + '/' + outgoingPath - : outgoingPath; + outgoing.path = common.urlJoin(targetPath, outgoingPath); return outgoing; }; @@ -109,4 +107,12 @@ common.getPort = function(req) { return res ? res[1] : req.connection.pair ? '443' : '80' ; -} +}; + +// OS-agnostic join (doesn't break on URLs like path.join does on Windows) +common.urlJoin = function() { + var args = Array.prototype.slice.call(arguments); + // Join all strings, but remove empty strings so we don't get extra slashes from + // joining e.g. ['', 'am'] + return args.filter(function(a) { return !!a; }).join('/').replace(/\/+/g, '/'); +}; diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 2ac8a96be..98313ff79 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -150,6 +150,15 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('hi'); }) + + it('should properly join paths', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, { + target: { path: '/forward' }, + }, { url: '/static/path' }); + + expect(outgoing.path).to.eql('/forward/static/path'); + }) }); describe('#setupSocket', function () { From a934cb6a46298c380e9bc794f18873576cf73c4c Mon Sep 17 00:00:00 2001 From: Arnout Kazemier Date: Fri, 12 Sep 2014 19:11:49 +0200 Subject: [PATCH 307/556] [ignore] Ignore npm-debug.log --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 099c4d9df..fdd88f86d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ atest.js notes primus-proxy.js tes.js +npm-debug.log From 3ab6e9591e66c203647605b4f275d374472c9d5f Mon Sep 17 00:00:00 2001 From: Arnout Kazemier Date: Fri, 12 Sep 2014 19:13:53 +0200 Subject: [PATCH 308/556] [minor] Code style adjustment. --- lib/http-proxy.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 3fa80c8ba..ccaaab730 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -4,9 +4,9 @@ var http = require('http'), httpProxy = require('./http-proxy/'); /** - * Export the the proxy "Server" as the main export + * Export the proxy "Server" as the main export. */ -module.exports = httpProxy.Server; +module.exports = httpProxy.Server; /** * Creates the proxy server. From 73e8a4cdd576868bf61d0848cc51f083a75454f9 Mon Sep 17 00:00:00 2001 From: Arnout Kazemier Date: Fri, 12 Sep 2014 19:21:12 +0200 Subject: [PATCH 309/556] [minor] Added missing JSDoc comments --- lib/http-proxy/common.js | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index abf182cc7..d5323968e 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -102,17 +102,36 @@ common.setupSocket = function(socket) { return socket; }; +/** + * Get the port number from the host. Or guess it based on the connection type. + * + * @param {Request} req Incoming HTTP request. + * + * @return {String} The port number. + * + * @api private + */ common.getPort = function(req) { - var res = req.headers.host ? req.headers.host.match(/:(\d+)/) : ""; + var res = req.headers.host ? req.headers.host.match(/:(\d+)/) : ''; + return res ? res[1] : - req.connection.pair ? '443' : '80' ; + req.connection.pair ? '443' : '80'; }; -// OS-agnostic join (doesn't break on URLs like path.join does on Windows) +/** + * OS-agnostic join (doesn't break on URLs like path.join does on Windows)> + * + * @return {String} The generated path. + * + * @api private + */ + common.urlJoin = function() { var args = Array.prototype.slice.call(arguments); - // Join all strings, but remove empty strings so we don't get extra slashes from + // Join all strings, but remove empty strings so we don't get extra slashes from // joining e.g. ['', 'am'] - return args.filter(function(a) { return !!a; }).join('/').replace(/\/+/g, '/'); + return args.filter(function filter(a) { + return !!a; + }).join('/').replace(/\/+/g, '/'); }; From 554f59c5182d58b359df0159a29ff5ea35dd3830 Mon Sep 17 00:00:00 2001 From: cronopio Date: Fri, 12 Sep 2014 12:31:28 -0500 Subject: [PATCH 310/556] Bump version v1.4.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 28a36e2cb..2ec6b9a50 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.4.2", + "version" : "1.4.3", "repository" : { "type" : "git", From 51eeebef683f6f6daca3c8c7640064254788b49c Mon Sep 17 00:00:00 2001 From: MinRK Date: Mon, 1 Sep 2014 21:25:37 -0700 Subject: [PATCH 311/556] handle 'upgrade' in comma-separated connection header Firefox sends `keep-alive, upgrade`, not just `upgrade`, which the proxy incorrectly turned into `close` --- lib/http-proxy/common.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index d5323968e..bcc7b8e87 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -53,7 +53,8 @@ common.setupOutgoing = function(outgoing, options, req, forward) { if (!outgoing.agent) { outgoing.headers = outgoing.headers || {}; if (typeof outgoing.headers.connection !== 'string' - || outgoing.headers.connection.toLowerCase() !== 'upgrade' + || !outgoing.headers.connection.toLowerCase().split(',').some( + function (s) { if (s.trim() === 'upgrade') { return true; } }) ) { outgoing.headers.connection = 'close'; } } From 65a21bce6dbbc6142a851dc959e237c0ef2b1091 Mon Sep 17 00:00:00 2001 From: MinRK Date: Tue, 16 Sep 2014 11:14:56 -0700 Subject: [PATCH 312/556] use regex to check for upgrade header in websocket connections --- lib/http-proxy/common.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index bcc7b8e87..52cb0ff7c 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -53,8 +53,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { if (!outgoing.agent) { outgoing.headers = outgoing.headers || {}; if (typeof outgoing.headers.connection !== 'string' - || !outgoing.headers.connection.toLowerCase().split(',').some( - function (s) { if (s.trim() === 'upgrade') { return true; } }) + || ! /(^|,)\s*upgrade\s*($|,)/i.test(outgoing.headers.connection) ) { outgoing.headers.connection = 'close'; } } From ec683b924b1ef8cbdd2cd2bfb7e141b502773163 Mon Sep 17 00:00:00 2001 From: MinRK Date: Tue, 16 Sep 2014 12:09:26 -0700 Subject: [PATCH 313/556] test new detection of connection: upgrade --- test/lib-http-proxy-common-test.js | 43 ++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 98313ff79..01af2f7ef 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -59,6 +59,49 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.headers.connection).to.eql('upgrade'); }); + it('should not override agentless connection: contains upgrade', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, + { + agent: undefined, + target: { + host : 'hey', + hostname : 'how', + socketPath: 'are', + port : 'you', + }, + headers: {'connection': 'keep-alive, upgrade'}, // this is what Firefox sets + }, + { + method : 'i', + url : 'am', + headers : {'pro':'xy','overwritten':false} + }); + expect(outgoing.headers.connection).to.eql('keep-alive, upgrade'); + }); + + it('should override agentless connection: contains improper upgrade', function () { + // sanity check on upgrade regex + var outgoing = {}; + common.setupOutgoing(outgoing, + { + agent: undefined, + target: { + host : 'hey', + hostname : 'how', + socketPath: 'are', + port : 'you', + }, + headers: {'connection': 'keep-alive, not upgrade'}, + }, + { + method : 'i', + url : 'am', + headers : {'pro':'xy','overwritten':false} + }); + expect(outgoing.headers.connection).to.eql('close'); + }); + it('should override agentless non-upgrade header to close', function () { var outgoing = {}; common.setupOutgoing(outgoing, From 45cf95a82e27939e4ed1be69df98b10ecd59bb3a Mon Sep 17 00:00:00 2001 From: Stephen Hebson Date: Tue, 16 Sep 2014 14:55:12 -0700 Subject: [PATCH 314/556] Fix typo in README.md "Is it then possible" -> "It is then possible" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49c6c1c84..6813e6db6 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ An object will be returned with four values: * listen `port` (a function that wraps the object in a webserver, for your convenience) * close `[callback]` (a function that closes the inner webserver and stops listening on given port) -Is it then possible to proxy requests by calling these functions +It is then possible to proxy requests by calling these functions ```javascript http.createServer(function(req, res) { From c0a796b3e31de4f22eef00d93164e7238d9aa3ba Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 17 Sep 2014 07:53:18 -0400 Subject: [PATCH 315/556] [fix] perf optimization so we have a precompiled regexp --- lib/http-proxy/common.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 52cb0ff7c..7c374b0c8 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -2,6 +2,7 @@ var common = exports, url = require('url'), extend = require('util')._extend; +var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i; /** * Copies the right headers from `options` and `req` to * `outgoing` which is then used to fire the proxied @@ -53,7 +54,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { if (!outgoing.agent) { outgoing.headers = outgoing.headers || {}; if (typeof outgoing.headers.connection !== 'string' - || ! /(^|,)\s*upgrade\s*($|,)/i.test(outgoing.headers.connection) + || ! upgradeHeader.test(outgoing.headers.connection) ) { outgoing.headers.connection = 'close'; } } From e7d50b1a376035a50c82db38605e99feb30afd36 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 25 Sep 2014 22:11:12 -0400 Subject: [PATCH 316/556] [minor] extra space --- lib/http-proxy/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 7c374b0c8..693198af3 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -54,7 +54,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { if (!outgoing.agent) { outgoing.headers = outgoing.headers || {}; if (typeof outgoing.headers.connection !== 'string' - || ! upgradeHeader.test(outgoing.headers.connection) + || !upgradeHeader.test(outgoing.headers.connection) ) { outgoing.headers.connection = 'close'; } } From a4ca578b442781cc2116be60f516af2624da293c Mon Sep 17 00:00:00 2001 From: Jimb Esser Date: Thu, 25 Sep 2014 20:54:46 -0700 Subject: [PATCH 317/556] Fixed misleading documentation options.xfwd definitely works fine without using the .listen method, and, AFAICT, .toProxy should as well. Only .ssl and .ws are referenced in .listen. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6813e6db6..a147a37cf 100644 --- a/README.md +++ b/README.md @@ -315,13 +315,13 @@ proxyServer.listen(8015); * **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 + * **xfwd**: true/false, adds x-forward headers + * **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies) 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 - * **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies) ### Shutdown From 000eb533de144cad01cfd97edf9ab6c350593d3c Mon Sep 17 00:00:00 2001 From: Thorsten Lorenz Date: Sun, 28 Sep 2014 22:26:39 -0400 Subject: [PATCH 318/556] emitting proxySocket on proxyServer - emitted once proxySocket was created and socket was piped into it - needed to support sniffing messages coming from proxy target --- README.md | 8 ++++++++ lib/http-proxy/passes/ws-incoming.js | 1 + 2 files changed, 9 insertions(+) diff --git a/README.md b/README.md index a147a37cf..1943f3f30 100644 --- a/README.md +++ b/README.md @@ -190,6 +190,7 @@ http.createServer(function (req, res) { * `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. +* `proxySocket`: This event is emitted once the proxy websocket was created and piped into the target websocket. ```js var httpProxy = require('http-proxy'); @@ -220,6 +221,13 @@ proxy.on('proxyRes', function (proxyRes, req, res) { console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2)); }); +// +// Listen for the `proxySocket` event on `proxy`. +// +proxy.on('proxySocket', function (proxySocket) { + // listen for messages coming FROM the target here + proxySocket.on('data', hybiParseAndLogMessage); +}); ``` #### Using HTTPS diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 7673fe067..8c05e32e8 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -108,6 +108,7 @@ var passes = exports; return i + ": " + proxyRes.headers[i]; }).join('\r\n') + '\r\n\r\n'); proxySocket.pipe(socket).pipe(proxySocket); + server.emit('proxySocket', proxySocket); }); return proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT From 232258b6ec2229497fe557454a121d917968f5e8 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 29 Sep 2014 22:38:47 -0400 Subject: [PATCH 319/556] [dist] Version bump. 1.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2ec6b9a50..3bb2be37f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.4.3", + "version" : "1.5.0", "repository" : { "type" : "git", From 10a294af4d4baac30b98ea9bec683a974443b83d Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 30 Sep 2014 15:22:52 -0400 Subject: [PATCH 320/556] [fix] do a check to make sure the server exists before we try and emit --- lib/http-proxy/passes/ws-incoming.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 8c05e32e8..1bc786980 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -108,7 +108,8 @@ var passes = exports; return i + ": " + proxyRes.headers[i]; }).join('\r\n') + '\r\n\r\n'); proxySocket.pipe(socket).pipe(proxySocket); - server.emit('proxySocket', proxySocket); + // Make sure server exists before we try to emit + server && server.emit('proxySocket', proxySocket); }); return proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT From f0bf7418156db2cb87a616b0a34bb1f028db9142 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 30 Sep 2014 15:23:02 -0400 Subject: [PATCH 321/556] [dist] Version bump. 1.5.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3bb2be37f..85e02a200 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.5.0", + "version" : "1.5.1", "repository" : { "type" : "git", From 77305489d9b88d283802477e155340e5dacfcc2c Mon Sep 17 00:00:00 2001 From: MinRK Date: Tue, 30 Sep 2014 16:11:49 -0700 Subject: [PATCH 322/556] test closing upstream socket prior to upgrade should close the client socket with ECONNRESET, but currently is left hanging. --- test/lib-http-proxy-test.js | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index e0b4eca92..1110d29f1 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -281,6 +281,11 @@ describe('lib/http-proxy.js', function() { client.send('hello there'); }); + client.on('error', function (err) { + expect(err).to.be.an(Error); + expect(err.code).to.be('ECONNRESET'); + }); + proxy.on('error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNREFUSED'); @@ -289,6 +294,41 @@ describe('lib/http-proxy.js', function() { }); }); + it('should close client socket if upstream is closed before upgrade', function (done) { + var ports = { source: gen.port, proxy: gen.port }; + var server = http.createServer(); + server.on('upgrade', function (req, socket, head) { + var response = [ + 'HTTP/1.1 404 Not Found', + 'Content-type: text/html', + '', + '' + ]; + socket.write(response.join('\r\n')); + socket.end(); + }); + server.listen(ports.source); + + 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'); + }); + + client.on('error', function (err) { + expect(err).to.be.an(Error); + expect(err.code).to.be('ECONNRESET'); + proxyServer.close(); + done(); + }); + }); + it('should proxy a socket.io stream', function (done) { var ports = { source: gen.port, proxy: gen.port }; var proxy = httpProxy.createProxyServer({ From bcd8a564a802512c90df20353ca341a1d8c84501 Mon Sep 17 00:00:00 2001 From: MinRK Date: Tue, 30 Sep 2014 16:13:17 -0700 Subject: [PATCH 323/556] close websocket if proxyReq is closed before upgrade avoids leaving client sockets open when upstream connections are rejected. --- lib/http-proxy/passes/ws-incoming.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 1bc786980..9d3970366 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -89,6 +89,10 @@ var passes = exports; ); // Error Handler proxyReq.on('error', onOutgoingError); + proxyReq.on('response', function (res) { + // if upgrade event isn't going to happen, close the socket + if (!res.upgrade) socket.end(); + }); proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { proxySocket.on('error', onOutgoingError); From 43c6f0c7c06d25a670c410500a8623531df458b1 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 30 Sep 2014 21:21:04 -0400 Subject: [PATCH 324/556] [dist] Version bump. 1.5.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 85e02a200..9217c8bae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.5.1", + "version" : "1.5.2", "repository" : { "type" : "git", From c62766391e54069c7cf82f0135536aeabad7cd90 Mon Sep 17 00:00:00 2001 From: MinRK Date: Tue, 30 Sep 2014 19:55:54 -0700 Subject: [PATCH 325/556] close socket if upstream request fails adds socket.end() to on('error') handlers for proxyReq and proxySocket --- lib/http-proxy/passes/ws-incoming.js | 1 + test/lib-http-proxy-test.js | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 9d3970366..c8a5f207a 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -124,6 +124,7 @@ var passes = exports; } else { server.emit('error', err, req, socket); } + socket.end(); } } diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 1110d29f1..830ccae6e 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -280,17 +280,24 @@ describe('lib/http-proxy.js', function() { client.on('open', function () { client.send('hello there'); }); + + var count = 0; + function maybe_done () { + count += 1; + if (count === 2) done(); + } client.on('error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNRESET'); + maybe_done(); }); proxy.on('error', function (err) { expect(err).to.be.an(Error); expect(err.code).to.be('ECONNREFUSED'); proxyServer.close(); - done(); + maybe_done(); }); }); From 9577a0faf2b78af606168673407ac47a851c084c Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 1 Oct 2014 07:10:51 -0400 Subject: [PATCH 326/556] [dist] Version bump. 1.5.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9217c8bae..408a2f78f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.5.2", + "version" : "1.5.3", "repository" : { "type" : "git", From 04c45a022ca880bdfc2be3e05359331ef3558f99 Mon Sep 17 00:00:00 2001 From: dan <464033315@qq.com> Date: Thu, 9 Oct 2014 14:30:11 +0800 Subject: [PATCH 327/556] update modify request body eg --- examples/middleware/bodyDecoder-middleware.js | 128 +++++++----------- 1 file changed, 52 insertions(+), 76 deletions(-) diff --git a/examples/middleware/bodyDecoder-middleware.js b/examples/middleware/bodyDecoder-middleware.js index 555c3d154..01511fc72 100644 --- a/examples/middleware/bodyDecoder-middleware.js +++ b/examples/middleware/bodyDecoder-middleware.js @@ -29,91 +29,67 @@ var http = require('http'), request = require('request'), colors = require('colors'), util = require('util'), - Store = require('../helpers/store'), + bodyParser = require('body-parser'), 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); +//restreame +var restreamer = function (){ + return function (req, res, next) { //restreame + req.removeAllListeners('data') + req.removeAllListeners('end') + next() + process.nextTick(function () { + rawBody = new Buffer(req.body) + console.log('dsfgsdgsdgsdrtwergtsdgf', JSON.stringify(req.body).length) + if(req.body) { + req.emit('data', JSON.stringify(req.body)) + } + req.emit('end') + }) + } +} - //greetings -> 7531, insults-> 2600 - // now, start a proxy server. +// +// Basic Http Proxy Server +// +var app = connect() + .use(bodyParser.json())//json + .use(restreamer())//restreame + .use(function(req, res){ + // modify body here, + // eg: req.body = {a: 1}. + console.log('proxy body:',req.body) + proxy.web(req, res, { + target: 'http://127.0.0.1:9013' + }) + }); - //don't worry about incoming contont type - //bodyParser.parse[''] = JSON.parse +http.createServer(app).listen(8013, function(){ + console.log('proxy linsten 8013'); +}); - 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 +// +// Target Http Server +// +var app1 = connect() + .use(bodyParser.json()) + .use(function(req, res){ + console.log('app1:',req.body) + res.end('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2)); + }); +http.createServer(app1).listen(9013, function(){ + //request to 8013 to proxy + request.post({// + url: 'http://127.0.0.1:8013', + json: {content: 123, type: "greeting"} + },function(err, res,data){ + console.log('return:' ,err, data) + }) +}); - //curl localhost:7531 - //["/hello","/g%27day","/kiora","/houdy"] - }) - }) -}); \ No newline at end of file From 0378b03e5301afb7d0249bf75ae06afacf09bbb8 Mon Sep 17 00:00:00 2001 From: dan <464033315@qq.com> Date: Thu, 9 Oct 2014 14:32:52 +0800 Subject: [PATCH 328/556] update modify request body eg --- examples/middleware/bodyDecoder-middleware.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/middleware/bodyDecoder-middleware.js b/examples/middleware/bodyDecoder-middleware.js index 01511fc72..80e3dfb87 100644 --- a/examples/middleware/bodyDecoder-middleware.js +++ b/examples/middleware/bodyDecoder-middleware.js @@ -42,7 +42,6 @@ var restreamer = function (){ next() process.nextTick(function () { rawBody = new Buffer(req.body) - console.log('dsfgsdgsdgsdrtwergtsdgf', JSON.stringify(req.body).length) if(req.body) { req.emit('data', JSON.stringify(req.body)) } From d46e876e273f7b11ca092d519ec5d0e82839638d Mon Sep 17 00:00:00 2001 From: dan <464033315@qq.com> Date: Thu, 9 Oct 2014 14:33:04 +0800 Subject: [PATCH 329/556] update modify request body eg --- examples/middleware/bodyDecoder-middleware.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/middleware/bodyDecoder-middleware.js b/examples/middleware/bodyDecoder-middleware.js index 80e3dfb87..00c97f909 100644 --- a/examples/middleware/bodyDecoder-middleware.js +++ b/examples/middleware/bodyDecoder-middleware.js @@ -41,7 +41,6 @@ var restreamer = function (){ req.removeAllListeners('end') next() process.nextTick(function () { - rawBody = new Buffer(req.body) if(req.body) { req.emit('data', JSON.stringify(req.body)) } From 9f684d0439174d889d7b9a4ef6e2353e09481b2d Mon Sep 17 00:00:00 2001 From: no9 Date: Wed, 15 Oct 2014 01:52:27 +0100 Subject: [PATCH 330/556] harmon notes --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 1943f3f30..ea204537a 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,11 @@ var server = http.createServer(function(req, res) { console.log("listening on port 5050") server.listen(5050); ``` +#### Modify a response from a proxied server +Sometimes when you have recieved a HTML/XML document from the server of origin you would like to modify it before forwarding it on. + +[Harmon](https://github.com/No9/harmon) allows you to do this in a streaming style so as to keep the pressure on the proxy to a minimum. + #### Setup a stand-alone proxy server with proxy request header re-writing This example shows how you can proxy a request using your own HTTP server that From f64954a08b0aec07e7130b0083dd7063dae389b6 Mon Sep 17 00:00:00 2001 From: Wade Dorrell Date: Tue, 14 Oct 2014 22:49:33 -0600 Subject: [PATCH 331/556] I presume you mean couchdb here --- examples/helpers/store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/helpers/store.js b/examples/helpers/store.js index e2860573f..09a4f6cd1 100644 --- a/examples/helpers/store.js +++ b/examples/helpers/store.js @@ -2,7 +2,7 @@ // // 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) +// (see couchdb for a grown-up version of this) // // API: // GET / From 796ab0bcc56a574d2cf21d77044f4f647918103d Mon Sep 17 00:00:00 2001 From: Alex Oshchepkov Date: Wed, 29 Oct 2014 07:25:19 +0500 Subject: [PATCH 332/556] Added changeOrigin option with test and docs --- lib/http-proxy.js | 1 + lib/http-proxy/common.js | 4 +++ ...lib-http-proxy-passes-web-incoming-test.js | 26 +++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index ccaaab730..c14d1a2d0 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -40,6 +40,7 @@ module.exports.createProxyServer = * toProxy: * prependPath: * localAddress : + * changeOrigin: true/false, Default: false - changes the origin of the host header to the target URL> * } * * NOTE: `options.ws` and `options.ssl` are optional. diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 693198af3..4d5b5f136 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -74,6 +74,10 @@ common.setupOutgoing = function(outgoing, options, req, forward) { outgoing.path = common.urlJoin(targetPath, outgoingPath); + if (options.changeOrigin) { + outgoing.headers.host = outgoing.host; + } + return outgoing; }; diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 2bd86d87b..f70001035 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -264,4 +264,30 @@ describe('#createProxyServer.web() using own http server', function () { source.listen('8080'); http.request('http://127.0.0.1:8086', function() {}).end(); }); + + it('should proxy the request and handle changeOrigin option', function (done) { + var proxy = httpProxy.createProxyServer({ + target: 'http://127.0.0.1:8080', + changeOrigin: true + }); + + 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('8080'); + done(); + }); + + proxyServer.listen('8081'); + source.listen('8080'); + + http.request('http://127.0.0.1:8081', function() {}).end(); + }); }); \ No newline at end of file From 43641b00b34ccc05bdf09f904695061d7c857aeb Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 28 Oct 2014 22:53:54 -0400 Subject: [PATCH 333/556] [dist] Version bump. 1.6.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 408a2f78f..8df5ab8ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.5.3", + "version" : "1.6.0", "repository" : { "type" : "git", From 1af8224cc149acbd309f51c587de81d6c99576a4 Mon Sep 17 00:00:00 2001 From: Alex Oshchepkov Date: Wed, 29 Oct 2014 08:09:43 +0500 Subject: [PATCH 334/556] changeOrigin option docs fix --- lib/http-proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index c14d1a2d0..9a7f81ba7 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -40,7 +40,7 @@ module.exports.createProxyServer = * toProxy: * prependPath: * localAddress : - * changeOrigin: true/false, Default: false - changes the origin of the host header to the target URL> + * changeOrigin: * } * * NOTE: `options.ws` and `options.ssl` are optional. From d1eabccf931ec79bdafc60d97f89250fea2323af Mon Sep 17 00:00:00 2001 From: Ming Liu Date: Tue, 4 Nov 2014 14:51:34 -0800 Subject: [PATCH 335/556] websocket needs to respect `options.secure` too --- lib/http-proxy/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 4d5b5f136..eda6b17e1 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -39,7 +39,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { extend(outgoing.headers, options.headers); } - if (options[forward || 'target'].protocol == 'https:') { + if (~['https:', 'wss:'].indexOf(options[forward || 'target'].protocol)) { outgoing.rejectUnauthorized = (typeof options.secure === "undefined") ? true : options.secure; } From fa797fca900c10ebc848a2b445204b47da799483 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 4 Nov 2014 18:14:09 -0500 Subject: [PATCH 336/556] [dist] Version bump. 1.6.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8df5ab8ef..6b5f5103e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.6.0", + "version" : "1.6.1", "repository" : { "type" : "git", From 4a2b870cc92300e9c12865081a5272a4c02c3d47 Mon Sep 17 00:00:00 2001 From: Ricky Miller Date: Sun, 9 Nov 2014 08:44:22 +0900 Subject: [PATCH 337/556] do not modify the query string --- lib/http-proxy/common.js | 23 +++++++++++++++++++---- test/lib-http-proxy-common-test.js | 9 +++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index eda6b17e1..9dd30822a 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -77,7 +77,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { if (options.changeOrigin) { outgoing.headers.host = outgoing.host; } - + return outgoing; }; @@ -134,9 +134,24 @@ common.getPort = function(req) { common.urlJoin = function() { var args = Array.prototype.slice.call(arguments); + + // We do not want to mess with the query string. All we want to touch is the path. + var lastIndex = args.length-1; + var last = args[lastIndex] + var lastSegs = last.split('?') + args[lastIndex] = lastSegs[0] + // Join all strings, but remove empty strings so we don't get extra slashes from // joining e.g. ['', 'am'] - return args.filter(function filter(a) { - return !!a; - }).join('/').replace(/\/+/g, '/'); + var retSegs = [ + args.filter(function filter(a) { + return !!a; + }).join('/').replace(/\/+/g, '/') + ]; + + // Only join the query string if it exists so we don't have trailing a '?' + // on every request + lastSegs[1] && retSegs.push(lastSegs[1]); + + return retSegs.join('?') }; diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 01af2f7ef..b74fd021f 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -202,6 +202,15 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('/forward/static/path'); }) + + it('should not modify the query string', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, { + target: { path: '/forward' }, + }, { url: '/?foo=bar//&target=http://foobar.com/' }); + + expect(outgoing.path).to.eql('/forward/?foo=bar//&target=http://foobar.com/'); + }) }); describe('#setupSocket', function () { From 7c5e40a429fbc0c538f38d29d74acb633cb9b8d4 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 10 Nov 2014 23:01:21 -0500 Subject: [PATCH 338/556] [fix] style changes --- lib/http-proxy/common.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 9dd30822a..bc6efd9d4 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -133,17 +133,21 @@ common.getPort = function(req) { */ common.urlJoin = function() { - var args = Array.prototype.slice.call(arguments); - - // We do not want to mess with the query string. All we want to touch is the path. - var lastIndex = args.length-1; - var last = args[lastIndex] - var lastSegs = last.split('?') - args[lastIndex] = lastSegs[0] + // + // We do not want to mess with the query string. All we want to touch is the path. + // + var args = Array.prototype.slice.call(arguments), + lastIndex = args.length - 1, + last = args[lastIndex], + lastSegs = last.split('?'), + args[lastIndex] = lastSegs[0], + retSegs; + // // Join all strings, but remove empty strings so we don't get extra slashes from // joining e.g. ['', 'am'] - var retSegs = [ + // + retSegs = [ args.filter(function filter(a) { return !!a; }).join('/').replace(/\/+/g, '/') From 3f19e6e178e168a16beee74186691f3e0e54d517 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 11 Nov 2014 11:47:15 -0500 Subject: [PATCH 339/556] [minor] this shouldnt be in var block --- lib/http-proxy/common.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index bc6efd9d4..43919b1b5 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -140,8 +140,9 @@ common.urlJoin = function() { lastIndex = args.length - 1, last = args[lastIndex], lastSegs = last.split('?'), - args[lastIndex] = lastSegs[0], retSegs; + + args[lastIndex] = lastSegs[0]; // // Join all strings, but remove empty strings so we don't get extra slashes from From 709b3e96560d619fab2617f9ddb902b4982b4103 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 11 Nov 2014 11:47:43 -0500 Subject: [PATCH 340/556] [dist] Version bump. 1.6.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6b5f5103e..a28d1881e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.6.1", + "version" : "1.6.2", "repository" : { "type" : "git", From 9ba8311343fd01b32505b8607ecf4294200f9dde Mon Sep 17 00:00:00 2001 From: jleal52 Date: Wed, 12 Nov 2014 14:41:46 +0000 Subject: [PATCH 341/556] Updated to support error callback on proxy.web and start/proxyReq/end continue working. --- lib/http-proxy/index.js | 2 +- lib/http-proxy/passes/web-incoming.js | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 8767dfb50..ba04e0dde 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -77,7 +77,7 @@ function createRightProxy(type) { * 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 + if(passes[i](req, res, options, head, this, cbl)) { // passes can return a truthy value to halt the loop break; } } diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index c7805a4b0..572c11a8c 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -92,9 +92,7 @@ web_o = Object.keys(web_o).map(function(pass) { function stream(req, res, options, _, server, clb) { // And we begin! - if (!clb) { - server.emit('start', req, res, options.target) - } + server.emit('start', req, res, options.target) if(options.forward) { // If forward enable, so just pipe the request var forwardReq = (options.forward.protocol === 'https:' ? https : http).request( @@ -151,9 +149,7 @@ web_o = Object.keys(web_o).map(function(pass) { // Allow us to listen when the proxy has completed proxyRes.on('end', function () { - if (!clb) { server.emit('end', req, res, proxyRes); - } }) proxyRes.pipe(res); From daa2ce0ee300df72ca34b720ad3a15d9dfbbffc8 Mon Sep 17 00:00:00 2001 From: Ricky Miller Date: Thu, 13 Nov 2014 04:37:45 +0900 Subject: [PATCH 342/556] copy headers instead of referencing them so they don't unexpectedly get overwritten --- lib/http-proxy/common.js | 7 +++---- test/lib-http-proxy-common-test.js | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 43919b1b5..06856f2ef 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -31,9 +31,8 @@ common.setupOutgoing = function(outgoing, options, req, forward) { function(e) { outgoing[e] = options[forward || 'target'][e]; } ); - ['method', 'headers'].forEach( - function(e) { outgoing[e] = req[e]; } - ); + outgoing.method = req.method + outgoing.headers = extend({},req.headers) if (options.headers){ extend(outgoing.headers, options.headers); @@ -141,7 +140,7 @@ common.urlJoin = function() { last = args[lastIndex], lastSegs = last.split('?'), retSegs; - + args[lastIndex] = lastSegs[0]; // diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index b74fd021f..c4edaf63a 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -146,7 +146,7 @@ describe('lib/http-proxy/common.js', function () { { method : 'i', url : 'am', - headers : 'proxy' + headers : {pro:'xy'} }); expect(outgoing.host).to.eql('how'); @@ -156,7 +156,7 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.method).to.eql('i'); expect(outgoing.path).to.eql('am'); - expect(outgoing.headers).to.eql('proxy') + expect(outgoing.headers.pro).to.eql('xy') expect(outgoing.port).to.eql(443); }); From 84036e9ddd1d4d925006c5438b3bcc0f17ba7a48 Mon Sep 17 00:00:00 2001 From: Ricky Miller Date: Thu, 13 Nov 2014 06:05:32 +0900 Subject: [PATCH 343/556] style changes --- lib/http-proxy/common.js | 4 ++-- test/lib-http-proxy-common-test.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 06856f2ef..a6aca80b0 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -31,8 +31,8 @@ common.setupOutgoing = function(outgoing, options, req, forward) { function(e) { outgoing[e] = options[forward || 'target'][e]; } ); - outgoing.method = req.method - outgoing.headers = extend({},req.headers) + outgoing.method = req.method; + outgoing.headers = extend({}, req.headers); if (options.headers){ extend(outgoing.headers, options.headers); diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index c4edaf63a..149c4226b 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -156,7 +156,7 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.method).to.eql('i'); expect(outgoing.path).to.eql('am'); - expect(outgoing.headers.pro).to.eql('xy') + expect(outgoing.headers.pro).to.eql('xy'); expect(outgoing.port).to.eql(443); }); From daf66a7a8828ae49b5ca28fbf6a8ef8d7a5ee4b4 Mon Sep 17 00:00:00 2001 From: Sam Saccone Date: Fri, 21 Nov 2014 00:19:11 -0500 Subject: [PATCH 344/556] Allow optional redirect host rewriting. --- lib/http-proxy/passes/web-incoming.js | 2 +- lib/http-proxy/passes/web-outgoing.js | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 572c11a8c..e8e84191b 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -144,7 +144,7 @@ web_o = Object.keys(web_o).map(function(pass) { proxyReq.on('response', function(proxyRes) { if(server) { server.emit('proxyRes', proxyRes, req, res); } for(var i=0; i < web_o.length; i++) { - if(web_o[i](req, res, proxyRes)) { break; } + if(web_o[i](req, res, proxyRes, options)) { break; } } // Allow us to listen when the proxy has completed diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 9281c4a45..52e6c828e 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -1,5 +1,6 @@ -var passes = exports; - +var url = require('url') +var passes = exports; +var redirectRegex = /^30(1|2|7|8)$/; /*! * Array of passes. * @@ -43,6 +44,13 @@ var passes = exports; } }, + function setRedirectHostRewrite(req, res, proxyRes, options) { + if (options.hostRewrite && redirectRegex.test(proxyRes.statusCode)) { + var u = url.parse(proxyRes.headers['location']); + u.host = options.hostRewrite; + proxyRes.headers['location'] = u.format(); + } + }, /** * Copy headers from proxyResponse to response * set each header in response object. From add81338a90dae132f9e74fd5a5905fbcef030b7 Mon Sep 17 00:00:00 2001 From: Sam Saccone Date: Sun, 23 Nov 2014 13:34:20 -0500 Subject: [PATCH 345/556] :pencil: Add host rewrite docs and specs. --- README.md | 1 + lib/http-proxy.js | 1 + ...lib-http-proxy-passes-web-outgoing-test.js | 52 +++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/README.md b/README.md index 1943f3f30..45d6e0ca8 100644 --- a/README.md +++ b/README.md @@ -325,6 +325,7 @@ proxyServer.listen(8015); * **secure**: true/false, if you want to verify the SSL Certs * **xfwd**: true/false, adds x-forward headers * **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies) + * **hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects. If you are using the `proxyServer.listen` method, the following options are also applicable: diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 9a7f81ba7..b1ad646f4 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -41,6 +41,7 @@ module.exports.createProxyServer = * prependPath: * localAddress : * changeOrigin: + * hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null. * } * * NOTE: `options.ws` and `options.ssl` are optional. diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index 0ae0bda6f..ee1077e03 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -2,6 +2,58 @@ var httpProxy = require('../lib/http-proxy/passes/web-outgoing'), expect = require('expect.js'); describe('lib/http-proxy/passes/web-outgoing.js', function () { + describe('#setRedirectHostRewrite', function () { + context('rewrites location host to option', function() { + beforeEach(function() { + this.proxyRes = { + statusCode: 301, + headers: { + location: "http://f.com/" + } + }; + + this.options = { + hostRewrite: "x.com" + }; + }); + + it('on 301', function() { + this.proxyRes.statusCode = 301; + httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + }); + + it('on 302', function() { + this.proxyRes.statusCode = 302; + httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + }); + + it('on 307', function() { + this.proxyRes.statusCode = 307; + httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + }); + + it('on 308', function() { + this.proxyRes.statusCode = 308; + httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + }); + + it('not on 200', function() { + this.proxyRes.statusCode = 200; + httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + }); + + it('not when hostRewrite is unset', function() { + httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, {}); + expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + }); + }); + }); + describe('#setConnection', function () { it('set the right connection with 1.0 - `close`', function() { var proxyRes = { headers: {} }; From 8a24a1e18f384d29a125eda1d2311bdd8ec66871 Mon Sep 17 00:00:00 2001 From: Mike Pennisi Date: Mon, 24 Nov 2014 17:14:48 -0500 Subject: [PATCH 346/556] Set `Content-Length` header for OPTIONS requests Web browsers automatically issue an OPTIONS request in advance of other HTTP requests when the document's domain does not match the target in order to facilitate Cross-Origin Resource Sharing. These requests are forbidden from specifying a body and typically do not specify an (unecessary) `Length` header. Node.js automatically adds the `Content-Encoding: chunked` header value to requests that do not specify a `Length` header. This makes proxied OPTIONS requests from web browsers invalid. Explicitly set the `Content-Length` header of all `OPTIONS` requests to "0", disabling the default "chunked" encoding behavior [2]. [1] http://www.w3.org/TR/cors/ [2] http://nodejs.org/api/http.html --- lib/http-proxy/passes/web-incoming.js | 3 ++- test/lib-http-proxy-passes-web-incoming-test.js | 13 +++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 572c11a8c..369171eb4 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -29,7 +29,8 @@ web_o = Object.keys(web_o).map(function(pass) { */ function deleteLength(req, res, options) { - if(req.method === 'DELETE' && !req.headers['content-length']) { + if((req.method === 'DELETE' || req.method === 'OPTIONS') + && !req.headers['content-length']) { req.headers['content-length'] = '0'; } }, diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index f70001035..f2c6f1304 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -5,14 +5,23 @@ var webPasses = require('../lib/http-proxy/passes/web-incoming'), describe('lib/http-proxy/passes/web.js', function() { describe('#deleteLength', function() { - it('should change `content-length`', function() { + it('should change `content-length` for DELETE requests', function() { var stubRequest = { method: 'DELETE', headers: {} }; webPasses.deleteLength(stubRequest, {}, {}); expect(stubRequest.headers['content-length']).to.eql('0'); - }) + }); + + it('should change `content-length` for OPTIONS requests', function() { + var stubRequest = { + method: 'OPTIONS', + headers: {} + }; + webPasses.deleteLength(stubRequest, {}, {}); + expect(stubRequest.headers['content-length']).to.eql('0'); + }); }); describe('#timeout', function() { From 48ae5d828c23d6f19c9e2dd8c922d88a09f5ed0f Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 25 Nov 2014 17:21:24 -0500 Subject: [PATCH 347/556] [minor] style consistency --- lib/http-proxy/passes/web-outgoing.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 52e6c828e..27b794064 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -1,6 +1,8 @@ -var url = require('url') -var passes = exports; +var url = require('url'), + passes = exports; + var redirectRegex = /^30(1|2|7|8)$/; + /*! * Array of passes. * @@ -21,7 +23,7 @@ var redirectRegex = /^30(1|2|7|8)$/; * @api private */ function removeChunked(req, res, proxyRes) { - if(req.httpVersion === '1.0') { + if (req.httpVersion === '1.0') { delete proxyRes.headers['transfer-encoding']; } }, From 8d68ac0e0fa3080b31580aa08e92a46cc1f27696 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 25 Nov 2014 17:22:23 -0500 Subject: [PATCH 348/556] [fix] be defensive and ensure location is in headers before running url.parse() --- lib/http-proxy/passes/web-outgoing.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 27b794064..67a1a6d98 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -47,7 +47,9 @@ var redirectRegex = /^30(1|2|7|8)$/; }, function setRedirectHostRewrite(req, res, proxyRes, options) { - if (options.hostRewrite && redirectRegex.test(proxyRes.statusCode)) { + if (options.hostRewrite + && proxyRes.headers['location'] + && redirectRegex.test(proxyRes.statusCode)) { var u = url.parse(proxyRes.headers['location']); u.host = options.hostRewrite; proxyRes.headers['location'] = u.format(); From 276f65a3b810ded01757ec4bfd4fe2b00a1e66a8 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 25 Nov 2014 17:31:28 -0500 Subject: [PATCH 349/556] [dist] Version bump. 1.7.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a28d1881e..260e34818 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.6.2", + "version" : "1.7.0", "repository" : { "type" : "git", From 70ed1c4273bc64500e8bae9b60d7fd6a19135246 Mon Sep 17 00:00:00 2001 From: koolc Date: Tue, 25 Nov 2014 17:50:36 +0800 Subject: [PATCH 350/556] [Bugfix] Allow for multiple ? in outgoing urls. Without this fix urls that had multiple ? in them would drop sections of the url since before there was an assumption of there only being one. --- lib/http-proxy/common.js | 6 ++++-- test/lib-http-proxy-common-test.js | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index a6aca80b0..a4ce19df2 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -141,7 +141,7 @@ common.urlJoin = function() { lastSegs = last.split('?'), retSegs; - args[lastIndex] = lastSegs[0]; + args[lastIndex] = lastSegs.shift(); // // Join all strings, but remove empty strings so we don't get extra slashes from @@ -155,7 +155,9 @@ common.urlJoin = function() { // Only join the query string if it exists so we don't have trailing a '?' // on every request - lastSegs[1] && retSegs.push(lastSegs[1]); + + // Handle case where there could be multiple ? in the URL. + retSegs.concat(lastSegs); return retSegs.join('?') }; diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 149c4226b..ef202ce23 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -203,13 +203,13 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('/forward/static/path'); }) - it('should not modify the query string', function () { + it.only('should not modify the query string', function () { var outgoing = {}; common.setupOutgoing(outgoing, { target: { path: '/forward' }, - }, { url: '/?foo=bar//&target=http://foobar.com/' }); + }, { url: '/?foo=bar//&target=http://foobar.com/?a=1%26b=2&other=2' }); - expect(outgoing.path).to.eql('/forward/?foo=bar//&target=http://foobar.com/'); + expect(outgoing.path).to.eql('/forward/?foo=bar//&target=http://foobar.com/?a=1%26b=2&other=2'); }) }); From d98d9516ea1b7c8f54390b3bfaee4e3c5dfb7098 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 2 Dec 2014 09:57:49 -0700 Subject: [PATCH 351/556] [fix] simple fixes #748 #744 #746 --- lib/http-proxy/common.js | 2 +- test/lib-http-proxy-common-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index a4ce19df2..6aee0bdc1 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -157,7 +157,7 @@ common.urlJoin = function() { // on every request // Handle case where there could be multiple ? in the URL. - retSegs.concat(lastSegs); + retSegs.push.apply(retSegs, lastSegs); return retSegs.join('?') }; diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index ef202ce23..342c0289b 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -203,7 +203,7 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('/forward/static/path'); }) - it.only('should not modify the query string', function () { + it('should not modify the query string', function () { var outgoing = {}; common.setupOutgoing(outgoing, { target: { path: '/forward' }, From 410a8ce94ccea566a8e50daf3b78e633b82875cb Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 2 Dec 2014 10:25:30 -0700 Subject: [PATCH 352/556] [test] add proper failing test case for #738 --- test/lib-http-proxy-common-test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 342c0289b..7cb5e1481 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -1,4 +1,5 @@ var common = require('../lib/http-proxy/common'), + url = require('url'), expect = require('expect.js'); describe('lib/http-proxy/common.js', function () { @@ -211,6 +212,20 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('/forward/?foo=bar//&target=http://foobar.com/?a=1%26b=2&other=2'); }) + + // + // This is the proper failing test case for the common.join problem + // + it('should correctly format the a toProxy URL', function () { + var outgoing = {}; + var google = 'https://google.com' + common.setupOutgoing(outgoing, { + target: url.parse('http://sometarget.com:80'), + toProxy: true, + }, { url: google }); + + expect(outgoing.path).to.eql('/' + google); + }) }); describe('#setupSocket', function () { From 9c0b8697bc689ef464b4e46c92717cd03e349e38 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 2 Dec 2014 10:25:46 -0700 Subject: [PATCH 353/556] [fix] fix #738 --- lib/http-proxy/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 6aee0bdc1..24ed323c7 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -150,7 +150,7 @@ common.urlJoin = function() { retSegs = [ args.filter(function filter(a) { return !!a; - }).join('/').replace(/\/+/g, '/') + }).join('/').replace(/\/+/g, '/').replace(/:\//g, '://') ]; // Only join the query string if it exists so we don't have trailing a '?' From 56a7b77645b13d337c1a2f879460193d310454c8 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 2 Dec 2014 10:28:04 -0700 Subject: [PATCH 354/556] [dist] Version bump. 1.7.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 260e34818..9d2e2daec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.7.0", + "version" : "1.7.1", "repository" : { "type" : "git", From aeb42a3614d51bbd406e76e98ebd953cd6fe8fc4 Mon Sep 17 00:00:00 2001 From: Kailan Blanks Date: Wed, 3 Dec 2014 11:49:19 +0000 Subject: [PATCH 355/556] Fix grammar in README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 32f427ce6..cf9b79826 100644 --- a/README.md +++ b/README.md @@ -169,11 +169,11 @@ var http = require('http'), var proxy = httpProxy.createProxyServer(); // -// Create your server that make an operation that take a while -// and then proxy de request +// Create your server that makes an operation that waits a while +// and then proxies the request // http.createServer(function (req, res) { - // This simulate an operation that take 500ms in execute + // This simulates an operation that takes 500ms to execute setTimeout(function () { proxy.web(req, res, { target: 'http://localhost:9008' From 81874f795b7df7929e03d9d4cb98a947b1ef114b Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 8 Dec 2014 16:11:28 -0500 Subject: [PATCH 356/556] [dist] pin down deps and add requires-port --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 9d2e2daec..c64ebd8c3 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "main" : "index.js", "dependencies" : { - "eventemitter3" : "*" + "eventemitter3" : "0.x.x", + "requires-port" : "0.x.x" }, "devDependencies": { "mocha" : "*", @@ -26,7 +27,7 @@ "coveralls" : "*", "mocha-lcov-reporter": "*", "blanket" : "*", - "ws" : "*", + "ws" : "~0.5.0", "socket.io" : "*", "socket.io-client" : "*", "async" : "*" From 501e8c2a9b61e5edc19251ece01b6f643dc1b19e Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 8 Dec 2014 16:14:16 -0500 Subject: [PATCH 357/556] [fix] properly include port in host header with changeOrigin in all cases fixes #750 --- lib/http-proxy/common.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 24ed323c7..15e039231 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -1,6 +1,7 @@ -var common = exports, - url = require('url'), - extend = require('util')._extend; +var common = exports, + url = require('url'), + extend = require('util')._extend, + required = require('requires-port'); var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i; /** @@ -74,9 +75,11 @@ common.setupOutgoing = function(outgoing, options, req, forward) { outgoing.path = common.urlJoin(targetPath, outgoingPath); if (options.changeOrigin) { - outgoing.headers.host = outgoing.host; + outgoing.headers.host = + required(outgoing.port, options[forward || 'target'].protocol) && !hasPort(outgoing.host) + ? outgoing.host + ':' + outgoing.port + : outgoing.host; } - return outgoing; }; @@ -161,3 +164,14 @@ common.urlJoin = function() { return retSegs.join('?') }; + +/** + * Check the host and see if it potentially has a port in it (keep it simple) + * + * @returns {Boolean} Whether we have one or not + * + * @api private + */ +function hasPort(host) { + return !!~host.indexOf(':'); +}; From 71a06aab0249487ff650c8a47906cc8281561664 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 8 Dec 2014 16:14:48 -0500 Subject: [PATCH 358/556] [test] add tests for the changeOrigin cases in properly setting the host header --- test/lib-http-proxy-common-test.js | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 7cb5e1481..87777c25f 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -216,7 +216,7 @@ describe('lib/http-proxy/common.js', function () { // // This is the proper failing test case for the common.join problem // - it('should correctly format the a toProxy URL', function () { + it('should correctly format the toProxy URL', function () { var outgoing = {}; var google = 'https://google.com' common.setupOutgoing(outgoing, { @@ -225,7 +225,33 @@ describe('lib/http-proxy/common.js', function () { }, { url: google }); expect(outgoing.path).to.eql('/' + google); - }) + }); + + describe('when using changeOrigin', function () { + it('should correctly set the port to the host when it is a non-standard port using url.parse', function () { + var outgoing = {}; + var myEndpoint = 'https://myCouch.com:6984'; + common.setupOutgoing(outgoing, { + target: url.parse(myEndpoint), + changeOrigin: true + }, { url: '/' }); + + expect(outgoing.headers.host).to.eql('mycouch.com:6984'); + }); + it('should correctly set the port to the host when it is a non-standard port when setting host and port manually (which ignores port)', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, { + target: { + protocol: 'https:', + host: 'mycouch.com', + port: 6984 + }, + changeOrigin: true + }, { url: '/' }); + expect(outgoing.headers.host).to.eql('mycouch.com:6984'); + }) + }); + }); describe('#setupSocket', function () { From 2086e4917c97f347f84c54b166799bc8db9f4162 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 8 Dec 2014 16:16:05 -0500 Subject: [PATCH 359/556] [dist] Version bump. 1.7.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c64ebd8c3..ae32ddfd2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.7.1", + "version" : "1.7.2", "repository" : { "type" : "git", From c04485671a147cd47d5ce1487bdc22187feccc7c Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 8 Dec 2014 23:04:23 -0500 Subject: [PATCH 360/556] [fix] use simple regex instead of indexOf to check the protocol to support without the colon fixes #711 --- lib/http-proxy/common.js | 12 +++++++++--- lib/http-proxy/passes/ws-incoming.js | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 15e039231..679812aec 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -3,7 +3,13 @@ var common = exports, extend = require('util')._extend, required = require('requires-port'); -var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i; +var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i, + isSSL = /^https|wss/; + +/** + * Simple Regex for testing if protocol is https + */ +common.isSSL = isSSL; /** * Copies the right headers from `options` and `req` to * `outgoing` which is then used to fire the proxied @@ -26,7 +32,7 @@ var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i; common.setupOutgoing = function(outgoing, options, req, forward) { outgoing.port = options[forward || 'target'].port || - (~['https:', 'wss:'].indexOf(options[forward || 'target'].protocol) ? 443 : 80); + (isSSL.test(options[forward || 'target'].protocol) ? 443 : 80); ['host', 'hostname', 'socketPath'].forEach( function(e) { outgoing[e] = options[forward || 'target'][e]; } @@ -39,7 +45,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { extend(outgoing.headers, options.headers); } - if (~['https:', 'wss:'].indexOf(options[forward || 'target'].protocol)) { + if (isSSL.test(options[forward || 'target'].protocol)) { outgoing.rejectUnauthorized = (typeof options.secure === "undefined") ? true : options.secure; } diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index c8a5f207a..9ad80602b 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -84,7 +84,7 @@ var passes = exports; if (head && head.length) socket.unshift(head); - var proxyReq = (~['https:', 'wss:'].indexOf(options.target.protocol) ? https : http).request( + var proxyReq = (common.isSSL.test(options.target.protocol) ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req) ); // Error Handler From 89f9ca1e89d679b2b85a8f85b65e8b0878694207 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 8 Dec 2014 23:04:41 -0500 Subject: [PATCH 361/556] [test] show that we support protocol without the colon --- test/lib-http-proxy-common-test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 87777c25f..559c02e93 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -185,6 +185,18 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('some-path/am'); }); + it('should properly detect https/wss protocol without the colon', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, { + target: { + protocol: 'https', + host: 'whatever.com' + } + }, { url: '/' }); + + expect(outgoing.port).to.eql(443); + }); + it('should not prepend the target path to the outgoing path with prependPath = false', function () { var outgoing = {}; common.setupOutgoing(outgoing, { From 6a330ff904d02a41f9a1cac338a98da1849c54ca Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 8 Dec 2014 23:05:01 -0500 Subject: [PATCH 362/556] [dist] Version bump. 1.7.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ae32ddfd2..019f7bb84 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.7.2", + "version" : "1.7.3", "repository" : { "type" : "git", From 4bd3c4671f1e51f9c67b80a68370416966769a93 Mon Sep 17 00:00:00 2001 From: Sean Hussey Date: Thu, 11 Dec 2014 11:02:09 -0500 Subject: [PATCH 363/556] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cf9b79826..2eec2c579 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ console.log("listening on port 5050") server.listen(5050); ``` #### Modify a response from a proxied server -Sometimes when you have recieved a HTML/XML document from the server of origin you would like to modify it before forwarding it on. +Sometimes when you have received a HTML/XML document from the server of origin you would like to modify it before forwarding it on. [Harmon](https://github.com/No9/harmon) allows you to do this in a streaming style so as to keep the pressure on the proxy to a minimum. From c1a94176a8a5bb247625cb8d89c99796d48a0da7 Mon Sep 17 00:00:00 2001 From: Eugene Zhdan Date: Sat, 13 Dec 2014 21:45:14 +0300 Subject: [PATCH 364/556] Fix variables scope in test --- test/lib-http-proxy-test.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 830ccae6e..525230058 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -337,14 +337,15 @@ describe('lib/http-proxy.js', function() { }); it('should proxy a socket.io stream', function (done) { - var ports = { source: gen.port, proxy: gen.port }; - var proxy = httpProxy.createProxyServer({ + var ports = { source: gen.port, proxy: gen.port }, + proxy = httpProxy.createProxyServer({ target: 'ws://127.0.0.1:' + ports.source, ws: true - }); - proxyServer = proxy.listen(ports.proxy); - var server = http.createServer(); + }), + proxyServer = proxy.listen(ports.proxy), + server = http.createServer(), destiny = io.listen(server); + function startSocketIo() { var client = ioClient.connect('ws://127.0.0.1:' + ports.proxy); From 26537866b3ca522927aa4604a958f90774c0c0c0 Mon Sep 17 00:00:00 2001 From: Jorge Date: Tue, 9 Dec 2014 06:53:42 +0100 Subject: [PATCH 365/556] [api] add close event in ws-incoming.js --- lib/http-proxy/passes/ws-incoming.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 9ad80602b..9e96fbdd2 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -96,6 +96,12 @@ var passes = exports; proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { proxySocket.on('error', onOutgoingError); + + // Allow us to listen when the websocket has completed + proxySocket.on('end', function () { + server.emit('close', proxyRes, proxySocket, proxyHead); + }); + // 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. From 8bff3ddc1276e3ba18fd68c34d8982148cd21455 Mon Sep 17 00:00:00 2001 From: Jorge Leal Date: Thu, 11 Dec 2014 15:11:21 +0100 Subject: [PATCH 366/556] Added websocket close event test --- test/lib-http-proxy-test.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 525230058..e087ebdea 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -336,6 +336,7 @@ describe('lib/http-proxy.js', function() { }); }); + it('should proxy a socket.io stream', function (done) { var ports = { source: gen.port, proxy: gen.port }, proxy = httpProxy.createProxyServer({ @@ -370,5 +371,36 @@ describe('lib/http-proxy.js', function() { }); }) }); + + + it('should emit close event when socket.io client disconnects', 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); + var server = http.createServer(); + destiny = io.listen(server); + + function startSocketIo() { + var client = ioClient.connect('ws://127.0.0.1:' + ports.proxy); + client.on('connect', function () { + client.disconnect(); + }); + } + + proxyServer.on('close', function() { + proxyServer.close(); + server.close(); + done(); + }); + + server.listen(ports.source); + server.on('listening', startSocketIo); + + }); + + }) }); From 05d18a4e1ba6c2de41b0b803cd1793357979384d Mon Sep 17 00:00:00 2001 From: Jorge Date: Thu, 11 Dec 2014 15:19:56 +0100 Subject: [PATCH 367/556] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 2eec2c579..aaf2f69bb 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,7 @@ http.createServer(function (req, res) { * `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. * `proxySocket`: This event is emitted once the proxy websocket was created and piped into the target websocket. +* `close`: This event is emitted once the proxy websocket was closed. ```js var httpProxy = require('http-proxy'); @@ -233,6 +234,14 @@ proxy.on('proxySocket', function (proxySocket) { // listen for messages coming FROM the target here proxySocket.on('data', hybiParseAndLogMessage); }); + +// +// Listen for the `close` event on `proxy`. +// +proxy.on('close', function (req, socket, head) { + // view disconnected websocket connections + console.log('Client disconnected'); +}); ``` #### Using HTTPS From c62610e8e4d59e8ba4642370ff3fb933c6ddb4eb Mon Sep 17 00:00:00 2001 From: Jorge Leal Date: Thu, 11 Dec 2014 20:47:22 +0100 Subject: [PATCH 368/556] Deprecated proxySocket event in favor to open event. Maintained both proxySocket and open for backward compatibility. Conflicts: test/lib-http-proxy-test.js --- README.md | 7 ++++--- lib/http-proxy/passes/ws-incoming.js | 5 +++-- test/lib-http-proxy-test.js | 14 ++++++++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index aaf2f69bb..cdf970b63 100644 --- a/README.md +++ b/README.md @@ -195,8 +195,9 @@ http.createServer(function (req, res) { * `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. -* `proxySocket`: This event is emitted once the proxy websocket was created and piped into the target websocket. +* `open`: This event is emitted once the proxy websocket was created and piped into the target websocket. * `close`: This event is emitted once the proxy websocket was closed. +* (DEPRECATED) `proxySocket`: Deprecated in favor to `open`. ```js var httpProxy = require('http-proxy'); @@ -228,9 +229,9 @@ proxy.on('proxyRes', function (proxyRes, req, res) { }); // -// Listen for the `proxySocket` event on `proxy`. +// Listen for the `open` event on `proxy`. // -proxy.on('proxySocket', function (proxySocket) { +proxy.on('open', function (proxySocket) { // listen for messages coming FROM the target here proxySocket.on('data', hybiParseAndLogMessage); }); diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 9e96fbdd2..b72e55702 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -118,8 +118,9 @@ var passes = exports; return i + ": " + proxyRes.headers[i]; }).join('\r\n') + '\r\n\r\n'); proxySocket.pipe(socket).pipe(proxySocket); - // Make sure server exists before we try to emit - server && server.emit('proxySocket', proxySocket); + + server.emit('open', proxySocket); + server.emit('proxySocket', proxySocket); //DEPRECATED. }); return proxyReq.end(); // XXX: CHECK IF THIS IS THIS CORRECT diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index e087ebdea..f482dd296 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -280,7 +280,7 @@ describe('lib/http-proxy.js', function() { client.on('open', function () { client.send('hello there'); }); - + var count = 0; function maybe_done () { count += 1; @@ -373,7 +373,7 @@ describe('lib/http-proxy.js', function() { }); - it('should emit close event when socket.io client disconnects', function (done) { + it('should emit open and close events when socket.io client connects and disconnects', function (done) { var ports = { source: gen.port, proxy: gen.port }; var proxy = httpProxy.createProxyServer({ target: 'ws://127.0.0.1:' + ports.source, @@ -389,11 +389,17 @@ describe('lib/http-proxy.js', function() { client.disconnect(); }); } - + var count = 0; + + proxyServer.on('open', function() { + count += 1; + + }); + proxyServer.on('close', function() { proxyServer.close(); server.close(); - done(); + if (count == 1) { done(); } }); server.listen(ports.source); From 8a8a894092ddbec8f0365ced0e94a75b1307ecf1 Mon Sep 17 00:00:00 2001 From: Jorge Leal Date: Mon, 15 Dec 2014 07:06:02 +0100 Subject: [PATCH 369/556] Changed proxyServer and destiny to local variables. --- test/lib-http-proxy-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index f482dd296..0143293a7 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -379,9 +379,9 @@ describe('lib/http-proxy.js', function() { target: 'ws://127.0.0.1:' + ports.source, ws: true }); - proxyServer = proxy.listen(ports.proxy); + var proxyServer = proxy.listen(ports.proxy); var server = http.createServer(); - destiny = io.listen(server); + var destiny = io.listen(server); function startSocketIo() { var client = ioClient.connect('ws://127.0.0.1:' + ports.proxy); From ea0a4ded803b30144e442344ad5a38a0d34bb3ba Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 17 Dec 2014 00:53:51 -0700 Subject: [PATCH 370/556] [fix] style spacing wtf --- lib/http-proxy/passes/web-incoming.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index a2121e4fd..b74e61a7e 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -145,13 +145,13 @@ web_o = Object.keys(web_o).map(function(pass) { proxyReq.on('response', function(proxyRes) { if(server) { server.emit('proxyRes', proxyRes, req, res); } for(var i=0; i < web_o.length; i++) { - if(web_o[i](req, res, proxyRes, options)) { break; } + if(web_o[i](req, res, proxyRes, options)) { break; } } // Allow us to listen when the proxy has completed proxyRes.on('end', function () { - server.emit('end', req, res, proxyRes); - }) + server.emit('end', req, res, proxyRes); + }); proxyRes.pipe(res); }); From f30486195cfa6cfcf6400ac445975d5adada72e4 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 17 Dec 2014 00:57:43 -0700 Subject: [PATCH 371/556] [minor] grammar --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cdf970b63..ada39bf9c 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ server.listen(5050); #### Modify a response from a proxied server Sometimes when you have received a HTML/XML document from the server of origin you would like to modify it before forwarding it on. -[Harmon](https://github.com/No9/harmon) allows you to do this in a streaming style so as to keep the pressure on the proxy to a minimum. +[Harmon](https://github.com/No9/harmon) allows you to do this in a streaming style so as to keep the pressure on the proxy to a minimum. #### Setup a stand-alone proxy server with proxy request header re-writing @@ -197,7 +197,7 @@ http.createServer(function (req, res) { * `proxyRes`: This event is emitted if the request to the target got a response. * `open`: This event is emitted once the proxy websocket was created and piped into the target websocket. * `close`: This event is emitted once the proxy websocket was closed. -* (DEPRECATED) `proxySocket`: Deprecated in favor to `open`. +* (DEPRECATED) `proxySocket`: Deprecated in favor of `open`. ```js var httpProxy = require('http-proxy'); From f0db5b3f708b0858f617d472dfdd0ba211b774ef Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 17 Dec 2014 00:58:17 -0700 Subject: [PATCH 372/556] [dist] Version bump. 1.8.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 019f7bb84..e2d15da30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.7.3", + "version" : "1.8.0", "repository" : { "type" : "git", From 402ab057340a29db7a521ff239c5e21ac0c12be8 Mon Sep 17 00:00:00 2001 From: Alistair Jones Date: Sat, 22 Feb 2014 22:48:06 +0000 Subject: [PATCH 373/556] Pass HTTPS client parameters. For more detailed control over HTTPS client behaviour, pass through the parameters listed here: http://nodejs.org/api/https.html#https_https_request_options_callback The `rejectUnauthorized` parameter is omitted, because it overlaps with the existing `secure` parameter: https://github.com/nodejitsu/node-http-proxy/blob/master/README.md#using-https Conflicts: test/lib-http-proxy-common-test.js --- lib/http-proxy/common.js | 3 ++- test/lib-http-proxy-common-test.js | 33 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 679812aec..66e80f9a1 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -34,7 +34,8 @@ common.setupOutgoing = function(outgoing, options, req, forward) { outgoing.port = options[forward || 'target'].port || (isSSL.test(options[forward || 'target'].protocol) ? 443 : 80); - ['host', 'hostname', 'socketPath'].forEach( + ['host', 'hostname', 'socketPath', 'pfx', 'key', + 'passphrase', 'cert', 'ca', 'ciphers', 'secureProtocol'].forEach( function(e) { outgoing[e] = options[forward || 'target'][e]; } ); diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 559c02e93..5cf36c232 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -250,6 +250,7 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.headers.host).to.eql('mycouch.com:6984'); }); + it('should correctly set the port to the host when it is a non-standard port when setting host and port manually (which ignores port)', function () { var outgoing = {}; common.setupOutgoing(outgoing, { @@ -264,6 +265,38 @@ describe('lib/http-proxy/common.js', function () { }) }); + it('should pass through https client parameters', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, + { + agent : '?', + target: { + host : 'how', + hostname : 'are', + socketPath: 'you', + protocol: 'https:', + pfx: 'my-pfx', + key: 'my-key', + passphrase: 'my-passphrase', + cert: 'my-cert', + ca: 'my-ca', + ciphers: 'my-ciphers', + secureProtocol: 'my-secure-protocol' + } + }, + { + method : 'i', + url : 'am' + }); + + expect(outgoing.pfx).eql('my-pfx'); + expect(outgoing.key).eql('my-key'); + expect(outgoing.passphrase).eql('my-passphrase'); + expect(outgoing.cert).eql('my-cert'); + expect(outgoing.ca).eql('my-ca'); + expect(outgoing.ciphers).eql('my-ciphers'); + expect(outgoing.secureProtocol).eql('my-secure-protocol'); + }); }); describe('#setupSocket', function () { From 3311106c2c2346f3ac1ffe402b80bca3c7c59275 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 17 Dec 2014 10:11:42 -0700 Subject: [PATCH 374/556] [dist] Version bump. 1.8.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e2d15da30..fce7c4268 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.8.0", + "version" : "1.8.1", "repository" : { "type" : "git", From 32aa10dfe2d0593743e0b86735e206029cfbb497 Mon Sep 17 00:00:00 2001 From: PanManAms Date: Sat, 20 Dec 2014 15:40:46 +0100 Subject: [PATCH 375/556] changed highlighted part - very minor --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ada39bf9c..cbdfd2c2a 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ proxies and load balancers. ### Core Concept A new proxy is created by calling `createProxyServer` and passing -an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L34-L51)) +an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L33-L50)) ```javascript var httpProxy = require('http-proxy'); From 9eefd4678ef95d878a9e5cdd25dd45b0c07311b7 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 23 Dec 2014 13:17:58 -0500 Subject: [PATCH 376/556] [api] add an ignorePath option if you want to disregard the path of the incoming request when proxying to the target server fixes #758 --- lib/http-proxy.js | 1 + lib/http-proxy/common.js | 11 ++++++++--- test/lib-http-proxy-common-test.js | 25 +++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index b1ad646f4..983d587b7 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -39,6 +39,7 @@ module.exports.createProxyServer = * secure : * toProxy: * prependPath: + * ignorePath: * localAddress : * changeOrigin: * hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null. diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 66e80f9a1..e3dd87ecc 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -79,6 +79,13 @@ common.setupOutgoing = function(outgoing, options, req, forward) { ? url.parse(req.url).path : req.url; + // + // Remark: ignorePath will just straight up ignore whatever the request's + // path is. This can be labeled as FOOT-GUN material if you do not know what + // you are doing and are using conflicting options. + // + outgoingPath = !options.ignorePath ? outgoingPath : '/'; + outgoing.path = common.urlJoin(targetPath, outgoingPath); if (options.changeOrigin) { @@ -158,9 +165,7 @@ common.urlJoin = function() { // joining e.g. ['', 'am'] // retSegs = [ - args.filter(function filter(a) { - return !!a; - }).join('/').replace(/\/+/g, '/').replace(/:\//g, '://') + args.filter(Boolean).join('/').replace(/\/+/g, '/').replace(/:\//g, '://') ]; // Only join the query string if it exists so we don't have trailing a '?' diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 5cf36c232..a455ad510 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -239,6 +239,31 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('/' + google); }); + describe('when using ignorePath', function () { + it('should ignore the path of the `req.url` passed in but use the target path', function () { + var outgoing = {}; + var myEndpoint = 'https://whatever.com/some/crazy/path/whoooo'; + common.setupOutgoing(outgoing, { + target: url.parse(myEndpoint), + ignorePath: true + }, { url: '/more/crazy/pathness' }); + + expect(outgoing.path).to.eql('/some/crazy/path/whoooo/'); + }); + + it('and prependPath: false, it should ignore path of target and incoming request', function () { + var outgoing = {}; + var myEndpoint = 'https://whatever.com/some/crazy/path/whoooo'; + common.setupOutgoing(outgoing, { + target: url.parse(myEndpoint), + ignorePath: true, + prependPath: false + }, { url: '/more/crazy/pathness' }); + + expect(outgoing.path).to.eql('/'); + }); + }); + describe('when using changeOrigin', function () { it('should correctly set the port to the host when it is a non-standard port using url.parse', function () { var outgoing = {}; From 7f2f3ac35c663b1332594044cc1095bdfb458df4 Mon Sep 17 00:00:00 2001 From: Matt Hauck Date: Thu, 5 Feb 2015 12:17:26 -0800 Subject: [PATCH 377/556] Add support for auto host rewriting and protocol rewriting auto host rewriting allows rewriting to work as expected in most cases without extra cumbersome configuration protocol rewriting allows node-http-proxy to be able to listen over HTTPS and properly reverse-proxy to sites running over HTTP (to avoid doing SSL twice) --- lib/http-proxy.js | 2 + lib/http-proxy/passes/web-outgoing.js | 12 +- ...lib-http-proxy-passes-web-outgoing-test.js | 125 +++++++++++++----- 3 files changed, 106 insertions(+), 33 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index b1ad646f4..78522b63b 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -42,6 +42,8 @@ module.exports.createProxyServer = * localAddress : * changeOrigin: * hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null. + * autoRewrite: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. + * protocolRewrite: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null. * } * * NOTE: `options.ws` and `options.ssl` are optional. diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 67a1a6d98..99f886477 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -47,11 +47,19 @@ var redirectRegex = /^30(1|2|7|8)$/; }, function setRedirectHostRewrite(req, res, proxyRes, options) { - if (options.hostRewrite + if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite) && proxyRes.headers['location'] && redirectRegex.test(proxyRes.statusCode)) { var u = url.parse(proxyRes.headers['location']); - u.host = options.hostRewrite; + if (options.hostRewrite) { + u.host = options.hostRewrite; + } else if (options.autoRewrite) { + u.host = req.headers['host']; + } + if (options.protocolRewrite) { + u.protocol = options.protocolRewrite; + } + proxyRes.headers['location'] = u.format(); } }, diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index ee1077e03..342f024ea 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -3,55 +3,118 @@ var httpProxy = require('../lib/http-proxy/passes/web-outgoing'), describe('lib/http-proxy/passes/web-outgoing.js', function () { describe('#setRedirectHostRewrite', function () { - context('rewrites location host to option', function() { - beforeEach(function() { - this.proxyRes = { - statusCode: 301, - headers: { - location: "http://f.com/" - } - }; + beforeEach(function() { + this.req = { + headers: { + host: "x2.com" + } + }; + this.proxyRes = { + statusCode: 301, + headers: { + location: "http://f.com/" + } + }; + }); + context('rewrites location host with hostRewrite', function() { + beforeEach(function() { this.options = { hostRewrite: "x.com" }; }); + [301, 302, 307, 308].forEach(function(code) { + it('on ' + code, function() { + this.proxyRes.statusCode = code; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + }); + }); - it('on 301', function() { - this.proxyRes.statusCode = 301; - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + it('not on 200', function() { + this.proxyRes.statusCode = 200; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://f.com/'); }); - it('on 302', function() { - this.proxyRes.statusCode = 302; - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + it('not when hostRewrite is unset', function() { + delete this.options.hostRewrite; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://f.com/'); }); - it('on 307', function() { - this.proxyRes.statusCode = 307; - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); + it('takes precedence over autoRewrite', function() { + this.options.autoRewrite = true; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); }); + }); - it('on 308', function() { - this.proxyRes.statusCode = 308; - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + context('rewrites location host with autoRewrite', function() { + beforeEach(function() { + this.options = { + autoRewrite: true, + }; + }); + [301, 302, 307, 308].forEach(function(code) { + it('on ' + code, function() { + this.proxyRes.statusCode = code; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://'+this.req.headers.host+'/'); + }); }); it('not on 200', function() { this.proxyRes.statusCode = 200; - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, this.options); + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://f.com/'); }); - it('not when hostRewrite is unset', function() { - httpProxy.setRedirectHostRewrite({}, {}, this.proxyRes, {}); + it('not when autoRewrite is unset', function() { + delete this.options.autoRewrite; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://f.com/'); }); }); + + context('rewrites location protocol with protocolRewrite', function() { + beforeEach(function() { + this.options = { + protocolRewrite: 'https', + }; + }); + [301, 302, 307, 308].forEach(function(code) { + it('on ' + code, function() { + this.proxyRes.statusCode = code; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('https://f.com/'); + }); + }); + + it('not on 200', function() { + this.proxyRes.statusCode = 200; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + }); + + it('not when protocolRewrite is unset', function() { + delete this.options.protocolRewrite; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + }); + + it('works together with hostRewrite', function() { + this.options.hostRewrite = 'x.com' + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('https://x.com/'); + }); + + it('works together with autoRewrite', function() { + this.options.autoRewrite = true + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('https://x2.com/'); + }); + }); }); describe('#setConnection', function () { @@ -64,7 +127,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { } }, {}, proxyRes); - expect(proxyRes.headers.connection).to.eql('close'); + expect(proxyRes.headers.connection).to.eql('close'); }); it('set the right connection with 1.0 - req.connection', function() { @@ -76,7 +139,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { } }, {}, proxyRes); - expect(proxyRes.headers.connection).to.eql('hey'); + expect(proxyRes.headers.connection).to.eql('hey'); }); it('set the right connection - req.connection', function() { @@ -88,7 +151,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { } }, {}, proxyRes); - expect(proxyRes.headers.connection).to.eql('hola'); + expect(proxyRes.headers.connection).to.eql('hola'); }); it('set the right connection - `keep-alive`', function() { @@ -100,7 +163,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { } }, {}, proxyRes); - expect(proxyRes.headers.connection).to.eql('keep-alive'); + expect(proxyRes.headers.connection).to.eql('keep-alive'); }); }); @@ -153,4 +216,4 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { }); }); - + From 14415a50741d1f258da884686455d87d68eb8121 Mon Sep 17 00:00:00 2001 From: Matt Hauck Date: Mon, 9 Mar 2015 11:49:28 -0700 Subject: [PATCH 378/556] refactor some tests for greater readability --- ...lib-http-proxy-passes-web-outgoing-test.js | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index 342f024ea..7aef725cc 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -6,113 +6,110 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { beforeEach(function() { this.req = { headers: { - host: "x2.com" + host: "ext-auto.com" } }; this.proxyRes = { statusCode: 301, headers: { - location: "http://f.com/" + location: "http://backend.com/" } }; + this.options = { + target: "http://backend.com" + }; }); context('rewrites location host with hostRewrite', function() { beforeEach(function() { - this.options = { - hostRewrite: "x.com" - }; + this.options.hostRewrite = "ext-manual.com"; }); [301, 302, 307, 308].forEach(function(code) { it('on ' + code, function() { this.proxyRes.statusCode = code; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + expect(this.proxyRes.headers.location).to.eql('http://ext-manual.com/'); }); }); it('not on 200', function() { this.proxyRes.statusCode = 200; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + expect(this.proxyRes.headers.location).to.eql('http://backend.com/'); }); it('not when hostRewrite is unset', function() { delete this.options.hostRewrite; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + expect(this.proxyRes.headers.location).to.eql('http://backend.com/'); }); it('takes precedence over autoRewrite', function() { this.options.autoRewrite = true; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://'+this.options.hostRewrite+'/'); + expect(this.proxyRes.headers.location).to.eql('http://ext-manual.com/'); }); }); context('rewrites location host with autoRewrite', function() { beforeEach(function() { - this.options = { - autoRewrite: true, - }; + this.options.autoRewrite = true; }); [301, 302, 307, 308].forEach(function(code) { it('on ' + code, function() { this.proxyRes.statusCode = code; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://'+this.req.headers.host+'/'); + expect(this.proxyRes.headers.location).to.eql('http://ext-auto.com/'); }); }); it('not on 200', function() { this.proxyRes.statusCode = 200; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + expect(this.proxyRes.headers.location).to.eql('http://backend.com/'); }); it('not when autoRewrite is unset', function() { delete this.options.autoRewrite; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + expect(this.proxyRes.headers.location).to.eql('http://backend.com/'); }); }); context('rewrites location protocol with protocolRewrite', function() { beforeEach(function() { - this.options = { - protocolRewrite: 'https', - }; + this.options.protocolRewrite = 'https'; }); [301, 302, 307, 308].forEach(function(code) { it('on ' + code, function() { this.proxyRes.statusCode = code; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('https://f.com/'); + expect(this.proxyRes.headers.location).to.eql('https://backend.com/'); }); }); it('not on 200', function() { this.proxyRes.statusCode = 200; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + expect(this.proxyRes.headers.location).to.eql('http://backend.com/'); }); it('not when protocolRewrite is unset', function() { delete this.options.protocolRewrite; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('http://f.com/'); + expect(this.proxyRes.headers.location).to.eql('http://backend.com/'); }); it('works together with hostRewrite', function() { - this.options.hostRewrite = 'x.com' + this.options.hostRewrite = 'ext-manual.com' httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('https://x.com/'); + expect(this.proxyRes.headers.location).to.eql('https://ext-manual.com/'); }); it('works together with autoRewrite', function() { this.options.autoRewrite = true httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); - expect(this.proxyRes.headers.location).to.eql('https://x2.com/'); + expect(this.proxyRes.headers.location).to.eql('https://ext-auto.com/'); }); }); }); From 26029ba7ac948b5dc0befb2091cc9a5862d0641c Mon Sep 17 00:00:00 2001 From: Matt Hauck Date: Mon, 9 Mar 2015 13:17:52 -0700 Subject: [PATCH 379/556] only rewrite redirect urls when it matches target if functioning as a reverse proxy for host1.foo.com, with a backend target of backend.foo.com:8080, the node proxy should only rewrite the redirect if it is a redirect to somewhere on backend.foo.com:8080 --- lib/http-proxy/passes/web-outgoing.js | 7 +++++ ...lib-http-proxy-passes-web-outgoing-test.js | 28 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 99f886477..977f1f747 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -50,7 +50,14 @@ var redirectRegex = /^30(1|2|7|8)$/; if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite) && proxyRes.headers['location'] && redirectRegex.test(proxyRes.statusCode)) { + var target = url.parse(options.target); var u = url.parse(proxyRes.headers['location']); + + // make sure the redirected host matches the target host before rewriting + if (target.host != u.host) { + return; + } + if (options.hostRewrite) { u.host = options.hostRewrite; } else if (options.autoRewrite) { diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index 7aef725cc..5b91c0bb2 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -49,6 +49,20 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://ext-manual.com/'); }); + + it('not when the redirected location does not match target host', function() { + this.proxyRes.statusCode = 302; + this.proxyRes.headers.location = "http://some-other/"; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://some-other/'); + }); + + it('not when the redirected location does not match target port', function() { + this.proxyRes.statusCode = 302; + this.proxyRes.headers.location = "http://backend.com:8080/"; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://backend.com:8080/'); + }); }); context('rewrites location host with autoRewrite', function() { @@ -74,6 +88,20 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://backend.com/'); }); + + it('not when the redirected location does not match target host', function() { + this.proxyRes.statusCode = 302; + this.proxyRes.headers.location = "http://some-other/"; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://some-other/'); + }); + + it('not when the redirected location does not match target port', function() { + this.proxyRes.statusCode = 302; + this.proxyRes.headers.location = "http://backend.com:8080/"; + httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); + expect(this.proxyRes.headers.location).to.eql('http://backend.com:8080/'); + }); }); context('rewrites location protocol with protocolRewrite', function() { From 6d074eff471fbe57ec6e763f03ae552d48578602 Mon Sep 17 00:00:00 2001 From: Feross Aboukhadijeh Date: Wed, 11 Mar 2015 00:33:34 -0700 Subject: [PATCH 380/556] fix "x-forwarded-proto" in node 0.12 and iojs The way to detect TLSSockets in node 0.12 and iojs has changed. You can just check `socket.encrypted` now :) Fixes #772 --- lib/http-proxy/passes/web-incoming.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index b74e61a7e..9f5ec20e0 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -64,10 +64,11 @@ web_o = Object.keys(web_o).map(function(pass) { function XHeaders(req, res, options) { if(!options.xfwd) return; + var encrypted = req.isSpdy || req.connection.encrypted || req.connection.pair; var values = { for : req.connection.remoteAddress || req.socket.remoteAddress, port : common.getPort(req), - proto: req.isSpdy ? 'https' : (req.connection.pair ? 'https' : 'http') + proto: encrypted ? 'https' : 'http' }; ['for', 'port', 'proto'].forEach(function(header) { From ab5c3e5c819ca993e0616d178bc1d282af539508 Mon Sep 17 00:00:00 2001 From: ashubham Date: Thu, 12 Mar 2015 13:15:06 -0700 Subject: [PATCH 381/556] auth header added --- lib/http-proxy.js | 1 + lib/http-proxy/common.js | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index b1ad646f4..8d37dd212 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -41,6 +41,7 @@ module.exports.createProxyServer = * prependPath: * localAddress : * changeOrigin: + * auth : Basic authentication i.e. 'user:password' to compute an Authorization header. * hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null. * } * diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 66e80f9a1..a8722f294 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -46,6 +46,10 @@ common.setupOutgoing = function(outgoing, options, req, forward) { extend(outgoing.headers, options.headers); } + if(options.auth){ + outgoing.auth = options.auth; + } + if (isSSL.test(options[forward || 'target'].protocol)) { outgoing.rejectUnauthorized = (typeof options.secure === "undefined") ? true : options.secure; } From f55ffa356a259c09685c6b768a404e4b73f674ce Mon Sep 17 00:00:00 2001 From: ashubham Date: Thu, 12 Mar 2015 13:40:49 -0700 Subject: [PATCH 382/556] auth header added tests --- test/lib-http-proxy-common-test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 5cf36c232..3ee041fca 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -17,6 +17,7 @@ describe('lib/http-proxy/common.js', function () { }, headers: {'fizz': 'bang', 'overwritten':true}, localAddress: 'local.address', + auth:'username:pass' }, { method : 'i', @@ -37,6 +38,7 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.headers.fizz).to.eql('bang'); expect(outgoing.headers.overwritten).to.eql(true); expect(outgoing.localAddress).to.eql('local.address'); + expect(outgoing.auth).to.eql('username:pass'); }); it('should not override agentless upgrade header', function () { From df158bfc53e35e62609d8169f3883f6dcf12b73c Mon Sep 17 00:00:00 2001 From: ashubham Date: Thu, 12 Mar 2015 15:11:56 -0700 Subject: [PATCH 383/556] added auth header test --- .idea/.name | 1 + .idea/encodings.xml | 4 + .idea/inspectionProfiles/Project_Default.xml | 8 + .../inspectionProfiles/profiles_settings.xml | 7 + .idea/jsLibraryMappings.xml | 6 + .idea/jsLinters/jscs.xml | 4 + .idea/jsLinters/jshint.xml | 70 +++++ .../node_http_proxy_node_modules.xml | 14 + .idea/modules.xml | 8 + .idea/node-http-proxy.iml | 9 + .idea/scopes/scope_settings.xml | 5 + .idea/vcs.xml | 6 + .idea/workspace.xml | 245 ++++++++++++++++++ lib/http-proxy/common.js | 2 +- ...lib-http-proxy-passes-web-incoming-test.js | 27 ++ 15 files changed, 415 insertions(+), 1 deletion(-) create mode 100644 .idea/.name create mode 100644 .idea/encodings.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/jsLibraryMappings.xml create mode 100644 .idea/jsLinters/jscs.xml create mode 100644 .idea/jsLinters/jshint.xml create mode 100644 .idea/libraries/node_http_proxy_node_modules.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/node-http-proxy.iml create mode 100644 .idea/scopes/scope_settings.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 000000000..cef877de7 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +node-http-proxy \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 000000000..d82104827 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 000000000..65ef11480 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 000000000..3b312839b --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 000000000..61cd2da79 --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jsLinters/jscs.xml b/.idea/jsLinters/jscs.xml new file mode 100644 index 000000000..8fc0d2994 --- /dev/null +++ b/.idea/jsLinters/jscs.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/jsLinters/jshint.xml b/.idea/jsLinters/jshint.xml new file mode 100644 index 000000000..c5f59800d --- /dev/null +++ b/.idea/jsLinters/jshint.xml @@ -0,0 +1,70 @@ + + + + + \ No newline at end of file diff --git a/.idea/libraries/node_http_proxy_node_modules.xml b/.idea/libraries/node_http_proxy_node_modules.xml new file mode 100644 index 000000000..200016519 --- /dev/null +++ b/.idea/libraries/node_http_proxy_node_modules.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..32e963d7a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/node-http-proxy.iml b/.idea/node-http-proxy.iml new file mode 100644 index 000000000..99ac45955 --- /dev/null +++ b/.idea/node-http-proxy.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 000000000..922003b84 --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..94a25f7f4 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 000000000..dea6016df --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,245 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1426197133406 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index a8722f294..59ece4dfb 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -46,7 +46,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { extend(outgoing.headers, options.headers); } - if(options.auth){ + if (options.auth) { outgoing.auth = options.auth; } diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index f2c6f1304..f6d532dff 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -299,4 +299,31 @@ describe('#createProxyServer.web() using own http server', function () { http.request('http://127.0.0.1:8081', function() {}).end(); }); + + it('should proxy the request with the Authorization header set', function (done) { + var proxy = httpProxy.createProxyServer({ + target: 'http://127.0.0.1:8080', + auth: 'user:pass' + }); + + function requestHandler(req, res) { + proxy.web(req, res); + } + + var proxyServer = http.createServer(requestHandler); + + var source = http.createServer(function(req, res) { + source.close(); + proxyServer.close(); + var auth = new Buffer(req.headers.authorization.split(' ')[1], 'base64'); + expect(req.method).to.eql('GET'); + expect(auth.toString()).to.eql('user:pass'); + done(); + }); + + proxyServer.listen('8081'); + source.listen('8080'); + + http.request('http://127.0.0.1:8081', function() {}).end(); + }); }); \ No newline at end of file From ff1626f0719652c92895cf80f9aacc22ededadad Mon Sep 17 00:00:00 2001 From: ashubham Date: Thu, 12 Mar 2015 15:12:53 -0700 Subject: [PATCH 384/556] added auth header test --- .idea/.name | 1 - .idea/encodings.xml | 4 - .idea/inspectionProfiles/Project_Default.xml | 8 - .../inspectionProfiles/profiles_settings.xml | 7 - .idea/jsLibraryMappings.xml | 6 - .idea/jsLinters/jscs.xml | 4 - .idea/jsLinters/jshint.xml | 70 ----- .../node_http_proxy_node_modules.xml | 14 - .idea/modules.xml | 8 - .idea/node-http-proxy.iml | 9 - .idea/scopes/scope_settings.xml | 5 - .idea/vcs.xml | 6 - .idea/workspace.xml | 245 ------------------ 13 files changed, 387 deletions(-) delete mode 100644 .idea/.name delete mode 100644 .idea/encodings.xml delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/jsLibraryMappings.xml delete mode 100644 .idea/jsLinters/jscs.xml delete mode 100644 .idea/jsLinters/jshint.xml delete mode 100644 .idea/libraries/node_http_proxy_node_modules.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/node-http-proxy.iml delete mode 100644 .idea/scopes/scope_settings.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/workspace.xml diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index cef877de7..000000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -node-http-proxy \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml deleted file mode 100644 index d82104827..000000000 --- a/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 65ef11480..000000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 3b312839b..000000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml deleted file mode 100644 index 61cd2da79..000000000 --- a/.idea/jsLibraryMappings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/jsLinters/jscs.xml b/.idea/jsLinters/jscs.xml deleted file mode 100644 index 8fc0d2994..000000000 --- a/.idea/jsLinters/jscs.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/jsLinters/jshint.xml b/.idea/jsLinters/jshint.xml deleted file mode 100644 index c5f59800d..000000000 --- a/.idea/jsLinters/jshint.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/libraries/node_http_proxy_node_modules.xml b/.idea/libraries/node_http_proxy_node_modules.xml deleted file mode 100644 index 200016519..000000000 --- a/.idea/libraries/node_http_proxy_node_modules.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 32e963d7a..000000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/node-http-proxy.iml b/.idea/node-http-proxy.iml deleted file mode 100644 index 99ac45955..000000000 --- a/.idea/node-http-proxy.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml deleted file mode 100644 index 922003b84..000000000 --- a/.idea/scopes/scope_settings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7f4..000000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index dea6016df..000000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,245 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1426197133406 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 63c9262df5bd04d83432db44fce2a4d5b19a59ea Mon Sep 17 00:00:00 2001 From: ashubham Date: Thu, 12 Mar 2015 15:14:49 -0700 Subject: [PATCH 385/556] space instead of tabs --- test/lib-http-proxy-common-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 3ee041fca..14ff87536 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -17,7 +17,7 @@ describe('lib/http-proxy/common.js', function () { }, headers: {'fizz': 'bang', 'overwritten':true}, localAddress: 'local.address', - auth:'username:pass' + auth:'username:pass' }, { method : 'i', From 7298510e9170d74ff057487085bc1e898f044177 Mon Sep 17 00:00:00 2001 From: ashubham Date: Thu, 12 Mar 2015 15:16:17 -0700 Subject: [PATCH 386/556] space instead of tabs --- test/lib-http-proxy-common-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 14ff87536..007ba39a4 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -17,7 +17,7 @@ describe('lib/http-proxy/common.js', function () { }, headers: {'fizz': 'bang', 'overwritten':true}, localAddress: 'local.address', - auth:'username:pass' + auth:'username:pass' }, { method : 'i', From e907d7bb2aa2825b43d9355cb1ee25bec47b15ad Mon Sep 17 00:00:00 2001 From: ashubham Date: Thu, 12 Mar 2015 15:17:26 -0700 Subject: [PATCH 387/556] end of file line space --- test/lib-http-proxy-passes-web-incoming-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index f6d532dff..cf9bf6b75 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -326,4 +326,4 @@ describe('#createProxyServer.web() using own http server', function () { http.request('http://127.0.0.1:8081', function() {}).end(); }); -}); \ No newline at end of file +}); From 87a92a72802a27f817fcba87382d55831fd04ddb Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 12 Mar 2015 18:59:32 -0400 Subject: [PATCH 388/556] [dist] Version bump. 1.9.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fce7c4268..939a3337c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.8.1", + "version" : "1.9.0", "repository" : { "type" : "git", From d145152655a69479348b0ebc726d4dc19720a12b Mon Sep 17 00:00:00 2001 From: Damon McMinn Date: Wed, 1 Apr 2015 13:14:11 +0100 Subject: [PATCH 389/556] Add test for https://github.com/nodejitsu/node-http-proxy/issues/747 --- test/lib-http-proxy-common-test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 007ba39a4..3c6ebd1db 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -299,6 +299,17 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.ciphers).eql('my-ciphers'); expect(outgoing.secureProtocol).eql('my-secure-protocol'); }); + + // url.parse('').path => null + it('should not pass null as last arg to #urlJoin', function(){ + var outgoing = {}; + common.setupOutgoing(outgoing, {target: + { path: '' } + }, { url : '' }); + + expect(outgoing.path).to.be('/'); + }); + }); describe('#setupSocket', function () { From ab37a224aab6335308d9f0b2c246096259461f89 Mon Sep 17 00:00:00 2001 From: Damon McMinn Date: Wed, 1 Apr 2015 13:19:03 +0100 Subject: [PATCH 390/556] Fix https://github.com/nodejitsu/node-http-proxy/issues/747 --- lib/http-proxy/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 59ece4dfb..225324ebf 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -80,7 +80,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { // Remark: Can we somehow not use url.parse as a perf optimization? // var outgoingPath = !options.toProxy - ? url.parse(req.url).path + ? (url.parse(req.url).path || '/') : req.url; outgoing.path = common.urlJoin(targetPath, outgoingPath); From 21b30b754db4f6410c3d2052bc123b3fdae57c46 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 1 Apr 2015 12:09:42 -0400 Subject: [PATCH 391/556] [dist] Version bump. 1.9.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 939a3337c..97073393b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.9.0", + "version" : "1.9.1", "repository" : { "type" : "git", From 1dabda241f3b93eb9195134042e7a3b84fd0ef57 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 1 Apr 2015 12:24:26 -0400 Subject: [PATCH 392/556] [dist] Version bump. 1.10.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 97073393b..9c9ae3822 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name" : "http-proxy", - "version" : "1.9.1", + "version" : "1.10.0", "repository" : { "type" : "git", From c33d1616cdbd60587ca2eb326c48b8a87ac56092 Mon Sep 17 00:00:00 2001 From: Jeremy Judeaux Date: Thu, 2 Apr 2015 14:11:45 +0200 Subject: [PATCH 393/556] force cipher AES128-GCM-SHA256 in https tests --- test/lib-https-proxy-test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js index 7a966f491..fbfabc94b 100644 --- a/test/lib-https-proxy-test.js +++ b/test/lib-https-proxy-test.js @@ -35,6 +35,7 @@ describe('lib/http-proxy.js', function() { ssl: { key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')), + ciphers: 'AES128-GCM-SHA256', } }).listen(ports.proxy); @@ -65,6 +66,7 @@ describe('lib/http-proxy.js', function() { var source = https.createServer({ key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')), + ciphers: 'AES128-GCM-SHA256', }, function (req, res) { expect(req.method).to.eql('GET'); expect(req.headers.host.split(':')[1]).to.eql(ports.proxy); @@ -105,6 +107,7 @@ describe('lib/http-proxy.js', function() { var source = https.createServer({ key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')), + ciphers: 'AES128-GCM-SHA256', }, function(req, res) { expect(req.method).to.eql('GET'); expect(req.headers.host.split(':')[1]).to.eql(ports.proxy); @@ -119,6 +122,7 @@ describe('lib/http-proxy.js', function() { ssl: { key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')), + ciphers: 'AES128-GCM-SHA256', }, secure: false }).listen(ports.proxy); @@ -150,6 +154,7 @@ describe('lib/http-proxy.js', function() { var source = https.createServer({ key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')), + ciphers: 'AES128-GCM-SHA256', }).listen(ports.source); var proxy = httpProxy.createProxyServer({ @@ -191,6 +196,7 @@ describe('lib/http-proxy.js', function() { var ownServer = https.createServer({ key: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-key.pem')), cert: fs.readFileSync(path.join(__dirname, 'fixtures', 'agent2-cert.pem')), + ciphers: 'AES128-GCM-SHA256', }, function (req, res) { proxy.web(req, res, { target: 'http://127.0.0.1:' + ports.source From 0ee314c436226391318b9a1b623cb3f7e8bf4df7 Mon Sep 17 00:00:00 2001 From: Jeremy Judeaux Date: Thu, 2 Apr 2015 14:22:26 +0200 Subject: [PATCH 394/556] fix expected error message when node 0.12.x --- test/lib-https-proxy-test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js index fbfabc94b..643c726a3 100644 --- a/test/lib-https-proxy-test.js +++ b/test/lib-https-proxy-test.js @@ -166,7 +166,11 @@ describe('lib/http-proxy.js', function() { proxy.on('error', function (err, req, res) { expect(err).to.be.an(Error); - expect(err.toString()).to.be('Error: DEPTH_ZERO_SELF_SIGNED_CERT') + if (process.versions.node.indexOf('0.12.') == 0) { + expect(err.toString()).to.be('Error: self signed certificate') + } else { + expect(err.toString()).to.be('Error: DEPTH_ZERO_SELF_SIGNED_CERT') + } done(); }) From 5f14bcaa704fe8a5e6f59d3a89722f22958cade9 Mon Sep 17 00:00:00 2001 From: Jeremy Judeaux Date: Thu, 2 Apr 2015 14:23:58 +0200 Subject: [PATCH 395/556] fix protocol and default port detection on node 0.12.x, compatible with 0.10.x --- lib/http-proxy/common.js | 15 ++++++++++++++- lib/http-proxy/passes/web-incoming.js | 2 +- lib/http-proxy/passes/ws-incoming.js | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 225324ebf..a169aafab 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -134,7 +134,20 @@ common.getPort = function(req) { return res ? res[1] : - req.connection.pair ? '443' : '80'; + common.hasEncryptedConnection(req) ? '443' : '80'; +}; + +/** + * Check if the request has an encrypted connection. + * + * @param {Request} req Incoming HTTP request. + * + * @return {Boolean} Whether the connection is encrypted or not. + * + * @api private + */ +common.hasEncryptedConnection = function(req) { + return Boolean(req.connection.encrypted || req.connection.pair); }; /** diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 9f5ec20e0..4070eb316 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -64,7 +64,7 @@ web_o = Object.keys(web_o).map(function(pass) { function XHeaders(req, res, options) { if(!options.xfwd) return; - var encrypted = req.isSpdy || req.connection.encrypted || req.connection.pair; + var encrypted = req.isSpdy || common.hasEncryptedConnection(req); var values = { for : req.connection.remoteAddress || req.socket.remoteAddress, port : common.getPort(req), diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index b72e55702..8264be669 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -57,7 +57,7 @@ var passes = exports; var values = { for : req.connection.remoteAddress || req.socket.remoteAddress, port : common.getPort(req), - proto: req.connection.pair ? 'wss' : 'ws' + proto: common.hasEncryptedConnection(req) ? 'wss' : 'ws' }; ['for', 'port', 'proto'].forEach(function(header) { From c6dfb04a67f3b5ac9a402b7b08c1b8baf29f89e6 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 2 Apr 2015 12:30:55 -0400 Subject: [PATCH 396/556] [fix] properly support iojs with test checking for HTTPS --- test/lib-https-proxy-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js index 643c726a3..e0634cd52 100644 --- a/test/lib-https-proxy-test.js +++ b/test/lib-https-proxy-test.js @@ -1,4 +1,5 @@ var httpProxy = require('../lib/http-proxy'), + semver = require('semver'), expect = require('expect.js'), http = require('http') https = require('https'), @@ -166,7 +167,7 @@ describe('lib/http-proxy.js', function() { proxy.on('error', function (err, req, res) { expect(err).to.be.an(Error); - if (process.versions.node.indexOf('0.12.') == 0) { + if (semver.gt(process.versions.node, '0.12.0')) { expect(err.toString()).to.be('Error: self signed certificate') } else { expect(err.toString()).to.be('Error: DEPTH_ZERO_SELF_SIGNED_CERT') From 1b89bc9a76c229070ff2572f7a0e1b969c4b4701 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 2 Apr 2015 12:31:17 -0400 Subject: [PATCH 397/556] [dist] add semver and normalize package.json with --save-dev --- package.json | 65 +++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/package.json b/package.json index 9c9ae3822..a1c8d2b3e 100644 --- a/package.json +++ b/package.json @@ -1,47 +1,44 @@ { - "name" : "http-proxy", - "version" : "1.10.0", - - "repository" : { - "type" : "git", - "url" : "https://github.com/nodejitsu/node-http-proxy.git" + "name": "http-proxy", + "version": "1.10.0", + "repository": { + "type": "git", + "url": "https://github.com/nodejitsu/node-http-proxy.git" }, - - "description" : "HTTP proxying for the masses", + "description": "HTTP proxying for the masses", "author": "Nodejitsu Inc. ", - "maintainers" : [ + "maintainers": [ "yawnt ", "indexzero " ], - - "main" : "index.js", - - "dependencies" : { - "eventemitter3" : "0.x.x", - "requires-port" : "0.x.x" + "main": "index.js", + "dependencies": { + "eventemitter3": "0.x.x", + "requires-port": "0.x.x" }, "devDependencies": { - "mocha" : "*", - "expect.js" : "*", - "dox" : "*", - "coveralls" : "*", + "async": "*", + "blanket": "*", + "coveralls": "*", + "dox": "*", + "expect.js": "*", + "mocha": "*", "mocha-lcov-reporter": "*", - "blanket" : "*", - "ws" : "~0.5.0", - "socket.io" : "*", - "socket.io-client" : "*", - "async" : "*" + "semver": "^4.3.3", + "socket.io": "*", + "socket.io-client": "*", + "ws": "~0.5.0" }, - "scripts" : { - "coveralls" : "mocha --require blanket --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js", - "blanket" : { "pattern": "lib/http-proxy" }, - "test" : "mocha -R landing test/*-test.js", - "test-cov" : "mocha --require blanket -R html-cov > cov/coverage.html" + "scripts": { + "coveralls": "mocha --require blanket --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js", + "blanket": { + "pattern": "lib/http-proxy" + }, + "test": "mocha -R landing test/*-test.js", + "test-cov": "mocha --require blanket -R html-cov > cov/coverage.html" }, - - "engines" : { - "node" : ">=0.10.0" + "engines": { + "node": ">=0.10.0" }, - - "license" : "MIT" + "license": "MIT" } From a6ae6c499743ddade9db12b9f7404d980c79f683 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 2 Apr 2015 12:32:08 -0400 Subject: [PATCH 398/556] [ci] add 0.12 and iojs to travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index c29c96922..63007cb99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ language: node_js node_js: - "0.10" + - "0.12" + - "iojs" notifications: email: From 0bd446c680e9991accfaa3a6a70e411fdac79164 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 2 Apr 2015 12:41:02 -0400 Subject: [PATCH 399/556] [dist] Version bump. 1.10.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a1c8d2b3e..55b0b68a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.10.0", + "version": "1.10.1", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 934e6c4d54292a1b961452074e02fb5d45da729a Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 20 Apr 2015 16:48:14 -0400 Subject: [PATCH 400/556] [dist] Version bump. 1.11.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 55b0b68a8..cce0bdde8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.10.1", + "version": "1.11.0", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 18c77cafc7d5479502cf5c4d2b663d8f85cfd6d4 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 22 Apr 2015 11:07:13 -0400 Subject: [PATCH 401/556] [fix] use the main export for EE3 --- lib/http-proxy/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index ba04e0dde..f86a7d833 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -1,7 +1,7 @@ var httpProxy = exports, extend = require('util')._extend, parse_url = require('url').parse, - EE3 = require('eventemitter3').EventEmitter, + EE3 = require('eventemitter3'), http = require('http'), https = require('https'), web = require('./passes/web-incoming'), From 607f96c00cbda2a6b881b8ff1db05437dbf4ce77 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 22 Apr 2015 11:07:24 -0400 Subject: [PATCH 402/556] [dist] update to new version of EE3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cce0bdde8..a5f366f4d 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ ], "main": "index.js", "dependencies": { - "eventemitter3": "0.x.x", + "eventemitter3": "1.x.x", "requires-port": "0.x.x" }, "devDependencies": { From d26ef56e1bc2a1232b06c01b4740e3bf35d63eda Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 22 Apr 2015 11:09:05 -0400 Subject: [PATCH 403/556] [fix] dont use bind in the one case we do --- lib/http-proxy/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index f86a7d833..7a5e1d2e8 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -104,7 +104,7 @@ function ProxyServer(options) { return ws[pass]; }); - this.on('error', this.onError.bind(this)); + this.on('error', this.onError, this); } From 7e6c66a7e485a6c0ec3a1c567bbe800fdc56c9fd Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 22 Apr 2015 11:09:36 -0400 Subject: [PATCH 404/556] [dist] Version bump. 1.11.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a5f366f4d..e7633d6f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.11.0", + "version": "1.11.1", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 3f997b92899713057269e8b328da30ffeab36273 Mon Sep 17 00:00:00 2001 From: klammbueddel Date: Thu, 30 Apr 2015 10:19:40 +0200 Subject: [PATCH 405/556] fixes comment --- examples/http/proxy-https-to-https.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/http/proxy-https-to-https.js b/examples/http/proxy-https-to-https.js index e543f98a7..45f0fd7d0 100644 --- a/examples/http/proxy-https-to-https.js +++ b/examples/http/proxy-https-to-https.js @@ -47,7 +47,7 @@ https.createServer(httpsOpts, function (req, res) { }).listen(9010); // -// Create the proxy server listening on port 443 +// Create the proxy server listening on port 8010 // httpProxy.createServer({ ssl: httpsOpts, From 7e82a04a1677f70fb4f5daa429ea2fb1c301801e Mon Sep 17 00:00:00 2001 From: Fernando Montoya Date: Tue, 12 May 2015 21:38:05 -0500 Subject: [PATCH 406/556] Added installation instructions --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index cbdfd2c2a..b38d5035b 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@ node-http-proxy websockets. It is suitable for implementing components such as proxies and load balancers. +### Installation + +`npm install http-proxy --save` + ### Build Status

From 38864d016794b9ff3d8d1d1cb81a730b40a1bf9c Mon Sep 17 00:00:00 2001 From: Alberto Pose Date: Mon, 18 May 2015 20:30:43 -0300 Subject: [PATCH 407/556] Created reverse-proxy.js example. --- examples/http/reverse-proxy.js | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 examples/http/reverse-proxy.js diff --git a/examples/http/reverse-proxy.js b/examples/http/reverse-proxy.js new file mode 100644 index 000000000..1e80d4e93 --- /dev/null +++ b/examples/http/reverse-proxy.js @@ -0,0 +1,54 @@ +/* + reverse-proxy.js: Example of reverse proxying (with HTTPS support) + Copyright (c) 2015 Alberto Pose + + 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'), + net = require('net'), + httpProxy = require('http-proxy'), + url = require('url'), + util = require('util'); + +var proxy = httpProxy.createServer(); + +var server = http.createServer(function (req, res) { + util.puts('Receiving reverse proxy request for:' + req.url); + + proxy.web(req, res, {target: req.url, secure: false}); +}).listen(8213); + +server.on('connect', function (req, socket) { + util.puts('Receiving reverse proxy request for:' + req.url); + + var serverUrl = url.parse('https://' + req.url); + + var srvSocket = net.connect(serverUrl.port, serverUrl.hostname, function() { + socket.write('HTTP/1.1 200 Connection Established\r\n' + + 'Proxy-agent: Node-Proxy\r\n' + + '\r\n'); + srvSocket.pipe(socket); + socket.pipe(srvSocket); + }); +}); + +// Test with: +// curl -vv -x http://127.0.0.1:8213 https://www.google.com +// curl -vv -x http://127.0.0.1:8213 http://www.google.com From fe3dd8363f8f40fa355390685eb8cec59b8cf6d1 Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 9 Jul 2015 08:03:23 -0300 Subject: [PATCH 408/556] Added missing configuration options Added missing config options for httpProxy.createProxyServer. Updated to include all options listed in `lib/http-proxy.js` Addresses nodejitsu/node-http-proxy#851 --- README.md | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b38d5035b..f68fad56f 100644 --- a/README.md +++ b/README.md @@ -339,12 +339,25 @@ proxyServer.listen(8015); `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 - * **xfwd**: true/false, adds x-forward headers - * **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies) - * **hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects. +* **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) +* **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, if you want to verify the SSL Certs +* **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies) +* **prependPath**: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path +* **ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request +* **localAddress**: Local interface string to bind for outgoing connections +* **changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL +* **auth**: Basic authentication i.e. 'user:password' to compute an Authorization header. +* **hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects. +* **autoRewrite**: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. +* **protocolRewrite**: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null. + +**NOTE:** +`options.ws` and `options.ssl` are optional. +`options.target` and `options.forward` cannot both be missing If you are using the `proxyServer.listen` method, the following options are also applicable: From 1f4fccd2c6d16c1ca78f81fcca98cffdd79770ea Mon Sep 17 00:00:00 2001 From: "Stuart P. Bentley" Date: Fri, 14 Aug 2015 09:02:50 -0700 Subject: [PATCH 409/556] Fix broken option list indentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f68fad56f..162bde9b7 100644 --- a/README.md +++ b/README.md @@ -338,7 +338,7 @@ proxyServer.listen(8015); `httpProxy.createProxyServer` supports the following options: - * **target**: url string to be parsed with the url module +* **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) * **ssl**: object to be passed to https.createServer() From 349b843731ecc1ab20aad5ad51e87ec41d4fb235 Mon Sep 17 00:00:00 2001 From: Daniel Levy Date: Mon, 24 Aug 2015 13:23:53 -0600 Subject: [PATCH 410/556] Update gzip-middleware.js Punctuation --- examples/middleware/gzip-middleware.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/middleware/gzip-middleware.js b/examples/middleware/gzip-middleware.js index 756b68fa3..be991b9ff 100644 --- a/examples/middleware/gzip-middleware.js +++ b/examples/middleware/gzip-middleware.js @@ -27,7 +27,7 @@ var util = require('util'), colors = require('colors'), http = require('http'), - connect = require('connect') + connect = require('connect'), httpProxy = require('../../lib/http-proxy'); // From 8bfd90c4d9331fd129f17a788ef9fc733654b7e0 Mon Sep 17 00:00:00 2001 From: Arttu Liimola Date: Thu, 27 Aug 2015 12:53:43 +0300 Subject: [PATCH 411/556] Use raw headers instead parsed. Set-Cookie headers are parsed into single header with cookies in array. This messes up the Set-Cookie headers, because browser receives multiple Set-Cookie headers as single with cookies separted with comma. --- lib/http-proxy/passes/ws-incoming.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 8264be669..1284f6443 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -114,8 +114,10 @@ var passes = exports; 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]; + socket.write(proxyRes.rawHeaders.map(function(v, i, a) { + return !(i % 2) ? v + ": " + a[i+1] : null; + }).filter(function (v) { + return v ? true : false; }).join('\r\n') + '\r\n\r\n'); proxySocket.pipe(socket).pipe(proxySocket); From 855cebdac4d33ef5f2fab4c4c78fdc07cdb61402 Mon Sep 17 00:00:00 2001 From: Arttu Liimola Date: Sun, 30 Aug 2015 19:53:05 +0300 Subject: [PATCH 412/556] Added websocket set-cookie headers test --- test/lib-http-proxy-test.js | 39 ++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 0143293a7..e613605de 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -407,6 +407,43 @@ describe('lib/http-proxy.js', function() { }); - + it('should pass all set-cookie headers to client', 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 key = new Buffer(Math.random().toString(35)).toString('base64'); + + var requestOptions = { + port: ports.proxy, + host: '127.0.0.1', + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Host': 'ws://127.0.0.1', + 'Sec-WebSocket-Version': 13, + 'Sec-WebSocket-Key': key + } + }; + + var req = http.request(requestOptions); + + req.on('upgrade', function (res, socket, upgradeHead) { + expect(res.headers['set-cookie'].length).to.be(2); + done(); + }); + + req.end(); + }); + + destiny.on('headers', function (headers) { + headers.push('Set-Cookie: test1=test1'); + headers.push('Set-Cookie: test2=test2'); + }); + }); + }) }); From da674ec4df2b371f09e912f3b376c48581090a0f Mon Sep 17 00:00:00 2001 From: Arttu Liimola Date: Sun, 30 Aug 2015 22:17:18 +0300 Subject: [PATCH 413/556] Modify the set-cookie header fix to work with node 0.10.x. --- lib/http-proxy/passes/ws-incoming.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 1284f6443..eb77adf76 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -1,5 +1,6 @@ var http = require('http'), https = require('https'), + util = require('util'), common = require('../common'), passes = exports; @@ -113,12 +114,24 @@ var passes = exports; if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead); - socket.write('HTTP/1.1 101 Switching Protocols\r\n'); - socket.write(proxyRes.rawHeaders.map(function(v, i, a) { - return !(i % 2) ? v + ": " + a[i+1] : null; - }).filter(function (v) { - return v ? true : false; - }).join('\r\n') + '\r\n\r\n'); + var writeHead = [ + 'HTTP/1.1 101 Switching Protocols' + ]; + + Object.keys(proxyRes.headers).map(function(i) { + if (util.isArray(proxyRes.headers[i])) { + var a = proxyRes.headers[i]; + var len = a.length; + + for (var x = 0; x < len; x++) { + writeHead.push(i + ": " + a[x]); + } + } else { + writeHead.push(i + ": " + proxyRes.headers[i]); + } + }); + + socket.write(writeHead.join('\r\n') + '\r\n\r\n'); proxySocket.pipe(socket).pipe(proxySocket); server.emit('open', proxySocket); From ca732087498582df01ab78fb7da77912dab8f138 Mon Sep 17 00:00:00 2001 From: Arttu Liimola Date: Sun, 30 Aug 2015 22:19:57 +0300 Subject: [PATCH 414/556] Websocket key was unnecessary long. --- test/lib-http-proxy-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index e613605de..d9eea5150 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -415,7 +415,7 @@ describe('lib/http-proxy.js', function() { }), proxyServer = proxy.listen(ports.proxy), destiny = new ws.Server({ port: ports.source }, function () { - var key = new Buffer(Math.random().toString(35)).toString('base64'); + var key = new Buffer(Math.random().toString()).toString('base64'); var requestOptions = { port: ports.proxy, From 3d2350c54ff0fb9271f5fcfea1d23f22ad97c47c Mon Sep 17 00:00:00 2001 From: Arttu Liimola Date: Sun, 30 Aug 2015 22:30:09 +0300 Subject: [PATCH 415/556] Replaced Object.keys().map with for in loop. --- lib/http-proxy/passes/ws-incoming.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index eb77adf76..1d57b78c3 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -118,7 +118,7 @@ var passes = exports; 'HTTP/1.1 101 Switching Protocols' ]; - Object.keys(proxyRes.headers).map(function(i) { + for(var i in proxyRes.headers) { if (util.isArray(proxyRes.headers[i])) { var a = proxyRes.headers[i]; var len = a.length; @@ -129,7 +129,7 @@ var passes = exports; } else { writeHead.push(i + ": " + proxyRes.headers[i]); } - }); + } socket.write(writeHead.join('\r\n') + '\r\n\r\n'); proxySocket.pipe(socket).pipe(proxySocket); From cea0e8676b3e609828320bb03051eaf78cc43b54 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sun, 30 Aug 2015 17:28:05 -0400 Subject: [PATCH 416/556] [fix] make more functional --- lib/http-proxy/passes/ws-incoming.js | 38 +++++++++++++++------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 1d57b78c3..f51785749 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -1,6 +1,5 @@ var http = require('http'), https = require('https'), - util = require('util'), common = require('../common'), passes = exports; @@ -114,24 +113,27 @@ var passes = exports; if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead); - var writeHead = [ - 'HTTP/1.1 101 Switching Protocols' - ]; - - for(var i in proxyRes.headers) { - if (util.isArray(proxyRes.headers[i])) { - var a = proxyRes.headers[i]; - var len = a.length; - - for (var x = 0; x < len; x++) { - writeHead.push(i + ": " + a[x]); - } - } else { - writeHead.push(i + ": " + proxyRes.headers[i]); - } - } + // + // Remark: Handle writing the headers to the socket when switching protocols + // Also handles when a header is an array + // + socket.write( + Object.keys(proxyRes.headers).reduce(function (head, key) { + var value = proxyRes.headers[key]; + + if (!Array.isArray(value)) { + head.push(key + ': ' + value); + return head; + } + + for (var i = 0; i < value.length; i++) { + head.push(key + ': ' + value[i]); + } + return head; + }, ['HTTP/1.1 101 Switching Protocols']) + .join('\r\n') + '\r\n\r\n' + ); - socket.write(writeHead.join('\r\n') + '\r\n\r\n'); proxySocket.pipe(socket).pipe(proxySocket); server.emit('open', proxySocket); From 30e3b371de0116e40e15156394f31c7e0b0aa9f1 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sun, 30 Aug 2015 17:29:25 -0400 Subject: [PATCH 417/556] [dist] Version bump. 1.11.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e7633d6f5..88102be7e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.11.1", + "version": "1.11.2", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 302d981dd2cf06dbf751b1f64e3dfea08d0f9476 Mon Sep 17 00:00:00 2001 From: indexzero Date: Mon, 21 Sep 2015 18:22:31 -0700 Subject: [PATCH 418/556] [dist] Update .travis.yml to be more modern. --- .travis.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 63007cb99..f5dda471b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,22 @@ +sudo: false language: node_js node_js: - "0.10" - "0.12" - - "iojs" + - "4.1" + +before_install: + - travis_retry npm install -g npm@2.14.5 + - travis_retry npm install + +script: + - npm test + +matrix: + allow_failures: + - node_js: "4.1" notifications: email: - travis@nodejitsu.com irc: "irc.freenode.org#nodejitsu" - -script: - npm test From c86ae51bb9658309a9628f4f5182d4c45c803b84 Mon Sep 17 00:00:00 2001 From: chimurai Date: Mon, 13 Apr 2015 20:50:42 +0200 Subject: [PATCH 419/556] docs: options.headers --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 162bde9b7..dc29ee9a3 100644 --- a/README.md +++ b/README.md @@ -354,6 +354,7 @@ proxyServer.listen(8015); * **hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects. * **autoRewrite**: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. * **protocolRewrite**: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null. + * **headers**: object with extra headers to be added to target requests. **NOTE:** `options.ws` and `options.ssl` are optional. From e666a4e07d30f287041567497dda0a49988d151b Mon Sep 17 00:00:00 2001 From: Don Mai Date: Sun, 18 Oct 2015 01:12:19 -0700 Subject: [PATCH 420/556] Updating the upgrading doc Recently ran into a case where I had to upgrade the `http-proxy` version for an app, and that app was using a proxy table. I'm not sure how many users are still using the 0.x.x version of `http-proxy`, but the added link (found from one of the GH issues) may encourage them to switch over to 1.x.x if they were using the old version due to its proxy table support and the activation energy to upgrade was too high. I might release a module for this eventually, lol, since there was some work involved in creating a proxy table to map paths to paths for the same hostname. --- UPGRADING.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/UPGRADING.md b/UPGRADING.md index c28bbfedf..0e8942726 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -92,5 +92,6 @@ which were in the core and delegate them to eventual "userland" modules. 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) +### ProxyTable API - +See this [link](http://blog.nodejitsu.com/node-http-proxy-1dot0/) for an example of how to add proxy table functionality using the new API. From eb97bf5423a5d7ebf8e569abe7105a78f28cba8c Mon Sep 17 00:00:00 2001 From: donasaur Date: Sun, 18 Oct 2015 13:04:06 -0700 Subject: [PATCH 421/556] Removed unspecified trailing slash in proxy url --- lib/http-proxy/common.js | 2 +- test/lib-http-proxy-common-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 1d040d405..577f9b438 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -80,7 +80,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { // Remark: Can we somehow not use url.parse as a perf optimization? // var outgoingPath = !options.toProxy - ? (url.parse(req.url).path || '/') + ? (url.parse(req.url).path || '') : req.url; // diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 4a1f0d375..1c5fe47c9 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -332,7 +332,7 @@ describe('lib/http-proxy/common.js', function () { { path: '' } }, { url : '' }); - expect(outgoing.path).to.be('/'); + expect(outgoing.path).to.be(''); }); }); From 60baca5aed4f45ef1d7b3f7edd909375853d344b Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 19 Oct 2015 09:30:18 -0400 Subject: [PATCH 422/556] [dist] Version bump. 1.11.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 88102be7e..3f59d8f21 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.11.2", + "version": "1.11.3", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From a05fc2d1692d038f1eaad6d9b26c174039bc1949 Mon Sep 17 00:00:00 2001 From: Laurent Brucher Date: Thu, 22 Oct 2015 15:56:34 +0200 Subject: [PATCH 423/556] Provide a "proxyReq" event also for websocket connections. --- README.md | 2 ++ lib/http-proxy/passes/ws-incoming.js | 4 +++ test/lib-http-proxy-test.js | 43 ++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/README.md b/README.md index 162bde9b7..0bc800fc8 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,8 @@ http.createServer(function (req, res) { #### Listening for proxy events * `error`: The error event is emitted if the request to the target fail. +* `proxyReq`: This event is emitted before the data is sent. It gives you a chance to alter the proxyReq request object. Applies to "web" connections +* `proxyReqWs`: This event is emitted before the data is sent. It gives you a chance to alter the proxyReq request object. Applies to "websocket" connections * `proxyRes`: This event is emitted if the request to the target got a response. * `open`: This event is emitted once the proxy websocket was created and piped into the target websocket. * `close`: This event is emitted once the proxy websocket was closed. diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index f51785749..87f5fe1a0 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -87,6 +87,10 @@ var passes = exports; var proxyReq = (common.isSSL.test(options.target.protocol) ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req) ); + + // Enable developers to modify the proxyReq before headers are sent + if(server) { server.emit('proxyReqWs', proxyReq, req, socket, options, head); } + // Error Handler proxyReq.on('error', onOutgoingError); proxyReq.on('response', function (res) { diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index d9eea5150..08403828b 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -444,6 +444,49 @@ describe('lib/http-proxy.js', function() { headers.push('Set-Cookie: test2=test2'); }); }); + + it('should detect a proxyReq event and modify headers', function (done) { + var ports = { source: gen.port, proxy: gen.port }, + proxy, + proxyServer, + destiny; + + proxy = httpProxy.createProxyServer({ + target: 'ws://127.0.0.1:' + ports.source, + ws: true + }); + + proxy.on('proxyReqWs', function(proxyReq, req, res, options) { + proxyReq.setHeader('X-Special-Proxy-Header', 'foobar'); + }); + + 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.close(); + destiny.close(); + done(); + }); + }); + + destiny.on('connection', function (socket) { + expect(socket.upgradeReq.headers['x-special-proxy-header']).to.eql('foobar'); + + socket.on('message', function (msg) { + expect(msg).to.be('hello there'); + socket.send('Hello over websockets'); + }); + }); + }); }) }); From 9752652e76da3bcfb6a635620e4162518ca43203 Mon Sep 17 00:00:00 2001 From: Laurent Brucher Date: Thu, 22 Oct 2015 18:38:58 +0200 Subject: [PATCH 424/556] fixes after PR review --- lib/http-proxy/passes/ws-incoming.js | 2 +- test/lib-http-proxy-test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 87f5fe1a0..a6ddb3125 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -89,7 +89,7 @@ var passes = exports; ); // Enable developers to modify the proxyReq before headers are sent - if(server) { server.emit('proxyReqWs', proxyReq, req, socket, options, head); } + if (server) { server.emit('proxyReqWs', proxyReq, req, socket, options, head); } // Error Handler proxyReq.on('error', onOutgoingError); diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 08403828b..49e8a8687 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -456,7 +456,7 @@ describe('lib/http-proxy.js', function() { ws: true }); - proxy.on('proxyReqWs', function(proxyReq, req, res, options) { + proxy.on('proxyReqWs', function(proxyReq, req, socket, options, head) { proxyReq.setHeader('X-Special-Proxy-Header', 'foobar'); }); From b5a6d0e58396363f4c457f6d1654614bdfcfcb73 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 22 Oct 2015 19:27:24 -0400 Subject: [PATCH 425/556] [dist] Version bump. 1.12.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3f59d8f21..b150bdf93 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.11.3", + "version": "1.12.0", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 64fa52078913c6d4fe95673f182aac4924961e8b Mon Sep 17 00:00:00 2001 From: glortho Date: Wed, 28 Oct 2015 15:52:37 -0400 Subject: [PATCH 426/556] Add tests for testing forwarding of continuation frames This adds two tests that send payloads below and at the threshold for continuation frames. Using node 0.12.7 both tests pass. Using node 4.1.2 the test below the threshold passes but the other fails. --- test/lib-http-proxy-test.js | 65 ++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 49e8a8687..6380b8bce 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -487,6 +487,69 @@ describe('lib/http-proxy.js', function() { }); }); }); + + it('should forward frames with single frame payload (including on node 4.x)', function (done) { + var payload = Array(65529).join('0'); + 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(payload); + }); + + client.on('message', function (msg) { + expect(msg).to.be('Hello over websockets'); + client.close(); + proxyServer.close(); + destiny.close(); + done(); + }); + }); + + destiny.on('connection', function (socket) { + socket.on('message', function (msg) { + expect(msg).to.be(payload); + socket.send('Hello over websockets'); + }); + }); + }); - }) + it('should forward continuation frames with big payload (including on node 4.x)', function (done) { + var payload = Array(65530).join('0'); + 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(payload); + }); + + client.on('message', function (msg) { + expect(msg).to.be('Hello over websockets'); + client.close(); + proxyServer.close(); + destiny.close(); + done(); + }); + }); + + destiny.on('connection', function (socket) { + socket.on('message', function (msg) { + expect(msg).to.be(payload); + socket.send('Hello over websockets'); + }); + }); + }); + }); }); From 5d593e8ef11d8fcb8de40afe3464bd9a92d9cec1 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Fri, 30 Oct 2015 14:14:03 -0700 Subject: [PATCH 427/556] [example] add an example for NTLM authentication --- examples/http/ntlm-authentication.js | 26 ++++++++++++++++++++++++++ examples/package.json | 7 ++++--- 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 examples/http/ntlm-authentication.js diff --git a/examples/http/ntlm-authentication.js b/examples/http/ntlm-authentication.js new file mode 100644 index 000000000..5634ded4b --- /dev/null +++ b/examples/http/ntlm-authentication.js @@ -0,0 +1,26 @@ +var httpProxy = require('http-proxy'); +var Agent = require('agentkeepalive'); + +var agent = new Agent({ + maxSockets: 100, + keepAlive: true, + maxFreeSockets: 10, + keepAliveMsecs:1000, + timeout: 60000, + keepAliveTimeout: 30000 // free socket keepalive for 30 seconds +}); + +var proxy = httpProxy.createProxy({ target: 'http://whatever.com', agent: agent); + +// +// Modify headers of the request before it gets sent +// So that we handle the NLTM authentication request +// +proxy.on('proxyRes', function (proxyRes) { + var key = 'www-authenticate'; + proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(','); +}); + +require('http').createServer(function (req, res) { + proxy.web(req, res); +}).listen(3000); diff --git a/examples/package.json b/examples/package.json index 3daede1f1..9bc57095a 100644 --- a/examples/package.json +++ b/examples/package.json @@ -3,11 +3,12 @@ "description": "packages required to run the examples", "version": "0.0.0", "dependencies": { + "agentkeepalive": "^2.0.3", "colors": "~0.6.2", - "socket.io": "~0.9.16", - "socket.io-client": "~0.9.16", "connect": "~2.11.0", + "connect-restreamer": "~1.0.0", "request": "~2.27.0", - "connect-restreamer": "~1.0.0" + "socket.io": "~0.9.16", + "socket.io-client": "~0.9.16" } } From 9ea1e89a2fd9c392cd40265bdb13494a3614e290 Mon Sep 17 00:00:00 2001 From: Shinnosuke Watanabe Date: Thu, 5 Nov 2015 17:49:45 +0900 Subject: [PATCH 428/556] [fix] bump requires-port, server and ws npm v3 tries to dedupe the dependencies by default, and keeping dependencies up-to-date helps better deduplication. https://github.com/unshiftio/requires-port https://github.com/npm/node-semver https://github.com/websockets/ws --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index b150bdf93..b003eb8c7 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "main": "index.js", "dependencies": { "eventemitter3": "1.x.x", - "requires-port": "0.x.x" + "requires-port": "1.x.x" }, "devDependencies": { "async": "*", @@ -24,10 +24,10 @@ "expect.js": "*", "mocha": "*", "mocha-lcov-reporter": "*", - "semver": "^4.3.3", + "semver": "^5.0.3", "socket.io": "*", "socket.io-client": "*", - "ws": "~0.5.0" + "ws": "^0.8.0" }, "scripts": { "coveralls": "mocha --require blanket --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js", From f82ce18d2f187b085c2c4f49d857755d21c582b1 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 9 Nov 2015 19:43:18 -0800 Subject: [PATCH 429/556] [ci] use node 4.2 to test and do not allow failures --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index f5dda471b..0570d5071 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: node_js node_js: - "0.10" - "0.12" - - "4.1" + - "4.2" before_install: - travis_retry npm install -g npm@2.14.5 @@ -12,10 +12,6 @@ before_install: script: - npm test -matrix: - allow_failures: - - node_js: "4.1" - notifications: email: - travis@nodejitsu.com From eea79cab53f27371cad387a524ee3aaefa742c48 Mon Sep 17 00:00:00 2001 From: donasaur Date: Fri, 20 Nov 2015 17:28:37 -0800 Subject: [PATCH 430/556] Updated markdown docs to mention proxy rules --- README.md | 3 +++ UPGRADING.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0bc800fc8..a07ac8117 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,9 @@ proxyServer.on('upgrade', function (req, socket, head) { proxyServer.listen(8015); ``` +#### ProxyTable API +A proxy table API is available through through this add-on [module](https://github.com/donasaur/http-proxy-rules), which lets you define a set of rules to translate matching routes to target routes that the reverse proxy will talk to. + ### Contributing and Issues * Search on Google/Github diff --git a/UPGRADING.md b/UPGRADING.md index 0e8942726..f77243dc9 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -94,4 +94,4 @@ The new API makes it really easy to implement code that behaves like the old Mid ### ProxyTable API -See this [link](http://blog.nodejitsu.com/node-http-proxy-1dot0/) for an example of how to add proxy table functionality using the new API. +See this [link](https://github.com/donasaur/http-proxy-rules/) for an add-on proxy rules module that you can use to simulate the old ProxyTable API. From cd1d7776e8fb5d67e2c52b9ef27d8c932e7b72e2 Mon Sep 17 00:00:00 2001 From: donasaur Date: Mon, 23 Nov 2015 09:30:05 -0800 Subject: [PATCH 431/556] Organized README more --- README.md | 200 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 113 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index a07ac8117..af6705932 100644 --- a/README.md +++ b/README.md @@ -5,24 +5,46 @@ 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. +### Table of Contents + * [Installation](#installation) + * [Upgrading from 0.8.x ?](#upgrade-from-08x) + * [Core Concept](#core-concept) + * [Use Cases](#use-cases) + * [Setup a basic stand-alone proxy server](#setup-a-basic-stand-alone-proxy-server) + * [Setup a stand-alone proxy server with custom server logic](#setup-a-stand-alone-proxy-server-with-custom-server-logic) + * [Setup a stand-alone proxy server with proxy request header re-writing](#setup-a-stand-alone-proxy-server-with-proxy-request-header-re-writing) + * [Modify a response from a proxied server](#modify-a-response-from-a-proxied-server) + * [Setup a stand-alone proxy server with latency](#setup-a-stand-alone-proxy-server-with-latency) + * [Using HTTPS](#using-https) + * [Proxying WebSockets](#proxying-websockets) + * [Options](#options) + * [Listening for proxy events](#listening-for-proxy-events) + * [Shutdown](#shutdown) + * [Miscellaneous](#miscellaneous) + * [Test](#test) + * [ProxyTable API](#proxytable-api) + * [Logo](#logo) + * [Contributing and Issues](#contributing-and-issues) + * [License](#license) + ### Installation `npm install http-proxy --save` -### Build Status - -

- -    - - -

+### Upgrading from 0.8.x ? -### Looking to Upgrade from 0.8.x ? Click [here](UPGRADING.md) +Click [here](UPGRADING.md) ### Core Concept @@ -32,8 +54,9 @@ an `options` object as argument ([valid properties are available here](lib/http- ```javascript var httpProxy = require('http-proxy'); -var proxy = httpProxy.createProxyServer(options); +var proxy = httpProxy.createProxyServer(options); // See (†) ``` +†Unless listen(..) is invoked on the object, this does not create a webserver. See below. An object will be returned with four values: @@ -70,6 +93,7 @@ The first pipeline (ingoing) is responsible for the creation and manipulation of The second pipeline (outgoing) is responsible for the creation and manipulation of the stream that, from your target, returns data to the client. +### Use Cases #### Setup a basic stand-alone proxy server @@ -79,7 +103,7 @@ var http = require('http'), // // Create your proxy server and set the target in the options. // -httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); +httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); // See (†) // // Create your target server @@ -90,6 +114,7 @@ http.createServer(function (req, res) { res.end(); }).listen(9000); ``` +†Invoking listen(..) triggers the creation of a web server. Otherwise, just the proxy instance is created. #### Setup a stand-alone proxy server with custom server logic This example show how you can proxy a request using your own HTTP server @@ -118,11 +143,6 @@ var server = http.createServer(function(req, res) { console.log("listening on port 5050") server.listen(5050); ``` -#### Modify a response from a proxied server -Sometimes when you have received a HTML/XML document from the server of origin you would like to modify it before forwarding it on. - -[Harmon](https://github.com/No9/harmon) allows you to do this in a streaming style so as to keep the pressure on the proxy to a minimum. - #### Setup a stand-alone proxy server with proxy request header re-writing This example shows how you can proxy a request using your own HTTP server that @@ -161,6 +181,11 @@ console.log("listening on port 5050") server.listen(5050); ``` +#### Modify a response from a proxied server +Sometimes when you have received a HTML/XML document from the server of origin you would like to modify it before forwarding it on. + +[Harmon](https://github.com/No9/harmon) allows you to do this in a streaming style so as to keep the pressure on the proxy to a minimum. + #### Setup a stand-alone proxy server with latency ```js @@ -195,62 +220,6 @@ http.createServer(function (req, res) { }).listen(9008); ``` -#### Listening for proxy events - -* `error`: The error event is emitted if the request to the target fail. -* `proxyReq`: This event is emitted before the data is sent. It gives you a chance to alter the proxyReq request object. Applies to "web" connections -* `proxyReqWs`: This event is emitted before the data is sent. It gives you a chance to alter the proxyReq request object. Applies to "websocket" connections -* `proxyRes`: This event is emitted if the request to the target got a response. -* `open`: This event is emitted once the proxy websocket was created and piped into the target websocket. -* `close`: This event is emitted once the proxy websocket was closed. -* (DEPRECATED) `proxySocket`: Deprecated in favor of `open`. - -```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 (proxyRes, req, res) { - console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2)); -}); - -// -// Listen for the `open` event on `proxy`. -// -proxy.on('open', function (proxySocket) { - // listen for messages coming FROM the target here - proxySocket.on('data', hybiParseAndLogMessage); -}); - -// -// Listen for the `close` event on `proxy`. -// -proxy.on('close', function (req, socket, head) { - // view disconnected websocket connections - console.log('Client disconnected'); -}); -``` - #### 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. @@ -328,17 +297,6 @@ proxyServer.on('upgrade', function (req, socket, head) { proxyServer.listen(8015); ``` -#### ProxyTable API -A proxy table API is available through through this add-on [module](https://github.com/donasaur/http-proxy-rules), which lets you define a set of rules to translate matching routes to target routes that the reverse proxy will talk to. - -### 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: @@ -369,6 +327,62 @@ If you are using the `proxyServer.listen` method, the following options are also * **ssl**: object to be passed to https.createServer() * **ws**: true/false, if you want to proxy websockets +### Listening for proxy events + +* `error`: The error event is emitted if the request to the target fail. **We do not do any error handling of messages passed between client and proxy, and messages passed between proxy and target, so it is recommended that you listen on errors and handle them.** +* `proxyReq`: This event is emitted before the data is sent. It gives you a chance to alter the proxyReq request object. Applies to "web" connections +* `proxyReqWs`: This event is emitted before the data is sent. It gives you a chance to alter the proxyReq request object. Applies to "websocket" connections +* `proxyRes`: This event is emitted if the request to the target got a response. +* `open`: This event is emitted once the proxy websocket was created and piped into the target websocket. +* `close`: This event is emitted once the proxy websocket was closed. +* (DEPRECATED) `proxySocket`: Deprecated in favor of `open`. + +```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 (proxyRes, req, res) { + console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2)); +}); + +// +// Listen for the `open` event on `proxy`. +// +proxy.on('open', function (proxySocket) { + // listen for messages coming FROM the target here + proxySocket.on('data', hybiParseAndLogMessage); +}); + +// +// Listen for the `close` event on `proxy`. +// +proxy.on('close', function (req, socket, head) { + // view disconnected websocket connections + console.log('Client disconnected'); +}); +``` + ### Shutdown * When testing or running server within another program it may be necessary to close the proxy. @@ -385,16 +399,30 @@ var proxy = new httpProxy.createProxyServer({ proxy.close(); ``` -### Test +### Miscellaneous + +#### ProxyTable API + +A proxy table API is available through through this add-on [module](https://github.com/donasaur/http-proxy-rules), which lets you define a set of rules to translate matching routes to target routes that the reverse proxy will talk to. + +#### Test ``` $ npm test ``` -### Logo +#### Logo Logo created by [Diego Pasquali](http://dribbble.com/diegopq) +### 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) + ### License >The MIT License (MIT) @@ -418,5 +446,3 @@ Logo created by [Diego Pasquali](http://dribbble.com/diegopq) >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. - - From 6106d4c32f7c7960f0391591661e6f0d229db52d Mon Sep 17 00:00:00 2001 From: donasaur Date: Mon, 23 Nov 2015 09:42:26 -0800 Subject: [PATCH 432/556] Added back to top helpers --- README.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af6705932..f424a9669 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ proxies and load balancers. ### Table of Contents * [Installation](#installation) - * [Upgrading from 0.8.x ?](#upgrade-from-08x) + * [Upgrading from 0.8.x ?](#upgrading-from-08x-) * [Core Concept](#core-concept) * [Use Cases](#use-cases) * [Setup a basic stand-alone proxy server](#setup-a-basic-stand-alone-proxy-server) @@ -42,10 +42,14 @@ proxies and load balancers. `npm install http-proxy --save` +**[Back to top](#table-of-contents)** + ### Upgrading from 0.8.x ? Click [here](UPGRADING.md) +**[Back to top](#table-of-contents)** + ### Core Concept A new proxy is created by calling `createProxyServer` and passing @@ -93,6 +97,8 @@ The first pipeline (ingoing) is responsible for the creation and manipulation of The second pipeline (outgoing) is responsible for the creation and manipulation of the stream that, from your target, returns data to the client. +**[Back to top](#table-of-contents)** + ### Use Cases #### Setup a basic stand-alone proxy server @@ -116,6 +122,8 @@ http.createServer(function (req, res) { ``` †Invoking listen(..) triggers the creation of a web server. Otherwise, just the proxy instance is created. +**[Back to top](#table-of-contents)** + #### 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. @@ -144,6 +152,8 @@ console.log("listening on port 5050") server.listen(5050); ``` +**[Back to top](#table-of-contents)** + #### Setup a stand-alone proxy server with proxy request header re-writing This example shows how you can proxy a request using your own HTTP server that modifies the outgoing proxy request by adding a special header. @@ -181,11 +191,15 @@ console.log("listening on port 5050") server.listen(5050); ``` +**[Back to top](#table-of-contents)** + #### Modify a response from a proxied server Sometimes when you have received a HTML/XML document from the server of origin you would like to modify it before forwarding it on. [Harmon](https://github.com/No9/harmon) allows you to do this in a streaming style so as to keep the pressure on the proxy to a minimum. +**[Back to top](#table-of-contents)** + #### Setup a stand-alone proxy server with latency ```js @@ -220,6 +234,8 @@ http.createServer(function (req, res) { }).listen(9008); ``` +**[Back to top](#table-of-contents)** + #### 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. @@ -257,6 +273,8 @@ httpProxy.createServer({ }).listen(443); ``` +**[Back to top](#table-of-contents)** + #### Proxying WebSockets You can activate the websocket support for the proxy using `ws:true` in the options. @@ -297,6 +315,8 @@ proxyServer.on('upgrade', function (req, socket, head) { proxyServer.listen(8015); ``` +**[Back to top](#table-of-contents)** + ### Options `httpProxy.createProxyServer` supports the following options: @@ -327,6 +347,8 @@ If you are using the `proxyServer.listen` method, the following options are also * **ssl**: object to be passed to https.createServer() * **ws**: true/false, if you want to proxy websockets +**[Back to top](#table-of-contents)** + ### Listening for proxy events * `error`: The error event is emitted if the request to the target fail. **We do not do any error handling of messages passed between client and proxy, and messages passed between proxy and target, so it is recommended that you listen on errors and handle them.** @@ -383,6 +405,8 @@ proxy.on('close', function (req, socket, head) { }); ``` +**[Back to top](#table-of-contents)** + ### Shutdown * When testing or running server within another program it may be necessary to close the proxy. @@ -399,6 +423,8 @@ var proxy = new httpProxy.createProxyServer({ proxy.close(); ``` +**[Back to top](#table-of-contents)** + ### Miscellaneous #### ProxyTable API @@ -415,6 +441,8 @@ $ npm test Logo created by [Diego Pasquali](http://dribbble.com/diegopq) +**[Back to top](#table-of-contents)** + ### Contributing and Issues * Search on Google/Github @@ -423,6 +451,8 @@ Logo created by [Diego Pasquali](http://dribbble.com/diegopq) * Commit to your local branch (which must be different from `master`) * Submit your Pull Request (be sure to include tests and update documentation) +**[Back to top](#table-of-contents)** + ### License >The MIT License (MIT) From e4760727f1b8d652abfeaa407f5ddfd252e9483e Mon Sep 17 00:00:00 2001 From: "Aaron T. Maturen" Date: Sun, 6 Dec 2015 19:34:42 -0500 Subject: [PATCH 433/556] SSE example and test --- examples/http/sse.js | 67 +++++++++++++++++++++++++++++++++++++ examples/package.json | 3 +- package.json | 1 + test/lib-http-proxy-test.js | 37 +++++++++++++++++++- 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 examples/http/sse.js diff --git a/examples/http/sse.js b/examples/http/sse.js new file mode 100644 index 000000000..b6e3f065c --- /dev/null +++ b/examples/http/sse.js @@ -0,0 +1,67 @@ +/* + sse.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'), + SSE = require('sse'); + +// +// Basic Http Proxy Server +// +var proxy = new httpProxy.createProxyServer(); +http.createServer(function (req, res) { + proxy.web(req, res, { + target: 'http://localhost:9003' + }); +}).listen(8003); + +// +// Target Http Server +// +var server = http.createServer(function(req, res) { + res.writeHead(200, {'Content-Type': 'text/html'}); + res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2)); + res.end(); +}); + +// +// Use SSE +// + +var sse = new SSE(server, {path: '/'}); +sse.on('connection', function(client) { + var count = 0; + setInterval(function(){ + client.send('message #' + count++); + }, 1500); +}); + +server.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); diff --git a/examples/package.json b/examples/package.json index 9bc57095a..93cc86519 100644 --- a/examples/package.json +++ b/examples/package.json @@ -9,6 +9,7 @@ "connect-restreamer": "~1.0.0", "request": "~2.27.0", "socket.io": "~0.9.16", - "socket.io-client": "~0.9.16" + "socket.io-client": "~0.9.16", + "sse": "0.0.6" } } diff --git a/package.json b/package.json index b003eb8c7..c951425ff 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "semver": "^5.0.3", "socket.io": "*", "socket.io-client": "*", + "sse": "0.0.6", "ws": "^0.8.0" }, "scripts": { diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 6380b8bce..edbb6f9f1 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -3,6 +3,7 @@ var httpProxy = require('../lib/http-proxy'), http = require('http'), ws = require('ws') io = require('socket.io'), + SSE = require('sse'), ioClient = require('socket.io-client'); // @@ -62,6 +63,41 @@ describe('lib/http-proxy.js', function() { }); describe('#createProxyServer using the web-incoming passes', function () { + it('should proxy sse', function(done){ + var ports = { source: gen.port, proxy: gen.port }, + proxy = httpProxy.createProxyServer({ + target: 'http://localhost:' + ports.source, + }), + proxyServer = proxy.listen(ports.proxy), + source = http.createServer(), + sse = new SSE(source, {path: '/'}); + + sse.on('connection', function(client) { + client.send('Hello over SSE'); + client.close(); + }); + + source.listen(ports.source); + + var options = { + hostname: 'localhost', + port: ports.proxy, + }; + + var req = http.request(options, function(res) { + var streamData = ''; + res.on('data', function (chunk) { + streamData += chunk.toString('utf8'); + }); + res.on('end', function (chunk) { + expect(streamData).to.equal(':ok\n\ndata: Hello over SSE\n\n'); + source.close(); + proxy.close(); + done(); + }); + }).end(); + }); + it('should make the request on pipe and finish it', function(done) { var ports = { source: gen.port, proxy: gen.port }; var proxy = httpProxy.createProxyServer({ @@ -336,7 +372,6 @@ describe('lib/http-proxy.js', function() { }); }); - it('should proxy a socket.io stream', function (done) { var ports = { source: gen.port, proxy: gen.port }, proxy = httpProxy.createProxyServer({ From 41414a56a11ddfac3a337711ac4c64124eb62377 Mon Sep 17 00:00:00 2001 From: "Afriza N. Arief" Date: Mon, 4 Jan 2016 12:40:05 +0800 Subject: [PATCH 434/556] README.md: introduction to specify reverse proxy clarify proxy type to be reverse proxy in the introduction --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f424a9669..91722e7b6 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ node-http-proxy

`node-http-proxy` is an HTTP programmable proxying library that supports -websockets. It is suitable for implementing components such as +websockets. It is suitable for implementing components such as reverse proxies and load balancers. ### Table of Contents From f2093b5313c855cd6309cc0ddebb31f369e525ed Mon Sep 17 00:00:00 2001 From: Torstein Thune Date: Wed, 13 Jan 2016 09:16:50 +0100 Subject: [PATCH 435/556] No longer appends / to path if ignorePath is set --- lib/http-proxy/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 577f9b438..d143cf9f1 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -88,7 +88,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { // path is. This can be labeled as FOOT-GUN material if you do not know what // you are doing and are using conflicting options. // - outgoingPath = !options.ignorePath ? outgoingPath : '/'; + outgoingPath = !options.ignorePath ? outgoingPath : ''; outgoing.path = common.urlJoin(targetPath, outgoingPath); From f9540de7b13f41091be2dcb68d8f23be65ad3885 Mon Sep 17 00:00:00 2001 From: Torstein Thune Date: Wed, 13 Jan 2016 15:24:46 +0100 Subject: [PATCH 436/556] Fixed tests depending on ignorePath --- test/lib-http-proxy-common-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index 1c5fe47c9..e118f2e61 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -250,7 +250,7 @@ describe('lib/http-proxy/common.js', function () { ignorePath: true }, { url: '/more/crazy/pathness' }); - expect(outgoing.path).to.eql('/some/crazy/path/whoooo/'); + expect(outgoing.path).to.eql('/some/crazy/path/whoooo'); }); it('and prependPath: false, it should ignore path of target and incoming request', function () { @@ -262,7 +262,7 @@ describe('lib/http-proxy/common.js', function () { prependPath: false }, { url: '/more/crazy/pathness' }); - expect(outgoing.path).to.eql('/'); + expect(outgoing.path).to.eql(''); }); }); From 0cb1d3c68e793fed9aa4a7624c32a018e796aa95 Mon Sep 17 00:00:00 2001 From: Torstein Thune Date: Wed, 13 Jan 2016 15:27:51 +0100 Subject: [PATCH 437/556] Added note for appending trailing / when using ignorePath --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f424a9669..82fae255b 100644 --- a/README.md +++ b/README.md @@ -330,7 +330,7 @@ proxyServer.listen(8015); * **secure**: true/false, if you want to verify the SSL Certs * **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies) * **prependPath**: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path -* **ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request +* **ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required). * **localAddress**: Local interface string to bind for outgoing connections * **changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL * **auth**: Basic authentication i.e. 'user:password' to compute an Authorization header. From 3b39d2c3dcb1785cc06043fcb226c652f554941e Mon Sep 17 00:00:00 2001 From: merpnderp Date: Fri, 22 Jan 2016 09:17:14 -0600 Subject: [PATCH 438/556] Added check to passes/web-outgoing.js to make sure the header being set is not undefined, which should be the only falsey value that could accidently show up and break that call. This fixes windows NTLM auth issues behind http-proxy. --- lib/http-proxy/passes/web-outgoing.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 977f1f747..ad8b8d0c8 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -82,7 +82,9 @@ var redirectRegex = /^30(1|2|7|8)$/; */ function writeHeaders(req, res, proxyRes) { Object.keys(proxyRes.headers).forEach(function(key) { - res.setHeader(key, proxyRes.headers[key]); + if(proxyRes.headers[key] != undefined){ + res.setHeader(key, proxyRes.headers[key]); + } }); }, From e017fa8189254f6aeabd000a2e9e45f354a597fe Mon Sep 17 00:00:00 2001 From: Kaleb Murphy Date: Sun, 24 Jan 2016 14:11:12 -0600 Subject: [PATCH 439/556] Bump version for npm publish Would be great to get the NTLM fix into npm. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c951425ff..e7383e054 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.12.0", + "version": "1.12.1", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From a76e226221b1e288880d13c3136a08a5dd748425 Mon Sep 17 00:00:00 2001 From: Prayag Verma Date: Tue, 26 Jan 2016 14:12:24 +0530 Subject: [PATCH 440/556] Update license year range to 2016 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f424a9669..85d08c9d5 100644 --- a/README.md +++ b/README.md @@ -457,7 +457,7 @@ Logo created by [Diego Pasquali](http://dribbble.com/diegopq) >The MIT License (MIT) > ->Copyright (c) 2010 - 2013 Nodejitsu Inc. +>Copyright (c) 2010 - 2016 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 From 268994ea45d9f8737343001ab9542e03023a5c96 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 26 Jan 2016 17:11:50 -0500 Subject: [PATCH 441/556] [dist] Version bump. 1.13.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e7383e054..9df7d8033 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.12.1", + "version": "1.13.0", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 7bad3fbca4168269bede5d25dfe0134660efc4a9 Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 28 Jan 2016 13:22:28 -0500 Subject: [PATCH 442/556] fix(common) urlJoin replace: ":/" -> "http?s:/" --- lib/http-proxy/common.js | 5 ++++- test/lib-http-proxy-common-test.js | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index d143cf9f1..2602305d7 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -182,7 +182,10 @@ common.urlJoin = function() { // joining e.g. ['', 'am'] // retSegs = [ - args.filter(Boolean).join('/').replace(/\/+/g, '/').replace(/:\//g, '://') + args.filter(Boolean).join('/') + .replace(/\/+/g, '/') + .replace('http:/', 'http://') + .replace('https:/', 'https://') ]; // Only join the query string if it exists so we don't have trailing a '?' diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index e118f2e61..ef99ca109 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -241,6 +241,28 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('/' + google); }); + it('should not replace :\ to :\\ when no https word before', function () { + var outgoing = {}; + var google = 'https://google.com:/join/join.js' + common.setupOutgoing(outgoing, { + target: url.parse('http://sometarget.com:80'), + toProxy: true, + }, { url: google }); + + expect(outgoing.path).to.eql('/' + google); + }); + + it('should not replace :\ to :\\ when no http word before', function () { + var outgoing = {}; + var google = 'http://google.com:/join/join.js' + common.setupOutgoing(outgoing, { + target: url.parse('http://sometarget.com:80'), + toProxy: true, + }, { url: google }); + + expect(outgoing.path).to.eql('/' + google); + }); + describe('when using ignorePath', function () { it('should ignore the path of the `req.url` passed in but use the target path', function () { var outgoing = {}; From bfcab93d8d9e91b910a31af700268b0bff8b5d6e Mon Sep 17 00:00:00 2001 From: Alfredo Delgado Date: Sat, 30 Jan 2016 12:26:26 -0500 Subject: [PATCH 443/556] Update README.md Fixed typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f52ea8aab..c66123899 100644 --- a/README.md +++ b/README.md @@ -429,7 +429,7 @@ proxy.close(); #### ProxyTable API -A proxy table API is available through through this add-on [module](https://github.com/donasaur/http-proxy-rules), which lets you define a set of rules to translate matching routes to target routes that the reverse proxy will talk to. +A proxy table API is available through this add-on [module](https://github.com/donasaur/http-proxy-rules), which lets you define a set of rules to translate matching routes to target routes that the reverse proxy will talk to. #### Test From 9d9fa940cff3aa6134c60732c23aea8171fc7296 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Mon, 1 Feb 2016 21:02:33 -0800 Subject: [PATCH 444/556] [dist] Version bump. 1.13.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9df7d8033..8ee9e9d80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.13.0", + "version": "1.13.1", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 25e56d01823f71fc3fc3936840ddaca78277230f Mon Sep 17 00:00:00 2001 From: Caio Quirino da Silva Date: Tue, 2 Feb 2016 11:56:39 -0200 Subject: [PATCH 445/556] #949 Proxy example using req instead res on README README example implies request instead of response parameter --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f52ea8aab..dc11ddd02 100644 --- a/README.md +++ b/README.md @@ -399,7 +399,7 @@ proxy.on('open', function (proxySocket) { // // Listen for the `close` event on `proxy`. // -proxy.on('close', function (req, socket, head) { +proxy.on('close', function (res, socket, head) { // view disconnected websocket connections console.log('Client disconnected'); }); From 5c46e4b75415863f22c8e9b9140743c724ecaba8 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Mon, 15 Feb 2016 15:43:14 +0100 Subject: [PATCH 446/556] Remove "transfer-encoding" header if "content-length" is set to zero --- lib/http-proxy/passes/web-incoming.js | 1 + test/lib-http-proxy-passes-web-incoming-test.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 4070eb316..af28546b3 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -32,6 +32,7 @@ web_o = Object.keys(web_o).map(function(pass) { if((req.method === 'DELETE' || req.method === 'OPTIONS') && !req.headers['content-length']) { req.headers['content-length'] = '0'; + delete req.headers['transfer-encoding']; } }, diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index cf9bf6b75..6ca63d398 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -22,6 +22,18 @@ describe('lib/http-proxy/passes/web.js', function() { webPasses.deleteLength(stubRequest, {}, {}); expect(stubRequest.headers['content-length']).to.eql('0'); }); + + it('should remove `transfer-encoding` from empty DELETE requests', function() { + var stubRequest = { + method: 'DELETE', + headers: { + 'transfer-encoding': 'chunked' + } + }; + webPasses.deleteLength(stubRequest, {}, {}); + expect(stubRequest.headers['content-length']).to.eql('0'); + expect(stubRequest.headers).to.not.have.key('transfer-encoding'); + }); }); describe('#timeout', function() { From 570cf3b4f9f6bf8f49e912d0b056eb51e3e0914a Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Mon, 15 Feb 2016 15:47:46 +0100 Subject: [PATCH 447/556] mocha: Use default reporter Unfortunately the "landing" reporter doesn't really look good on CI servers at all... --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8ee9e9d80..b198dd25a 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "blanket": { "pattern": "lib/http-proxy" }, - "test": "mocha -R landing test/*-test.js", + "test": "mocha test/*-test.js", "test-cov": "mocha --require blanket -R html-cov > cov/coverage.html" }, "engines": { From e1b2f4c31b34464431db251b3b6169689dadf518 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 17 Feb 2016 11:00:08 -0500 Subject: [PATCH 448/556] [dist] Version bump. 1.13.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b198dd25a..252cae8aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.13.1", + "version": "1.13.2", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From ef86b50427f7a30db4ca61dbda990c4caf732863 Mon Sep 17 00:00:00 2001 From: Jakob Backlund Date: Fri, 26 Feb 2016 14:29:55 +0200 Subject: [PATCH 449/556] Set the x-forwarded-host flag when xfwd is enabled Reasoning: Rack's request class [makes use of](https://github.com/rack/rack/blob/master/lib/rack/request.rb#L243) this HTTP header. Certain edge-case scenarios (proxying from ember-cli to a Rails backend) can be problematic without this header being present. /cc @perlun, @jesjos --- lib/http-proxy/passes/web-incoming.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index af28546b3..670ac9613 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -78,6 +78,8 @@ web_o = Object.keys(web_o).map(function(pass) { (req.headers['x-forwarded-' + header] ? ',' : '') + values[header]; }); + + req.headers['x-forwarded-host'] = req.headers['host']; }, /** From f8d605d53f648e2ca8e48f8a8c2f6299f4aebd10 Mon Sep 17 00:00:00 2001 From: Brendan McLoughlin Date: Tue, 8 Mar 2016 18:07:11 -0500 Subject: [PATCH 450/556] Fix formatting of the `headers` option --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0cafaaaea..89cfe188c 100644 --- a/README.md +++ b/README.md @@ -337,7 +337,7 @@ proxyServer.listen(8015); * **hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects. * **autoRewrite**: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. * **protocolRewrite**: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null. - * **headers**: object with extra headers to be added to target requests. +* **headers**: object with extra headers to be added to target requests. **NOTE:** `options.ws` and `options.ssl` are optional. From f345a1ac2dde1884e72b952a685a0a1796059f14 Mon Sep 17 00:00:00 2001 From: indexzero Date: Sat, 12 Mar 2016 00:05:21 -0800 Subject: [PATCH 451/556] [dist] Update LICENSE to reflect 2015 changes. --- LICENSE | 4 ++-- README.md | 8 ++++---- .../balancer/simple-balancer-with-websockets.js | 15 +++++++-------- examples/balancer/simple-balancer.js | 4 ++-- examples/http/basic-proxy.js | 10 +++++----- examples/http/concurrent-proxy.js | 8 ++++---- examples/http/custom-proxy-error.js | 4 ++-- examples/http/error-handling.js | 2 +- examples/http/forward-and-target-proxy.js | 2 +- examples/http/forward-proxy.js | 2 +- examples/http/latent-proxy.js | 2 +- examples/http/proxy-http-to-https.js | 2 +- examples/http/proxy-https-to-http.js | 6 +++--- examples/http/proxy-https-to-https.js | 6 +++--- examples/http/sse.js | 4 ++-- examples/http/standalone-proxy.js | 2 +- examples/middleware/bodyDecoder-middleware.js | 2 +- examples/middleware/gzip-middleware.js | 2 +- examples/middleware/modifyResponse-middleware.js | 2 +- examples/websocket/latent-websocket-proxy.js | 6 +++--- examples/websocket/standalone-websocket-proxy.js | 4 ++-- examples/websocket/websocket-proxy.js | 2 +- package.json | 5 ++--- test/examples-test.js | 2 +- 24 files changed, 52 insertions(+), 54 deletions(-) diff --git a/LICENSE b/LICENSE index 2bab4b9b1..84820c000 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ node-http-proxy - Copyright (c) Nodejitsu 2013 + Copyright (c) 2010-2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -20,4 +20,4 @@ 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 + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 89cfe188c..83a6e8042 100644 --- a/README.md +++ b/README.md @@ -333,14 +333,14 @@ proxyServer.listen(8015); * **ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required). * **localAddress**: Local interface string to bind for outgoing connections * **changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL -* **auth**: Basic authentication i.e. 'user:password' to compute an Authorization header. +* **auth**: Basic authentication i.e. 'user:password' to compute an Authorization header. * **hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects. * **autoRewrite**: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. * **protocolRewrite**: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null. * **headers**: object with extra headers to be added to target requests. -**NOTE:** -`options.ws` and `options.ssl` are optional. +**NOTE:** +`options.ws` and `options.ssl` are optional. `options.target` and `options.forward` cannot both be missing If you are using the `proxyServer.listen` method, the following options are also applicable: @@ -458,7 +458,7 @@ Logo created by [Diego Pasquali](http://dribbble.com/diegopq) >The MIT License (MIT) > ->Copyright (c) 2010 - 2016 Nodejitsu Inc. +>Copyright (c) 2010 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. > >Permission is hereby granted, free of charge, to any person obtaining a copy >of this software and associated documentation files (the "Software"), to deal diff --git a/examples/balancer/simple-balancer-with-websockets.js b/examples/balancer/simple-balancer-with-websockets.js index cc13f4b5c..2fa45f1f4 100644 --- a/examples/balancer/simple-balancer-with-websockets.js +++ b/examples/balancer/simple-balancer-with-websockets.js @@ -1,7 +1,7 @@ /* simple-balancer.js: Example of a simple round robin balancer for websockets - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -29,7 +29,7 @@ var http = require('http'), // // A simple round-robin load balancing strategy. -// +// // First, list the servers you want to use in your rotation. // var addresses = [ @@ -64,16 +64,16 @@ function nextProxy() { return proxy; } -// -// Get the 'next' proxy and send the http request +// +// Get the 'next' proxy and send the http request // -var server = http.createServer(function (req, res) { +var server = http.createServer(function (req, res) { nextProxy().web(req, res); }); -// -// Get the 'next' proxy and send the upgrade request +// +// Get the 'next' proxy and send the upgrade request // server.on('upgrade', function (req, socket, head) { @@ -81,4 +81,3 @@ server.on('upgrade', function (req, socket, head) { }); server.listen(8001); - \ No newline at end of file diff --git a/examples/balancer/simple-balancer.js b/examples/balancer/simple-balancer.js index 16612b1b1..e702946cf 100644 --- a/examples/balancer/simple-balancer.js +++ b/examples/balancer/simple-balancer.js @@ -1,7 +1,7 @@ /* simple-balancer.js: Example of a simple round robin balancer - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -28,7 +28,7 @@ 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 = [ diff --git a/examples/http/basic-proxy.js b/examples/http/basic-proxy.js index e9be0d79b..dede897f3 100644 --- a/examples/http/basic-proxy.js +++ b/examples/http/basic-proxy.js @@ -1,7 +1,7 @@ /* basic-proxy.js: Basic example of proxying over HTTP - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -31,10 +31,10 @@ var util = require('util'), var welcome = [ '# # ##### ##### ##### ##### ##### #### # # # #', - '# # # # # # # # # # # # # # # # ', - '###### # # # # ##### # # # # # # ## # ', - '# # # # ##### ##### ##### # # ## # ', - '# # # # # # # # # # # # # ', + '# # # # # # # # # # # # # # # # ', + '###### # # # # ##### # # # # # # ## # ', + '# # # # ##### ##### ##### # # ## # ', + '# # # # # # # # # # # # # ', '# # # # # # # # #### # # # ' ].join('\n'); diff --git a/examples/http/concurrent-proxy.js b/examples/http/concurrent-proxy.js index 30aa53dd6..7e54935dd 100644 --- a/examples/http/concurrent-proxy.js +++ b/examples/http/concurrent-proxy.js @@ -1,7 +1,7 @@ /* concurrent-proxy.js: check levelof concurrency through proxy. - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -44,7 +44,7 @@ httpProxy.createServer({ // -var connections = [], +var connections = [], go; http.createServer(function (req, res) { @@ -53,9 +53,9 @@ http.createServer(function (req, res) { 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) { diff --git a/examples/http/custom-proxy-error.js b/examples/http/custom-proxy-error.js index 1c54b5ab8..855995fdf 100644 --- a/examples/http/custom-proxy-error.js +++ b/examples/http/custom-proxy-error.js @@ -1,7 +1,7 @@ /* custom-proxy-error.js: Example of using the custom `proxyError` event. - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -47,7 +47,7 @@ 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.'); }); diff --git a/examples/http/error-handling.js b/examples/http/error-handling.js index 292fb6144..a20360325 100644 --- a/examples/http/error-handling.js +++ b/examples/http/error-handling.js @@ -1,7 +1,7 @@ /* error-handling.js: Example of handle erros for HTTP and WebSockets - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/examples/http/forward-and-target-proxy.js b/examples/http/forward-and-target-proxy.js index c564bfbbd..5f4231add 100644 --- a/examples/http/forward-and-target-proxy.js +++ b/examples/http/forward-and-target-proxy.js @@ -1,7 +1,7 @@ /* forward-and-target-proxy.js: Example of proxying over HTTP with additional forward proxy - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/examples/http/forward-proxy.js b/examples/http/forward-proxy.js index d94f48414..d0bc30ca0 100644 --- a/examples/http/forward-proxy.js +++ b/examples/http/forward-proxy.js @@ -1,7 +1,7 @@ /* forward-proxy.js: Example of proxying over HTTP with additional forward proxy - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/examples/http/latent-proxy.js b/examples/http/latent-proxy.js index 01ec93cc7..0c8ba5d16 100644 --- a/examples/http/latent-proxy.js +++ b/examples/http/latent-proxy.js @@ -1,7 +1,7 @@ /* latent-proxy.js: Example of proxying over HTTP with latency - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/examples/http/proxy-http-to-https.js b/examples/http/proxy-http-to-https.js index ba5c83816..4df98e4d6 100644 --- a/examples/http/proxy-http-to-https.js +++ b/examples/http/proxy-http-to-https.js @@ -1,7 +1,7 @@ /* proxy-http-to-https.js: Basic example of proxying over HTTP to a target HTTPS server - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/examples/http/proxy-https-to-http.js b/examples/http/proxy-https-to-http.js index d2a2d5c0d..227f4373e 100644 --- a/examples/http/proxy-https-to-http.js +++ b/examples/http/proxy-https-to-http.js @@ -1,7 +1,7 @@ /* proxy-https-to-http.js: Basic example of proxying over HTTPS to a target HTTP server - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -32,9 +32,9 @@ var https = require('https'), colors = require('colors'), httpProxy = require('../../lib/http-proxy'), fixturesDir = path.join(__dirname, '..', '..', 'test', 'fixtures'); - + // -// Create the target HTTP server +// Create the target HTTP server // http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); diff --git a/examples/http/proxy-https-to-https.js b/examples/http/proxy-https-to-https.js index 45f0fd7d0..4cfe0c18c 100644 --- a/examples/http/proxy-https-to-https.js +++ b/examples/http/proxy-https-to-https.js @@ -1,7 +1,7 @@ /* proxy-https-to-https.js: Basic example of proxying over HTTPS to a target HTTPS server - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -36,9 +36,9 @@ var https = require('https'), 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 +// Create the target HTTPS server // https.createServer(httpsOpts, function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); diff --git a/examples/http/sse.js b/examples/http/sse.js index b6e3f065c..ef4693ec3 100644 --- a/examples/http/sse.js +++ b/examples/http/sse.js @@ -1,7 +1,7 @@ /* sse.js: Basic example of proxying over HTTP - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -50,7 +50,7 @@ var server = http.createServer(function(req, res) { }); // -// Use SSE +// Use SSE // var sse = new SSE(server, {path: '/'}); diff --git a/examples/http/standalone-proxy.js b/examples/http/standalone-proxy.js index 410d70b31..e67259e9b 100644 --- a/examples/http/standalone-proxy.js +++ b/examples/http/standalone-proxy.js @@ -1,7 +1,7 @@ /* standalone-proxy.js: Example of proxying over HTTP with a standalone HTTP server. - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/examples/middleware/bodyDecoder-middleware.js b/examples/middleware/bodyDecoder-middleware.js index 00c97f909..36c5fae91 100644 --- a/examples/middleware/bodyDecoder-middleware.js +++ b/examples/middleware/bodyDecoder-middleware.js @@ -1,7 +1,7 @@ /* bodyDecoder-middleware.js: Basic example of `connect.bodyParser()` middleware in node-http-proxy - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/examples/middleware/gzip-middleware.js b/examples/middleware/gzip-middleware.js index be991b9ff..7cbb49a0c 100644 --- a/examples/middleware/gzip-middleware.js +++ b/examples/middleware/gzip-middleware.js @@ -1,7 +1,7 @@ /* gzip-middleware.js: Basic example of `connect-gzip` middleware in node-http-proxy - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/examples/middleware/modifyResponse-middleware.js b/examples/middleware/modifyResponse-middleware.js index fdd7e6596..e2cc79f87 100644 --- a/examples/middleware/modifyResponse-middleware.js +++ b/examples/middleware/modifyResponse-middleware.js @@ -1,7 +1,7 @@ /* modifyBody-middleware.js: Example of middleware which modifies response - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/examples/websocket/latent-websocket-proxy.js b/examples/websocket/latent-websocket-proxy.js index 64d3d7ce0..f5ad868bc 100644 --- a/examples/websocket/latent-websocket-proxy.js +++ b/examples/websocket/latent-websocket-proxy.js @@ -1,7 +1,7 @@ /* standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server. - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -59,7 +59,7 @@ server.sockets.on('connection', function (client) { // var proxy = new httpProxy.createProxyServer({ target: { - host: 'localhost', + host: 'localhost', port: 9016 } }); @@ -69,7 +69,7 @@ var proxyServer = http.createServer(function (req, res) { }); // -// Listen to the `upgrade` event and proxy the +// Listen to the `upgrade` event and proxy the // WebSocket requests as well. // proxyServer.on('upgrade', function (req, socket, head) { diff --git a/examples/websocket/standalone-websocket-proxy.js b/examples/websocket/standalone-websocket-proxy.js index 81d019650..78ac697f0 100644 --- a/examples/websocket/standalone-websocket-proxy.js +++ b/examples/websocket/standalone-websocket-proxy.js @@ -1,7 +1,7 @@ /* standalone-websocket-proxy.js: Example of proxying websockets over HTTP with a standalone HTTP server. - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -68,7 +68,7 @@ var proxyServer = http.createServer(function (req, res) { }); // -// Listen to the `upgrade` event and proxy the +// Listen to the `upgrade` event and proxy the // WebSocket requests as well. // proxyServer.on('upgrade', function (req, socket, head) { diff --git a/examples/websocket/websocket-proxy.js b/examples/websocket/websocket-proxy.js index 33d78c675..5feacb4f4 100644 --- a/examples/websocket/websocket-proxy.js +++ b/examples/websocket/websocket-proxy.js @@ -1,7 +1,7 @@ /* web-socket-proxy.js: Example of proxying over HTTP and WebSockets. - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/package.json b/package.json index 252cae8aa..7d5fe55cc 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,9 @@ "url": "https://github.com/nodejitsu/node-http-proxy.git" }, "description": "HTTP proxying for the masses", - "author": "Nodejitsu Inc. ", + "author": "Charlie Robbins ", "maintainers": [ - "yawnt ", - "indexzero " + "jcrugzz " ], "main": "index.js", "dependencies": { diff --git a/test/examples-test.js b/test/examples-test.js index 8464e3fe5..c31346364 100644 --- a/test/examples-test.js +++ b/test/examples-test.js @@ -1,7 +1,7 @@ /* examples-test.js: Test to run all the examples - Copyright (c) Nodejitsu 2013 + Copyright (c) 2013 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors. */ var path = require('path'), From 820fc5987ce642c601ad154d38f2e6e912e45491 Mon Sep 17 00:00:00 2001 From: Kyle Hayes Date: Tue, 22 Mar 2016 08:47:14 -0700 Subject: [PATCH 452/556] Update README For clarity --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83a6e8042..f0b969e2e 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ var proxy = httpProxy.createProxyServer(options); // See (†) ``` †Unless listen(..) is invoked on the object, this does not create a webserver. See below. -An object will be returned with four values: +An object will be returned with four methods: * web `req, res, [options]` (used for proxying regular HTTP(S) requests) * ws `req, socket, head, [options]` (used for proxying WS(S) requests) From bdb3492b215a000bd3502c07a8bf1a8cf14dbaa1 Mon Sep 17 00:00:00 2001 From: deanshelton913 Date: Wed, 23 Mar 2016 15:19:50 -0700 Subject: [PATCH 453/556] Add expected datatype to readme This confused me while attempting to use this feature --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f0b969e2e..dd5c2cdc8 100644 --- a/README.md +++ b/README.md @@ -328,7 +328,7 @@ proxyServer.listen(8015); * **ws**: true/false, if you want to proxy websockets * **xfwd**: true/false, adds x-forward headers * **secure**: true/false, if you want to verify the SSL Certs -* **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies) +* **toProxy**: true/false, passes the absolute URL as the `path` (useful for proxying to proxies) * **prependPath**: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path * **ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required). * **localAddress**: Local interface string to bind for outgoing connections From ecdfff408fda451e208ffee3ba823d6fadf62d4e Mon Sep 17 00:00:00 2001 From: Adam Roderick Date: Thu, 14 Apr 2016 16:21:39 -0500 Subject: [PATCH 454/556] Update ntlm-authentication.js missing bracket --- examples/http/ntlm-authentication.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/http/ntlm-authentication.js b/examples/http/ntlm-authentication.js index 5634ded4b..294680132 100644 --- a/examples/http/ntlm-authentication.js +++ b/examples/http/ntlm-authentication.js @@ -10,7 +10,7 @@ var agent = new Agent({ keepAliveTimeout: 30000 // free socket keepalive for 30 seconds }); -var proxy = httpProxy.createProxy({ target: 'http://whatever.com', agent: agent); +var proxy = httpProxy.createProxy({ target: 'http://whatever.com', agent: agent }); // // Modify headers of the request before it gets sent From 284903d3796180a48e0bdd9ebe4fd91efb6a4b74 Mon Sep 17 00:00:00 2001 From: Mihai Ene Date: Tue, 26 Apr 2016 21:26:35 +0100 Subject: [PATCH 455/556] Sanitize header keys before setting them (#997) Fixes #996. --- lib/http-proxy/passes/web-outgoing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index ad8b8d0c8..20b0f3cba 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -83,7 +83,7 @@ var redirectRegex = /^30(1|2|7|8)$/; function writeHeaders(req, res, proxyRes) { Object.keys(proxyRes.headers).forEach(function(key) { if(proxyRes.headers[key] != undefined){ - res.setHeader(key, proxyRes.headers[key]); + res.setHeader(String(key).trim(), proxyRes.headers[key]); } }); }, From 6baf1498cb1e1135ab1e1ebb617c32f3b1e0b576 Mon Sep 17 00:00:00 2001 From: Muromi Ukari Date: Fri, 29 Apr 2016 00:15:03 +0800 Subject: [PATCH 456/556] alter message error (#998) message error about port 9001 -> port 9002 --- examples/http/standalone-proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/http/standalone-proxy.js b/examples/http/standalone-proxy.js index e67259e9b..0c89c6cdb 100644 --- a/examples/http/standalone-proxy.js +++ b/examples/http/standalone-proxy.js @@ -51,4 +51,4 @@ http.createServer(function (req, res) { }).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); +util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9002 '.yellow); From 433a7408cf775aa7b74405682b183d1af92aeac8 Mon Sep 17 00:00:00 2001 From: idjem Date: Sun, 15 May 2016 21:40:01 +0200 Subject: [PATCH 457/556] fix browserify compatibility (#975) --- lib/http-proxy/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index 7a5e1d2e8..caaa10bd4 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -1,4 +1,4 @@ -var httpProxy = exports, +var httpProxy = module.exports, extend = require('util')._extend, parse_url = require('url').parse, EE3 = require('eventemitter3'), From 5082acc067bbf287f503bbd5b776f798ab169db1 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sun, 15 May 2016 23:14:51 -0400 Subject: [PATCH 458/556] [dist] Version bump. 1.13.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d5fe55cc..b64d74086 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.13.2", + "version": "1.13.3", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 3e966361bcbd22cd1924059d8199ccb60fb75be4 Mon Sep 17 00:00:00 2001 From: Jeremy Judeaux Date: Wed, 25 May 2016 18:18:51 +0200 Subject: [PATCH 459/556] fix test for node 0.10 + socket.io-client@1.4.6 (engine.io-client@1.6.9) (#1010) --- test/lib-http-proxy-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index edbb6f9f1..385c8aad2 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -419,7 +419,7 @@ describe('lib/http-proxy.js', function() { var destiny = io.listen(server); function startSocketIo() { - var client = ioClient.connect('ws://127.0.0.1:' + ports.proxy); + var client = ioClient.connect('ws://127.0.0.1:' + ports.proxy, {rejectUnauthorized: null}); client.on('connect', function () { client.disconnect(); }); From 42df703830a0e8a10abb42cb4d50dc1210a1b76e Mon Sep 17 00:00:00 2001 From: Deividy Metheler Date: Fri, 3 Jun 2016 14:39:40 -0300 Subject: [PATCH 460/556] Emit disconnected event instead of error when ECONNRESET (#966) * Emit disconnected event instead of error when ECONNRESET ECONNRESET means the other side of the TCP conversation abruptly closed its end of the connection. If we get an ECONNRESET error from the proxy request and the socket is destroyed this means that the client has closed his connection, and emit this as an error can lead to confusion and hacks to filter that kind of message. I think that the best we can do is abort and emit another event, so if any caller wants to handle with that kind of error, he can by listen the disconnected event. https://github.com/nodejitsu/node-http-proxy/issues/813 * code standards, move econnreset check, change ev name --- lib/http-proxy/passes/web-incoming.js | 5 +++++ test/lib-http-proxy-passes-web-incoming-test.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 670ac9613..0197a6cd4 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -137,6 +137,11 @@ web_o = Object.keys(web_o).map(function(pass) { proxyReq.on('error', proxyError); function proxyError (err){ + if (req.socket.destroyed && err.code === 'ECONNRESET') { + server.emit('econnreset', err, req, res, options.target); + return proxyReq.abort(); + } + if (clb) { clb(err, req, res, options.target); } else { diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 6ca63d398..a89fc2354 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -229,7 +229,7 @@ describe('#createProxyServer.web() using own http server', function () { var started = new Date().getTime(); function requestHandler(req, res) { - proxy.once('error', function (err, errReq, errRes) { + proxy.once('econnreset', function (err, errReq, errRes) { proxyServer.close(); expect(err).to.be.an(Error); expect(errReq).to.be.equal(req); From fcfb0b37f6ac61369565507446377f91d955cf29 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 15 Jun 2016 10:52:53 -0400 Subject: [PATCH 461/556] [dist] Version bump. 1.14.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b64d74086..7a476c899 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.13.3", + "version": "1.14.0", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 3a347af543932443d6deeb07cb7a10f569d3c163 Mon Sep 17 00:00:00 2001 From: Ken Date: Thu, 11 Aug 2016 12:20:35 -0400 Subject: [PATCH 462/556] #866 Copy CA from options into outbound proxy (#1042) While using secure: true for proxy connections, there is no way to pass the trusted root CA(s) or intermediate CA(s). This change allows that to be passed in the httpProxy createServer options and used for the outgoing proxy connection. --- lib/http-proxy/common.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 2602305d7..bf467a2cd 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -49,6 +49,10 @@ common.setupOutgoing = function(outgoing, options, req, forward) { if (options.auth) { outgoing.auth = options.auth; } + + if (options.ca) { + outgoing.ca = options.ca; + } if (isSSL.test(options[forward || 'target'].protocol)) { outgoing.rejectUnauthorized = (typeof options.secure === "undefined") ? true : options.secure; From 183b5bb4fc0a8cf0c08b2e949319dd3a2f134c5e Mon Sep 17 00:00:00 2001 From: Gabriel Boucher Date: Thu, 11 Aug 2016 12:36:17 -0400 Subject: [PATCH 463/556] Location rewriting for responses with status 201 (#1024) Implement rewriting of the location header for responses with status code 201, according to RFC2616 section 10.2.2 --- README.md | 6 +++--- lib/http-proxy/passes/web-outgoing.js | 2 +- test/lib-http-proxy-passes-web-outgoing-test.js | 7 +++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index dd5c2cdc8..518803fbc 100644 --- a/README.md +++ b/README.md @@ -334,9 +334,9 @@ proxyServer.listen(8015); * **localAddress**: Local interface string to bind for outgoing connections * **changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL * **auth**: Basic authentication i.e. 'user:password' to compute an Authorization header. -* **hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects. -* **autoRewrite**: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. -* **protocolRewrite**: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null. +* **hostRewrite**: rewrites the location hostname on (201/301/302/307/308) redirects. +* **autoRewrite**: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false. +* **protocolRewrite**: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null. * **headers**: object with extra headers to be added to target requests. **NOTE:** diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 20b0f3cba..7047c098f 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -1,7 +1,7 @@ var url = require('url'), passes = exports; -var redirectRegex = /^30(1|2|7|8)$/; +var redirectRegex = /^201|30(1|2|7|8)$/; /*! * Array of passes. diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index 5b91c0bb2..c8b5ec12a 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -24,7 +24,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { beforeEach(function() { this.options.hostRewrite = "ext-manual.com"; }); - [301, 302, 307, 308].forEach(function(code) { + [201, 301, 302, 307, 308].forEach(function(code) { it('on ' + code, function() { this.proxyRes.statusCode = code; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); @@ -69,7 +69,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { beforeEach(function() { this.options.autoRewrite = true; }); - [301, 302, 307, 308].forEach(function(code) { + [201, 301, 302, 307, 308].forEach(function(code) { it('on ' + code, function() { this.proxyRes.statusCode = code; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); @@ -108,7 +108,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { beforeEach(function() { this.options.protocolRewrite = 'https'; }); - [301, 302, 307, 308].forEach(function(code) { + [201, 301, 302, 307, 308].forEach(function(code) { it('on ' + code, function() { this.proxyRes.statusCode = code; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); @@ -241,4 +241,3 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { }); }); - From d0e000e1f91a969f1711eb3be7d1acb16c4538df Mon Sep 17 00:00:00 2001 From: "Mati B. Terefe" Date: Fri, 12 Aug 2016 01:37:32 +0900 Subject: [PATCH 464/556] Restream body before proxying (#1027) Support for bodyparser.json and bodyparser.urlencoded. Fixes #955 #843 #791 --- examples/middleware/bodyDecoder-middleware.js | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/examples/middleware/bodyDecoder-middleware.js b/examples/middleware/bodyDecoder-middleware.js index 36c5fae91..38559ef3b 100644 --- a/examples/middleware/bodyDecoder-middleware.js +++ b/examples/middleware/bodyDecoder-middleware.js @@ -34,28 +34,25 @@ var http = require('http'), proxy = httpProxy.createProxyServer({}); -//restreame -var restreamer = function (){ - return function (req, res, next) { //restreame - req.removeAllListeners('data') - req.removeAllListeners('end') - next() - process.nextTick(function () { - if(req.body) { - req.emit('data', JSON.stringify(req.body)) - } - req.emit('end') - }) +//restream parsed body before proxying +proxy.on('proxyReq', function(proxyReq, req, res, options) { + if(req.body) { + let bodyData = JSON.stringify(req.body); + // incase if content-type is application/x-www-form-urlencoded -> we need to change to application/json + proxyReq.setHeader('Content-Type','application/json'); + proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData)); + // stream the content + proxyReq.write(bodyData); } -} +}); // // Basic Http Proxy Server // var app = connect() - .use(bodyParser.json())//json - .use(restreamer())//restreame + .use(bodyParser.json())//json parser + .use(bodyParser.urlencoded())//urlencoded parser .use(function(req, res){ // modify body here, // eg: req.body = {a: 1}. @@ -84,9 +81,17 @@ http.createServer(app1).listen(9013, function(){ //request to 8013 to proxy request.post({// url: 'http://127.0.0.1:8013', - json: {content: 123, type: "greeting"} + json: {content: 123, type: "greeting from json request"} + },function(err, res,data){ + console.log('return for json request:' ,err, data) + }) + + // application/x-www-form-urlencoded request + request.post({// + url: 'http://127.0.0.1:8013', + form: {content: 123, type: "greeting from urlencoded request"} },function(err, res,data){ - console.log('return:' ,err, data) + console.log('return for urlencoded request:' ,err, data) }) }); From 9d06ca99d37495ffcdeafc63e1d19c78c93663e7 Mon Sep 17 00:00:00 2001 From: wuchangming Date: Fri, 12 Aug 2016 00:37:57 +0800 Subject: [PATCH 465/556] Update ntlm-authentication.js (#1025) --- examples/http/ntlm-authentication.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/http/ntlm-authentication.js b/examples/http/ntlm-authentication.js index 294680132..f18f2cbfc 100644 --- a/examples/http/ntlm-authentication.js +++ b/examples/http/ntlm-authentication.js @@ -13,8 +13,8 @@ var agent = new Agent({ var proxy = httpProxy.createProxy({ target: 'http://whatever.com', agent: agent }); // -// Modify headers of the request before it gets sent -// So that we handle the NLTM authentication request +// Modify headers of the response before it gets sent +// So that we handle the NLTM authentication response // proxy.on('proxyRes', function (proxyRes) { var key = 'www-authenticate'; From 1e52f660f0246690e065c8b0e5e86e2b9cc40dfd Mon Sep 17 00:00:00 2001 From: Jeremy Judeaux Date: Sat, 13 Aug 2016 01:42:18 +0800 Subject: [PATCH 466/556] cookieDomainRewrite option (#1009) --- README.md | 12 ++ lib/http-proxy/common.js | 38 +++++- lib/http-proxy/passes/web-outgoing.js | 16 ++- ...lib-http-proxy-passes-web-outgoing-test.js | 110 +++++++++++++----- 4 files changed, 146 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 518803fbc..9aded714f 100644 --- a/README.md +++ b/README.md @@ -337,6 +337,18 @@ proxyServer.listen(8015); * **hostRewrite**: rewrites the location hostname on (201/301/302/307/308) redirects. * **autoRewrite**: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false. * **protocolRewrite**: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null. +* **cookieDomainRewrite**: rewrites domain of `set-cookie` headers. Possible values: + * `false` (default): disable cookie rewriting + * String: new domain, for example `cookieDomainRewrite: "new.domain"`. To remove the domain, use `cookieDomainRewrite: ""`. + * Object: mapping of domains to new domains, use `"*"` to match all domains. + For example keep one domain unchanged, rewrite one domain and remove other domains: + ``` + cookieDomainRewrite: { + "unchanged.domain": "unchanged.domain", + "old.domain": "new.domain", + "*": "" + } + ``` * **headers**: object with extra headers to be added to target requests. **NOTE:** diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index bf467a2cd..aa9700234 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -4,7 +4,8 @@ var common = exports, required = require('requires-port'); var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i, - isSSL = /^https|wss/; + isSSL = /^https|wss/, + cookieDomainRegex = /(;\s*domain=)([^;]+)/i; /** * Simple Regex for testing if protocol is https @@ -201,6 +202,41 @@ common.urlJoin = function() { return retSegs.join('?') }; +/** + * Rewrites or removes the domain of a cookie header + * + * @param {String|Array} Header + * @param {Object} Config, mapping of domain to rewritten domain. + * '*' key to match any domain, null value to remove the domain. + * + * @api private + */ +common.rewriteCookieDomain = function rewriteCookieDomain(header, config) { + if (Array.isArray(header)) { + return header.map(function (headerElement) { + return rewriteCookieDomain(headerElement, config); + }); + } + return header.replace(cookieDomainRegex, function(match, prefix, previousDomain) { + var newDomain; + if (previousDomain in config) { + newDomain = config[previousDomain]; + } else if ('*' in config) { + newDomain = config['*']; + } else { + //no match, return previous domain + return match; + } + if (newDomain) { + //replace domain + return prefix + newDomain; + } else { + //remove domain + return ''; + } + }); +}; + /** * Check the host and see if it potentially has a port in it (keep it simple) * diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 7047c098f..d8c17a282 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -1,4 +1,5 @@ var url = require('url'), + common = require('../common'), passes = exports; var redirectRegex = /^201|30(1|2|7|8)$/; @@ -77,13 +78,22 @@ var redirectRegex = /^201|30(1|2|7|8)$/; * @param {ClientRequest} Req Request object * @param {IncomingMessage} Res Response object * @param {proxyResponse} Res Response object from the proxy request + * @param {Object} Options options.cookieDomainRewrite: Config to rewrite cookie domain * * @api private */ - function writeHeaders(req, res, proxyRes) { + function writeHeaders(req, res, proxyRes, options) { + var rewriteCookieDomainConfig = options.cookieDomainRewrite; + if (typeof rewriteCookieDomainConfig === 'string') { //also test for '' + rewriteCookieDomainConfig = { '*': rewriteCookieDomainConfig }; + } Object.keys(proxyRes.headers).forEach(function(key) { - if(proxyRes.headers[key] != undefined){ - res.setHeader(String(key).trim(), proxyRes.headers[key]); + var header = proxyRes.headers[key]; + if (header != undefined) { + if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') { + header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig); + } + res.setHeader(String(key).trim(), header); } }); }, diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index c8b5ec12a..f9d947e4b 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -6,23 +6,23 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { beforeEach(function() { this.req = { headers: { - host: "ext-auto.com" + host: 'ext-auto.com' } }; this.proxyRes = { statusCode: 301, headers: { - location: "http://backend.com/" + location: 'http://backend.com/' } }; this.options = { - target: "http://backend.com" + target: 'http://backend.com' }; }); context('rewrites location host with hostRewrite', function() { beforeEach(function() { - this.options.hostRewrite = "ext-manual.com"; + this.options.hostRewrite = 'ext-manual.com'; }); [201, 301, 302, 307, 308].forEach(function(code) { it('on ' + code, function() { @@ -52,14 +52,14 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { it('not when the redirected location does not match target host', function() { this.proxyRes.statusCode = 302; - this.proxyRes.headers.location = "http://some-other/"; + this.proxyRes.headers.location = 'http://some-other/'; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://some-other/'); }); it('not when the redirected location does not match target port', function() { this.proxyRes.statusCode = 302; - this.proxyRes.headers.location = "http://backend.com:8080/"; + this.proxyRes.headers.location = 'http://backend.com:8080/'; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://backend.com:8080/'); }); @@ -91,14 +91,14 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { it('not when the redirected location does not match target host', function() { this.proxyRes.statusCode = 302; - this.proxyRes.headers.location = "http://some-other/"; + this.proxyRes.headers.location = 'http://some-other/'; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://some-other/'); }); it('not when the redirected location does not match target port', function() { this.proxyRes.statusCode = 302; - this.proxyRes.headers.location = "http://backend.com:8080/"; + this.proxyRes.headers.location = 'http://backend.com:8080/'; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('http://backend.com:8080/'); }); @@ -129,13 +129,13 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { }); it('works together with hostRewrite', function() { - this.options.hostRewrite = 'ext-manual.com' + this.options.hostRewrite = 'ext-manual.com'; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('https://ext-manual.com/'); }); it('works together with autoRewrite', function() { - this.options.autoRewrite = true + this.options.autoRewrite = true; httpProxy.setRedirectHostRewrite(this.req, {}, this.proxyRes, this.options); expect(this.proxyRes.headers.location).to.eql('https://ext-auto.com/'); }); @@ -199,31 +199,89 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { writeHead: function(n) { expect(n).to.eql(200); } - } + }; httpProxy.writeStatusCode({}, res, { statusCode: 200 }); }); }); describe('#writeHeaders', function() { - var proxyRes = { - headers: { - hey: 'hello', - how: 'are you?' - } - }; + beforeEach(function() { + this.proxyRes = { + headers: { + hey: 'hello', + how: 'are you?', + 'set-cookie': 'hello; domain=my.domain; path=/' + } + }; + this.res = { + setHeader: function(k, v) { + this.headers[k] = v; + }, + headers: {} + }; + }); - var res = { - setHeader: function(k, v) { - this.headers[k] = v; - }, - headers: {} - }; + it('writes headers', function() { + var options = {}; - httpProxy.writeHeaders({}, res, proxyRes); + httpProxy.writeHeaders({}, this.res, this.proxyRes, options); + + expect(this.res.headers.hey).to.eql('hello'); + expect(this.res.headers.how).to.eql('are you?'); + }); - expect(res.headers.hey).to.eql('hello'); - expect(res.headers.how).to.eql('are you?'); + it('does not rewrite domain', function() { + var options = {}; + + httpProxy.writeHeaders({}, this.res, this.proxyRes, options); + + expect(this.res.headers['set-cookie']).to.eql('hello; domain=my.domain; path=/'); + }); + + it('rewrites domain', function() { + var options = { + cookieDomainRewrite: 'my.new.domain' + }; + + httpProxy.writeHeaders({}, this.res, this.proxyRes, options); + + expect(this.res.headers['set-cookie']).to.eql('hello; domain=my.new.domain; path=/'); + }); + + it('removes domain', function() { + var options = { + cookieDomainRewrite: '' + }; + + httpProxy.writeHeaders({}, this.res, this.proxyRes, options); + + expect(this.res.headers['set-cookie']).to.eql('hello; path=/'); + }); + + it('rewrites headers with advanced configuration', function() { + var options = { + cookieDomainRewrite: { + '*': '', + 'my.old.domain': 'my.new.domain', + 'my.special.domain': 'my.special.domain' + } + }; + this.proxyRes.headers['set-cookie'] = [ + 'hello-on-my.domain; domain=my.domain; path=/', + 'hello-on-my.old.domain; domain=my.old.domain; path=/', + 'hello-on-my.special.domain; domain=my.special.domain; path=/' + ]; + + httpProxy.writeHeaders({}, this.res, this.proxyRes, options); + + expect(this.res.headers['set-cookie']) + .to.contain('hello-on-my.domain; path=/'); + expect(this.res.headers['set-cookie']) + .to.contain('hello-on-my.old.domain; domain=my.new.domain; path=/'); + expect(this.res.headers['set-cookie']) + .to.contain('hello-on-my.special.domain; domain=my.special.domain; path=/'); + }); }); From d8fb34471594f8899013718e77d99c2acbf2c6c9 Mon Sep 17 00:00:00 2001 From: Cole Chamberlain Date: Tue, 13 Sep 2016 15:19:33 -0700 Subject: [PATCH 467/556] Fix for Reason-Phrase being overwritten on proxy response. (#1051) * Fix for Reason-Phrase being overwritten on proxy response. Calling res.writeHead has the side effect of defaulting the Reason-Phrase to default ones. I'm using Reason-Phrase codes to sub-route api responses and they were all being reset. This change only sets the statusMessage (Reason-Phrase) if it exists on the proxyRes and is successfully passing it through in my tests. * Fixed spaces and bracket formatting. --- lib/http-proxy/passes/web-outgoing.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index d8c17a282..b49fbc86b 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -108,7 +108,10 @@ var redirectRegex = /^201|30(1|2|7|8)$/; * @api private */ function writeStatusCode(req, res, proxyRes) { - res.writeHead(proxyRes.statusCode); + res.statusCode = proxyRes.statusCode; + if(proxyRes.statusMessage) { + res.statusMessage = proxyRes.statusMessage; + } } ] // <-- From cbd577706019a62181414c29b97fdba07e46a649 Mon Sep 17 00:00:00 2001 From: Michael Ira Krufky Date: Wed, 14 Sep 2016 07:02:30 -0400 Subject: [PATCH 468/556] README.md: fix typo: 'ingoing' should be 'incoming' (#1060) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9aded714f..3c0a26fab 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ 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 first pipeline (incoming) 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. From b781af641ade623b7a1537e32cf9f8fffd3e551e Mon Sep 17 00:00:00 2001 From: Alex Indigo Date: Wed, 14 Sep 2016 04:03:48 -0700 Subject: [PATCH 469/556] Made it not to crash with omited Host http header (#1050) --- lib/http-proxy/passes/web-incoming.js | 4 +- test/lib-http-proxy-test.js | 61 +++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 0197a6cd4..5858d6399 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -78,8 +78,8 @@ web_o = Object.keys(web_o).map(function(pass) { (req.headers['x-forwarded-' + header] ? ',' : '') + values[header]; }); - - req.headers['x-forwarded-host'] = req.headers['host']; + + req.headers['x-forwarded-host'] = req.headers['host'] || ''; }, /** diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 385c8aad2..bd28483b4 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -1,7 +1,8 @@ var httpProxy = require('../lib/http-proxy'), expect = require('expect.js'), http = require('http'), - ws = require('ws') + net = require('net'), + ws = require('ws'), io = require('socket.io'), SSE = require('sse'), ioClient = require('socket.io-client'); @@ -17,7 +18,6 @@ Object.defineProperty(gen, 'port', { } }); - describe('lib/http-proxy.js', function() { describe('#createProxyServer', function() { it.skip('should throw without options', function() { @@ -223,11 +223,54 @@ describe('lib/http-proxy.js', function() { }); testReq.end(); + }); + }); + + describe('#createProxyServer with xfwd option', function () { + it('should not throw on empty http host header', function (done) { + var ports = { source: gen.port, proxy: gen.port }; + var proxy = httpProxy.createProxyServer({ + forward: 'http://127.0.0.1:' + ports.source, + xfwd: true + }).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.source); + source.close(); + proxy.close(); + done(); + }); + + source.listen(ports.source); + + var socket = net.connect({port: ports.proxy}, function() + { + socket.write('GET / HTTP/1.0\r\n\r\n'); + }); + + // handle errors + socket.on('error', function() + { + expect.fail('Unexpected socket error'); + }); + + socket.on('data', function(data) + { + socket.end(); + }); + + socket.on('end', function() + { + expect('Socket to finish').to.be.ok(); + }); + +// http.request('http://127.0.0.1:' + ports.proxy, function() {}).end(); }) - }) + }); // describe('#createProxyServer using the web-incoming passes', function () { - // it('should emit events correclty', function(done) { + // it('should emit events correctly', function(done) { // var proxy = httpProxy.createProxyServer({ // target: 'http://127.0.0.1:8080' // }), @@ -451,7 +494,7 @@ describe('lib/http-proxy.js', function() { proxyServer = proxy.listen(ports.proxy), destiny = new ws.Server({ port: ports.source }, function () { var key = new Buffer(Math.random().toString()).toString('base64'); - + var requestOptions = { port: ports.proxy, host: '127.0.0.1', @@ -465,15 +508,15 @@ describe('lib/http-proxy.js', function() { }; var req = http.request(requestOptions); - + req.on('upgrade', function (res, socket, upgradeHead) { expect(res.headers['set-cookie'].length).to.be(2); done(); }); - + req.end(); }); - + destiny.on('headers', function (headers) { headers.push('Set-Cookie: test1=test1'); headers.push('Set-Cookie: test2=test2'); @@ -554,7 +597,7 @@ describe('lib/http-proxy.js', function() { }); }); }); - + it('should forward continuation frames with big payload (including on node 4.x)', function (done) { var payload = Array(65530).join('0'); var ports = { source: gen.port, proxy: gen.port }; From b98c75b1ff3ebdf7f78224eb0d9aa857af2db1d9 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 14 Sep 2016 13:05:56 -0400 Subject: [PATCH 470/556] [dist] Version bump. 1.15.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7a476c899..bb2d5845b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.14.0", + "version": "1.15.0", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 84087208ddc04a5f8133d1a1348d8db49afc1981 Mon Sep 17 00:00:00 2001 From: briman0094 Date: Wed, 14 Sep 2016 16:08:26 -0500 Subject: [PATCH 471/556] Properly write response header optionally including statusMessage (#1061) --- lib/http-proxy/passes/web-outgoing.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index b49fbc86b..f21d117e3 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -108,9 +108,11 @@ var redirectRegex = /^201|30(1|2|7|8)$/; * @api private */ function writeStatusCode(req, res, proxyRes) { - res.statusCode = proxyRes.statusCode; + // From Node.js docs: response.writeHead(statusCode[, statusMessage][, headers]) if(proxyRes.statusMessage) { - res.statusMessage = proxyRes.statusMessage; + res.writeHead(proxyRes.statusCode, proxyRes.statusMessage); + } else { + res.writeHead(proxyRes.statusCode); } } From 912cd3acaef484f7ea08affc9339250082e04058 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Wed, 14 Sep 2016 17:12:30 -0400 Subject: [PATCH 472/556] [dist] Version bump. 1.15.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bb2d5845b..0de986adb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.15.0", + "version": "1.15.1", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From d0a15886399a175fc7aab448fbdf2537b5cb0839 Mon Sep 17 00:00:00 2001 From: Ashish Dahiya Date: Tue, 4 Oct 2016 06:54:52 -0700 Subject: [PATCH 473/556] Add proxy-timeout option to documentation (#1075) http-proxy provides a [proxyTimeout option](https://github.com/nodejitsu/node-http-proxy/blob/master/lib/http-proxy/passes/web-incoming.js#L122) that allows us to set a timeout on the outgoing socket connection to the target. This timeout is very effective when the upstream target does not respond within an expected time. I had wasted a few hours searching for this option. Documenting this option can save others a significant amount of time. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3c0a26fab..ae8ed8110 100644 --- a/README.md +++ b/README.md @@ -350,6 +350,7 @@ proxyServer.listen(8015); } ``` * **headers**: object with extra headers to be added to target requests. +* **proxyTimeout**: timeout (in millis) when proxy receives no response from target **NOTE:** `options.ws` and `options.ssl` are optional. From 2d01edc5a5ace591784022b85860a3bbc48c5e12 Mon Sep 17 00:00:00 2001 From: Niranjan Ojha Date: Wed, 5 Oct 2016 19:47:22 +0530 Subject: [PATCH 474/556] not setting connection header in case of http2 as it is deprecated --- lib/http-proxy/passes/web-outgoing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index f21d117e3..8bda89355 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -42,7 +42,7 @@ var redirectRegex = /^201|30(1|2|7|8)$/; function setConnection(req, res, proxyRes) { if (req.httpVersion === '1.0') { proxyRes.headers.connection = req.headers.connection || 'close'; - } else if (!proxyRes.headers.connection) { + } else if (req.httpVersion !== '2.0' && !proxyRes.headers.connection) { proxyRes.headers.connection = req.headers.connection || 'keep-alive'; } }, From f5217d6c20c164ed412a3b20f660786b6f88b35b Mon Sep 17 00:00:00 2001 From: Niranjan Ojha Date: Thu, 6 Oct 2016 12:32:30 +0530 Subject: [PATCH 475/556] test case added --- ...lib-http-proxy-passes-web-outgoing-test.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index f9d947e4b..c636e2027 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -191,6 +191,28 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { expect(proxyRes.headers.connection).to.eql('keep-alive'); }); + it('don`t set connection with 2.0 if exist', function() { + var proxyRes = { headers: {} }; + httpProxy.setConnection({ + httpVersion: '2.0', + headers: { + connection: 'namstey' + } + }, {}, proxyRes); + + expect(proxyRes.headers.connection).to.eql(undefined); + }); + + it('don`t set connection with 2.0 if doesn`t exist', function() { + var proxyRes = { headers: {} }; + httpProxy.setConnection({ + httpVersion: '2.0', + headers: {} + }, {}, proxyRes); + + expect(proxyRes.headers.connection).to.eql(undefined); + }) + }); describe('#writeStatusCode', function () { From 8eddf45f2a043e4e1b3f6e33c304e68fe7e1c406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Leurent?= <131.js@cloudyks.org> Date: Wed, 20 Jul 2016 12:23:19 +0200 Subject: [PATCH 476/556] Fix browserification Browserify fails to resolve the "./http-proxy/" as "./http-proxy/index.js" but as "./http-proxy.js" (so nothing works) Beeing explicit here does not cost much for http-proxy, yet it's intrinsically complicated for browserify to fix (as trailing slash might be used as a pollyfill shim for native/non-natives addons i.e. require('url/') vs require('url') ) --- lib/http-proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 365acedb1..c25de7395 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -1,7 +1,7 @@ var http = require('http'), https = require('https'), url = require('url'), - httpProxy = require('./http-proxy/'); + httpProxy = require('./http-proxy/index.js'); /** * Export the proxy "Server" as the main export. From fbc266809c289fbdb59d7944345816a858303c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Leurent?= <131.js@cloudyks.org> Date: Sat, 17 Sep 2016 22:47:41 +0200 Subject: [PATCH 477/556] With a comment --- lib/http-proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index c25de7395..1614b270d 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -1,7 +1,7 @@ var http = require('http'), https = require('https'), url = require('url'), - httpProxy = require('./http-proxy/index.js'); + httpProxy = require('./http-proxy/index.js'); //use explicit /index.js to help browserify negociation in require '/lib/http-proxy' (!) /** * Export the proxy "Server" as the main export. From 61c28891093b256bbc0dae78e45e2c5f0acf2101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Leurent?= <131.php@cloudyks.org> Date: Tue, 20 Sep 2016 15:26:34 +0200 Subject: [PATCH 478/556] Do not rely on func.name (no scope) --- lib/http-proxy.js | 32 ++++++++++++++++----------- lib/http-proxy/passes/web-outgoing.js | 21 ++++++++---------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 1614b270d..44e723f5a 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -1,12 +1,6 @@ -var http = require('http'), - https = require('https'), - url = require('url'), - httpProxy = require('./http-proxy/index.js'); //use explicit /index.js to help browserify negociation in require '/lib/http-proxy' (!) + //use explicit /index.js to help browserify negociation in require '/lib/http-proxy' (!) +var ProxyServer = require('./http-proxy/index.js').Server; -/** - * Export the proxy "Server" as the main export. - */ -module.exports = httpProxy.Server; /** * Creates the proxy server. @@ -23,9 +17,8 @@ module.exports = httpProxy.Server; * @api public */ -module.exports.createProxyServer = - module.exports.createServer = - module.exports.createProxy = function createProxyServer(options) { + +var createProxyServer = function(options) { /* * `options` is needed and it must have the following layout: * @@ -54,6 +47,19 @@ module.exports.createProxyServer = * } */ - return new httpProxy.Server(options); -}; + return new ProxyServer(options); +} + + +ProxyServer.createProxyServer = createProxyServer; +ProxyServer.createServer = createProxyServer; +ProxyServer.createProxy = createProxyServer; + + + + +/** + * Export the proxy "Server" as the main export. + */ +module.exports = ProxyServer; diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 8bda89355..69d383ed8 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -1,6 +1,6 @@ var url = require('url'), - common = require('../common'), - passes = exports; + common = require('../common'); + var redirectRegex = /^201|30(1|2|7|8)$/; @@ -12,7 +12,7 @@ var redirectRegex = /^201|30(1|2|7|8)$/; * flexible. */ -[ // <-- +module.exports = { // <-- /** * If is a HTTP 1.0 request, remove chunk headers @@ -23,7 +23,7 @@ var redirectRegex = /^201|30(1|2|7|8)$/; * * @api private */ - function removeChunked(req, res, proxyRes) { + removeChunked : function (req, res, proxyRes) { if (req.httpVersion === '1.0') { delete proxyRes.headers['transfer-encoding']; } @@ -39,7 +39,7 @@ var redirectRegex = /^201|30(1|2|7|8)$/; * * @api private */ - function setConnection(req, res, proxyRes) { + setConnection: function(req, res, proxyRes) { if (req.httpVersion === '1.0') { proxyRes.headers.connection = req.headers.connection || 'close'; } else if (req.httpVersion !== '2.0' && !proxyRes.headers.connection) { @@ -47,7 +47,7 @@ var redirectRegex = /^201|30(1|2|7|8)$/; } }, - function setRedirectHostRewrite(req, res, proxyRes, options) { + setRedirectHostRewrite: function(req, res, proxyRes, options) { if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite) && proxyRes.headers['location'] && redirectRegex.test(proxyRes.statusCode)) { @@ -82,7 +82,7 @@ var redirectRegex = /^201|30(1|2|7|8)$/; * * @api private */ - function writeHeaders(req, res, proxyRes, options) { + writeHeaders : function(req, res, proxyRes, options) { var rewriteCookieDomainConfig = options.cookieDomainRewrite; if (typeof rewriteCookieDomainConfig === 'string') { //also test for '' rewriteCookieDomainConfig = { '*': rewriteCookieDomainConfig }; @@ -107,7 +107,7 @@ var redirectRegex = /^201|30(1|2|7|8)$/; * * @api private */ - function writeStatusCode(req, res, proxyRes) { + writeStatusCode : function(req, res, proxyRes) { // From Node.js docs: response.writeHead(statusCode[, statusMessage][, headers]) if(proxyRes.statusMessage) { res.writeHead(proxyRes.statusCode, proxyRes.statusMessage); @@ -116,7 +116,4 @@ var redirectRegex = /^201|30(1|2|7|8)$/; } } -] // <-- - .forEach(function(func) { - passes[func.name] = func; - }); +}; From d48f67eb90d8af66211093e91efdd6638859e0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Leurent?= <131.php@cloudyks.org> Date: Tue, 20 Sep 2016 15:32:14 +0200 Subject: [PATCH 479/556] Do not rely on func.name (no scope) --- lib/http-proxy/passes/web-incoming.js | 19 ++++++++----------- lib/http-proxy/passes/ws-incoming.js | 18 ++++++------------ 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 5858d6399..6ff6e07cf 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -1,8 +1,7 @@ var http = require('http'), https = require('https'), web_o = require('./web-outgoing'), - common = require('../common'), - passes = exports; + common = require('../common'); web_o = Object.keys(web_o).map(function(pass) { return web_o[pass]; @@ -16,7 +15,8 @@ web_o = Object.keys(web_o).map(function(pass) { * flexible. */ -[ // <-- + +module.exports = { /** * Sets `content-length` to '0' if request is of DELETE type. @@ -28,7 +28,7 @@ web_o = Object.keys(web_o).map(function(pass) { * @api private */ - function deleteLength(req, res, options) { + deleteLength : function(req, res, options) { if((req.method === 'DELETE' || req.method === 'OPTIONS') && !req.headers['content-length']) { req.headers['content-length'] = '0'; @@ -46,7 +46,7 @@ web_o = Object.keys(web_o).map(function(pass) { * @api private */ - function timeout(req, res, options) { + timeout: function(req, res, options) { if(options.timeout) { req.socket.setTimeout(options.timeout); } @@ -62,7 +62,7 @@ web_o = Object.keys(web_o).map(function(pass) { * @api private */ - function XHeaders(req, res, options) { + XHeaders : function(req, res, options) { if(!options.xfwd) return; var encrypted = req.isSpdy || common.hasEncryptedConnection(req); @@ -94,7 +94,7 @@ web_o = Object.keys(web_o).map(function(pass) { * @api private */ - function stream(req, res, options, _, server, clb) { + stream : function(req, res, options, _, server, clb) { // And we begin! server.emit('start', req, res, options.target) @@ -168,7 +168,4 @@ web_o = Object.keys(web_o).map(function(pass) { //proxyReq.end(); } -] // <-- - .forEach(function(func) { - passes[func.name] = func; - }); +}; diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index a6ddb3125..1dfe1fa20 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -1,7 +1,6 @@ var http = require('http'), https = require('https'), - common = require('../common'), - passes = exports; + common = require('../common'); /*! * Array of passes. @@ -16,9 +15,8 @@ var http = require('http'), * */ -var passes = exports; -[ +module.exports = { /** * WebSocket requests must have the `GET` method and * the `upgrade:websocket` header @@ -29,7 +27,7 @@ var passes = exports; * @api private */ - function checkMethodAndHeader (req, socket) { + checkMethodAndHeader : function (req, socket) { if (req.method !== 'GET' || !req.headers.upgrade) { socket.destroy(); return true; @@ -51,7 +49,7 @@ var passes = exports; * @api private */ - function XHeaders(req, socket, options) { + XHeaders : function(req, socket, options) { if(!options.xfwd) return; var values = { @@ -78,7 +76,7 @@ var passes = exports; * * @api private */ - function stream(req, socket, options, head, server, clb) { + stream : function(req, socket, options, head, server, clb) { common.setupSocket(socket); if (head && head.length) socket.unshift(head); @@ -155,8 +153,4 @@ var passes = exports; socket.end(); } } - -] // <-- - .forEach(function(func) { - passes[func.name] = func; - }); +}; From 220f5fb795d2977c5a68ae59d7db65089efed50c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Leurent?= Date: Sat, 22 Oct 2016 17:18:51 +0200 Subject: [PATCH 480/556] Expose full callback names --- lib/http-proxy/passes/web-incoming.js | 8 ++++---- lib/http-proxy/passes/web-outgoing.js | 10 +++++----- lib/http-proxy/passes/ws-incoming.js | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 6ff6e07cf..df5dfb58a 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -28,7 +28,7 @@ module.exports = { * @api private */ - deleteLength : function(req, res, options) { + deleteLength : function deleteLength(req, res, options) { if((req.method === 'DELETE' || req.method === 'OPTIONS') && !req.headers['content-length']) { req.headers['content-length'] = '0'; @@ -46,7 +46,7 @@ module.exports = { * @api private */ - timeout: function(req, res, options) { + timeout: function timeout(req, res, options) { if(options.timeout) { req.socket.setTimeout(options.timeout); } @@ -62,7 +62,7 @@ module.exports = { * @api private */ - XHeaders : function(req, res, options) { + XHeaders : function XHeaders(req, res, options) { if(!options.xfwd) return; var encrypted = req.isSpdy || common.hasEncryptedConnection(req); @@ -94,7 +94,7 @@ module.exports = { * @api private */ - stream : function(req, res, options, _, server, clb) { + stream : function stream(req, res, options, _, server, clb) { // And we begin! server.emit('start', req, res, options.target) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 69d383ed8..e00bf5077 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -23,7 +23,7 @@ module.exports = { // <-- * * @api private */ - removeChunked : function (req, res, proxyRes) { + removeChunked : function removeChunked(req, res, proxyRes) { if (req.httpVersion === '1.0') { delete proxyRes.headers['transfer-encoding']; } @@ -39,7 +39,7 @@ module.exports = { // <-- * * @api private */ - setConnection: function(req, res, proxyRes) { + setConnection: function setConnection(req, res, proxyRes) { if (req.httpVersion === '1.0') { proxyRes.headers.connection = req.headers.connection || 'close'; } else if (req.httpVersion !== '2.0' && !proxyRes.headers.connection) { @@ -47,7 +47,7 @@ module.exports = { // <-- } }, - setRedirectHostRewrite: function(req, res, proxyRes, options) { + setRedirectHostRewrite: function setRedirectHostRewrite(req, res, proxyRes, options) { if ((options.hostRewrite || options.autoRewrite || options.protocolRewrite) && proxyRes.headers['location'] && redirectRegex.test(proxyRes.statusCode)) { @@ -82,7 +82,7 @@ module.exports = { // <-- * * @api private */ - writeHeaders : function(req, res, proxyRes, options) { + writeHeaders : function writeHeaders(req, res, proxyRes, options) { var rewriteCookieDomainConfig = options.cookieDomainRewrite; if (typeof rewriteCookieDomainConfig === 'string') { //also test for '' rewriteCookieDomainConfig = { '*': rewriteCookieDomainConfig }; @@ -107,7 +107,7 @@ module.exports = { // <-- * * @api private */ - writeStatusCode : function(req, res, proxyRes) { + writeStatusCode : function writeStatusCode(req, res, proxyRes) { // From Node.js docs: response.writeHead(statusCode[, statusMessage][, headers]) if(proxyRes.statusMessage) { res.writeHead(proxyRes.statusCode, proxyRes.statusMessage); diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 1dfe1fa20..cf3796cde 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -27,7 +27,7 @@ module.exports = { * @api private */ - checkMethodAndHeader : function (req, socket) { + checkMethodAndHeader : function checkMethodAndHeader(req, socket) { if (req.method !== 'GET' || !req.headers.upgrade) { socket.destroy(); return true; @@ -49,7 +49,7 @@ module.exports = { * @api private */ - XHeaders : function(req, socket, options) { + XHeaders : function XHeaders(req, socket, options) { if(!options.xfwd) return; var values = { @@ -76,7 +76,7 @@ module.exports = { * * @api private */ - stream : function(req, socket, options, head, server, clb) { + stream : function stream(req, socket, options, head, server, clb) { common.setupSocket(socket); if (head && head.length) socket.unshift(head); From d0f1dfeb8277d46a057017cd888b50e85f6725d6 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sat, 22 Oct 2016 11:44:35 -0400 Subject: [PATCH 481/556] [fix] style nits --- lib/http-proxy.js | 6 +++--- lib/http-proxy/passes/web-incoming.js | 6 +++--- lib/http-proxy/passes/web-outgoing.js | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 44e723f5a..40f2e4b91 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -1,4 +1,4 @@ - //use explicit /index.js to help browserify negociation in require '/lib/http-proxy' (!) + // Use explicit /index.js to help browserify negociation in require '/lib/http-proxy' (!) var ProxyServer = require('./http-proxy/index.js').Server; @@ -18,7 +18,7 @@ var ProxyServer = require('./http-proxy/index.js').Server; */ -var createProxyServer = function(options) { +function createProxyServer(options) { /* * `options` is needed and it must have the following layout: * @@ -35,7 +35,7 @@ var createProxyServer = function(options) { * ignorePath: * localAddress : * changeOrigin: - * auth : Basic authentication i.e. 'user:password' to compute an Authorization header. + * auth : Basic authentication i.e. 'user:password' to compute an Authorization header. * hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null. * autoRewrite: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. * protocolRewrite: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null. diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index df5dfb58a..16a122dc7 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -28,7 +28,7 @@ module.exports = { * @api private */ - deleteLength : function deleteLength(req, res, options) { + deleteLength: function deleteLength(req, res, options) { if((req.method === 'DELETE' || req.method === 'OPTIONS') && !req.headers['content-length']) { req.headers['content-length'] = '0'; @@ -62,7 +62,7 @@ module.exports = { * @api private */ - XHeaders : function XHeaders(req, res, options) { + XHeaders: function XHeaders(req, res, options) { if(!options.xfwd) return; var encrypted = req.isSpdy || common.hasEncryptedConnection(req); @@ -94,7 +94,7 @@ module.exports = { * @api private */ - stream : function stream(req, res, options, _, server, clb) { + stream: function stream(req, res, options, _, server, clb) { // And we begin! server.emit('start', req, res, options.target) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index e00bf5077..e2d957f51 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -23,7 +23,7 @@ module.exports = { // <-- * * @api private */ - removeChunked : function removeChunked(req, res, proxyRes) { + removeChunked: function removeChunked(req, res, proxyRes) { if (req.httpVersion === '1.0') { delete proxyRes.headers['transfer-encoding']; } @@ -82,7 +82,7 @@ module.exports = { // <-- * * @api private */ - writeHeaders : function writeHeaders(req, res, proxyRes, options) { + writeHeaders: function writeHeaders(req, res, proxyRes, options) { var rewriteCookieDomainConfig = options.cookieDomainRewrite; if (typeof rewriteCookieDomainConfig === 'string') { //also test for '' rewriteCookieDomainConfig = { '*': rewriteCookieDomainConfig }; @@ -107,7 +107,7 @@ module.exports = { // <-- * * @api private */ - writeStatusCode : function writeStatusCode(req, res, proxyRes) { + writeStatusCode: function writeStatusCode(req, res, proxyRes) { // From Node.js docs: response.writeHead(statusCode[, statusMessage][, headers]) if(proxyRes.statusMessage) { res.writeHead(proxyRes.statusCode, proxyRes.statusMessage); From d8223884f61a05fabf788a0bd921c7a6197a96ee Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sat, 22 Oct 2016 11:47:23 -0400 Subject: [PATCH 482/556] 1.15.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0de986adb..0585e8ab9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.15.1", + "version": "1.15.2", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 2f7f03778cfb94396acf0d778061ea197212fbb5 Mon Sep 17 00:00:00 2001 From: purificant Date: Sun, 27 Nov 2016 01:14:38 +0000 Subject: [PATCH 483/556] add node 6 to travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0570d5071..975e73b04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ node_js: - "0.10" - "0.12" - "4.2" + - "6" before_install: - travis_retry npm install -g npm@2.14.5 From 69cf892519b0fecf084c0cb0b5edac781ca696fe Mon Sep 17 00:00:00 2001 From: Maarten ter Horst Date: Thu, 1 Dec 2016 15:39:46 +0100 Subject: [PATCH 484/556] Handle errors for forward request, add test case (#1099) --- lib/http-proxy/passes/web-incoming.js | 6 +++- ...lib-http-proxy-passes-web-incoming-test.js | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 16a122dc7..2fa28d227 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -103,6 +103,10 @@ module.exports = { var forwardReq = (options.forward.protocol === 'https:' ? https : http).request( common.setupOutgoing(options.ssl || {}, options, req, 'forward') ); + + // error handler (e.g. ECONNREFUSED) + forwardReq.on('error', proxyError); + (options.buffer || req).pipe(forwardReq); if(!options.target) { return res.end(); } } @@ -138,7 +142,7 @@ module.exports = { function proxyError (err){ if (req.socket.destroyed && err.code === 'ECONNRESET') { - server.emit('econnreset', err, req, res, options.target); + server.emit('econnreset', err, req, res, options.target || options.forward); return proxyReq.abort(); } diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index a89fc2354..1996276d2 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -177,6 +177,35 @@ describe('#createProxyServer.web() using own http server', function () { }, function() {}).end(); }); + it('should forward the request and handle error via event listener', function(done) { + var proxy = httpProxy.createProxyServer({ + forward: '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(); + }); + it('should proxy the request and handle timeout error (proxyTimeout)', function(done) { var proxy = httpProxy.createProxyServer({ target: 'http://127.0.0.1:45000', From 4edbb62cc5881b20e7dae5e6240e693b03fd3609 Mon Sep 17 00:00:00 2001 From: Yuta Shimizu Date: Fri, 2 Dec 2016 10:03:13 +0900 Subject: [PATCH 485/556] Keep original letter case of response header keys (#1098) * Keep original letter case of response header keys * Support node older than v0.11.6 messege.rawHeaders was added in v0.11.6 * Extract duplicated logic to method --- lib/http-proxy/passes/web-outgoing.js | 35 +++++++++++++------ ...lib-http-proxy-passes-web-outgoing-test.js | 19 ++++++++-- test/lib-http-proxy-test.js | 5 +++ 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index e2d957f51..0c71e54ea 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -83,19 +83,34 @@ module.exports = { // <-- * @api private */ writeHeaders: function writeHeaders(req, res, proxyRes, options) { - var rewriteCookieDomainConfig = options.cookieDomainRewrite; + var rewriteCookieDomainConfig = options.cookieDomainRewrite, + setHeader = function(key, header) { + if (header != undefined) { + if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') { + header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig); + } + res.setHeader(String(key).trim(), header); + } + }; + if (typeof rewriteCookieDomainConfig === 'string') { //also test for '' rewriteCookieDomainConfig = { '*': rewriteCookieDomainConfig }; } - Object.keys(proxyRes.headers).forEach(function(key) { - var header = proxyRes.headers[key]; - if (header != undefined) { - if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') { - header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig); - } - res.setHeader(String(key).trim(), header); - } - }); + + // message.rawHeaders is added in: v0.11.6 + // https://nodejs.org/api/http.html#http_message_rawheaders + if (proxyRes.rawHeaders != undefined) { + for (var i = 0; i < proxyRes.rawHeaders.length; i += 2) { + var key = proxyRes.rawHeaders[i]; + var header = proxyRes.rawHeaders[i + 1]; + setHeader(key, header); + }; + } else { + Object.keys(proxyRes.headers).forEach(function(key) { + var header = proxyRes.headers[key]; + setHeader(key, header); + }); + } }, /** diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index c636e2027..6a3ec2230 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -234,11 +234,18 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { hey: 'hello', how: 'are you?', 'set-cookie': 'hello; domain=my.domain; path=/' - } + }, + rawHeaders: [ + 'Hey', 'hello', + 'How', 'are you?', + 'Set-Cookie', 'hello; domain=my.domain; path=/' + ] }; this.res = { setHeader: function(k, v) { - this.headers[k] = v; + // https://nodejs.org/api/http.html#http_message_headers + // Header names are lower-cased + this.headers[k.toLowerCase()] = v; }, headers: {} }; @@ -260,7 +267,7 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { expect(this.res.headers['set-cookie']).to.eql('hello; domain=my.domain; path=/'); }); - + it('rewrites domain', function() { var options = { cookieDomainRewrite: 'my.new.domain' @@ -294,6 +301,12 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { 'hello-on-my.old.domain; domain=my.old.domain; path=/', 'hello-on-my.special.domain; domain=my.special.domain; path=/' ]; + var setCookieValueIndex = this.proxyRes.rawHeaders.indexOf('Set-Cookie') + 1; + this.proxyRes.rawHeaders[setCookieValueIndex] = [ + 'hello-on-my.domain; domain=my.domain; path=/', + 'hello-on-my.old.domain; domain=my.old.domain; path=/', + 'hello-on-my.special.domain; domain=my.special.domain; path=/' + ]; httpProxy.writeHeaders({}, this.res, this.proxyRes, options); diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index bd28483b4..8b024c9f1 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -148,6 +148,11 @@ describe('lib/http-proxy.js', function() { method: 'GET' }, function(res) { expect(res.statusCode).to.eql(200); + expect(res.headers['content-type']).to.eql('text/plain'); + if (res.rawHeaders != undefined) { + expect(res.rawHeaders.indexOf('Content-Type')).not.to.eql(-1); + expect(res.rawHeaders.indexOf('text/plain')).not.to.eql(-1); + } res.on('data', function (data) { expect(data.toString()).to.eql('Hello from ' + ports.source); From 927357bedc42f2e3067c44c10ab9563be7d8b032 Mon Sep 17 00:00:00 2001 From: Maarten ter Horst Date: Fri, 2 Dec 2016 15:09:11 +0100 Subject: [PATCH 486/556] Fix newly introduced error in error handler for ECONNREFUSED in forward proxy (#1100) --- lib/http-proxy/passes/web-incoming.js | 37 +++++++++++++++------------ 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 2fa28d227..5cb0b03d3 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -97,15 +97,19 @@ module.exports = { stream: function stream(req, res, options, _, server, clb) { // And we begin! - server.emit('start', req, res, options.target) + server.emit('start', req, res, options.target || options.forward); + 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') ); - // error handler (e.g. ECONNREFUSED) - forwardReq.on('error', proxyError); + // error handler (e.g. ECONNRESET, ECONNREFUSED) + // Handle errors on incoming request as well as it makes sense to + var forwardError = createErrorHandler(forwardReq, options.forward); + req.on('error', forwardError); + forwardReq.on('error', forwardError); (options.buffer || req).pipe(forwardReq); if(!options.target) { return res.end(); } @@ -134,22 +138,23 @@ module.exports = { proxyReq.abort(); }); - // Handle errors on incoming request as well as it makes sense to + // handle errors in proxy and incoming request, just like for forward proxy + var proxyError = createErrorHandler(proxyReq, options.target); req.on('error', proxyError); - - // Error Handler proxyReq.on('error', proxyError); - function proxyError (err){ - if (req.socket.destroyed && err.code === 'ECONNRESET') { - server.emit('econnreset', err, req, res, options.target || options.forward); - return proxyReq.abort(); - } - - if (clb) { - clb(err, req, res, options.target); - } else { - server.emit('error', err, req, res, options.target); + function createErrorHandler(proxyReq, url) { + return function proxyError(err) { + if (req.socket.destroyed && err.code === 'ECONNRESET') { + server.emit('econnreset', err, req, res, url); + return proxyReq.abort(); + } + + if (clb) { + clb(err, req, res, url); + } else { + server.emit('error', err, req, res, url); + } } } From c252b32f6c7f832f157cc4647ceaff33dd265d82 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Fri, 2 Dec 2016 09:13:10 -0500 Subject: [PATCH 487/556] 1.16.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0585e8ab9..40a30ca79 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.15.2", + "version": "1.16.0", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 8cb451f20cff0a19fc9576fc2558307fb17a5710 Mon Sep 17 00:00:00 2001 From: Kris Williams Date: Sat, 3 Dec 2016 18:48:18 -0800 Subject: [PATCH 488/556] Enable proxy response to have multiple Set-Cookie raw headers #1101 --- examples/http/proxy-https-to-http.js | 2 +- examples/http/proxy-https-to-https.js | 2 +- lib/http-proxy/passes/web-outgoing.js | 20 ++++-- ...lib-http-proxy-passes-web-outgoing-test.js | 67 +++++++++++++++---- test/lib-https-proxy-test.js | 2 +- 5 files changed, 72 insertions(+), 21 deletions(-) diff --git a/examples/http/proxy-https-to-http.js b/examples/http/proxy-https-to-http.js index 227f4373e..5eb07a14c 100644 --- a/examples/http/proxy-https-to-http.js +++ b/examples/http/proxy-https-to-http.js @@ -39,7 +39,7 @@ var https = require('https'), http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('hello http over https\n'); - res.end(); + res.end(); }).listen(9009); // diff --git a/examples/http/proxy-https-to-https.js b/examples/http/proxy-https-to-https.js index 4cfe0c18c..e600f389c 100644 --- a/examples/http/proxy-https-to-https.js +++ b/examples/http/proxy-https-to-https.js @@ -43,7 +43,7 @@ var https = require('https'), https.createServer(httpsOpts, function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('hello https\n'); - res.end(); + res.end(); }).listen(9010); // diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 0c71e54ea..e7dc479f8 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -84,13 +84,18 @@ module.exports = { // <-- */ writeHeaders: function writeHeaders(req, res, proxyRes, options) { var rewriteCookieDomainConfig = options.cookieDomainRewrite, + // In proxyRes.rawHeaders Set-Cookie headers are sparse. + // so, we'll collect Set-Cookie headers, and set them in the response as an array. + setCookies = [], setHeader = function(key, header) { - if (header != undefined) { - if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') { - header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig); - } - res.setHeader(String(key).trim(), header); + if (header == undefined) return; + if (key.toLowerCase() !== 'set-cookie') { + return res.setHeader(String(key).trim(), header); } + if (rewriteCookieDomainConfig) { + header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig); + } + setCookies.push(header); // defer to the end when we have all of them }; if (typeof rewriteCookieDomainConfig === 'string') { //also test for '' @@ -104,13 +109,16 @@ module.exports = { // <-- var key = proxyRes.rawHeaders[i]; var header = proxyRes.rawHeaders[i + 1]; setHeader(key, header); - }; + } } else { Object.keys(proxyRes.headers).forEach(function(key) { var header = proxyRes.headers[key]; setHeader(key, header); }); } + if (setCookies.length) { + res.setHeader('Set-Cookie', setCookies.length === 1 ? setCookies[0] : setCookies); + } }, /** diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index 6a3ec2230..451f61419 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -233,12 +233,18 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { headers: { hey: 'hello', how: 'are you?', - 'set-cookie': 'hello; domain=my.domain; path=/' - }, + 'set-cookie': [ + 'hello; domain=my.domain; path=/', + 'there; domain=my.domain; path=/' + ] + } + }; + this.rawProxyRes = { rawHeaders: [ 'Hey', 'hello', 'How', 'are you?', - 'Set-Cookie', 'hello; domain=my.domain; path=/' + 'Set-Cookie', 'hello; domain=my.domain; path=/', + 'Set-Cookie', 'there; domain=my.domain; path=/' ] }; this.res = { @@ -253,11 +259,26 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { it('writes headers', function() { var options = {}; - httpProxy.writeHeaders({}, this.res, this.proxyRes, options); expect(this.res.headers.hey).to.eql('hello'); expect(this.res.headers.how).to.eql('are you?'); + + expect(this.res.headers).to.have.key('set-cookie'); + expect(this.res.headers['set-cookie']).to.be.an(Array); + expect(this.res.headers['set-cookie']).to.have.length(2); + }); + + it('writes raw headers', function() { + var options = {}; + httpProxy.writeHeaders({}, this.res, this.rawProxyRes, options); + + expect(this.res.headers.hey).to.eql('hello'); + expect(this.res.headers.how).to.eql('are you?'); + + expect(this.res.headers).to.have.key('set-cookie'); + expect(this.res.headers['set-cookie']).to.be.an(Array); + expect(this.res.headers['set-cookie']).to.have.length(2); }); it('does not rewrite domain', function() { @@ -265,7 +286,8 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { httpProxy.writeHeaders({}, this.res, this.proxyRes, options); - expect(this.res.headers['set-cookie']).to.eql('hello; domain=my.domain; path=/'); + expect(this.res.headers['set-cookie']) + .to.contain('hello; domain=my.domain; path=/'); }); it('rewrites domain', function() { @@ -275,7 +297,8 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { httpProxy.writeHeaders({}, this.res, this.proxyRes, options); - expect(this.res.headers['set-cookie']).to.eql('hello; domain=my.new.domain; path=/'); + expect(this.res.headers['set-cookie']) + .to.contain('hello; domain=my.new.domain; path=/'); }); it('removes domain', function() { @@ -285,7 +308,8 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { httpProxy.writeHeaders({}, this.res, this.proxyRes, options); - expect(this.res.headers['set-cookie']).to.eql('hello; path=/'); + expect(this.res.headers['set-cookie']) + .to.contain('hello; path=/'); }); it('rewrites headers with advanced configuration', function() { @@ -301,14 +325,33 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { 'hello-on-my.old.domain; domain=my.old.domain; path=/', 'hello-on-my.special.domain; domain=my.special.domain; path=/' ]; - var setCookieValueIndex = this.proxyRes.rawHeaders.indexOf('Set-Cookie') + 1; - this.proxyRes.rawHeaders[setCookieValueIndex] = [ + httpProxy.writeHeaders({}, this.res, this.proxyRes, options); + + expect(this.res.headers['set-cookie']) + .to.contain('hello-on-my.domain; path=/'); + expect(this.res.headers['set-cookie']) + .to.contain('hello-on-my.old.domain; domain=my.new.domain; path=/'); + expect(this.res.headers['set-cookie']) + .to.contain('hello-on-my.special.domain; domain=my.special.domain; path=/'); + }); + + it('rewrites raw headers with advanced configuration', function() { + var options = { + cookieDomainRewrite: { + '*': '', + 'my.old.domain': 'my.new.domain', + 'my.special.domain': 'my.special.domain' + } + }; + this.rawProxyRes.rawHeaders = this.rawProxyRes.rawHeaders.concat([ + 'Set-Cookie', 'hello-on-my.domain; domain=my.domain; path=/', + 'Set-Cookie', 'hello-on-my.old.domain; domain=my.old.domain; path=/', + 'Set-Cookie', 'hello-on-my.special.domain; domain=my.special.domain; path=/' - ]; - - httpProxy.writeHeaders({}, this.res, this.proxyRes, options); + ]); + httpProxy.writeHeaders({}, this.res, this.rawProxyRes, options); expect(this.res.headers['set-cookie']) .to.contain('hello-on-my.domain; path=/'); diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js index e0634cd52..a44fadbf8 100644 --- a/test/lib-https-proxy-test.js +++ b/test/lib-https-proxy-test.js @@ -19,7 +19,7 @@ Object.defineProperty(gen, 'port', { describe('lib/http-proxy.js', function() { describe('HTTPS #createProxyServer', function() { - describe('HTTPS to HTTP', 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) { From ac1a01b1f3caa3a2a9433341bf5e7a95072d6612 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sun, 4 Dec 2016 10:59:46 -0500 Subject: [PATCH 489/556] [dist] Version bump. 1.16.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 40a30ca79..1452445b7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.16.0", + "version": "1.16.1", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From 961f457622b931935d0af096c728fd8635606b80 Mon Sep 17 00:00:00 2001 From: Yuta Shimizu Date: Tue, 6 Dec 2016 23:51:01 +0900 Subject: [PATCH 490/556] [WIP] Revert default behavior of writeHeaders method (#1104) * Replace header key only * Add preserveHeaderKeyCase Option --- README.md | 1 + lib/http-proxy.js | 1 + lib/http-proxy/passes/web-outgoing.js | 34 ++++++++----------- ...lib-http-proxy-passes-web-outgoing-test.js | 13 +++++++ test/lib-http-proxy-test.js | 3 +- 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index ae8ed8110..49c49a396 100644 --- a/README.md +++ b/README.md @@ -333,6 +333,7 @@ proxyServer.listen(8015); * **ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required). * **localAddress**: Local interface string to bind for outgoing connections * **changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL +* **preserveHeaderKeyCase**: true/false, Default: false - specify whether you want to keep letter case of response header key * **auth**: Basic authentication i.e. 'user:password' to compute an Authorization header. * **hostRewrite**: rewrites the location hostname on (201/301/302/307/308) redirects. * **autoRewrite**: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false. diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 40f2e4b91..7dab7a48d 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -35,6 +35,7 @@ function createProxyServer(options) { * ignorePath: * localAddress : * changeOrigin: + * preserveHeaderKeyCase: * auth : Basic authentication i.e. 'user:password' to compute an Authorization header. * hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null. * autoRewrite: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index e7dc479f8..cff86a700 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -84,18 +84,14 @@ module.exports = { // <-- */ writeHeaders: function writeHeaders(req, res, proxyRes, options) { var rewriteCookieDomainConfig = options.cookieDomainRewrite, - // In proxyRes.rawHeaders Set-Cookie headers are sparse. - // so, we'll collect Set-Cookie headers, and set them in the response as an array. - setCookies = [], + preserveHeaderKeyCase = options.preserveHeaderKeyCase, + rawHeaderKeyMap, setHeader = function(key, header) { if (header == undefined) return; - if (key.toLowerCase() !== 'set-cookie') { - return res.setHeader(String(key).trim(), header); - } - if (rewriteCookieDomainConfig) { + if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') { header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig); } - setCookies.push(header); // defer to the end when we have all of them + res.setHeader(String(key).trim(), header); }; if (typeof rewriteCookieDomainConfig === 'string') { //also test for '' @@ -104,21 +100,21 @@ module.exports = { // <-- // message.rawHeaders is added in: v0.11.6 // https://nodejs.org/api/http.html#http_message_rawheaders - if (proxyRes.rawHeaders != undefined) { + if (preserveHeaderKeyCase && proxyRes.rawHeaders != undefined) { + rawHeaderKeyMap = {}; for (var i = 0; i < proxyRes.rawHeaders.length; i += 2) { var key = proxyRes.rawHeaders[i]; - var header = proxyRes.rawHeaders[i + 1]; - setHeader(key, header); + rawHeaderKeyMap[key.toLowerCase()] = key; } - } else { - Object.keys(proxyRes.headers).forEach(function(key) { - var header = proxyRes.headers[key]; - setHeader(key, header); - }); - } - if (setCookies.length) { - res.setHeader('Set-Cookie', setCookies.length === 1 ? setCookies[0] : setCookies); } + + Object.keys(proxyRes.headers).forEach(function(key) { + var header = proxyRes.headers[key]; + if (preserveHeaderKeyCase && rawHeaderKeyMap) { + key = rawHeaderKeyMap[key] || key; + } + setHeader(key, header); + }); }, /** diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index 451f61419..ae86904da 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -240,6 +240,14 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { } }; this.rawProxyRes = { + headers: { + hey: 'hello', + how: 'are you?', + 'set-cookie': [ + 'hello; domain=my.domain; path=/', + 'there; domain=my.domain; path=/' + ] + }, rawHeaders: [ 'Hey', 'hello', 'How', 'are you?', @@ -343,6 +351,11 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { 'my.special.domain': 'my.special.domain' } }; + this.rawProxyRes.headers['set-cookie'] = [ + 'hello-on-my.domain; domain=my.domain; path=/', + 'hello-on-my.old.domain; domain=my.old.domain; path=/', + 'hello-on-my.special.domain; domain=my.special.domain; path=/' + ]; this.rawProxyRes.rawHeaders = this.rawProxyRes.rawHeaders.concat([ 'Set-Cookie', 'hello-on-my.domain; domain=my.domain; path=/', diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 8b024c9f1..06702be05 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -130,7 +130,8 @@ describe('lib/http-proxy.js', 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 + target: 'http://127.0.0.1:' + ports.source, + preserveHeaderKeyCase: true }).listen(ports.proxy); var source = http.createServer(function(req, res) { From c1fb596b856df971d291585ccf105233f7deca51 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Tue, 6 Dec 2016 10:49:02 -0500 Subject: [PATCH 491/556] 1.16.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1452445b7..caf4193de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.16.1", + "version": "1.16.2", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From d4d85ac5c4bc812a03b02ade2b4d089e6558ac36 Mon Sep 17 00:00:00 2001 From: Luigi Pinca Date: Fri, 16 Dec 2016 18:28:52 +0100 Subject: [PATCH 492/556] [deps] Update eventemitter3 to version 2.0.x (#1109) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index caf4193de..3718993c3 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ ], "main": "index.js", "dependencies": { - "eventemitter3": "1.x.x", + "eventemitter3": "2.0.x", "requires-port": "1.x.x" }, "devDependencies": { From a539f3cbc10f44e2424a30e2d8aa4442df25bab8 Mon Sep 17 00:00:00 2001 From: Ivan Nieto Date: Sat, 24 Dec 2016 19:27:54 +0100 Subject: [PATCH 493/556] Add Code Of Conduct (#1119) * Add Code Of Conduct * Update CODE_OF_CONDUCT.md Fix placeholder --- CODE_OF_CONDUCT.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..78e80cc61 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ From d73f1ee8735aaa3f06329b64d2eace755f4a2b3b Mon Sep 17 00:00:00 2001 From: Ivan Nieto Date: Sat, 24 Dec 2016 23:02:41 +0100 Subject: [PATCH 494/556] Update README.md with CoC link (#1120) * Add Code Of Conduct * Update CODE_OF_CONDUCT.md Fix placeholder * Update REAME.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 49c49a396..8e800ff55 100644 --- a/README.md +++ b/README.md @@ -460,6 +460,8 @@ Logo created by [Diego Pasquali](http://dribbble.com/diegopq) ### Contributing and Issues +* Read carefully our [Code Of Conduct](https://github.com/nodejitsu/node-http-proxy/blob/master/CODE_OF_CONDUCT.md) + * Search on Google/Github * If you can't find anything, open an issue * If you feel comfortable about fixing the issue, fork the repo From e6f24ba6173c4fdd26089b3c729de5dbdd71ad74 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sat, 24 Dec 2016 17:03:33 -0500 Subject: [PATCH 495/556] [fix] rm newline --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 8e800ff55..edec456b0 100644 --- a/README.md +++ b/README.md @@ -461,7 +461,6 @@ Logo created by [Diego Pasquali](http://dribbble.com/diegopq) ### Contributing and Issues * Read carefully our [Code Of Conduct](https://github.com/nodejitsu/node-http-proxy/blob/master/CODE_OF_CONDUCT.md) - * Search on Google/Github * If you can't find anything, open an issue * If you feel comfortable about fixing the issue, fork the repo From c979ba9f2cbb6988a210ca42bf59698545496723 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Wed, 11 Jan 2017 12:53:05 -0800 Subject: [PATCH 496/556] Update README.md (#1131) Update link to properties --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index edec456b0..40367e111 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ 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#L33-L50)) +an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L22-L50)) ```javascript var httpProxy = require('http-proxy'); From 812757541db6a6eb9021dc459830d7c0a9b4429d Mon Sep 17 00:00:00 2001 From: Georgi Yordanov Date: Wed, 3 Jan 2018 02:48:17 +0200 Subject: [PATCH 497/556] Fix overwriting of global options (#1074) --- lib/http-proxy/index.js | 13 +++--- ...lib-http-proxy-passes-web-incoming-test.js | 45 +++++++++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/lib/http-proxy/index.js b/lib/http-proxy/index.js index caaa10bd4..977a4b362 100644 --- a/lib/http-proxy/index.js +++ b/lib/http-proxy/index.js @@ -41,14 +41,15 @@ function createRightProxy(type) { cntr--; } + var requestOptions = options; if( !(args[cntr] instanceof Buffer) && args[cntr] !== res ) { //Copy global options - options = extend({}, options); + requestOptions = extend({}, options); //Overwrite with request options - extend(options, args[cntr]); + extend(requestOptions, args[cntr]); cntr--; } @@ -60,11 +61,11 @@ function createRightProxy(type) { /* optional args parse end */ ['target', 'forward'].forEach(function(e) { - if (typeof options[e] === 'string') - options[e] = parse_url(options[e]); + if (typeof requestOptions[e] === 'string') + requestOptions[e] = parse_url(requestOptions[e]); }); - if (!options.target && !options.forward) { + if (!requestOptions.target && !requestOptions.forward) { return this.emit('error', new Error('Must provide a proper URL as target')); } @@ -77,7 +78,7 @@ function createRightProxy(type) { * refer to the connection socket * pass(req, socket, options, head) */ - if(passes[i](req, res, options, head, this, cbl)) { // passes can return a truthy value to halt the loop + if(passes[i](req, res, requestOptions, head, this, cbl)) { // passes can return a truthy value to halt the loop break; } } diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 1996276d2..7a34a58bc 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -367,4 +367,49 @@ describe('#createProxyServer.web() using own http server', function () { http.request('http://127.0.0.1:8081', function() {}).end(); }); + + it('should proxy requests to multiple servers with different options', function (done) { + var proxy = httpProxy.createProxyServer(); + + // proxies to two servers depending on url, rewriting the url as well + // http://127.0.0.1:8080/s1/ -> http://127.0.0.1:8081/ + // http://127.0.0.1:8080/ -> http://127.0.0.1:8082/ + function requestHandler(req, res) { + if (req.url.indexOf('/s1/') === 0) { + proxy.web(req, res, { + ignorePath: true, + target: 'http://127.0.0.1:8081' + req.url.substring(3) + }); + } else { + proxy.web(req, res, { + target: 'http://127.0.0.1:8082' + }); + } + } + + var proxyServer = http.createServer(requestHandler); + + var source1 = http.createServer(function(req, res) { + expect(req.method).to.eql('GET'); + expect(req.headers.host.split(':')[1]).to.eql('8080'); + expect(req.url).to.eql('/test1'); + }); + + var source2 = http.createServer(function(req, res) { + source1.close(); + source2.close(); + proxyServer.close(); + expect(req.method).to.eql('GET'); + expect(req.headers.host.split(':')[1]).to.eql('8080'); + expect(req.url).to.eql('/test2'); + done(); + }); + + proxyServer.listen('8080'); + source1.listen('8081'); + source2.listen('8082'); + + http.request('http://127.0.0.1:8080/s1/test1', function() {}).end(); + http.request('http://127.0.0.1:8080/test2', function() {}).end(); + }); }); From 09dcb984565dabb159a01a75a188b974f8c176ad Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 19 Apr 2018 13:22:35 -0400 Subject: [PATCH 498/556] [dist] make tests work reliably, add package-lock.json --- .gitignore | 1 + .travis.yml | 8 +- package-lock.json | 3418 +++++++++++++++++++++++++++++++++++ package.json | 27 +- test/lib-http-proxy-test.js | 1 + 5 files changed, 3431 insertions(+), 24 deletions(-) create mode 100644 package-lock.json diff --git a/.gitignore b/.gitignore index fdd88f86d..347bedbb4 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ notes primus-proxy.js tes.js npm-debug.log +.nyc_output diff --git a/.travis.yml b/.travis.yml index 975e73b04..c687bb062 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,8 @@ sudo: false language: node_js node_js: - - "0.10" - - "0.12" - - "4.2" - "6" - -before_install: - - travis_retry npm install -g npm@2.14.5 - - travis_retry npm install + - "8" script: - npm test diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..d02391c37 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3418 @@ +{ + "name": "http-proxy", + "version": "1.16.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "2.1.18", + "negotiator": "0.6.1" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", + "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "dev": true, + "requires": { + "lodash": "4.17.5" + } + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "bindings": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", + "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=", + "dev": true, + "optional": true + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "bufferutil": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.2.1.tgz", + "integrity": "sha1-N75dNuHgZJIiHmjUdLGsWOUQy9c=", + "dev": true, + "optional": true, + "requires": { + "bindings": "1.2.1", + "nan": "2.10.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "engine.io": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", + "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "dev": true, + "requires": { + "accepts": "1.3.5", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "3.1.0", + "engine.io-parser": "2.1.2", + "ws": "3.3.3" + }, + "dependencies": { + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.1", + "ultron": "1.1.1" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "3.1.0", + "engine.io-parser": "2.1.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "3.3.3", + "xmlhttprequest-ssl": "1.5.5", + "yeast": "0.1.2" + }, + "dependencies": { + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.1", + "ultron": "1.1.1" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eventemitter3": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.0.1.tgz", + "integrity": "sha512-QOCPu979MMWX9XNlfRZoin+Wm+bK1SP7vv3NGUniYwuSJK/+cPA10blMaeRgzg31RvoSFk6FsCDVa4vNryBTGA==" + }, + "expect.js": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/expect.js/-/expect.js-0.3.1.tgz", + "integrity": "sha1-sKWaDS7/VDdUTr8M6qYBWEHQm1s=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "has-binary2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz", + "integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "dev": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "1.33.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "mocha": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", + "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "dev": true, + "optional": true + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "nyc": { + "version": "11.7.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.7.1.tgz", + "integrity": "sha512-EGePURSKUEpS1jWnEKAMhY+GWZzi7JC+f8iBDOATaOsLZW5hM/9eYx2dHGaEXa1ITvMm44CJugMksvP3NwMQMw==", + "dev": true, + "requires": { + "archy": "1.0.0", + "arrify": "1.0.1", + "caching-transform": "1.0.1", + "convert-source-map": "1.5.1", + "debug-log": "1.0.1", + "default-require-extensions": "1.0.0", + "find-cache-dir": "0.1.1", + "find-up": "2.1.0", + "foreground-child": "1.5.6", + "glob": "7.1.2", + "istanbul-lib-coverage": "1.2.0", + "istanbul-lib-hook": "1.1.0", + "istanbul-lib-instrument": "1.10.1", + "istanbul-lib-report": "1.1.3", + "istanbul-lib-source-maps": "1.2.3", + "istanbul-reports": "1.4.0", + "md5-hex": "1.3.0", + "merge-source-map": "1.1.0", + "micromatch": "2.3.11", + "mkdirp": "0.5.1", + "resolve-from": "2.0.0", + "rimraf": "2.6.2", + "signal-exit": "3.0.2", + "spawn-wrap": "1.4.2", + "test-exclude": "4.2.1", + "yargs": "11.1.0", + "yargs-parser": "8.1.0" + }, + "dependencies": { + "align-text": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true, + "dev": true + }, + "append-transform": { + "version": "0.4.0", + "bundled": true, + "dev": true, + "requires": { + "default-require-extensions": "1.0.0" + } + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "arr-diff": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "async": { + "version": "1.5.2", + "bundled": true, + "dev": true + }, + "atob": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-generator": { + "version": "6.26.1", + "bundled": true, + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.5", + "source-map": "0.5.7", + "trim-right": "1.0.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "core-js": "2.5.5", + "regenerator-runtime": "0.11.1" + } + }, + "babel-template": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.5" + } + }, + "babel-traverse": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.5" + } + }, + "babel-types": { + "version": "6.26.0", + "bundled": true, + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "base": { + "version": "0.11.2", + "bundled": true, + "dev": true, + "requires": { + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "bundled": true, + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "caching-transform": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "md5-hex": "1.3.0", + "mkdirp": "0.5.1", + "write-file-atomic": "1.3.4" + } + }, + "camelcase": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true + }, + "center-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "class-utils": { + "version": "0.3.6", + "bundled": true, + "dev": true, + "requires": { + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "cliui": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "map-visit": "1.0.0", + "object-visit": "1.0.1" + } + }, + "commondir": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "convert-source-map": { + "version": "1.5.1", + "bundled": true, + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "core-js": { + "version": "2.5.5", + "bundled": true, + "dev": true + }, + "cross-spawn": { + "version": "4.0.2", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "4.1.2", + "which": "1.3.0" + } + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "debug-log": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "strip-bom": "2.0.0" + } + }, + "define-property": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "1.0.2", + "isobject": "3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "detect-indent": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "error-ex": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true, + "dev": true + }, + "execa": { + "version": "0.7.0", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "dev": true, + "requires": { + "lru-cache": "4.1.2", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + } + } + }, + "expand-brackets": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "bundled": true, + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "extend-shallow": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } + } + } + }, + "extglob": { + "version": "0.3.2", + "bundled": true, + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "filename-regex": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "fill-range": { + "version": "2.2.3", + "bundled": true, + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "find-cache-dir": { + "version": "0.1.1", + "bundled": true, + "dev": true, + "requires": { + "commondir": "1.0.1", + "mkdirp": "0.5.1", + "pkg-dir": "1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "for-in": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "for-own": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "foreground-child": { + "version": "1.5.6", + "bundled": true, + "dev": true, + "requires": { + "cross-spawn": "4.0.2", + "signal-exit": "3.0.2" + } + }, + "fragment-cache": { + "version": "0.2.1", + "bundled": true, + "dev": true, + "requires": { + "map-cache": "0.2.2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "get-caller-file": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "get-value": { + "version": "2.0.6", + "bundled": true, + "dev": true + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "bundled": true, + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "globals": { + "version": "9.18.0", + "bundled": true, + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "bundled": true, + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "bundled": true, + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "has-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "has-values": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "hosted-git-info": { + "version": "2.6.0", + "bundled": true, + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "invariant": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "bundled": true, + "dev": true + } + } + }, + "is-dotfile": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-odd": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-number": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "bundled": true, + "dev": true + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "isobject": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "istanbul-lib-coverage": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "append-transform": "0.4.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.10.1", + "bundled": true, + "dev": true, + "requires": { + "babel-generator": "6.26.1", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.2.0", + "semver": "5.5.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "requires": { + "istanbul-lib-coverage": "1.2.0", + "mkdirp": "0.5.1", + "path-parse": "1.0.5", + "supports-color": "3.2.3" + }, + "dependencies": { + "supports-color": { + "version": "3.2.3", + "bundled": true, + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.3", + "bundled": true, + "dev": true, + "requires": { + "debug": "3.1.0", + "istanbul-lib-coverage": "1.2.0", + "mkdirp": "0.5.1", + "rimraf": "2.6.2", + "source-map": "0.5.7" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "istanbul-reports": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "handlebars": "4.0.11" + } + }, + "js-tokens": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "jsesc": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + }, + "lazy-cache": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "optional": true + }, + "lcid": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "lodash": { + "version": "4.17.5", + "bundled": true, + "dev": true + }, + "longest": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "lru-cache": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "map-cache": { + "version": "0.2.2", + "bundled": true, + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "object-visit": "1.0.1" + } + }, + "md5-hex": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "md5-o-matic": "0.1.1" + } + }, + "md5-o-matic": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "mem": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "merge-source-map": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "bundled": true, + "dev": true + } + } + }, + "micromatch": { + "version": "2.3.11", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "bundled": true, + "dev": true, + "requires": { + "for-in": "1.0.2", + "is-extendable": "1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "nanomatch": { + "version": "1.2.9", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-odd": "2.0.0", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "dev": true, + "requires": { + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "normalize-path": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true, + "requires": { + "path-key": "2.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "requires": { + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "object.omit": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "optimist": { + "version": "0.6.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "1.2.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "parse-glob": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "pascalcase": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "path-type": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "bundled": true, + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "find-up": "1.1.2" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "preserve": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "randomatic": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "read-pkg": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + } + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "bundled": true, + "dev": true + }, + "regex-cache": { + "version": "0.4.4", + "bundled": true, + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "bundled": true, + "dev": true + }, + "repeating": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "resolve-from": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "ret": { + "version": "0.1.15", + "bundled": true, + "dev": true + }, + "right-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-regex": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "requires": { + "ret": "0.1.15" + } + }, + "semver": { + "version": "5.5.0", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "set-value": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "slide": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "bundled": true, + "dev": true, + "requires": { + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.1", + "use": "3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "source-map": { + "version": "0.5.7", + "bundled": true, + "dev": true + }, + "source-map-resolve": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "atob": "2.1.0", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "bundled": true, + "dev": true + }, + "spawn-wrap": { + "version": "1.4.2", + "bundled": true, + "dev": true, + "requires": { + "foreground-child": "1.5.6", + "mkdirp": "0.5.1", + "os-homedir": "1.0.2", + "rimraf": "2.6.2", + "signal-exit": "3.0.2", + "which": "1.3.0" + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "split-string": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "3.0.2" + } + }, + "static-extend": { + "version": "0.1.2", + "bundled": true, + "dev": true, + "requires": { + "define-property": "0.2.5", + "object-copy": "0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + } + } + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "test-exclude": { + "version": "4.2.1", + "bundled": true, + "dev": true, + "requires": { + "arrify": "1.0.1", + "micromatch": "3.1.10", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "require-main-filename": "1.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "braces": { + "version": "2.3.2", + "bundled": true, + "dev": true, + "requires": { + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.2", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "bundled": true, + "dev": true, + "requires": { + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "bundled": true, + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "bundled": true, + "dev": true, + "requires": { + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + } + }, + "is-descriptor": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "bundled": true, + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.9", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + } + } + } + }, + "to-fast-properties": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "to-regex": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "requires": { + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "requires": { + "is-number": "3.0.0", + "repeat-string": "1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + } + } + }, + "trim-right": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "union-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "set-value": { + "version": "0.4.3", + "bundled": true, + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" + } + } + } + }, + "unset-value": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "has-value": "0.3.1", + "isobject": "3.0.1" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "bundled": true, + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "isobject": { + "version": "3.0.1", + "bundled": true, + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "bundled": true, + "dev": true + }, + "use": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "bundled": true, + "dev": true + } + } + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "which": { + "version": "1.3.0", + "bundled": true, + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "window-size": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "0.0.3", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "1.3.4", + "bundled": true, + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + }, + "y18n": { + "version": "3.2.1", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "11.1.0", + "bundled": true, + "dev": true, + "requires": { + "cliui": "4.0.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "cliui": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "yargs-parser": { + "version": "9.0.2", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "8.1.0", + "bundled": true, + "dev": true, + "requires": { + "camelcase": "4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + } + } + } + } + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", + "dev": true + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "socket.io": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.0.tgz", + "integrity": "sha512-KS+3CNWWNtLbVN5j0/B+1hjxRzey+oTK6ejpAOoxMZis6aXeB8cUtfuvjHl97tuZx+t/qD/VyqFMjuzu2Js6uQ==", + "dev": true, + "requires": { + "debug": "3.1.0", + "engine.io": "3.2.0", + "has-binary2": "1.0.2", + "socket.io-adapter": "1.1.1", + "socket.io-client": "2.1.0", + "socket.io-parser": "3.2.0" + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.0.tgz", + "integrity": "sha512-TvKPpL0cBON5LduQfR8Rxrr+ktj70bLXGvqHCL3er5avBXruB3gpnbaud5ikFYVfANH1gCABAvo0qN8Axpg2ew==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "3.1.0", + "engine.io-client": "3.2.1", + "has-binary2": "1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "3.2.0", + "to-array": "0.1.4" + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "sse": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/sse/-/sse-0.0.6.tgz", + "integrity": "sha1-MZJGHfo4x4Qk3Zv46gJWGaElqhA=", + "dev": true, + "requires": { + "options": "0.0.6" + } + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "utf-8-validate": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.2.2.tgz", + "integrity": "sha1-i7hxpHQeCFxwSHynrNvX1tNgKes=", + "dev": true, + "optional": true, + "requires": { + "bindings": "1.2.1", + "nan": "2.4.0" + }, + "dependencies": { + "nan": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz", + "integrity": "sha1-+zxZ1F/k7/4hXwuJD4rfbrMtIjI=", + "dev": true, + "optional": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-0.8.1.tgz", + "integrity": "sha1-a2UnO5kZPF8Gekz1gJWY93fjt1k=", + "dev": true, + "requires": { + "bufferutil": "1.2.1", + "options": "0.0.6", + "ultron": "1.0.2", + "utf-8-validate": "1.2.2" + }, + "dependencies": { + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", + "dev": true + } + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + } + } +} diff --git a/package.json b/package.json index 3718993c3..950cbfea0 100644 --- a/package.json +++ b/package.json @@ -12,33 +12,26 @@ ], "main": "index.js", "dependencies": { - "eventemitter3": "2.0.x", - "requires-port": "1.x.x" + "eventemitter3": "^3.0.0", + "requires-port": "^1.0.0" }, "devDependencies": { - "async": "*", - "blanket": "*", - "coveralls": "*", - "dox": "*", - "expect.js": "*", - "mocha": "*", - "mocha-lcov-reporter": "*", + "async": "^2.0.0", + "expect.js": "~0.3.1", + "mocha": "^3.5.3", + "nyc": "^11.7.1", "semver": "^5.0.3", - "socket.io": "*", - "socket.io-client": "*", + "socket.io": "^2.1.0", + "socket.io-client": "^2.1.0", "sse": "0.0.6", "ws": "^0.8.0" }, "scripts": { - "coveralls": "mocha --require blanket --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js", - "blanket": { - "pattern": "lib/http-proxy" - }, "test": "mocha test/*-test.js", - "test-cov": "mocha --require blanket -R html-cov > cov/coverage.html" + "test-cov": "nyc npm test" }, "engines": { - "node": ">=0.10.0" + "node": ">=4.0.0" }, "license": "MIT" } diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index 06702be05..ec6273f94 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -483,6 +483,7 @@ describe('lib/http-proxy.js', function() { proxyServer.on('close', function() { proxyServer.close(); server.close(); + destiny.close(); if (count == 1) { done(); } }); From f4ff1006b9e71eb4185a3edf03333dbe514a84c9 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 19 Apr 2018 16:10:05 -0400 Subject: [PATCH 499/556] [wip] proper tests and reporting --- .gitignore | 1 + .travis.yml | 6 ++++-- README.md | 9 ++------- package.json | 4 ++-- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 347bedbb4..02593a904 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ primus-proxy.js tes.js npm-debug.log .nyc_output +coverage diff --git a/.travis.yml b/.travis.yml index c687bb062..956c0fcbe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,10 +3,12 @@ language: node_js node_js: - "6" - "8" - script: - npm test - +after_success: + - bash <(curl -s https://codecov.io/bash) +matrix: + fast_finish: true notifications: email: - travis@nodejitsu.com diff --git a/README.md b/README.md index 40367e111..c66a58aa2 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,7 @@ node-http-proxy ======= -

- -    - - -

+[![Build Status](https://travis-ci.org/nodejitsu/node-http-proxy.svg?branch=master)](https://travis-ci.org/nodejitsu/node-http-proxy) `node-http-proxy` is an HTTP programmable proxying library that supports websockets. It is suitable for implementing components such as reverse @@ -341,7 +336,7 @@ proxyServer.listen(8015); * **cookieDomainRewrite**: rewrites domain of `set-cookie` headers. Possible values: * `false` (default): disable cookie rewriting * String: new domain, for example `cookieDomainRewrite: "new.domain"`. To remove the domain, use `cookieDomainRewrite: ""`. - * Object: mapping of domains to new domains, use `"*"` to match all domains. + * Object: mapping of domains to new domains, use `"*"` to match all domains. For example keep one domain unchanged, rewrite one domain and remove other domains: ``` cookieDomainRewrite: { diff --git a/package.json b/package.json index 950cbfea0..8950610ff 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,8 @@ "ws": "^0.8.0" }, "scripts": { - "test": "mocha test/*-test.js", - "test-cov": "nyc npm test" + "mocha": "mocha test/*-test.js", + "test": "nyc --reporter=text --reporter=lcov npm run mocha" }, "engines": { "node": ">=4.0.0" From a4bccc332d36d7db93db984674cd7e51b43a1b99 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 19 Apr 2018 16:16:33 -0400 Subject: [PATCH 500/556] [dist][test] codecov config --- codecov.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..9937c4cc4 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,10 @@ +coverage: + parsers: + javascript: + enable_partials: yes + status: + project: + default: + target: "80%" + patch: + enabled: false From 543636d0f662308ec8c9afdbf641f4036f002bfd Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 19 Apr 2018 16:22:46 -0400 Subject: [PATCH 501/556] [fix] move badges --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index c66a58aa2..e7eebc34a 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,7 @@

-node-http-proxy -======= - -[![Build Status](https://travis-ci.org/nodejitsu/node-http-proxy.svg?branch=master)](https://travis-ci.org/nodejitsu/node-http-proxy) +# node-http-proxy [![Build Status](https://travis-ci.org/nodejitsu/node-http-proxy.svg?branch=master)](https://travis-ci.org/nodejitsu/node-http-proxy) [![codecov](https://codecov.io/gh/nodejitsu/node-http-proxy/branch/master/graph/badge.svg)](https://codecov.io/gh/nodejitsu/node-http-proxy) `node-http-proxy` is an HTTP programmable proxying library that supports websockets. It is suitable for implementing components such as reverse From 2c98416ac2bf17bb5f515b9e10ee4485f5913846 Mon Sep 17 00:00:00 2001 From: Sean Willis Date: Tue, 20 Feb 2018 17:50:59 -0800 Subject: [PATCH 502/556] Adding ability to set cookie path --- lib/http-proxy/common.js | 29 ++++++++++--------- lib/http-proxy/passes/web-outgoing.js | 10 ++++++- ...lib-http-proxy-passes-web-outgoing-test.js | 11 +++++++ 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index aa9700234..c00994cde 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -5,7 +5,7 @@ var common = exports, var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i, isSSL = /^https|wss/, - cookieDomainRegex = /(;\s*domain=)([^;]+)/i; + cookieProps = ['domain', 'path']; /** * Simple Regex for testing if protocol is https @@ -211,27 +211,30 @@ common.urlJoin = function() { * * @api private */ -common.rewriteCookieDomain = function rewriteCookieDomain(header, config) { +common.rewriteCookieProperty = function rewriteCookieProperty(header, config, property) { + if(cookieProps.indexOf(property) === -1) //Property not supported + return header; + if (Array.isArray(header)) { return header.map(function (headerElement) { - return rewriteCookieDomain(headerElement, config); + return rewriteCookieProperty(headerElement, config, property); }); } - return header.replace(cookieDomainRegex, function(match, prefix, previousDomain) { - var newDomain; - if (previousDomain in config) { - newDomain = config[previousDomain]; + return header.replace(new RegExp("(;\\s*" + property + "=)([^;]+)"), function(match, prefix, previousValue) { + var newValue; + if (previousValue in config) { + newValue = config[previousValue]; } else if ('*' in config) { - newDomain = config['*']; + newValue = config['*']; } else { - //no match, return previous domain + //no match, return previous value return match; } - if (newDomain) { - //replace domain - return prefix + newDomain; + if (newValue) { + //replace value + return prefix + newValue; } else { - //remove domain + //remove value return ''; } }); diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index cff86a700..05ded881c 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -84,12 +84,16 @@ module.exports = { // <-- */ writeHeaders: function writeHeaders(req, res, proxyRes, options) { var rewriteCookieDomainConfig = options.cookieDomainRewrite, + rewriteCookiePathConfig = options.cookiePathRewrite, preserveHeaderKeyCase = options.preserveHeaderKeyCase, rawHeaderKeyMap, setHeader = function(key, header) { if (header == undefined) return; if (rewriteCookieDomainConfig && key.toLowerCase() === 'set-cookie') { - header = common.rewriteCookieDomain(header, rewriteCookieDomainConfig); + header = common.rewriteCookieProperty(header, rewriteCookieDomainConfig, 'domain'); + } + if (rewriteCookiePathConfig && key.toLowerCase() === 'set-cookie') { + header = common.rewriteCookieProperty(header, rewriteCookiePathConfig, 'path'); } res.setHeader(String(key).trim(), header); }; @@ -98,6 +102,10 @@ module.exports = { // <-- rewriteCookieDomainConfig = { '*': rewriteCookieDomainConfig }; } + if (typeof rewriteCookiePathConfig === 'string') { //also test for '' + rewriteCookiePathConfig = { '*': rewriteCookiePathConfig }; + } + // message.rawHeaders is added in: v0.11.6 // https://nodejs.org/api/http.html#http_message_rawheaders if (preserveHeaderKeyCase && proxyRes.rawHeaders != undefined) { diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index ae86904da..aef521cf0 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -298,6 +298,17 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { .to.contain('hello; domain=my.domain; path=/'); }); + it('rewrites path', function() { + var options = { + cookiePathRewrite: '/dummyPath' + }; + + httpProxy.writeHeaders({}, this.res, this.proxyRes, options); + + expect(this.res.headers['set-cookie']) + .to.contain('hello; domain=my.domain; path=/dummyPath'); + }); + it('rewrites domain', function() { var options = { cookieDomainRewrite: 'my.new.domain' From 50f58b4cd9b4422a11512a6a065432159b5bc806 Mon Sep 17 00:00:00 2001 From: Sean Willis Date: Tue, 20 Feb 2018 20:40:49 -0800 Subject: [PATCH 503/556] Forgot 'i' flag when changing from regex shorthand to string. --- lib/http-proxy/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index c00994cde..8fae2cd25 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -220,7 +220,7 @@ common.rewriteCookieProperty = function rewriteCookieProperty(header, config, pr return rewriteCookieProperty(headerElement, config, property); }); } - return header.replace(new RegExp("(;\\s*" + property + "=)([^;]+)"), function(match, prefix, previousValue) { + return header.replace(new RegExp("(;\\s*" + property + "=)([^;]+)", 'i'), function(match, prefix, previousValue) { var newValue; if (previousValue in config) { newValue = config[previousValue]; From f5c2381395e01bf8d6655cc70e14032c8f0aaa67 Mon Sep 17 00:00:00 2001 From: Sean Willis Date: Tue, 20 Feb 2018 20:53:39 -0800 Subject: [PATCH 504/556] Updating docs and adding more tests. --- README.md | 12 ++++++++ ...lib-http-proxy-passes-web-outgoing-test.js | 28 ++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e7eebc34a..4a56ff691 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,18 @@ proxyServer.listen(8015); "*": "" } ``` +* **cookiePathRewrite**: rewrites path of `set-cookie` headers. Possible values: + * `false` (default): disable cookie rewriting + * String: new path, for example `cookiePathRewrite: "/newPath/"`. To remove the path, use `cookiePathRewrite: ""`. To set path to root use `cookiePathRewrite: "/"`. + * Object: mapping of paths to new paths, use `"*"` to match all paths. + For example keep one path unchanged, rewrite one path and remove other paths: + ``` + cookiePathRewrite: { + "/unchanged.path/": "/unchanged.path/", + "/old.path/": "/new.path/", + "*": "" + } + ``` * **headers**: object with extra headers to be added to target requests. * **proxyTimeout**: timeout (in millis) when proxy receives no response from target diff --git a/test/lib-http-proxy-passes-web-outgoing-test.js b/test/lib-http-proxy-passes-web-outgoing-test.js index aef521cf0..a509cf1ae 100644 --- a/test/lib-http-proxy-passes-web-outgoing-test.js +++ b/test/lib-http-proxy-passes-web-outgoing-test.js @@ -289,7 +289,18 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { expect(this.res.headers['set-cookie']).to.have.length(2); }); - it('does not rewrite domain', function() { + it('rewrites path', function() { + var options = { + cookiePathRewrite: '/dummyPath' + }; + + httpProxy.writeHeaders({}, this.res, this.proxyRes, options); + + expect(this.res.headers['set-cookie']) + .to.contain('hello; domain=my.domain; path=/dummyPath'); + }); + + it('does not rewrite path', function() { var options = {}; httpProxy.writeHeaders({}, this.res, this.proxyRes, options); @@ -298,15 +309,24 @@ describe('lib/http-proxy/passes/web-outgoing.js', function () { .to.contain('hello; domain=my.domain; path=/'); }); - it('rewrites path', function() { + it('removes path', function() { var options = { - cookiePathRewrite: '/dummyPath' + cookiePathRewrite: '' }; httpProxy.writeHeaders({}, this.res, this.proxyRes, options); expect(this.res.headers['set-cookie']) - .to.contain('hello; domain=my.domain; path=/dummyPath'); + .to.contain('hello; domain=my.domain'); + }); + + it('does not rewrite domain', function() { + var options = {}; + + httpProxy.writeHeaders({}, this.res, this.proxyRes, options); + + expect(this.res.headers['set-cookie']) + .to.contain('hello; domain=my.domain; path=/'); }); it('rewrites domain', function() { From bc6a23709c37c65b5b16cc802d05cb57f099b0ce Mon Sep 17 00:00:00 2001 From: Sean Willis Date: Wed, 21 Feb 2018 10:19:34 -0800 Subject: [PATCH 505/556] Removing unnecessary check since this is a private API --- lib/http-proxy/common.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index 8fae2cd25..b2f302cad 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -4,8 +4,7 @@ var common = exports, required = require('requires-port'); var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i, - isSSL = /^https|wss/, - cookieProps = ['domain', 'path']; + isSSL = /^https|wss/; /** * Simple Regex for testing if protocol is https @@ -212,9 +211,6 @@ common.urlJoin = function() { * @api private */ common.rewriteCookieProperty = function rewriteCookieProperty(header, config, property) { - if(cookieProps.indexOf(property) === -1) //Property not supported - return header; - if (Array.isArray(header)) { return header.map(function (headerElement) { return rewriteCookieProperty(headerElement, config, property); From de1b80851ab1b1251b5eaeaf0beab164024f09b6 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 19 Apr 2018 16:38:15 -0400 Subject: [PATCH 506/556] [fix] slightly more tolerant --- codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codecov.yml b/codecov.yml index 9937c4cc4..cafdd1ced 100644 --- a/codecov.yml +++ b/codecov.yml @@ -5,6 +5,6 @@ coverage: status: project: default: - target: "80%" + target: "70%" patch: enabled: false From 107c18720c3906f9049cc14d075b31910c0ccf55 Mon Sep 17 00:00:00 2001 From: jlaamanen Date: Wed, 31 Jan 2018 09:00:24 +0200 Subject: [PATCH 507/556] Added timeout option to docs --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4a56ff691..258245d02 100644 --- a/README.md +++ b/README.md @@ -355,7 +355,8 @@ proxyServer.listen(8015); } ``` * **headers**: object with extra headers to be added to target requests. -* **proxyTimeout**: timeout (in millis) when proxy receives no response from target +* **proxyTimeout**: timeout (in millis) for outgoing proxy requests +* **timeout**: timeout (in millis) for incoming requests **NOTE:** `options.ws` and `options.ssl` are optional. From c5d846648304f2e36a172b25d9fb8300d8131f8c Mon Sep 17 00:00:00 2001 From: Aydin Date: Tue, 23 Jan 2018 12:40:08 +0100 Subject: [PATCH 508/556] Update common.js Add method parameter to options for overriding the proxy-outgoing HTTP-method --- lib/http-proxy/common.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/common.js b/lib/http-proxy/common.js index b2f302cad..6513e81d8 100644 --- a/lib/http-proxy/common.js +++ b/lib/http-proxy/common.js @@ -39,7 +39,7 @@ common.setupOutgoing = function(outgoing, options, req, forward) { function(e) { outgoing[e] = options[forward || 'target'][e]; } ); - outgoing.method = req.method; + outgoing.method = options.method || req.method; outgoing.headers = extend({}, req.headers); if (options.headers){ From 89f9ef87e0532d54d086719c5ace1a968a42e51b Mon Sep 17 00:00:00 2001 From: "shaohui.tsh" Date: Thu, 7 Dec 2017 11:12:37 +0800 Subject: [PATCH 509/556] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0response?= =?UTF-8?q?=E8=87=AA=E5=A4=84=E7=90=86=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http-proxy/passes/web-incoming.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 5cb0b03d3..2e72f312a 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -162,16 +162,19 @@ module.exports = { proxyReq.on('response', function(proxyRes) { if(server) { server.emit('proxyRes', proxyRes, req, res); } - for(var i=0; i < web_o.length; i++) { - if(web_o[i](req, res, proxyRes, options)) { break; } - } // Allow us to listen when the proxy has completed proxyRes.on('end', function () { server.emit('end', req, res, proxyRes); }); - proxyRes.pipe(res); + if(!options.selfHandleResponse) { + for(var i=0; i < web_o.length; i++) { + if(web_o[i](req, res, proxyRes, options)) { break; } + } + + proxyRes.pipe(res); + } }); //proxyReq.end(); From d533a1be437b37fed5bd25f5e58298eea819f974 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 19 Apr 2018 16:50:52 -0400 Subject: [PATCH 510/556] [dist] document the feature --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 258245d02..ac466d08e 100644 --- a/README.md +++ b/README.md @@ -345,7 +345,7 @@ proxyServer.listen(8015); * **cookiePathRewrite**: rewrites path of `set-cookie` headers. Possible values: * `false` (default): disable cookie rewriting * String: new path, for example `cookiePathRewrite: "/newPath/"`. To remove the path, use `cookiePathRewrite: ""`. To set path to root use `cookiePathRewrite: "/"`. - * Object: mapping of paths to new paths, use `"*"` to match all paths. + * Object: mapping of paths to new paths, use `"*"` to match all paths. For example keep one path unchanged, rewrite one path and remove other paths: ``` cookiePathRewrite: { @@ -357,6 +357,7 @@ proxyServer.listen(8015); * **headers**: object with extra headers to be added to target requests. * **proxyTimeout**: timeout (in millis) for outgoing proxy requests * **timeout**: timeout (in millis) for incoming requests +* **selfHandleRequest** true/false, if set to true, none of the webOutgoing passes are called and its your responsibility ro appropriately return the response by listening and acting on the `proxyRes` event **NOTE:** `options.ws` and `options.ssl` are optional. From 81d58c531be3f61efb56d2489a66c73a7b2325fe Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 19 Apr 2018 16:57:35 -0400 Subject: [PATCH 511/556] [test] for override method feature --- test/lib-http-proxy-common-test.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/lib-http-proxy-common-test.js b/test/lib-http-proxy-common-test.js index ef99ca109..58233f754 100644 --- a/test/lib-http-proxy-common-test.js +++ b/test/lib-http-proxy-common-test.js @@ -251,7 +251,7 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('/' + google); }); - + it('should not replace :\ to :\\ when no http word before', function () { var outgoing = {}; var google = 'http://google.com:/join/join.js' @@ -262,7 +262,7 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.path).to.eql('/' + google); }); - + describe('when using ignorePath', function () { it('should ignore the path of the `req.url` passed in but use the target path', function () { var outgoing = {}; @@ -347,6 +347,16 @@ describe('lib/http-proxy/common.js', function () { expect(outgoing.secureProtocol).eql('my-secure-protocol'); }); + it('should handle overriding the `method` of the http request', function () { + var outgoing = {}; + common.setupOutgoing(outgoing, { + target: url.parse('https://whooooo.com'), + method: 'POST' , + }, { method: 'GET', url: '' }); + + expect(outgoing.method).eql('POST'); + }); + // url.parse('').path => null it('should not pass null as last arg to #urlJoin', function(){ var outgoing = {}; From 8231984fb02dca331b4ef77e089db50855eea4f5 Mon Sep 17 00:00:00 2001 From: carpsareokiguess Date: Mon, 30 Oct 2017 22:31:05 +0100 Subject: [PATCH 512/556] fix small typos in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ac466d08e..9eb56bbd3 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ http.createServer(function (req, res) { **[Back to top](#table-of-contents)** #### Setup a stand-alone proxy server with custom server logic -This example show how you can proxy a request using your own HTTP server +This example shows how you can proxy a request using your own HTTP server and also you can put your own logic to handle the request. ```js @@ -229,7 +229,7 @@ http.createServer(function (req, res) { **[Back to top](#table-of-contents)** #### 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. +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 From d2f9db824136358a06dc3dd566644f3a016f24e2 Mon Sep 17 00:00:00 2001 From: Radu Serbanescu Date: Mon, 16 Oct 2017 18:32:45 +0300 Subject: [PATCH 513/556] Add use case for proxy to HTTPS using a PKCS12 client certificate --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 9eb56bbd3..64cbb4f30 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,24 @@ httpProxy.createServer({ }).listen(443); ``` +##### HTTP -> HTTPS (using a PKCS12 client certificate) + +```js +// +// Create an HTTP proxy server with an HTTPS target +// +httpProxy.createProxyServer({ + target: { + protocol: 'https:', + host: 'my-domain-name', + port: 443, + pfx: fs.readFileSync('path/to/certificate.p12'), + passphrase: 'password', + }, + changeOrigin: true, +}).listen(8000); +``` + **[Back to top](#table-of-contents)** #### Proxying WebSockets From 6f88caf6e46d84a809910c591e138250b333b39f Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Mon, 11 Sep 2017 13:31:13 +0100 Subject: [PATCH 514/556] Add detail about "buffer" option --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 64cbb4f30..5971e5ab3 100644 --- a/README.md +++ b/README.md @@ -376,7 +376,24 @@ proxyServer.listen(8015); * **proxyTimeout**: timeout (in millis) for outgoing proxy requests * **timeout**: timeout (in millis) for incoming requests * **selfHandleRequest** true/false, if set to true, none of the webOutgoing passes are called and its your responsibility ro appropriately return the response by listening and acting on the `proxyRes` event +* **buffer**: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option: + ``` + 'use strict'; + + const streamify = require('stream-array'); + const HttpProxy = require('http-proxy'); + const proxy = new HttpProxy(); + + module.exports = (req, res, next) => { + + proxy.web(req, res, { + target: 'http://localhost:4003/', + buffer: streamify(req.rawBody) + }, next); + + }; + ``` **NOTE:** `options.ws` and `options.ssl` are optional. `options.target` and `options.forward` cannot both be missing @@ -386,6 +403,7 @@ If you are using the `proxyServer.listen` method, the following options are also * **ssl**: object to be passed to https.createServer() * **ws**: true/false, if you want to proxy websockets + **[Back to top](#table-of-contents)** ### Listening for proxy events From c9a556cfa57c7ce0b877e16f2c2e1448d8cc278d Mon Sep 17 00:00:00 2001 From: n30n0v Date: Thu, 17 Aug 2017 18:22:44 +0300 Subject: [PATCH 515/556] Add followRedirects option --- README.md | 1 + lib/http-proxy/passes/web-incoming.js | 13 +++++-- package.json | 3 +- ...lib-http-proxy-passes-web-incoming-test.js | 37 +++++++++++++++++++ 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5971e5ab3..f290c4caf 100644 --- a/README.md +++ b/README.md @@ -375,6 +375,7 @@ proxyServer.listen(8015); * **headers**: object with extra headers to be added to target requests. * **proxyTimeout**: timeout (in millis) for outgoing proxy requests * **timeout**: timeout (in millis) for incoming requests +* **followRedirects**: true/false, Default: false - specify whether you want to follow redirects * **selfHandleRequest** true/false, if set to true, none of the webOutgoing passes are called and its your responsibility ro appropriately return the response by listening and acting on the `proxyRes` event * **buffer**: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option: diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 2e72f312a..419a5dfb6 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -1,12 +1,15 @@ -var http = require('http'), - https = require('https'), +var httpNative = require('http'), + httpsNative = require('https'), web_o = require('./web-outgoing'), - common = require('../common'); + common = require('../common'), + followRedirects = require('follow-redirects'); web_o = Object.keys(web_o).map(function(pass) { return web_o[pass]; }); +var nativeAgents = { http: httpNative, https: httpsNative }; + /*! * Array of passes. * @@ -99,6 +102,10 @@ module.exports = { // And we begin! server.emit('start', req, res, options.target || options.forward); + var agents = options.followRedirects ? followRedirects : nativeAgents; + var http = agents.http; + var https = agents.https; + if(options.forward) { // If forward enable, so just pipe the request var forwardReq = (options.forward.protocol === 'https:' ? https : http).request( diff --git a/package.json b/package.json index 8950610ff..2f01cf795 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "main": "index.js", "dependencies": { "eventemitter3": "^3.0.0", - "requires-port": "^1.0.0" + "requires-port": "^1.0.0", + "follow-redirects": "^1.0.0" }, "devDependencies": { "async": "^2.0.0", diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 7a34a58bc..cffe1af1e 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -1,6 +1,7 @@ var webPasses = require('../lib/http-proxy/passes/web-incoming'), httpProxy = require('../lib/http-proxy'), expect = require('expect.js'), + url = require('url'), http = require('http'); describe('lib/http-proxy/passes/web.js', function() { @@ -413,3 +414,39 @@ describe('#createProxyServer.web() using own http server', function () { http.request('http://127.0.0.1:8080/test2', function() {}).end(); }); }); + +describe('#followRedirects', function () { + it('should proxy the request follow redirects', function (done) { + var proxy = httpProxy.createProxyServer({ + target: 'http://127.0.0.1:8080', + followRedirects: true + }); + + function requestHandler(req, res) { + proxy.web(req, res); + } + + var proxyServer = http.createServer(requestHandler); + + var source = http.createServer(function(req, res) { + + if (url.parse(req.url).pathname === '/redirect') { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('ok'); + } + + res.writeHead(301, { 'Location': '/redirect' }); + res.end(); + }); + + proxyServer.listen('8081'); + source.listen('8080'); + + http.request('http://127.0.0.1:8081', function(res) { + source.close(); + proxyServer.close(); + expect(res.statusCode).to.eql(200); + done(); + }).end(); + }); +}); From bab02e909e4047bd65353a79bb60b2bfa0f82dc5 Mon Sep 17 00:00:00 2001 From: Gustav Tiger Date: Tue, 20 Jun 2017 13:38:28 +0200 Subject: [PATCH 516/556] Include websocket non-upgrade response When the server do not accept the upgrade request for websockets the server's response was previously not included and sent back. Now the proxy will include the response in these cases. Fixes #890. --- lib/http-proxy/passes/ws-incoming.js | 40 ++++++++++++++++------------ test/lib-http-proxy-test.js | 1 - 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index cf3796cde..270f23f45 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -77,6 +77,24 @@ module.exports = { * @api private */ stream : function stream(req, socket, options, head, server, clb) { + + var createHttpHeader = function(line, headers) { + return Object.keys(headers).reduce(function (head, key) { + var value = headers[key]; + + if (!Array.isArray(value)) { + head.push(key + ': ' + value); + return head; + } + + for (var i = 0; i < value.length; i++) { + head.push(key + ': ' + value[i]); + } + return head; + }, [line]) + .join('\r\n') + '\r\n\r\n'; + } + common.setupSocket(socket); if (head && head.length) socket.unshift(head); @@ -93,7 +111,10 @@ module.exports = { proxyReq.on('error', onOutgoingError); proxyReq.on('response', function (res) { // if upgrade event isn't going to happen, close the socket - if (!res.upgrade) socket.end(); + if (!res.upgrade) { + socket.write(createHttpHeader('HTTP/' + res.httpVersion + ' ' + res.statusCode + ' ' + res.statusMessage, res.headers)); + res.pipe(socket); + } }); proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { @@ -119,22 +140,7 @@ module.exports = { // Remark: Handle writing the headers to the socket when switching protocols // Also handles when a header is an array // - socket.write( - Object.keys(proxyRes.headers).reduce(function (head, key) { - var value = proxyRes.headers[key]; - - if (!Array.isArray(value)) { - head.push(key + ': ' + value); - return head; - } - - for (var i = 0; i < value.length; i++) { - head.push(key + ': ' + value[i]); - } - return head; - }, ['HTTP/1.1 101 Switching Protocols']) - .join('\r\n') + '\r\n\r\n' - ); + socket.write(createHttpHeader('HTTP/1.1 101 Switching Protocols', proxyRes.headers)); proxySocket.pipe(socket).pipe(proxySocket); diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index ec6273f94..b507a0052 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -415,7 +415,6 @@ describe('lib/http-proxy.js', function() { client.on('error', function (err) { expect(err).to.be.an(Error); - expect(err.code).to.be('ECONNRESET'); proxyServer.close(); done(); }); From abf882e03c92cf1665d5b7d4dbdaf87feb50a677 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 19 Apr 2018 18:06:55 -0400 Subject: [PATCH 517/556] [dist] update package-lock.json --- package-lock.json | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d02391c37..1824f1ad3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -163,7 +163,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -263,6 +262,14 @@ "integrity": "sha1-sKWaDS7/VDdUTr8M6qYBWEHQm1s=", "dev": true }, + "follow-redirects": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", + "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", + "requires": { + "debug": "3.1.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -507,8 +514,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "nan": { "version": "2.10.0", From 8097ae237e0daeb43a36d4b09c48709dd429c113 Mon Sep 17 00:00:00 2001 From: Thiago Bustamante Date: Fri, 26 May 2017 11:05:29 -0300 Subject: [PATCH 518/556] Fix "Can't set headers after they are sent" errors This PR tries to fix "Can't set headers after they are sent" errors. That are a lot of situations where this error can occurs. In my case, it is happening because I have others middlewares (in an expressjs application that tries to proxy requests). Some of those middlewares (like [passportjs](http://passportjs.org/), or [cors](https://www.npmjs.com/package/cors)) can run ```res.end()``` and when the proxy receive a response, it is already finished. So, it is necessary to test if we can write on the user response when the proxy response is ready. I think it could also fix #930, #1168, #908 --- lib/http-proxy/passes/web-incoming.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 419a5dfb6..e8521d671 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -170,21 +170,23 @@ module.exports = { proxyReq.on('response', function(proxyRes) { if(server) { server.emit('proxyRes', proxyRes, req, res); } - // Allow us to listen when the proxy has completed - proxyRes.on('end', function () { - server.emit('end', req, res, proxyRes); - }); - - if(!options.selfHandleResponse) { + if(!res.headersSent && !options.selfHandleResponse) { for(var i=0; i < web_o.length; i++) { if(web_o[i](req, res, proxyRes, options)) { break; } } - - proxyRes.pipe(res); } - }); - //proxyReq.end(); + if (!res.finished) { + // Allow us to listen when the proxy has completed + proxyRes.on('end', function () { + if (server) server.emit('end', req, res, proxyRes); + }); + // We do this separately since we are also checking for res.finished + if (!options.selfHandleResponse) proxyRes.pipe(res); + } else { + if (server) server.emit('end', req, res, proxyRes); + } + }); } }; From 2c44039a7c30b190043da654ee7e5aed0304e979 Mon Sep 17 00:00:00 2001 From: Jake Furler Date: Wed, 14 Jun 2017 14:46:54 +1000 Subject: [PATCH 519/556] issue #953: stop using writeHead object.keys in web-incoming.js results in a non-deterministic ordering of keys, which means that in web-outgoing writeHead might be called before setHeader, which throws an error --- lib/http-proxy/passes/web-outgoing.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/http-proxy/passes/web-outgoing.js b/lib/http-proxy/passes/web-outgoing.js index 05ded881c..46352f6e3 100644 --- a/lib/http-proxy/passes/web-outgoing.js +++ b/lib/http-proxy/passes/web-outgoing.js @@ -137,9 +137,10 @@ module.exports = { // <-- writeStatusCode: function writeStatusCode(req, res, proxyRes) { // From Node.js docs: response.writeHead(statusCode[, statusMessage][, headers]) if(proxyRes.statusMessage) { - res.writeHead(proxyRes.statusCode, proxyRes.statusMessage); + res.statusCode = proxyRes.statusCode; + res.statusMessage = proxyRes.statusMessage; } else { - res.writeHead(proxyRes.statusCode); + res.statusCode = proxyRes.statusCode; } } From e5c02b8a8a902e204eee886acafbbfe46c4a3aef Mon Sep 17 00:00:00 2001 From: guoxiangyang Date: Thu, 8 Jun 2017 00:45:00 +0800 Subject: [PATCH 520/556] add support for modify response --- README.md | 26 ++++++++++++++++++++++++++ lib/http-proxy/passes/web-incoming.js | 4 ++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f290c4caf..736caac73 100644 --- a/README.md +++ b/README.md @@ -377,6 +377,7 @@ proxyServer.listen(8015); * **timeout**: timeout (in millis) for incoming requests * **followRedirects**: true/false, Default: false - specify whether you want to follow redirects * **selfHandleRequest** true/false, if set to true, none of the webOutgoing passes are called and its your responsibility ro appropriately return the response by listening and acting on the `proxyRes` event +* **modifyResponse**: do not pipe proxyRes to res, so you can respond to client with your own response. It still goes through all out going web passes unlike selfHandleRequest * **buffer**: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option: ``` @@ -395,6 +396,7 @@ proxyServer.listen(8015); }; ``` + **NOTE:** `options.ws` and `options.ssl` are optional. `options.target` and `options.forward` cannot both be missing @@ -485,6 +487,30 @@ proxy.close(); ### Miscellaneous +### Modify response + +``` + + var option = { + target: target, + modifyResponse : true + }; + proxy.on('proxyRes', function (proxyRes, req, res) { + var body = new Buffer(''); + proxyRes.on('data', function (data) { + body = Buffer.concat([body, data]); + }); + proxyRes.on('end', function () { + body = body.toString(); + console.log("res from proxied server:", body); + res.end("my response to cli"); + }); + }); + proxy.web(req, res, option); + + +``` + #### ProxyTable API A proxy table API is available through this add-on [module](https://github.com/donasaur/http-proxy-rules), which lets you define a set of rules to translate matching routes to target routes that the reverse proxy will talk to. diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index e8521d671..eeff92ce8 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -181,8 +181,8 @@ module.exports = { proxyRes.on('end', function () { if (server) server.emit('end', req, res, proxyRes); }); - // We do this separately since we are also checking for res.finished - if (!options.selfHandleResponse) proxyRes.pipe(res); + // We pipe to the response unless its expected to be handled by the user + if (!options.selfHandleResponse && !options.modifyResponse) proxyRes.pipe(res); } else { if (server) server.emit('end', req, res, proxyRes); } From 4a37175a5296d2ea2da0fc15a3f8fe08599bb592 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Thu, 19 Apr 2018 20:13:13 -0400 Subject: [PATCH 521/556] [test] add test for selfHandleRequest and remove modifyResponse as selfHandleRequest is the only way that functionality works --- .travis.yml | 1 + README.md | 8 ++- lib/http-proxy/passes/web-incoming.js | 2 +- package-lock.json | 72 +++++++++++++++++++ package.json | 1 + ...lib-http-proxy-passes-web-incoming-test.js | 40 +++++++++++ 6 files changed, 120 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 956c0fcbe..564cffd83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ sudo: false language: node_js node_js: + - "4" - "6" - "8" script: diff --git a/README.md b/README.md index 736caac73..7bb26c9a1 100644 --- a/README.md +++ b/README.md @@ -377,7 +377,6 @@ proxyServer.listen(8015); * **timeout**: timeout (in millis) for incoming requests * **followRedirects**: true/false, Default: false - specify whether you want to follow redirects * **selfHandleRequest** true/false, if set to true, none of the webOutgoing passes are called and its your responsibility ro appropriately return the response by listening and acting on the `proxyRes` event -* **modifyResponse**: do not pipe proxyRes to res, so you can respond to client with your own response. It still goes through all out going web passes unlike selfHandleRequest * **buffer**: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option: ``` @@ -487,13 +486,16 @@ proxy.close(); ### Miscellaneous +If you want to handle your own response after receiving the proxyRes, you can do +so with `selfHandleResponse` + ### Modify response ``` var option = { - target: target, - modifyResponse : true + target: target, + selfHandleResponse : true }; proxy.on('proxyRes', function (proxyRes, req, res) { var body = new Buffer(''); diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index eeff92ce8..995a0db4d 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -182,7 +182,7 @@ module.exports = { if (server) server.emit('end', req, res, proxyRes); }); // We pipe to the response unless its expected to be handled by the user - if (!options.selfHandleResponse && !options.modifyResponse) proxyRes.pipe(res); + if (!options.selfHandleResponse) proxyRes.pipe(res); } else { if (server) server.emit('end', req, res, proxyRes); } diff --git a/package-lock.json b/package-lock.json index 1824f1ad3..104c174f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -103,6 +103,12 @@ "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", "dev": true }, + "buffer-from": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", + "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", + "dev": true + }, "bufferutil": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.2.1.tgz", @@ -153,12 +159,30 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "1.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, "cookie": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", "dev": true }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -359,6 +383,12 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, "json3": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", @@ -3254,6 +3284,27 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -3341,6 +3392,15 @@ "options": "0.0.6" } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, "supports-color": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", @@ -3356,6 +3416,12 @@ "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", "dev": true }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", @@ -3382,6 +3448,12 @@ } } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 2f01cf795..2ca6b6083 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "devDependencies": { "async": "^2.0.0", + "concat-stream": "^1.6.2", "expect.js": "~0.3.1", "mocha": "^3.5.3", "nyc": "^11.7.1", diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index cffe1af1e..37f74204b 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -1,6 +1,8 @@ var webPasses = require('../lib/http-proxy/passes/web-incoming'), httpProxy = require('../lib/http-proxy'), expect = require('expect.js'), + concat = require('concat-stream'), + async = require('async'), url = require('url'), http = require('http'); @@ -316,6 +318,44 @@ describe('#createProxyServer.web() using own http server', function () { http.request('http://127.0.0.1:8086', function() {}).end(); }); + it('should proxy the request and provide and respond to manual user response when using modifyResponse', function(done) { + var proxy = httpProxy.createProxyServer({ + target: 'http://127.0.0.1:8080', + selfHandleResponse: true + }); + + function requestHandler(req, res) { + proxy.once('proxyRes', function (proxyRes, pReq, pRes) { + proxyRes.pipe(concat(function (body) { + expect(body.toString('utf8')).eql('Response'); + pRes.end(Buffer.from('my-custom-response')); + })) + }); + + proxy.web(req, res); + } + + var proxyServer = http.createServer(requestHandler); + + var source = http.createServer(function(req, res) { + res.end('Response'); + }); + + async.parallel([ + next => proxyServer.listen(8086, next), + next => source.listen(8080, next) + ], function (err) { + http.get('http://127.0.0.1:8086', function(res) { + res.pipe(concat(function(body) { + expect(body.toString('utf8')).eql('my-custom-response'); + source.close(); + proxyServer.close(); + done(); + })); + }).once('error', done); + }) + }); + it('should proxy the request and handle changeOrigin option', function (done) { var proxy = httpProxy.createProxyServer({ target: 'http://127.0.0.1:8080', From e94d52973a26cf817a9de12d97e5ae603093f70d Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Fri, 20 Apr 2018 11:33:35 -0400 Subject: [PATCH 522/556] [dist] doc updates --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7bb26c9a1..ea73dca31 100644 --- a/README.md +++ b/README.md @@ -364,7 +364,7 @@ proxyServer.listen(8015); * `false` (default): disable cookie rewriting * String: new path, for example `cookiePathRewrite: "/newPath/"`. To remove the path, use `cookiePathRewrite: ""`. To set path to root use `cookiePathRewrite: "/"`. * Object: mapping of paths to new paths, use `"*"` to match all paths. - For example keep one path unchanged, rewrite one path and remove other paths: + For example, to keep one path unchanged, rewrite one path and remove other paths: ``` cookiePathRewrite: { "/unchanged.path/": "/unchanged.path/", @@ -376,7 +376,7 @@ proxyServer.listen(8015); * **proxyTimeout**: timeout (in millis) for outgoing proxy requests * **timeout**: timeout (in millis) for incoming requests * **followRedirects**: true/false, Default: false - specify whether you want to follow redirects -* **selfHandleRequest** true/false, if set to true, none of the webOutgoing passes are called and its your responsibility ro appropriately return the response by listening and acting on the `proxyRes` event +* **selfHandleResponse** true/false, if set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the `proxyRes` event * **buffer**: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option: ``` @@ -486,12 +486,15 @@ proxy.close(); ### Miscellaneous -If you want to handle your own response after receiving the proxyRes, you can do -so with `selfHandleResponse` +If you want to handle your own response after receiving the `proxyRes`, you can do +so with `selfHandleResponse`. As you can see below, if you use this option, you +are able to intercept and read the `proxyRes` but you must also make sure to +reply to the `res` itself otherwise the original client will never receive any +data. ### Modify response -``` +```js var option = { target: target, From 42e8e1e099c086d818d8f62c8f15ec5a8f1a6624 Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Fri, 20 Apr 2018 11:42:55 -0400 Subject: [PATCH 523/556] 1.17.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 104c174f3..6c0d0abc0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.16.2", + "version": "1.17.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2ca6b6083..3c2d64365 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.16.2", + "version": "1.17.0", "repository": { "type": "git", "url": "https://github.com/nodejitsu/node-http-proxy.git" From a3fe02d651d05d02d0ced377c22ae8345a2435a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=BB=E4=BE=A0?= Date: Thu, 7 Jun 2018 00:39:50 +0800 Subject: [PATCH 524/556] [examples] Restream body before proxying, support for Content-Type of application/x-www-form-urlencoded (#1264) --- examples/middleware/bodyDecoder-middleware.js | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/examples/middleware/bodyDecoder-middleware.js b/examples/middleware/bodyDecoder-middleware.js index 38559ef3b..71e16c8ac 100644 --- a/examples/middleware/bodyDecoder-middleware.js +++ b/examples/middleware/bodyDecoder-middleware.js @@ -29,6 +29,7 @@ var http = require('http'), request = require('request'), colors = require('colors'), util = require('util'), + queryString = require('querystring'), bodyParser = require('body-parser'), httpProxy = require('../../lib/http-proxy'), proxy = httpProxy.createProxyServer({}); @@ -36,12 +37,23 @@ var http = require('http'), //restream parsed body before proxying proxy.on('proxyReq', function(proxyReq, req, res, options) { - if(req.body) { - let bodyData = JSON.stringify(req.body); - // incase if content-type is application/x-www-form-urlencoded -> we need to change to application/json - proxyReq.setHeader('Content-Type','application/json'); + if (!req.body || !Object.keys(req.body).length) { + return; + } + + var contentType = proxyReq.getHeader('Content-Type'); + var bodyData; + + if (contentType === 'application/json') { + bodyData = JSON.stringify(req.body); + } + + if (contentType === 'application/x-www-form-urlencoded') { + bodyData = queryString.stringify(req.body); + } + + if (bodyData) { proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData)); - // stream the content proxyReq.write(bodyData); } }); @@ -94,5 +106,3 @@ http.createServer(app1).listen(9013, function(){ console.log('return for urlencoded request:' ,err, data) }) }); - - From cb3171abfa7944d5ddaf0911f5d21148c051bb06 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2019 01:38:48 -0500 Subject: [PATCH 525/556] Configure Renovate (#1355) * Add renovate.json * [dist] Configure renovate more. --- renovate.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 renovate.json diff --git a/renovate.json b/renovate.json new file mode 100644 index 000000000..fc1d2aa3a --- /dev/null +++ b/renovate.json @@ -0,0 +1,19 @@ +{ + "platform": "github", + "autodiscover": false, + "requireConfig": true, + "ignoreNpmrcFile": true, + "rangeStrategy": "replace", + "packageRules": [ + { + "packagePatterns": [ + "*" + ], + "minor": { + "groupName": "all non-major dependencies", + "groupSlug": "all-minor-patch" + } + } + ], + "commitMessagePrefix": "[dist]" +} From 569e2ac4fb6d04b0522649027b3f7971121b464d Mon Sep 17 00:00:00 2001 From: Marcin K Date: Thu, 22 Aug 2019 07:39:17 +0100 Subject: [PATCH 526/556] Update .nyc_output (#1339) Currently published version includes .nyc_output and coverage --- .npmignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.npmignore b/.npmignore index 081a48c64..d4cb9c574 100644 --- a/.npmignore +++ b/.npmignore @@ -2,6 +2,8 @@ test examples doc benchmark +coverage +.nyc_output .travis.yml CHANGELOG.md -UPGRADING.md \ No newline at end of file +UPGRADING.md From acdbec09c69c2f42f73a8ffff62e8afc5af4f080 Mon Sep 17 00:00:00 2001 From: Stein Martin Hustad Date: Thu, 22 Aug 2019 08:40:03 +0200 Subject: [PATCH 527/556] Fix docs for rewrite options - 201 also handled (#1147) Updates options documentation for location rewrite to include 201 responses. See #1024 --- lib/http-proxy.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/http-proxy.js b/lib/http-proxy.js index 7dab7a48d..8ea278938 100644 --- a/lib/http-proxy.js +++ b/lib/http-proxy.js @@ -37,9 +37,9 @@ function createProxyServer(options) { * changeOrigin: * preserveHeaderKeyCase: * auth : Basic authentication i.e. 'user:password' to compute an Authorization header. - * hostRewrite: rewrites the location hostname on (301/302/307/308) redirects, Default: null. - * autoRewrite: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false. - * protocolRewrite: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null. + * hostRewrite: rewrites the location hostname on (201/301/302/307/308) redirects, Default: null. + * autoRewrite: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false. + * protocolRewrite: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null. * } * * NOTE: `options.ws` and `options.ssl` are optional. From 235f0aa047ccc1cf3da0f6dfcc51995297703f95 Mon Sep 17 00:00:00 2001 From: Justin Russell Date: Thu, 22 Aug 2019 02:41:47 -0400 Subject: [PATCH 528/556] Highlight correct lines for createProxyServer (#1117) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ea73dca31..d69773a55 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ 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#L22-L50)) +an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L26-L42)) ```javascript var httpProxy = require('http-proxy'); From 91fee3e943dc4497e8dd4ef27116388dce091988 Mon Sep 17 00:00:00 2001 From: Charlie Robbins Date: Thu, 22 Aug 2019 01:46:16 -0500 Subject: [PATCH 529/556] [refactor doc] Complete rename to http-party org. (#1362) --- CODE_OF_CONDUCT.md | 2 +- README.md | 6 +++--- UPGRADING.md | 8 ++++---- package.json | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 78e80cc61..29238b798 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at . All +reported by contacting the project team at . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. diff --git a/README.md b/README.md index d69773a55..1ab0f9e44 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@

- +

-# node-http-proxy [![Build Status](https://travis-ci.org/nodejitsu/node-http-proxy.svg?branch=master)](https://travis-ci.org/nodejitsu/node-http-proxy) [![codecov](https://codecov.io/gh/nodejitsu/node-http-proxy/branch/master/graph/badge.svg)](https://codecov.io/gh/nodejitsu/node-http-proxy) +# node-http-proxy [![Build Status](https://travis-ci.org/http-party/node-http-proxy.svg?branch=master)](https://travis-ci.org/http-party/node-http-proxy) [![codecov](https://codecov.io/gh/http-party/node-http-proxy/branch/master/graph/badge.svg)](https://codecov.io/gh/http-party/node-http-proxy) `node-http-proxy` is an HTTP programmable proxying library that supports websockets. It is suitable for implementing components such as reverse @@ -534,7 +534,7 @@ Logo created by [Diego Pasquali](http://dribbble.com/diegopq) ### Contributing and Issues -* Read carefully our [Code Of Conduct](https://github.com/nodejitsu/node-http-proxy/blob/master/CODE_OF_CONDUCT.md) +* Read carefully our [Code Of Conduct](https://github.com/http-party/node-http-proxy/blob/master/CODE_OF_CONDUCT.md) * Search on Google/Github * If you can't find anything, open an issue * If you feel comfortable about fixing the issue, fork the repo diff --git a/UPGRADING.md b/UPGRADING.md index f77243dc9..6552039dd 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -12,11 +12,11 @@ httpProxy.createServer({ }).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. +Check the [README.md](https://github.com/http-party/node-http-proxy/blob/caronte/README.md) for a more detailed explanation of the parameters. ## Proxying -Web proxying is done by calling the `.web()` method on a Proxy instance. You can check among some use cases in the [examples folder](https://github.com/nodejitsu/node-http-proxy/tree/caronte/examples/http) +Web proxying is done by calling the `.web()` method on a Proxy instance. You can check among some use cases in the [examples folder](https://github.com/http-party/node-http-proxy/tree/caronte/examples/http) ```javascript // @@ -32,7 +32,7 @@ httpProxy.createProxyServer({ ``` -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! +Websockets are proxied by the `.ws()` method. The [examples folder](https://github.com/http-party/node-http-proxy/tree/caronte/examples/websocket) again provides a lot of useful snippets! ```javascript var proxy = new httpProxy.createProxyServer({ @@ -90,7 +90,7 @@ which were in the core and delegate them to eventual "userland" modules. ### 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) +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/http-party/node-http-proxy/tree/caronte/examples/middleware) ### ProxyTable API diff --git a/package.json b/package.json index 3c2d64365..7dac58ca3 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.17.0", "repository": { "type": "git", - "url": "https://github.com/nodejitsu/node-http-proxy.git" + "url": "https://github.com/http-party/node-http-proxy.git" }, "description": "HTTP proxying for the masses", "author": "Charlie Robbins ", From 36bfe566a7db13035c947e40cfb15c88fd10b527 Mon Sep 17 00:00:00 2001 From: Jaggernoth Date: Thu, 22 Aug 2019 09:09:26 +0200 Subject: [PATCH 530/556] x-forwarded-host overwrite for mutli level proxies (#1267) With more than 1 proxy the original host was lost, now it will be passed down the proxy chain --- lib/http-proxy/passes/web-incoming.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 995a0db4d..781b32692 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -82,7 +82,7 @@ module.exports = { values[header]; }); - req.headers['x-forwarded-host'] = req.headers['host'] || ''; + req.headers['x-forwarded-host'] = req.headers['x-forwarded-host'] || req.headers['host'] || ''; }, /** From b00911c93740a00c5cfbacbb91565cb6912ed255 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Thu, 22 Aug 2019 06:40:05 +0000 Subject: [PATCH 531/556] [dist] Update dependency ws to v3 [SECURITY] --- package-lock.json | 70 ++++++----------------------------------------- package.json | 2 +- 2 files changed, 10 insertions(+), 62 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6c0d0abc0..4bb9925fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,13 +74,6 @@ "callsite": "1.0.0" } }, - "bindings": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", - "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=", - "dev": true, - "optional": true - }, "blob": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", @@ -109,17 +102,6 @@ "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", "dev": true }, - "bufferutil": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.2.1.tgz", - "integrity": "sha1-N75dNuHgZJIiHmjUdLGsWOUQy9c=", - "dev": true, - "optional": true, - "requires": { - "bindings": "1.2.1", - "nan": "2.10.0" - } - }, "callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", @@ -546,13 +528,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", - "dev": true, - "optional": true - }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", @@ -598,6 +573,7 @@ "version": "0.1.4", "bundled": true, "dev": true, + "optional": true, "requires": { "kind-of": "3.2.2", "longest": "1.0.1", @@ -1754,7 +1730,8 @@ "longest": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "loose-envify": { "version": "1.3.1", @@ -3428,26 +3405,6 @@ "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", "dev": true }, - "utf-8-validate": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.2.2.tgz", - "integrity": "sha1-i7hxpHQeCFxwSHynrNvX1tNgKes=", - "dev": true, - "optional": true, - "requires": { - "bindings": "1.2.1", - "nan": "2.4.0" - }, - "dependencies": { - "nan": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz", - "integrity": "sha1-+zxZ1F/k7/4hXwuJD4rfbrMtIjI=", - "dev": true, - "optional": true - } - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3461,23 +3418,14 @@ "dev": true }, "ws": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-0.8.1.tgz", - "integrity": "sha1-a2UnO5kZPF8Gekz1gJWY93fjt1k=", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "dev": true, "requires": { - "bufferutil": "1.2.1", - "options": "0.0.6", - "ultron": "1.0.2", - "utf-8-validate": "1.2.2" - }, - "dependencies": { - "ultron": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", - "dev": true - } + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" } }, "xmlhttprequest-ssl": { diff --git a/package.json b/package.json index 7dac58ca3..8afb823e1 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "socket.io": "^2.1.0", "socket.io-client": "^2.1.0", "sse": "0.0.6", - "ws": "^0.8.0" + "ws": "^3.0.0" }, "scripts": { "mocha": "mocha test/*-test.js", From a9b09cce43f072db99fb5170030a05536177ccb7 Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 22 Aug 2019 01:59:01 -0500 Subject: [PATCH 532/556] [dist] End of an era. --- test/fixtures/agent2-cert.pem | 13 ------------- test/fixtures/agent2-csr.pem | 10 ---------- test/fixtures/agent2-key.pem | 9 --------- test/fixtures/agent2.cnf | 19 ------------------- 4 files changed, 51 deletions(-) delete mode 100644 test/fixtures/agent2-cert.pem delete mode 100644 test/fixtures/agent2-csr.pem delete mode 100644 test/fixtures/agent2-key.pem delete mode 100644 test/fixtures/agent2.cnf diff --git a/test/fixtures/agent2-cert.pem b/test/fixtures/agent2-cert.pem deleted file mode 100644 index 8e4354db4..000000000 --- a/test/fixtures/agent2-cert.pem +++ /dev/null @@ -1,13 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIB7DCCAZYCCQC7gs0MDNn6MTANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJV -UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO -BgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEgMB4GCSqGSIb3DQEJARYR -cnlAdGlueWNsb3Vkcy5vcmcwHhcNMTEwMzE0MTgyOTEyWhcNMzgwNzI5MTgyOTEy -WjB9MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYD -VQQKEwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDzANBgNVBAMTBmFnZW50MjEg -MB4GCSqGSIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwXDANBgkqhkiG9w0BAQEF -AANLADBIAkEAyXb8FrRdKbhrKLgLSsn61i1C7w7fVVVd7OQsmV/7p9WB2lWFiDlC -WKGU9SiIz/A6wNZDUAuc2E+VwtpCT561AQIDAQABMA0GCSqGSIb3DQEBBQUAA0EA -C8HzpuNhFLCI3A5KkBS5zHAQax6TFUOhbpBCR0aTDbJ6F1liDTK1lmU/BjvPoj+9 -1LHwrmh29rK8kBPEjmymCQ== ------END CERTIFICATE----- diff --git a/test/fixtures/agent2-csr.pem b/test/fixtures/agent2-csr.pem deleted file mode 100644 index a670c4c63..000000000 --- a/test/fixtures/agent2-csr.pem +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBXTCCAQcCAQAwfTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQH -EwJTRjEPMA0GA1UEChMGSm95ZW50MRAwDgYDVQQLEwdOb2RlLmpzMQ8wDQYDVQQD -EwZhZ2VudDIxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMFwwDQYJ -KoZIhvcNAQEBBQADSwAwSAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf -+6fVgdpVhYg5QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAaAlMCMGCSqG -SIb3DQEJBzEWExRBIGNoYWxsZW5nZSBwYXNzd29yZDANBgkqhkiG9w0BAQUFAANB -AJnll2pt5l0pzskQSpjjLVTlFDFmJr/AZ3UK8v0WxBjYjCe5Jx4YehkChpxIyDUm -U3J9q9MDUf0+Y2+EGkssFfk= ------END CERTIFICATE REQUEST----- diff --git a/test/fixtures/agent2-key.pem b/test/fixtures/agent2-key.pem deleted file mode 100644 index 522903c63..000000000 --- a/test/fixtures/agent2-key.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIBOgIBAAJBAMl2/Ba0XSm4ayi4C0rJ+tYtQu8O31VVXezkLJlf+6fVgdpVhYg5 -QlihlPUoiM/wOsDWQ1ALnNhPlcLaQk+etQECAwEAAQJBAMT6Bf34+UHKY1ObpsbH -9u2jsVblFq1rWvs8GPMY6oertzvwm3DpuSUp7PTgOB1nLTLYtCERbQ4ovtN8tn3p -OHUCIQDzIEGsoCr5vlxXvy2zJwu+fxYuhTZWMVuo1397L0VyhwIhANQh+yzqUgaf -WRtSB4T2W7ADtJI35ET61jKBty3CqJY3AiAIwju7dVW3A5WeD6Qc1SZGKZvp9yCb -AFI2BfVwwaY11wIgXF3PeGcvACMyMWsuSv7aPXHfliswAbkWuzcwA4TW01ECIGWa -cgsDvVFxmfM5NPSuT/UDTa6R5BFISB5ea0N0AR3I ------END RSA PRIVATE KEY----- diff --git a/test/fixtures/agent2.cnf b/test/fixtures/agent2.cnf deleted file mode 100644 index 0a9f2c737..000000000 --- a/test/fixtures/agent2.cnf +++ /dev/null @@ -1,19 +0,0 @@ -[ 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 - From 7e4a0e511bc30c059216860153301de2cdd1e97f Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 22 Aug 2019 01:59:10 -0500 Subject: [PATCH 533/556] [dist] New test fixtures. --- test/fixtures/agent2-cert.pem | 25 +++++++++++++++++++++++++ test/fixtures/agent2-key.pem | 27 +++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 test/fixtures/agent2-cert.pem create mode 100644 test/fixtures/agent2-key.pem diff --git a/test/fixtures/agent2-cert.pem b/test/fixtures/agent2-cert.pem new file mode 100644 index 000000000..852d09f93 --- /dev/null +++ b/test/fixtures/agent2-cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEIDCCAggCCQChRDh/XiBF+zANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJ1 +czETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEeMBwGA1UE +AwwVRHVtbXkgSW50ZXJtZWRpYXRlIENBMB4XDTE4MDYyMjIwMzEwNFoXDTMyMDIy +OTIwMzEwNFowUDELMAkGA1UEBhMCdXMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAO +BgNVBAcMB1NlYXR0bGUxGjAYBgNVBAMMEWR1bW15LmV4YW1wbGUuY29tMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvSQq3d8AeZMTvtqZ13jWCckikyXJ +SACvkGCQUCJqOceESbg6IHdRzQdoccE4P3sbvNsf9BlbdJKM+neCxabqKaU1PPje +4P0tHT57t6yJrMuUh9NxEz3Bgh1srNHVS7saKvwHmcKm79jc+wxlioPmEQvQagjn +y7oTkyLt0sn4LGxBjrcv2JoHOC9f1pxX7l47MaiN0/ctRau7Nr3PFn+pkB4Yf6Z0 +VyicVJbaUSz39Qo4HQWl1L2hiBP3CS1oKs2Yk0O1aOCMExWrhZQan+ZgHqL1rhgm +kPpw2/zwwPt5Vf9CSakvHwg198EXuTTXtkzYduuIJAm8yp969iEIiG2xTwIDAQAB +MA0GCSqGSIb3DQEBCwUAA4ICAQBnMSIo+kujkeXPh+iErFBmNtu/7EA+i/QnFPbN +lSLngclYYBJAGQI+DhirJI8ghDi6vmlHB2THewDaOJXEKvC1czE8064wioIcA9HJ +l3QJ3YYOFRctYdSHBU4TWdJbPgkLWDzYP5smjOfw8nDdr4WO/5jh9qRFcFpTFmQf +DyU3xgWLsQnNK3qXLdJjWG75pEhHR+7TGo+Ob/RUho/1RX/P89Ux7/oVbzdKqqFu +SErXAsjEIEFzWOM2uDOt6hrxDF6q+8/zudwQNEo422poEcTT9tDEFxMQ391CzZRi +nozBm4igRn1f5S3YZzLI6VEUns0s76BNy2CzvFWn40DziTqNBExAMfFFj76wiMsX +6fTIdcvkaTBa0S9SZB0vN99qahBdcG17rt4RssMHVRH1Wn7NXMwe476L0yXZ6gO7 +Z4uNAPxgaI3BRP75EPfslLutCLZ+BC4Zzu6MY0Salbpfl0Go462EhsKCxvYhE2Dg +T477pICLfETZfA499Fd1tOaIsoLCrILAia/+Yd76uf94MuXUIqykDng/4H7xCc47 +BZhNFJiPC6XHaXzN7NYSEUNX9VOwY8ncxKwtP6TXga96PdMUy/p98KIM8RZlDoxB +Xy9dcZBFNn/zrqjW7R0CCWCUriDIFSmEP0wDZ91YYa6BVuJMb5uL/USkTLpjZS4/ +HNGvug== +-----END CERTIFICATE----- diff --git a/test/fixtures/agent2-key.pem b/test/fixtures/agent2-key.pem new file mode 100644 index 000000000..4de9ee77e --- /dev/null +++ b/test/fixtures/agent2-key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAvSQq3d8AeZMTvtqZ13jWCckikyXJSACvkGCQUCJqOceESbg6 +IHdRzQdoccE4P3sbvNsf9BlbdJKM+neCxabqKaU1PPje4P0tHT57t6yJrMuUh9Nx +Ez3Bgh1srNHVS7saKvwHmcKm79jc+wxlioPmEQvQagjny7oTkyLt0sn4LGxBjrcv +2JoHOC9f1pxX7l47MaiN0/ctRau7Nr3PFn+pkB4Yf6Z0VyicVJbaUSz39Qo4HQWl +1L2hiBP3CS1oKs2Yk0O1aOCMExWrhZQan+ZgHqL1rhgmkPpw2/zwwPt5Vf9CSakv +Hwg198EXuTTXtkzYduuIJAm8yp969iEIiG2xTwIDAQABAoIBAGPIw/C/qJF7HYyv +6T+7GTiaa2o0IiehbP3/Y8NTFLWc49a8obXlHTvMr7Zr2I/tE+ojtIzkH9K1SjkN +eelqsNj9tsOPDI6oIvftsflpxkxqLtclnt8m0oMhoObf4OaONDT/N8dP4SBiSdsM +ZDmacnMFx5NZVWiup4sVf2CYexx7qks9FhyN2K5PArCQ4S9LHjFhSJVH4DSEpv7E +Ykbp30rhpqV7wSwjgUsm8ZYvI2NOlmffzLSiPdt3vy2K5Q25S/MVEAicg83rfDgK +6EluHjeygRI1xU6DJ0hU7tnU7zE9KURoHPUycO3BKzZnzUH26AA36I58Pu4fXWw/ +Cgmbv2ECgYEA+og9E4ziKCEi3p8gqjIfwTRgWZxDLjEzooB/K0UhEearn/xiX29A +FiSzEHKfCB4uSrw5OENg2ckDs8uy08Qmxx7xFXL7AtufAl5fIYaWa0sNSqCaIk7p +ebbUmPcaYhKiLzIEd1EYEL38sXVZ62wvSVMRSWvEMq44g1qnoRlDa/8CgYEAwUTt +talYNwVmR9ZdkVEWm9ZxirdzoM6NaM6u4Tf34ygptpapdmIFSUhfq4iOiEnRGNg/ +tuNqhNCIb3LNpJbhRPEzqN7E7qiF/mp7AcJgbuxLZBm12QuLuJdG3nrisKPFXcY1 +lA4A7CFmNgH3E4THFfgwzyDXsBOxVLXleTqn+rECgYEA9up1P6J3dtOJuV2d5P/3 +ugRz/X173LfTSxJXw36jZDAy8D/feG19/RT4gnplcKvGNhQiVOhbOOnbw0U8n2fQ +TCmbs+cZqyxnH/+AxNsPvvk+RVHZ93xMsY/XIldP4l65B8jFDA+Zp06IESI2mEeM +pzi+bd1Phh+dRSCA2865W2MCgYEAlxYsgmQ1WyX0dFpHYU+zzfXRYzDQyrhOYc2Z +duVK+yCto1iad7pfCY/zgmRJkI+sT7DV9kJIRjXDQuTLkEyHJF8vFGe6KhxCS8aw +DIsI2g4NTd6vg1J8UryoIUqNpqsQoqNNxUVBQVdG0ReuMGsPO8R/W50AIFz0txVP +o/rP0LECgYEA7e/mOwCnR+ovmS/CAksmos3oIqvkRkXNKpKe513FVmp3TpTU38ex +cBkFNU3hEO31FyrX1hGIKp3N5mHYSQ1lyODHM6teHW0OLWWTwIe8rIGvR2jfRLe0 +bbkdj40atYVkfeFmpz9uHHG24CUYxJdPc360jbXTVp4i3q8zqgL5aMY= +-----END RSA PRIVATE KEY----- From fc93520d741ec80be8ae31ca005f3e9c199e330e Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 22 Aug 2019 01:59:32 -0500 Subject: [PATCH 534/556] [dist] .gitattributes all the things. --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..1a6bd4587 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +package-lock.json binary From 16d4f8a95162b2e2e4ee6657c500f1208c044b2d Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 22 Aug 2019 01:59:46 -0500 Subject: [PATCH 535/556] [dist] Regenerate package-lock.json. --- package-lock.json | 1094 ++++++++++++++++++++++----------------------- 1 file changed, 547 insertions(+), 547 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4bb9925fb..e603ff0f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "dev": true, "requires": { - "mime-types": "2.1.18", + "mime-types": "~2.1.18", "negotiator": "0.6.1" } }, @@ -32,7 +32,7 @@ "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", "dev": true, "requires": { - "lodash": "4.17.5" + "lodash": "^4.14.0" } }, "async-limiter": { @@ -86,7 +86,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -114,7 +114,7 @@ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true, "requires": { - "graceful-readlink": "1.0.1" + "graceful-readlink": ">= 1.0.0" } }, "component-bind": { @@ -147,10 +147,10 @@ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { - "buffer-from": "1.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, "cookie": { @@ -185,12 +185,12 @@ "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", "dev": true, "requires": { - "accepts": "1.3.5", + "accepts": "~1.3.4", "base64id": "1.0.0", "cookie": "0.3.1", - "debug": "3.1.0", - "engine.io-parser": "2.1.2", - "ws": "3.3.3" + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" }, "dependencies": { "ws": { @@ -199,9 +199,9 @@ "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "dev": true, "requires": { - "async-limiter": "1.0.0", - "safe-buffer": "5.1.1", - "ultron": "1.1.1" + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" } } } @@ -214,14 +214,14 @@ "requires": { "component-emitter": "1.2.1", "component-inherit": "0.0.3", - "debug": "3.1.0", - "engine.io-parser": "2.1.2", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", "has-cors": "1.1.0", "indexof": "0.0.1", "parseqs": "0.0.5", "parseuri": "0.0.5", - "ws": "3.3.3", - "xmlhttprequest-ssl": "1.5.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", "yeast": "0.1.2" }, "dependencies": { @@ -231,9 +231,9 @@ "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "dev": true, "requires": { - "async-limiter": "1.0.0", - "safe-buffer": "5.1.1", - "ultron": "1.1.1" + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" } } } @@ -245,10 +245,10 @@ "dev": true, "requires": { "after": "0.8.2", - "arraybuffer.slice": "0.0.7", + "arraybuffer.slice": "~0.0.7", "base64-arraybuffer": "0.1.5", "blob": "0.0.4", - "has-binary2": "1.0.2" + "has-binary2": "~1.0.2" } }, "escape-string-regexp": { @@ -273,7 +273,7 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", "requires": { - "debug": "3.1.0" + "debug": "^3.1.0" } }, "fs.realpath": { @@ -288,12 +288,12 @@ "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "graceful-readlink": { @@ -355,8 +355,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -389,8 +389,8 @@ "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", "dev": true, "requires": { - "lodash._basecopy": "3.0.1", - "lodash.keys": "3.1.2" + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" } }, "lodash._basecopy": { @@ -423,9 +423,9 @@ "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", "dev": true, "requires": { - "lodash._baseassign": "3.2.0", - "lodash._basecreate": "3.0.3", - "lodash._isiterateecall": "3.0.9" + "lodash._baseassign": "^3.0.0", + "lodash._basecreate": "^3.0.0", + "lodash._isiterateecall": "^3.0.0" } }, "lodash.isarguments": { @@ -446,9 +446,9 @@ "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { - "lodash._getnative": "3.9.1", - "lodash.isarguments": "3.1.0", - "lodash.isarray": "3.0.4" + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" } }, "mime-db": { @@ -463,7 +463,7 @@ "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "dev": true, "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.33.0" } }, "minimatch": { @@ -472,7 +472,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "mkdirp": { @@ -540,33 +540,33 @@ "integrity": "sha512-EGePURSKUEpS1jWnEKAMhY+GWZzi7JC+f8iBDOATaOsLZW5hM/9eYx2dHGaEXa1ITvMm44CJugMksvP3NwMQMw==", "dev": true, "requires": { - "archy": "1.0.0", - "arrify": "1.0.1", - "caching-transform": "1.0.1", - "convert-source-map": "1.5.1", - "debug-log": "1.0.1", - "default-require-extensions": "1.0.0", - "find-cache-dir": "0.1.1", - "find-up": "2.1.0", - "foreground-child": "1.5.6", - "glob": "7.1.2", - "istanbul-lib-coverage": "1.2.0", - "istanbul-lib-hook": "1.1.0", - "istanbul-lib-instrument": "1.10.1", - "istanbul-lib-report": "1.1.3", - "istanbul-lib-source-maps": "1.2.3", - "istanbul-reports": "1.4.0", - "md5-hex": "1.3.0", - "merge-source-map": "1.1.0", - "micromatch": "2.3.11", - "mkdirp": "0.5.1", - "resolve-from": "2.0.0", - "rimraf": "2.6.2", - "signal-exit": "3.0.2", - "spawn-wrap": "1.4.2", - "test-exclude": "4.2.1", + "archy": "^1.0.0", + "arrify": "^1.0.1", + "caching-transform": "^1.0.0", + "convert-source-map": "^1.5.1", + "debug-log": "^1.0.1", + "default-require-extensions": "^1.0.0", + "find-cache-dir": "^0.1.1", + "find-up": "^2.1.0", + "foreground-child": "^1.5.3", + "glob": "^7.0.6", + "istanbul-lib-coverage": "^1.1.2", + "istanbul-lib-hook": "^1.1.0", + "istanbul-lib-instrument": "^1.10.0", + "istanbul-lib-report": "^1.1.3", + "istanbul-lib-source-maps": "^1.2.3", + "istanbul-reports": "^1.4.0", + "md5-hex": "^1.2.0", + "merge-source-map": "^1.0.2", + "micromatch": "^2.3.11", + "mkdirp": "^0.5.0", + "resolve-from": "^2.0.0", + "rimraf": "^2.5.4", + "signal-exit": "^3.0.1", + "spawn-wrap": "^1.4.2", + "test-exclude": "^4.2.0", "yargs": "11.1.0", - "yargs-parser": "8.1.0" + "yargs-parser": "^8.0.0" }, "dependencies": { "align-text": { @@ -575,9 +575,9 @@ "dev": true, "optional": true, "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" } }, "amdefine": { @@ -600,7 +600,7 @@ "bundled": true, "dev": true, "requires": { - "default-require-extensions": "1.0.0" + "default-require-extensions": "^1.0.0" } }, "archy": { @@ -613,7 +613,7 @@ "bundled": true, "dev": true, "requires": { - "arr-flatten": "1.1.0" + "arr-flatten": "^1.0.1" } }, "arr-flatten": { @@ -656,9 +656,9 @@ "bundled": true, "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, "babel-generator": { @@ -666,14 +666,14 @@ "bundled": true, "dev": true, "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.5", - "source-map": "0.5.7", - "trim-right": "1.0.1" + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" } }, "babel-messages": { @@ -681,7 +681,7 @@ "bundled": true, "dev": true, "requires": { - "babel-runtime": "6.26.0" + "babel-runtime": "^6.22.0" } }, "babel-runtime": { @@ -689,8 +689,8 @@ "bundled": true, "dev": true, "requires": { - "core-js": "2.5.5", - "regenerator-runtime": "0.11.1" + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, "babel-template": { @@ -698,11 +698,11 @@ "bundled": true, "dev": true, "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.5" + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" } }, "babel-traverse": { @@ -710,15 +710,15 @@ "bundled": true, "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.9", - "globals": "9.18.0", - "invariant": "2.2.4", - "lodash": "4.17.5" + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" } }, "babel-types": { @@ -726,10 +726,10 @@ "bundled": true, "dev": true, "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.5", - "to-fast-properties": "1.0.3" + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" } }, "babylon": { @@ -747,13 +747,13 @@ "bundled": true, "dev": true, "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.2.1", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.1", - "pascalcase": "0.1.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { @@ -761,7 +761,7 @@ "bundled": true, "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -769,7 +769,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -777,7 +777,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -785,9 +785,9 @@ "bundled": true, "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "isobject": { @@ -807,7 +807,7 @@ "bundled": true, "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -816,9 +816,9 @@ "bundled": true, "dev": true, "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.2" + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "builtin-modules": { @@ -831,15 +831,15 @@ "bundled": true, "dev": true, "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.2.1", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.0", - "to-object-path": "0.3.0", - "union-value": "1.0.0", - "unset-value": "1.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" }, "dependencies": { "isobject": { @@ -854,9 +854,9 @@ "bundled": true, "dev": true, "requires": { - "md5-hex": "1.3.0", - "mkdirp": "0.5.1", - "write-file-atomic": "1.3.4" + "md5-hex": "^1.2.0", + "mkdirp": "^0.5.1", + "write-file-atomic": "^1.1.4" } }, "camelcase": { @@ -871,8 +871,8 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, "chalk": { @@ -880,11 +880,11 @@ "bundled": true, "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "class-utils": { @@ -892,10 +892,10 @@ "bundled": true, "dev": true, "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -903,7 +903,7 @@ "bundled": true, "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "isobject": { @@ -919,8 +919,8 @@ "dev": true, "optional": true, "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", + "center-align": "^0.1.1", + "right-align": "^0.1.1", "wordwrap": "0.0.2" }, "dependencies": { @@ -942,8 +942,8 @@ "bundled": true, "dev": true, "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "commondir": { @@ -981,8 +981,8 @@ "bundled": true, "dev": true, "requires": { - "lru-cache": "4.1.2", - "which": "1.3.0" + "lru-cache": "^4.0.1", + "which": "^1.2.9" } }, "debug": { @@ -1013,7 +1013,7 @@ "bundled": true, "dev": true, "requires": { - "strip-bom": "2.0.0" + "strip-bom": "^2.0.0" } }, "define-property": { @@ -1021,8 +1021,8 @@ "bundled": true, "dev": true, "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -1030,7 +1030,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -1038,7 +1038,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -1046,9 +1046,9 @@ "bundled": true, "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "isobject": { @@ -1068,7 +1068,7 @@ "bundled": true, "dev": true, "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "error-ex": { @@ -1076,7 +1076,7 @@ "bundled": true, "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "escape-string-regexp": { @@ -1094,13 +1094,13 @@ "bundled": true, "dev": true, "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" }, "dependencies": { "cross-spawn": { @@ -1108,9 +1108,9 @@ "bundled": true, "dev": true, "requires": { - "lru-cache": "4.1.2", - "shebang-command": "1.2.0", - "which": "1.3.0" + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } } } @@ -1120,7 +1120,7 @@ "bundled": true, "dev": true, "requires": { - "is-posix-bracket": "0.1.1" + "is-posix-bracket": "^0.1.0" } }, "expand-range": { @@ -1128,7 +1128,7 @@ "bundled": true, "dev": true, "requires": { - "fill-range": "2.2.3" + "fill-range": "^2.1.0" } }, "extend-shallow": { @@ -1136,8 +1136,8 @@ "bundled": true, "dev": true, "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -1145,7 +1145,7 @@ "bundled": true, "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -1155,7 +1155,7 @@ "bundled": true, "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "filename-regex": { @@ -1168,11 +1168,11 @@ "bundled": true, "dev": true, "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^1.1.3", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" } }, "find-cache-dir": { @@ -1180,9 +1180,9 @@ "bundled": true, "dev": true, "requires": { - "commondir": "1.0.1", - "mkdirp": "0.5.1", - "pkg-dir": "1.0.0" + "commondir": "^1.0.1", + "mkdirp": "^0.5.1", + "pkg-dir": "^1.0.0" } }, "find-up": { @@ -1190,7 +1190,7 @@ "bundled": true, "dev": true, "requires": { - "locate-path": "2.0.0" + "locate-path": "^2.0.0" } }, "for-in": { @@ -1203,7 +1203,7 @@ "bundled": true, "dev": true, "requires": { - "for-in": "1.0.2" + "for-in": "^1.0.1" } }, "foreground-child": { @@ -1211,8 +1211,8 @@ "bundled": true, "dev": true, "requires": { - "cross-spawn": "4.0.2", - "signal-exit": "3.0.2" + "cross-spawn": "^4", + "signal-exit": "^3.0.0" } }, "fragment-cache": { @@ -1220,7 +1220,7 @@ "bundled": true, "dev": true, "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fs.realpath": { @@ -1248,12 +1248,12 @@ "bundled": true, "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "glob-base": { @@ -1261,8 +1261,8 @@ "bundled": true, "dev": true, "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" } }, "glob-parent": { @@ -1270,7 +1270,7 @@ "bundled": true, "dev": true, "requires": { - "is-glob": "2.0.1" + "is-glob": "^2.0.0" } }, "globals": { @@ -1288,10 +1288,10 @@ "bundled": true, "dev": true, "requires": { - "async": "1.5.2", - "optimist": "0.6.1", - "source-map": "0.4.4", - "uglify-js": "2.8.29" + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" }, "dependencies": { "source-map": { @@ -1299,7 +1299,7 @@ "bundled": true, "dev": true, "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -1309,7 +1309,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -1322,9 +1322,9 @@ "bundled": true, "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" }, "dependencies": { "isobject": { @@ -1339,8 +1339,8 @@ "bundled": true, "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "is-number": { @@ -1348,7 +1348,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -1356,7 +1356,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1366,7 +1366,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -1386,8 +1386,8 @@ "bundled": true, "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -1400,7 +1400,7 @@ "bundled": true, "dev": true, "requires": { - "loose-envify": "1.3.1" + "loose-envify": "^1.0.0" } }, "invert-kv": { @@ -1413,7 +1413,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "is-arrayish": { @@ -1431,7 +1431,7 @@ "bundled": true, "dev": true, "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-data-descriptor": { @@ -1439,7 +1439,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "is-descriptor": { @@ -1447,9 +1447,9 @@ "bundled": true, "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { @@ -1469,7 +1469,7 @@ "bundled": true, "dev": true, "requires": { - "is-primitive": "2.0.0" + "is-primitive": "^2.0.0" } }, "is-extendable": { @@ -1487,7 +1487,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-fullwidth-code-point": { @@ -1500,7 +1500,7 @@ "bundled": true, "dev": true, "requires": { - "is-extglob": "1.0.0" + "is-extglob": "^1.0.0" } }, "is-number": { @@ -1508,7 +1508,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "is-odd": { @@ -1516,7 +1516,7 @@ "bundled": true, "dev": true, "requires": { - "is-number": "4.0.0" + "is-number": "^4.0.0" }, "dependencies": { "is-number": { @@ -1531,7 +1531,7 @@ "bundled": true, "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" }, "dependencies": { "isobject": { @@ -1594,7 +1594,7 @@ "bundled": true, "dev": true, "requires": { - "append-transform": "0.4.0" + "append-transform": "^0.4.0" } }, "istanbul-lib-instrument": { @@ -1602,13 +1602,13 @@ "bundled": true, "dev": true, "requires": { - "babel-generator": "6.26.1", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "istanbul-lib-coverage": "1.2.0", - "semver": "5.5.0" + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.0", + "semver": "^5.3.0" } }, "istanbul-lib-report": { @@ -1616,10 +1616,10 @@ "bundled": true, "dev": true, "requires": { - "istanbul-lib-coverage": "1.2.0", - "mkdirp": "0.5.1", - "path-parse": "1.0.5", - "supports-color": "3.2.3" + "istanbul-lib-coverage": "^1.1.2", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" }, "dependencies": { "supports-color": { @@ -1627,7 +1627,7 @@ "bundled": true, "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } } } @@ -1637,11 +1637,11 @@ "bundled": true, "dev": true, "requires": { - "debug": "3.1.0", - "istanbul-lib-coverage": "1.2.0", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "source-map": "0.5.7" + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.1.2", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" }, "dependencies": { "debug": { @@ -1659,7 +1659,7 @@ "bundled": true, "dev": true, "requires": { - "handlebars": "4.0.11" + "handlebars": "^4.0.3" } }, "js-tokens": { @@ -1677,7 +1677,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } }, "lazy-cache": { @@ -1691,7 +1691,7 @@ "bundled": true, "dev": true, "requires": { - "invert-kv": "1.0.0" + "invert-kv": "^1.0.0" } }, "load-json-file": { @@ -1699,11 +1699,11 @@ "bundled": true, "dev": true, "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" } }, "locate-path": { @@ -1711,8 +1711,8 @@ "bundled": true, "dev": true, "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" }, "dependencies": { "path-exists": { @@ -1738,7 +1738,7 @@ "bundled": true, "dev": true, "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } }, "lru-cache": { @@ -1746,8 +1746,8 @@ "bundled": true, "dev": true, "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "map-cache": { @@ -1760,7 +1760,7 @@ "bundled": true, "dev": true, "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "md5-hex": { @@ -1768,7 +1768,7 @@ "bundled": true, "dev": true, "requires": { - "md5-o-matic": "0.1.1" + "md5-o-matic": "^0.1.1" } }, "md5-o-matic": { @@ -1781,7 +1781,7 @@ "bundled": true, "dev": true, "requires": { - "mimic-fn": "1.2.0" + "mimic-fn": "^1.0.0" } }, "merge-source-map": { @@ -1789,7 +1789,7 @@ "bundled": true, "dev": true, "requires": { - "source-map": "0.6.1" + "source-map": "^0.6.1" }, "dependencies": { "source-map": { @@ -1804,19 +1804,19 @@ "bundled": true, "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" } }, "mimic-fn": { @@ -1829,7 +1829,7 @@ "bundled": true, "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1842,8 +1842,8 @@ "bundled": true, "dev": true, "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -1851,7 +1851,7 @@ "bundled": true, "dev": true, "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -1874,18 +1874,18 @@ "bundled": true, "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "fragment-cache": "0.2.1", - "is-odd": "2.0.0", - "is-windows": "1.0.2", - "kind-of": "6.0.2", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-odd": "^2.0.0", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "arr-diff": { @@ -1910,10 +1910,10 @@ "bundled": true, "dev": true, "requires": { - "hosted-git-info": "2.6.0", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "normalize-path": { @@ -1921,7 +1921,7 @@ "bundled": true, "dev": true, "requires": { - "remove-trailing-separator": "1.1.0" + "remove-trailing-separator": "^1.0.1" } }, "npm-run-path": { @@ -1929,7 +1929,7 @@ "bundled": true, "dev": true, "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "number-is-nan": { @@ -1947,9 +1947,9 @@ "bundled": true, "dev": true, "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { @@ -1957,7 +1957,7 @@ "bundled": true, "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -1967,7 +1967,7 @@ "bundled": true, "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" }, "dependencies": { "isobject": { @@ -1982,8 +1982,8 @@ "bundled": true, "dev": true, "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" } }, "object.pick": { @@ -1991,7 +1991,7 @@ "bundled": true, "dev": true, "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" }, "dependencies": { "isobject": { @@ -2006,7 +2006,7 @@ "bundled": true, "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "optimist": { @@ -2014,8 +2014,8 @@ "bundled": true, "dev": true, "requires": { - "minimist": "0.0.8", - "wordwrap": "0.0.3" + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" } }, "os-homedir": { @@ -2028,9 +2028,9 @@ "bundled": true, "dev": true, "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" } }, "p-finally": { @@ -2043,7 +2043,7 @@ "bundled": true, "dev": true, "requires": { - "p-try": "1.0.0" + "p-try": "^1.0.0" } }, "p-locate": { @@ -2051,7 +2051,7 @@ "bundled": true, "dev": true, "requires": { - "p-limit": "1.2.0" + "p-limit": "^1.1.0" } }, "p-try": { @@ -2064,10 +2064,10 @@ "bundled": true, "dev": true, "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" } }, "parse-json": { @@ -2075,7 +2075,7 @@ "bundled": true, "dev": true, "requires": { - "error-ex": "1.3.1" + "error-ex": "^1.2.0" } }, "pascalcase": { @@ -2088,7 +2088,7 @@ "bundled": true, "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "path-is-absolute": { @@ -2111,9 +2111,9 @@ "bundled": true, "dev": true, "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "pify": { @@ -2131,7 +2131,7 @@ "bundled": true, "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pkg-dir": { @@ -2139,7 +2139,7 @@ "bundled": true, "dev": true, "requires": { - "find-up": "1.1.2" + "find-up": "^1.0.0" }, "dependencies": { "find-up": { @@ -2147,8 +2147,8 @@ "bundled": true, "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } } } @@ -2173,8 +2173,8 @@ "bundled": true, "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "is-number": { @@ -2182,7 +2182,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2190,7 +2190,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2200,7 +2200,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2210,9 +2210,9 @@ "bundled": true, "dev": true, "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" } }, "read-pkg-up": { @@ -2220,8 +2220,8 @@ "bundled": true, "dev": true, "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" }, "dependencies": { "find-up": { @@ -2229,8 +2229,8 @@ "bundled": true, "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } } } @@ -2245,7 +2245,7 @@ "bundled": true, "dev": true, "requires": { - "is-equal-shallow": "0.1.3" + "is-equal-shallow": "^0.1.3" } }, "regex-not": { @@ -2253,8 +2253,8 @@ "bundled": true, "dev": true, "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "remove-trailing-separator": { @@ -2277,7 +2277,7 @@ "bundled": true, "dev": true, "requires": { - "is-finite": "1.0.2" + "is-finite": "^1.0.0" } }, "require-directory": { @@ -2311,7 +2311,7 @@ "dev": true, "optional": true, "requires": { - "align-text": "0.1.4" + "align-text": "^0.1.1" } }, "rimraf": { @@ -2319,7 +2319,7 @@ "bundled": true, "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "safe-regex": { @@ -2327,7 +2327,7 @@ "bundled": true, "dev": true, "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "semver": { @@ -2345,10 +2345,10 @@ "bundled": true, "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -2356,7 +2356,7 @@ "bundled": true, "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2366,7 +2366,7 @@ "bundled": true, "dev": true, "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -2389,14 +2389,14 @@ "bundled": true, "dev": true, "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.1", - "use": "3.1.0" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "dependencies": { "define-property": { @@ -2404,7 +2404,7 @@ "bundled": true, "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -2412,7 +2412,7 @@ "bundled": true, "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2422,9 +2422,9 @@ "bundled": true, "dev": true, "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -2432,7 +2432,7 @@ "bundled": true, "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -2440,7 +2440,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -2448,7 +2448,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -2456,9 +2456,9 @@ "bundled": true, "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "isobject": { @@ -2478,7 +2478,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" } }, "source-map": { @@ -2491,11 +2491,11 @@ "bundled": true, "dev": true, "requires": { - "atob": "2.1.0", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.0", - "urix": "0.1.0" + "atob": "^2.0.0", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-url": { @@ -2508,12 +2508,12 @@ "bundled": true, "dev": true, "requires": { - "foreground-child": "1.5.6", - "mkdirp": "0.5.1", - "os-homedir": "1.0.2", - "rimraf": "2.6.2", - "signal-exit": "3.0.2", - "which": "1.3.0" + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" } }, "spdx-correct": { @@ -2521,8 +2521,8 @@ "bundled": true, "dev": true, "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { @@ -2535,8 +2535,8 @@ "bundled": true, "dev": true, "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { @@ -2549,7 +2549,7 @@ "bundled": true, "dev": true, "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" } }, "static-extend": { @@ -2557,8 +2557,8 @@ "bundled": true, "dev": true, "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -2566,7 +2566,7 @@ "bundled": true, "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -2576,8 +2576,8 @@ "bundled": true, "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" }, "dependencies": { "ansi-regex": { @@ -2590,7 +2590,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } } } @@ -2600,7 +2600,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -2608,7 +2608,7 @@ "bundled": true, "dev": true, "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } }, "strip-eof": { @@ -2626,11 +2626,11 @@ "bundled": true, "dev": true, "requires": { - "arrify": "1.0.1", - "micromatch": "3.1.10", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "require-main-filename": "1.0.1" + "arrify": "^1.0.1", + "micromatch": "^3.1.8", + "object-assign": "^4.1.0", + "read-pkg-up": "^1.0.1", + "require-main-filename": "^1.0.1" }, "dependencies": { "arr-diff": { @@ -2648,16 +2648,16 @@ "bundled": true, "dev": true, "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.2", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -2665,7 +2665,7 @@ "bundled": true, "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2675,13 +2675,13 @@ "bundled": true, "dev": true, "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -2689,7 +2689,7 @@ "bundled": true, "dev": true, "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -2697,7 +2697,7 @@ "bundled": true, "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { @@ -2705,7 +2705,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2713,7 +2713,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2723,7 +2723,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2731,7 +2731,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2741,9 +2741,9 @@ "bundled": true, "dev": true, "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" } }, "kind-of": { @@ -2758,14 +2758,14 @@ "bundled": true, "dev": true, "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -2773,7 +2773,7 @@ "bundled": true, "dev": true, "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -2781,7 +2781,7 @@ "bundled": true, "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2791,10 +2791,10 @@ "bundled": true, "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -2802,7 +2802,7 @@ "bundled": true, "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2812,7 +2812,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -2820,7 +2820,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -2828,9 +2828,9 @@ "bundled": true, "dev": true, "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.2" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } }, "is-number": { @@ -2838,7 +2838,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -2846,7 +2846,7 @@ "bundled": true, "dev": true, "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2866,19 +2866,19 @@ "bundled": true, "dev": true, "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.2", - "nanomatch": "1.2.9", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } } } @@ -2893,7 +2893,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } }, "to-regex": { @@ -2901,10 +2901,10 @@ "bundled": true, "dev": true, "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, "to-regex-range": { @@ -2912,8 +2912,8 @@ "bundled": true, "dev": true, "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" }, "dependencies": { "is-number": { @@ -2921,7 +2921,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" } } } @@ -2937,9 +2937,9 @@ "dev": true, "optional": true, "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" }, "dependencies": { "yargs": { @@ -2948,9 +2948,9 @@ "dev": true, "optional": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", "window-size": "0.1.0" } } @@ -2967,10 +2967,10 @@ "bundled": true, "dev": true, "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "0.4.3" + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" }, "dependencies": { "extend-shallow": { @@ -2978,7 +2978,7 @@ "bundled": true, "dev": true, "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "set-value": { @@ -2986,10 +2986,10 @@ "bundled": true, "dev": true, "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "to-object-path": "0.3.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" } } } @@ -2999,8 +2999,8 @@ "bundled": true, "dev": true, "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -3008,9 +3008,9 @@ "bundled": true, "dev": true, "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -3045,7 +3045,7 @@ "bundled": true, "dev": true, "requires": { - "kind-of": "6.0.2" + "kind-of": "^6.0.2" }, "dependencies": { "kind-of": { @@ -3060,8 +3060,8 @@ "bundled": true, "dev": true, "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, "which": { @@ -3069,7 +3069,7 @@ "bundled": true, "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "which-module": { @@ -3093,8 +3093,8 @@ "bundled": true, "dev": true, "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" }, "dependencies": { "is-fullwidth-code-point": { @@ -3102,7 +3102,7 @@ "bundled": true, "dev": true, "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "string-width": { @@ -3110,9 +3110,9 @@ "bundled": true, "dev": true, "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } } } @@ -3127,9 +3127,9 @@ "bundled": true, "dev": true, "requires": { - "graceful-fs": "4.1.11", - "imurmurhash": "0.1.4", - "slide": "1.1.6" + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "slide": "^1.1.5" } }, "y18n": { @@ -3147,18 +3147,18 @@ "bundled": true, "dev": true, "requires": { - "cliui": "4.0.0", - "decamelize": "1.2.0", - "find-up": "2.1.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "9.0.2" + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" }, "dependencies": { "ansi-regex": { @@ -3176,9 +3176,9 @@ "bundled": true, "dev": true, "requires": { - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "wrap-ansi": "2.1.0" + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" } }, "strip-ansi": { @@ -3186,7 +3186,7 @@ "bundled": true, "dev": true, "requires": { - "ansi-regex": "3.0.0" + "ansi-regex": "^3.0.0" } }, "yargs-parser": { @@ -3194,7 +3194,7 @@ "bundled": true, "dev": true, "requires": { - "camelcase": "4.1.0" + "camelcase": "^4.1.0" } } } @@ -3204,7 +3204,7 @@ "bundled": true, "dev": true, "requires": { - "camelcase": "4.1.0" + "camelcase": "^4.1.0" }, "dependencies": { "camelcase": { @@ -3228,7 +3228,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "options": { @@ -3243,7 +3243,7 @@ "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "parseuri": { @@ -3252,7 +3252,7 @@ "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", "dev": true, "requires": { - "better-assert": "1.0.2" + "better-assert": "~1.0.0" } }, "path-is-absolute": { @@ -3273,13 +3273,13 @@ "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.1", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "requires-port": { @@ -3305,12 +3305,12 @@ "integrity": "sha512-KS+3CNWWNtLbVN5j0/B+1hjxRzey+oTK6ejpAOoxMZis6aXeB8cUtfuvjHl97tuZx+t/qD/VyqFMjuzu2Js6uQ==", "dev": true, "requires": { - "debug": "3.1.0", - "engine.io": "3.2.0", - "has-binary2": "1.0.2", - "socket.io-adapter": "1.1.1", + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", "socket.io-client": "2.1.0", - "socket.io-parser": "3.2.0" + "socket.io-parser": "~3.2.0" } }, "socket.io-adapter": { @@ -3329,15 +3329,15 @@ "base64-arraybuffer": "0.1.5", "component-bind": "1.0.0", "component-emitter": "1.2.1", - "debug": "3.1.0", - "engine.io-client": "3.2.1", - "has-binary2": "1.0.2", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", "has-cors": "1.1.0", "indexof": "0.0.1", "object-component": "0.0.3", "parseqs": "0.0.5", "parseuri": "0.0.5", - "socket.io-parser": "3.2.0", + "socket.io-parser": "~3.2.0", "to-array": "0.1.4" } }, @@ -3348,7 +3348,7 @@ "dev": true, "requires": { "component-emitter": "1.2.1", - "debug": "3.1.0", + "debug": "~3.1.0", "isarray": "2.0.1" }, "dependencies": { @@ -3366,7 +3366,7 @@ "integrity": "sha1-MZJGHfo4x4Qk3Zv46gJWGaElqhA=", "dev": true, "requires": { - "options": "0.0.6" + "options": "^0.0.6" } }, "string_decoder": { @@ -3375,7 +3375,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "~5.1.0" } }, "supports-color": { @@ -3384,7 +3384,7 @@ "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", "dev": true, "requires": { - "has-flag": "1.0.0" + "has-flag": "^1.0.0" } }, "to-array": { From dd1d08b6319d1def729554446a5b0176978a8dad Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 22 Aug 2019 01:59:54 -0500 Subject: [PATCH 536/556] [fix test] Update tests. --- test/lib-http-proxy-test.js | 4 ++-- test/lib-https-proxy-test.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/lib-http-proxy-test.js b/test/lib-http-proxy-test.js index b507a0052..e38809c18 100644 --- a/test/lib-http-proxy-test.js +++ b/test/lib-http-proxy-test.js @@ -562,8 +562,8 @@ describe('lib/http-proxy.js', function() { }); }); - destiny.on('connection', function (socket) { - expect(socket.upgradeReq.headers['x-special-proxy-header']).to.eql('foobar'); + destiny.on('connection', function (socket, upgradeReq) { + expect(upgradeReq.headers['x-special-proxy-header']).to.eql('foobar'); socket.on('message', function (msg) { expect(msg).to.be('hello there'); diff --git a/test/lib-https-proxy-test.js b/test/lib-https-proxy-test.js index a44fadbf8..904de629e 100644 --- a/test/lib-https-proxy-test.js +++ b/test/lib-https-proxy-test.js @@ -168,7 +168,7 @@ describe('lib/http-proxy.js', function() { proxy.on('error', function (err, req, res) { expect(err).to.be.an(Error); if (semver.gt(process.versions.node, '0.12.0')) { - expect(err.toString()).to.be('Error: self signed certificate') + expect(err.toString()).to.be('Error: unable to verify the first certificate') } else { expect(err.toString()).to.be('Error: DEPTH_ZERO_SELF_SIGNED_CERT') } From 59c4403e9dc15ab9b19ee2a3f4aecbfc6c3d94c4 Mon Sep 17 00:00:00 2001 From: indexzero Date: Thu, 22 Aug 2019 02:02:28 -0500 Subject: [PATCH 537/556] [fix] Latest versions. --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 564cffd83..a4676174c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,12 @@ sudo: false language: node_js node_js: - - "4" - "6" - "8" + - "10" script: - npm test after_success: - bash <(curl -s https://codecov.io/bash) matrix: fast_finish: true -notifications: - email: - - travis@nodejitsu.com - irc: "irc.freenode.org#nodejitsu" From e5882136441100d17ee9da3076d5f1145c7cea42 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2019 02:16:50 -0500 Subject: [PATCH 538/556] [dist] Update dependency concat-stream to v2 (#1363) --- package-lock.json | 64 ++++++++++++++++++----------------------------- package.json | 2 +- 2 files changed, 26 insertions(+), 40 deletions(-) diff --git a/package-lock.json b/package-lock.json index e603ff0f8..b98a72dec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -97,9 +97,9 @@ "dev": true }, "buffer-from": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, "callsite": { @@ -142,14 +142,14 @@ "dev": true }, "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", "dev": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", - "readable-stream": "^2.2.2", + "readable-stream": "^3.0.2", "typedarray": "^0.0.6" } }, @@ -159,12 +159,6 @@ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", "dev": true }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -365,12 +359,6 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, "json3": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", @@ -3261,25 +3249,15 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true - }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "requires-port": { @@ -3370,12 +3348,20 @@ } }, "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } } }, "supports-color": { diff --git a/package.json b/package.json index 8afb823e1..68bd87905 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "async": "^2.0.0", - "concat-stream": "^1.6.2", + "concat-stream": "^2.0.0", "expect.js": "~0.3.1", "mocha": "^3.5.3", "nyc": "^11.7.1", From 749eec65c361cd3f890639ad9a1414184b0ebd49 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2019 02:21:15 -0500 Subject: [PATCH 539/556] [dist] Update dependency nyc to v14 (#1367) --- package-lock.json | 4051 +++++++++++++++------------------------------ package.json | 2 +- 2 files changed, 1291 insertions(+), 2762 deletions(-) diff --git a/package-lock.json b/package-lock.json index b98a72dec..50a3a6c29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,152 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/generator": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz", + "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==", + "dev": true, + "requires": { + "@babel/types": "^7.5.5", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz", + "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==", + "dev": true + }, + "@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/traverse": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz", + "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.5.5", + "@babel/types": "^7.5.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", + "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } + } + }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", @@ -20,6 +166,45 @@ "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", "dev": true }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", @@ -102,12 +287,84 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "caching-transform": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", + "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "dev": true, + "requires": { + "hasha": "^3.0.0", + "make-dir": "^2.0.0", + "package-hash": "^3.0.0", + "write-file-atomic": "^2.4.2" + } + }, "callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", "dev": true }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, "commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", @@ -117,6 +374,12 @@ "graceful-readlink": ">= 1.0.0" } }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", @@ -153,12 +416,44 @@ "typedarray": "^0.0.6" } }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, "cookie": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", "dev": true }, + "cp-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", + "integrity": "sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "make-dir": "^2.0.0", + "nested-error-stacks": "^2.0.0", + "pify": "^4.0.1", + "safe-buffer": "^5.0.1" + } + }, + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -167,12 +462,33 @@ "ms": "2.0.0" } }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, "diff": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", "dev": true }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "engine.io": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", @@ -245,12 +561,39 @@ "has-binary2": "~1.0.2" } }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, "eventemitter3": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.0.1.tgz", @@ -262,6 +605,26 @@ "integrity": "sha1-sKWaDS7/VDdUTr8M6qYBWEHQm1s=", "dev": true }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, "follow-redirects": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", @@ -270,12 +633,28 @@ "debug": "^3.1.0" } }, + "foreground-child": { + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", + "dev": true, + "requires": { + "cross-spawn": "^4", + "signal-exit": "^3.0.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", @@ -290,6 +669,18 @@ "path-is-absolute": "^1.0.0" } }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", + "dev": true + }, "graceful-readlink": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", @@ -302,6 +693,26 @@ "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", "dev": true }, + "handlebars": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "has-binary2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz", @@ -331,12 +742,33 @@ "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", "dev": true }, + "hasha": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", + "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", + "dev": true, + "requires": { + "is-stream": "^1.0.1" + } + }, "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", "dev": true }, + "hosted-git-info": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", + "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", @@ -359,79 +791,278 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "json3": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", - "dev": true - }, - "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, - "lodash._baseassign": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", - "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, - "lodash._basecreate": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", - "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", "dev": true }, - "lodash.create": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", - "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", "dev": true, "requires": { - "lodash._baseassign": "^3.0.0", - "lodash._basecreate": "^3.0.0", - "lodash._isiterateecall": "^3.0.0" + "append-transform": "^1.0.0" } }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "dev": true, + "requires": { + "handlebars": "^4.1.2" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "dev": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "^3.0.0", + "lodash._basecreate": "^3.0.0", + "lodash._isiterateecall": "^3.0.0" + } + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", "dev": true, "requires": { "lodash._getnative": "^3.0.0", @@ -439,6 +1070,51 @@ "lodash.isarray": "^3.0.0" } }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", @@ -463,6 +1139,12 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -492,2714 +1174,105 @@ "diff": "3.2.0", "escape-string-regexp": "1.0.5", "glob": "7.1.1", - "growl": "1.9.2", - "he": "1.1.1", - "json3": "3.3.2", - "lodash.create": "3.1.1", - "mkdirp": "0.5.1", - "supports-color": "3.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", - "dev": true - }, - "nyc": { - "version": "11.7.1", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.7.1.tgz", - "integrity": "sha512-EGePURSKUEpS1jWnEKAMhY+GWZzi7JC+f8iBDOATaOsLZW5hM/9eYx2dHGaEXa1ITvMm44CJugMksvP3NwMQMw==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "arrify": "^1.0.1", - "caching-transform": "^1.0.0", - "convert-source-map": "^1.5.1", - "debug-log": "^1.0.1", - "default-require-extensions": "^1.0.0", - "find-cache-dir": "^0.1.1", - "find-up": "^2.1.0", - "foreground-child": "^1.5.3", - "glob": "^7.0.6", - "istanbul-lib-coverage": "^1.1.2", - "istanbul-lib-hook": "^1.1.0", - "istanbul-lib-instrument": "^1.10.0", - "istanbul-lib-report": "^1.1.3", - "istanbul-lib-source-maps": "^1.2.3", - "istanbul-reports": "^1.4.0", - "md5-hex": "^1.2.0", - "merge-source-map": "^1.0.2", - "micromatch": "^2.3.11", - "mkdirp": "^0.5.0", - "resolve-from": "^2.0.0", - "rimraf": "^2.5.4", - "signal-exit": "^3.0.1", - "spawn-wrap": "^1.4.2", - "test-exclude": "^4.2.0", - "yargs": "11.1.0", - "yargs-parser": "^8.0.0" - }, - "dependencies": { - "align-text": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - } - }, - "amdefine": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "bundled": true, - "dev": true - }, - "append-transform": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "requires": { - "default-require-extensions": "^1.0.0" - } - }, - "archy": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "arr-diff": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "arr-flatten": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "bundled": true, - "dev": true - }, - "array-unique": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "arrify": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "async": { - "version": "1.5.2", - "bundled": true, - "dev": true - }, - "atob": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "bundled": true, - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "babel-generator": { - "version": "6.26.1", - "bundled": true, - "dev": true, - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - } - }, - "babel-messages": { - "version": "6.23.0", - "bundled": true, - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-runtime": { - "version": "6.26.0", - "bundled": true, - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "bundled": true, - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "bundled": true, - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "bundled": true, - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "bundled": true, - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "base": { - "version": "0.11.2", - "bundled": true, - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "1.8.5", - "bundled": true, - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "builtin-modules": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "caching-transform": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "md5-hex": "^1.2.0", - "mkdirp": "^0.5.1", - "write-file-atomic": "^1.1.4" - } - }, - "camelcase": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true - }, - "center-align": { - "version": "0.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, - "chalk": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "class-utils": { - "version": "0.3.6", - "bundled": true, - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "cliui": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "commondir": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "component-emitter": { - "version": "1.2.1", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "convert-source-map": { - "version": "1.5.1", - "bundled": true, - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "core-js": { - "version": "2.5.5", - "bundled": true, - "dev": true - }, - "cross-spawn": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "debug-log": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "decamelize": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "bundled": true, - "dev": true - }, - "default-require-extensions": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "strip-bom": "^2.0.0" - } - }, - "define-property": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "detect-indent": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "error-ex": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true, - "dev": true - }, - "execa": { - "version": "0.7.0", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - } - } - }, - "expand-brackets": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "expand-range": { - "version": "1.8.2", - "bundled": true, - "dev": true, - "requires": { - "fill-range": "^2.1.0" - } - }, - "extend-shallow": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "0.3.2", - "bundled": true, - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "filename-regex": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "fill-range": { - "version": "2.2.3", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^1.1.3", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "find-cache-dir": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "requires": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "for-in": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "for-own": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "foreground-child": { - "version": "1.5.6", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^4", - "signal-exit": "^3.0.0" - } - }, - "fragment-cache": { - "version": "0.2.1", - "bundled": true, - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "get-caller-file": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "get-value": { - "version": "2.0.6", - "bundled": true, - "dev": true - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-base": { - "version": "0.3.0", - "bundled": true, - "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - } - }, - "glob-parent": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "globals": { - "version": "9.18.0", - "bundled": true, - "dev": true - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "handlebars": { - "version": "4.0.11", - "bundled": true, - "dev": true, - "requires": { - "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" - }, - "dependencies": { - "source-map": { - "version": "0.4.4", - "bundled": true, - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "has-flag": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "has-value": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "has-values": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hosted-git-info": { - "version": "2.6.0", - "bundled": true, - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "invariant": { - "version": "2.2.4", - "bundled": true, - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "bundled": true, - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "bundled": true, - "dev": true - } - } - }, - "is-dotfile": { - "version": "1.0.3", - "bundled": true, - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "bundled": true, - "dev": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "is-extglob": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "is-finite": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-number": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-odd": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "bundled": true, - "dev": true - } - } - }, - "is-plain-object": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "is-utf8": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "isobject": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "isarray": "1.0.0" - } - }, - "istanbul-lib-coverage": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "istanbul-lib-hook": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "append-transform": "^0.4.0" - } - }, - "istanbul-lib-instrument": { - "version": "1.10.1", - "bundled": true, - "dev": true, - "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.0", - "semver": "^5.3.0" - } - }, - "istanbul-lib-report": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "requires": { - "istanbul-lib-coverage": "^1.1.2", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" - }, - "dependencies": { - "supports-color": { - "version": "3.2.3", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "1.2.3", - "bundled": true, - "dev": true, - "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.1.2", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "istanbul-reports": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "handlebars": "^4.0.3" - } - }, - "js-tokens": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "jsesc": { - "version": "1.3.0", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - }, - "lazy-cache": { - "version": "1.0.4", - "bundled": true, - "dev": true, - "optional": true - }, - "lcid": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "bundled": true, - "dev": true - } - } - }, - "lodash": { - "version": "4.17.5", - "bundled": true, - "dev": true - }, - "longest": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "loose-envify": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "js-tokens": "^3.0.0" - } - }, - "lru-cache": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "map-cache": { - "version": "0.2.2", - "bundled": true, - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "md5-hex": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "md5-o-matic": "^0.1.1" - } - }, - "md5-o-matic": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "mem": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "merge-source-map": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "bundled": true, - "dev": true - } - } - }, - "micromatch": { - "version": "2.3.11", - "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true, - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mixin-deep": { - "version": "1.3.1", - "bundled": true, - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "nanomatch": { - "version": "1.2.9", - "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "normalize-package-data": { - "version": "2.4.0", - "bundled": true, - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "bundled": true, - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "object-visit": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "isobject": "^3.0.0" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "object.omit": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - } - }, - "object.pick": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optimist": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "os-locale": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "p-finally": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "p-limit": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "parse-glob": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "bundled": true, - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "pascalcase": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "path-exists": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "path-key": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "path-parse": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, - "path-type": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "bundled": true, - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "bundled": true, - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "find-up": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - } - } - }, - "posix-character-classes": { - "version": "0.1.1", - "bundled": true, - "dev": true - }, - "preserve": { - "version": "0.2.0", - "bundled": true, - "dev": true - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "randomatic": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "read-pkg": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - } - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "bundled": true, - "dev": true - }, - "regex-cache": { - "version": "0.4.4", - "bundled": true, - "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, - "regex-not": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "repeat-element": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "bundled": true, - "dev": true - }, - "repeating": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "require-directory": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "resolve-from": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "bundled": true, - "dev": true - }, - "ret": { - "version": "0.1.15", - "bundled": true, - "dev": true - }, - "right-align": { - "version": "0.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.1" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-regex": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "semver": { - "version": "5.5.0", - "bundled": true, - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "set-value": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true - }, - "slide": { - "version": "1.1.6", - "bundled": true, - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.2.0" - } - }, - "source-map": { - "version": "0.5.7", - "bundled": true, - "dev": true - }, - "source-map-resolve": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "atob": "^2.0.0", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "bundled": true, - "dev": true - }, - "spawn-wrap": { - "version": "1.4.2", - "bundled": true, - "dev": true, - "requires": { - "foreground-child": "^1.5.6", - "mkdirp": "^0.5.0", - "os-homedir": "^1.0.1", - "rimraf": "^2.6.2", - "signal-exit": "^3.0.2", - "which": "^1.3.0" - } - }, - "spdx-correct": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "split-string": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "static-extend": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "test-exclude": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "requires": { - "arrify": "^1.0.1", - "micromatch": "^3.1.8", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "bundled": true, - "dev": true - }, - "braces": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "bundled": true, - "dev": true - } - } - }, - "extglob": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "bundled": true, - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - }, - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "bundled": true, - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "to-fast-properties": { - "version": "1.0.3", - "bundled": true, - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "to-regex": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - } - } - }, - "trim-right": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "uglify-js": { - "version": "2.8.29", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "yargs": { - "version": "3.10.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "union-value": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "bundled": true, - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } - } - }, - "unset-value": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "bundled": true, - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "isobject": { - "version": "3.0.1", - "bundled": true, - "dev": true - } - } - }, - "urix": { - "version": "0.1.0", - "bundled": true, - "dev": true - }, - "use": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "bundled": true, - "dev": true - } - } - }, - "validate-npm-package-license": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "which": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "window-size": { - "version": "0.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "wordwrap": { - "version": "0.0.3", - "bundled": true, - "dev": true - }, - "wrap-ansi": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "write-file-atomic": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "slide": "^1.1.5" - } - }, - "y18n": { - "version": "3.2.1", - "bundled": true, - "dev": true - }, - "yallist": { - "version": "2.1.2", - "bundled": true, - "dev": true - }, - "yargs": { - "version": "11.1.0", - "bundled": true, + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "camelcase": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "cliui": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "yargs-parser": { - "version": "9.0.2", - "bundled": true, - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } + "ms": "2.0.0" } - }, - "yargs-parser": { - "version": "8.1.0", - "bundled": true, + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "nested-error-stacks": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz", + "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "nyc": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.1.1.tgz", + "integrity": "sha512-OI0vm6ZGUnoGZv/tLdZ2esSVzDwUC88SNs+6JoSOMVxA+gKMB8Tk7jBwgemLx4O40lhhvZCVw1C+OYLOBOPXWw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "caching-transform": "^3.0.2", + "convert-source-map": "^1.6.0", + "cp-file": "^6.2.0", + "find-cache-dir": "^2.1.0", + "find-up": "^3.0.0", + "foreground-child": "^1.5.6", + "glob": "^7.1.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "merge-source-map": "^1.1.0", + "resolve-from": "^4.0.0", + "rimraf": "^2.6.3", + "signal-exit": "^3.0.2", + "spawn-wrap": "^1.4.2", + "test-exclude": "^5.2.3", + "uuid": "^3.3.2", + "yargs": "^13.2.2", + "yargs-parser": "^13.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { - "camelcase": "^4.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "bundled": true, - "dev": true - } + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } @@ -3219,12 +1292,74 @@ "wrappy": "1" } }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, "options": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", "dev": true }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "package-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", + "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^3.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, "parseqs": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", @@ -3243,12 +1378,83 @@ "better-assert": "~1.0.0" } }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, "readable-stream": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", @@ -3260,11 +1466,72 @@ "util-deprecate": "^1.0.1" } }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -3277,6 +1544,18 @@ "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, "socket.io": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.0.tgz", @@ -3338,6 +1617,64 @@ } } }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "spawn-wrap": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", + "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", + "dev": true, + "requires": { + "foreground-child": "^1.5.6", + "mkdirp": "^0.5.0", + "os-homedir": "^1.0.1", + "rimraf": "^2.6.2", + "signal-exit": "^3.0.2", + "which": "^1.3.0" + } + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "sse": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/sse/-/sse-0.0.6.tgz", @@ -3347,6 +1684,17 @@ "options": "^0.0.6" } }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -3364,6 +1712,21 @@ } } }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "supports-color": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", @@ -3373,18 +1736,85 @@ "has-flag": "^1.0.0" } }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", "dev": true }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "uglify-js": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", + "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true, + "optional": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", @@ -3397,12 +1827,71 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, "ws": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", @@ -3420,6 +1909,46 @@ "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", "dev": true }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", diff --git a/package.json b/package.json index 68bd87905..4ca207e80 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "concat-stream": "^2.0.0", "expect.js": "~0.3.1", "mocha": "^3.5.3", - "nyc": "^11.7.1", + "nyc": "^14.0.0", "semver": "^5.0.3", "socket.io": "^2.1.0", "socket.io-client": "^2.1.0", From 7a154f81d163e14cd2fc791203aef69b5142196e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2019 02:24:25 -0500 Subject: [PATCH 540/556] [dist] Update dependency agentkeepalive to v4 (#1358) --- examples/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/package.json b/examples/package.json index 93cc86519..55feb6937 100644 --- a/examples/package.json +++ b/examples/package.json @@ -3,7 +3,7 @@ "description": "packages required to run the examples", "version": "0.0.0", "dependencies": { - "agentkeepalive": "^2.0.3", + "agentkeepalive": "^4.0.0", "colors": "~0.6.2", "connect": "~2.11.0", "connect-restreamer": "~1.0.0", From 4a657a71267ae093e43473a155a3bb9dfc9784f8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2019 02:24:41 -0500 Subject: [PATCH 541/556] [dist] Update all non-major dependencies (#1356) --- examples/package.json | 4 ++-- package-lock.json | 8 ++++---- package.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/package.json b/examples/package.json index 55feb6937..1b96a860c 100644 --- a/examples/package.json +++ b/examples/package.json @@ -5,11 +5,11 @@ "dependencies": { "agentkeepalive": "^4.0.0", "colors": "~0.6.2", - "connect": "~2.11.0", + "connect": "~2.30.0", "connect-restreamer": "~1.0.0", "request": "~2.27.0", "socket.io": "~0.9.16", "socket.io-client": "~0.9.16", - "sse": "0.0.6" + "sse": "0.0.8" } } diff --git a/package-lock.json b/package-lock.json index 50a3a6c29..80d02fd3f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1676,12 +1676,12 @@ "dev": true }, "sse": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/sse/-/sse-0.0.6.tgz", - "integrity": "sha1-MZJGHfo4x4Qk3Zv46gJWGaElqhA=", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/sse/-/sse-0.0.8.tgz", + "integrity": "sha512-cviG7JH31TUhZeaEVhac3zTzA+2FwA7qvHziAHpb7mC7RNVJ/RbHN+6LIGsS2ugP4o2H15DWmrSMK+91CboIcg==", "dev": true, "requires": { - "options": "^0.0.6" + "options": "0.0.6" } }, "string-width": { diff --git a/package.json b/package.json index 4ca207e80..0e26e83dc 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "semver": "^5.0.3", "socket.io": "^2.1.0", "socket.io-client": "^2.1.0", - "sse": "0.0.6", + "sse": "0.0.8", "ws": "^3.0.0" }, "scripts": { From 192b2b980b1cd319eb4a6b397ad35e6935430fea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2019 02:29:14 -0500 Subject: [PATCH 542/556] [dist] Update dependency colors to v1 (#1360) --- examples/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/package.json b/examples/package.json index 1b96a860c..48320a686 100644 --- a/examples/package.json +++ b/examples/package.json @@ -4,8 +4,7 @@ "version": "0.0.0", "dependencies": { "agentkeepalive": "^4.0.0", - "colors": "~0.6.2", - "connect": "~2.30.0", + "colors": "~1.3.0", "connect-restreamer": "~1.0.0", "request": "~2.27.0", "socket.io": "~0.9.16", From 9d75b981a1f6bf651c63c2b1655a28abb00b1c58 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2019 02:29:37 -0500 Subject: [PATCH 543/556] [dist] Update dependency eventemitter3 to v4 (#1365) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 80d02fd3f..fc8220dc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -595,9 +595,9 @@ "dev": true }, "eventemitter3": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.0.1.tgz", - "integrity": "sha512-QOCPu979MMWX9XNlfRZoin+Wm+bK1SP7vv3NGUniYwuSJK/+cPA10blMaeRgzg31RvoSFk6FsCDVa4vNryBTGA==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==" }, "expect.js": { "version": "0.3.1", diff --git a/package.json b/package.json index 0e26e83dc..2d630f294 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ ], "main": "index.js", "dependencies": { - "eventemitter3": "^3.0.0", + "eventemitter3": "^4.0.0", "requires-port": "^1.0.0", "follow-redirects": "^1.0.0" }, From 0d9ed366b13bfbdab4511a70b0ea69db2c6f04f9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2019 02:30:06 -0500 Subject: [PATCH 544/556] [dist] Update dependency request to ~2.88.0 [SECURITY] (#1357) --- examples/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/package.json b/examples/package.json index 48320a686..6a3812fa1 100644 --- a/examples/package.json +++ b/examples/package.json @@ -6,7 +6,7 @@ "agentkeepalive": "^4.0.0", "colors": "~1.3.0", "connect-restreamer": "~1.0.0", - "request": "~2.27.0", + "request": "~2.88.0", "socket.io": "~0.9.16", "socket.io-client": "~0.9.16", "sse": "0.0.8" From c8fa599983976052343b0477da55d39c3a82a6b9 Mon Sep 17 00:00:00 2001 From: Subomi Oluwalana Date: Thu, 22 Aug 2019 08:31:44 +0100 Subject: [PATCH 545/556] Update README.md (#970) There were errors in the examples highlighted, check issue #969 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1ab0f9e44..9f0e75476 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ var proxy = httpProxy.createProxyServer({}); var server = 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' }); + proxy.web(req, res, { target: 'http://127.0.0.1:5050' }); }); console.log("listening on port 5050") @@ -175,7 +175,7 @@ var server = 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' + target: 'http://127.0.0.1:5050' }); }); From 806e4927c9d83c009aed3dbeea12e69c50103ddb Mon Sep 17 00:00:00 2001 From: Li Bin Date: Thu, 22 Aug 2019 15:34:29 +0800 Subject: [PATCH 546/556] fix reverse-proxy example require path (#1067) --- examples/http/reverse-proxy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/http/reverse-proxy.js b/examples/http/reverse-proxy.js index 1e80d4e93..336803fed 100644 --- a/examples/http/reverse-proxy.js +++ b/examples/http/reverse-proxy.js @@ -23,7 +23,7 @@ var http = require('http'), net = require('net'), - httpProxy = require('http-proxy'), + httpProxy = require('../../lib/http-proxy'), url = require('url'), util = require('util'); From c662f9ebcd8d623db374dbc7bef231b2b0af0c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristoffer=20Lund=C3=A9n?= Date: Thu, 22 Aug 2019 09:35:20 +0200 Subject: [PATCH 547/556] Fix path to local http-proxy in examples. (#1072) --- examples/http/ntlm-authentication.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/http/ntlm-authentication.js b/examples/http/ntlm-authentication.js index f18f2cbfc..808eaa0ef 100644 --- a/examples/http/ntlm-authentication.js +++ b/examples/http/ntlm-authentication.js @@ -1,4 +1,4 @@ -var httpProxy = require('http-proxy'); +var httpProxy = require('../../lib/http-proxy'); var Agent = require('agentkeepalive'); var agent = new Agent({ From 77a98159d2da0f20a03e2819c79662f36069f234 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2019 02:37:57 -0500 Subject: [PATCH 548/556] [dist] Update dependency async to v3 (#1359) --- package-lock.json | 17 ++++------------- package.json | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc8220dc6..1fbeb0d35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -212,13 +212,10 @@ "dev": true }, "async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", - "dev": true, - "requires": { - "lodash": "^4.14.0" - } + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.1.0.tgz", + "integrity": "sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ==", + "dev": true }, "async-limiter": { "version": "1.0.0", @@ -990,12 +987,6 @@ "path-exists": "^3.0.0" } }, - "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", - "dev": true - }, "lodash._baseassign": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", diff --git a/package.json b/package.json index 2d630f294..d5f4172b3 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "follow-redirects": "^1.0.0" }, "devDependencies": { - "async": "^2.0.0", + "async": "^3.0.0", "concat-stream": "^2.0.0", "expect.js": "~0.3.1", "mocha": "^3.5.3", From b4028ba78bc4616e6969e0e66b0fe4634849b68b Mon Sep 17 00:00:00 2001 From: Ben Costolo Date: Thu, 22 Aug 2019 03:38:28 -0400 Subject: [PATCH 549/556] Fix modify response middleware example (#1139) * declare app variable to house middleware * remove deprecated connect.createServer() function call * specify middleware with app.use() and pass app middleware to an http server --- .../middleware/modifyResponse-middleware.js | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/examples/middleware/modifyResponse-middleware.js b/examples/middleware/modifyResponse-middleware.js index e2cc79f87..5cd5885f0 100644 --- a/examples/middleware/modifyResponse-middleware.js +++ b/examples/middleware/modifyResponse-middleware.js @@ -28,24 +28,26 @@ var util = require('util'), colors = require('colors'), http = require('http'), connect = require('connect'), + app = connect(), httpProxy = require('../../lib/http-proxy'); // // Basic Connect App // -connect.createServer( - function (req, res, next) { - var _write = res.write; +app.use(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); + res.write = function (data) { + _write.call(res, data.toString().replace("Ruby", "nodejitsu")); } -).listen(8013); + next(); +}); + +app.use(function (req, res) { + proxy.web(req, res) +}); + +http.createServer(app).listen(8013); // // Basic Http Proxy Server From 244303b994525684e1ec8dff2e8055f89b62b1ee Mon Sep 17 00:00:00 2001 From: IdeaHunter Date: Thu, 22 Aug 2019 10:39:14 +0300 Subject: [PATCH 550/556] Fix incorrect target name for reverse proxy example (#1135) --- examples/http/reverse-proxy.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/http/reverse-proxy.js b/examples/http/reverse-proxy.js index 336803fed..b07caa5a8 100644 --- a/examples/http/reverse-proxy.js +++ b/examples/http/reverse-proxy.js @@ -31,8 +31,9 @@ var proxy = httpProxy.createServer(); var server = http.createServer(function (req, res) { util.puts('Receiving reverse proxy request for:' + req.url); - - proxy.web(req, res, {target: req.url, secure: false}); + var parsedUrl = url.parse(req.url); + var target = parsedUrl.protocol + '//' + parsedUrl.hostname; + proxy.web(req, res, {target: target, secure: false}); }).listen(8213); server.on('connect', function (req, socket) { From d05624167ce75e860770c13afeacec2ce0f67add Mon Sep 17 00:00:00 2001 From: Nick Gilligan Date: Thu, 22 Aug 2019 00:40:15 -0700 Subject: [PATCH 551/556] fix 'Modify Response' readme section to avoid unnecessary array copying (#1300) --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9f0e75476..5b2d0b3a2 100644 --- a/README.md +++ b/README.md @@ -501,12 +501,12 @@ data. selfHandleResponse : true }; proxy.on('proxyRes', function (proxyRes, req, res) { - var body = new Buffer(''); - proxyRes.on('data', function (data) { - body = Buffer.concat([body, data]); + var body = []; + proxyRes.on('data', function (chunk) { + body.push(chunk); }); proxyRes.on('end', function () { - body = body.toString(); + body = Buffer.concat(body).toString(); console.log("res from proxied server:", body); res.end("my response to cli"); }); From 6e4bef4d1cd96e7a284717941e0fc274acbd3712 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 5 Sep 2019 14:11:16 -0400 Subject: [PATCH 552/556] Added in auto-changelog module set to keepachangelog format (#1373) Removed last nodejitsu reference --- .auto-changelog | 6 + CHANGELOG.md | 1852 +++++++++++++++++ .../middleware/modifyResponse-middleware.js | 4 +- package-lock.json | 60 + package.json | 6 +- 5 files changed, 1924 insertions(+), 4 deletions(-) create mode 100644 .auto-changelog create mode 100644 CHANGELOG.md diff --git a/.auto-changelog b/.auto-changelog new file mode 100644 index 000000000..38e245582 --- /dev/null +++ b/.auto-changelog @@ -0,0 +1,6 @@ +{ + "output": "CHANGELOG.md", + "template": "keepachangelog", + "unreleased": true, + "commitLimit": false +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..caac0e520 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1852 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). + +## [Unreleased](https://github.com/http-party/node-http-proxy/compare/1.17.0...HEAD) + +### Merged + +- fix 'Modify Response' readme section to avoid unnecessary array copying [`#1300`](https://github.com/http-party/node-http-proxy/pull/1300) +- Fix incorrect target name for reverse proxy example [`#1135`](https://github.com/http-party/node-http-proxy/pull/1135) +- Fix modify response middleware example [`#1139`](https://github.com/http-party/node-http-proxy/pull/1139) +- [dist] Update dependency async to v3 [`#1359`](https://github.com/http-party/node-http-proxy/pull/1359) +- Fix path to local http-proxy in examples. [`#1072`](https://github.com/http-party/node-http-proxy/pull/1072) +- fix reverse-proxy example require path [`#1067`](https://github.com/http-party/node-http-proxy/pull/1067) +- Update README.md [`#970`](https://github.com/http-party/node-http-proxy/pull/970) +- [dist] Update dependency request to ~2.88.0 [SECURITY] [`#1357`](https://github.com/http-party/node-http-proxy/pull/1357) +- [dist] Update dependency eventemitter3 to v4 [`#1365`](https://github.com/http-party/node-http-proxy/pull/1365) +- [dist] Update dependency colors to v1 [`#1360`](https://github.com/http-party/node-http-proxy/pull/1360) +- [dist] Update all non-major dependencies [`#1356`](https://github.com/http-party/node-http-proxy/pull/1356) +- [dist] Update dependency agentkeepalive to v4 [`#1358`](https://github.com/http-party/node-http-proxy/pull/1358) +- [dist] Update dependency nyc to v14 [`#1367`](https://github.com/http-party/node-http-proxy/pull/1367) +- [dist] Update dependency concat-stream to v2 [`#1363`](https://github.com/http-party/node-http-proxy/pull/1363) +- x-forwarded-host overwrite for mutli level proxies [`#1267`](https://github.com/http-party/node-http-proxy/pull/1267) +- [refactor doc] Complete rename to http-party org. [`#1362`](https://github.com/http-party/node-http-proxy/pull/1362) +- Highlight correct lines for createProxyServer [`#1117`](https://github.com/http-party/node-http-proxy/pull/1117) +- Fix docs for rewrite options - 201 also handled [`#1147`](https://github.com/http-party/node-http-proxy/pull/1147) +- Update .nyc_output [`#1339`](https://github.com/http-party/node-http-proxy/pull/1339) +- Configure Renovate [`#1355`](https://github.com/http-party/node-http-proxy/pull/1355) +- [examples] Restream body before proxying, support for Content-Type of application/x-www-form-urlencoded [`#1264`](https://github.com/http-party/node-http-proxy/pull/1264) + +### Commits + +- [dist] New test fixtures. [`7e4a0e5`](https://github.com/http-party/node-http-proxy/commit/7e4a0e511bc30c059216860153301de2cdd1e97f) +- [dist] End of an era. [`a9b09cc`](https://github.com/http-party/node-http-proxy/commit/a9b09cce43f072db99fb5170030a05536177ccb7) +- [fix] Latest versions. [`59c4403`](https://github.com/http-party/node-http-proxy/commit/59c4403e9dc15ab9b19ee2a3f4aecbfc6c3d94c4) +- [fix test] Update tests. [`dd1d08b`](https://github.com/http-party/node-http-proxy/commit/dd1d08b6319d1def729554446a5b0176978a8dad) +- [dist] Update dependency ws to v3 [SECURITY] [`b00911c`](https://github.com/http-party/node-http-proxy/commit/b00911c93740a00c5cfbacbb91565cb6912ed255) +- [dist] .gitattributes all the things. [`fc93520`](https://github.com/http-party/node-http-proxy/commit/fc93520d741ec80be8ae31ca005f3e9c199e330e) +- [dist] Regenerate package-lock.json. [`16d4f8a`](https://github.com/http-party/node-http-proxy/commit/16d4f8a95162b2e2e4ee6657c500f1208c044b2d) + +## [1.17.0](https://github.com/http-party/node-http-proxy/compare/1.16.2...1.17.0) - 2018-04-20 + +### Merged + +- Fix overwriting of global options [`#1074`](https://github.com/http-party/node-http-proxy/pull/1074) +- Update README.md [`#1131`](https://github.com/http-party/node-http-proxy/pull/1131) +- Update README.md with CoC link [`#1120`](https://github.com/http-party/node-http-proxy/pull/1120) +- Add Code Of Conduct [`#1119`](https://github.com/http-party/node-http-proxy/pull/1119) +- [deps] Update eventemitter3 to version 2.0.x [`#1109`](https://github.com/http-party/node-http-proxy/pull/1109) + +### Fixed + +- Fix "Can't set headers after they are sent" errors [`#930`](https://github.com/http-party/node-http-proxy/issues/930) +- Include websocket non-upgrade response [`#890`](https://github.com/http-party/node-http-proxy/issues/890) + +### Commits + +- Add followRedirects option [`c9a556c`](https://github.com/http-party/node-http-proxy/commit/c9a556cfa57c7ce0b877e16f2c2e1448d8cc278d) +- [test] add test for selfHandleRequest and remove modifyResponse as selfHandleRequest is the only way that functionality works [`4a37175`](https://github.com/http-party/node-http-proxy/commit/4a37175a5296d2ea2da0fc15a3f8fe08599bb592) +- Adding ability to set cookie path [`2c98416`](https://github.com/http-party/node-http-proxy/commit/2c98416ac2bf17bb5f515b9e10ee4485f5913846) +- Updating docs and adding more tests. [`f5c2381`](https://github.com/http-party/node-http-proxy/commit/f5c2381395e01bf8d6655cc70e14032c8f0aaa67) +- [dist] make tests work reliably, add package-lock.json [`09dcb98`](https://github.com/http-party/node-http-proxy/commit/09dcb984565dabb159a01a75a188b974f8c176ad) +- add support for modify response [`e5c02b8`](https://github.com/http-party/node-http-proxy/commit/e5c02b8a8a902e204eee886acafbbfe46c4a3aef) +- [wip] proper tests and reporting [`f4ff100`](https://github.com/http-party/node-http-proxy/commit/f4ff1006b9e71eb4185a3edf03333dbe514a84c9) +- Add detail about "buffer" option [`6f88caf`](https://github.com/http-party/node-http-proxy/commit/6f88caf6e46d84a809910c591e138250b333b39f) +- Add use case for proxy to HTTPS using a PKCS12 client certificate [`d2f9db8`](https://github.com/http-party/node-http-proxy/commit/d2f9db824136358a06dc3dd566644f3a016f24e2) +- [test] for override method feature [`81d58c5`](https://github.com/http-party/node-http-proxy/commit/81d58c531be3f61efb56d2489a66c73a7b2325fe) +- [dist] doc updates [`e94d529`](https://github.com/http-party/node-http-proxy/commit/e94d52973a26cf817a9de12d97e5ae603093f70d) +- feat: 添加response自处理参数 [`89f9ef8`](https://github.com/http-party/node-http-proxy/commit/89f9ef87e0532d54d086719c5ace1a968a42e51b) +- [dist][test] codecov config [`a4bccc3`](https://github.com/http-party/node-http-proxy/commit/a4bccc332d36d7db93db984674cd7e51b43a1b99) +- Removing unnecessary check since this is a private API [`bc6a237`](https://github.com/http-party/node-http-proxy/commit/bc6a23709c37c65b5b16cc802d05cb57f099b0ce) +- issue #953: stop using writeHead [`2c44039`](https://github.com/http-party/node-http-proxy/commit/2c44039a7c30b190043da654ee7e5aed0304e979) +- [fix] move badges [`543636d`](https://github.com/http-party/node-http-proxy/commit/543636d0f662308ec8c9afdbf641f4036f002bfd) +- fix small typos in README [`8231984`](https://github.com/http-party/node-http-proxy/commit/8231984fb02dca331b4ef77e089db50855eea4f5) +- Added timeout option to docs [`107c187`](https://github.com/http-party/node-http-proxy/commit/107c18720c3906f9049cc14d075b31910c0ccf55) +- [dist] document the feature [`d533a1b`](https://github.com/http-party/node-http-proxy/commit/d533a1be437b37fed5bd25f5e58298eea819f974) +- [fix] slightly more tolerant [`de1b808`](https://github.com/http-party/node-http-proxy/commit/de1b80851ab1b1251b5eaeaf0beab164024f09b6) +- Forgot 'i' flag when changing from regex shorthand to string. [`50f58b4`](https://github.com/http-party/node-http-proxy/commit/50f58b4cd9b4422a11512a6a065432159b5bc806) +- Update common.js [`c5d8466`](https://github.com/http-party/node-http-proxy/commit/c5d846648304f2e36a172b25d9fb8300d8131f8c) +- [fix] rm newline [`e6f24ba`](https://github.com/http-party/node-http-proxy/commit/e6f24ba6173c4fdd26089b3c729de5dbdd71ad74) +- [dist] update package-lock.json [`abf882e`](https://github.com/http-party/node-http-proxy/commit/abf882e03c92cf1665d5b7d4dbdaf87feb50a677) + +## [1.16.2](https://github.com/http-party/node-http-proxy/compare/1.16.1...1.16.2) - 2016-12-06 + +### Merged + +- [WIP] Revert default behavior of writeHeaders method [`#1104`](https://github.com/http-party/node-http-proxy/pull/1104) + +## [1.16.1](https://github.com/http-party/node-http-proxy/compare/1.16.0...1.16.1) - 2016-12-04 + +### Commits + +- Enable proxy response to have multiple Set-Cookie raw headers #1101 [`8cb451f`](https://github.com/http-party/node-http-proxy/commit/8cb451f20cff0a19fc9576fc2558307fb17a5710) +- [dist] Version bump. 1.16.1 [`ac1a01b`](https://github.com/http-party/node-http-proxy/commit/ac1a01b1f3caa3a2a9433341bf5e7a95072d6612) + +## [1.16.0](https://github.com/http-party/node-http-proxy/compare/1.15.2...1.16.0) - 2016-12-02 + +### Merged + +- Fix newly introduced error in error handler for ECONNREFUSED in forward proxy [`#1100`](https://github.com/http-party/node-http-proxy/pull/1100) +- Keep original letter case of response header keys [`#1098`](https://github.com/http-party/node-http-proxy/pull/1098) +- Handle errors for forward request, add test case [`#1099`](https://github.com/http-party/node-http-proxy/pull/1099) + +### Commits + +- add node 6 to travis [`2f7f037`](https://github.com/http-party/node-http-proxy/commit/2f7f03778cfb94396acf0d778061ea197212fbb5) + +## [1.15.2](https://github.com/http-party/node-http-proxy/compare/1.15.1...1.15.2) - 2016-10-22 + +### Merged + +- Add proxy-timeout option to documentation [`#1075`](https://github.com/http-party/node-http-proxy/pull/1075) + +### Commits + +- Do not rely on func.name (no scope) [`61c2889`](https://github.com/http-party/node-http-proxy/commit/61c28891093b256bbc0dae78e45e2c5f0acf2101) +- Do not rely on func.name (no scope) [`d48f67e`](https://github.com/http-party/node-http-proxy/commit/d48f67eb90d8af66211093e91efdd6638859e0bf) +- Expose full callback names [`220f5fb`](https://github.com/http-party/node-http-proxy/commit/220f5fb795d2977c5a68ae59d7db65089efed50c) +- test case added [`f5217d6`](https://github.com/http-party/node-http-proxy/commit/f5217d6c20c164ed412a3b20f660786b6f88b35b) +- [fix] style nits [`d0f1dfe`](https://github.com/http-party/node-http-proxy/commit/d0f1dfeb8277d46a057017cd888b50e85f6725d6) +- With a comment [`fbc2668`](https://github.com/http-party/node-http-proxy/commit/fbc266809c289fbdb59d7944345816a858303c96) +- Fix browserification [`8eddf45`](https://github.com/http-party/node-http-proxy/commit/8eddf45f2a043e4e1b3f6e33c304e68fe7e1c406) +- not setting connection header in case of http2 as it is deprecated [`2d01edc`](https://github.com/http-party/node-http-proxy/commit/2d01edc5a5ace591784022b85860a3bbc48c5e12) + +## [1.15.1](https://github.com/http-party/node-http-proxy/compare/1.15.0...1.15.1) - 2016-09-14 + +### Merged + +- Properly write response header optionally including statusMessage [`#1061`](https://github.com/http-party/node-http-proxy/pull/1061) + +### Commits + +- [dist] Version bump. 1.15.1 [`912cd3a`](https://github.com/http-party/node-http-proxy/commit/912cd3acaef484f7ea08affc9339250082e04058) + +## [1.15.0](https://github.com/http-party/node-http-proxy/compare/1.14.0...1.15.0) - 2016-09-14 + +### Merged + +- Made it not to crash with omited Host http header [`#1050`](https://github.com/http-party/node-http-proxy/pull/1050) +- README.md: fix typo: 'ingoing' should be 'incoming' [`#1060`](https://github.com/http-party/node-http-proxy/pull/1060) +- Fix for Reason-Phrase being overwritten on proxy response. [`#1051`](https://github.com/http-party/node-http-proxy/pull/1051) +- cookieDomainRewrite option [`#1009`](https://github.com/http-party/node-http-proxy/pull/1009) +- Update ntlm-authentication.js [`#1025`](https://github.com/http-party/node-http-proxy/pull/1025) +- Restream body before proxying [`#1027`](https://github.com/http-party/node-http-proxy/pull/1027) +- Location rewriting for responses with status 201 [`#1024`](https://github.com/http-party/node-http-proxy/pull/1024) +- #866 Copy CA from options into outbound proxy [`#1042`](https://github.com/http-party/node-http-proxy/pull/1042) + +### Commits + +- [dist] Version bump. 1.15.0 [`b98c75b`](https://github.com/http-party/node-http-proxy/commit/b98c75b1ff3ebdf7f78224eb0d9aa857af2db1d9) + +## [1.14.0](https://github.com/http-party/node-http-proxy/compare/1.13.3...1.14.0) - 2016-06-15 + +### Merged + +- Emit disconnected event instead of error when ECONNRESET [`#966`](https://github.com/http-party/node-http-proxy/pull/966) +- fix test for node 0.10 + socket.io-client@1.4.6 (engine.io-client@1.6.9) [`#1010`](https://github.com/http-party/node-http-proxy/pull/1010) + +### Commits + +- [dist] Version bump. 1.14.0 [`fcfb0b3`](https://github.com/http-party/node-http-proxy/commit/fcfb0b37f6ac61369565507446377f91d955cf29) + +## [1.13.3](https://github.com/http-party/node-http-proxy/compare/1.13.2...1.13.3) - 2016-05-16 + +### Merged + +- fix browserify compatibility [`#975`](https://github.com/http-party/node-http-proxy/pull/975) +- alter message error [`#998`](https://github.com/http-party/node-http-proxy/pull/998) +- Sanitize header keys before setting them [`#997`](https://github.com/http-party/node-http-proxy/pull/997) +- Update ntlm-authentication.js [`#989`](https://github.com/http-party/node-http-proxy/pull/989) +- Add expected datatype to readme [`#983`](https://github.com/http-party/node-http-proxy/pull/983) +- Update README [`#982`](https://github.com/http-party/node-http-proxy/pull/982) +- Fix formatting of the `headers` option [`#974`](https://github.com/http-party/node-http-proxy/pull/974) +- Set the x-forwarded-host flag when xfwd is enabled [`#967`](https://github.com/http-party/node-http-proxy/pull/967) + +### Commits + +- [dist] Update LICENSE to reflect 2015 changes. [`f345a1a`](https://github.com/http-party/node-http-proxy/commit/f345a1ac2dde1884e72b952a685a0a1796059f14) +- [dist] Version bump. 1.13.3 [`5082acc`](https://github.com/http-party/node-http-proxy/commit/5082acc067bbf287f503bbd5b776f798ab169db1) + +## [1.13.2](https://github.com/http-party/node-http-proxy/compare/1.13.1...1.13.2) - 2016-02-17 + +### Merged + +- Fixed missing documentation: #options.headers [`#806`](https://github.com/http-party/node-http-proxy/pull/806) +- #949 Proxy example using req instead res on README [`#950`](https://github.com/http-party/node-http-proxy/pull/950) +- mocha: Use default reporter [`#962`](https://github.com/http-party/node-http-proxy/pull/962) +- Remove "transfer-encoding" header if "content-length" is set to zero [`#961`](https://github.com/http-party/node-http-proxy/pull/961) + +### Commits + +- [dist] Version bump. 1.13.2 [`e1b2f4c`](https://github.com/http-party/node-http-proxy/commit/e1b2f4c31b34464431db251b3b6169689dadf518) + +## [1.13.1](https://github.com/http-party/node-http-proxy/compare/1.13.0...1.13.1) - 2016-02-02 + +### Merged + +- README.md: summary to specify reverse proxy [`#932`](https://github.com/http-party/node-http-proxy/pull/932) +- fix(common) urlJoin replace: ":/" -> "http?s:/" [`#947`](https://github.com/http-party/node-http-proxy/pull/947) +- Update README.md [`#948`](https://github.com/http-party/node-http-proxy/pull/948) + +### Commits + +- [dist] Version bump. 1.13.1 [`9d9fa94`](https://github.com/http-party/node-http-proxy/commit/9d9fa940cff3aa6134c60732c23aea8171fc7296) + +## [1.13.0](https://github.com/http-party/node-http-proxy/compare/1.12.1...1.13.0) - 2016-01-26 + +### Merged + +- Fix for #839 (Ignore path and the trailing slash) [`#934`](https://github.com/http-party/node-http-proxy/pull/934) +- Update license year range to 2016 [`#943`](https://github.com/http-party/node-http-proxy/pull/943) + +### Commits + +- [dist] Version bump. 1.13.0 [`268994e`](https://github.com/http-party/node-http-proxy/commit/268994ea45d9f8737343001ab9542e03023a5c96) + +## [1.12.1](https://github.com/http-party/node-http-proxy/compare/1.12.0...1.12.1) - 2016-01-24 + +### Merged + +- Bump version for npm publish [`#942`](https://github.com/http-party/node-http-proxy/pull/942) +- Added check to passes/web-outgoing.js to make sure the header being s… [`#940`](https://github.com/http-party/node-http-proxy/pull/940) +- Created reverse-proxy.js example. [`#825`](https://github.com/http-party/node-http-proxy/pull/825) +- SSE example and test [`#922`](https://github.com/http-party/node-http-proxy/pull/922) +- More structured readme [`#912`](https://github.com/http-party/node-http-proxy/pull/912) +- Updated markdown docs to mention proxy rules module [`#910`](https://github.com/http-party/node-http-proxy/pull/910) +- Add tests for forwarding of continuation frames [`#901`](https://github.com/http-party/node-http-proxy/pull/901) +- Bump requires-port, server and ws [`#904`](https://github.com/http-party/node-http-proxy/pull/904) +- [example] add an example for NTLM authentication [`#903`](https://github.com/http-party/node-http-proxy/pull/903) + +### Commits + +- Organized README more [`cd1d777`](https://github.com/http-party/node-http-proxy/commit/cd1d7776e8fb5d67e2c52b9ef27d8c932e7b72e2) +- Add tests for testing forwarding of continuation frames [`64fa520`](https://github.com/http-party/node-http-proxy/commit/64fa52078913c6d4fe95673f182aac4924961e8b) +- Added back to top helpers [`6106d4c`](https://github.com/http-party/node-http-proxy/commit/6106d4c32f7c7960f0391591661e6f0d229db52d) +- [ci] use node 4.2 to test and do not allow failures [`f82ce18`](https://github.com/http-party/node-http-proxy/commit/f82ce18d2f187b085c2c4f49d857755d21c582b1) +- [fix] bump requires-port, server and ws [`9ea1e89`](https://github.com/http-party/node-http-proxy/commit/9ea1e89a2fd9c392cd40265bdb13494a3614e290) +- Updated markdown docs to mention proxy rules [`eea79ca`](https://github.com/http-party/node-http-proxy/commit/eea79cab53f27371cad387a524ee3aaefa742c48) +- Fixed tests depending on ignorePath [`f9540de`](https://github.com/http-party/node-http-proxy/commit/f9540de7b13f41091be2dcb68d8f23be65ad3885) +- Added check to passes/web-outgoing.js to make sure the header being set is not undefined, which should be the only falsey value that could accidently show up and break that call. This fixes windows NTLM auth issues behind http-proxy. [`3b39d2c`](https://github.com/http-party/node-http-proxy/commit/3b39d2c3dcb1785cc06043fcb226c652f554941e) +- No longer appends / to path if ignorePath is set [`f2093b5`](https://github.com/http-party/node-http-proxy/commit/f2093b5313c855cd6309cc0ddebb31f369e525ed) +- README.md: introduction to specify reverse proxy [`41414a5`](https://github.com/http-party/node-http-proxy/commit/41414a56a11ddfac3a337711ac4c64124eb62377) +- Added note for appending trailing / when using ignorePath [`0cb1d3c`](https://github.com/http-party/node-http-proxy/commit/0cb1d3c68e793fed9aa4a7624c32a018e796aa95) + +## [1.12.0](https://github.com/http-party/node-http-proxy/compare/1.11.3...1.12.0) - 2015-10-22 + +### Merged + +- Issue #896: provide a "proxyReq" event also for websocket connections. [`#897`](https://github.com/http-party/node-http-proxy/pull/897) + +### Commits + +- Provide a "proxyReq" event also for websocket connections. [`a05fc2d`](https://github.com/http-party/node-http-proxy/commit/a05fc2d1692d038f1eaad6d9b26c174039bc1949) +- fixes after PR review [`9752652`](https://github.com/http-party/node-http-proxy/commit/9752652e76da3bcfb6a635620e4162518ca43203) +- [dist] Version bump. 1.12.0 [`b5a6d0e`](https://github.com/http-party/node-http-proxy/commit/b5a6d0e58396363f4c457f6d1654614bdfcfcb73) + +## [1.11.3](https://github.com/http-party/node-http-proxy/compare/1.11.2...1.11.3) - 2015-10-19 + +### Merged + +- Removed unspecified trailing slash in proxy url [`#893`](https://github.com/http-party/node-http-proxy/pull/893) +- Updating the upgrading doc [`#892`](https://github.com/http-party/node-http-proxy/pull/892) + +### Commits + +- [dist] Update .travis.yml to be more modern. [`302d981`](https://github.com/http-party/node-http-proxy/commit/302d981dd2cf06dbf751b1f64e3dfea08d0f9476) +- [dist] Version bump. 1.11.3 [`60baca5`](https://github.com/http-party/node-http-proxy/commit/60baca5aed4f45ef1d7b3f7edd909375853d344b) +- docs: options.headers [`c86ae51`](https://github.com/http-party/node-http-proxy/commit/c86ae51bb9658309a9628f4f5182d4c45c803b84) + +## [1.11.2](https://github.com/http-party/node-http-proxy/compare/v1.11.1...1.11.2) - 2015-08-30 + +### Merged + +- Update gzip-middleware.js [`#870`](https://github.com/http-party/node-http-proxy/pull/870) +- Fix broken option list indentation [`#863`](https://github.com/http-party/node-http-proxy/pull/863) +- Added missing configuration options [`#852`](https://github.com/http-party/node-http-proxy/pull/852) +- Added installation instructions [`#823`](https://github.com/http-party/node-http-proxy/pull/823) +- fixes comment [`#817`](https://github.com/http-party/node-http-proxy/pull/817) + +### Commits + +- Created reverse-proxy.js example. [`38864d0`](https://github.com/http-party/node-http-proxy/commit/38864d016794b9ff3d8d1d1cb81a730b40a1bf9c) +- Added websocket set-cookie headers test [`855cebd`](https://github.com/http-party/node-http-proxy/commit/855cebdac4d33ef5f2fab4c4c78fdc07cdb61402) +- [fix] make more functional [`cea0e86`](https://github.com/http-party/node-http-proxy/commit/cea0e8676b3e609828320bb03051eaf78cc43b54) +- Modify the set-cookie header fix to work with node 0.10.x. [`da674ec`](https://github.com/http-party/node-http-proxy/commit/da674ec4df2b371f09e912f3b376c48581090a0f) +- Use raw headers instead parsed. [`8bfd90c`](https://github.com/http-party/node-http-proxy/commit/8bfd90c4d9331fd129f17a788ef9fc733654b7e0) +- Replaced Object.keys().map with for in loop. [`3d2350c`](https://github.com/http-party/node-http-proxy/commit/3d2350c54ff0fb9271f5fcfea1d23f22ad97c47c) +- [dist] Version bump. 1.11.2 [`30e3b37`](https://github.com/http-party/node-http-proxy/commit/30e3b371de0116e40e15156394f31c7e0b0aa9f1) +- Websocket key was unnecessary long. [`ca73208`](https://github.com/http-party/node-http-proxy/commit/ca732087498582df01ab78fb7da77912dab8f138) + +## [v1.11.1](https://github.com/http-party/node-http-proxy/compare/v1.11.0...v1.11.1) - 2015-04-22 + +### Commits + +- [dist] Version bump. 1.11.1 [`7e6c66a`](https://github.com/http-party/node-http-proxy/commit/7e6c66a7e485a6c0ec3a1c567bbe800fdc56c9fd) +- [fix] dont use bind in the one case we do [`d26ef56`](https://github.com/http-party/node-http-proxy/commit/d26ef56e1bc2a1232b06c01b4740e3bf35d63eda) +- [dist] update to new version of EE3 [`607f96c`](https://github.com/http-party/node-http-proxy/commit/607f96c00cbda2a6b881b8ff1db05437dbf4ce77) +- [fix] use the main export for EE3 [`18c77ca`](https://github.com/http-party/node-http-proxy/commit/18c77cafc7d5479502cf5c4d2b663d8f85cfd6d4) + +## [v1.11.0](https://github.com/http-party/node-http-proxy/compare/v1.10.1...v1.11.0) - 2015-04-20 + +### Merged + +- [api] add an ignorePath option if you want to disregard the path of the ... [`#759`](https://github.com/http-party/node-http-proxy/pull/759) + +### Commits + +- [dist] Version bump. 1.11.0 [`934e6c4`](https://github.com/http-party/node-http-proxy/commit/934e6c4d54292a1b961452074e02fb5d45da729a) + +## [v1.10.1](https://github.com/http-party/node-http-proxy/compare/v1.10.0...v1.10.1) - 2015-04-02 + +### Merged + +- Fix default port detection with node 0.12.x [`#799`](https://github.com/http-party/node-http-proxy/pull/799) + +### Commits + +- [dist] add semver and normalize package.json with --save-dev [`1b89bc9`](https://github.com/http-party/node-http-proxy/commit/1b89bc9a76c229070ff2572f7a0e1b969c4b4701) +- fix protocol and default port detection on node 0.12.x, compatible with 0.10.x [`5f14bca`](https://github.com/http-party/node-http-proxy/commit/5f14bcaa704fe8a5e6f59d3a89722f22958cade9) +- fix expected error message when node 0.12.x [`0ee314c`](https://github.com/http-party/node-http-proxy/commit/0ee314c436226391318b9a1b623cb3f7e8bf4df7) +- force cipher AES128-GCM-SHA256 in https tests [`c33d161`](https://github.com/http-party/node-http-proxy/commit/c33d1616cdbd60587ca2eb326c48b8a87ac56092) +- [fix] properly support iojs with test checking for HTTPS [`c6dfb04`](https://github.com/http-party/node-http-proxy/commit/c6dfb04a67f3b5ac9a402b7b08c1b8baf29f89e6) +- [dist] Version bump. 1.10.1 [`0bd446c`](https://github.com/http-party/node-http-proxy/commit/0bd446c680e9991accfaa3a6a70e411fdac79164) +- [ci] add 0.12 and iojs to travis [`a6ae6c4`](https://github.com/http-party/node-http-proxy/commit/a6ae6c499743ddade9db12b9f7404d980c79f683) + +## [v1.10.0](https://github.com/http-party/node-http-proxy/compare/v1.9.1...v1.10.0) - 2015-04-01 + +### Merged + +- Fixes / additions to URL rewriting [`#787`](https://github.com/http-party/node-http-proxy/pull/787) + +### Commits + +- [dist] Version bump. 1.10.0 [`1dabda2`](https://github.com/http-party/node-http-proxy/commit/1dabda241f3b93eb9195134042e7a3b84fd0ef57) + +## [v1.9.1](https://github.com/http-party/node-http-proxy/compare/v1.9.0...v1.9.1) - 2015-04-01 + +### Merged + +- Fix #747 [`#798`](https://github.com/http-party/node-http-proxy/pull/798) + +### Fixed + +- Fix https://github.com/nodejitsu/node-http-proxy/issues/747 [`#747`](https://github.com/nodejitsu/node-http-proxy/issues/747) + +### Commits + +- Add test for https://github.com/nodejitsu/node-http-proxy/issues/747 [`d145152`](https://github.com/http-party/node-http-proxy/commit/d145152655a69479348b0ebc726d4dc19720a12b) +- [dist] Version bump. 1.9.1 [`21b30b7`](https://github.com/http-party/node-http-proxy/commit/21b30b754db4f6410c3d2052bc123b3fdae57c46) + +## [v1.9.0](https://github.com/http-party/node-http-proxy/compare/v1.8.1...v1.9.0) - 2015-03-12 + +### Merged + +- Adding the nodejs0.12 auth option [`#792`](https://github.com/http-party/node-http-proxy/pull/792) +- fix "x-forwarded-proto" in node 0.12 and iojs [`#789`](https://github.com/http-party/node-http-proxy/pull/789) +- Add support for auto host rewriting and protocol rewriting [`#1`](https://github.com/http-party/node-http-proxy/pull/1) +- changed highlighted part - very minor [`#756`](https://github.com/http-party/node-http-proxy/pull/756) +- Update README.md for benchmarks [`#625`](https://github.com/http-party/node-http-proxy/pull/625) + +### Fixed + +- fix "x-forwarded-proto" in node 0.12 and iojs [`#772`](https://github.com/http-party/node-http-proxy/issues/772) +- [api] add an ignorePath option if you want to disregard the path of the incoming request when proxying to the target server fixes #758 [`#758`](https://github.com/http-party/node-http-proxy/issues/758) + +### Commits + +- added auth header test [`df158bf`](https://github.com/http-party/node-http-proxy/commit/df158bfc53e35e62609d8169f3883f6dcf12b73c) +- added auth header test [`ff1626f`](https://github.com/http-party/node-http-proxy/commit/ff1626f0719652c92895cf80f9aacc22ededadad) +- refactor some tests for greater readability [`14415a5`](https://github.com/http-party/node-http-proxy/commit/14415a50741d1f258da884686455d87d68eb8121) +- only rewrite redirect urls when it matches target [`26029ba`](https://github.com/http-party/node-http-proxy/commit/26029ba7ac948b5dc0befb2091cc9a5862d0641c) +- auth header added [`ab5c3e5`](https://github.com/http-party/node-http-proxy/commit/ab5c3e5c819ca993e0616d178bc1d282af539508) +- [dist] Version bump. 1.9.0 [`87a92a7`](https://github.com/http-party/node-http-proxy/commit/87a92a72802a27f817fcba87382d55831fd04ddb) +- end of file line space [`e907d7b`](https://github.com/http-party/node-http-proxy/commit/e907d7bb2aa2825b43d9355cb1ee25bec47b15ad) +- space instead of tabs [`7298510`](https://github.com/http-party/node-http-proxy/commit/7298510e9170d74ff057487085bc1e898f044177) +- space instead of tabs [`63c9262`](https://github.com/http-party/node-http-proxy/commit/63c9262df5bd04d83432db44fce2a4d5b19a59ea) +- auth header added tests [`f55ffa3`](https://github.com/http-party/node-http-proxy/commit/f55ffa356a259c09685c6b768a404e4b73f674ce) + +## [v1.8.1](https://github.com/http-party/node-http-proxy/compare/v1.8.0...v1.8.1) - 2014-12-17 + +### Commits + +- Pass HTTPS client parameters. [`402ab05`](https://github.com/http-party/node-http-proxy/commit/402ab057340a29db7a521ff239c5e21ac0c12be8) +- [dist] Version bump. 1.8.1 [`3311106`](https://github.com/http-party/node-http-proxy/commit/3311106c2c2346f3ac1ffe402b80bca3c7c59275) + +## [v1.8.0](https://github.com/http-party/node-http-proxy/compare/v1.7.3...v1.8.0) - 2014-12-17 + +### Merged + +- Fix variables scope in test [`#752`](https://github.com/http-party/node-http-proxy/pull/752) +- Fix typo [`#751`](https://github.com/http-party/node-http-proxy/pull/751) + +### Commits + +- Added websocket close event test [`8bff3dd`](https://github.com/http-party/node-http-proxy/commit/8bff3ddc1276e3ba18fd68c34d8982148cd21455) +- Deprecated proxySocket event in favor to open event. [`c62610e`](https://github.com/http-party/node-http-proxy/commit/c62610e8e4d59e8ba4642370ff3fb933c6ddb4eb) +- Update README.md [`05d18a4`](https://github.com/http-party/node-http-proxy/commit/05d18a4e1ba6c2de41b0b803cd1793357979384d) +- [fix] style spacing wtf [`ea0a4de`](https://github.com/http-party/node-http-proxy/commit/ea0a4ded803b30144e442344ad5a38a0d34bb3ba) +- [api] add close event in ws-incoming.js [`2653786`](https://github.com/http-party/node-http-proxy/commit/26537866b3ca522927aa4604a958f90774c0c0c0) +- [minor] grammar [`f304861`](https://github.com/http-party/node-http-proxy/commit/f30486195cfa6cfcf6400ac445975d5adada72e4) +- Changed proxyServer and destiny to local variables. [`8a8a894`](https://github.com/http-party/node-http-proxy/commit/8a8a894092ddbec8f0365ced0e94a75b1307ecf1) +- [dist] Version bump. 1.8.0 [`f0db5b3`](https://github.com/http-party/node-http-proxy/commit/f0db5b3f708b0858f617d472dfdd0ba211b774ef) + +## [v1.7.3](https://github.com/http-party/node-http-proxy/compare/v1.7.2...v1.7.3) - 2014-12-09 + +### Fixed + +- [fix] use simple regex instead of indexOf to check the protocol to support without the colon fixes #711 [`#711`](https://github.com/http-party/node-http-proxy/issues/711) + +### Commits + +- [test] show that we support protocol without the colon [`89f9ca1`](https://github.com/http-party/node-http-proxy/commit/89f9ca1e89d679b2b85a8f85b65e8b0878694207) +- [dist] Version bump. 1.7.3 [`6a330ff`](https://github.com/http-party/node-http-proxy/commit/6a330ff904d02a41f9a1cac338a98da1849c54ca) + +## [v1.7.2](https://github.com/http-party/node-http-proxy/compare/v1.7.1...v1.7.2) - 2014-12-08 + +### Merged + +- Fix grammar in README.md [`#749`](https://github.com/http-party/node-http-proxy/pull/749) + +### Fixed + +- [fix] properly include port in host header with changeOrigin in all cases fixes #750 [`#750`](https://github.com/http-party/node-http-proxy/issues/750) + +### Commits + +- [test] add tests for the changeOrigin cases in properly setting the host header [`71a06aa`](https://github.com/http-party/node-http-proxy/commit/71a06aab0249487ff650c8a47906cc8281561664) +- [dist] pin down deps and add requires-port [`81874f7`](https://github.com/http-party/node-http-proxy/commit/81874f795b7df7929e03d9d4cb98a947b1ef114b) +- [dist] Version bump. 1.7.2 [`2086e49`](https://github.com/http-party/node-http-proxy/commit/2086e4917c97f347f84c54b166799bc8db9f4162) + +## [v1.7.1](https://github.com/http-party/node-http-proxy/compare/v1.7.0...v1.7.1) - 2014-12-02 + +### Merged + +- Adding harmon to the README [`#716`](https://github.com/http-party/node-http-proxy/pull/716) + +### Fixed + +- [fix] fix #738 [`#738`](https://github.com/http-party/node-http-proxy/issues/738) +- [fix] simple fixes #748 #744 #746 [`#748`](https://github.com/http-party/node-http-proxy/issues/748) + +### Commits + +- [test] add proper failing test case for #738 [`410a8ce`](https://github.com/http-party/node-http-proxy/commit/410a8ce94ccea566a8e50daf3b78e633b82875cb) +- [Bugfix] Allow for multiple ? in outgoing urls. [`70ed1c4`](https://github.com/http-party/node-http-proxy/commit/70ed1c4273bc64500e8bae9b60d7fd6a19135246) +- [dist] Version bump. 1.7.1 [`56a7b77`](https://github.com/http-party/node-http-proxy/commit/56a7b77645b13d337c1a2f879460193d310454c8) + +## [v1.7.0](https://github.com/http-party/node-http-proxy/compare/v1.6.2...v1.7.0) - 2014-11-25 + +### Merged + +- Allow optional redirect host rewriting. [`#741`](https://github.com/http-party/node-http-proxy/pull/741) +- Set `Content-Length` header for OPTIONS requests [`#742`](https://github.com/http-party/node-http-proxy/pull/742) +- copy headers instead of referencing them so they don't unexpectedly get overwritten [`#736`](https://github.com/http-party/node-http-proxy/pull/736) +- Updated to support error callback on proxy.web and start/proxyReq/end co... [`#735`](https://github.com/http-party/node-http-proxy/pull/735) + +### Commits + +- :pencil: Add host rewrite docs and specs. [`add8133`](https://github.com/http-party/node-http-proxy/commit/add81338a90dae132f9e74fd5a5905fbcef030b7) +- [minor] style consistency [`48ae5d8`](https://github.com/http-party/node-http-proxy/commit/48ae5d828c23d6f19c9e2dd8c922d88a09f5ed0f) +- Updated to support error callback on proxy.web and start/proxyReq/end continue working. [`9ba8311`](https://github.com/http-party/node-http-proxy/commit/9ba8311343fd01b32505b8607ecf4294200f9dde) +- style changes [`84036e9`](https://github.com/http-party/node-http-proxy/commit/84036e9ddd1d4d925006c5438b3bcc0f17ba7a48) +- [fix] be defensive and ensure location is in headers before running url.parse() [`8d68ac0`](https://github.com/http-party/node-http-proxy/commit/8d68ac0e0fa3080b31580aa08e92a46cc1f27696) +- [dist] Version bump. 1.7.0 [`276f65a`](https://github.com/http-party/node-http-proxy/commit/276f65a3b810ded01757ec4bfd4fe2b00a1e66a8) + +## [v1.6.2](https://github.com/http-party/node-http-proxy/compare/v1.6.1...v1.6.2) - 2014-11-11 + +### Merged + +- do not modify the query string [`#733`](https://github.com/http-party/node-http-proxy/pull/733) + +### Commits + +- [fix] style changes [`7c5e40a`](https://github.com/http-party/node-http-proxy/commit/7c5e40a429fbc0c538f38d29d74acb633cb9b8d4) +- [minor] this shouldnt be in var block [`3f19e6e`](https://github.com/http-party/node-http-proxy/commit/3f19e6e178e168a16beee74186691f3e0e54d517) +- [dist] Version bump. 1.6.2 [`709b3e9`](https://github.com/http-party/node-http-proxy/commit/709b3e96560d619fab2617f9ddb902b4982b4103) + +## [v1.6.1](https://github.com/http-party/node-http-proxy/compare/v1.6.0...v1.6.1) - 2014-11-04 + +### Merged + +- websocket needs to respect `options.secure` too [`#729`](https://github.com/http-party/node-http-proxy/pull/729) +- changeOrigin option docs fix [`#724`](https://github.com/http-party/node-http-proxy/pull/724) + +### Commits + +- [dist] Version bump. 1.6.1 [`fa797fc`](https://github.com/http-party/node-http-proxy/commit/fa797fca900c10ebc848a2b445204b47da799483) + +## [v1.6.0](https://github.com/http-party/node-http-proxy/compare/v1.5.3...v1.6.0) - 2014-10-29 + +### Merged + +- Added changeOrigin option with test and docs [`#723`](https://github.com/http-party/node-http-proxy/pull/723) +- I presume you mean couchdb here [`#717`](https://github.com/http-party/node-http-proxy/pull/717) +- update modify request body eg [`#712`](https://github.com/http-party/node-http-proxy/pull/712) + +### Commits + +- harmon notes [`9f684d0`](https://github.com/http-party/node-http-proxy/commit/9f684d0439174d889d7b9a4ef6e2353e09481b2d) +- [dist] Version bump. 1.6.0 [`43641b0`](https://github.com/http-party/node-http-proxy/commit/43641b00b34ccc05bdf09f904695061d7c857aeb) + +## [v1.5.3](https://github.com/http-party/node-http-proxy/compare/v1.5.2...v1.5.3) - 2014-10-01 + +### Merged + +- close socket if upstream request fails [`#709`](https://github.com/http-party/node-http-proxy/pull/709) + +### Commits + +- [dist] Version bump. 1.5.3 [`9577a0f`](https://github.com/http-party/node-http-proxy/commit/9577a0faf2b78af606168673407ac47a851c084c) + +## [v1.5.2](https://github.com/http-party/node-http-proxy/compare/v1.5.1...v1.5.2) - 2014-10-01 + +### Merged + +- close websocket if proxyReq is closed before upgrade [`#708`](https://github.com/http-party/node-http-proxy/pull/708) + +### Commits + +- test closing upstream socket prior to upgrade [`7730548`](https://github.com/http-party/node-http-proxy/commit/77305489d9b88d283802477e155340e5dacfcc2c) +- [dist] Version bump. 1.5.2 [`43c6f0c`](https://github.com/http-party/node-http-proxy/commit/43c6f0c7c06d25a670c410500a8623531df458b1) + +## [v1.5.1](https://github.com/http-party/node-http-proxy/compare/v1.5.0...v1.5.1) - 2014-09-30 + +### Commits + +- [fix] do a check to make sure the server exists before we try and emit [`10a294a`](https://github.com/http-party/node-http-proxy/commit/10a294af4d4baac30b98ea9bec683a974443b83d) +- [dist] Version bump. 1.5.1 [`f0bf741`](https://github.com/http-party/node-http-proxy/commit/f0bf7418156db2cb87a616b0a34bb1f028db9142) + +## [v1.5.0](https://github.com/http-party/node-http-proxy/compare/v1.4.3...v1.5.0) - 2014-09-30 + +### Merged + +- exposing proxySocket on socket to support sniffing messages coming from proxy target [`#706`](https://github.com/http-party/node-http-proxy/pull/706) +- Fixed misleading documentation [`#705`](https://github.com/http-party/node-http-proxy/pull/705) +- Fix typo in README.md [`#702`](https://github.com/http-party/node-http-proxy/pull/702) +- handle 'upgrade' in comma-separated connection header [`#691`](https://github.com/http-party/node-http-proxy/pull/691) + +### Commits + +- test new detection of connection: upgrade [`ec683b9`](https://github.com/http-party/node-http-proxy/commit/ec683b924b1ef8cbdd2cd2bfb7e141b502773163) +- emitting proxySocket on proxyServer [`000eb53`](https://github.com/http-party/node-http-proxy/commit/000eb533de144cad01cfd97edf9ab6c350593d3c) +- [fix] perf optimization so we have a precompiled regexp [`c0a796b`](https://github.com/http-party/node-http-proxy/commit/c0a796b3e31de4f22eef00d93164e7238d9aa3ba) +- use regex to check for upgrade header [`65a21bc`](https://github.com/http-party/node-http-proxy/commit/65a21bce6dbbc6142a851dc959e237c0ef2b1091) +- [dist] Version bump. 1.5.0 [`232258b`](https://github.com/http-party/node-http-proxy/commit/232258b6ec2229497fe557454a121d917968f5e8) +- [minor] extra space [`e7d50b1`](https://github.com/http-party/node-http-proxy/commit/e7d50b1a376035a50c82db38605e99feb30afd36) + +## [v1.4.3](https://github.com/http-party/node-http-proxy/compare/v1.4.2...v1.4.3) - 2014-09-12 + +### Merged + +- Urgent: Fix breaking bug on url joining resulting in paths like `///path`. [`#699`](https://github.com/http-party/node-http-proxy/pull/699) + +### Commits + +- [minor] Added missing JSDoc comments [`73e8a4c`](https://github.com/http-party/node-http-proxy/commit/73e8a4cdd576868bf61d0848cc51f083a75454f9) +- Fix breaking bug on url joining resulting in paths like `///path`. [`73d865b`](https://github.com/http-party/node-http-proxy/commit/73d865bc9f8940f61c1ad4812f220920ead553b5) +- [minor] Code style adjustment. [`3ab6e95`](https://github.com/http-party/node-http-proxy/commit/3ab6e9591e66c203647605b4f275d374472c9d5f) +- Bump version v1.4.3 [`554f59c`](https://github.com/http-party/node-http-proxy/commit/554f59c5182d58b359df0159a29ff5ea35dd3830) +- [ignore] Ignore npm-debug.log [`a934cb6`](https://github.com/http-party/node-http-proxy/commit/a934cb6a46298c380e9bc794f18873576cf73c4c) + +## [v1.4.2](https://github.com/http-party/node-http-proxy/compare/v1.4.1...v1.4.2) - 2014-09-12 + +### Commits + +- [fix] ensure path works on windows because path.join doesnt like URLs [`ed73f06`](https://github.com/http-party/node-http-proxy/commit/ed73f06ed307ad2204e565781cc3154047941a8c) +- [dist] Version bump. 1.4.2 [`df12aeb`](https://github.com/http-party/node-http-proxy/commit/df12aeb12de79de1157898d45f4347fd0037dd70) + +## [v1.4.1](https://github.com/http-party/node-http-proxy/compare/v1.3.1...v1.4.1) - 2014-09-11 + +### Merged + +- Trimming contents of distributed npm package. [`#644`](https://github.com/http-party/node-http-proxy/pull/644) +- Remove changelog - it was not maintained [`#669`](https://github.com/http-party/node-http-proxy/pull/669) +- Removed duplicated imported dependencies [`#695`](https://github.com/http-party/node-http-proxy/pull/695) + +### Commits + +- [test] add test for prependPath option [`e44fabe`](https://github.com/http-party/node-http-proxy/commit/e44fabe58a233b367d42f26f15113e2022f71d7b) +- [api] add prependPath option to go with path change [`9a534c6`](https://github.com/http-party/node-http-proxy/commit/9a534c6ff63d776140918bc839801d247affd18d) +- [dist] Version bump. 1.4.1 [`d5c656b`](https://github.com/http-party/node-http-proxy/commit/d5c656bceb50dc9008ef223bc58b918adcf05352) +- [dist] Version bump. 1.4.0 [`dceef40`](https://github.com/http-party/node-http-proxy/commit/dceef407a1130033679e7e836c6753b76187ce5f) + +## [v1.3.1](https://github.com/http-party/node-http-proxy/compare/v1.3.0...v1.3.1) - 2014-09-09 + +### Merged + +- Allow proxy to maintain the original target path [`#693`](https://github.com/http-party/node-http-proxy/pull/693) +- Clarify usable parameters for 'proxyRes' event [`#686`](https://github.com/http-party/node-http-proxy/pull/686) + +### Commits + +- fix tests for maintaining proxy path [`a65021d`](https://github.com/http-party/node-http-proxy/commit/a65021d52b0ee039486819b5a95f442229458776) +- Fix proxy path [`511b7b3`](https://github.com/http-party/node-http-proxy/commit/511b7b3d4743636de9d9fbe8ff409730d221d273) +- Clarify usable parameters for proxyRes event. [`49a0de1`](https://github.com/http-party/node-http-proxy/commit/49a0de1e7cdcec9b555695605ab914038f99d66b) +- [dist] Version bump. 1.3.1 [`fc73828`](https://github.com/http-party/node-http-proxy/commit/fc73828035baf3cea3664560f8964f2a2a200d0a) +- [ci] remove 0.11.x to avoid failing builds caused by TLS errors [`6b83ae4`](https://github.com/http-party/node-http-proxy/commit/6b83ae47bbf2d5eab8ac94b4d6130e09a21ac85b) + +## [v1.3.0](https://github.com/http-party/node-http-proxy/compare/v1.2.1...v1.3.0) - 2014-08-14 + +### Merged + +- Added functionality to close proxy. [`#679`](https://github.com/http-party/node-http-proxy/pull/679) + +### Commits + +- [fix] cleanup and stylize close function [`261742a`](https://github.com/http-party/node-http-proxy/commit/261742a4295268ef93f45aa0f1e3a04208a2aed3) +- updated close function for safety [`8be9d94`](https://github.com/http-party/node-http-proxy/commit/8be9d945d03169056bbf84d702292b5763b015dc) +- [dist] Version bump. 1.3.0 [`05f0b89`](https://github.com/http-party/node-http-proxy/commit/05f0b891a610fb7779f90916fcd9ed750df818b2) + +## [v1.2.1](https://github.com/http-party/node-http-proxy/compare/v1.2.0...v1.2.1) - 2014-08-14 + +### Commits + +- Added close method to proxy server. [`a3d0219`](https://github.com/http-party/node-http-proxy/commit/a3d02196c5e62cd58bc0ebe8a66afcdb905d96b3) +- [fix] emit an error if proper URL is not passed in as a target [`37036dd`](https://github.com/http-party/node-http-proxy/commit/37036dd32565f72ad5777e47509293db18b60ed3) +- [dist] Version bump. 1.2.1 [`0a6b424`](https://github.com/http-party/node-http-proxy/commit/0a6b424e2c3b6cef68362a71f0e56740b2605af7) + +## [v1.2.0](https://github.com/http-party/node-http-proxy/compare/v1.1.6...v1.2.0) - 2014-08-05 + +### Merged + +- [api] Add event-based ability to modify pre-flight proxy requests. [`#673`](https://github.com/http-party/node-http-proxy/pull/673) + +### Commits + +- [dist] Version bump. 1.2.0 [`63c53a1`](https://github.com/http-party/node-http-proxy/commit/63c53a177217283ec14e4f7c2e891db48842ab4b) + +## [v1.1.6](https://github.com/http-party/node-http-proxy/compare/v1.1.5...v1.1.6) - 2014-07-17 + +### Fixed + +- do proper checking for a pass not existing. fixes #671 [`#671`](https://github.com/http-party/node-http-proxy/issues/671) + +### Commits + +- Remove changelog - it was not maintained [`e336b52`](https://github.com/http-party/node-http-proxy/commit/e336b52629276e647abeee300d7091db44e5b885) +- [dist] Version bump. 1.1.6 [`ed9e12b`](https://github.com/http-party/node-http-proxy/commit/ed9e12b0edb0fc206610e94bd696425619868474) + +## [v1.1.5](https://github.com/http-party/node-http-proxy/compare/v1.1.4...v1.1.5) - 2014-07-10 + +### Merged + +- Fix simple-balancer example [`#666`](https://github.com/http-party/node-http-proxy/pull/666) +- Added proxyTimeout option and two tests for timeout [`#658`](https://github.com/http-party/node-http-proxy/pull/658) + +### Fixed + +- Fix #657 [`#657`](https://github.com/http-party/node-http-proxy/issues/657) +- Fix #657 [`#657`](https://github.com/http-party/node-http-proxy/issues/657) + +### Commits + +- Added targetTimeout option and two tests for timeout [`0f24351`](https://github.com/http-party/node-http-proxy/commit/0f243516e1c6737b95fba220a5028439264b5de6) +- Change name targetTimeout to proxyTimeout [`7b79a74`](https://github.com/http-party/node-http-proxy/commit/7b79a7409ade7a8c79b2ae5761abc4843529063a) +- Trimming contents of distributed npm package. [`431aba7`](https://github.com/http-party/node-http-proxy/commit/431aba79d8d521e228c1403aaf4fd4a26fba03c3) +- [api] also emit the target on a proxy error [`d1baa36`](https://github.com/http-party/node-http-proxy/commit/d1baa3684e449610a2aae270816a7b8a907e588e) +- [dist] Version bump. 1.1.5 [`7104a7c`](https://github.com/http-party/node-http-proxy/commit/7104a7c023073a49091969f825738c79ae036123) +- fix balancer example [`9df4bc1`](https://github.com/http-party/node-http-proxy/commit/9df4bc1e1216a8e53675f0be16fb9081c11da225) + +## [v1.1.4](https://github.com/http-party/node-http-proxy/compare/v1.1.3...v1.1.4) - 2014-05-11 + +### Merged + +- `proxyRes` event, provide access to the req and res objects [`#642`](https://github.com/http-party/node-http-proxy/pull/642) + +### Commits + +- Add a test for the proxyRes event [`1385635`](https://github.com/http-party/node-http-proxy/commit/1385635e18f081af759c8e088f2f6b0219df83db) +- [dist] Version bump. 1.1.4 [`7cb98a4`](https://github.com/http-party/node-http-proxy/commit/7cb98a4e417312f01cf4432b52dbb3773aca60a0) +- Add the req and res objects to the proxyRes event [`1213e46`](https://github.com/http-party/node-http-proxy/commit/1213e46b1b0975ad1d5c5d0aaeace40a0811118f) + +## [v1.1.3](https://github.com/http-party/node-http-proxy/compare/v1.1.2...v1.1.3) - 2014-05-11 + +### Merged + +- Don't override connection header if Upgrading [`#640`](https://github.com/http-party/node-http-proxy/pull/640) + +### Commits + +- Adding test cases on preventing upgrade override [`8aa7c51`](https://github.com/http-party/node-http-proxy/commit/8aa7c519b15f734af7db34d2102781adbeae10aa) +- Update README.md for benchmarks [`4947484`](https://github.com/http-party/node-http-proxy/commit/4947484806f839d5e0a1b615b56a1bc847b8f534) +- [minor] style [`ccad177`](https://github.com/http-party/node-http-proxy/commit/ccad17795417de74bea2bcb6d6c559a4601af76d) +- [dist] Version bump. 1.1.3 [`c472527`](https://github.com/http-party/node-http-proxy/commit/c472527ea60da8b2f737d5742bc61ad2772b7e0b) + +## [v1.1.2](https://github.com/http-party/node-http-proxy/compare/v1.1.1...v1.1.2) - 2014-04-14 + +### Commits + +- [fix test] handle proxy error since we are properly aborting the proxy Request [`61c8734`](https://github.com/http-party/node-http-proxy/commit/61c8734e8b1115fab0e0db23fd8eeccbae61eee0) +- [fix] handle error on incoming request as well and properly abort proxy if client request is aborted [`77a1cff`](https://github.com/http-party/node-http-proxy/commit/77a1cff9bcf697eab27819eef054024bdc0a2ba3) +- [dist] Version bump. 1.1.2 [`c54278b`](https://github.com/http-party/node-http-proxy/commit/c54278bd3b00e82f4253393b6f6beb1d5a1b19e5) + +## [v1.1.1](https://github.com/http-party/node-http-proxy/compare/v1.1.0...v1.1.1) - 2014-04-11 + +### Commits + +- [dist] Version bump. 1.1.1 [`d908e2a`](https://github.com/http-party/node-http-proxy/commit/d908e2ad61013ed1f6e2f80c4b67a6dce7d0f504) +- [fix] let user make the decision on what to do with the buffer [`4f07dc2`](https://github.com/http-party/node-http-proxy/commit/4f07dc220d700ac90bd8405f7cb0724bdae4b430) + +## [v1.1.0](https://github.com/http-party/node-http-proxy/compare/v1.0.3...v1.1.0) - 2014-04-09 + +### Merged + +- Update UPGRADING.md [`#616`](https://github.com/http-party/node-http-proxy/pull/616) + +### Fixed + +- [fix] always be an eventemitter for consistency fixes #606 [`#606`](https://github.com/http-party/node-http-proxy/issues/606) + +### Commits + +- [api] emit a start an an end event [`8b48a9f`](https://github.com/http-party/node-http-proxy/commit/8b48a9fdab01624f7249c53f25919b1295eefb10) +- [dist] Version bump. 1.1.0 [`97ceeb3`](https://github.com/http-party/node-http-proxy/commit/97ceeb37d04e5d2195352365985165866323c4d7) +- [minor] missing angle bracket [`eca765a`](https://github.com/http-party/node-http-proxy/commit/eca765a856164c077ff9128949019552cdaf9a67) + +## [v1.0.3](https://github.com/http-party/node-http-proxy/compare/v1.0.2...v1.0.3) - 2014-03-27 + +### Merged + +- Fix for #591 [`#592`](https://github.com/http-party/node-http-proxy/pull/592) +- Add Repository field to package.json [`#578`](https://github.com/http-party/node-http-proxy/pull/578) +- Fix doc: option lines [`#575`](https://github.com/http-party/node-http-proxy/pull/575) + +### Fixed + +- [api] add toProxy method to allow absolute URLs to be sent when sending to another proxy fixes #603 [`#603`](https://github.com/http-party/node-http-proxy/issues/603) + +### Commits + +- [doc] update docs with toProxy option [`ece85b4`](https://github.com/http-party/node-http-proxy/commit/ece85b4e1ba379b3ed084bd8f606e285c14d4db3) +- [fix] set connection to CLOSE in cases where the agent is false. [`89a22bc`](https://github.com/http-party/node-http-proxy/commit/89a22bc00396f069eeb054ce30891a204077d16d) +- @xtreme-topher-bullock - update package.json to have proper repository key and formatting [`68fa17b`](https://github.com/http-party/node-http-proxy/commit/68fa17bbcaa73ae2d9539cba6f6ddff29f9e30d5) +- [dist] Version bump. 1.0.3 [`07fceb7`](https://github.com/http-party/node-http-proxy/commit/07fceb7c7aed25a8991d0295db4b4a7e50d79cf9) +- Add support for localAddress [`e633b0f`](https://github.com/http-party/node-http-proxy/commit/e633b0f7e4fd719d809eaeb4725e589f79c271ab) + +## [v1.0.2](https://github.com/http-party/node-http-proxy/compare/v1.0.1...v1.0.2) - 2014-01-28 + +### Merged + +- Update README.md [`#566`](https://github.com/http-party/node-http-proxy/pull/566) +- Fix argument order for ws stream pass [`#560`](https://github.com/http-party/node-http-proxy/pull/560) +- Extend listen to enable IPv6 support. [`#558`](https://github.com/http-party/node-http-proxy/pull/558) +- Fix before and after type check [`#556`](https://github.com/http-party/node-http-proxy/pull/556) + +### Fixed + +- Close outgoing ws if incoming ws emits error [`#559`](https://github.com/http-party/node-http-proxy/issues/559) +- [fix] closes #555 [`#555`](https://github.com/http-party/node-http-proxy/issues/555) + +### Commits + +- [fix] replicate node core behavior and throw an error if the user does not add their own error listener [`daad470`](https://github.com/http-party/node-http-proxy/commit/daad4703f3a80014936c89f4d67affdc3246f478) +- [dist] Version bump. 1.0.2 [`4bdc3e4`](https://github.com/http-party/node-http-proxy/commit/4bdc3e4f455b2749c03961404db74e3112a3e9e8) +- [doc] Fix broken image in npm by using an absolute link [`8004f4e`](https://github.com/http-party/node-http-proxy/commit/8004f4e5fc0f535806e92ec4e1bd973a45367dac) + +## [v1.0.1](https://github.com/http-party/node-http-proxy/compare/v1.0.0...v1.0.1) - 2014-01-17 + +### Fixed + +- [fix] closes #553 [`#553`](https://github.com/http-party/node-http-proxy/issues/553) + +### Commits + +- [dist] bump v1.0.1 [`68c5512`](https://github.com/http-party/node-http-proxy/commit/68c55123039369cdf8a55a64b36b719c96b672cf) +- typo [`689459f`](https://github.com/http-party/node-http-proxy/commit/689459fe46885a1b3b8e32a4df55f2d1339143e5) + +## [v1.0.0](https://github.com/http-party/node-http-proxy/compare/v0.10.4...v1.0.0) - 2014-01-16 + +### Merged + +- Http proxy 1.0 [`#552`](https://github.com/http-party/node-http-proxy/pull/552) +- Caronte [`#551`](https://github.com/http-party/node-http-proxy/pull/551) +- Only emit response if a valid server is present [`#549`](https://github.com/http-party/node-http-proxy/pull/549) +- [fix] add `type` to before and after to grab correct `passes`, fixes #537 [`#539`](https://github.com/http-party/node-http-proxy/pull/539) +- export the proxy itself from the main require [`#536`](https://github.com/http-party/node-http-proxy/pull/536) + +### Fixed + +- [fix] closes #547 [`#547`](https://github.com/http-party/node-http-proxy/issues/547) +- [fix] add `type` to before and after to grab correct `passes`, fixes #537 [`#537`](https://github.com/http-party/node-http-proxy/issues/537) + +### Commits + +- [nuke] old files [`a4ee8f9`](https://github.com/http-party/node-http-proxy/commit/a4ee8f9d82f71ef423c401b1f5e9f712b13cbc98) +- [docs] upgrade UPGRADING.md [`e599151`](https://github.com/http-party/node-http-proxy/commit/e5991519dbc7838aa4b8aeb5077d1c1ec5a13813) +- [api] export the httpProxy.Server as the main export but preserve the createServer factory [`182c76c`](https://github.com/http-party/node-http-proxy/commit/182c76cd2322d4d4c041c2a964d51db396c5c96b) +- [fix] remove caronte [`d6d2d0c`](https://github.com/http-party/node-http-proxy/commit/d6d2d0c8821bba9888eee7c3881fc408b3b2008e) +- [fix] ee3 error handling [`d23353d`](https://github.com/http-party/node-http-proxy/commit/d23353d980d8aa1b2606e3d36a83d27432952bef) +- [fix] comments [`6fa23e1`](https://github.com/http-party/node-http-proxy/commit/6fa23e11f6dc0b9c09766b268611ade919bfaa08) + +## [v0.10.4](https://github.com/http-party/node-http-proxy/compare/v0.10.3...v0.10.4) - 2013-12-27 + +### Merged + +- Update README.md [`#521`](https://github.com/http-party/node-http-proxy/pull/521) +- Better examples [`#520`](https://github.com/http-party/node-http-proxy/pull/520) +- Send path in req.path and not the url [`#416`](https://github.com/http-party/node-http-proxy/pull/416) +- Fix websocket error handing [`#518`](https://github.com/http-party/node-http-proxy/pull/518) +- attempting to fix links to 2 source locations in README.md [`#502`](https://github.com/http-party/node-http-proxy/pull/502) +- [merge] rename codename to actual project name [`#492`](https://github.com/http-party/node-http-proxy/pull/492) +- [merge] Added error handling example [`#484`](https://github.com/http-party/node-http-proxy/pull/484) +- [merge] https & agent [`#482`](https://github.com/http-party/node-http-proxy/pull/482) +- [merge] caronte tests [`#476`](https://github.com/http-party/node-http-proxy/pull/476) +- FIX: ws error event [`#475`](https://github.com/http-party/node-http-proxy/pull/475) +- Fix accidental write to global variable. [`#472`](https://github.com/http-party/node-http-proxy/pull/472) +- [fix] 2 spelling mistakes [`#14`](https://github.com/http-party/node-http-proxy/pull/14) +- [fix] add ability to proxy websockets over HTTPS [`#11`](https://github.com/http-party/node-http-proxy/pull/11) +- Tests [`#3`](https://github.com/http-party/node-http-proxy/pull/3) + +### Fixed + +- determine x-forwarded-port from host header [`#341`](https://github.com/http-party/node-http-proxy/issues/341) +- [fix] closes #529 [`#529`](https://github.com/http-party/node-http-proxy/issues/529) +- [fix] fixes #341 [`#341`](https://github.com/http-party/node-http-proxy/issues/341) +- [tests] https test pass, fix #511. Exposed the rejectUnauthorized flag [`#511`](https://github.com/http-party/node-http-proxy/issues/511) +- [fix] pass proper options object that extend the global options and parse the per proxy args into options. fixes #510 [`#510`](https://github.com/http-party/node-http-proxy/issues/510) +- [readme] add links to badges on readme, fix #483 [`#483`](https://github.com/http-party/node-http-proxy/issues/483) +- [fix] pooled connections, closes #478 [`#478`](https://github.com/http-party/node-http-proxy/issues/478) +- [fix] add 0.10 link, fixes #459 [`#459`](https://github.com/http-party/node-http-proxy/issues/459) +- [fix] closes #473 [`#473`](https://github.com/http-party/node-http-proxy/issues/473) +- [fix] add 0.10 compatibily.. closes #474 [`#474`](https://github.com/http-party/node-http-proxy/issues/474) +- [fix] headers, closes #469 [`#469`](https://github.com/http-party/node-http-proxy/issues/469) +- [fix] headers, fixes #467 [`#467`](https://github.com/http-party/node-http-proxy/issues/467) +- [fix] yawnt baaaka .. fixes #8 [`#8`](https://github.com/http-party/node-http-proxy/issues/8) + +### Commits + +- [fix] more jshint intendation [`17399e7`](https://github.com/http-party/node-http-proxy/commit/17399e7c3ef9addf9dd8f7c628b273e693f128a1) +- [fix] tests [`a255f98`](https://github.com/http-party/node-http-proxy/commit/a255f984fecf24c9290f3ad58d1b68e54a7509eb) +- [minor] remove coverage [`335af81`](https://github.com/http-party/node-http-proxy/commit/335af81d0244e62ecb501690bd15bc5a04ec51a3) +- [examples] updated websockets examples [`ed8c9ee`](https://github.com/http-party/node-http-proxy/commit/ed8c9eeba99d60f39f5c36c4f34ed1a781d2cfd8) +- [tests] removed unused tests [`7e25bde`](https://github.com/http-party/node-http-proxy/commit/7e25bded27effc1b3d47121ce21465a4e2ec7c0b) +- [tests] Added a test case for run all the examples [`bc236d7`](https://github.com/http-party/node-http-proxy/commit/bc236d7e95ef10bc17cf551eea2cd2fb9bf265eb) +- [tests] drop the test of own streams, moved the usable tests [`dc9d7e5`](https://github.com/http-party/node-http-proxy/commit/dc9d7e5452c7d39ae1d242cb8021ca75e4f736d4) +- [fix] default port [`d166354`](https://github.com/http-party/node-http-proxy/commit/d1663549ec070e7ae8bc45ffb148f40ee903192f) +- [tests] added the ws passes test and the streams webscokets test [`8b3fe32`](https://github.com/http-party/node-http-proxy/commit/8b3fe32f6ae60ae067bc5e40cdc43015e689467f) +- [refactor minor] s/caronte/http-proxy/ or s/caronte/httpProxy/ where appropriate. [`bb0d28c`](https://github.com/http-party/node-http-proxy/commit/bb0d28c58729e2cc70e8446f7fbf1113a6fa9310) +- [examples] updated bodyDecoder middleware example [`c82ff2c`](https://github.com/http-party/node-http-proxy/commit/c82ff2c3c0c0165421fbc4e7e94fa3f59d59aa38) +- [dist] first [`4d13156`](https://github.com/http-party/node-http-proxy/commit/4d131567211bcefc6ef0b0592d374fef7bd5abd8) +- [examples] update forward and custom error examples [`b726116`](https://github.com/http-party/node-http-proxy/commit/b7261161343c3471201d6de36ba1030aced26425) +- [refactor docs] add descriptions [`d05af4a`](https://github.com/http-party/node-http-proxy/commit/d05af4af60a5f3d308aa68bf09ab0cf9e5528c52) +- [tests] make the tests run with the last refactor [`5bb83b9`](https://github.com/http-party/node-http-proxy/commit/5bb83b967edb514402698eecfe3db7ab5fe60b06) +- [examples] deleted this examples [`bdeabb7`](https://github.com/http-party/node-http-proxy/commit/bdeabb767a537bcb9f98ef74f6efe9762a9b1c34) +- websocket draft [`07551c6`](https://github.com/http-party/node-http-proxy/commit/07551c63e428551e5d6e52362efd9620a14c71b4) +- [fix] naming [`2a59366`](https://github.com/http-party/node-http-proxy/commit/2a593664a5768c90d9b2edf4c298460416b38926) +- [dist doc] Added documentation for consistent benchmarking of node-http-proxy [`f7f5fa7`](https://github.com/http-party/node-http-proxy/commit/f7f5fa727e8f1d3f4946e61ad03830dab1da01a5) +- [examples] update old examples [`7e44d36`](https://github.com/http-party/node-http-proxy/commit/7e44d3669bbd1b13e6452f265d52b22396f68b5d) +- [docs] more short examples to the Readme [`0393b5d`](https://github.com/http-party/node-http-proxy/commit/0393b5da990bb45e873bb80d87a0bc9e4dd6a477) +- [examples] updated old proxy examples [`e02317c`](https://github.com/http-party/node-http-proxy/commit/e02317ce86ff2dabd496cf7e2741e219a22ac817) +- [wip] Initial HTTPS->HTTP test, updated https-secure example. Work in progress, need to add more https tests [`33a2462`](https://github.com/http-party/node-http-proxy/commit/33a2462d28c7d1fa26b03bcf290242ff7cd83e7a) +- [docs] readme [`886a870`](https://github.com/http-party/node-http-proxy/commit/886a8707078f59d0467b34686455bb5bdfadbc0c) +- [examples] added error-handling using callbacks and HTTP-to-HTTPS examples [`d7064f2`](https://github.com/http-party/node-http-proxy/commit/d7064f2e1e149fe870cbb158932cb99f9f192fce) +- [examples] updated old examples [`588327c`](https://github.com/http-party/node-http-proxy/commit/588327c2c4392618b515164989f08ef20a30842b) +- stuff [`e45bfd6`](https://github.com/http-party/node-http-proxy/commit/e45bfd66a21a2470c5a4a4cc1d6095494bbc0f6b) +- [doc] added some documentation to functions and comments to understand better the code [`5dcdf2b`](https://github.com/http-party/node-http-proxy/commit/5dcdf2b36c24a9584f044b7529265b9ac861d8c7) +- Fixed issue where error callback would not invoke, including new test cases. Added req/res values to error events. [`0bfb9be`](https://github.com/http-party/node-http-proxy/commit/0bfb9be418926f2113489e92504038127d4c04bb) +- [examples] updated balancer examples [`831a44b`](https://github.com/http-party/node-http-proxy/commit/831a44b3c8c3acf6c046c47703a07cd6362a0d1c) +- socket.io stuff [`a74cd85`](https://github.com/http-party/node-http-proxy/commit/a74cd85c8a5aae2851acf7139648fefd6a02a57b) +- [tests] move contributions of @mmoulton to correct place [`7c72f3b`](https://github.com/http-party/node-http-proxy/commit/7c72f3b407a084a896e420c23ababc3e9357feca) +- [tests] this file is not necessary anymore [`881c7e6`](https://github.com/http-party/node-http-proxy/commit/881c7e62e0bef7b4b9f81b6fd121f7ad6641bd77) +- [refactor] move to leaner architecture [`8273cb6`](https://github.com/http-party/node-http-proxy/commit/8273cb6461e4d33f36e583b0354d1bea038d0a56) +- [fix] remove trailing whitespaces [`0aeaba7`](https://github.com/http-party/node-http-proxy/commit/0aeaba7fe6c51f150d0322eb90a77c1701ed88f5) +- [test] added tests for web-outgoing.js [`16a4d9d`](https://github.com/http-party/node-http-proxy/commit/16a4d9da1136b79f40ad80482d3fd17dc74274b1) +- [fix] some stuff start debugging proxystream [`d4f0da8`](https://github.com/http-party/node-http-proxy/commit/d4f0da898e5e8a2d6740e50a7fc34576435e1132) +- [tests] now each test use a different port to avoid some slow opening and closing ports [`c75d06c`](https://github.com/http-party/node-http-proxy/commit/c75d06c5f92eb7c814deb49bb33cf9fffc632d97) +- [tests] fixed inherits problem and listen for the correct event [`c65ffbb`](https://github.com/http-party/node-http-proxy/commit/c65ffbb976467dc1768983dcffe111d18e8f2db1) +- [fix] ProxyStraem now works [`356f43d`](https://github.com/http-party/node-http-proxy/commit/356f43d719998d135e0fc404ac8508e330cf1e5b) +- [examples] fix the copyright header of example files [`e592c53`](https://github.com/http-party/node-http-proxy/commit/e592c53d1a23b7920d603a9e9ac294fc0e841f6d) +- [feature] start working on the new server [`b79bd29`](https://github.com/http-party/node-http-proxy/commit/b79bd29d5e984f34b9c07fbdc803aed83b3fd0bb) +- ENH: updated examples [`f566a42`](https://github.com/http-party/node-http-proxy/commit/f566a42e511f4a6a8f3620f64e05df209e61b64f) +- [examples] updated the modifyResponse-middleware example [`de3ff11`](https://github.com/http-party/node-http-proxy/commit/de3ff11656b4a847de3a63b28feed39b6c816480) +- [examples] add example of gzip using the connect.compress() middleware [`2142c50`](https://github.com/http-party/node-http-proxy/commit/2142c506e08f56d52e1995da5506c3e032f19c3c) +- [fix] refactor error handling [`601dbcb`](https://github.com/http-party/node-http-proxy/commit/601dbcbfe929af31995568b4f36b877245809058) +- [tests] fixed according new refactor and added test to common.setupSocket() [`1cb967b`](https://github.com/http-party/node-http-proxy/commit/1cb967b90aaa5b9da57727b8acbd95108437797a) +- [feature] websocket support [`79a14ac`](https://github.com/http-party/node-http-proxy/commit/79a14acfd2b2bf03f5ae2b334e7a37e619da6bb9) +- keepalive sockets [`dad211e`](https://github.com/http-party/node-http-proxy/commit/dad211e71c9ac3b32eba1ea3755edb688053b9d3) +- [tests] Using target field, tests now pass. We are missing the tests using forward field [`8085178`](https://github.com/http-party/node-http-proxy/commit/8085178dc2c24567adfb872a583863709ce60b5b) +- [fix] callback as optional error handler [`c7924e0`](https://github.com/http-party/node-http-proxy/commit/c7924e01f92aeec07333273f0882c1dd5e9521ae) +- ENH: added new https example, needs to be simplified before merge [`427d8d8`](https://github.com/http-party/node-http-proxy/commit/427d8d85369b0cd1d38afa0dd0f28ac98fa16001) +- [test] proxystream test [`c961279`](https://github.com/http-party/node-http-proxy/commit/c9612798f1207a4c40b616608bf6274d79ad0e4d) +- [lib] initial draft to websockets passes [`79f7f99`](https://github.com/http-party/node-http-proxy/commit/79f7f99528661162ae4153856888f078f666e017) +- [tests] added HTTPS to HTTPS test [`31d919b`](https://github.com/http-party/node-http-proxy/commit/31d919b0a3d0b7f574e88fc5eed093c6b1a53548) +- [fix] minor [`7599cee`](https://github.com/http-party/node-http-proxy/commit/7599cee3fd03a5ce645e313f35557a41c9ac1aee) +- [feature] started working on error propagation, kinda sucks, gotta think it over [`9ab8749`](https://github.com/http-party/node-http-proxy/commit/9ab8749a9bec33b49c495975e8364336ad7be1a3) +- [test] testing the onResponse proxy method [`27df8d7`](https://github.com/http-party/node-http-proxy/commit/27df8d72ad86d02cfce00a6e5c183d93dd50f97e) +- [docs] Update readme with more how to [`ae0faef`](https://github.com/http-party/node-http-proxy/commit/ae0faef5aa0080d742a9740f9cb38bfd54b7d97e) +- [fix] remove duplicate [`10c0f11`](https://github.com/http-party/node-http-proxy/commit/10c0f11b68e39552051e508c7bf20d65d2d59177) +- [tests] add more tests [`cedc5c4`](https://github.com/http-party/node-http-proxy/commit/cedc5c4bd2059585e1222ec4f03f09e8bcc808fc) +- [tests] added test for socket.io proxying [`10a0db4`](https://github.com/http-party/node-http-proxy/commit/10a0db4f0dd4594839f9098b9d67130085a067bc) +- [tests] added test HTTPS to HTTP using own server [`bbe3bfd`](https://github.com/http-party/node-http-proxy/commit/bbe3bfdf98255b82a185a798ff9f29e74615b6ca) +- [fix] quote [`c4ddc4e`](https://github.com/http-party/node-http-proxy/commit/c4ddc4edd324d9910a11eea14561a0e3b953f29c) +- [examples] update the error-handling example using the new error handle way [`a1b25a1`](https://github.com/http-party/node-http-proxy/commit/a1b25a123b4ff71e731f9beb27c5e078acfead65) +- ENH: updated README and added examples file. [`07091b5`](https://github.com/http-party/node-http-proxy/commit/07091b5077a40dfee29f6fd33ecb38d3fa25b801) +- [test] passes/web.js (first 2 funcs) [`d40e4be`](https://github.com/http-party/node-http-proxy/commit/d40e4beb62381b962b6cf3254451de0a39f182b1) +- [test] add test for forwardstream [`8fc3389`](https://github.com/http-party/node-http-proxy/commit/8fc33893672d26013c2b2ff396b777bcf1751527) +- [tests] fixing tests, fixed some typos and changed how passes are stored [`a704213`](https://github.com/http-party/node-http-proxy/commit/a7042132c881656dd32f915d9b0b962f0ef92efb) +- [test] added the lib/caronte/streams/forward.js initial test, one test pending [`2fac7b9`](https://github.com/http-party/node-http-proxy/commit/2fac7b9b009b12a940efb22de3af6db55ee686a9) +- [api] add draft for proxystream [`4f24664`](https://github.com/http-party/node-http-proxy/commit/4f24664e8a50aa9b9a3ea155d067b85f94a8c81b) +- [experiment] new api for proxying [`07cfa6b`](https://github.com/http-party/node-http-proxy/commit/07cfa6b981ff54d8d96eea6c9aa4b560ee3867ec) +- [tests] the options got a problem and this test probe that timeout is not being set [`1d1ee88`](https://github.com/http-party/node-http-proxy/commit/1d1ee8858283d7c8984f1c1d6c5185b6822f9235) +- new error propagation [`3a39e44`](https://github.com/http-party/node-http-proxy/commit/3a39e444ff68a74f6b586f0736bbd3f8a2511ca5) +- [examples] added concurrent proxy example [`04c1011`](https://github.com/http-party/node-http-proxy/commit/04c10113f7a3b568fb95b18f30e4aca3e059d961) +- [fix] docs [`ec981c5`](https://github.com/http-party/node-http-proxy/commit/ec981c5b74bf43dd36c8ca89833b751f59f01d38) +- [test] started writing tests [`16eacfa`](https://github.com/http-party/node-http-proxy/commit/16eacfa961d2a2d80534e95eba83010ed6ab01b4) +- [fix] closes number #487 [`cde08fb`](https://github.com/http-party/node-http-proxy/commit/cde08fb2ee2df03c9457678d8e6776a5d89165b2) +- [tests] added tests for websockets [`02007ed`](https://github.com/http-party/node-http-proxy/commit/02007ed0fb38f798436ae5669bb18d4f27496667) +- [examples] added forward example [`7a3f6df`](https://github.com/http-party/node-http-proxy/commit/7a3f6dfbcc80ba32fa81004438c637e8d29eb029) +- [fix] fixed options and server reference to can access them from passes functions [`90fb01d`](https://github.com/http-party/node-http-proxy/commit/90fb01d38ac5af7ef395547b24e985b6f63b4abc) +- mm test file [`1a7bef0`](https://github.com/http-party/node-http-proxy/commit/1a7bef0cda58243416a263075dc6eb51f22b6dec) +- Revert "[fix] fixed options and server reference to can access them from passes functions" [`babdf53`](https://github.com/http-party/node-http-proxy/commit/babdf531fecd32f9af0963902909fcfa2cd374f1) +- [docs] add UPGRADING.md [`db12f6c`](https://github.com/http-party/node-http-proxy/commit/db12f6c24e22c034c698457cc28ff60c990b55a5) +- DOC: Added error handling example [`32a4088`](https://github.com/http-party/node-http-proxy/commit/32a40889cedfd6b0d92224aa921700a7b7271c68) +- [test] test onError part, proxying to no where [`b85aa16`](https://github.com/http-party/node-http-proxy/commit/b85aa16e75401a223a947cde444d42cf7eeafb67) +- ENH: updated agent options in `common.setupOutgoing` [`12cda56`](https://github.com/http-party/node-http-proxy/commit/12cda561afe534427a5f84da9d7e0beb64a8ecbc) +- [fix] minor and short fixes [`e0faaaf`](https://github.com/http-party/node-http-proxy/commit/e0faaaf81152203b96f0313c68706468e7ee7357) +- support websockets [`4a4607d`](https://github.com/http-party/node-http-proxy/commit/4a4607d075a912746386d1751fd6b0fc98cf6b20) +- [test] COVERAGE [`004a46c`](https://github.com/http-party/node-http-proxy/commit/004a46c09df2f0f7b15d8e8f7119bc6039e0c01c) +- [misc] add a LICENSE file [`584ce76`](https://github.com/http-party/node-http-proxy/commit/584ce76e7576c906e25cdd04a2e079f97bcf86ff) +- ENH: updated https and agent option [`13741a8`](https://github.com/http-party/node-http-proxy/commit/13741a823f1c1c884d4a37e597e4b188598b0e25) +- [fix] write connection header [`2c10f25`](https://github.com/http-party/node-http-proxy/commit/2c10f256b658bc0e906c20f29d94ab7eaf653055) +- [fix] merge #495, thanks @glasser [`d0862af`](https://github.com/http-party/node-http-proxy/commit/d0862aff0c693366dcb11649b6abe1d011268953) +- support forward [`8c8c455`](https://github.com/http-party/node-http-proxy/commit/8c8c455541f21ad9a9ac7ca19d1f37368206a2e2) +- [tests] fix tests set correct host headers [`cfd417d`](https://github.com/http-party/node-http-proxy/commit/cfd417de2352b0f05535b979dc15abff60c1fb96) +- [fix] Optimize fix for `x-forwarded-for-port`. [`2d42709`](https://github.com/http-party/node-http-proxy/commit/2d42709c3283637de16a49e815b03e63432bbd29) +- ENH: updated readme with an example [`edd8e2f`](https://github.com/http-party/node-http-proxy/commit/edd8e2f04e4b39391b062fa6437d61b4ebde8748) +- [doc] update README.md [`dcb873a`](https://github.com/http-party/node-http-proxy/commit/dcb873ad9992b1534615d59b8a0a70e8b87d7884) +- [test] passes/web.js XHeaders func [`c02b721`](https://github.com/http-party/node-http-proxy/commit/c02b721321c455bc287c3fed6b9b21392ce2fc70) +- [fix] fixed passes functions, now 'this' can be used and options are stored on 'this.options' [`9b3e1eb`](https://github.com/http-party/node-http-proxy/commit/9b3e1eb247df29d18ea299ff4ebb2f10eeb71269) +- Revert "[fix] fixed passes functions, now 'this' can be used and options are stored on 'this.options'" [`5e130de`](https://github.com/http-party/node-http-proxy/commit/5e130de8548ad41b821da49299b4fd1c9536c5f0) +- [minor] Remove duplicate dependencies and cleanup of the scripts [`a51b062`](https://github.com/http-party/node-http-proxy/commit/a51b0622780f48160001f9e74340f7d720cbfce6) +- TEST: added agent and header tests [`39b0c46`](https://github.com/http-party/node-http-proxy/commit/39b0c46a6967fda5329760ad93a8ec01bc4a6f14) +- [examples] fix styling and bad spaces [`6a6dfbb`](https://github.com/http-party/node-http-proxy/commit/6a6dfbb79dc156679f75dd519344d19a5b61613b) +- ENH: added error events [`1b867a7`](https://github.com/http-party/node-http-proxy/commit/1b867a7f594f7dfe49fc17ff53451a353ec509d9) +- [test] remove chunked on http1.0 [`ca09263`](https://github.com/http-party/node-http-proxy/commit/ca092635e7ac4d967b554e3b94a16a931946d464) +- [tests] fix test to use the new way to pass options [`52ecd52`](https://github.com/http-party/node-http-proxy/commit/52ecd52ee5aa78603e44ba8d5ff9187410351622) +- [examples] fixed https examples [`a467b7b`](https://github.com/http-party/node-http-proxy/commit/a467b7b4a9614a7cbfdc256524e1495616e3d4d9) +- Revert "[tests] fix test to use the new way to pass options" [`2bf20d6`](https://github.com/http-party/node-http-proxy/commit/2bf20d61d53201e9820c5f9215e641fcf88f5172) +- [fix] better code [`3d8e538`](https://github.com/http-party/node-http-proxy/commit/3d8e5383cd9d527825f95d9071a87865fcebca05) +- [feature] implement _write and _read [`6a4294c`](https://github.com/http-party/node-http-proxy/commit/6a4294cbdfe85fa162969b1393032adc9d418441) +- [fix] use the correct arguments order [`cc09ae6`](https://github.com/http-party/node-http-proxy/commit/cc09ae6a345cfde1689e1d8731c5822675c59d4d) +- [fix] fix the correct order of arguments in ws-incoming passes [`02df9a3`](https://github.com/http-party/node-http-proxy/commit/02df9a33c5cce17ea32a892017acbe5ce57ab2e5) +- [fix] write status [`e08d4ed`](https://github.com/http-party/node-http-proxy/commit/e08d4edad339d0f7f55900b3e6e6a0e770960215) +- [fix] finished jshint fixes [`455f97e`](https://github.com/http-party/node-http-proxy/commit/455f97e14cb4929e0a3a5c746471e9c5e76436fc) +- Update the README to describe middleware err handler. [`25bb3bf`](https://github.com/http-party/node-http-proxy/commit/25bb3bfa7012e0f975e10f0311cae8c39183fa41) +- Prevent headers to be sent twice [`8332e74`](https://github.com/http-party/node-http-proxy/commit/8332e744202ed9de94288d8f1c822cd9fe788983) +- [examples] added package.json with the dependencies needed by examples [`d85ccdd`](https://github.com/http-party/node-http-proxy/commit/d85ccdd333edcfc7551bcf8e0ffd7dc166e38e61) +- [tests] added .travis.yml file [`0602500`](https://github.com/http-party/node-http-proxy/commit/06025002303f351f71d9e5f78a93895257f0d283) +- [dist minor] 2 space indents next time @samalba [`7e8041d`](https://github.com/http-party/node-http-proxy/commit/7e8041d2b687b8375a1d0fe45270029c6e8ddee6) +- [fix] naming [`8931009`](https://github.com/http-party/node-http-proxy/commit/893100972c22febbf133134394bc0bcef47d9e12) +- Fix for #458. Host header may cause some sites not to be proxyable with changeOrigin enabled [`781c038`](https://github.com/http-party/node-http-proxy/commit/781c038f2b4d14a01cc9297e1e0dba6ce39dd6cb) +- [docs] typos, typos everywhere... [`03880d8`](https://github.com/http-party/node-http-proxy/commit/03880d8d069e9e17ca7d7aea6eb760f6626a869c) +- ENH: updated `ws` and `web` functions to use the global options object as a base [`268afe3`](https://github.com/http-party/node-http-proxy/commit/268afe34bb51448d511c9cd73c03e97d1c1baee0) +- [fix] make @mmalecki a happy camper [`c9cd6d2`](https://github.com/http-party/node-http-proxy/commit/c9cd6d2ad324e0e6222932c8f29f27621071e045) +- write [`f97c0c6`](https://github.com/http-party/node-http-proxy/commit/f97c0c6167371c5ff92e6361b1df02e3fd5506d7) +- [fix] [`a9f9e21`](https://github.com/http-party/node-http-proxy/commit/a9f9e21eda2f8e912523e6b62abb0101c0353505) +- [fix] coveralls.. will it work? [`f36cb4d`](https://github.com/http-party/node-http-proxy/commit/f36cb4d5a110fc86272e878278f103f313c86f56) +- ENH: updated target and forward options so that a string may be specified [`ef946a7`](https://github.com/http-party/node-http-proxy/commit/ef946a7697b38b13178881b3d1ebde63681dd4a1) +- added option for eventlistenerCount(max) [`8eb6780`](https://github.com/http-party/node-http-proxy/commit/8eb6780f8705caff13a5375446539b0621d497d7) +- [fix] support buffer [`1204a35`](https://github.com/http-party/node-http-proxy/commit/1204a35e467c6c1855ba0dac8f55d79f899148a6) +- DOC: updated readme with options [`1b5fb1d`](https://github.com/http-party/node-http-proxy/commit/1b5fb1d8fc21421b8383919d93e4149b586b211b) +- ENH: added 'headers' to available options, to add or overwrite existing headers [`7d840d3`](https://github.com/http-party/node-http-proxy/commit/7d840d35151be1aac612798754af47368594781d) +- [fix] move logo [`57abb7f`](https://github.com/http-party/node-http-proxy/commit/57abb7f26c14e281c3be07a8b84e3c79e066f59f) +- FIX: tests. still need to add more tests tho [`a350fad`](https://github.com/http-party/node-http-proxy/commit/a350fadea6bace293131581487f8c66948009449) +- [fix] move logo [`aaff196`](https://github.com/http-party/node-http-proxy/commit/aaff1966e4e2eb42c9890e57737f57a64e8d964a) +- [docs] add travis build status [`6b61878`](https://github.com/http-party/node-http-proxy/commit/6b618787598a2a37850898dbdb3b4fe8f3c3414d) +- [fix] do not send chunked responses to http1.0 clients [`8663ac1`](https://github.com/http-party/node-http-proxy/commit/8663ac1c43505f0081d906c3cd8e702d4b5ddeb0) +- [dist] Bump dependencies. [`a81dd8d`](https://github.com/http-party/node-http-proxy/commit/a81dd8d53e1595cba9acf5cc3ca9517165dcc4aa) +- [fix] readme [`4d3a4e1`](https://github.com/http-party/node-http-proxy/commit/4d3a4e1ee7370347898d1863ab73aa68ed345d8d) +- [fix] proxying to https [`26c4c43`](https://github.com/http-party/node-http-proxy/commit/26c4c43a06263ec6721bc0e8a90644297d0cf217) +- [fix] new logo [`ee3cc38`](https://github.com/http-party/node-http-proxy/commit/ee3cc380665a31ec6af28ddb73dfc543f430d3f8) +- [fix] naming convention [`7d71a86`](https://github.com/http-party/node-http-proxy/commit/7d71a867a8bdc375f7577cec3905cca89bbf415c) +- fix docs [`9243444`](https://github.com/http-party/node-http-proxy/commit/9243444ac006f73c00b0f1f78c4a77f342b0b4e4) +- [fix] short circuit [`a6256ca`](https://github.com/http-party/node-http-proxy/commit/a6256cac1df1739e3da78fe5f0cf122ef7ce6b14) +- [tests] this test is already in web-incoming tests [`920f1e7`](https://github.com/http-party/node-http-proxy/commit/920f1e7707aa1751577533cd368529f8a704d7af) +- Emit middlewareError when on middleware error. [`bc12ca3`](https://github.com/http-party/node-http-proxy/commit/bc12ca39394f9aeed3e3047f59035ba48afa2885) +- DOC: updated readme [`7ad5c0f`](https://github.com/http-party/node-http-proxy/commit/7ad5c0f993294c9e2e7650e15fbc62d11a2cb062) +- [docs] add logo [`8b05626`](https://github.com/http-party/node-http-proxy/commit/8b05626eed5e45e72cf9b1f14a4c4dca1dd2ed0f) +- [fix] making @stoke a happy camper [`34f16e7`](https://github.com/http-party/node-http-proxy/commit/34f16e74647095199f84ab61e10c8dafd60b505a) +- [feature] add buffer support [`e3f8d5f`](https://github.com/http-party/node-http-proxy/commit/e3f8d5fdbe1ebc4f04188d95bbef768d09718d2c) +- [Fix] 2 spelling mistakes [`5823842`](https://github.com/http-party/node-http-proxy/commit/58238421945bcc4236e280ebca7799b831ae29a4) +- [fix] do not call .end [`6e77cd3`](https://github.com/http-party/node-http-proxy/commit/6e77cd390929842088ae9f6deb922a6627ddfecd) +- attempting to fix link to valid options properties [`bbe2b27`](https://github.com/http-party/node-http-proxy/commit/bbe2b2788a7ee3c74fd44fe88b6dcf213264436f) +- [fix] slimmer proxying [`031aa0f`](https://github.com/http-party/node-http-proxy/commit/031aa0fbf30bd377696c4efa508f6fc769bf1070) +- [fix] use agent pool [`abf1d90`](https://github.com/http-party/node-http-proxy/commit/abf1d90fdf05a17ebe05a3e90d464a592e0aee69) +- [tests] fix test using undefined url [`c4d56a5`](https://github.com/http-party/node-http-proxy/commit/c4d56a5faf1e89cdeb911f0ece0efe065eb58c45) +- [fix] legacy [`162a42f`](https://github.com/http-party/node-http-proxy/commit/162a42f58f515c5418ccfac0b68f4c928103b1e1) +- [tests] fixing minor typos [`b333e63`](https://github.com/http-party/node-http-proxy/commit/b333e63648aa67ea1b1aaf17ba684e5fc6f751a6) +- Updated readme [`bd106d6`](https://github.com/http-party/node-http-proxy/commit/bd106d69f074a1c7018e685a4e144e23a17beb8c) +- [misc] use the local mocha instead the global [`f1aeb05`](https://github.com/http-party/node-http-proxy/commit/f1aeb0500cde39b63e570323e0e478530d1222ab) +- added unlimited listeners to the reverproxy event obj. [`1333c0c`](https://github.com/http-party/node-http-proxy/commit/1333c0cc62e7b590843f9b00326fe80137163c5e) +- [tests] throw error when no options, ALL TESTS PASSING! YAY [`86750c7`](https://github.com/http-party/node-http-proxy/commit/86750c7e594c419dfae957aaf7e44e61e1d480e8) +- ENH: updated example [`1c7ace2`](https://github.com/http-party/node-http-proxy/commit/1c7ace26c5a36fb63497f1ab67793c5b75495063) +- [merge] PR #470 [`38e6d7c`](https://github.com/http-party/node-http-proxy/commit/38e6d7cd5449a7264dcf5244b3dfd07b2dda60e1) +- [fix] remove stuff [`6a03e5f`](https://github.com/http-party/node-http-proxy/commit/6a03e5f7cf356416ea13584e279f5bfa3791c058) +- [test][misc] remove node@0.8 to test on travis [`8eff1a1`](https://github.com/http-party/node-http-proxy/commit/8eff1a1f26bb739dfc5a1ad90b140ff2a18921d5) +- merge with @cronopio [`0fb3381`](https://github.com/http-party/node-http-proxy/commit/0fb33810f5e70b714bd9868557d85a531b8e11e3) +- [merge] text [`98f29bd`](https://github.com/http-party/node-http-proxy/commit/98f29bdcfca9b818ffe107b09578539fdf379c8a) +- [fix] woops [`bd3df45`](https://github.com/http-party/node-http-proxy/commit/bd3df45010f282997cae3a699c7ecb885c01bdf8) +- [test] Test on newer version of node [`ebbba73`](https://github.com/http-party/node-http-proxy/commit/ebbba73eda49563ade09f38bdc8aef13d1cf6c00) +- new error propagation - follows [`1993faf`](https://github.com/http-party/node-http-proxy/commit/1993faf8a4227acda3423d46cf2cf13b4d9861e7) +- [fix] minor typo [`5a1504f`](https://github.com/http-party/node-http-proxy/commit/5a1504f0764b7747b53cc0d92a69ff3093e85ade) +- [fix] proxy to http(s) [`3c91ed3`](https://github.com/http-party/node-http-proxy/commit/3c91ed3d26d9af640d0c7a09fb9cdaf80ad673ca) +- Put the arguments the right way around in the README. [`1457980`](https://github.com/http-party/node-http-proxy/commit/145798062e332ac2aed7f8e8e3240e38464c870a) +- [fix] use some [`4480699`](https://github.com/http-party/node-http-proxy/commit/4480699d3a2a5080c051e7b8a100689fd1f58657) +- [fix] layout [`d7078e2`](https://github.com/http-party/node-http-proxy/commit/d7078e2fdd16d23d0b5f8f1d8a7ab3e9011fea4f) +- [docs] logo [`dd0f7b8`](https://github.com/http-party/node-http-proxy/commit/dd0f7b8876ae5b57fffab8857735b25b159f2bdb) +- [fix] url [`0637322`](https://github.com/http-party/node-http-proxy/commit/0637322d96e54bbcf5a14bf009dd73314cada4ce) +- [fix] opts [`adc5be0`](https://github.com/http-party/node-http-proxy/commit/adc5be020c7fff09a1c05ac771d5c5ab61002c23) +- [docs] fix syntax highlighting [`da9de70`](https://github.com/http-party/node-http-proxy/commit/da9de7034a452d1281217a349bc9403fddcc2b7f) +- [fix] typo [`275a519`](https://github.com/http-party/node-http-proxy/commit/275a5192fa257f78287a954b347e65023795487d) +- [tests] fix code coverage, changed pattern on blanket options [`4090250`](https://github.com/http-party/node-http-proxy/commit/40902506af3361b642b8798350b48404fe0a4e78) +- Put the arguments the right way around in emitter. [`7c8ecc8`](https://github.com/http-party/node-http-proxy/commit/7c8ecc8ea85b59fc16b55b9a142372b6ac168b2a) +- [fix] link [`72a89ea`](https://github.com/http-party/node-http-proxy/commit/72a89eab8bafef3742d78e8de8631094f961f427) +- [fix] space [`69f126b`](https://github.com/http-party/node-http-proxy/commit/69f126b34cbd190be8541a854d21f13bfb5a61bf) +- [fix] tests [`8269eca`](https://github.com/http-party/node-http-proxy/commit/8269eca2bb34d08336b8889e06e53d3522fa79fe) +- [fix] console [`18341d5`](https://github.com/http-party/node-http-proxy/commit/18341d559717e0a86f5ee4da024109e4b5a595a7) +- Set travis to run `npm test` while we fix coveralss.io integration [`e2a5d51`](https://github.com/http-party/node-http-proxy/commit/e2a5d513cac3ebceff446787fa106c7f00caf785) +- [fix] making @jcrugzz a happy camper [`2e7343d`](https://github.com/http-party/node-http-proxy/commit/2e7343d728a3187d48821b88ec2e2d4699bb2afe) +- [fix] minor typo [`5d66ce1`](https://github.com/http-party/node-http-proxy/commit/5d66ce11bb7eef7e704a2de2c0ef3b5f754843e9) +- [tests] tests fixed [`d60353f`](https://github.com/http-party/node-http-proxy/commit/d60353f80bbbcba128a2c51066e107365270e878) +- [tests] disabled the examples-test by now [`d83fdf6`](https://github.com/http-party/node-http-proxy/commit/d83fdf69a1121bfcfba72bbffcd3105ae5852c56) +- [fix] _ because it is unused [`590bb60`](https://github.com/http-party/node-http-proxy/commit/590bb604dae11223a0ae80469b59d6d341488f1f) +- [tests] disable test, by now is not throwing without options [`a2b1f0a`](https://github.com/http-party/node-http-proxy/commit/a2b1f0a4c9079342db6255c5f92db4a0cb992707) +- [fix] support target and forward [`961d2f9`](https://github.com/http-party/node-http-proxy/commit/961d2f9400b4cfd236c3c8ccbf401d37f8e871b8) +- [dist] Version bump. 0.10.4 [`840f6d8`](https://github.com/http-party/node-http-proxy/commit/840f6d8d29dffc11d3726123c2d400940ca2bdda) +- [fix] remove old reminescence [`4d65280`](https://github.com/http-party/node-http-proxy/commit/4d65280ea313438a94589bacf55f7a09cc107888) +- [feature] add emit proxyRes [`dda6f7a`](https://github.com/http-party/node-http-proxy/commit/dda6f7a45a46d2bf63e482d0b47b7c36ae548546) +- [docs] test badge [`1ceea3e`](https://github.com/http-party/node-http-proxy/commit/1ceea3e5f9b6232d60d673946bbccb7d8ccb4beb) +- [tests] remove caronte and use http-proxy for file names [`c9f5772`](https://github.com/http-party/node-http-proxy/commit/c9f5772fc18226aca31471bc96c44a6dbff5cbea) +- [logo] [`4c2f2f3`](https://github.com/http-party/node-http-proxy/commit/4c2f2f3b9a5ba65f97403e778a670f14301d52c1) + +## [v0.10.3](https://github.com/http-party/node-http-proxy/compare/v0.10.2...v0.10.3) - 2013-06-20 + +### Merged + +- Pass default certs to SNICallback example [`#419`](https://github.com/http-party/node-http-proxy/pull/419) + +### Fixed + +- Pass default certs to SNICallback example [`#399`](https://github.com/http-party/node-http-proxy/issues/399) + +### Commits + +- [dist] Bump version to 0.10.3 [`2fd748f`](https://github.com/http-party/node-http-proxy/commit/2fd748fb61dac7de0daa50aabbface7033c6a222) +- [fix] Respect `maxSockets` from `target` options in `RoutingProxy` [`e1d384e`](https://github.com/http-party/node-http-proxy/commit/e1d384e769e9f4adc5a06c516cfb721ff24b4b6d) +- Send path in req.path and not the url [`0c75323`](https://github.com/http-party/node-http-proxy/commit/0c753234c0c85333f909bdbef034ffb6e192bad5) + +## [v0.10.2](https://github.com/http-party/node-http-proxy/compare/v0.10.1...v0.10.2) - 2013-04-21 + +### Merged + +- Correct keep-alive responses to HTTP 1.0 clients [`#407`](https://github.com/http-party/node-http-proxy/pull/407) + +### Fixed + +- [minor] Style compliance. Fixes #402. [`#402`](https://github.com/http-party/node-http-proxy/issues/402) + +### Commits + +- Correct keep-alive responses to HTTP 1.0 clients. [`a29b5e8`](https://github.com/http-party/node-http-proxy/commit/a29b5e8e289c34c00d2b450e5fb9dd1969db4b97) +- [minor] Strip trailing whitespace. [`7fc39d7`](https://github.com/http-party/node-http-proxy/commit/7fc39d77f47311b82c24ab05f8e1a45a2733305c) +- Add headers on 'handshake' [`985025c`](https://github.com/http-party/node-http-proxy/commit/985025c90f3b2fafede64d8b17c318326f2423d9) +- Don't test raw HTTP 1.0 requests over HTTPS. [`daf53bd`](https://github.com/http-party/node-http-proxy/commit/daf53bd753879223dc84a49c92d0efaf576c1fd3) +- [dist] Version bump. 0.10.2 [`de0928f`](https://github.com/http-party/node-http-proxy/commit/de0928f616dd62165e8a22c00d091cabf31e1e87) + +## [v0.10.1](https://github.com/http-party/node-http-proxy/compare/v0.10.0...v0.10.1) - 2013-04-12 + +### Merged + +- Fix for slab buffer retention, leading to large memory consumption [`#370`](https://github.com/http-party/node-http-proxy/pull/370) + +### Commits + +- [dist] Version bump. 0.10.1 [`9c13ad4`](https://github.com/http-party/node-http-proxy/commit/9c13ad46e416125373d6604f3954ec3df1f55449) + +## [v0.10.0](https://github.com/http-party/node-http-proxy/compare/v0.9.1...v0.10.0) - 2013-03-18 + +### Merged + +- Change the emitter of the `proxyResponse` event [`#385`](https://github.com/http-party/node-http-proxy/pull/385) +- Fixing a bug that generates an unexpected TypeError [`#383`](https://github.com/http-party/node-http-proxy/pull/383) +- Mention Harmon used for response modifications in the readme [`#384`](https://github.com/http-party/node-http-proxy/pull/384) + +### Commits + +- [dist] Update CHANGELOG.md [`8665f3c`](https://github.com/http-party/node-http-proxy/commit/8665f3cc600feecbb4c8229699823149c69a144f) +- Harmon messsage [`35ba0db`](https://github.com/http-party/node-http-proxy/commit/35ba0db554c6bace21b1bacfa8f5fb6df4228db0) +- [fix breaking] Emit the `proxyResponse` event on the HttpProxy instance to reduce listener churn and reference counts. [`2620f06`](https://github.com/http-party/node-http-proxy/commit/2620f06e2db9a267945566f10837c4c2a5df753d) +- [dist] Version bump. 0.10.0 [`71183bf`](https://github.com/http-party/node-http-proxy/commit/71183bf30bc2b9ad2eaf57c51980eeb0bc7edff0) +- Fixing the if statement as it lead to 'TypeError: Parameter 'url' must be a string, not undefined' in certain cases [`c9b6895`](https://github.com/http-party/node-http-proxy/commit/c9b6895c5e14add6aba4f826a2173458a1896a5f) +- Harmon messsage [`4e42354`](https://github.com/http-party/node-http-proxy/commit/4e42354e77d5731a383d516fc0b249d5d0eda745) + +## [v0.9.1](https://github.com/http-party/node-http-proxy/compare/v0.9.0...v0.9.1) - 2013-03-09 + +### Commits + +- [dist doc] Updated CHANGELOG.md for `v0.9.1` [`ea5e214`](https://github.com/http-party/node-http-proxy/commit/ea5e214522d8ac34d1129b28ff188c0f232ce63f) +- [dist] Version bump. 0.9.1 [`701dc69`](https://github.com/http-party/node-http-proxy/commit/701dc698e3eb39ca6836a02611d8dce750f4e212) +- [breaking] Ensure that `webSocketProxyError` also receives the error to be consistent with `proxyError` events. [`c78356e`](https://github.com/http-party/node-http-proxy/commit/c78356e9cf27a21c57e4c98ef7dd3c22abe864c2) + +## [v0.9.0](https://github.com/http-party/node-http-proxy/compare/v0.8.7...v0.9.0) - 2013-03-09 + +### Merged + +- If HTTP 1.1 is used and backend doesn't return 'Connection' header, expicitly return Connection: keep-alive. [`#298`](https://github.com/http-party/node-http-proxy/pull/298) +- add "with custom server logic" to the "Proxying WebSockets" section of the readme [`#332`](https://github.com/http-party/node-http-proxy/pull/332) +- routing proxy 'this' reference bug? [`#365`](https://github.com/http-party/node-http-proxy/pull/365) +- fixed issue #364 'proxyError' event emitted twice [`#374`](https://github.com/http-party/node-http-proxy/pull/374) +- Misleading documentation for Websockets via .createServer [`#349`](https://github.com/http-party/node-http-proxy/pull/349) + +### Fixed + +- [api test] Manually merge #195 from @tglines since that fork was deleted. Update tests to use new macros. Fixes #195. Fixes #60. [`#195`](https://github.com/http-party/node-http-proxy/issues/195) [`#60`](https://github.com/http-party/node-http-proxy/issues/60) +- [fix] Set "content-length" header to "0" if it is not already set on DELETE requests. Fixes #338. [`#338`](https://github.com/http-party/node-http-proxy/issues/338) +- [fix] Do not use "Transfer-Encoding: chunked" header for proxied DELETE requests with no "Content-Length" header. Fixes #373. [`#373`](https://github.com/http-party/node-http-proxy/issues/373) +- [fix] http-proxy should not modify the protocol in redirect request for external sites. Fixes #359. [`#359`](https://github.com/http-party/node-http-proxy/issues/359) +- [fix] Emit `notFound` event when ProxyTable location does not exist. Fixes #355. Fixes #333. [`#355`](https://github.com/http-party/node-http-proxy/issues/355) [`#333`](https://github.com/http-party/node-http-proxy/issues/333) +- [fix] Make options immutable in `RoutingProxy`. Fixes #248. [`#248`](https://github.com/http-party/node-http-proxy/issues/248) +- [fix] Remove special case handling of `304` responses since it was fixed in 182dcd3. Fixes #322. [`#322`](https://github.com/http-party/node-http-proxy/issues/322) +- [fix] Ensure `response.headers.location` is defined. Fixes #276. [`#276`](https://github.com/http-party/node-http-proxy/issues/276) + +### Commits + +- [minor] s/function(/function (/ s/){/) {/ [`9cecd97`](https://github.com/http-party/node-http-proxy/commit/9cecd97153ccce4f81c5eda35a49079e651fb27a) +- working on x-forwarded-for [`1332409`](https://github.com/http-party/node-http-proxy/commit/133240937dc63aca0007388327837bc24808f79a) +- Routing Proxy was not sending x-forward-*. Fixing It... [`916d44e`](https://github.com/http-party/node-http-proxy/commit/916d44e3d2a17bb9d5178f347ddad9796b988e05) +- Added timeout option and test to test new timeout parameter, added requestFail assertion. [`89d43c2`](https://github.com/http-party/node-http-proxy/commit/89d43c20dd0dec1dda1fd70e57f3f250b9e3b431) +- Add tests for headers bug fixes [`ecb5472`](https://github.com/http-party/node-http-proxy/commit/ecb547223f3f1d9bf551842c2026ee2f1a18638a) +- Added simple round robin example with websocket support [`83fbd42`](https://github.com/http-party/node-http-proxy/commit/83fbd4250660f41de1ab2b5490a3bf58200ae148) +- - support unix donain sockets and windows named pipes (socketPath) on node 0.8.x. On node 0.6.x the support was opaque via port, but on the new node, socketPath should be set explicitely. [`ffe74ed`](https://github.com/http-party/node-http-proxy/commit/ffe74ed299f81206b898147dbcc985519b2921f8) +- pathnameOnly flag added. Ignores hostname and applies routing table to the paths being requested. [`46b078a`](https://github.com/http-party/node-http-proxy/commit/46b078a98d10de7726a3bbca89121acc57ad7625) +- [doc] added comments to pathnameOnly block. [`5e6be6c`](https://github.com/http-party/node-http-proxy/commit/5e6be6ccf5a39ff450e57d7b24e374a83569fa85) +- remove offending code, final fix for issue #364 [`3b84e27`](https://github.com/http-party/node-http-proxy/commit/3b84e27ab4efd5ce3b8ac837d699d4ff6661c7e7) +- memory leak fix in closing of the scokets [`2055d0c`](https://github.com/http-party/node-http-proxy/commit/2055d0c8ec16699ffb06adf6d64d9506920b2071) +- Fix truncated chunked responses [`ef66833`](https://github.com/http-party/node-http-proxy/commit/ef66833c4d7f07ae9f42026f2bcc0fbca2440579) +- Re-added previous description [`603106a`](https://github.com/http-party/node-http-proxy/commit/603106a13d28c0199fa4456cc9aee1692eb2588c) +- pathnameOnly option documented in the Readme.md [`a1607c1`](https://github.com/http-party/node-http-proxy/commit/a1607c1684a7d7617e5148a0dca882eb08a9f03b) +- [fix minor] Prevent crashes from attempting to remove listeners more than once when proxying websocket requests. [`a681493`](https://github.com/http-party/node-http-proxy/commit/a681493371ae63f026e869bf58b6fea682dc5de3) +- Added comments [`64efa7f`](https://github.com/http-party/node-http-proxy/commit/64efa7f9291a2377a32e942a247700b71b107993) +- Revert "[fix minor] Prevent crashes from attempting to remove listeners more than once when proxying websocket requests." [`c6da760`](https://github.com/http-party/node-http-proxy/commit/c6da760ca9f375025229fe3fc174aca943362f38) +- [doc dist] Update CHANGELOG.md for `v0.9.0`. [`133115c`](https://github.com/http-party/node-http-proxy/commit/133115c9760130dcef447efbd18c470c08795c90) +- add support for loading CA bundles [`10f6b05`](https://github.com/http-party/node-http-proxy/commit/10f6b0577518bdfcb6b43c1f516dc988bdcade53) +- problem: don't want to run my server as root to bind to privileged ports (e.g. 80, 443). [`2c36507`](https://github.com/http-party/node-http-proxy/commit/2c3650746cd90fed63b140a8d393e18bd35cd8f9) +- Add 'proxyResponse' event so observer can modify response headers or abort response. [`3b86a7a`](https://github.com/http-party/node-http-proxy/commit/3b86a7aae3fc366c5fa8645285a4368dbac7a0dc) +- [minor] Move private helper to end of file. [`476cbe7`](https://github.com/http-party/node-http-proxy/commit/476cbe741fc41b7f1eb269d841d922784e8b3c6b) +- Fix for retaining large slab buffers in node core [`d2888c8`](https://github.com/http-party/node-http-proxy/commit/d2888c83f5eab3fb82425ef4fd51e62621bf2764) +- [dist] Update `devDependencies` [`ad21310`](https://github.com/http-party/node-http-proxy/commit/ad213106d06cfc79004841f04b8e73fe7d7ef67a) +- [minor] Small whitespace compliance. [`ea0587a`](https://github.com/http-party/node-http-proxy/commit/ea0587a8f98b1eedc38c66b69293ae091e24be6e) +- [doc fix] Add undefined var in example. [`deca756`](https://github.com/http-party/node-http-proxy/commit/deca7565c51fd678354d26eaae7fe2481e36e2c3) +- working on x-forwarded-for [`31fc94a`](https://github.com/http-party/node-http-proxy/commit/31fc94aa5e43c54033d5384caaf104eebf3889bd) +- Allow event observers to access upstream response headers and data. [`4c130f5`](https://github.com/http-party/node-http-proxy/commit/4c130f5dac5f2cfbfc2618446b86244aff4cb04f) +- [fix doc] Fix bad variable reference in `README.md`. [`440013c`](https://github.com/http-party/node-http-proxy/commit/440013c263a96c6681bfe92a8f56db93b58efa8d) +- Change wording for handling websocket proxy events [`ee6bbe0`](https://github.com/http-party/node-http-proxy/commit/ee6bbe00244c90bd532b11ff1c796aea8c7372f8) +- [dist] Version bump. 0.9.0 [`c68e038`](https://github.com/http-party/node-http-proxy/commit/c68e0389120d8530e578e20496d8ee091e69a580) +- fix 'this' reference in routing proxy listener bindings [`15afc23`](https://github.com/http-party/node-http-proxy/commit/15afc23a275f3fa16653fff6179368122661a0af) +- cleanning [`8d87399`](https://github.com/http-party/node-http-proxy/commit/8d8739999fcaf4cdd8f2471046f6f036c44dc8f7) +- cleanning [`9672b99`](https://github.com/http-party/node-http-proxy/commit/9672b9927156a0dfe3ce4539f380aaf3172f6267) +- Fix typo which slipped in during patch clean-up [`ba65a48`](https://github.com/http-party/node-http-proxy/commit/ba65a485fcf7230e85cee77f6eefcd17e46c8f86) +- Remove data event that is not needed after-all. [`b1c4bd6`](https://github.com/http-party/node-http-proxy/commit/b1c4bd61e8ae5705d4cc97bf719c381554671967) + +## [v0.8.7](https://github.com/http-party/node-http-proxy/compare/v0.8.6...v0.8.7) - 2012-12-22 + +### Commits + +- [fix] Handle errors on request object [`edfe869`](https://github.com/http-party/node-http-proxy/commit/edfe86915941e465a06c1d0a3330ee32e5834aa6) +- [dist] Bump version to 0.8.7 [`26d3646`](https://github.com/http-party/node-http-proxy/commit/26d3646ff252129f35525ab0540a31f5617a31d2) +- [fix] Don't remove `error` listener after response ends [`223eacd`](https://github.com/http-party/node-http-proxy/commit/223eacda85a4267f2860f6c46f7dedfa9db8c224) + +## [v0.8.6](https://github.com/http-party/node-http-proxy/compare/v0.8.5...v0.8.6) - 2012-12-21 + +### Merged + +- http-proxy: 304 responses should emit 'end' too [`#337`](https://github.com/http-party/node-http-proxy/pull/337) + +### Commits + +- [bench] Remove silly "benchmarks" [`2bd9cd9`](https://github.com/http-party/node-http-proxy/commit/2bd9cd9adb6cea6763930468d22cb56fffab6218) +- [bench] Add a benchmark for websockets throughput [`6797a27`](https://github.com/http-party/node-http-proxy/commit/6797a2705a309d19a655ab468bcc80ba2e43cf41) +- [fix] Handle socket errors [`2a61ec8`](https://github.com/http-party/node-http-proxy/commit/2a61ec85bdaeed9a5fca2a117efb36a7f76becc4) +- [dist] Update `devDependencies` [`b81d9b7`](https://github.com/http-party/node-http-proxy/commit/b81d9b71daa32a571384cff29d81227993299236) +- [dist] Bump version to 0.8.6 [`6cd78f6`](https://github.com/http-party/node-http-proxy/commit/6cd78f6af9ca08b8797c409896eea2ae6bb6d835) +- [bench] More exact size display [`7bc1a62`](https://github.com/http-party/node-http-proxy/commit/7bc1a628feab78f8931e9e6481737dd871debfeb) + +## [v0.8.5](https://github.com/http-party/node-http-proxy/compare/v0.8.4...v0.8.5) - 2012-11-16 + +### Merged + +- lib: allow overriding maxSockets [`#323`](https://github.com/http-party/node-http-proxy/pull/323) + +### Fixed + +- [fix] Convert strings to numbers if possible in `.createServer` [`#321`](https://github.com/http-party/node-http-proxy/issues/321) + +### Commits + +- [test] Delete invalid core test [`886a395`](https://github.com/http-party/node-http-proxy/commit/886a395429f20163992ca76e7b0d059256f56ba6) +- [test] Upgrade `common.js` from node core [`fefbf04`](https://github.com/http-party/node-http-proxy/commit/fefbf04ac03126858bdad07df7b10131a46e17d6) +- add "with custom server logic" to the "Proxying WebSockets" section of the readme.md [`03dbe11`](https://github.com/http-party/node-http-proxy/commit/03dbe115c2b088737e5b9abcadf91a8298f56f1f) +- [test] Kill child process when exiting test runner [`74ec175`](https://github.com/http-party/node-http-proxy/commit/74ec1757153c503ce57eb552031648fe79731d48) +- [fix] Correctly kill test processes [`b8c27ed`](https://github.com/http-party/node-http-proxy/commit/b8c27ed565e416827b7c4bb123aa9ee119d008e6) +- [test] Make global detection work with older node versions [`3531fd6`](https://github.com/http-party/node-http-proxy/commit/3531fd609a8ce156d27c27ca38ac912a73aebfeb) +- [dist] Bump version to 0.8.5 [`22639b3`](https://github.com/http-party/node-http-proxy/commit/22639b378189ec78f9962dde64337df050e29a6f) +- [test] Run core tests on `npm test` [`41c9a9c`](https://github.com/http-party/node-http-proxy/commit/41c9a9caad679221b8f1d4dcfb74f9b2bdb8270b) +- [test] Stop testing on `node v0.9`, tests timeout [`9042665`](https://github.com/http-party/node-http-proxy/commit/9042665ea98a6587e1d6800e51d3c354c0a1b20a) + +## [v0.8.4](https://github.com/http-party/node-http-proxy/compare/v0.8.2...v0.8.4) - 2012-10-23 + +### Merged + +- Events patch [`#320`](https://github.com/http-party/node-http-proxy/pull/320) +- documentation for options [`#315`](https://github.com/http-party/node-http-proxy/pull/315) +- Added travis build status [`#308`](https://github.com/http-party/node-http-proxy/pull/308) +- Fix installation instructions: s/http/https/ [`#302`](https://github.com/http-party/node-http-proxy/pull/302) +- If supplied pass changeOrigin option through to HttpProxy instance if set in RoutingProxy [`#285`](https://github.com/http-party/node-http-proxy/pull/285) + +### Commits + +- [fix test] Fix examples to use newest version of socket.io and helpers. Added tests for ensuring that examples require as expected with no errors. [`fd648a5`](https://github.com/http-party/node-http-proxy/commit/fd648a529090cefc202613fff3fdfec9ba0e6a72) +- [fix] spdy should look like https when forwarding (until we get a client) [`698b01d`](https://github.com/http-party/node-http-proxy/commit/698b01da8e1fe6195b00e5006032d262a0a86f4e) +- [docs] options [`4c8e1d9`](https://github.com/http-party/node-http-proxy/commit/4c8e1d96a36523a548959415903bc669ebcc138d) +- http-proxy: emit websocket:start [`5df6e7b`](https://github.com/http-party/node-http-proxy/commit/5df6e7bdb8d4685a18e94ff1bf117ce8eff8d1c9) +- [fix] `destroy()` websockets in case of an error [`0d00b06`](https://github.com/http-party/node-http-proxy/commit/0d00b06af307dc5c70c36e89617a08486eb665e2) +- [fix] Suppress EADDRINUSE errors from `test/examples-test.js` since we are just looking for require-time errors. Isolate tests to ensure idempotency of ports [`c4a7b15`](https://github.com/http-party/node-http-proxy/commit/c4a7b1584302fe12a8fc06b6774db5ff602c3607) +- [docs] more options [`d4cb9da`](https://github.com/http-party/node-http-proxy/commit/d4cb9dad6ce36a823c9e8970e0bb3266d844e536) +- If HTTP 1.1 is used and backend doesn't return 'Connection' header, explicitly [`850171c`](https://github.com/http-party/node-http-proxy/commit/850171cdc41cb93343f7c31f650ac908a8d2dacb) +- [refactor] Pass all options to `Agent` constructor [`eafdc74`](https://github.com/http-party/node-http-proxy/commit/eafdc744b67b33b5ed3cfc80de84dafcd850bdd0) +- Fix socket leaks when FIN packet isn't responded to [`24b8406`](https://github.com/http-party/node-http-proxy/commit/24b84068eac1c704d9f8df3dc833b976850c328f) +- [fix] Partial fix for rejecting self-signed certs in tests [`2e7d8a8`](https://github.com/http-party/node-http-proxy/commit/2e7d8a88f4b470dcc9da1639fe2a69e03251036c) +- [fix] Dont use `-i` when running vows because it supresses `--target=` and `--proxy=` CLI arguments [`1783ab0`](https://github.com/http-party/node-http-proxy/commit/1783ab0625743355eecc11f5cfd57469c429daa0) +- [test] Add `node v0.9` testing, test all branches [`4f6387c`](https://github.com/http-party/node-http-proxy/commit/4f6387c17f55c23da4aac161cf2e5a4dd2a25c40) +- [minor] Remove `setEncoding` on incoming socket [`812868d`](https://github.com/http-party/node-http-proxy/commit/812868ddfc720b6c4fd26603c2fe4d5ae68f2492) +- [dist] v0.8.3 [`a89a5b8`](https://github.com/http-party/node-http-proxy/commit/a89a5b80889a56dd31634096bc6546b6b7b26da2) +- [fix] Ignore npm version errors when installing dependencies for examples [`a454666`](https://github.com/http-party/node-http-proxy/commit/a454666e7a0465ed65b7bbd29cf1b0c6c126d153) +- [fix] function [`213e03c`](https://github.com/http-party/node-http-proxy/commit/213e03c99844c5c984fbf857bae32095165a1e8f) +- [dist] Bump version to 0.8.4 [`4d7e8a8`](https://github.com/http-party/node-http-proxy/commit/4d7e8a808d83d3db1b729820aba5f481ab3d18f4) +- [minor doc] Correct comment [`cee27fe`](https://github.com/http-party/node-http-proxy/commit/cee27feeddf9b4db06917dfa9e59e6bcd7e14c27) + +## [v0.8.2](https://github.com/http-party/node-http-proxy/compare/v0.8.1...v0.8.2) - 2012-07-22 + +### Merged + +- Add example for gzip middleware using a proxy table. [`#221`](https://github.com/http-party/node-http-proxy/pull/221) +- Implement RoutingProxy.prototype.remove [`#246`](https://github.com/http-party/node-http-proxy/pull/246) +- prefer `target.hostname` over `target.host` [`#235`](https://github.com/http-party/node-http-proxy/pull/235) +- add "Using two certificiates" to the https section of the readme.md [`#275`](https://github.com/http-party/node-http-proxy/pull/275) +- Add support for setting the host in the executable [`#268`](https://github.com/http-party/node-http-proxy/pull/268) +- Hi! I fixed some calls to "sys" for you! [`#270`](https://github.com/http-party/node-http-proxy/pull/270) +- Fix bug: x-forwarded-proto set incorrectly as httphttps or wswss [`#266`](https://github.com/http-party/node-http-proxy/pull/266) + +### Commits + +- [refactor] Rewrite tests to use saner vows idioms. Update tests to use latest socket.io [`4ae7a5b`](https://github.com/http-party/node-http-proxy/commit/4ae7a5b84011bb5b9ec3a36ded4c5e5b3330db80) +- [dist] Remove out-dated docco docs [`2d75510`](https://github.com/http-party/node-http-proxy/commit/2d75510d827c770c30a7292c31ef0f2007da7086) +- [refactor test] Finish removing old test code. [`e2dc7f9`](https://github.com/http-party/node-http-proxy/commit/e2dc7f96937e5d565fea16c9f56b9f5d3e427de2) +- [dist] Complete JSHint compliance except for `too many var statements` [`36226da`](https://github.com/http-party/node-http-proxy/commit/36226daa2e4cbc65fae80d2d09fd64c0e7ce36ba) +- [refactor test] Add support for `http*-to-http*` testing from CLI arguments [`828dbeb`](https://github.com/http-party/node-http-proxy/commit/828dbebcaaf11e338a7727bf9d2fff8bfbd3726e) +- [fix api] Optimize lookups in the ProxyTable. Ensure that RoutingProxy can proxy to `https` by default. [`55286a7`](https://github.com/http-party/node-http-proxy/commit/55286a7c499c0fe267f75d8e8441ff89f1e65f99) +- Whitespace fixes. [`04ce49c`](https://github.com/http-party/node-http-proxy/commit/04ce49c5b289acb6ad72303e9ac70c637ea490b2) +- [refactor tests] Finished refactoring tests to support `ws*-to-ws*` tests based on CLI arguments [`7e854d7`](https://github.com/http-party/node-http-proxy/commit/7e854d778b89201f7cb933e8bbda66316b98b0b4) +- [doc] Minor formatting updates to README.md [`6753951`](https://github.com/http-party/node-http-proxy/commit/67539519faf1f32073fdb562404bd897072e24ee) +- [fix] Changed require('util') to require('util') for compatibility with node v0.8 [`bf7e328`](https://github.com/http-party/node-http-proxy/commit/bf7e328fb837de69455c42f41822b0caae2777b6) +- [test] Add .travis.yml file for Travis CI. [`29e6e74`](https://github.com/http-party/node-http-proxy/commit/29e6e748f780629d05635eebb421e8ee1d125058) +- Use changeOrigin for proxyRequest. [`0273958`](https://github.com/http-party/node-http-proxy/commit/0273958b0a5c7823c6212cb6ce6e4f801a215d3b) +- adding support for setting the host [`06e78f2`](https://github.com/http-party/node-http-proxy/commit/06e78f27475165d023fd66afbe5dd626a6a548af) +- match style requested by @cronopio [`415d4ed`](https://github.com/http-party/node-http-proxy/commit/415d4ed908e45332421d683eb45e0d6873b85ae7) +- Fix bug: x-forwarded-proto set incorrectly [`0933f1c`](https://github.com/http-party/node-http-proxy/commit/0933f1c598c1b62a75e040c3ed3ccb262612d3c9) +- [dist] Version bump. 0.8.2 [`13c34d0`](https://github.com/http-party/node-http-proxy/commit/13c34d09b2f8be14fbbe4be77c49b23066667f1b) + +## [v0.8.1](https://github.com/http-party/node-http-proxy/compare/v0.8.0...v0.8.1) - 2012-06-05 + +### Merged + +- [misc] Updating the changelog. Close #137 [`#256`](https://github.com/http-party/node-http-proxy/pull/256) +- Fix problem with req.url not being not properly replaced. [`#218`](https://github.com/http-party/node-http-proxy/pull/218) +- Re-emit 'start', 'forward' and 'end' events in RoutingProxy, and fix some hanging issues. [`#216`](https://github.com/http-party/node-http-proxy/pull/216) +- Fixes to make the websockets example work. [`#225`](https://github.com/http-party/node-http-proxy/pull/225) +- [minor] Syntax error [`#222`](https://github.com/http-party/node-http-proxy/pull/222) +- [docs] Making README links consistent with latest project structure. [`#208`](https://github.com/http-party/node-http-proxy/pull/208) +- [docs] improved grammar [`#205`](https://github.com/http-party/node-http-proxy/pull/205) +- proposed doc addition for #180 [`#189`](https://github.com/http-party/node-http-proxy/pull/189) + +### Fixed + +- [misc] Updating the changelog. Close #137 [`#137`](https://github.com/http-party/node-http-proxy/issues/137) + +### Commits + +- Whitespace fixes [`e9fd3f4`](https://github.com/http-party/node-http-proxy/commit/e9fd3f43d7e890f0164b5a03a34f196dd162d043) +- Added example for gzip middleware using a ProxyTable. [`6201328`](https://github.com/http-party/node-http-proxy/commit/62013281b8a980c53a38362f10d746bfbf36c52e) +- [examples] Added simple load balancer example [`fd7fcd8`](https://github.com/http-party/node-http-proxy/commit/fd7fcd8decbf0c7ab00cab84e151991e380b8fae) +- [dist] Update author field for consistency [`27316e2`](https://github.com/http-party/node-http-proxy/commit/27316e22e8e7786252583cdb9131cfd8cacb07c1) +- Add documentation for listening for proxy events to prevent a common mistake. [`4f2bc58`](https://github.com/http-party/node-http-proxy/commit/4f2bc58431c7f44d486ee8c1ee3136b3637f9405) +- Fix RoutingProxy hanging when there is an error [`b26b434`](https://github.com/http-party/node-http-proxy/commit/b26b434e9fc501f7e0c4a966dbee6220c355bc7c) +- prefer `target.hostname` over `target.host` [`c4d185d`](https://github.com/http-party/node-http-proxy/commit/c4d185dca9696c77d5c38d24d897c2679f6762a0) +- [doc] Fix style in websockets example [`ed06af9`](https://github.com/http-party/node-http-proxy/commit/ed06af97efe406ea2533009be64a6b568f9d0601) +- Add tests for remapping URL properly. [`5d839dd`](https://github.com/http-party/node-http-proxy/commit/5d839dd5f8890c6d2af96807b96d1bd5bb0f7276) +- fixed comment typos in examples/http/proxy-https-to-http.js and proxy-https-to-https.js, lines 37 and 46 [`868f7e7`](https://github.com/http-party/node-http-proxy/commit/868f7e7a287c4709c541c077f3e2303f45b1f072) +- [misc] changelog updated to version 0.8.1 [`e9a3a30`](https://github.com/http-party/node-http-proxy/commit/e9a3a3012c5507dff46afd3e5cececf43b1717ae) +- Implement RoutingProxy.prototype.remove [`0532995`](https://github.com/http-party/node-http-proxy/commit/0532995dfa0be53d285c886a9922b8915f297d36) +- Making README links consistent with latest project structure. [`7fa6599`](https://github.com/http-party/node-http-proxy/commit/7fa6599f4f2c92bb29bc5fc8a9ba06d704652c5e) +- Address ticket #180 here since that problem is so hard to discover when you run into it. If there was an error, people would search for the error text, but there isn't. [`73e415a`](https://github.com/http-party/node-http-proxy/commit/73e415a22634bfc9e5993377902f67ac3212714a) +- [tests] used socket.io 0.6.17 fixed version for tests [`45d67f4`](https://github.com/http-party/node-http-proxy/commit/45d67f42cba373db4f47765d6a3dd38a7d19dae6) +- [fix] x-forwarded-proto sets properly [`ca37ad7`](https://github.com/http-party/node-http-proxy/commit/ca37ad74367764cca479a1af63bd7491dc79606b) +- [doc] add missing {} to make an object [`843901e`](https://github.com/http-party/node-http-proxy/commit/843901eeeb24611ad24889f13edcbfd5dee4314d) +- fix the broken english and clarified the sentence (I hope) [`e15db4f`](https://github.com/http-party/node-http-proxy/commit/e15db4fb50db3e2191f3ebd30e12eeed9c376bc2) +- Re-emit 'start', 'forward' and 'end' events in RoutingProxy. [`99ee542`](https://github.com/http-party/node-http-proxy/commit/99ee54259eae70c0c680ee82efc7dd184313f182) +- [doc] call listen() to get the server started [`4fc1ee8`](https://github.com/http-party/node-http-proxy/commit/4fc1ee85d35d9feb468f808ddd11aaf186eaedd4) +- syntax error fixed [`5842d0e`](https://github.com/http-party/node-http-proxy/commit/5842d0ee7de875378d9b8ae240748dd2af567be9) +- [dist] Version bump 0.8.1 [`81f6095`](https://github.com/http-party/node-http-proxy/commit/81f6095cf08f84a84ae2bbda7ca0315729638fe0) +- finally removed hidden char [`4358a4c`](https://github.com/http-party/node-http-proxy/commit/4358a4c1225acf8c13536fd742b845166f3a65a6) +- [minor fix] delete white space [`df650d1`](https://github.com/http-party/node-http-proxy/commit/df650d11dd0a47653a4905f871d8d3d6c327d600) + +## [v0.8.0](https://github.com/http-party/node-http-proxy/compare/v0.7.3...v0.8.0) - 2011-12-23 + +### Merged + +- Fix issue where front-end is HTTPS, back-end is HTTP, and server issues a redirect. [`#165`](https://github.com/http-party/node-http-proxy/pull/165) +- Modified the ad-hoc proxy lookup to use _getKey(), rather than the error-prone in-line method. [`#164`](https://github.com/http-party/node-http-proxy/pull/164) +- Allows node-http-proxy to append new values to existing headers for incoming "x-forward-for","x-forward-proto" and "x-forward-port" [`#163`](https://github.com/http-party/node-http-proxy/pull/163) +- [fix] only set one drain listener while paused [`#136`](https://github.com/http-party/node-http-proxy/pull/136) +- [docs] grammar correction [`#134`](https://github.com/http-party/node-http-proxy/pull/134) + +### Fixed + +- [fix] Avoid `Transfer-Encoding: chunked` for HTTP/1.0 client, closes #59. [`#59`](https://github.com/http-party/node-http-proxy/issues/59) + +### Commits + +- [refactor minor] Update vendor/websocket.js to be compatible with node@0.6.x [`ea7fea6`](https://github.com/http-party/node-http-proxy/commit/ea7fea627255ed34d39902438b55e740c7c9b08c) +- [test] Add common.js file from core [`543f214`](https://github.com/http-party/node-http-proxy/commit/543f214361605cffdbee7b233029edf343c358c1) +- [test] Add core `test-http-proxy` test [`feb324b`](https://github.com/http-party/node-http-proxy/commit/feb324b0d4c0a2307493b35be944ed08ffc9187a) +- [test] Add core `test-http` test [`25a9e2d`](https://github.com/http-party/node-http-proxy/commit/25a9e2d217cabef07d6f161f5d6ded49342dbb2f) +- [test] Add core `test-http-host-headers` test [`f298411`](https://github.com/http-party/node-http-proxy/commit/f298411f76a106791f34dd4d31ea033a7bdca9c7) +- [test] Add core `test-http-extra-response` test [`c26ab5e`](https://github.com/http-party/node-http-proxy/commit/c26ab5e46ff2649f0ea6585f20d8f58b7d0cadef) +- [test] Add core `test-http-set-cookies` test [`b3b5cce`](https://github.com/http-party/node-http-proxy/commit/b3b5cce3aee98a7fd5b50fb8e1bd6bd5e1c7512f) +- [test] Add core `test-http-client-abort` test [`7bf8d4a`](https://github.com/http-party/node-http-proxy/commit/7bf8d4a7be668591b350144b4546559abf9a0b5f) +- [test] Add core `test-http-client-upload` test [`7648fe5`](https://github.com/http-party/node-http-proxy/commit/7648fe50c1859597dc390e9e628db938372483e7) +- [test] Add core `test-http-client-upload-buf` test [`5ac9878`](https://github.com/http-party/node-http-proxy/commit/5ac987857c934d07073b853f5243d2d8fc6d8c2b) +- [test] Add core `test-http-upgrade-server2` test [`bc98c0d`](https://github.com/http-party/node-http-proxy/commit/bc98c0dbce154ef266eef83d3c2f737a2d60f0e6) +- [test] Implement basic runner for multiple tests [`a4079c6`](https://github.com/http-party/node-http-proxy/commit/a4079c6a1c8b87334d12d47d67f060cbb1214696) +- [test] Add core `test-http-upload-timeout` test [`60ff181`](https://github.com/http-party/node-http-proxy/commit/60ff181af9c22405d3822ce5955f178ab13de79d) +- [test] Add core `test-http-status-code` test [`82060a5`](https://github.com/http-party/node-http-proxy/commit/82060a53430de05f2dc95450d8487bc8139544d5) +- [test] Add core `test-http-many-keep-alive-connections` test [`4e1ca6e`](https://github.com/http-party/node-http-proxy/commit/4e1ca6e61899b11cad1b437cc9d9490b9d856665) +- [test] Add core `test-http-chunked` test [`d7461f3`](https://github.com/http-party/node-http-proxy/commit/d7461f3206cca0691fbd438545ff325589770627) +- [test] Add core `test-http-head-response-has-no-body-end` test [`13389db`](https://github.com/http-party/node-http-proxy/commit/13389db1bef38a7fc7ddc3ada479a608f033020c) +- [test] Add core `test-http-server-multiheaders` test [`d7f15d0`](https://github.com/http-party/node-http-proxy/commit/d7f15d02f7477c76529fc76daddee5029079eb2d) +- [test] Add core `test-http-multi-line-headers` test [`35d2088`](https://github.com/http-party/node-http-proxy/commit/35d2088c96bacb44b17755176b6e9451ed0299dd) +- [test] Add core `test-http-head-response-has-no-body` test [`f79f3ad`](https://github.com/http-party/node-http-proxy/commit/f79f3adf0295ec5bb7fb9f6525b48ba5209d04c6) +- [refactor] Improved event handler cleanup [`9f92332`](https://github.com/http-party/node-http-proxy/commit/9f923325d08ac018a3325beaa9e0805b5eda61e6) +- [fix minor] Correctly set x-forwarded-proto in WebSocket requests [`c81bae2`](https://github.com/http-party/node-http-proxy/commit/c81bae2fdde3bf0087fe71a39855c61c43ffb145) +- Revert "[refactor] Improved event handler cleanup " [`c83d88e`](https://github.com/http-party/node-http-proxy/commit/c83d88ee88faac10b53cd4296165ed85f26036b4) +- Allowing the common proxy headers' value to be appended in proxy chain scenarios. [`621f9b4`](https://github.com/http-party/node-http-proxy/commit/621f9b425a272421de98a674f1679f0c47912733) +- [test] Add basic test runner [`87999d0`](https://github.com/http-party/node-http-proxy/commit/87999d028880dfccca349c9c44f9e66a613c4d38) +- [examples] Add some hand-crafted middleware [`6e65c20`](https://github.com/http-party/node-http-proxy/commit/6e65c20017a2e1a87dc6d58e847bc6db16440f3c) +- [test] Add core `test-http-malformed-request` test [`a635389`](https://github.com/http-party/node-http-proxy/commit/a6353897cdbe8c380d52a060f5e66784f67ad98e) +- [example] Response modification middleware [`dd83199`](https://github.com/http-party/node-http-proxy/commit/dd8319972c1c2f9421a90a21dce9560fd5ca199f) +- [test] Add core `test-http-head-request` test [`c0857f2`](https://github.com/http-party/node-http-proxy/commit/c0857f2d59c33d91cb3e0c131c44ec1667f592fa) +- [test] Add core `test-http-response-close` test [`f1c0be3`](https://github.com/http-party/node-http-proxy/commit/f1c0be3f0bd2c5e87d44a37ba4f29aafd9903ad4) +- [refactor] core proxy logic. all tests should be passing. [`63ac925`](https://github.com/http-party/node-http-proxy/commit/63ac9252606d23e2003696da1fb34a539abee7ca) +- [test] Add core `test-http-contentLength0` test [`275109b`](https://github.com/http-party/node-http-proxy/commit/275109b2f8c8519c56ca9f456096d4002698fab1) +- [test] Add core `test-http-client-abort2` test [`98bbe54`](https://github.com/http-party/node-http-proxy/commit/98bbe541e4fa581f1b9e2eadb821c0609da6ab81) +- adding tests for url segment proxytable routing [`91e9bb9`](https://github.com/http-party/node-http-proxy/commit/91e9bb90709cc8a361066d6f6b8f51f58bfd7e36) +- [test] Add core `test-http-eof-on-connect` test [`80c216d`](https://github.com/http-party/node-http-proxy/commit/80c216df0cc59b88c6934f795c03ea16a737af34) +- [example] Replace `sys` usages with `util` [`8d701bb`](https://github.com/http-party/node-http-proxy/commit/8d701bb20b593c6cdf0ff1bc35cf83051b21a35e) +- [refactor] Updates to support http2 from @mikeal [`5b52c89`](https://github.com/http-party/node-http-proxy/commit/5b52c896947db42ac01e6038c9170d8859d33aea) +- [refactor] Listen for `socket` events since reverseProxy.socket is no longer set synchronously [`3828616`](https://github.com/http-party/node-http-proxy/commit/38286168161d4f4ad24d2ad95ccd8335e9ed08a4) +- [test] Run tests in `test/core/simple` by default [`68cebbe`](https://github.com/http-party/node-http-proxy/commit/68cebbe0e79ea283eea8a1ca850ab462c66c611a) +- simplify proxytable path segment rewrite logic [`c03a450`](https://github.com/http-party/node-http-proxy/commit/c03a450d9b952e1463ae2609303029e317ff5da2) +- change proxytable routing to route one level shallower [`4d50915`](https://github.com/http-party/node-http-proxy/commit/4d50915373b6afaafc7857a3e9366e8e77315683) +- [docs] Little explanation for test/core directory [`8ca5d83`](https://github.com/http-party/node-http-proxy/commit/8ca5d83497cc106a2456ff7f2ebe3db5c8634d69) +- [minor] Allow user to set `colors.mode` [`48d4a8b`](https://github.com/http-party/node-http-proxy/commit/48d4a8b263faa9acda06651bceeff50881f21b26) +- [minor] Indentation fix [`9e630da`](https://github.com/http-party/node-http-proxy/commit/9e630daf81d10485206ec136c3e1a07fe065ffeb) +- [v0.6] `http.Agent` uses different structure for sockets [`86b4122`](https://github.com/http-party/node-http-proxy/commit/86b4122323ca32d455714b1149b99acce49a9e45) +- [minor] Nicer output from test runner [`5c3d41b`](https://github.com/http-party/node-http-proxy/commit/5c3d41bf4e101d0250fb0b3db4a8dc078104dcad) +- Modified the ad-hoc proxy lookup to use _getKey(), rather than the [`553e7fb`](https://github.com/http-party/node-http-proxy/commit/553e7fbc335a9befd166d472f057aa50452a9d40) +- [fix] When client request is aborted, abort server request [`4d43d81`](https://github.com/http-party/node-http-proxy/commit/4d43d81e5c2d7c8088716d4fd574019f43ebb5ce) +- Fixes memory leak when clients abort connections [`c98ccb4`](https://github.com/http-party/node-http-proxy/commit/c98ccb40e9fe5c5198a1605fa8835efc3ff1856c) +- [fix test] Make test runner exit after test exits [`31a8c68`](https://github.com/http-party/node-http-proxy/commit/31a8c6800ddf8d91b477d980605a4c19284a1648) +- [test dist] Run core tests on `npm test` [`8358ef8`](https://github.com/http-party/node-http-proxy/commit/8358ef8a2bdf817c8ed515be7bc9cec0a9b5f486) +- don't add upgrade handler if a custom handler is passed in [`d6ea3a4`](https://github.com/http-party/node-http-proxy/commit/d6ea3a425c203695394eaba4ce8abd57f7809e98) +- always emit end in 0.4 [`182dcd3`](https://github.com/http-party/node-http-proxy/commit/182dcd34555f361c1bb2b8d2777689e64ce32f87) +- [fix] Fix incorrect depth check. [`3ab02f3`](https://github.com/http-party/node-http-proxy/commit/3ab02f3ad7f2c59d73c621695eb238233c16d09c) +- [minor] Everybody loves Unicode [`38bd906`](https://github.com/http-party/node-http-proxy/commit/38bd906f2bc9322b156b92c47457bb7904f0d23a) +- [test minor] Update copyright notice on test runner [`2ccc5c7`](https://github.com/http-party/node-http-proxy/commit/2ccc5c73eaef30ab5a2af7e456bfcc270583c460) +- [minor] When running tests output only basename [`e109eba`](https://github.com/http-party/node-http-proxy/commit/e109eba9724494737021579938c1094c9dfbc8ee) +- [dist] Version bump. 0.8.0 [`5055689`](https://github.com/http-party/node-http-proxy/commit/5055689a11f3b990f848bf2699e0111d9e708d5f) +- Revert "[dist] Adjusted engines field to allow for 0.6; version bump 0.7.7" [`1e33434`](https://github.com/http-party/node-http-proxy/commit/1e33434fcc4772c233825b5aada7472113c0be50) +- changeOrigin option: set the host header to the proxy destination [`f27d26f`](https://github.com/http-party/node-http-proxy/commit/f27d26f4515c900ea4cf1756ef279257a189e308) +- [dist] Adjusted engines field to allow for 0.6; version bump 0.7.7 [`30dac89`](https://github.com/http-party/node-http-proxy/commit/30dac898f30a8508b4c4b4236e9438987f320167) +- [fix] In routing proxy, match line beginning [`63dfc7f`](https://github.com/http-party/node-http-proxy/commit/63dfc7f1757fc9a1a9bceeb3b035e97be6504692) +- [v0.6] Don't use `agent.appendMessage()` [`6655e01`](https://github.com/http-party/node-http-proxy/commit/6655e0164216449a97090651230266da8ced0150) +- bump version 0.7.4 [`3dfba2b`](https://github.com/http-party/node-http-proxy/commit/3dfba2ba4591e0fcd65ff0bfd012b3ab749a0a02) +- bump version 0.7.6 [`c5dc929`](https://github.com/http-party/node-http-proxy/commit/c5dc9295c711177c165bfb34c67407e1a5a0ed06) +- Revert "update outgoing.headers.host incase the destination does proxying" [`2061c71`](https://github.com/http-party/node-http-proxy/commit/2061c713664b044852fdf67aa5e173e5c3b6d874) +- update outgoing.headers.host incase the destination does proxying [`65b7872`](https://github.com/http-party/node-http-proxy/commit/65b7872e6ad433deae4de823c63629cb341bd649) +- bump version 0.7.5 [`b4d41c3`](https://github.com/http-party/node-http-proxy/commit/b4d41c3628ade82792eb361b095ab014a88d537a) +- [minor] Fix indent on timeout notice [`c4124da`](https://github.com/http-party/node-http-proxy/commit/c4124da4f25860497790fc06c97dde6e8985ab73) +- [minor] Change test runner output order [`b76680b`](https://github.com/http-party/node-http-proxy/commit/b76680b045f69e03759bc119f4827f337a8f395d) +- grammar correction [`729496d`](https://github.com/http-party/node-http-proxy/commit/729496d2898612969f5369e7f1c313cb4034f96c) +- [dist] Test runner depends on `async` [`219b0ff`](https://github.com/http-party/node-http-proxy/commit/219b0ff8f8780cde4714267273b0a1637c84679f) +- [test fix] Remove unnecessary console.log in tests/websocket/websocket-proxy-test.js [`f188f4f`](https://github.com/http-party/node-http-proxy/commit/f188f4ffd8c47b6312cd88c28de7e5ac63565047) +- [test refactor] `test/core/{run => run-single}` [`004be38`](https://github.com/http-party/node-http-proxy/commit/004be38048792d6f1d3efb361a5e7e66d5dbee8d) + +## [v0.7.3](https://github.com/http-party/node-http-proxy/compare/v0.7.2...v0.7.3) - 2011-10-03 + +### Commits + +- added what is necessary for having proxyError on Routing proxywq [`b7adf86`](https://github.com/http-party/node-http-proxy/commit/b7adf866b595f0d64a3ef6bde19271276450e723) +- [dist] Version bump. 0.7.3 [`db185bb`](https://github.com/http-party/node-http-proxy/commit/db185bb303ce9c413b2abccbc885f8ec43b61202) + +## [v0.7.2](https://github.com/http-party/node-http-proxy/compare/v0.7.1...v0.7.2) - 2011-09-30 + +### Merged + +- [fix] Examples have working require paths now. [`#118`](https://github.com/http-party/node-http-proxy/pull/118) + +### Commits + +- [fix] Fixed require paths in examples [`2e8d4c6`](https://github.com/http-party/node-http-proxy/commit/2e8d4c6e49e2e9b27443c0b9ae2b96331715402b) +- [websockets] add latest websockets support [`45ef87e`](https://github.com/http-party/node-http-proxy/commit/45ef87e71bc9cccefe5fb6afc3121fb09b8efbc3) +- [dist] Version bump. 0.7.2 [`ccccc45`](https://github.com/http-party/node-http-proxy/commit/ccccc45f11fbe535017b1806fad43578f143649d) + +## [v0.7.1](https://github.com/http-party/node-http-proxy/compare/v0.7.0...v0.7.1) - 2011-09-21 + +### Merged + +- Readme fixes [`#114`](https://github.com/http-party/node-http-proxy/pull/114) +- #107: Set x-forwarded-for header (amongst others) [`#110`](https://github.com/http-party/node-http-proxy/pull/110) +- command line tool - make sure targetPort is an integer [`#109`](https://github.com/http-party/node-http-proxy/pull/109) + +### Fixed + +- [dist] Version bump v0.7.1, closes #107 #112 [`#107`](https://github.com/http-party/node-http-proxy/issues/107) + +### Commits + +- [test] Added a test for the "x-forwarded-for" header [`66e9820`](https://github.com/http-party/node-http-proxy/commit/66e982060c6c41ad7dfadce1403c8e13d267781a) +- [docs] Updated examples in README.md for 0.7.x API. [`24ef919`](https://github.com/http-party/node-http-proxy/commit/24ef9194953c27fb11a8f1ceb499e5feca11c30c) +- [examples] Updated examples to v0.7.x API. [`8fc8d96`](https://github.com/http-party/node-http-proxy/commit/8fc8d966c4681d514af00516b348105608e13382) +- [examples] More fixes to examples. [`549360a`](https://github.com/http-party/node-http-proxy/commit/549360a462c134cc2b02301070209084ec94c393) +- [fix] x-forwarded http headers should set properly. [`2677bb6`](https://github.com/http-party/node-http-proxy/commit/2677bb6c44244ea0b584db744955bedf7aee2c62) +- [fix] connection.socket -> socket for source of x-forwarded-for data [`1f33943`](https://github.com/http-party/node-http-proxy/commit/1f33943b231cdf2cb619977801c7b0d4e98ab6df) +- Make sure the target port is an integer [`5ba25aa`](https://github.com/http-party/node-http-proxy/commit/5ba25aa3451f131b6c6c8892848a4f236f5b859e) + +## [v0.7.0](https://github.com/http-party/node-http-proxy/compare/v0.6.6...v0.7.0) - 2011-09-10 + +### Fixed + +- [fix] Add `x-forward-*` headers for WebSocket requests. Closes #74 [`#74`](https://github.com/http-party/node-http-proxy/issues/74) +- [doc] Document `setMaxSockets`. Fixes #81 [`#81`](https://github.com/http-party/node-http-proxy/issues/81) + +### Commits + +- [api test dist] Stubbed out the API for the higher-level `RoutingProxy` object to be exposed by `node-http-proxy` [`5927ecd`](https://github.com/http-party/node-http-proxy/commit/5927ecd62a082269c3b6a0ae4f5b4a673784bcdb) +- [api] Finalized the RoutingProxy API [`f765f90`](https://github.com/http-party/node-http-proxy/commit/f765f90ec37defaa2b493f859a982add51e25b76) +- [minor] Move private methods to the bottom of file(s) [`ec03d72`](https://github.com/http-party/node-http-proxy/commit/ec03d72c5d8749aee835f571869f69816be02265) +- [test] Updated tests to reflect finalized API of the RoutingProxy [`734769f`](https://github.com/http-party/node-http-proxy/commit/734769fa9b2c3054d45e33c3e552af80ce3f4740) +- [api doc] Rebuilt httpProxy.createServer() with the newer high-level RoutingProxy API [`598fe2e`](https://github.com/http-party/node-http-proxy/commit/598fe2e38def56518a1f0a8196b2fcb7f1bc569e) +- [minor] Remove commented out debug statements. [`5575bcf`](https://github.com/http-party/node-http-proxy/commit/5575bcf60c87def74d1755b2e5cc73e085dbf8c3) +- [doc] Updated examples [`13eaec5`](https://github.com/http-party/node-http-proxy/commit/13eaec55dc50e2aae164cb8adaa0f1a3c5a66c68) +- Add flow control [`6a7fd14`](https://github.com/http-party/node-http-proxy/commit/6a7fd14bfa9f25694d75cf490e32817ff15a94fe) +- Add flow control [`2b9e09b`](https://github.com/http-party/node-http-proxy/commit/2b9e09b00ac40e6c6de2b68754df7b8e8c1e3878) +- Emit drain if it doesn't happen on its own in 100ms [`37e2541`](https://github.com/http-party/node-http-proxy/commit/37e25418916a31e4a513ee5866d6013858d579cf) +- resume() can throw [`558a8a4`](https://github.com/http-party/node-http-proxy/commit/558a8a4f79716496dbdee13759c8641606458c05) +- [fix] Memory leak hunting. [`ca1d12c`](https://github.com/http-party/node-http-proxy/commit/ca1d12cf1bbfbe98b5159f9c02e2f6c818a1c749) +- Emit drain if it doesn't happen on its own in 100ms [`84be9f2`](https://github.com/http-party/node-http-proxy/commit/84be9f2c3a244c7dbfe2c6320fa26d85cf80ec31) +- resume() can throw [`0c71119`](https://github.com/http-party/node-http-proxy/commit/0c71119ee58ee84068120be72308ecb28cb3e532) +- [dist] Update examples/package.json to conform to nodejitsu style guidelines [`2937229`](https://github.com/http-party/node-http-proxy/commit/29372298208135f571538cc29dcc05f41f79b01c) +- Fixed large DoS vector in the middleware implementation [`0e36912`](https://github.com/http-party/node-http-proxy/commit/0e36912906640fdb007e0492b75c3f6a7b580ec6) +- [api] Added new `close()` method which cleans up sockets from HttpProxy instances [`0eae2a9`](https://github.com/http-party/node-http-proxy/commit/0eae2a913a2173d85478f8c9deec929388284ee2) +- Fixed large DoS vector in the middleware implementation [`07c8d2e`](https://github.com/http-party/node-http-proxy/commit/07c8d2ee6017264c3d4deac9f42ca264a3740b48) +- [minor] More contextual errors when middleware(s) error [`38315f6`](https://github.com/http-party/node-http-proxy/commit/38315f6b1f7b01bc6e55587878a57590135945c0) +- [dist] Update scripts in package.json [`6e1ade0`](https://github.com/http-party/node-http-proxy/commit/6e1ade0bb8174b744abb58df72b098bd96134ca4) +- [dist] Version bump. 0.7.0 [`0182ba3`](https://github.com/http-party/node-http-proxy/commit/0182ba37cd4c618cd50947ea2addef823349e49f) +- [merge] Merge from significant internal refactor in v0.7.x. No external API changes [`f7010e5`](https://github.com/http-party/node-http-proxy/commit/f7010e5169ac23114b9b35da272e9a041743fbb9) +- [minor] Small update to bin/node-http-proxy [`2cd8256`](https://github.com/http-party/node-http-proxy/commit/2cd8256c4d6089409f603655ea3b3a5ccf1fb065) +- [dist] Update .gitignore [`6c1c554`](https://github.com/http-party/node-http-proxy/commit/6c1c5544515bf17f0e6ed3588e16ae1a75f8a25b) +- [doc] Update README.md [`0ba5023`](https://github.com/http-party/node-http-proxy/commit/0ba5023e82fe8a08ed55194644d147c323368f41) +- [doc] Drop version number from README.md. [`bdf48be`](https://github.com/http-party/node-http-proxy/commit/bdf48bea36eae441c775e9321ab6e17db470bf27) +- [dist] Version bump. 0.7.0 [`00e34a1`](https://github.com/http-party/node-http-proxy/commit/00e34a10bd9ffca9e636b2e5aebb4f18ff6765ec) +- [test] Whitespace fix [`3a4d312`](https://github.com/http-party/node-http-proxy/commit/3a4d312eda08e7a5cecb3c82b04023e22f368e2b) +- [dist] Reorganize examples based on classification(s): http, websocket, or middleware [`81d6c31`](https://github.com/http-party/node-http-proxy/commit/81d6c318758231f77a52fab7de174fcc63b7a243) + +## [v0.6.6](https://github.com/http-party/node-http-proxy/compare/v0.6.5...v0.6.6) - 2011-08-31 + +### Commits + +- Memory leak hunting. [`f4fcf93`](https://github.com/http-party/node-http-proxy/commit/f4fcf934030e84c15cceca620e974aafc35f1691) +- [fix] Add guards to every throw-able res.end call [`e1c41d0`](https://github.com/http-party/node-http-proxy/commit/e1c41d06942b56f6cd65a079ae78b54456a8bbe1) +- [fix] Only set `x-forward-*` headers if req.connection and req.connection.socket [`de4a6fe`](https://github.com/http-party/node-http-proxy/commit/de4a6fe8a5f78460b030e635e5f4a63312cd4a76) +- [dist] Version bump. 0.6.6 [`967884c`](https://github.com/http-party/node-http-proxy/commit/967884c5de311f21b8405a5030730ef8db912531) + +## [v0.6.5](https://github.com/http-party/node-http-proxy/compare/v0.6.4...v0.6.5) - 2011-08-29 + +### Commits + +- [fix] Use `req.connection` for all x-forward-* headers [`f6dc12a`](https://github.com/http-party/node-http-proxy/commit/f6dc12a971fdd892614b32d2a4fb2ff39ddc0e67) +- [dist] Version bump. 0.6.5 [`7beead5`](https://github.com/http-party/node-http-proxy/commit/7beead54654bdc7f9ab4ed0c17000118a3e7b4fc) + +## [v0.6.4](https://github.com/http-party/node-http-proxy/compare/v0.6.3...v0.6.4) - 2011-08-28 + +### Fixed + +- Fix #95 Don't look on req.connection if it's not set. [`#95`](https://github.com/http-party/node-http-proxy/issues/95) + +### Commits + +- [api breaking] Begin refactor to optimize node-http-proxy by managing one instance of HttpProxy per `host:port` location [`d2b0e43`](https://github.com/http-party/node-http-proxy/commit/d2b0e4399e8026d3e2ece78ac8fdb1def6649950) +- [api test] Updated httpProxy.createServer() for new API exposed by simplified HttpProxy object. [`be4562d`](https://github.com/http-party/node-http-proxy/commit/be4562da9fafef8b26856f7f73f6c5a2c4e389b0) +- [test fix] A few minor fixes to ensure basic WebSocket tests are working. Better scope tests by supported protocol [`daf9231`](https://github.com/http-party/node-http-proxy/commit/daf9231a66f10a25782d2227df1b1501099ac5d1) +- [test] Updates for readability [`db10c4a`](https://github.com/http-party/node-http-proxy/commit/db10c4af918c3e4bc448163f4b9e9b9267145d47) +- Add guards to every throw-able res.end call [`7bda25b`](https://github.com/http-party/node-http-proxy/commit/7bda25b1c60d082f0f2fd12fc61b45a33b74f13d) +- [minor] Dont use `.bind()` [`340be42`](https://github.com/http-party/node-http-proxy/commit/340be42797e87fcc11859a771200075e7fe0c5f1) +- [dist] Version bump. 0.6.4 [`216d46d`](https://github.com/http-party/node-http-proxy/commit/216d46dc81bda1aeb0feb1318e34f37bee38c8fb) + +## [v0.6.3](https://github.com/http-party/node-http-proxy/compare/v0.5.11...v0.6.3) - 2011-08-28 + +### Merged + +- This adds a flag to ProxyRequest to disable the setting of x-forwarded-[for|port|proto] [`#73`](https://github.com/http-party/node-http-proxy/pull/73) + +### Fixed + +- Merge branch 'patch-1' of https://github.com/KimSchneider/node-http-proxy [`#80`](https://github.com/http-party/node-http-proxy/issues/80) + +### Commits + +- [minor] Style updates and whitespace cleaning for consistency [`f0917a3`](https://github.com/http-party/node-http-proxy/commit/f0917a3f97e8df2d58252f14c15ec54369c969ae) +- [api] refactor out middlewares from examples. [`2cf4e0a`](https://github.com/http-party/node-http-proxy/commit/2cf4e0a9e6c78dfd093c098fc87100ae71bc9450) +- [docs] add middleware examples (first draft) [`020290a`](https://github.com/http-party/node-http-proxy/commit/020290a162146c4996831f4f13d71c1dc949f508) +- [fix] use routing table mhen proxying WebSockets. [`efa17ef`](https://github.com/http-party/node-http-proxy/commit/efa17ef6cf614b763fc3b76570a24e750e2ddd31) +- Tested & fixed url middleware example, added comments. [`4cc18f4`](https://github.com/http-party/node-http-proxy/commit/4cc18f4217739b0bd1b3ac88287cc8a23d486b6b) +- [minor] add middleware to node-http-proxy [`b54666f`](https://github.com/http-party/node-http-proxy/commit/b54666ff69c574d842ce1349700c6b6248484d24) +- [minor] add middleware to node-http-proxy [`c773eed`](https://github.com/http-party/node-http-proxy/commit/c773eedeb6d0b22e2b41ab9215cfdc064a8095e3) +- [minor] add url-proxying middleware example [`45f3df8`](https://github.com/http-party/node-http-proxy/commit/45f3df80937ffd5854727c91ea6b0e09cf77e160) +- [fix] Removed bad example. [`2626308`](https://github.com/http-party/node-http-proxy/commit/2626308cd845982c82a284b0d0bc064090aaf116) +- [minor] add example to test concurrency [`6ec8d6c`](https://github.com/http-party/node-http-proxy/commit/6ec8d6caace3797841c0447feb081aa7920aa0dd) +- [minor] add example of using middleware to gzip response [`d3c0697`](https://github.com/http-party/node-http-proxy/commit/d3c06973a1bf1f1c54ca55a5d7f93b77133ef9a2) +- support old (port,host) and (options) style when using middlewares [`7976de1`](https://github.com/http-party/node-http-proxy/commit/7976de1121a40f963e18ea0a4673d185f847df4c) +- [minor] Added body decoder middleware example. Needs fixing. [`8eaec35`](https://github.com/http-party/node-http-proxy/commit/8eaec3507456731c1138c0b8ebb4e51dedc7c300) +- [minor dist] Use `pkginfo`. Minor updates to variable scoping in `.createServer()` [`5d0bbb3`](https://github.com/http-party/node-http-proxy/commit/5d0bbb38c3af14907567e2dc7c4f84a915b60ce5) +- [doc] add comments to examples/url-middleware.js [`f6484de`](https://github.com/http-party/node-http-proxy/commit/f6484de4112463c74105db82d27f131d64478f1d) +- Handle cases where res.write throws [`be3a0d8`](https://github.com/http-party/node-http-proxy/commit/be3a0d84a1e75b45bc1fc63fe63cdabd9844eb59) +- [minor] code style changes [`8b48b7e`](https://github.com/http-party/node-http-proxy/commit/8b48b7e0af656fdbd6da2b16ec6365beec47c302) +- [doc] note in readme about middleware [`b5d5eaa`](https://github.com/http-party/node-http-proxy/commit/b5d5eaababa276f7d197e4b6a8a771b364b73139) +- Allow forwarding for x-forwarded-[for|port|proto] to enabled layering of http-proxies. [`404818b`](https://github.com/http-party/node-http-proxy/commit/404818b1dce9e77a917ce9f0c187772eb8c18042) +- [style] tidy [`0f8fe8e`](https://github.com/http-party/node-http-proxy/commit/0f8fe8e2460fd27edfba44989b78aa6b8c9a38e2) +- [fix] do not use middleware code if it's not needed [`2012588`](https://github.com/http-party/node-http-proxy/commit/20125889b362c61c85924810de446e1e7b18d079) +- [minor] minor fixes to gzip middleware example [`caa1f49`](https://github.com/http-party/node-http-proxy/commit/caa1f494ab4effabad6d08272c3606c1d82005ea) +- [minor] default enableXForwarded to true [`e3d95ec`](https://github.com/http-party/node-http-proxy/commit/e3d95ecab24700535184df32f3a97e8699099b7f) +- Updating to enableXForwarded [`ee3506a`](https://github.com/http-party/node-http-proxy/commit/ee3506a8e7262f780eeada331898d42ca0e9838a) +- [api] Expose adapted version of `stack` so it can be used with HttpProxy instances not created by `httpProxy.createServer()` [`5d6e6b9`](https://github.com/http-party/node-http-proxy/commit/5d6e6b9f78eb98b28db01490a36b23c1aade133f) +- The number of maxSockets has to be set after the agent is created. Setting the property in the constructor does not work. [`2caa5d2`](https://github.com/http-party/node-http-proxy/commit/2caa5d2b0d55898c133a0bf3a0048ee969efb121) +- [fix] Dont use res.* in proxyWebSocketRequest [`f7452bc`](https://github.com/http-party/node-http-proxy/commit/f7452bc42d963406f7ee19dfa353d72ce3252dd6) +- [fix] fix syntax errors. close issue #86 [`b8f8499`](https://github.com/http-party/node-http-proxy/commit/b8f84994b0515e12c9d87f89f81a8601be47a6ff) +- [api] merge middleware branch [`e6ff8d6`](https://github.com/http-party/node-http-proxy/commit/e6ff8d6597a977baf0caf4f69c75bfa93d7281f3) +- [dist] Version bump. 0.6.3 [`1389b70`](https://github.com/http-party/node-http-proxy/commit/1389b706b5c1d857c571c2947b7c758b5cc70ca3) +- merged [`5ba0f89`](https://github.com/http-party/node-http-proxy/commit/5ba0f89aa356b2e76f5cf64c16e8578d71c45d8a) +- [fix] handler variable in createServer was global (!) [`25c06a3`](https://github.com/http-party/node-http-proxy/commit/25c06a3a952068de6a24c643cb0c872f7b9a0846) +- [dist] bump version 6.0 [`03475a5`](https://github.com/http-party/node-http-proxy/commit/03475a59445a1c1c1029d0673aafabe63af1e711) +- [dist] bump version 0.6.2 [`d8068a8`](https://github.com/http-party/node-http-proxy/commit/d8068a832d437790ce8680b9b34a9f171d75786c) +- [dist] bump version 5.12 [`5d33ad7`](https://github.com/http-party/node-http-proxy/commit/5d33ad711895b2afcbd6dd5e1c0449cee1ceae7b) +- [dist] bump version 0.6.1 [`fea371d`](https://github.com/http-party/node-http-proxy/commit/fea371dc0a47dfb4f84427e5740e8756f4e5b285) +- [fix] broken RegExp [`549bfea`](https://github.com/http-party/node-http-proxy/commit/549bfeac233888ec84edeec350ed5a7377f3773e) +- [doc] add note on middleware to Using node-http-proxy section of the README [`5bf2d59`](https://github.com/http-party/node-http-proxy/commit/5bf2d59241a7695f43bb89e5cb41ade2ab7a0ad2) + +## [v0.5.11](https://github.com/http-party/node-http-proxy/compare/v0.5.10...v0.5.11) - 2011-06-26 + +### Fixed + +- [api] Simplify the usage for the `.changeHeaders` option. Fixes #34 [`#34`](https://github.com/http-party/node-http-proxy/issues/34) + +### Commits + +- [api doc test] node-http-proxy now emits `websocket:*` on important WebSocket events. Added tests for these features and updated some code docs [`4f85ca0`](https://github.com/http-party/node-http-proxy/commit/4f85ca04e425a7d4df1e46c9cadd6026eeed32f6) +- [doc] Updated docco docs [`f0649d8`](https://github.com/http-party/node-http-proxy/commit/f0649d8d6a9f84ac61d5f173c585fa4307ffb3c3) +- [doc] Added examples/latent-websocket-proxy.js [`fcfe846`](https://github.com/http-party/node-http-proxy/commit/fcfe84626fff15be21ac83ccd69b96bf3ca1f7a2) +- [doc] Add examples/standalone-websocket-proxy.js [`1ee8ae7`](https://github.com/http-party/node-http-proxy/commit/1ee8ae710497e239716f72d45e2f61ead3995dc3) +- [doc] Added sample for custom error messages using the `proxyError` event [`4cdbf0e`](https://github.com/http-party/node-http-proxy/commit/4cdbf0e8729a0665904b577376240c00e56ad876) +- [dist] Version bump. 0.5.11 [`baf0b9e`](https://github.com/http-party/node-http-proxy/commit/baf0b9e25af53e2738812ff78614cc12966e99e3) +- [doc] Small update to code docs [`9d9509f`](https://github.com/http-party/node-http-proxy/commit/9d9509f791c4c566629c2e323259885f1c3db7ed) +- [minor] Add missing space [`b608a02`](https://github.com/http-party/node-http-proxy/commit/b608a029f8aa26f1a74a917e0bec0ac37e4615a0) + +## [v0.5.10](https://github.com/http-party/node-http-proxy/compare/v0.5.9...v0.5.10) - 2011-06-13 + +### Commits + +- [refactor] Manage our own internal list of Agent instances [`887c580`](https://github.com/http-party/node-http-proxy/commit/887c5808c90b7128c040e510e237ddb4d034fe3e) +- [doc] Update docco docs for 0.5.9 [`b4ac4d4`](https://github.com/http-party/node-http-proxy/commit/b4ac4d441fe4fb84d463bd889a5ce8d7f4d596ca) +- [test] Update tests to use `localhost` [`a1cdf00`](https://github.com/http-party/node-http-proxy/commit/a1cdf005b98c422c777c88a7d7baf2eeb91f732d) +- [dist] Version bump. 0.5.10 [`7b574d3`](https://github.com/http-party/node-http-proxy/commit/7b574d3d3e52b09a6445c011b8f2ae0d78282111) +- [doc] Bump version in README.md [`653c6ca`](https://github.com/http-party/node-http-proxy/commit/653c6ca1af607623b653d3148b1bb45a304aab87) + +## [v0.5.9](https://github.com/http-party/node-http-proxy/compare/v0.5.8...v0.5.9) - 2011-05-23 + +### Commits + +- [fix] Change sec-websocket-location header when proxying WSS --> WS. Added test coverage for this scenario [`028d204`](https://github.com/http-party/node-http-proxy/commit/028d2044e71d70b7bc21d339de29e2275c3be5c2) +- [dist] Version bump. 0.5.9 [`57ca62c`](https://github.com/http-party/node-http-proxy/commit/57ca62c878c9a953f2344719556e05492ece3435) + +## [v0.5.8](https://github.com/http-party/node-http-proxy/compare/v0.5.7...v0.5.8) - 2011-05-21 + +### Commits + +- [doc] Regenerate docco docs [`c5fd368`](https://github.com/http-party/node-http-proxy/commit/c5fd368a8d803b6ab47e32e744a6fd6a6ca5361f) +- [doc] Update docco docs [`74120d8`](https://github.com/http-party/node-http-proxy/commit/74120d8988627bb0686d3a26cb8ec1408cc41287) +- [doc] Update to v0.5.7 in code and README.md [`6fd272a`](https://github.com/http-party/node-http-proxy/commit/6fd272ac18240811d8a8a39c85ee483557c414b3) +- [dist] Version bump. 0.5.8. Forwards compatible with new versions of nodejs [`76ecb51`](https://github.com/http-party/node-http-proxy/commit/76ecb51e7b41a23288f922c9c5df3ce40f67bf80) +- [fix] Dont force `Connection: close` now that Keep-Alive is supported [`a86d18b`](https://github.com/http-party/node-http-proxy/commit/a86d18bc7f93d013df715d1f4d88e651846f645d) +- [test] Update to vows description for web-socket-proxy-test.js [`a865fe6`](https://github.com/http-party/node-http-proxy/commit/a865fe662ff04a4badcc90ce2af80d2380c40a85) + +## [v0.5.7](https://github.com/http-party/node-http-proxy/compare/v0.5.6...v0.5.7) - 2011-05-19 + +### Commits + +- [api] Add `x-forwarded-proto` and `x-forwarded-port` to proxied HTTP requests [`421895f`](https://github.com/http-party/node-http-proxy/commit/421895fa308d49628bbbb546d542efa96769c3f4) +- [dist] Version bump. v0.5.7. Only good on node v0.4.7. See issue #48. [`0911c17`](https://github.com/http-party/node-http-proxy/commit/0911c1719e641c6e4342027e8d5d82c47c6f310e) +- [fix] Set `x-forwarded-for` from req.connection.socket.remoteAddress if req.connection.remoteAddress is not defined [`e9b3ec9`](https://github.com/http-party/node-http-proxy/commit/e9b3ec9b1d0ebf427e138176b28af44f0f973670) + +## [v0.5.6](https://github.com/http-party/node-http-proxy/compare/v0.5.5...v0.5.6) - 2011-05-19 + +### Commits + +- [fix doc] Add `error` handler to reverseProxy request when proxying WebSockets to prevent unhandled ParseError. Rename some variables in proxyWebSocketRequest to make the code more readable [`76580c2`](https://github.com/http-party/node-http-proxy/commit/76580c292a152c0007352a9d383f59e48993cd03) +- [doc] Regenerate docco docs [`bd45216`](https://github.com/http-party/node-http-proxy/commit/bd45216bc9207e5016f394a4bfee2bdffcc669c7) +- [api minor] Small refactor to emit `webSocketProxyError` from a single helper function on any of the various `error` events in the proxy chain [`5d2192e`](https://github.com/http-party/node-http-proxy/commit/5d2192e654f23e1b76e0b66554debe1590a3af64) +- [api] Manual merge of #46: add custom `proxyError` event and enable production error handling. [`652cca3`](https://github.com/http-party/node-http-proxy/commit/652cca37ea321ec9d1d55125217df0214c8090b6) +- [dist] Version bump. v0.5.6 Only good on node v0.4.7. See issue #48. [`f1c0f64`](https://github.com/http-party/node-http-proxy/commit/f1c0f641aa14dc3c267de37370a7369c3131c636) + +## [v0.5.5](https://github.com/http-party/node-http-proxy/compare/v0.5.4...v0.5.5) - 2011-05-19 + +### Commits + +- [fix] Change variable references for Websockets, bugs found from using wsbench [`7bf0cae`](https://github.com/http-party/node-http-proxy/commit/7bf0caef9fae86a34719f04f7b9926095fb6a146) +- [dist] Version bump. 0.5.5. Only good on node v0.4.7. See issue #48. [`acacc05`](https://github.com/http-party/node-http-proxy/commit/acacc0561f2efabc0a7859b9a410e954f2dca6fd) + +## [v0.5.4](https://github.com/http-party/node-http-proxy/compare/v0.5.3...v0.5.4) - 2011-05-19 + +### Commits + +- [doc] Update docco docs [`faf2618`](https://github.com/http-party/node-http-proxy/commit/faf2618cf3b53a972779514842bc4264ec9541fa) +- [doc] Update README.md to reflect the new HTTPS to HTTP proxy capabilities [`abc01bc`](https://github.com/http-party/node-http-proxy/commit/abc01bce293f7c1a88f9be08b0540407d2b0f4a1) +- [doc] Update examples for HTTPS to HTTP proxying [`91737fa`](https://github.com/http-party/node-http-proxy/commit/91737fadb640f30d3cd959f29069537473207efd) +- [doc test api] Improve node-http-proxy API to allow for HTTPS to HTTP proxying scenarios. Update tests accordingly. [`895f577`](https://github.com/http-party/node-http-proxy/commit/895f577744e3cbcbb5f479c4aacec5323bb001f7) +- [dist] Version bump. 0.5.4. Only good on node v0.4.7. See issue #48. [`c04eec1`](https://github.com/http-party/node-http-proxy/commit/c04eec1c370ca0eb212c96c0896c27b349f7ea97) +- [minor] Update README.md to conform to Github flavored markdown [`32a15dd`](https://github.com/http-party/node-http-proxy/commit/32a15dd79d860343453c38a7eef8339d7b99718b) +- [minor] Update README.md to conform to Github flavored markdown [`521fe27`](https://github.com/http-party/node-http-proxy/commit/521fe271853632563143fb4b76c032f7afa7831a) + +## [v0.5.3](https://github.com/http-party/node-http-proxy/compare/v0.5.2...v0.5.3) - 2011-05-18 + +### Commits + +- [test] Continued work around Origin mismatch tests [`44a8566`](https://github.com/http-party/node-http-proxy/commit/44a85664a80fd67e20bbc36d280816dbd1a796c5) +- [doc] Regenerate docco docs [`9e36d2d`](https://github.com/http-party/node-http-proxy/commit/9e36d2d2e619be322bb73092db2a9d72ef6709e8) +- [fix test api] Only change Origin headers in WebSocket requests when the `changeOrigin` option is set explicitly. Added tests to ensure Origin and sec-websocket-origin headers match when proxying websockets. [`9c6c4b9`](https://github.com/http-party/node-http-proxy/commit/9c6c4b908b7d6ce67144ba9d41702b5694254099) +- [test] Improve websocket tests to inspect outgoing and incoming HTTP headers to test origin mismatch bugs [`6e679c8`](https://github.com/http-party/node-http-proxy/commit/6e679c8019e1eb62b2b1da48628f89b8046203fd) +- [test] Refined tests to begin checking Origin == Sec-Websocket-Origin [`9ab54ab`](https://github.com/http-party/node-http-proxy/commit/9ab54ab47fc43d98f3182da9c41487f524933783) +- [doc minor] Update docs and code docs for v0.5.3 release [`03b9087`](https://github.com/http-party/node-http-proxy/commit/03b908744612faed82d9233f3b6d4af70368cf3c) +- [dist] Version bump. v0.5.3. Only good on node v0.4.7. See issue #48. [`d9fa261`](https://github.com/http-party/node-http-proxy/commit/d9fa261cdc97aee71279064e536a4a22edbe3b5b) + +## [v0.5.2](https://github.com/http-party/node-http-proxy/compare/v0.5.1...v0.5.2) - 2011-05-17 + +### Merged + +- Readme: fix syntax error, reformat code blocks [`#52`](https://github.com/http-party/node-http-proxy/pull/52) + +### Commits + +- format markdown for syntax highlighting on GitHub [`28f6dc1`](https://github.com/http-party/node-http-proxy/commit/28f6dc153a7d9fa9b6a08637c90765cf3a07fd3e) +- [doc] Regenerate docco docs [`a5e1e3e`](https://github.com/http-party/node-http-proxy/commit/a5e1e3e70d02f32ab86b711ec4b262df5955a1a9) +- [test] Fix tests in https mode [`1ee6bef`](https://github.com/http-party/node-http-proxy/commit/1ee6beff6aa3087e332701fd3cfda70b4e968ce8) +- [fix] Manage bookkeeping for incoming requests to the underlying sockets behind reverse proxied websocket events. Only use the appropriate variables in the closure scope of the `upgrade` event from this bookkeeping [`85223ea`](https://github.com/http-party/node-http-proxy/commit/85223ea0800ad63ea82783c9dc2dc4a0e3345ae8) +- [minor] Fix syntax in examples/ [`ff82946`](https://github.com/http-party/node-http-proxy/commit/ff829467d33d326c588861a46acc2bf9adbdddd2) +- add spacing around code blocks to fix README rendering [`ab8c264`](https://github.com/http-party/node-http-proxy/commit/ab8c264e6d729de81c93982f97875006e52240f0) +- [dist] Use devDependencies in package.json [`e6c52d4`](https://github.com/http-party/node-http-proxy/commit/e6c52d431f8a32e11cd347fbabeb7a03d0d40790) +- don't highlight non-javascript as javascript [`d5b9ba7`](https://github.com/http-party/node-http-proxy/commit/d5b9ba7180376b8a67b9cbfebe9acf7399cab3ed) +- fix syntax error in README example [`332d2d7`](https://github.com/http-party/node-http-proxy/commit/332d2d780ab62ccc996157dacd2498c568816ffc) +- [minor] Ignore npm modules and debug logs [`e90cbd6`](https://github.com/http-party/node-http-proxy/commit/e90cbd6f148633ef7d3e2de06aaabe1cc493cc37) +- [dist] Include docco module as a dev dependency [`d08c2bb`](https://github.com/http-party/node-http-proxy/commit/d08c2bb525ec661c0c8e6539e28605972b1ae9b8) +- [dist] Version bump. 0.5.2. Only good on node v0.4.7. See issue #48. [`360e79a`](https://github.com/http-party/node-http-proxy/commit/360e79a005d298f40f36ee0e25c34fe534311b09) + +## [v0.5.1](https://github.com/http-party/node-http-proxy/compare/v0.5.0...v0.5.1) - 2011-05-10 + +### Commits + +- [dist] Version bump. 0.5.1. Only good on node v0.4.7. See issue #48. [`6c80177`](https://github.com/http-party/node-http-proxy/commit/6c8017734053bc683f32a2b9f0ba18ba0c014855) +- Revert "Fixed "Invalid argument to getAgent" when proxying HTTP" [`40dc9de`](https://github.com/http-party/node-http-proxy/commit/40dc9dee2d1e617af7f85a056d281b4f220f2802) +- [fix] Fix typo in bin/node-http-proxy [`57127a3`](https://github.com/http-party/node-http-proxy/commit/57127a367193bcf12be2b367e1e01cbc57d685fe) +- Merged pull request #39 from timmattison/master. [`ac425d7`](https://github.com/http-party/node-http-proxy/commit/ac425d70ef63b847fe6eb17dbfc4b084d0dd2d20) +- Fixed "Invalid argument to getAgent" when proxying HTTP [`642e158`](https://github.com/http-party/node-http-proxy/commit/642e15805dbd572835bb4fee9527e4f2da658833) + +## [v0.5.0](https://github.com/http-party/node-http-proxy/compare/v0.4.2...v0.5.0) - 2011-04-17 + +### Commits + +- [doc] Breakout demo.js into files in example/. Add web-socket-proxy.js example [`6e4bf6a`](https://github.com/http-party/node-http-proxy/commit/6e4bf6a9cbc400fcd2be420649ce08936417dd83) +- [api test doc] Improve HTTPS support. Update minor documentation. Change tests accordingly. [`bf68dc3`](https://github.com/http-party/node-http-proxy/commit/bf68dc30a5c508bc8f533f52c083206b87963811) +- [api] Update WebSocket support to use http.Agent APIs [`b0b0183`](https://github.com/http-party/node-http-proxy/commit/b0b0183c2b54fa63bd2a6f9c92475c7f56d811a3) +- [api] Update `.proxyRequest()` and `.proxyWebSocketRequest()` APIs to take an options hash instead of a set of arguments. Add HTTPS support. [`cfddd12`](https://github.com/http-party/node-http-proxy/commit/cfddd12e821bd6b07ff2dbf0aa543ddfc3664dca) +- [doc api] Update README.md and CHANGELOG.md for v0.5.0. Update bin/node-http-proxy to read files specified in `config.https` [`212009d`](https://github.com/http-party/node-http-proxy/commit/212009df6b08de3c0c97a4e9ec43f60f6bf49ea6) +- [test] Add WebSocket tests [`4d18ac1`](https://github.com/http-party/node-http-proxy/commit/4d18ac1ae611f84e5e0cc599234124d183d81ffd) +- [doc] Regenerate docco docs [`c485c87`](https://github.com/http-party/node-http-proxy/commit/c485c8742c86b504823020d2cf6c1342a1bcce48) +- [doc test] Small updates to README.md. Update to try require socket.io [`12064d8`](https://github.com/http-party/node-http-proxy/commit/12064d8e5debf674cd5d367e563b699f10a4325e) +- [api] Remove winston logging in favor of custom events [`a89b397`](https://github.com/http-party/node-http-proxy/commit/a89b3976b25516db9b601c0327948f3d90fab006) +- [doc] Update README.md [`bd6a262`](https://github.com/http-party/node-http-proxy/commit/bd6a2622ad67b8c7ec15868037a48048207ce0df) +- [dist] Version bump. v0.5.0 [`ddf31b2`](https://github.com/http-party/node-http-proxy/commit/ddf31b22ec71ef9dacca9c178ee26b6314d9fdf4) +- [api] Update `request` event to be consistent by emitting both `req` and `res`. Add `x-forwarded-for` header. [`a3cb527`](https://github.com/http-party/node-http-proxy/commit/a3cb527be5e42d5192400933bf32a361b8c707c4) +- [api] Emit `end` event when done proxying [`5681fc1`](https://github.com/http-party/node-http-proxy/commit/5681fc1a28ff06dfa91d9bf5512c688235cafac4) +- [minor] Small update to README.md [`40c51a7`](https://github.com/http-party/node-http-proxy/commit/40c51a703baaf050b35f60131d3e78b42e7b0858) +- [dist] Move pgriess' websocket client into vendor/* [`7cbf447`](https://github.com/http-party/node-http-proxy/commit/7cbf44732068dc788d31432553b3bdfcfb39f743) + +## [v0.4.2](https://github.com/http-party/node-http-proxy/compare/v0.4.1...v0.4.2) - 2011-04-13 + +### Commits + +- [dist] Version bump. 0.4.2. Remove `eyes` dependency. [`a5d88aa`](https://github.com/http-party/node-http-proxy/commit/a5d88aaacc209bdceaf0799e99ff82bdce1bdc10) + +## [v0.4.1](https://github.com/http-party/node-http-proxy/compare/v0.4.0...v0.4.1) - 2011-03-20 + +### Commits + +- [dist] Version bump. 0.4.1. Fix package.json [`0d1a3fe`](https://github.com/http-party/node-http-proxy/commit/0d1a3fe99511dda1ac949536a9eb4a045db39979) + +## [v0.4.0](https://github.com/http-party/node-http-proxy/compare/v0.3.1...v0.4.0) - 2011-03-20 + +### Commits + +- [api] Further work on refactor for node 0.4.0 [`e39a9f9`](https://github.com/http-party/node-http-proxy/commit/e39a9f93d2f9ab6ea769fad5e9dda25d022d8a1a) +- [doc] Added docco generated literate coding documentation [`3bc7d16`](https://github.com/http-party/node-http-proxy/commit/3bc7d16adc48ad1aa1161bb02bd0c27d4fb20639) +- [doc api test] Wrap things up for v0.4.0 release: Add hostnameOnly routing to ProxyTable, add more documentation, fix edge-cases until they can be further investigated in node.js core [`5715318`](https://github.com/http-party/node-http-proxy/commit/571531820e2233b0d2f7268a1d4db8510fcabf91) +- [api] First pass at removing pool and working with node v0.4.0 [`9faa924`](https://github.com/http-party/node-http-proxy/commit/9faa924a29544cfd84c28cb1c45489f495e3806a) +- [doc api test] Rename HttpProxy.pause to HttpProxy.resume. Update documentation and tests accordingly [`4110448`](https://github.com/http-party/node-http-proxy/commit/4110448046dd945afe3e092968d9382d573a369a) +- [doc] Added more documentation [`973f19f`](https://github.com/http-party/node-http-proxy/commit/973f19fd5a14e3bfad5f67e54710a4076a469fe0) +- [doc] Regenerate docco docs [`6c42f04`](https://github.com/http-party/node-http-proxy/commit/6c42f045241194061c3786ba5827aebf88070201) +- [api] Force connection header to be `close` until keep-alive is replemented [`3fd3c96`](https://github.com/http-party/node-http-proxy/commit/3fd3c96fa05fda45c7ef9ff44594644ac54f4a1e) +- [dist] Version bump. 0.4.0 [`cbb5fbc`](https://github.com/http-party/node-http-proxy/commit/cbb5fbccd0e65c51eba14e75ef44184714cc8971) +- [api test] All tests are passing when run as individual files [`389159d`](https://github.com/http-party/node-http-proxy/commit/389159da1b91ab60b8de3c379d84e76c703e6b59) +- [minor doc] Update demo and small fix to node-http-proxy [`d8c5406`](https://github.com/http-party/node-http-proxy/commit/d8c54063dc5961fa619f7c04fa2d225da9aa1439) +- [fix] Fixed cli parsing issue when --argument=value is not used [`34cba38`](https://github.com/http-party/node-http-proxy/commit/34cba38c297d6dcb845e95b9e1ce0271da1631d2) +- [test] Small update to proxy-table-test.js [`3588687`](https://github.com/http-party/node-http-proxy/commit/3588687874eb691fe59407a207d38efa418211d0) +- [minor] Expose version on module [`1dd9b3b`](https://github.com/http-party/node-http-proxy/commit/1dd9b3b15088a3c4595faae64822969014a61d52) +- [doc] Update to v0.3.1 in README.md [`8ef2e1f`](https://github.com/http-party/node-http-proxy/commit/8ef2e1fe33e0fca2b80c0d6474dba994e625f094) +- [dist] Change package.json for npm version bump [`0e7f362`](https://github.com/http-party/node-http-proxy/commit/0e7f3626718ecf108f3cafa814b0f4ffb3e6faa2) + +## [v0.3.1](https://github.com/http-party/node-http-proxy/compare/v0.3.0...v0.3.1) - 2010-11-22 + +### Commits + +- [api test doc] Updated tests. Added ProxyTable functionality [`bedc7a3`](https://github.com/http-party/node-http-proxy/commit/bedc7a3ae57d5ec07b372a550fa69772f9fbc19e) +- [test] Simplified tests. Added tests for experimental websocket support [`8c3e993`](https://github.com/http-party/node-http-proxy/commit/8c3e993833e2a09376fdb5e7c847ff00b53e70d8) +- [test doc api] Added forward proxy functionality with tests [`c06f4bf`](https://github.com/http-party/node-http-proxy/commit/c06f4bf7fe50f29677dc5a5aad596193fc893018) +- [dist minor] Removed vendored pool. Changed all references of sys to util [`8251296`](https://github.com/http-party/node-http-proxy/commit/8251296d7f5c472ec523316e905d678042b043d3) +- WebSocket proxy support, fixed 304 code halting [`7249ef3`](https://github.com/http-party/node-http-proxy/commit/7249ef3ee776c66acc95036dc76a2d08dc3f6350) +- [api] pseduo-vendor pool until pull request is finalized [`7c2eb5d`](https://github.com/http-party/node-http-proxy/commit/7c2eb5de3531f20ea92c99dd8ab207d26be9dce8) +- No-server fix [`f84880f`](https://github.com/http-party/node-http-proxy/commit/f84880fcd946e55585d8e901e5bc32933f629837) +- [api test bin doc] Added bin script and simple logging [`00014d6`](https://github.com/http-party/node-http-proxy/commit/00014d624c052e7404ce96c7e06769440c4eae2a) +- [debug] Removed pool as a dependency for stress test [`73381cf`](https://github.com/http-party/node-http-proxy/commit/73381cf71ae92b9ed1c2da5986aa7ca31a7cf2e8) +- 'end' event becomes 'close', added more try-catch handling [`cd78af5`](https://github.com/http-party/node-http-proxy/commit/cd78af5feaa67c5005df921a8d1a61575a58fca2) +- Added support of automatic websocket tunneling, added test for it [`56003b5`](https://github.com/http-party/node-http-proxy/commit/56003b527625b2d83a191f3172005c87856aa87d) +- [debug] Better debug messages to try to determine if pool is slowly losing clients to forever busy [`dd1918d`](https://github.com/http-party/node-http-proxy/commit/dd1918dc360dc0f9553c35c82f3f0f93ac3bfb46) +- [doc dist] Version bump. Added CHANGELOG.md [`de53d5e`](https://github.com/http-party/node-http-proxy/commit/de53d5eb2c3d671be0ad0e736a6435c3bf5f55f4) +- Moved error handling to response.on('end'), fixed error handling in websocket's part [`7e61f0c`](https://github.com/http-party/node-http-proxy/commit/7e61f0cf5725dedf37b956545639c2d6129855d3) +- [minor] Pushing hot-fix from Mikeal for vendored pool repo [`60791f3`](https://github.com/http-party/node-http-proxy/commit/60791f361f8a11f9d1bad2c6366bf0ce72b40f66) +- [api] Integrated commits from donnerjack and worked on pool changes [`3bb458e`](https://github.com/http-party/node-http-proxy/commit/3bb458e115037bc27691705d255b0d2e2504a9f1) +- [doc] Updated Copyright ... added Fedor [`9128a8c`](https://github.com/http-party/node-http-proxy/commit/9128a8c5a15d0f64a0bae946f3e741ea708bc56f) +- [minor] Listen to error event on pool so we dont fail out unexpectedly anymore [`711258e`](https://github.com/http-party/node-http-proxy/commit/711258ef469d064cc0dbe0f0320ed1047ed0bd54) +- adding more debugging messages [`5d54ea5`](https://github.com/http-party/node-http-proxy/commit/5d54ea58c93c26635e0de96871e824baffea34dd) +- adding some debug messages for live testing [`4069a7e`](https://github.com/http-party/node-http-proxy/commit/4069a7e98c22a48bae7fd57ad5f315d0e5006dfc) +- [minor] Listen to error events re-emitted by pool into the ClientRequest [`f8bff4c`](https://github.com/http-party/node-http-proxy/commit/f8bff4c618ab2a6b6185ac973cd0e21cea19c23a) +- [minor] Updated max clients for pool [`32aaf74`](https://github.com/http-party/node-http-proxy/commit/32aaf74e95f8a39d847b352ca984145e7abe89a6) +- [debug] Trying to repair pool busy client growth [`7b0ea85`](https://github.com/http-party/node-http-proxy/commit/7b0ea85e2ac58d5f711f64b855f746fb2423a276) +- [debug] Roll back last commit ... connection = close was ineffective [`266e524`](https://github.com/http-party/node-http-proxy/commit/266e5246eacb4877bb6ab557e6e6b9b8434ad612) + +## [v0.3.0](https://github.com/http-party/node-http-proxy/compare/v0.2.0...v0.3.0) - 2010-09-10 + +### Commits + +- [api] Revert to old 0.1.x codebase for bug testing and performance comparison [`66afb2a`](https://github.com/http-party/node-http-proxy/commit/66afb2a2a35a479512ce2601c89b82f13596fc9f) +- [api test dist doc] Updated for 0.3.0 release [`a9084b9`](https://github.com/http-party/node-http-proxy/commit/a9084b923afa66c3004abec4951ff02e031631da) +- [api] Object creation is cheap for HttpProxy, so lets take advantage [`9f0aeac`](https://github.com/http-party/node-http-proxy/commit/9f0aeacab1a632136f5905a0d03ad04be9f93f51) +- [doc] Update contributors for 0.3.0 [`6d47d98`](https://github.com/http-party/node-http-proxy/commit/6d47d98f5345b7f335c3b93f8e4a31dd90235dda) + +## [v0.2.0](https://github.com/http-party/node-http-proxy/compare/v0.1.5...v0.2.0) - 2010-09-07 + +### Commits + +- [dist] Version bump and update to README + LICENCE. Word to Mikeal for coming thru for 0.2.0 [`69c162d`](https://github.com/http-party/node-http-proxy/commit/69c162dc3da334b2ece0a19be5ea4c8da7e0fe87) +- [api dist] Merge of branch 0.2.0 [`fd61828`](https://github.com/http-party/node-http-proxy/commit/fd618289338ca2d7595f695c0b8531b40145bbca) +- [api] Completely refactored node-http-proxy with help from Mikeal [`1221939`](https://github.com/http-party/node-http-proxy/commit/1221939accf00467adb25f8908e991e984043c85) +- [api minor debug] Remove debug code, set Connection header if not set [`6d08f24`](https://github.com/http-party/node-http-proxy/commit/6d08f24c863e071eb4a0d3ede15656e5e7c27c4b) +- [debug] Added some debugging to figure out why AB wont complete a test with v0.2.0 [`9715ebd`](https://github.com/http-party/node-http-proxy/commit/9715ebd40bdbbe883eb383676d5b0df24968dd72) +- [api] Integrated a little more from Mikeal to make our return headers consistent [`eb39018`](https://github.com/http-party/node-http-proxy/commit/eb39018fd0b5751dd90fabce905997e52f2ffecd) +- [doc] Updated README.md [`f291efb`](https://github.com/http-party/node-http-proxy/commit/f291efbaa4360d6e7ff4004cc11f8df0d737c1d0) + +## v0.1.5 - 2010-09-02 + +### Commits + +- [api] More changes for createServer api [`5d94ae2`](https://github.com/http-party/node-http-proxy/commit/5d94ae27bc2d56d1f817b0cf1dfdb01dcc376393) +- added colors and asciimo [`d490b50`](https://github.com/http-party/node-http-proxy/commit/d490b50ada8c1024cb785335966b71d69fae3407) +- [api] First commit of http-proxy [`30b68c1`](https://github.com/http-party/node-http-proxy/commit/30b68c153270619119ec36615bb54ee7a2816ecc) +- updating demo [`c4b7c0d`](https://github.com/http-party/node-http-proxy/commit/c4b7c0d8a0cc5fd7f43257594bd0a71c7bd12a63) +- initial release v0.1.0, sure to have many updates coming. [`85f7372`](https://github.com/http-party/node-http-proxy/commit/85f73723415ec54539721777e77d5d10de383469) +- fleshing out demo [`994f748`](https://github.com/http-party/node-http-proxy/commit/994f7481ce07c15afa5ab993b79d920b8220be44) +- [docs] added benchmarks [`bbed176`](https://github.com/http-party/node-http-proxy/commit/bbed17640f84e56aaea06c6d4eb7d04952957fce) +- updated paths to use npm [`972c8c0`](https://github.com/http-party/node-http-proxy/commit/972c8c05274c72c7320291389f88b0694ac290ca) +- added spark demo [`d0ad931`](https://github.com/http-party/node-http-proxy/commit/d0ad93176d8430301a8a42f8c2b817674ce7ba32) +- [test] Updated tests to include support for latent requests [`095e86a`](https://github.com/http-party/node-http-proxy/commit/095e86aa653c1c8e07cd1403697e0e4b638b8294) +- started to flesh out simple demo based on tests [`2fb5ffb`](https://github.com/http-party/node-http-proxy/commit/2fb5ffba7765462e95badd0f7243e65395a3fd2e) +- added createServer but hated it, gonna remove [`b1eb13e`](https://github.com/http-party/node-http-proxy/commit/b1eb13eb70b67ea76f5ab720d566894677a53ca2) +- [test] Updated node-http-proxy tests [`2f265a2`](https://github.com/http-party/node-http-proxy/commit/2f265a23e4a10971495d0bd7b324b7ba786e5065) +- [api] Updated request hashes to use a unique identifier [`c887a75`](https://github.com/http-party/node-http-proxy/commit/c887a757623f5a3d7d1e0fafeb00b96731c89872) +- [api] Updated http-proxy to work with vows [`ead7567`](https://github.com/http-party/node-http-proxy/commit/ead7567db8099264a2001fd876cded84bc4f111f) +- [dist] Renamed node-proxy to node-http-proxy, updated package.json [`2f49810`](https://github.com/http-party/node-http-proxy/commit/2f49810ef86f49927991f32ae42605f1118b0c25) +- updating docs, almost there [`6e651f4`](https://github.com/http-party/node-http-proxy/commit/6e651f420f4d1e15dbbf823a8e3b311e9533c805) +- changed api to better reflect nodes api. updated demos, tests, docs [`bde98f4`](https://github.com/http-party/node-http-proxy/commit/bde98f489234fe22f49468011b7e342cd108603f) +- updating docs [`341bbd4`](https://github.com/http-party/node-http-proxy/commit/341bbd404f3fd81e65197b3830c3fa9e544bc1e7) +- fixed npm package, i think. bumped version 0.1.1 [`fca40da`](https://github.com/http-party/node-http-proxy/commit/fca40da694d8df17ed6140265e374c0ceabd1167) +- updated demo [`b622702`](https://github.com/http-party/node-http-proxy/commit/b62270210e7ad3c54fd6b2c86bde9f9942328a67) +- added readme [`d6a2f8a`](https://github.com/http-party/node-http-proxy/commit/d6a2f8aa7dae3f6721b9607a702c68b1ad7fc692) +- [api] Corrected chain of argument passing [`da55777`](https://github.com/http-party/node-http-proxy/commit/da55777a92d100a5ddb7a8267e56ba26bd8c2270) +- updated demo [`e9511ea`](https://github.com/http-party/node-http-proxy/commit/e9511eafdf9ada6a0ce6defb3c5f2299411633b1) +- [deploy] Added package.json [`dce80b9`](https://github.com/http-party/node-http-proxy/commit/dce80b9b4546064da1943e0e396e19b41390588a) +- updated readme [`76d0649`](https://github.com/http-party/node-http-proxy/commit/76d0649abcafd80509af922503c5544e646bcebb) +- update to docs and package.json [`d15bba4`](https://github.com/http-party/node-http-proxy/commit/d15bba4c1d2cbdaf0af27f3adcaa1db9b534d968) +- [minor] Removed eyes dependency [`eaeed83`](https://github.com/http-party/node-http-proxy/commit/eaeed8306d6dc6e1b30223cf6d59cda6d5bb76de) +- merge [`93505a4`](https://github.com/http-party/node-http-proxy/commit/93505a422c688b7f41fdaf304270c893ef4cf09a) +- fixed additional port / server mismatches for new api [`15c18b6`](https://github.com/http-party/node-http-proxy/commit/15c18b612d6cd5a1f3ae46b5590dda1fc586fb35) +- [doc] added nodejitsu.com link to ReadMe. http-proxy is used in our front facing load-balancers. look for bugs...try to improve benchmarks.... ^_^ [`6661753`](https://github.com/http-party/node-http-proxy/commit/6661753f07dcf4e5ae684df4d1709f3c238346c9) +- removed extra self, updated colors requirement, bumped to version 0.1.3 [`9bc5b6f`](https://github.com/http-party/node-http-proxy/commit/9bc5b6f8621fb2a37e84524c3e5b91aab9b45675) +- fixed pathing issue, bumped version 0.1.3 [`ede6490`](https://github.com/http-party/node-http-proxy/commit/ede649037e08b615a8995179f46bc701550354d6) +- updated docs [`07d96bb`](https://github.com/http-party/node-http-proxy/commit/07d96bb8887a7880a21a739e0a8f495698e7e79e) +- updated docs [`1594367`](https://github.com/http-party/node-http-proxy/commit/15943675edef490d9b8732345a750bc5ab1f5d7e) +- updated readme [`fb8c5ab`](https://github.com/http-party/node-http-proxy/commit/fb8c5abd3c2a722c1c18046dcf2fffea4fa7d050) +- updated docs [`17b6c69`](https://github.com/http-party/node-http-proxy/commit/17b6c6998544572300fc9d4faa63af1aee4c3d88) +- updated docs [`c8dd8c4`](https://github.com/http-party/node-http-proxy/commit/c8dd8c4e28e09f25c161980316b259d81d5a4e91) +- updated package.json again [`ddba155`](https://github.com/http-party/node-http-proxy/commit/ddba155377942259554842f37de98c508130fe11) +- initial release v0.1.0, sure to have many updates coming. [`6a1baa2`](https://github.com/http-party/node-http-proxy/commit/6a1baa25ccf9fc3a3fc4d1a4764c968993e48cab) +- bumped to version 0.1.5 [`b195a16`](https://github.com/http-party/node-http-proxy/commit/b195a16406534912161671448a53d6633a1f2458) +- updated readme [`9aa2216`](https://github.com/http-party/node-http-proxy/commit/9aa22162f139ab2fa6df6b11e2a96336ee1d2612) +- added spark demo [`d408e39`](https://github.com/http-party/node-http-proxy/commit/d408e39ed6dbd44709d0164a95ad9bc67f76ba13) +- bumped to version 0.1.4. improved on api [`82b8228`](https://github.com/http-party/node-http-proxy/commit/82b822827d35a54501068f9880111473e19c72f9) +- initial release v0.1.0, sure to have many updates coming. [`1e04552`](https://github.com/http-party/node-http-proxy/commit/1e04552bd8f39e3dcba36bbf7fb36674e5c0c9ff) +- updated readme [`0a2eaaa`](https://github.com/http-party/node-http-proxy/commit/0a2eaaa7db690f86aca8c0b952f745e806ad818c) +- updating docs [`198000f`](https://github.com/http-party/node-http-proxy/commit/198000feefd525125a2031557b3556978a057bde) +- [api] Added createServer api to node-http-proxy [`2e2b55f`](https://github.com/http-party/node-http-proxy/commit/2e2b55f113eb3bc81c43717c0db5de695fb694c1) diff --git a/examples/middleware/modifyResponse-middleware.js b/examples/middleware/modifyResponse-middleware.js index 5cd5885f0..41c4cec8c 100644 --- a/examples/middleware/modifyResponse-middleware.js +++ b/examples/middleware/modifyResponse-middleware.js @@ -38,7 +38,7 @@ app.use(function (req, res, next) { var _write = res.write; res.write = function (data) { - _write.call(res, data.toString().replace("Ruby", "nodejitsu")); + _write.call(res, data.toString().replace("Ruby", "http-party")); } next(); }); @@ -61,7 +61,7 @@ var proxy = httpProxy.createProxyServer({ // http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); - res.end('Hello, I know Ruby\n'); + res.end('Hello, I love Ruby\n'); }).listen(9013); util.puts('http proxy server'.blue + ' started '.green.bold + 'on port '.blue + '8013'.yellow); diff --git a/package-lock.json b/package-lock.json index 1fbeb0d35..b77a784f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -223,6 +223,36 @@ "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "dev": true }, + "auto-changelog": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-1.15.0.tgz", + "integrity": "sha512-TnF15fXgJUOHdAzbMnbSzKq+0lK6NFVAssShYJJDykLduUO1xqHSzhwZXYa6ZkSTMARh4F7gz3W74ly0pLJ1vw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "core-js": "^3.1.4", + "handlebars": "^4.1.2", + "lodash.uniqby": "^4.7.0", + "node-fetch": "^2.6.0", + "parse-github-url": "^1.0.2", + "regenerator-runtime": "^0.13.2", + "semver": "^6.1.1" + }, + "dependencies": { + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", @@ -428,6 +458,12 @@ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", "dev": true }, + "core-js": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "dev": true + }, "cp-file": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-6.2.0.tgz", @@ -1061,6 +1097,12 @@ "lodash.isarray": "^3.0.0" } }, + "lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=", + "dev": true + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -1207,6 +1249,12 @@ "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", "dev": true }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", + "dev": true + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -1341,6 +1389,12 @@ "release-zalgo": "^1.0.0" } }, + "parse-github-url": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", + "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", + "dev": true + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -1457,6 +1511,12 @@ "util-deprecate": "^1.0.1" } }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", + "dev": true + }, "release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", diff --git a/package.json b/package.json index d5f4172b3..be5968c0a 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "devDependencies": { "async": "^3.0.0", + "auto-changelog": "^1.15.0", "concat-stream": "^2.0.0", "expect.js": "~0.3.1", "mocha": "^3.5.3", @@ -30,10 +31,11 @@ }, "scripts": { "mocha": "mocha test/*-test.js", - "test": "nyc --reporter=text --reporter=lcov npm run mocha" + "test": "nyc --reporter=text --reporter=lcov npm run mocha", + "version": "auto-changelog -p && git add CHANGELOG.md" }, "engines": { - "node": ">=4.0.0" + "node": ">=6.0.0" }, "license": "MIT" } From 9bbe486c5efcc356fb4d189ef38eee275bbde345 Mon Sep 17 00:00:00 2001 From: indexzero Date: Tue, 17 Sep 2019 21:40:59 -0400 Subject: [PATCH 553/556] [dist] Version bump. 1.18.0 --- CHANGELOG.md | 24 ++- package-lock.json | 460 ++++++++++++++++++++++++---------------------- package.json | 2 +- 3 files changed, 258 insertions(+), 228 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index caac0e520..06cb1b776 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -## [Unreleased](https://github.com/http-party/node-http-proxy/compare/1.17.0...HEAD) +## [v1.18.0](https://github.com/http-party/node-http-proxy/compare/1.17.0...v1.18.0) - 2019-09-18 ### Merged +- Added in auto-changelog module set to keepachangelog format [`#1373`](https://github.com/http-party/node-http-proxy/pull/1373) - fix 'Modify Response' readme section to avoid unnecessary array copying [`#1300`](https://github.com/http-party/node-http-proxy/pull/1300) - Fix incorrect target name for reverse proxy example [`#1135`](https://github.com/http-party/node-http-proxy/pull/1135) - Fix modify response middleware example [`#1139`](https://github.com/http-party/node-http-proxy/pull/1139) @@ -150,6 +151,10 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Location rewriting for responses with status 201 [`#1024`](https://github.com/http-party/node-http-proxy/pull/1024) - #866 Copy CA from options into outbound proxy [`#1042`](https://github.com/http-party/node-http-proxy/pull/1042) +### Fixed + +- Restream body before proxying (#1027) [`#955`](https://github.com/http-party/node-http-proxy/issues/955) + ### Commits - [dist] Version bump. 1.15.0 [`b98c75b`](https://github.com/http-party/node-http-proxy/commit/b98c75b1ff3ebdf7f78224eb0d9aa857af2db1d9) @@ -178,6 +183,10 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - Fix formatting of the `headers` option [`#974`](https://github.com/http-party/node-http-proxy/pull/974) - Set the x-forwarded-host flag when xfwd is enabled [`#967`](https://github.com/http-party/node-http-proxy/pull/967) +### Fixed + +- Sanitize header keys before setting them (#997) [`#996`](https://github.com/http-party/node-http-proxy/issues/996) + ### Commits - [dist] Update LICENSE to reflect 2015 changes. [`f345a1a`](https://github.com/http-party/node-http-proxy/commit/f345a1ac2dde1884e72b952a685a0a1796059f14) @@ -201,7 +210,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Merged - README.md: summary to specify reverse proxy [`#932`](https://github.com/http-party/node-http-proxy/pull/932) -- fix(common) urlJoin replace: ":/" -> "http?s:/" [`#947`](https://github.com/http-party/node-http-proxy/pull/947) +- fix(common) urlJoin replace: ":/" -> "http?s:/" [`#947`](https://github.com/http-party/node-http-proxy/pull/947) - Update README.md [`#948`](https://github.com/http-party/node-http-proxy/pull/948) ### Commits @@ -346,6 +355,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Fixed +- Merge pull request #798 from damonmcminn/master [`#747`](https://github.com/http-party/node-http-proxy/issues/747) - Fix https://github.com/nodejitsu/node-http-proxy/issues/747 [`#747`](https://github.com/nodejitsu/node-http-proxy/issues/747) ### Commits @@ -783,6 +793,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Fixed - [fix] closes #547 [`#547`](https://github.com/http-party/node-http-proxy/issues/547) +- Merge pull request #539 from nodejitsu/fix-before-after [`#537`](https://github.com/http-party/node-http-proxy/issues/537) - [fix] add `type` to before and after to grab correct `passes`, fixes #537 [`#537`](https://github.com/http-party/node-http-proxy/issues/537) ### Commits @@ -853,7 +864,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [examples] update old examples [`7e44d36`](https://github.com/http-party/node-http-proxy/commit/7e44d3669bbd1b13e6452f265d52b22396f68b5d) - [docs] more short examples to the Readme [`0393b5d`](https://github.com/http-party/node-http-proxy/commit/0393b5da990bb45e873bb80d87a0bc9e4dd6a477) - [examples] updated old proxy examples [`e02317c`](https://github.com/http-party/node-http-proxy/commit/e02317ce86ff2dabd496cf7e2741e219a22ac817) -- [wip] Initial HTTPS->HTTP test, updated https-secure example. Work in progress, need to add more https tests [`33a2462`](https://github.com/http-party/node-http-proxy/commit/33a2462d28c7d1fa26b03bcf290242ff7cd83e7a) +- [wip] Initial HTTPS->HTTP test, updated https-secure example. Work in progress, need to add more https tests [`33a2462`](https://github.com/http-party/node-http-proxy/commit/33a2462d28c7d1fa26b03bcf290242ff7cd83e7a) - [docs] readme [`886a870`](https://github.com/http-party/node-http-proxy/commit/886a8707078f59d0467b34686455bb5bdfadbc0c) - [examples] added error-handling using callbacks and HTTP-to-HTTPS examples [`d7064f2`](https://github.com/http-party/node-http-proxy/commit/d7064f2e1e149fe870cbb158932cb99f9f192fce) - [examples] updated old examples [`588327c`](https://github.com/http-party/node-http-proxy/commit/588327c2c4392618b515164989f08ef20a30842b) @@ -1287,6 +1298,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Fixed +- Merge pull request #256 from nodejitsu/changelog [`#137`](https://github.com/http-party/node-http-proxy/issues/137) - [misc] Updating the changelog. Close #137 [`#137`](https://github.com/http-party/node-http-proxy/issues/137) ### Commits @@ -1405,7 +1417,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - grammar correction [`729496d`](https://github.com/http-party/node-http-proxy/commit/729496d2898612969f5369e7f1c313cb4034f96c) - [dist] Test runner depends on `async` [`219b0ff`](https://github.com/http-party/node-http-proxy/commit/219b0ff8f8780cde4714267273b0a1637c84679f) - [test fix] Remove unnecessary console.log in tests/websocket/websocket-proxy-test.js [`f188f4f`](https://github.com/http-party/node-http-proxy/commit/f188f4ffd8c47b6312cd88c28de7e5ac63565047) -- [test refactor] `test/core/{run => run-single}` [`004be38`](https://github.com/http-party/node-http-proxy/commit/004be38048792d6f1d3efb361a5e7e66d5dbee8d) +- [test refactor] `test/core/{run => run-single}` [`004be38`](https://github.com/http-party/node-http-proxy/commit/004be38048792d6f1d3efb361a5e7e66d5dbee8d) ## [v0.7.3](https://github.com/http-party/node-http-proxy/compare/v0.7.2...v0.7.3) - 2011-10-03 @@ -1445,7 +1457,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [examples] Updated examples to v0.7.x API. [`8fc8d96`](https://github.com/http-party/node-http-proxy/commit/8fc8d966c4681d514af00516b348105608e13382) - [examples] More fixes to examples. [`549360a`](https://github.com/http-party/node-http-proxy/commit/549360a462c134cc2b02301070209084ec94c393) - [fix] x-forwarded http headers should set properly. [`2677bb6`](https://github.com/http-party/node-http-proxy/commit/2677bb6c44244ea0b584db744955bedf7aee2c62) -- [fix] connection.socket -> socket for source of x-forwarded-for data [`1f33943`](https://github.com/http-party/node-http-proxy/commit/1f33943b231cdf2cb619977801c7b0d4e98ab6df) +- [fix] connection.socket -> socket for source of x-forwarded-for data [`1f33943`](https://github.com/http-party/node-http-proxy/commit/1f33943b231cdf2cb619977801c7b0d4e98ab6df) - Make sure the target port is an integer [`5ba25aa`](https://github.com/http-party/node-http-proxy/commit/5ba25aa3451f131b6c6c8892848a4f236f5b859e) ## [v0.7.0](https://github.com/http-party/node-http-proxy/compare/v0.6.6...v0.7.0) - 2011-09-10 @@ -1601,7 +1613,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). ### Commits -- [fix] Change sec-websocket-location header when proxying WSS --> WS. Added test coverage for this scenario [`028d204`](https://github.com/http-party/node-http-proxy/commit/028d2044e71d70b7bc21d339de29e2275c3be5c2) +- [fix] Change sec-websocket-location header when proxying WSS --> WS. Added test coverage for this scenario [`028d204`](https://github.com/http-party/node-http-proxy/commit/028d2044e71d70b7bc21d339de29e2275c3be5c2) - [dist] Version bump. 0.5.9 [`57ca62c`](https://github.com/http-party/node-http-proxy/commit/57ca62c878c9a953f2344719556e05492ece3435) ## [v0.5.8](https://github.com/http-party/node-http-proxy/compare/v0.5.7...v0.5.8) - 2011-05-21 diff --git a/package-lock.json b/package-lock.json index b77a784f0..ac0cc0f63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.17.0", + "version": "1.18.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -14,22 +14,22 @@ } }, "@babel/generator": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.5.5.tgz", - "integrity": "sha512-ETI/4vyTSxTzGnU2c49XHv2zhExkv9JHLTwDAFz85kmcwuShvYG2H08FwgIguQf4JC75CBnXAUM5PqeF4fj0nQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.0.tgz", + "integrity": "sha512-Ms8Mo7YBdMMn1BYuNtKuP/z0TgEIhbcyB8HVR6PPNYp4P61lMsABiS4A3VG1qznjXVCf3r+fVHhm4efTYVsySA==", "dev": true, "requires": { - "@babel/types": "^7.5.5", + "@babel/types": "^7.6.0", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0", "trim-right": "^1.0.1" }, "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true } } @@ -75,34 +75,34 @@ } }, "@babel/parser": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.5.5.tgz", - "integrity": "sha512-E5BN68cqR7dhKan1SfqgPGhQ178bkVKpXTPEXnFJBrEt8/DKRZlybmy+IgYLTeN7tp1R5Ccmbm2rBk17sHYU3g==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.0.tgz", + "integrity": "sha512-+o2q111WEx4srBs7L9eJmcwi655eD8sXniLqMB93TBK9GrNzGrxDWSjiqz2hLU0Ha8MTXFIP0yd9fNdP+m43ZQ==", "dev": true }, "@babel/template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", - "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", + "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.4.4", - "@babel/types": "^7.4.4" + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" } }, "@babel/traverse": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.5.5.tgz", - "integrity": "sha512-MqB0782whsfffYfSjH4TM+LMjrJnhCNEDMDIjeTpl+ASaUvxcjoiVCo/sM1GhS1pHOXYfWVCYneLjMckuUxDaQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.0.tgz", + "integrity": "sha512-93t52SaOBgml/xY74lsmt7xOR4ufYvhb5c5qiM6lu4J/dWGMAfAh6eKw4PjLes6DI6nQgearoxnFJk60YchpvQ==", "dev": true, "requires": { "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.5.5", + "@babel/generator": "^7.6.0", "@babel/helper-function-name": "^7.1.0", "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.5.5", - "@babel/types": "^7.5.5", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" @@ -116,48 +116,28 @@ "requires": { "ms": "^2.1.1" } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true } } }, "@babel/types": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.5.5.tgz", - "integrity": "sha512-s63F9nJioLqOlW3UkyMd+BYhXt44YuaFm/VV0VwuteqjYwRrObkU7ra9pY4wAJR3oXi8hJrMcrcJdO/HH33vtw==", + "version": "7.6.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz", + "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", "dev": true, "requires": { "esutils": "^2.0.2", "lodash": "^4.17.13", "to-fast-properties": "^2.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - } } }, "accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "dev": true, "requires": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" + "mime-types": "~2.1.24", + "negotiator": "0.6.2" } }, "after": { @@ -218,33 +198,27 @@ "dev": true }, "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "dev": true }, "auto-changelog": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-1.15.0.tgz", - "integrity": "sha512-TnF15fXgJUOHdAzbMnbSzKq+0lK6NFVAssShYJJDykLduUO1xqHSzhwZXYa6ZkSTMARh4F7gz3W74ly0pLJ1vw==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/auto-changelog/-/auto-changelog-1.16.1.tgz", + "integrity": "sha512-1OMUN5UWWhKtlEMpGUfbLFcZHDf4IXMNU4SsGs44xTlSBhjgTOx9ukbahoC7hTqIm6+sRAnlAbLY4UjbDZY18A==", "dev": true, "requires": { - "commander": "^2.20.0", - "core-js": "^3.1.4", + "commander": "^3.0.1", + "core-js": "^3.2.1", "handlebars": "^4.1.2", "lodash.uniqby": "^4.7.0", "node-fetch": "^2.6.0", "parse-github-url": "^1.0.2", - "regenerator-runtime": "^0.13.2", - "semver": "^6.1.1" + "regenerator-runtime": "^0.13.3", + "semver": "^6.3.0" }, "dependencies": { - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -287,9 +261,9 @@ } }, "blob": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", - "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", "dev": true }, "brace-expansion": { @@ -393,13 +367,10 @@ "dev": true }, "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": ">= 1.0.0" - } + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.1.tgz", + "integrity": "sha512-UNgvDd+csKdc9GD4zjtkHKQbT8Aspt2jCBqNSPp53vAS0L1tS9sXB2TCEOPHJ7kt9bN/niWkYj8T3RQSoMXdSQ==", + "dev": true }, "commondir": { "version": "1.0.1", @@ -450,6 +421,14 @@ "dev": true, "requires": { "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, "cookie": { @@ -488,11 +467,11 @@ } }, "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "decamelize": { @@ -523,9 +502,9 @@ "dev": true }, "engine.io": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.0.tgz", - "integrity": "sha512-mRbgmAtQ4GAlKwuPnnAvXXwdPhEx+jkc0OBCLrXuD/CRvwNK3AxRSnqK4FSqmAMRRHryVJP8TopOvmEaA64fKw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.3.2.tgz", + "integrity": "sha512-AsaA9KG7cWPXWHp5FvHdDWY3AMWeZ8x+2pUVLcn71qE5AtAzgGbxuclOytygskw8XGmiQafTmnI9Bix3uihu2w==", "dev": true, "requires": { "accepts": "~1.3.4", @@ -533,26 +512,39 @@ "cookie": "0.3.1", "debug": "~3.1.0", "engine.io-parser": "~2.1.0", - "ws": "~3.3.1" + "ws": "~6.1.0" }, "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", "dev": true, "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" + "async-limiter": "~1.0.0" } } } }, "engine.io-client": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", - "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.3.2.tgz", + "integrity": "sha512-y0CPINnhMvPuwtqXfsGuWE8BB66+B6wTtCofQDRecMQPYX3MYUZXFNKDhdrSe3EVjgOu4V3rxdeqN/Tr91IgbQ==", "dev": true, "requires": { "component-emitter": "1.2.1", @@ -563,34 +555,47 @@ "indexof": "0.0.1", "parseqs": "0.0.5", "parseuri": "0.0.5", - "ws": "~3.3.1", + "ws": "~6.1.0", "xmlhttprequest-ssl": "~1.5.4", "yeast": "0.1.2" }, "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", "dev": true, "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" + "async-limiter": "~1.0.0" } } } }, "engine.io-parser": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", - "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", "dev": true, "requires": { "after": "0.8.2", "arraybuffer.slice": "~0.0.7", "base64-arraybuffer": "0.1.5", - "blob": "0.0.4", + "blob": "0.0.5", "has-binary2": "~1.0.2" } }, @@ -659,11 +664,11 @@ } }, "follow-redirects": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", - "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", + "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", "requires": { - "debug": "^3.1.0" + "debug": "^3.0.0" } }, "foreground-child": { @@ -727,40 +732,24 @@ "dev": true }, "handlebars": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", - "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.2.0.tgz", + "integrity": "sha512-Kb4xn5Qh1cxAKvQnzNWZ512DhABzyFNmsaJf3OAkWNa4NkaqWcNI8Tao8Tasi0/F4JD9oyG0YxuFyvyR57d+Gw==", "dev": true, "requires": { "neo-async": "^2.6.0", "optimist": "^0.6.1", "source-map": "^0.6.1", "uglify-js": "^3.1.4" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "has-binary2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz", - "integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", "dev": true, "requires": { "isarray": "2.0.1" - }, - "dependencies": { - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "dev": true - } } }, "has-cors": { @@ -819,9 +808,9 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "is-arrayish": { @@ -842,6 +831,12 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -935,18 +930,6 @@ "requires": { "ms": "^2.1.1" } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -1023,6 +1006,12 @@ "path-exists": "^3.0.0" } }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, "lodash._baseassign": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", @@ -1121,14 +1110,6 @@ "requires": { "pify": "^4.0.1", "semver": "^5.6.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } } }, "merge-source-map": { @@ -1138,29 +1119,21 @@ "dev": true, "requires": { "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", "dev": true }, "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", "dev": true, "requires": { - "mime-db": "~1.33.0" + "mime-db": "1.40.0" } }, "minimatch": { @@ -1215,6 +1188,15 @@ "supports-color": "3.1.2" }, "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, "debug": { "version": "2.6.8", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", @@ -1223,18 +1205,24 @@ "requires": { "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", "dev": true }, "neo-async": { @@ -1584,15 +1572,15 @@ } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", "dev": true }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "set-blocking": { @@ -1608,17 +1596,28 @@ "dev": true }, "socket.io": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.0.tgz", - "integrity": "sha512-KS+3CNWWNtLbVN5j0/B+1hjxRzey+oTK6ejpAOoxMZis6aXeB8cUtfuvjHl97tuZx+t/qD/VyqFMjuzu2Js6uQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.2.0.tgz", + "integrity": "sha512-wxXrIuZ8AILcn+f1B4ez4hJTPG24iNgxBBDaJfT6MsyOhVYiTXWexGoPkd87ktJG8kQEcL/NBvRi64+9k4Kc0w==", "dev": true, "requires": { - "debug": "~3.1.0", - "engine.io": "~3.2.0", + "debug": "~4.1.0", + "engine.io": "~3.3.1", "has-binary2": "~1.0.2", "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.1.0", - "socket.io-parser": "~3.2.0" + "socket.io-client": "2.2.0", + "socket.io-parser": "~3.3.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, "socket.io-adapter": { @@ -1628,9 +1627,9 @@ "dev": true }, "socket.io-client": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.0.tgz", - "integrity": "sha512-TvKPpL0cBON5LduQfR8Rxrr+ktj70bLXGvqHCL3er5avBXruB3gpnbaud5ikFYVfANH1gCABAvo0qN8Axpg2ew==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.2.0.tgz", + "integrity": "sha512-56ZrkTDbdTLmBIyfFYesgOxsjcLnwAKoN4CiPyTVkMQj3zTUh0QAx3GbvIvLpFEOvQWu92yyWICxB0u7wkVbYA==", "dev": true, "requires": { "backo2": "1.0.2", @@ -1638,21 +1637,38 @@ "component-bind": "1.0.0", "component-emitter": "1.2.1", "debug": "~3.1.0", - "engine.io-client": "~3.2.0", + "engine.io-client": "~3.3.1", "has-binary2": "~1.0.2", "has-cors": "1.1.0", "indexof": "0.0.1", "object-component": "0.0.3", "parseqs": "0.0.5", "parseuri": "0.0.5", - "socket.io-parser": "~3.2.0", + "socket.io-parser": "~3.3.0", "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, "socket.io-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", - "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", + "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", "dev": true, "requires": { "component-emitter": "1.2.1", @@ -1660,24 +1676,33 @@ "isarray": "2.0.1" }, "dependencies": { - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true } } }, "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "spawn-wrap": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", - "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", + "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", "dev": true, "requires": { "foreground-child": "^1.5.6", @@ -1753,14 +1778,6 @@ "dev": true, "requires": { "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", - "dev": true - } } }, "strip-ansi": { @@ -1856,13 +1873,6 @@ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true, "optional": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true } } }, @@ -1952,6 +1962,14 @@ "async-limiter": "~1.0.0", "safe-buffer": "~5.1.0", "ultron": "~1.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } } }, "xmlhttprequest-ssl": { diff --git a/package.json b/package.json index be5968c0a..1f716758f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.17.0", + "version": "1.18.0", "repository": { "type": "git", "url": "https://github.com/http-party/node-http-proxy.git" From dba39668ba4c9ad461316e834b2d64b77e1ca88e Mon Sep 17 00:00:00 2001 From: Jason Date: Sun, 17 May 2020 17:16:55 -0400 Subject: [PATCH 554/556] Remove node6 support, add node12 to build (#1397) --- .travis.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a4676174c..5bb844250 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ sudo: false language: node_js node_js: - - "6" - "8" - "10" + - "12" script: - npm test after_success: diff --git a/package.json b/package.json index 1f716758f..a6c97bcdf 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "version": "auto-changelog -p && git add CHANGELOG.md" }, "engines": { - "node": ">=6.0.0" + "node": ">=8.0.0" }, "license": "MIT" } From 335aeeba2f0c286dc89c402eeb76af47834c89a3 Mon Sep 17 00:00:00 2001 From: Jason Date: Sun, 17 May 2020 17:18:42 -0400 Subject: [PATCH 555/556] Skip sending the proxyReq event when the expect header is present (#1447) * Skip sending the proxyReq event when the expect header is present * Adjust padding to match advisory Co-authored-by: Smylnycky, Jason M --- lib/http-proxy/passes/web-incoming.js | 4 +- ...lib-http-proxy-passes-web-incoming-test.js | 44 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/lib/http-proxy/passes/web-incoming.js b/lib/http-proxy/passes/web-incoming.js index 781b32692..7ae735514 100644 --- a/lib/http-proxy/passes/web-incoming.js +++ b/lib/http-proxy/passes/web-incoming.js @@ -129,7 +129,9 @@ module.exports = { // Enable developers to modify the proxyReq before headers are sent proxyReq.on('socket', function(socket) { - if(server) { server.emit('proxyReq', proxyReq, req, res, options); } + if(server && !proxyReq.getHeader('expect')) { + server.emit('proxyReq', proxyReq, req, res, options); + } }); // allow outgoing socket to timeout so that we could diff --git a/test/lib-http-proxy-passes-web-incoming-test.js b/test/lib-http-proxy-passes-web-incoming-test.js index 37f74204b..f6553d300 100644 --- a/test/lib-http-proxy-passes-web-incoming-test.js +++ b/test/lib-http-proxy-passes-web-incoming-test.js @@ -126,6 +126,50 @@ describe('#createProxyServer.web() using own http server', function () { http.request('http://127.0.0.1:8081', function() {}).end(); }); + it('should skip proxyReq event when handling a request with header "expect: 100-continue" [https://www.npmjs.com/advisories/1486]', function (done) { + var proxy = httpProxy.createProxyServer({ + target: 'http://127.0.0.1:8080', + }); + + proxy.on('proxyReq', function(proxyReq, req, res, options) { + proxyReq.setHeader('X-Special-Proxy-Header', 'foobar'); + }); + + 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.headers['x-special-proxy-header']).to.not.eql('foobar'); + done(); + }); + + proxyServer.listen('8081'); + source.listen('8080'); + + const postData = ''.padStart(1025, 'x'); + + const postOptions = { + hostname: '127.0.0.1', + port: 8081, + path: '/', + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': Buffer.byteLength(postData), + 'expect': '100-continue' + } + }; + + const req = http.request(postOptions, function() {}); + req.write(postData); + req.end(); + }); + it('should proxy the request and handle error via callback', function(done) { var proxy = httpProxy.createProxyServer({ target: 'http://127.0.0.1:8080' From 9b96cd725127a024dabebec6c7ea8c807272223d Mon Sep 17 00:00:00 2001 From: Jarrett Cruger Date: Sun, 17 May 2020 17:26:59 -0400 Subject: [PATCH 556/556] 1.18.1 --- CHANGELOG.md | 32 ++++++++++++++++++++------------ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06cb1b776..6c80d84c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -## [v1.18.0](https://github.com/http-party/node-http-proxy/compare/1.17.0...v1.18.0) - 2019-09-18 +## [v1.18.1](https://github.com/http-party/node-http-proxy/compare/1.18.0...v1.18.1) - 2020-05-17 + +### Merged + +- Skip sending the proxyReq event when the expect header is present [`#1447`](https://github.com/http-party/node-http-proxy/pull/1447) +- Remove node6 support, add node12 to build [`#1397`](https://github.com/http-party/node-http-proxy/pull/1397) + +## [1.18.0](https://github.com/http-party/node-http-proxy/compare/1.17.0...1.18.0) - 2019-09-18 ### Merged @@ -38,6 +45,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [dist] New test fixtures. [`7e4a0e5`](https://github.com/http-party/node-http-proxy/commit/7e4a0e511bc30c059216860153301de2cdd1e97f) - [dist] End of an era. [`a9b09cc`](https://github.com/http-party/node-http-proxy/commit/a9b09cce43f072db99fb5170030a05536177ccb7) +- [dist] Version bump. 1.18.0 [`9bbe486`](https://github.com/http-party/node-http-proxy/commit/9bbe486c5efcc356fb4d189ef38eee275bbde345) - [fix] Latest versions. [`59c4403`](https://github.com/http-party/node-http-proxy/commit/59c4403e9dc15ab9b19ee2a3f4aecbfc6c3d94c4) - [fix test] Update tests. [`dd1d08b`](https://github.com/http-party/node-http-proxy/commit/dd1d08b6319d1def729554446a5b0176978a8dad) - [dist] Update dependency ws to v3 [SECURITY] [`b00911c`](https://github.com/http-party/node-http-proxy/commit/b00911c93740a00c5cfbacbb91565cb6912ed255) @@ -885,7 +893,6 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [examples] fix the copyright header of example files [`e592c53`](https://github.com/http-party/node-http-proxy/commit/e592c53d1a23b7920d603a9e9ac294fc0e841f6d) - [feature] start working on the new server [`b79bd29`](https://github.com/http-party/node-http-proxy/commit/b79bd29d5e984f34b9c07fbdc803aed83b3fd0bb) - ENH: updated examples [`f566a42`](https://github.com/http-party/node-http-proxy/commit/f566a42e511f4a6a8f3620f64e05df209e61b64f) -- [examples] updated the modifyResponse-middleware example [`de3ff11`](https://github.com/http-party/node-http-proxy/commit/de3ff11656b4a847de3a63b28feed39b6c816480) - [examples] add example of gzip using the connect.compress() middleware [`2142c50`](https://github.com/http-party/node-http-proxy/commit/2142c506e08f56d52e1995da5506c3e032f19c3c) - [fix] refactor error handling [`601dbcb`](https://github.com/http-party/node-http-proxy/commit/601dbcbfe929af31995568b4f36b877245809058) - [tests] fixed according new refactor and added test to common.setupSocket() [`1cb967b`](https://github.com/http-party/node-http-proxy/commit/1cb967b90aaa5b9da57727b8acbd95108437797a) @@ -896,17 +903,17 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - ENH: added new https example, needs to be simplified before merge [`427d8d8`](https://github.com/http-party/node-http-proxy/commit/427d8d85369b0cd1d38afa0dd0f28ac98fa16001) - [test] proxystream test [`c961279`](https://github.com/http-party/node-http-proxy/commit/c9612798f1207a4c40b616608bf6274d79ad0e4d) - [lib] initial draft to websockets passes [`79f7f99`](https://github.com/http-party/node-http-proxy/commit/79f7f99528661162ae4153856888f078f666e017) -- [tests] added HTTPS to HTTPS test [`31d919b`](https://github.com/http-party/node-http-proxy/commit/31d919b0a3d0b7f574e88fc5eed093c6b1a53548) - [fix] minor [`7599cee`](https://github.com/http-party/node-http-proxy/commit/7599cee3fd03a5ce645e313f35557a41c9ac1aee) +- [tests] added HTTPS to HTTPS test [`31d919b`](https://github.com/http-party/node-http-proxy/commit/31d919b0a3d0b7f574e88fc5eed093c6b1a53548) - [feature] started working on error propagation, kinda sucks, gotta think it over [`9ab8749`](https://github.com/http-party/node-http-proxy/commit/9ab8749a9bec33b49c495975e8364336ad7be1a3) - [test] testing the onResponse proxy method [`27df8d7`](https://github.com/http-party/node-http-proxy/commit/27df8d72ad86d02cfce00a6e5c183d93dd50f97e) -- [docs] Update readme with more how to [`ae0faef`](https://github.com/http-party/node-http-proxy/commit/ae0faef5aa0080d742a9740f9cb38bfd54b7d97e) - [fix] remove duplicate [`10c0f11`](https://github.com/http-party/node-http-proxy/commit/10c0f11b68e39552051e508c7bf20d65d2d59177) - [tests] add more tests [`cedc5c4`](https://github.com/http-party/node-http-proxy/commit/cedc5c4bd2059585e1222ec4f03f09e8bcc808fc) +- [docs] Update readme with more how to [`ae0faef`](https://github.com/http-party/node-http-proxy/commit/ae0faef5aa0080d742a9740f9cb38bfd54b7d97e) - [tests] added test for socket.io proxying [`10a0db4`](https://github.com/http-party/node-http-proxy/commit/10a0db4f0dd4594839f9098b9d67130085a067bc) - [tests] added test HTTPS to HTTP using own server [`bbe3bfd`](https://github.com/http-party/node-http-proxy/commit/bbe3bfdf98255b82a185a798ff9f29e74615b6ca) -- [fix] quote [`c4ddc4e`](https://github.com/http-party/node-http-proxy/commit/c4ddc4edd324d9910a11eea14561a0e3b953f29c) - [examples] update the error-handling example using the new error handle way [`a1b25a1`](https://github.com/http-party/node-http-proxy/commit/a1b25a123b4ff71e731f9beb27c5e078acfead65) +- [fix] quote [`c4ddc4e`](https://github.com/http-party/node-http-proxy/commit/c4ddc4edd324d9910a11eea14561a0e3b953f29c) - ENH: updated README and added examples file. [`07091b5`](https://github.com/http-party/node-http-proxy/commit/07091b5077a40dfee29f6fd33ecb38d3fa25b801) - [test] passes/web.js (first 2 funcs) [`d40e4be`](https://github.com/http-party/node-http-proxy/commit/d40e4beb62381b962b6cf3254451de0a39f182b1) - [test] add test for forwardstream [`8fc3389`](https://github.com/http-party/node-http-proxy/commit/8fc33893672d26013c2b2ff396b777bcf1751527) @@ -916,17 +923,18 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [experiment] new api for proxying [`07cfa6b`](https://github.com/http-party/node-http-proxy/commit/07cfa6b981ff54d8d96eea6c9aa4b560ee3867ec) - [tests] the options got a problem and this test probe that timeout is not being set [`1d1ee88`](https://github.com/http-party/node-http-proxy/commit/1d1ee8858283d7c8984f1c1d6c5185b6822f9235) - new error propagation [`3a39e44`](https://github.com/http-party/node-http-proxy/commit/3a39e444ff68a74f6b586f0736bbd3f8a2511ca5) -- [examples] added concurrent proxy example [`04c1011`](https://github.com/http-party/node-http-proxy/commit/04c10113f7a3b568fb95b18f30e4aca3e059d961) - [fix] docs [`ec981c5`](https://github.com/http-party/node-http-proxy/commit/ec981c5b74bf43dd36c8ca89833b751f59f01d38) -- [test] started writing tests [`16eacfa`](https://github.com/http-party/node-http-proxy/commit/16eacfa961d2a2d80534e95eba83010ed6ab01b4) +- [examples] added concurrent proxy example [`04c1011`](https://github.com/http-party/node-http-proxy/commit/04c10113f7a3b568fb95b18f30e4aca3e059d961) - [fix] closes number #487 [`cde08fb`](https://github.com/http-party/node-http-proxy/commit/cde08fb2ee2df03c9457678d8e6776a5d89165b2) +- [test] started writing tests [`16eacfa`](https://github.com/http-party/node-http-proxy/commit/16eacfa961d2a2d80534e95eba83010ed6ab01b4) - [tests] added tests for websockets [`02007ed`](https://github.com/http-party/node-http-proxy/commit/02007ed0fb38f798436ae5669bb18d4f27496667) -- [examples] added forward example [`7a3f6df`](https://github.com/http-party/node-http-proxy/commit/7a3f6dfbcc80ba32fa81004438c637e8d29eb029) -- [fix] fixed options and server reference to can access them from passes functions [`90fb01d`](https://github.com/http-party/node-http-proxy/commit/90fb01d38ac5af7ef395547b24e985b6f63b4abc) -- mm test file [`1a7bef0`](https://github.com/http-party/node-http-proxy/commit/1a7bef0cda58243416a263075dc6eb51f22b6dec) - Revert "[fix] fixed options and server reference to can access them from passes functions" [`babdf53`](https://github.com/http-party/node-http-proxy/commit/babdf531fecd32f9af0963902909fcfa2cd374f1) +- mm test file [`1a7bef0`](https://github.com/http-party/node-http-proxy/commit/1a7bef0cda58243416a263075dc6eb51f22b6dec) +- [fix] fixed options and server reference to can access them from passes functions [`90fb01d`](https://github.com/http-party/node-http-proxy/commit/90fb01d38ac5af7ef395547b24e985b6f63b4abc) +- [examples] added forward example [`7a3f6df`](https://github.com/http-party/node-http-proxy/commit/7a3f6dfbcc80ba32fa81004438c637e8d29eb029) - [docs] add UPGRADING.md [`db12f6c`](https://github.com/http-party/node-http-proxy/commit/db12f6c24e22c034c698457cc28ff60c990b55a5) - DOC: Added error handling example [`32a4088`](https://github.com/http-party/node-http-proxy/commit/32a40889cedfd6b0d92224aa921700a7b7271c68) +- [examples] updated the modifyResponse-middleware example [`de3ff11`](https://github.com/http-party/node-http-proxy/commit/de3ff11656b4a847de3a63b28feed39b6c816480) - [test] test onError part, proxying to no where [`b85aa16`](https://github.com/http-party/node-http-proxy/commit/b85aa16e75401a223a947cde444d42cf7eeafb67) - ENH: updated agent options in `common.setupOutgoing` [`12cda56`](https://github.com/http-party/node-http-proxy/commit/12cda561afe534427a5f84da9d7e0beb64a8ecbc) - [fix] minor and short fixes [`e0faaaf`](https://github.com/http-party/node-http-proxy/commit/e0faaaf81152203b96f0313c68706468e7ee7357) @@ -1593,8 +1601,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [api doc test] node-http-proxy now emits `websocket:*` on important WebSocket events. Added tests for these features and updated some code docs [`4f85ca0`](https://github.com/http-party/node-http-proxy/commit/4f85ca04e425a7d4df1e46c9cadd6026eeed32f6) - [doc] Updated docco docs [`f0649d8`](https://github.com/http-party/node-http-proxy/commit/f0649d8d6a9f84ac61d5f173c585fa4307ffb3c3) - [doc] Added examples/latent-websocket-proxy.js [`fcfe846`](https://github.com/http-party/node-http-proxy/commit/fcfe84626fff15be21ac83ccd69b96bf3ca1f7a2) -- [doc] Add examples/standalone-websocket-proxy.js [`1ee8ae7`](https://github.com/http-party/node-http-proxy/commit/1ee8ae710497e239716f72d45e2f61ead3995dc3) - [doc] Added sample for custom error messages using the `proxyError` event [`4cdbf0e`](https://github.com/http-party/node-http-proxy/commit/4cdbf0e8729a0665904b577376240c00e56ad876) +- [doc] Add examples/standalone-websocket-proxy.js [`1ee8ae7`](https://github.com/http-party/node-http-proxy/commit/1ee8ae710497e239716f72d45e2f61ead3995dc3) - [dist] Version bump. 0.5.11 [`baf0b9e`](https://github.com/http-party/node-http-proxy/commit/baf0b9e25af53e2738812ff78614cc12966e99e3) - [doc] Small update to code docs [`9d9509f`](https://github.com/http-party/node-http-proxy/commit/9d9509f791c4c566629c2e323259885f1c3db7ed) - [minor] Add missing space [`b608a02`](https://github.com/http-party/node-http-proxy/commit/b608a029f8aa26f1a74a917e0bec0ac37e4615a0) @@ -1658,8 +1666,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - [doc] Update docco docs [`faf2618`](https://github.com/http-party/node-http-proxy/commit/faf2618cf3b53a972779514842bc4264ec9541fa) - [doc] Update README.md to reflect the new HTTPS to HTTP proxy capabilities [`abc01bc`](https://github.com/http-party/node-http-proxy/commit/abc01bce293f7c1a88f9be08b0540407d2b0f4a1) -- [doc] Update examples for HTTPS to HTTP proxying [`91737fa`](https://github.com/http-party/node-http-proxy/commit/91737fadb640f30d3cd959f29069537473207efd) - [doc test api] Improve node-http-proxy API to allow for HTTPS to HTTP proxying scenarios. Update tests accordingly. [`895f577`](https://github.com/http-party/node-http-proxy/commit/895f577744e3cbcbb5f479c4aacec5323bb001f7) +- [doc] Update examples for HTTPS to HTTP proxying [`91737fa`](https://github.com/http-party/node-http-proxy/commit/91737fadb640f30d3cd959f29069537473207efd) - [dist] Version bump. 0.5.4. Only good on node v0.4.7. See issue #48. [`c04eec1`](https://github.com/http-party/node-http-proxy/commit/c04eec1c370ca0eb212c96c0896c27b349f7ea97) - [minor] Update README.md to conform to Github flavored markdown [`32a15dd`](https://github.com/http-party/node-http-proxy/commit/32a15dd79d860343453c38a7eef8339d7b99718b) - [minor] Update README.md to conform to Github flavored markdown [`521fe27`](https://github.com/http-party/node-http-proxy/commit/521fe271853632563143fb4b76c032f7afa7831a) diff --git a/package-lock.json b/package-lock.json index ac0cc0f63..d614b95f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.18.0", + "version": "1.18.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a6c97bcdf..9fe81a26d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-proxy", - "version": "1.18.0", + "version": "1.18.1", "repository": { "type": "git", "url": "https://github.com/http-party/node-http-proxy.git"