Merge branch 'master' into experimental

This commit is contained in:
indexzero 2011-05-17 21:44:46 -04:00
commit 54dac80575
17 changed files with 760 additions and 598 deletions

4
.gitignore vendored
View File

@ -1 +1,3 @@
test/config.json
test/config.json
node_modules/
npm-debug.log

434
README.md
View File

@ -1,4 +1,4 @@
# node-http-proxy - v0.5.0
# node-http-proxy - v0.5.3
<img src="http://i.imgur.com/8fTt9.png" />
@ -23,14 +23,16 @@
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)
<pre>
curl http://npmjs.org/install.sh | sh
</pre>
```
curl http://npmjs.org/install.sh | sh
```
### Installing node-http-proxy
<pre>
npm install http-proxy
</pre>
```
npm install http-proxy
```
## Using node-http-proxy
@ -47,251 +49,262 @@ In each of these scenarios node-http-proxy can handle any of these types of requ
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
<pre>
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);
</pre>
``` 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
<pre>
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);
</pre>
``` 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)
<pre>
var http = require('http'),
httpProxy = require('http-proxy');
``` 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 = proxy.buffer(req);
//
// Create a proxy server with custom application logic
// Wait for two seconds then respond: this simulates
// performing async actions before proxying a request
//
httpProxy.createServer(function (req, res, proxy) {
//
// Buffer the request so that `data` and `end` events
// are not lost during async operation(s).
//
var buffer = proxy.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);
</pre>
### Proxy requests within another http server
<pre>
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a new instance of HttProxy to use in your server
//
var proxy = new httpProxy.HttpProxy();
//
// Create a regular http server and proxy its handler
//
http.createServer(function (req, res) {
//
// Put your custom server logic here, then proxy
//
setTimeout(function () {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 9000
});
}).listen(8001);
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);
</pre>
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.HttpProxy();
//
// 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:
<pre>
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'
}
};
</pre>
``` 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:
<pre>
var proxyServer = httpProxy.createServer(options);
proxyServer.listen(80);
</pre>
``` 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:
<pre>
var options = {
hostnameOnly, true,
router: {
'foo.com': '127.0.0.1:8001',
'bar.com': '127.0.0.1:8002'
}
``` js
var options = {
hostnameOnly: true,
router: {
'foo.com': '127.0.0.1:8001',
'bar.com': '127.0.0.1:8002'
}
</pre>
}
```
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 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:
<pre>
var proxyServerWithForwarding = httpProxy.createServer(9000, 'localhost', {
forward: {
port: 9000,
host: 'staging.com'
}
});
proxyServerWithForwarding.listen(80);
</pre>
``` 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'.
### 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:
<pre>
usage: node-http-proxy [options]
All options should be set with the syntax --option=value
``` js
usage: node-http-proxy [options]
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
</pre>
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
```
### Proxying over 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.
<pre>
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')
}
};
//
// 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({ https: true });
https.createServer(options.https, function (req, res) {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 8000
})
}).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);
</pre>
``` 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')
}
};
//
// 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({ https: true });
https.createServer(options.https, function (req, res) {
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 8000
})
}).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);
```
### Proxying WebSockets
Websockets are handled automatically when using the `httpProxy.createServer()`, but if you want to use it in conjunction with a stand-alone HTTP + WebSocket (such as [socket.io][5]) server here's how:
<pre>
var http = require('http'),
httpProxy = require('http-proxy');
``` js
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create an instance of node-http-proxy
//
var proxy = new httpProxy.HttpProxy();
var server = http.createServer(function (req, res) {
//
// Create an instance of node-http-proxy
// Proxy normal HTTP requests
//
var proxy = new httpProxy.HttpProxy();
var server = http.createServer(function (req, res) {
//
// Proxy normal HTTP requests
//
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 8000
})
proxy.proxyRequest(req, res, {
host: 'localhost',
port: 8000
})
});
server.on('upgrade', function(req, socket, head) {
//
// Proxy websocket requests too
//
proxy.proxyWebSocketRequest(req, socket, head, {
host: 'localhost',
port: 8000
});
server.on('upgrade', function(req, socket, head) {
//
// Proxy websocket requests too
//
proxy.proxyWebSocketRequest(req, socket, head, {
host: 'localhost',
port: 8000
});
});
</pre>
});
```
<br/>
### Why doesn't node-http-proxy have more advanced features like x, y, or z?
@ -299,10 +312,11 @@ Websockets are handled automatically when using the `httpProxy.createServer()`,
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.
## Run Tests
<pre>
vows test/*-test.js --spec
vows test/*-test.js --spec --https
</pre>
```
vows test/*-test.js --spec
vows test/*-test.js --spec --https
```
<br/>
### License
@ -336,4 +350,4 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[3]: https://github.com/nodejitsu/node-http-proxy/tree/v0.5.0/examples
[4]: http://www.ietf.org/rfc/rfc2616.txt
[5]: http://socket.io
[6]: http://github.com/nodejitsu/node-http-proxy/issues
[6]: http://github.com/nodejitsu/node-http-proxy/issues

View File

@ -26,18 +26,48 @@
<span class="kd">var</span> <span class="nx">util</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;util&#39;</span><span class="p">),</span>
<span class="nx">http</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">),</span>
<span class="nx">https</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;https&#39;</span><span class="p">),</span>
<span class="nx">events</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;events&#39;</span><span class="p">),</span>
<span class="nx">ProxyTable</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./proxy-table&#39;</span><span class="p">).</span><span class="nx">ProxyTable</span><span class="p">,</span>
<span class="nx">maxSockets</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <h3>Version 0.4.2</h3> </td> <td class="code"> <div class="highlight"><pre><span class="nx">exports</span><span class="p">.</span><span class="nx">version</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">2</span><span class="p">];</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h3>function _getAgent (host, port)</h3>
<span class="nx">maxSockets</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <h3>Version 0.5.3 // 5/17/2011</h3> </td> <td class="code"> <div class="highlight"><pre><span class="nx">exports</span><span class="p">.</span><span class="nx">version</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">];</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h3>function _getAgent (host, port, secure)</h3>
<h4>@host {string} Host of the agent to get</h4>
<h4>@port {number} Port of the agent to get</h4>
<p>Retreives an agent from the <code>http</code> module
and sets the <code>maxSockets</code> property appropriately.</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">_getAgent</span> <span class="p">(</span><span class="nx">host</span><span class="p">,</span> <span class="nx">port</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>TODO (indexzero): Make this configurable for http / https</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">agent</span> <span class="o">=</span> <span class="nx">http</span><span class="p">.</span><span class="nx">getAgent</span><span class="p">(</span><span class="nx">host</span><span class="p">,</span> <span class="nx">port</span><span class="p">);</span>
<h4>@secure {boolean} Value indicating whether or not to use HTTPS</h4>
<p>Retreives an agent from the <code>http</code> or <code>https</code> module
and sets the <code>maxSockets</code> property appropriately.</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">_getAgent</span> <span class="p">(</span><span class="nx">host</span><span class="p">,</span> <span class="nx">port</span><span class="p">,</span> <span class="nx">secure</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">agent</span> <span class="o">=</span> <span class="o">!</span><span class="nx">secure</span> <span class="o">?</span> <span class="nx">http</span><span class="p">.</span><span class="nx">getAgent</span><span class="p">(</span><span class="nx">host</span><span class="p">,</span> <span class="nx">port</span><span class="p">)</span> <span class="o">:</span> <span class="nx">https</span><span class="p">.</span><span class="nx">getAgent</span><span class="p">({</span>
<span class="nx">host</span><span class="o">:</span> <span class="nx">host</span><span class="p">,</span>
<span class="nx">port</span><span class="o">:</span> <span class="nx">port</span>
<span class="p">});</span>
<span class="nx">agent</span><span class="p">.</span><span class="nx">maxSockets</span> <span class="o">=</span> <span class="nx">maxSockets</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">agent</span><span class="p">;</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <h3>function _getProtocol (secure, outgoing)</h3>
<h4>@secure {Object|boolean} Settings for <code>https</code></h4>
<h4>@outgoing {Object} Outgoing request options</h4>
<p>Returns the appropriate protocol based on the settings in
<code>secure</code>. If the protocol is <code>https</code> this function will update
the options in <code>outgoing</code> as appropriate by adding <code>ca</code>, <code>key</code>,
and <code>cert</code> if they exist in <code>secure</code>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">_getProtocol</span> <span class="p">(</span><span class="nx">secure</span><span class="p">,</span> <span class="nx">outgoing</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">protocol</span> <span class="o">=</span> <span class="nx">secure</span> <span class="o">?</span> <span class="nx">https</span> <span class="o">:</span> <span class="nx">http</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">secure</span> <span class="o">===</span> <span class="s1">&#39;object&#39;</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">outgoing</span> <span class="o">=</span> <span class="nx">outgoing</span> <span class="o">||</span> <span class="p">{};</span>
<span class="p">[</span><span class="s1">&#39;ca&#39;</span><span class="p">,</span> <span class="s1">&#39;cert&#39;</span><span class="p">,</span> <span class="s1">&#39;key&#39;</span><span class="p">].</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">prop</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">secure</span><span class="p">[</span><span class="nx">prop</span><span class="p">])</span> <span class="p">{</span>
<span class="nx">outgoing</span><span class="p">[</span><span class="nx">prop</span><span class="p">]</span> <span class="o">=</span> <span class="nx">secure</span><span class="p">[</span><span class="nx">prop</span><span class="p">];</span>
<span class="p">}</span>
<span class="p">})</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">protocol</span><span class="p">;</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <h3>function getMaxSockets ()</h3>
<p>Returns the maximum number of sockets
@ -67,11 +97,10 @@ made by <strong>all</strong> instances of <code>HttpProxy</code></p>
<li>`httpProxy.createServer(9000, 'localhost', options)</li>
<li><code>httpPRoxy.createServer(function (req, res, proxy) { ... })</code></li>
</ul> </td> <td class="code"> <div class="highlight"><pre><span class="nx">exports</span><span class="p">.</span><span class="nx">createServer</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">args</span><span class="p">,</span> <span class="nx">callback</span><span class="p">,</span> <span class="nx">port</span><span class="p">,</span> <span class="nx">host</span><span class="p">,</span> <span class="nx">forward</span><span class="p">,</span>
<span class="nx">silent</span><span class="p">,</span> <span class="nx">options</span><span class="p">,</span> <span class="nx">proxy</span><span class="p">,</span> <span class="nx">server</span><span class="p">;</span>
<span class="nx">args</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">);</span>
<span class="nx">callback</span> <span class="o">=</span> <span class="k">typeof</span> <span class="nx">args</span><span class="p">[</span><span class="nx">args</span><span class="p">.</span><span class="nx">length</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">===</span> <span class="s1">&#39;function&#39;</span> <span class="o">&amp;&amp;</span> <span class="nx">args</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
<span class="kd">var</span> <span class="nx">args</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">arguments</span><span class="p">),</span>
<span class="nx">callback</span> <span class="o">=</span> <span class="k">typeof</span> <span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">===</span> <span class="s1">&#39;function&#39;</span> <span class="o">&amp;&amp;</span> <span class="nx">args</span><span class="p">.</span><span class="nx">shift</span><span class="p">(),</span>
<span class="nx">options</span> <span class="o">=</span> <span class="p">{},</span>
<span class="nx">port</span><span class="p">,</span> <span class="nx">host</span><span class="p">,</span> <span class="nx">forward</span><span class="p">,</span> <span class="nx">silent</span><span class="p">,</span> <span class="nx">proxy</span><span class="p">,</span> <span class="nx">server</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">args</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">port</span> <span class="o">=</span> <span class="nx">args</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
@ -86,21 +115,27 @@ made by <strong>all</strong> instances of <code>HttpProxy</code></p>
<span class="p">}</span>
<span class="nx">proxy</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">HttpProxy</span><span class="p">(</span><span class="nx">options</span><span class="p">);</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">http</span><span class="p">.</span><span class="nx">createServer</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">proxy</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;request&#39;</span><span class="p">,</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">request</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">host</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">url</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>If we were passed a callback to process the request
or response in some way, then call it.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">callback</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">proxy</span><span class="p">);</span>
<span class="nx">handler</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <p>If we were passed a callback to process the request
or response in some way, then call it.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">callback</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">proxy</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">port</span> <span class="o">&amp;&amp;</span> <span class="nx">host</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">proxy</span><span class="p">.</span><span class="nx">proxyRequest</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">port</span><span class="p">,</span> <span class="nx">host</span><span class="p">);</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">port</span> <span class="o">&amp;&amp;</span> <span class="nx">host</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>If we have a target host and port for the request
then proxy to the specified location.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">proxy</span><span class="p">.</span><span class="nx">proxyRequest</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">port</span><span class="o">:</span> <span class="nx">port</span><span class="p">,</span>
<span class="nx">host</span><span class="o">:</span> <span class="nx">host</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">proxy</span><span class="p">.</span><span class="nx">proxyTable</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">proxy</span><span class="p">.</span><span class="nx">proxyRequest</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">);</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">proxy</span><span class="p">.</span><span class="nx">proxyTable</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>If the proxy is configured with a ProxyTable
instance then use that before failing.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">proxy</span><span class="p">.</span><span class="nx">proxyRequest</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s1">&#39;Cannot proxy without port, host, or router.&#39;</span><span class="p">)</span>
<span class="k">else</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <p>Otherwise this server is improperly configured.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s1">&#39;Cannot proxy without port, host, or router.&#39;</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">};</span>
<span class="nx">server</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">https</span>
<span class="o">?</span> <span class="nx">https</span><span class="p">.</span><span class="nx">createServer</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">https</span><span class="p">,</span> <span class="nx">handler</span><span class="p">)</span>
<span class="o">:</span> <span class="nx">http</span><span class="p">.</span><span class="nx">createServer</span><span class="p">(</span><span class="nx">handler</span><span class="p">);</span>
<span class="nx">server</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;close&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">proxy</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>
@ -110,14 +145,19 @@ or response in some way, then call it.</p> </td> <td cla
<span class="nx">server</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;routes&#39;</span><span class="p">,</span> <span class="nx">routes</span><span class="p">);</span>
<span class="p">});</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <p>WebSocket support: if callback is empty tunnel
websocket request automatically</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">server</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;upgrade&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">socket</span><span class="p">,</span> <span class="nx">head</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>Tunnel websocket requests too</p> </td> <td class="code"> <div class="highlight"><pre>
<span class="nx">proxy</span><span class="p">.</span><span class="nx">proxyWebSocketRequest</span><span class="p">(</span><span class="nx">port</span><span class="p">,</span> <span class="nx">host</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>WebSocket support: if callback is empty tunnel
websocket request automatically</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">server</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;upgrade&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">socket</span><span class="p">,</span> <span class="nx">head</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Tunnel websocket requests too</p> </td> <td class="code"> <div class="highlight"><pre>
<span class="nx">proxy</span><span class="p">.</span><span class="nx">proxyWebSocketRequest</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">socket</span><span class="p">,</span> <span class="nx">head</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">port</span><span class="o">:</span> <span class="nx">port</span><span class="p">,</span>
<span class="nx">host</span><span class="o">:</span> <span class="nx">host</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="p">}</span>
</pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>Set the proxy on the server so it is available
to the consumer of the server</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">server</span><span class="p">.</span><span class="nx">proxy</span> <span class="o">=</span> <span class="nx">proxy</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">server</span><span class="p">;</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <h3>function HttpProxy (options)</h3>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <h3>function HttpProxy (options)</h3>
<h4>@options {Object} Options for this instance.</h4>
@ -139,17 +179,19 @@ for managing the life-cycle of streaming reverse proxyied HTTP requests.</p>
</code></pre> </td> <td class="code"> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">HttpProxy</span> <span class="o">=</span> <span class="nx">exports</span><span class="p">.</span><span class="nx">HttpProxy</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">events</span><span class="p">.</span><span class="nx">EventEmitter</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="nx">options</span> <span class="o">=</span> <span class="nx">options</span> <span class="o">||</span> <span class="p">{};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">options</span> <span class="o">=</span> <span class="nx">options</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
<span class="nx">options</span> <span class="o">=</span> <span class="nx">options</span> <span class="o">||</span> <span class="p">{};</span>
<span class="k">this</span><span class="p">.</span><span class="nx">forward</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">forward</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">https</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">https</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">changeOrigin</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">changeOrigin</span> <span class="o">||</span> <span class="kc">false</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">router</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">proxyTable</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ProxyTable</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">router</span><span class="p">,</span> <span class="nx">options</span><span class="p">.</span><span class="nx">silent</span><span class="p">,</span> <span class="nx">options</span><span class="p">.</span><span class="nx">hostnameOnly</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">proxyTable</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;routes&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">routes</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;routes&#39;</span><span class="p">,</span> <span class="nx">routes</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Inherit from events.EventEmitter</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">util</span><span class="p">.</span><span class="nx">inherits</span><span class="p">(</span><span class="nx">HttpProxy</span><span class="p">,</span> <span class="nx">events</span><span class="p">.</span><span class="nx">EventEmitter</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <h3>function buffer (obj)</h3>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Inherit from events.EventEmitter</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">util</span><span class="p">.</span><span class="nx">inherits</span><span class="p">(</span><span class="nx">HttpProxy</span><span class="p">,</span> <span class="nx">events</span><span class="p">.</span><span class="nx">EventEmitter</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <h3>function buffer (obj)</h3>
<h4>@obj {Object} Object to pause events from</h4>
@ -167,7 +209,7 @@ the async operation has completed, otherwise these
<p><strong>Attribution:</strong> This approach is based heavily on
<a href="https://github.com/senchalabs/connect/blob/master/lib/utils.js#L157">Connect</a>.
However, this is not a big leap from the implementation in node-http-proxy &lt; 0.4.0.
However, this is not a big leap from the implementation in node-http-proxy &lt; 0.4.0.
This simply chooses to manage the scope of the events on a new Object literal as opposed to
<a href="https://github.com/nodejitsu/node-http-proxy/blob/v0.3.1/lib/node-http-proxy.js#L154">on the HttpProxy instance</a>.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">HttpProxy</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">buffer</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">onData</span><span class="p">,</span> <span class="nx">onEnd</span><span class="p">,</span> <span class="nx">events</span> <span class="o">=</span> <span class="p">[];</span>
@ -192,51 +234,54 @@ This simply chooses to manage the scope of the events on a new Object literal a
<span class="p">}</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <h3>function close ()</h3>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</a> </div> <h3>function close ()</h3>
<p>Frees the resources associated with this instance,
if they exist. </p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">HttpProxy</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">close</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">proxyTable</span><span class="p">)</span> <span class="k">this</span><span class="p">.</span><span class="nx">proxyTable</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <h3>function proxyRequest (req, res, [port, host, paused])</h3>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <h3>function proxyRequest (req, res, [port, host, paused])</h3>
<h4>@req {ServerRequest} Incoming HTTP Request to proxy.</h4>
<h4>@res {ServerResponse} Outgoing HTTP Request to write proxied data to.</h4>
<h4>@port {number} <strong>Optional</strong> Port to use on the proxy target host.</h4>
<h4>@options {Object} Options for the outgoing proxy request.</h4>
<h4>@host {string} <strong>Optional</strong> Host of the proxy target.</h4>
<h4>@buffer {Object} <strong>Optional</strong> Result from <code>httpProxy.buffer(req)</code></h4> </td> <td class="code"> <div class="highlight"><pre><span class="nx">HttpProxy</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">proxyRequest</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">port</span><span class="p">,</span> <span class="nx">host</span><span class="p">,</span> <span class="nx">buffer</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span> <span class="nx">reverseProxy</span><span class="p">,</span> <span class="nx">location</span><span class="p">,</span> <span class="nx">errState</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">opts</span><span class="p">;</span>
</pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Check the proxy table for this instance to see if we need
<pre><code>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.
</code></pre> </td> <td class="code"> <div class="highlight"><pre><span class="nx">HttpProxy</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">proxyRequest</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span> <span class="nx">errState</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">location</span><span class="p">,</span> <span class="nx">outgoing</span><span class="p">,</span> <span class="nx">protocol</span><span class="p">,</span> <span class="nx">reverseProxy</span><span class="p">;</span>
</pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p>Create an empty options hash if none is passed.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">options</span> <span class="o">=</span> <span class="nx">options</span> <span class="o">||</span> <span class="p">{};</span>
</pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">&#182;</a> </div> <p>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 <code>port</code> and <code>host</code>
arguments are supplied to <code>proxyRequest</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">proxyTable</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">host</span><span class="p">)</span> <span class="p">{</span>
arguments are supplied to <code>proxyRequest</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">proxyTable</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">options</span><span class="p">.</span><span class="nx">host</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">location</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">proxyTable</span><span class="p">.</span><span class="nx">getProxyLocation</span><span class="p">(</span><span class="nx">req</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>If no location is returned from the ProxyTable instance
</pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">&#182;</a> </div> <p>If no location is returned from the ProxyTable instance
then respond with <code>404</code> since we do not have a valid proxy target.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">location</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="mi">404</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span>
</pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</a> </div> <p>When using the ProxyTable in conjunction with an HttpProxy instance
</pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">&#182;</a> </div> <p>When using the ProxyTable in conjunction with an HttpProxy instance
only the following arguments are valid:</p>
<ul>
<li><code>proxy.proxyRequest(req, res, port, host, buffer)</code>: This will be skipped</li>
<li><code>proxy.proxyRequest(req, res, buffer)</code>: Buffer will get updated appropriately</li>
<li><code>proxy.proxyRequest(req, res)</code>: No effect <code>undefined = undefined</code> </li>
</ul> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">buffer</span> <span class="o">=</span> <span class="nx">port</span><span class="p">;</span>
<span class="nx">port</span> <span class="o">=</span> <span class="nx">location</span><span class="p">.</span><span class="nx">port</span><span class="p">;</span>
<span class="nx">host</span> <span class="o">=</span> <span class="nx">location</span><span class="p">.</span><span class="nx">host</span><span class="p">;</span>
<li><code>proxy.proxyRequest(req, res, { host: 'localhost' })</code>: This will be skipped</li>
<li><code>proxy.proxyRequest(req, res, { buffer: buffer })</code>: Buffer will get updated appropriately</li>
<li><code>proxy.proxyRequest(req, res)</code>: Options will be assigned appropriately. </li>
</ul> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">options</span><span class="p">.</span><span class="nx">port</span> <span class="o">=</span> <span class="nx">location</span><span class="p">.</span><span class="nx">port</span><span class="p">;</span>
<span class="nx">options</span><span class="p">.</span><span class="nx">host</span> <span class="o">=</span> <span class="nx">location</span><span class="p">.</span><span class="nx">host</span><span class="p">;</span>
<span class="p">}</span>
</pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>Emit the <code>start</code> event indicating that we have begun the proxy operation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">this</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;start&#39;</span><span class="p">,</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">host</span><span class="p">,</span> <span class="nx">port</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p>If forwarding is enabled for this instance, foward proxy the
specified request to the address provided in <code>this.options.forward</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">forward</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;forward&#39;</span><span class="p">,</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">forward</span><span class="p">.</span><span class="nx">host</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">forward</span><span class="p">.</span><span class="nx">port</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-24">&#182;</a> </div> <p>Add <code>x-forwarded-for</code> header to availible client IP to apps behind proxy</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">req</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;x-forwarded-for&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">connection</span><span class="p">.</span><span class="nx">remoteAddress</span><span class="p">;</span>
</pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">&#182;</a> </div> <p>Emit the <code>start</code> event indicating that we have begun the proxy operation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">this</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;start&#39;</span><span class="p">,</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">&#182;</a> </div> <p>If forwarding is enabled for this instance, foward proxy the
specified request to the address provided in <code>this.forward</code></p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">forward</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;forward&#39;</span><span class="p">,</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">forward</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nx">_forwardRequest</span><span class="p">(</span><span class="nx">req</span><span class="p">);</span>
<span class="p">}</span>
</pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">&#182;</a> </div> <h4>function proxyError (err)</h4>
</pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">&#182;</a> </div> <h4>function proxyError (err)</h4>
<h4>@err {Error} Error contacting the proxy target</h4>
@ -252,28 +297,30 @@ contacting the proxy target at <code>host</code> / <code>port</code>.</p>
<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span>
<span class="kd">var</span> <span class="nx">opts</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">host</span><span class="o">:</span> <span class="nx">host</span><span class="p">,</span>
<span class="nx">port</span><span class="o">:</span> <span class="nx">port</span><span class="p">,</span>
<span class="nx">agent</span><span class="o">:</span> <span class="nx">_getAgent</span><span class="p">(</span><span class="nx">host</span><span class="p">,</span> <span class="nx">port</span><span class="p">),</span>
<span class="nx">outgoing</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">host</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">host</span><span class="p">,</span>
<span class="nx">port</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">port</span><span class="p">,</span>
<span class="nx">agent</span><span class="o">:</span> <span class="nx">_getAgent</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">host</span><span class="p">,</span> <span class="nx">options</span><span class="p">.</span><span class="nx">port</span><span class="p">,</span> <span class="nx">options</span><span class="p">.</span><span class="nx">https</span> <span class="o">||</span> <span class="k">this</span><span class="p">.</span><span class="nx">https</span><span class="p">),</span>
<span class="nx">method</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">method</span><span class="p">,</span>
<span class="nx">path</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">url</span><span class="p">,</span>
<span class="nx">headers</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">headers</span>
<span class="p">};</span>
</pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">&#182;</a> </div> <p>Force the <code>connection</code> header to be 'close' until
node.js core re-implements 'keep-alive'.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">opts</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;connection&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;close&#39;</span><span class="p">;</span>
</pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">&#182;</a> </div> <p>Open new HTTP request to internal resource with will act as a reverse proxy pass</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">reverseProxy</span> <span class="o">=</span> <span class="nx">http</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="nx">opts</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
</pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-24">&#182;</a> </div> <p>Process the <code>reverseProxy</code> <code>response</code> when it's received.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">connection</span><span class="p">)</span> <span class="p">{</span>
</pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-28">&#182;</a> </div> <p>Force the <code>connection</code> header to be 'close' until
node.js core re-implements 'keep-alive'.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">outgoing</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;connection&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;close&#39;</span><span class="p">;</span>
<span class="nx">protocol</span> <span class="o">=</span> <span class="nx">_getProtocol</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">https</span> <span class="o">||</span> <span class="k">this</span><span class="p">.</span><span class="nx">https</span><span class="p">,</span> <span class="nx">outgoing</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-29">&#182;</a> </div> <p>Open new HTTP request to internal resource with will act as a reverse proxy pass</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">reverseProxy</span> <span class="o">=</span> <span class="nx">protocol</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="nx">outgoing</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
</pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">&#182;</a> </div> <p>Process the <code>reverseProxy</code> <code>response</code> when it's received.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">connection</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">connection</span><span class="p">)</span> <span class="nx">response</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">connection</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">connection</span><span class="p">;</span>
<span class="k">else</span> <span class="nx">response</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">connection</span> <span class="o">=</span> <span class="s1">&#39;close&#39;</span><span class="p">;</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">&#182;</a> </div> <p>Set the headers of the client response</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">res</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">statusCode</span><span class="p">,</span> <span class="nx">response</span><span class="p">.</span><span class="nx">headers</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">&#182;</a> </div> <p><code>response.statusCode === 304</code>: No 'data' event and no 'end'</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">statusCode</span> <span class="o">===</span> <span class="mi">304</span><span class="p">)</span> <span class="p">{</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">&#182;</a> </div> <p>Set the headers of the client response</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">res</span><span class="p">.</span><span class="nx">writeHead</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">statusCode</span><span class="p">,</span> <span class="nx">response</span><span class="p">.</span><span class="nx">headers</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">&#182;</a> </div> <p><code>response.statusCode === 304</code>: No 'data' event and no 'end'</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">statusCode</span> <span class="o">===</span> <span class="mi">304</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">&#182;</a> </div> <p>For each data <code>chunk</code> received from the <code>reverseProxy</code>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-33">&#182;</a> </div> <p>For each data <code>chunk</code> received from the <code>reverseProxy</code>
<code>response</code> write it to the outgoing <code>res</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">response</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">chunk</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">!==</span> <span class="s1">&#39;HEAD&#39;</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">chunk</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-28">&#182;</a> </div> <p>When the <code>reverseProxy</code> <code>response</code> ends, end the
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-34">&#182;</a> </div> <p>When the <code>reverseProxy</code> <code>response</code> ends, end the
corresponding outgoing <code>res</code> unless we have entered
an error state. In which case, assume <code>res.end()</code> has
already been called and the 'error' event listener
@ -281,164 +328,182 @@ removed.</p> </td> <td class="code"> <div
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">errState</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="nx">proxyError</span><span class="p">);</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
</pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-35">&#182;</a> </div> <p>Emit the <code>end</code> event now that we have completed proxying</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">self</span><span class="p">.</span><span class="nx">emit</span><span class="p">(</span><span class="s1">&#39;end&#39;</span><span class="p">,</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">});</span>
</pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-29">&#182;</a> </div> <p>Handle 'error' events from the <code>reverseProxy</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">once</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="nx">proxyError</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">&#182;</a> </div> <p>For each data <code>chunk</code> received from the incoming
</pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-36">&#182;</a> </div> <p>Handle 'error' events from the <code>reverseProxy</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">once</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="nx">proxyError</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-37">&#182;</a> </div> <p>For each data <code>chunk</code> received from the incoming
<code>req</code> write it to the <code>reverseProxy</code> request.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">req</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">chunk</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">errState</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">chunk</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">&#182;</a> </div> <p>When the incoming <code>req</code> ends, end the corresponding <code>reverseProxy</code>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-38"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-38">&#182;</a> </div> <p>When the incoming <code>req</code> ends, end the corresponding <code>reverseProxy</code>
request unless we have entered an error state. </p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">req</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;end&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">errState</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-32"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-32">&#182;</a> </div> <p>If we have been passed buffered data, resume it.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">buffer</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">errState</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">buffer</span><span class="p">.</span><span class="nx">resume</span><span class="p">();</span>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-39">&#182;</a> </div> <p>If we have been passed buffered data, resume it.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">buffer</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">errState</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">options</span><span class="p">.</span><span class="nx">buffer</span><span class="p">.</span><span class="nx">resume</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">};</span>
</pre></div> </td> </tr> <tr id="section-33"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-33">&#182;</a> </div> <h3>@private function _forwardRequest (req)</h3>
</pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-40">&#182;</a> </div> <h3>@private function _forwardRequest (req)</h3>
<h4>@req {ServerRequest} Incoming HTTP Request to proxy.</h4>
<p>Forwards the specified <code>req</code> to the location specified
by <code>this.options.forward</code> ignoring errors and the subsequent response.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">HttpProxy</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">_forwardRequest</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span> <span class="nx">port</span><span class="p">,</span> <span class="nx">host</span><span class="p">,</span> <span class="nx">forwardProxy</span><span class="p">,</span> <span class="nx">opts</span><span class="p">;</span>
by <code>this.forward</code> ignoring errors and the subsequent response.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">HttpProxy</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">_forwardRequest</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span> <span class="nx">port</span><span class="p">,</span> <span class="nx">host</span><span class="p">,</span> <span class="nx">outgoing</span><span class="p">,</span> <span class="nx">protocol</span><span class="p">,</span> <span class="nx">forwardProxy</span><span class="p">;</span>
<span class="nx">port</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">forward</span><span class="p">.</span><span class="nx">port</span><span class="p">;</span>
<span class="nx">host</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">options</span><span class="p">.</span><span class="nx">forward</span><span class="p">.</span><span class="nx">host</span><span class="p">;</span>
<span class="nx">port</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">forward</span><span class="p">.</span><span class="nx">port</span><span class="p">;</span>
<span class="nx">host</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">forward</span><span class="p">.</span><span class="nx">host</span><span class="p">;</span>
<span class="nx">opts</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">outgoing</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">host</span><span class="o">:</span> <span class="nx">host</span><span class="p">,</span>
<span class="nx">port</span><span class="o">:</span> <span class="nx">port</span><span class="p">,</span>
<span class="nx">agent</span><span class="o">:</span> <span class="nx">_getAgent</span><span class="p">(</span><span class="nx">host</span><span class="p">,</span> <span class="nx">port</span><span class="p">),</span>
<span class="nx">agent</span><span class="o">:</span> <span class="nx">_getAgent</span><span class="p">(</span><span class="nx">host</span><span class="p">,</span> <span class="nx">port</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="nx">forward</span><span class="p">.</span><span class="nx">https</span><span class="p">),</span>
<span class="nx">method</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">method</span><span class="p">,</span>
<span class="nx">path</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">url</span><span class="p">,</span>
<span class="nx">headers</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">headers</span>
<span class="p">};</span>
</pre></div> </td> </tr> <tr id="section-34"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-34">&#182;</a> </div> <p>Force the <code>connection</code> header to be 'close' until
node.js core re-implements 'keep-alive'.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">opts</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;connection&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;close&#39;</span><span class="p">;</span>
</pre></div> </td> </tr> <tr id="section-35"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-35">&#182;</a> </div> <p>Open new HTTP request to internal resource with will act as a reverse proxy pass</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">forwardProxy</span> <span class="o">=</span> <span class="nx">http</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="nx">opts</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-36"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-36">&#182;</a> </div> <p>Ignore the response from the forward proxy since this is a 'fire-and-forget' proxy.
</pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-41">&#182;</a> </div> <p>Force the <code>connection</code> header to be 'close' until
node.js core re-implements 'keep-alive'.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">outgoing</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="s1">&#39;connection&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;close&#39;</span><span class="p">;</span>
<span class="nx">protocol</span> <span class="o">=</span> <span class="nx">_getProtocol</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">forward</span><span class="p">.</span><span class="nx">https</span><span class="p">,</span> <span class="nx">outgoing</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">&#182;</a> </div> <p>Open new HTTP request to internal resource with will act as a reverse proxy pass</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">forwardProxy</span> <span class="o">=</span> <span class="nx">protocol</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="nx">outgoing</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">&#182;</a> </div> <p>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.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="p">});</span>
</pre></div> </td> </tr> <tr id="section-37"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-37">&#182;</a> </div> <p>Add a listener for the connection timeout event.</p>
</pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">&#182;</a> </div> <p>Add a listener for the connection timeout event.</p>
<p>Remark: Ignoring this error in the event
forward target doesn't exist.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">forwardProxy</span><span class="p">.</span><span class="nx">once</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span> <span class="p">});</span></pre></div> </td> </tr> <tr id="section-38"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-38">&#182;</a> </div> <p>Chunk the client request body as chunks from the proxied request come in</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">req</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">chunk</span><span class="p">)</span> <span class="p">{</span>
forward target doesn't exist.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">forwardProxy</span><span class="p">.</span><span class="nx">once</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span> <span class="p">});</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-45">&#182;</a> </div> <p>Chunk the client request body as chunks from the proxied request come in</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">req</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">chunk</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">forwardProxy</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">chunk</span><span class="p">);</span>
<span class="p">})</span></pre></div> </td> </tr> <tr id="section-39"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-39">&#182;</a> </div> <p>At the end of the client request, we are going to stop the proxied request</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">req</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;end&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="p">})</span></pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-46">&#182;</a> </div> <p>At the end of the client request, we are going to stop the proxied request</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">req</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;end&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">forwardProxy</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">});</span>
<span class="p">};</span>
<span class="nx">HttpProxy</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">proxyWebSocketRequest</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">port</span><span class="p">,</span> <span class="nx">server</span><span class="p">,</span> <span class="nx">host</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span> <span class="nx">req</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">req</span><span class="p">,</span> <span class="nx">socket</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">sock</span><span class="p">,</span> <span class="nx">head</span> <span class="o">=</span> <span class="nx">self</span><span class="p">.</span><span class="nx">head</span><span class="p">,</span>
<span class="nx">headers</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">_headers</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">headers</span><span class="p">),</span> <span class="nx">CRLF</span> <span class="o">=</span> <span class="s1">&#39;\r\n&#39;</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-40"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-40">&#182;</a> </div> <p>Will generate clone of headers
To not change original</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">_headers</span><span class="p">(</span><span class="nx">headers</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">h</span> <span class="o">=</span> <span class="p">{};</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="k">in</span> <span class="nx">headers</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">h</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">headers</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">h</span><span class="p">;</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-41"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-41">&#182;</a> </div> <p>WebSocket requests has method = GET</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">!==</span> <span class="s1">&#39;GET&#39;</span> <span class="o">||</span> <span class="nx">headers</span><span class="p">.</span><span class="nx">upgrade</span><span class="p">.</span><span class="nx">toLowerCase</span><span class="p">()</span> <span class="o">!==</span> <span class="s1">&#39;websocket&#39;</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-42"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-42">&#182;</a> </div> <p>This request is not WebSocket request</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">return</span><span class="p">;</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-43"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-43">&#182;</a> </div> <p>Turn of all bufferings
<span class="nx">HttpProxy</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">proxyWebSocketRequest</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">socket</span><span class="p">,</span> <span class="nx">head</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">self</span> <span class="o">=</span> <span class="k">this</span><span class="p">,</span> <span class="nx">outgoing</span><span class="p">,</span> <span class="nx">errState</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span> <span class="nx">CRLF</span> <span class="o">=</span> <span class="s1">&#39;\r\n&#39;</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-47">&#182;</a> </div> <p>WebSocket requests has method = GET</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">method</span> <span class="o">!==</span> <span class="s1">&#39;GET&#39;</span> <span class="o">||</span> <span class="nx">req</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">upgrade</span><span class="p">.</span><span class="nx">toLowerCase</span><span class="p">()</span> <span class="o">!==</span> <span class="s1">&#39;websocket&#39;</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-48">&#182;</a> </div> <p>This request is not WebSocket request</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">return</span><span class="p">;</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-49">&#182;</a> </div> <p>Turn of all bufferings
For server set KeepAlive
For client set encoding</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">_socket</span><span class="p">(</span><span class="nx">socket</span><span class="p">,</span> <span class="nx">server</span><span class="p">)</span> <span class="p">{</span>
For client set encoding</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">_socket</span><span class="p">(</span><span class="nx">socket</span><span class="p">,</span> <span class="nx">keepAlive</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">setTimeout</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">setNoDelay</span><span class="p">(</span><span class="kc">true</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">server</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">setKeepAlive</span><span class="p">(</span><span class="kc">true</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">keepAlive</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">socket</span><span class="p">.</span><span class="nx">setKeepAlive</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">setKeepAlive</span><span class="p">(</span><span class="kc">true</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">socket</span><span class="p">.</span><span class="nx">pair</span><span class="p">.</span><span class="nx">cleartext</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">setKeepAlive</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">pair</span><span class="p">.</span><span class="nx">cleartext</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">setKeepAlive</span><span class="p">(</span><span class="kc">true</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">setEncoding</span><span class="p">(</span><span class="s1">&#39;utf8&#39;</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-44"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-44">&#182;</a> </div> <p>Client socket</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">_socket</span><span class="p">(</span><span class="nx">socket</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-45"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-45">&#182;</a> </div> <p>If host is undefined
Get it from headers</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">host</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">host</span> <span class="o">=</span> <span class="nx">headers</span><span class="p">.</span><span class="nx">Host</span><span class="p">;</span>
<span class="p">}</span>
</pre></div> </td> </tr> <tr id="section-46"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-46">&#182;</a> </div> <p>Remote host address</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">remote_host</span> <span class="o">=</span> <span class="nx">server</span> <span class="o">+</span> <span class="p">(</span><span class="nx">port</span> <span class="o">-</span> <span class="mi">80</span> <span class="o">===</span> <span class="mi">0</span> <span class="o">?</span> <span class="s1">&#39;&#39;</span> <span class="o">:</span> <span class="s1">&#39;:&#39;</span> <span class="o">+</span> <span class="nx">port</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-47"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-47">&#182;</a> </div> <p>Change headers</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">headers</span><span class="p">.</span><span class="nx">Host</span> <span class="o">=</span> <span class="nx">remote_host</span><span class="p">;</span>
<span class="nx">headers</span><span class="p">.</span><span class="nx">Origin</span> <span class="o">=</span> <span class="s1">&#39;http://&#39;</span> <span class="o">+</span> <span class="nx">remote_host</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-48"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-48">&#182;</a> </div> <p>Open request</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">p</span> <span class="o">=</span> <span class="nx">manager</span><span class="p">.</span><span class="nx">getPool</span><span class="p">(</span><span class="nx">port</span><span class="p">,</span> <span class="nx">server</span><span class="p">);</span>
<span class="nx">p</span><span class="p">.</span><span class="nx">getClient</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">client</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-49"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-49">&#182;</a> </div> <p>Based on 'pool/main.js'</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">client</span><span class="p">.</span><span class="nx">request</span><span class="p">(</span><span class="s1">&#39;GET&#39;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">url</span><span class="p">,</span> <span class="nx">headers</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">errorListener</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="nx">errorListener</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-50">&#182;</a> </div> <p>Remove the client from the pool's available clients since it has errored</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">p</span><span class="p">.</span><span class="nx">clients</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">clients</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">client</span><span class="p">),</span> <span class="mi">1</span><span class="p">);</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-51">&#182;</a> </div> <p>Not disconnect on update</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">client</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;upgrade&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="nx">remote_socket</span><span class="p">,</span> <span class="nx">head</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">&#182;</a> </div> <p>Prepare socket</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">_socket</span><span class="p">(</span><span class="nx">remote_socket</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-53">&#182;</a> </div> <p>Emit event</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">onUpgrade</span><span class="p">(</span><span class="nx">remote_socket</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="nx">errorListener</span><span class="p">);</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;response&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">response</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;end&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="nx">errorListener</span><span class="p">);</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">busy</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="nx">p</span><span class="p">.</span><span class="nx">onFree</span><span class="p">(</span><span class="nx">client</span><span class="p">);</span>
<span class="p">})</span>
<span class="p">})</span>
<span class="nx">client</span><span class="p">.</span><span class="nx">busy</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">handshake</span><span class="p">;</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">handshake</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">&#182;</a> </div> <p>Handshaking</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">&#182;</a> </div> <p>Ok, kind of harmfull part of code
Socket.IO is sending 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)</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">sdata</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span></pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-56">&#182;</a> </div> <p>Get Printable</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">sdata</span> <span class="o">=</span> <span class="nx">sdata</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">sdata</span><span class="p">.</span><span class="nx">search</span><span class="p">(</span><span class="nx">CRLF</span> <span class="o">+</span> <span class="nx">CRLF</span><span class="p">));</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-57">&#182;</a> </div> <p>Get Non-Printable</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">data</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="nx">Buffer</span><span class="p">.</span><span class="nx">byteLength</span><span class="p">(</span><span class="nx">sdata</span><span class="p">),</span> <span class="nx">data</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-58">&#182;</a> </div> <p>Replace host and origin</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">sdata</span> <span class="o">=</span> <span class="nx">sdata</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">remote_host</span><span class="p">,</span> <span class="nx">host</span><span class="p">)</span>
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">remote_host</span><span class="p">,</span> <span class="nx">host</span><span class="p">);</span>
<span class="k">try</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-59">&#182;</a> </div> <p>Write printable</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">socket</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">sdata</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-60">&#182;</a> </div> <p>Write non-printable</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">socket</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-61">&#182;</a> </div> <p>Catch socket errors</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-62">&#182;</a> </div> <p>Remove data listener now that the 'handshake' is complete</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">request</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">handshake</span><span class="p">);</span>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-63">&#182;</a> </div> <p>Write upgrade-head</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">try</span> <span class="p">{</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">head</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">catch</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="kd">function</span> <span class="nx">onUpgrade</span><span class="p">(</span><span class="nx">out</span><span class="p">,</span> <span class="nx">reverseProxy</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">out</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">self</span><span class="p">.</span><span class="nx">unwatch</span><span class="p">(</span><span class="nx">socket</span><span class="p">);</span>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-64">&#182;</a> </div> <p>Request</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">onUpgrade</span><span class="p">(</span><span class="nx">reverse_proxy</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">listeners</span> <span class="o">=</span> <span class="p">{};</span>
</pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-65">&#182;</a> </div> <p>We're now connected to the server, so lets change server socket</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">reverse_proxy</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_r_data</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-66">&#182;</a> </div> <p>Pass data to client</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">socket</span><span class="p">.</span><span class="nx">writable</span><span class="p">)</span> <span class="p">{</span>
</pre></div> </td> </tr> <tr id="section-50"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-50">&#182;</a> </div> <p>We're now connected to the server, so lets change server socket</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_r_data</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-51"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-51">&#182;</a> </div> <p>Pass data to client</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">out</span><span class="p">.</span><span class="nx">incoming</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">writable</span><span class="p">)</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="nx">out</span><span class="p">.</span><span class="nx">incoming</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">reverse_proxy</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">out</span><span class="p">.</span><span class="nx">incoming</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_data</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-67">&#182;</a> </div> <p>Pass data from client to server</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">try</span> <span class="p">{</span>
<span class="nx">reverse_proxy</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="nx">out</span><span class="p">.</span><span class="nx">incoming</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_data</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-52"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-52">&#182;</a> </div> <p>Pass data from client to server</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">try</span> <span class="p">{</span>
<span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">reverse_proxy</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-68">&#182;</a> </div> <p>Detach event listeners from reverse_proxy</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">detach</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">reverse_proxy</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;close&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_r_close</span><span class="p">);</span>
<span class="nx">reverse_proxy</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_r_data</span><span class="p">);</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_data</span><span class="p">);</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;close&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_close</span><span class="p">);</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-69">&#182;</a> </div> <p>Hook disconnections</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">reverse_proxy</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;end&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_r_close</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-53"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-53">&#182;</a> </div> <p>Detach event listeners from reverseProxy</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">detach</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;close&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_r_close</span><span class="p">);</span>
<span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_r_data</span><span class="p">);</span>
<span class="nx">out</span><span class="p">.</span><span class="nx">incoming</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_data</span><span class="p">);</span>
<span class="nx">out</span><span class="p">.</span><span class="nx">incoming</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;close&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_close</span><span class="p">);</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-54"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-54">&#182;</a> </div> <p>Hook disconnections</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;end&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_r_close</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">out</span><span class="p">.</span><span class="nx">incoming</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">detach</span><span class="p">();</span>
<span class="p">});</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;end&#39;</span><span class="p">,</span> <span class="nx">listeners</span><span class="p">.</span><span class="nx">_close</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">reverse_proxy</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">reverseProxy</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">detach</span><span class="p">();</span>
<span class="p">});</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-55"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-55">&#182;</a> </div> <p>Client socket</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">_socket</span><span class="p">(</span><span class="nx">socket</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-56"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-56">&#182;</a> </div> <p>Remote host address</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">protocolName</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">https</span> <span class="o">||</span> <span class="k">this</span><span class="p">.</span><span class="nx">https</span> <span class="o">?</span> <span class="s1">&#39;https&#39;</span> <span class="o">:</span> <span class="s1">&#39;http&#39;</span><span class="p">,</span>
<span class="nx">agent</span> <span class="o">=</span> <span class="nx">_getAgent</span><span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">host</span><span class="p">,</span> <span class="nx">options</span><span class="p">.</span><span class="nx">port</span><span class="p">,</span> <span class="nx">options</span><span class="p">.</span><span class="nx">https</span> <span class="o">||</span> <span class="k">this</span><span class="p">.</span><span class="nx">https</span><span class="p">),</span>
<span class="nx">remoteHost</span> <span class="o">=</span> <span class="nx">options</span><span class="p">.</span><span class="nx">host</span> <span class="o">+</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">port</span> <span class="o">-</span> <span class="mi">80</span> <span class="o">===</span> <span class="mi">0</span> <span class="o">?</span> <span class="s1">&#39;&#39;</span> <span class="o">:</span> <span class="s1">&#39;:&#39;</span> <span class="o">+</span> <span class="nx">options</span><span class="p">.</span><span class="nx">port</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-57"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-57">&#182;</a> </div> <p>Change headers</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">changeOrigin</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">req</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">host</span> <span class="o">=</span> <span class="nx">remoteHost</span><span class="p">;</span>
<span class="nx">req</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">origin</span> <span class="o">=</span> <span class="nx">protocolName</span> <span class="o">+</span> <span class="s1">&#39;://&#39;</span> <span class="o">+</span> <span class="nx">remoteHost</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">outgoing</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">host</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">host</span><span class="p">,</span>
<span class="nx">port</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">port</span><span class="p">,</span>
<span class="nx">method</span><span class="o">:</span> <span class="s1">&#39;GET&#39;</span><span class="p">,</span>
<span class="nx">path</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">url</span><span class="p">,</span>
<span class="nx">headers</span><span class="o">:</span> <span class="nx">req</span><span class="p">.</span><span class="nx">headers</span><span class="p">,</span>
<span class="p">};</span></pre></div> </td> </tr> <tr id="section-58"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-58">&#182;</a> </div> <p>Make the outgoing WebSocket request</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">request</span> <span class="o">=</span> <span class="nx">agent</span><span class="p">.</span><span class="nx">appendMessage</span><span class="p">(</span><span class="nx">outgoing</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-59"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-59">&#182;</a> </div> <p>Here we set the incoming <code>req</code>, <code>socket</code> and <code>head</code> data to the outgoing
request so that we can reuse this data later on in the closure scope
available to the <code>upgrade</code> event. This bookkeeping is not tracked anywhere
in nodejs core and is <strong>very</strong> specific to proxying WebSockets.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">request</span><span class="p">.</span><span class="nx">agent</span> <span class="o">=</span> <span class="nx">agent</span><span class="p">;</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">incoming</span> <span class="o">=</span> <span class="p">{</span>
<span class="nx">request</span><span class="o">:</span> <span class="nx">req</span><span class="p">,</span>
<span class="nx">socket</span><span class="o">:</span> <span class="nx">socket</span><span class="p">,</span>
<span class="nx">head</span><span class="o">:</span> <span class="nx">head</span>
<span class="p">};</span>
</pre></div> </td> </tr> <tr id="section-60"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-60">&#182;</a> </div> <p>If the agent for this particular <code>host</code> and <code>port</code> combination
is not already listening for the <code>upgrade</code> event, then do so once.
This will force us not to disconnect. </p>
<p>In addition, it's important to note the closure scope here. Since
there is no mapping of the </p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">agent</span><span class="p">.</span><span class="nx">_events</span> <span class="o">||</span> <span class="nx">agent</span><span class="p">.</span><span class="nx">_events</span><span class="p">[</span><span class="s1">&#39;upgrade&#39;</span><span class="p">].</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">agent</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;upgrade&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">out</span><span class="p">,</span> <span class="nx">remoteSocket</span><span class="p">,</span> <span class="nx">head</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-61"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-61">&#182;</a> </div> <p>Prepare socket</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">_socket</span><span class="p">(</span><span class="nx">remoteSocket</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
</pre></div> </td> </tr> <tr id="section-62"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-62">&#182;</a> </div> <p>Emit event</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">onUpgrade</span><span class="p">(</span><span class="nx">remoteSocket</span><span class="p">.</span><span class="nx">_httpMessage</span><span class="p">,</span> <span class="nx">remoteSocket</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">request</span><span class="p">.</span><span class="nx">socket</span> <span class="o">!==</span> <span class="s1">&#39;undefined&#39;</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="nx">handshake</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-63"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-63">&#182;</a> </div> <p>Handshaking</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-64"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-64">&#182;</a> </div> <p>Ok, kind of harmfull part of code
Socket.IO is sending 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)</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">sdata</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span></pre></div> </td> </tr> <tr id="section-65"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-65">&#182;</a> </div> <p>Get Printable</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">sdata</span> <span class="o">=</span> <span class="nx">sdata</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">sdata</span><span class="p">.</span><span class="nx">search</span><span class="p">(</span><span class="nx">CRLF</span> <span class="o">+</span> <span class="nx">CRLF</span><span class="p">));</span></pre></div> </td> </tr> <tr id="section-66"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-66">&#182;</a> </div> <p>Get Non-Printable</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">data</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="nx">Buffer</span><span class="p">.</span><span class="nx">byteLength</span><span class="p">(</span><span class="nx">sdata</span><span class="p">),</span> <span class="nx">data</span><span class="p">.</span><span class="nx">length</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-67"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-67">&#182;</a> </div> <p>Replace host and origin</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">sdata</span> <span class="o">=</span> <span class="nx">sdata</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">remoteHost</span><span class="p">,</span> <span class="nx">options</span><span class="p">.</span><span class="nx">host</span><span class="p">)</span>
<span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">remoteHost</span><span class="p">,</span> <span class="nx">options</span><span class="p">.</span><span class="nx">host</span><span class="p">);</span>
<span class="k">try</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-68"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-68">&#182;</a> </div> <p>Write printable</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">socket</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">sdata</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-69"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-69">&#182;</a> </div> <p>Write non-printable</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">socket</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-70"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-70">&#182;</a> </div> <p>Catch socket errors</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">socket</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;error&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">});</span></pre></div> </td> </tr> <tr id="section-71"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-71">&#182;</a> </div> <p>Remove data listener now that the 'handshake' is complete</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">request</span><span class="p">.</span><span class="nx">socket</span><span class="p">.</span><span class="nx">removeListener</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="nx">handshake</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span></pre></div> </td> </tr> <tr id="section-72"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-72">&#182;</a> </div> <p>Write upgrade-head</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">try</span> <span class="p">{</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">head</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="nx">ex</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">request</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="nx">socket</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">}</span>
</pre></div> </td> </tr> <tr id="section-73"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-73">&#182;</a> </div> <p>If we have been passed buffered data, resume it.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">buffer</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">errState</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">options</span><span class="p">.</span><span class="nx">buffer</span><span class="p">.</span><span class="nx">resume</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">};</span>
</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>

View File

@ -46,8 +46,8 @@ https.createServer(opts, function (req, res) {
// Create the proxy server listening on port 443.
//
httpProxy.createServer(443, 'localhost', {
https: opts,
https: opts
}).listen(8080);
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 + '8080 '.yellow);
util.puts('https server '.blue + 'started '.green.bold + 'on port '.blue + '8080 '.yellow);

View File

@ -25,7 +25,7 @@
*/
var util = require('util'),
colors = require('colors')
colors = require('colors'),
http = require('http'),
httpProxy = require('./../lib/node-http-proxy');

View File

@ -25,10 +25,10 @@
*/
var util = require('util'),
colors = require('colors')
colors = require('colors'),
http = require('http'),
httpProxy = require('./../lib/node-http-proxy');
//
// Setup proxy server with forwarding
//
@ -52,12 +52,12 @@ http.createServer(function (req, res) {
// Target Http Forwarding Server
//
http.createServer(function (req, res) {
util.puts('Receiving forward for: ' + req.url)
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 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);

View File

@ -25,10 +25,10 @@
*/
var util = require('util'),
colors = require('colors')
colors = require('colors'),
http = require('http'),
httpProxy = require('./../lib/node-http-proxy');
//
// Http Proxy Server with Latency
//
@ -36,11 +36,11 @@ httpProxy.createServer(function (req, res, proxy) {
var buffer = proxy.buffer(req);
setTimeout(function() {
proxy.proxyRequest(req, res, {
port: 9000,
host: 'localhost',
port: 9000,
host: 'localhost',
buffer: buffer
});
}, 200)
}, 200);
}).listen(8002);
//
@ -53,4 +53,4 @@ http.createServer(function (req, res) {
}).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);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);

View File

@ -25,10 +25,10 @@
*/
var util = require('util'),
colors = require('colors')
colors = require('colors'),
http = require('http'),
httpProxy = require('./../lib/node-http-proxy');
//
// Http Proxy Server with Proxy Table
//
@ -47,5 +47,5 @@ http.createServer(function (req, res) {
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 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);

View File

@ -25,10 +25,10 @@
*/
var util = require('util'),
colors = require('colors')
colors = require('colors'),
http = require('http'),
httpProxy = require('./../lib/node-http-proxy');
//
// Http Server with proxyRequest Handler and Latency
//
@ -37,8 +37,8 @@ http.createServer(function (req, res) {
var buffer = proxy.buffer(req);
setTimeout(function() {
proxy.proxyRequest(req, res, {
port: 9000,
host: 'localhost',
port: 9000,
host: 'localhost',
buffer: buffer
});
}, 200);
@ -54,4 +54,4 @@ http.createServer(function (req, res) {
}).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);
util.puts('http server '.blue + 'started '.green.bold + 'on port '.blue + '9000 '.yellow);

View File

@ -32,7 +32,7 @@ var sys = require('sys'),
try {
var utils = require('socket.io/lib/socket.io/utils'),
io = require('socket.io');
io = require('socket.io');
}
catch (ex) {
console.error('Socket.io is required for this example:');
@ -55,11 +55,11 @@ server.listen(8080);
var socket = io.listen(server);
socket.on('connection', function (client) {
sys.debug('Got websocket connection');
client.on('message', function (msg) {
sys.debug('Got message from client: ' + msg);
});
socket.broadcast('from server');
});

View File

@ -32,9 +32,9 @@ var util = require('util'),
maxSockets = 100;
//
// ### Version 0.5.0
// ### Version 0.5.3 // 5/17/2011
//
exports.version = [0, 5, 0];
exports.version = [0, 5, 3];
//
// ### function _getAgent (host, port, secure)
@ -219,10 +219,11 @@ exports.createServer = function () {
var HttpProxy = exports.HttpProxy = function (options) {
events.EventEmitter.call(this);
var self = this;
options = options || {};
this.forward = options.forward;
this.https = options.https;
var self = this;
options = options || {};
this.forward = options.forward;
this.https = options.https;
this.changeOrigin = options.changeOrigin || false;
if (options.router) {
this.proxyTable = new ProxyTable(options.router, options.silent, options.hostnameOnly);
@ -523,31 +524,42 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options
socket.setTimeout(0);
socket.setNoDelay(true);
if (keepAlive) {
socket.setKeepAlive(true, 0);
if (socket.setKeepAlive) {
socket.setKeepAlive(true, 0);
}
else if (socket.pair.cleartext.socket.setKeepAlive) {
socket.pair.cleartext.socket.setKeepAlive(true, 0);
}
}
else {
socket.setEncoding('utf8');
}
}
function onUpgrade(reverseProxy) {
function onUpgrade(out, reverseProxy) {
if (!out) {
reverseProxy.end();
socket.end();
return;
}
var listeners = {};
// We're now connected to the server, so lets change server socket
reverseProxy.on('data', listeners._r_data = function(data) {
// Pass data to client
if (socket.writable) {
if (out.incoming.socket.writable) {
try {
socket.write(data);
out.incoming.socket.write(data);
}
catch (e) {
socket.end();
out.incoming.socket.end();
reverseProxy.end();
}
}
});
socket.on('data', listeners._data = function(data) {
out.incoming.socket.on('data', listeners._data = function(data) {
// Pass data from client to server
try {
reverseProxy.write(data);
@ -562,13 +574,13 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options
function detach() {
reverseProxy.removeListener('close', listeners._r_close);
reverseProxy.removeListener('data', listeners._r_data);
socket.removeListener('data', listeners._data);
socket.removeListener('close', listeners._close);
out.incoming.socket.removeListener('data', listeners._data);
out.incoming.socket.removeListener('close', listeners._close);
}
// Hook disconnections
reverseProxy.on('end', listeners._r_close = function() {
socket.end();
out.incoming.socket.end();
detach();
});
@ -582,37 +594,60 @@ HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options
_socket(socket);
// Remote host address
var agent = _getAgent(options.host, options.port),
remoteHost = options.host + (options.port - 80 === 0 ? '' : ':' + options.port);
var protocolName = options.https || this.https ? 'https' : 'http',
agent = _getAgent(options.host, options.port, options.https || this.https),
remoteHost = options.host + (options.port - 80 === 0 ? '' : ':' + options.port);
// Change headers
req.headers.host = remoteHost;
req.headers.origin = 'http://' + options.host;
if (this.changeOrigin) {
req.headers.host = remoteHost;
req.headers.origin = protocolName + '://' + remoteHost;
}
outgoing = {
host: options.host,
port: options.port,
agent: agent,
method: 'GET',
path: req.url,
headers: req.headers
headers: req.headers,
};
// Make the outgoing WebSocket request
var request = http.request(outgoing, function () { });
// Not disconnect on update
agent.on('upgrade', function(request, remoteSocket, head) {
// Prepare socket
_socket(remoteSocket, true);
var request = agent.appendMessage(outgoing);
// Emit event
onUpgrade(remoteSocket);
});
//
// 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.
//
request.agent = agent;
request.incoming = {
request: req,
socket: socket,
head: head
};
//
// 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
//
if (!agent._events || agent._events['upgrade'].length === 0) {
agent.on('upgrade', function (out, remoteSocket, head) {
// Prepare socket
_socket(remoteSocket, true);
// Emit event
onUpgrade(remoteSocket._httpMessage, remoteSocket);
});
}
var handshake;
if (typeof request.socket !== 'undefined') {
request.socket.on('data', handshake = function(data) {
request.socket.on('data', function handshake (data) {
// Handshaking
// Ok, kind of harmfull part of code

View File

@ -1,7 +1,7 @@
{
"name": "http-proxy",
"description": "A full-featured http reverse proxy for node.js",
"version": "0.5.1",
"version": "0.5.3",
"author": "Charlie Robbins <charlie.robbins@gmail.com>",
"contributors": [
{ "name": "Mikeal Rogers", "email": "mikeal.rogers@gmail.com" },
@ -16,11 +16,15 @@
"dependencies": {
"colors": ">= 0.5.x",
"optimist": ">= 0.1.x",
"request": ">= 1.9.x",
"vows": ">= 0.5.x"
"request": ">= 1.9.x"
},
"devDependencies": {
"vows": ">= 0.5.x",
"socket.io": ">= 0.6.x",
"docco": ">= 0.3.x"
},
"main": "./lib/node-http-proxy",
"bin": { "node-http-proxy": "./bin/node-http-proxy" },
"scripts": { "test": "vows test/*-test.js --spec" },
"engines": { "node": "= 0.4.7" }
}
}

View File

@ -37,7 +37,7 @@ var TestRunner = exports.TestRunner = function (protocol) {
this.options = {};
this.protocol = protocol;
this.testServers = [];
if (protocol === 'https') {
this.options.https = loadHttps();
}
@ -47,17 +47,17 @@ TestRunner.prototype.assertProxied = function (host, proxyPort, port, createProx
var self = this,
assertion = "should receive 'hello " + host + "'",
output = 'hello ' + host;
var test = {
topic: function () {
var that = this, options = {
method: 'GET',
method: 'GET',
uri: self.protocol + '://localhost:' + proxyPort,
headers: {
host: host
}
};
function startTest () {
if (port) {
return self.startTargetServer(port, output, function () {
@ -67,47 +67,48 @@ TestRunner.prototype.assertProxied = function (host, proxyPort, port, createProx
request(options, this.callback);
}
return createProxy ? createProxy(startTest) : startTest();
}
};
test[assertion] = function (err, res, body) {;
test[assertion] = function (err, res, body) {
assert.isNull(err);
assert.equal(body, output);
};
return test;
};
TestRunner.prototype.assertResponseCode = function (proxyPort, statusCode, createProxy) {
var assertion = "should receive " + statusCode + " responseCode";
var assertion = "should receive " + statusCode + " responseCode",
protocol = this.protocol;
var test = {
topic: function () {
var that = this, options = {
method: 'GET',
uri: 'http://localhost:' + proxyPort,
method: 'GET',
uri: protocol + '://localhost:' + proxyPort,
headers: {
host: 'unknown.com'
}
};
if (createProxy) {
return createProxy(function () {
request(options, that.callback);
request(options, that.callback);
});
}
request(options, this.callback);
}
};
test[assertion] = function (err, res, body) {
assert.isNull(err);
assert.equal(res.statusCode, statusCode);
};
return test;
};
@ -115,26 +116,28 @@ TestRunner.prototype.assertResponseCode = function (proxyPort, statusCode, creat
// Creates the reverse proxy server
//
TestRunner.prototype.startProxyServer = function (port, targetPort, host, callback) {
var that = this, proxyServer = httpProxy.createServer(targetPort, host);
var that = this,
options = that.options,
proxyServer = httpProxy.createServer(targetPort, host, options);
proxyServer.listen(port, function () {
that.testServers.push(proxyServer);
callback(null, proxyServer);
});
});
};
//
//
// Creates the reverse proxy server with a specified latency
//
TestRunner.prototype.startLatentProxyServer = function (port, targetPort, host, latency, callback) {
// Initialize the nodeProxy and start proxying the request
var that = this, proxyServer = httpProxy.createServer(function (req, res, proxy) {
var buffer = proxy.buffer(req);
setTimeout(function () {
proxy.proxyRequest(req, res, {
port: targetPort,
host: host,
port: targetPort,
host: host,
buffer: buffer
});
}, latency);
@ -150,12 +153,12 @@ TestRunner.prototype.startLatentProxyServer = function (port, targetPort, host,
// Creates the reverse proxy server with a ProxyTable
//
TestRunner.prototype.startProxyServerWithTable = function (port, options, callback) {
var that = this, proxyServer = httpProxy.createServer(merge({}, options, this.options));
var that = this, proxyServer = httpProxy.createServer(merge({}, options, this.options));
proxyServer.listen(port, function () {
that.testServers.push(proxyServer);
callback();
});
return proxyServer;
};
@ -164,21 +167,28 @@ TestRunner.prototype.startProxyServerWithTable = function (port, options, callba
//
TestRunner.prototype.startProxyServerWithTableAndLatency = function (port, latency, options, callback) {
// Initialize the nodeProxy and start proxying the request
var proxyServer, that = this, proxy = new httpProxy.HttpProxy(merge({}, options, this.options));
proxyServer = http.createServer(function (req, res) {
var proxyServer,
that = this,
proxy = new httpProxy.HttpProxy(merge({}, options, that.options));
var handler = function (req, res) {
var buffer = proxy.buffer(req);
setTimeout(function () {
proxy.proxyRequest(req, res, {
buffer: buffer
});
}, latency);
}, this.options);
};
proxyServer = that.options.https
? https.createServer(that.options.https, handler, that.options)
: http.createServer(handler, that.options);
proxyServer.listen(port, function () {
that.testServers.push(proxyServer);
callback();
});
return proxyServer;
};
@ -186,7 +196,7 @@ TestRunner.prototype.startProxyServerWithTableAndLatency = function (port, laten
// Creates proxy server forwarding to the specified options
//
TestRunner.prototype.startProxyServerWithForwarding = function (port, targetPort, host, options, callback) {
var that = this, proxyServer = httpProxy.createServer(targetPort, host, merge({}, options, this.options));
var that = this, proxyServer = httpProxy.createServer(targetPort, host, merge({}, options, this.options));
proxyServer.listen(port, function () {
that.testServers.push(proxyServer);
callback(null, proxyServer);
@ -200,13 +210,13 @@ TestRunner.prototype.startTargetServer = function (port, output, callback) {
var that = this, targetServer, handler = function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write(output);
res.end();
res.end();
};
targetServer = this.options.https
targetServer = this.options.https
? https.createServer(this.options.https, handler)
: http.createServer(handler);
targetServer.listen(port, function () {
that.testServers.push(targetServer);
callback(null, targetServer);
@ -222,4 +232,4 @@ TestRunner.prototype.closeServers = function () {
});
return this.testServers;
};
};

View File

@ -89,4 +89,4 @@ vows.describe('node-http-proxy/' + protocol).addBatch({
assert.isTrue(true);
}
}
}).export(module);
}).export(module);

View File

@ -14,7 +14,7 @@ var fs = require('fs'),
helpers = require('./helpers'),
argv = require('optimist').argv,
TestRunner = helpers.TestRunner;
var protocol = argv.https ? 'https' : 'http',
runner = new TestRunner(protocol),
routeFile = path.join(__dirname, 'config.json');
@ -78,13 +78,13 @@ vows.describe('node-http-proxy/proxy-table/' + protocol).addBatch({
data = fs.readFileSync(routeFile),
config = JSON.parse(data);
config.router['dynamic.com'] = "127.0.0.1:8103"
config.router['dynamic.com'] = "127.0.0.1:8103";
fs.writeFileSync(routeFile, JSON.stringify(config));
this.server.on('routes', function () {
var options = {
method: 'GET',
uri: 'http://localhost:8100',
method: 'GET',
uri: protocol + '://localhost:8100',
headers: {
host: 'dynamic.com'
}
@ -126,4 +126,4 @@ vows.describe('node-http-proxy/proxy-table/' + protocol).addBatch({
assert.isTrue(true);
}
}
}).export(module);
}).export(module);

View File

@ -23,18 +23,19 @@
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var vows = require('vows'),
util = require('util'),
colors = require('colors'),
request = require('request'),
assert = require('assert'),
argv = require('optimist').argv,
websocket = require('./../vendor/websocket'),
helpers = require('./helpers');
try {
var utils = require('socket.io/lib/socket.io/utils'),
io = require('socket.io');
io = require('socket.io');
}
catch (ex) {
console.error('Socket.io is required for this test:');
@ -42,7 +43,9 @@ catch (ex) {
process.exit(1);
}
var runner = new helpers.TestRunner();
var protocol = argv.https ? 'https' : 'http',
wsprotocol = argv.https ? 'wss' : 'ws',
runner = new helpers.TestRunner(protocol);
vows.describe('node-http-proxy/websocket').addBatch({
"When using server created by httpProxy.createServer()": {
@ -50,61 +53,83 @@ vows.describe('node-http-proxy/websocket').addBatch({
"when an inbound message is sent from a WebSocket client": {
topic: function () {
var that = this;
runner.startTargetServer(8130, 'hello websocket', function (err, target) {
var socket = io.listen(target);
var socket = io.listen(target),
headers = {};
socket.on('connection', function (client) {
client.on('message', function (msg) {
that.callback(null, msg);
that.callback(null, msg, headers);
});
});
runner.startProxyServer(8131, 8130, 'localhost', function (err, proxy) {
//
// Setup the web socket against our proxy
//
var ws = new websocket.WebSocket('ws://localhost:8131/socket.io/websocket/', 'borf');
var ws = new websocket.WebSocket(wsprotocol + '://home.devjitsu.com:8131/socket.io/websocket/', 'borf', {
origin: protocol + '://home.devjitsu.com'
});
ws.on('wsupgrade', function (req, res) {
headers.request = req;
headers.response = res.headers;
});
ws.on('open', function () {
ws.send(utils.encode('from client'));
});
});
})
});
},
"the target server should receive the message": function (err, msg) {
"the target server should receive the message": function (err, msg, headers) {
assert.equal(msg, 'from client');
}
},
"the origin and sec-websocket-origin headers should match": function (err, msg, headers) {
assert.equal(headers.request.Origin, headers.response['sec-websocket-origin']);
}
},
"when an outbound message is sent from the target server": {
topic: function () {
var that = this;
runner.startTargetServer(8132, 'hello websocket', function (err, target) {
var socket = io.listen(target);
var socket = io.listen(target),
headers = {};
socket.on('connection', function (client) {
socket.broadcast('from server');
});
runner.startProxyServer(8133, 8132, 'localhost', function (err, proxy) {
//
// Setup the web socket against our proxy
//
var ws = new websocket.WebSocket('ws://localhost:8133/socket.io/websocket/', 'borf');
var ws = new websocket.WebSocket(wsprotocol + '://home.devjitsu.com:8133/socket.io/websocket/', 'borf', {
origin: protocol + '://home.devjitsu.com'
});
ws.on('wsupgrade', function (req, res) {
headers.request = req;
headers.response = res.headers;
});
ws.on('message', function (msg) {
msg = utils.decode(msg);
if (!/\d+/.test(msg)) {
that.callback(null, msg);
that.callback(null, msg, headers);
}
});
});
})
});
},
"the client should receive the message": function (err, msg) {
"the client should receive the message": function (err, msg, headers) {
assert.equal(msg, 'from server');
}
},
"the origin and sec-websocket-origin headers should match": function (err, msg, headers) {
assert.equal(headers.request.Origin, headers.response['sec-websocket-origin']);
}
}
}
}
@ -117,4 +142,4 @@ vows.describe('node-http-proxy/websocket').addBatch({
assert.isTrue(true);
}
}
}).export(module);
}).export(module);

213
vendor/websocket.js vendored
View File

@ -35,6 +35,7 @@ var buffer = require('buffer');
var crypto = require('crypto');
var events = require('events');
var http = require('http');
var https = require('https');
var net = require('net');
var urllib = require('url');
var sys = require('sys');
@ -178,16 +179,6 @@ var str2hex = function(str) {
return out.trim();
};
// Get the scheme for a URL, undefined if none is found
var getUrlScheme = function(url) {
var i = url.indexOf(':');
if (i == -1) {
return undefined;
}
return url.substring(0, i);
};
// Set a constant on the given object
var setConstant = function(obj, name, value) {
Object.defineProperty(obj, name, {
@ -501,120 +492,136 @@ var WebSocket = function(url, proto, opts) {
// that http.Client passes its constructor arguments through,
// un-inspected to net.Stream.connect(). The latter accepts a
// string as its first argument to connect to a UNIX socket.
var httpClient = undefined;
switch (getUrlScheme(url)) {
case 'ws':
var u = urllib.parse(url);
httpClient = http.createClient(u.port || 80, u.hostname);
var protocol, agent, port, u = urllib.parse(url);
if (u.protocol === 'ws:' || u.protocol === 'wss:') {
protocol = u.protocol === 'ws:' ? http : https;
port = u.protocol === 'ws:' ? 80 : 443;
agent = u.protocol === 'ws:' ? protocol.getAgent(u.hostname, u.port || port) : protocol.getAgent({
host: u.hostname,
port: u.port || port
});
httpPath = (u.pathname || '/') + (u.search || '');
httpHeaders.Host = u.hostname + (u.port ? (":" + u.port) : "");
break;
case 'ws+unix':
var sockPath = url.substring('ws+unix://'.length, url.length);
httpClient = http.createClient(sockPath);
httpHeaders.Host = 'localhost';
break;
default:
}
else if (urlScheme === 'ws+unix') {
throw new Error('ws+unix is not implemented');
// var sockPath = url.substring('ws+unix://'.length, url.length);
// httpClient = http.createClient(sockPath);
// httpHeaders.Host = 'localhost';
}
else {
throw new Error('Invalid URL scheme \'' + urlScheme + '\' specified.');
}
if (!agent._events || agent._events['upgrade'].length === 0) {
agent.on('upgrade', (function() {
var data = undefined;
httpClient.on('upgrade', (function() {
var data = undefined;
return function(res, s, head) {
stream = s;
return function(req, s, head) {
stream = s;
//
// Emit the `wsupgrade` event to inspect the raw
// arguments returned from the websocket request.
//
self.emit('wsupgrade', httpHeaders, res, s, head);
stream.on('data', function(d) {
if (d.length <= 0) {
return;
}
if (!data) {
data = d;
} else {
var data2 = new buffer.Buffer(data.length + d.length);
stream.on('data', function(d) {
if (d.length <= 0) {
return;
}
data.copy(data2, 0, 0, data.length);
d.copy(data2, data.length, 0, d.length);
if (!data) {
data = d;
} else {
var data2 = new buffer.Buffer(data.length + d.length);
data = data2;
}
data.copy(data2, 0, 0, data.length);
d.copy(data2, data.length, 0, d.length);
if (data.length >= 16) {
var expected = computeSecretKeySignature(key1, key2, challenge);
var actual = data.slice(0, 16).toString('binary');
data = data2;
}
if (data.length >= 16) {
var expected = computeSecretKeySignature(key1, key2, challenge);
var actual = data.slice(0, 16).toString('binary');
// Handshaking fails; we're donezo
if (actual != expected) {
debug(
'expected=\'' + str2hex(expected) + '\'; ' +
'actual=\'' + str2hex(actual) + '\''
);
process.nextTick(function() {
// N.B. Emit 'wserror' here, as 'error' is a reserved word in the
// EventEmitter world, and gets thrown.
self.emit(
'wserror',
new Error('Invalid handshake from server:' +
'expected \'' + str2hex(expected) + '\', ' +
'actual \'' + str2hex(actual) + '\''
)
// Handshaking fails; we're donezo
if (actual != expected) {
debug(
'expected=\'' + str2hex(expected) + '\'; ' +
'actual=\'' + str2hex(actual) + '\''
);
if (self.onerror) {
self.onerror();
}
process.nextTick(function() {
// N.B. Emit 'wserror' here, as 'error' is a reserved word in the
// EventEmitter world, and gets thrown.
self.emit(
'wserror',
new Error('Invalid handshake from server:' +
'expected \'' + str2hex(expected) + '\', ' +
'actual \'' + str2hex(actual) + '\''
)
);
finishClose();
});
}
if (self.onerror) {
self.onerror();
}
// Un-register our data handler and add the one to be used
// for the normal, non-handshaking case. If we have extra
// data left over, manually fire off the handler on
// whatever remains.
//
// XXX: This is lame. We should only remove the listeners
// that we added.
httpClient.removeAllListeners('upgrade');
stream.removeAllListeners('data');
stream.on('data', dataListener);
readyState = OPEN;
process.nextTick(function() {
self.emit('open');
if (self.onopen) {
self.onopen();
finishClose();
});
}
});
// Consume any leftover data
if (data.length > 16) {
stream.emit('data', data.slice(16, data.length));
//
// Un-register our data handler and add the one to be used
// for the normal, non-handshaking case. If we have extra
// data left over, manually fire off the handler on
// whatever remains.
//
stream.removeAllListeners('data');
stream.on('data', dataListener);
readyState = OPEN;
process.nextTick(function() {
self.emit('open');
if (self.onopen) {
self.onopen();
}
});
// Consume any leftover data
if (data.length > 16) {
stream.emit('data', data.slice(16, data.length));
}
}
}
});
stream.on('fd', fdListener);
stream.on('error', errorListener);
stream.on('close', function() {
errorListener(new Error('Stream closed unexpectedly.'));
});
});
stream.on('fd', fdListener);
stream.on('error', errorListener);
stream.on('close', function() {
errorListener(new Error('Stream closed unexpectedly.'));
});
stream.emit('data', head);
};
})());
httpClient.on('error', function(e) {
httpClient.end();
stream.emit('data', head);
};
})());
}
agent.on('error', function (e) {
errorListener(e);
});
var httpReq = httpClient.request(httpPath, httpHeaders);
var httpReq = protocol.request({
host: u.hostname,
method: 'GET',
agent: agent,
port: u.port,
path: httpPath,
headers: httpHeaders
});
httpReq.write(challenge, 'binary');
httpReq.end();
})();