From 2d75510d827c770c30a7292c31ef0f2007da7086 Mon Sep 17 00:00:00 2001 From: indexzero Date: Sun, 22 Jul 2012 03:14:42 -0400 Subject: [PATCH] [dist] Remove out-dated docco docs --- docs/balancing-proxy.html | 90 ------ docs/docco.css | 194 ------------- docs/node-http-proxy.html | 591 -------------------------------------- docs/proxy-table.html | 136 --------- 4 files changed, 1011 deletions(-) delete mode 100644 docs/balancing-proxy.html delete mode 100644 docs/docco.css delete mode 100644 docs/node-http-proxy.html delete mode 100644 docs/proxy-table.html diff --git a/docs/balancing-proxy.html b/docs/balancing-proxy.html deleted file mode 100644 index ba3256e14..000000000 --- a/docs/balancing-proxy.html +++ /dev/null @@ -1,90 +0,0 @@ - balancing-proxy.js

balancing-proxy.js

/*
-  balancing-proxy.js: Transparent Load-Balancing Optimized HTTP Proxy 
-
-  Copyright (c) 2011 Charlie Robbins 
-
-  Permission is hereby granted, free of charge, to any person obtaining
-  a copy of this software and associated documentation files (the
-  "Software"), to deal in the Software without restriction, including
-  without limitation the rights to use, copy, modify, merge, publish,
-  distribute, sublicense, and/or sell copies of the Software, and to
-  permit persons to whom the Software is furnished to do so, subject to
-  the following conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-*/
-
-var net = require('net'),
-    HTTPParser = process.binding('http_parser').HTTPParser,
-    streams = require('morestreams');
-
-exports.createServer = function () {
-  var args = Array.prototype.slice.call(arguments), 
-      callback = typeof args[0] === 'function' && args.shift(),
-      options = {}, port, host, server;
-      
-  server = net.createServer(function (socket) {
-    var buffer = new streams.BufferedStream(),
-        parser = new HTTPParser('request');
-    
-    parser.onHeaderField = function(b, start, len) {
-      var slice = b.toString('ascii', start, start + len).toLowerCase();
-      if (parser.value != undefined) {
-        require('eyes').inspect(parser.value, parser.field);
-        parser.field = null;
-        parser.value = null;
-      }
-      if (parser.field) {
-        parser.field += slice;
-      } else {
-        parser.field = slice;
-      }
-    };
-
-    parser.onHeaderValue = function(b, start, len) {
-      var slice = b.toString('ascii', start, start + len);
-      if (parser.value) {
-        parser.value += slice;
-      } else {
-        parser.value = slice;
-      }
-    };
-    
-    parser.socket = socket;
-    
-    socket.ondata = function (d, start, end) {
-      var ret = parser.execute(d, start, end - start);
-      console.log(ret);
-    };
-    
-    socket.onend = function() {
-      var ret = parser.finish();
-
-      if (ret instanceof Error) {
-        socket.destroy(ret);
-        return;
-      }
-
-      if (socket.writable) {
-        socket.end();
-      }
-    };
-    
-    socket.write('hello world');
-    socket.end();
-  });
-  
-  return server;
-};
-
-
\ No newline at end of file diff --git a/docs/docco.css b/docs/docco.css deleted file mode 100644 index bd5413433..000000000 --- a/docs/docco.css +++ /dev/null @@ -1,194 +0,0 @@ -/*--------------------- Layout and Typography ----------------------------*/ -body { - font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; - font-size: 15px; - line-height: 22px; - color: #252519; - margin: 0; padding: 0; -} -a { - color: #261a3b; -} - a:visited { - color: #261a3b; - } -p { - margin: 0 0 15px 0; -} -h4, h5, h6 { - color: #333; - margin: 6px 0 6px 0; - font-size: 13px; -} - h2, h3 { - margin-bottom: 0; - color: #000; - } - h1 { - margin-top: 40px; - margin-bottom: 15px; - color: #000; - } -#container { - position: relative; -} -#background { - position: fixed; - top: 0; left: 525px; right: 0; bottom: 0; - background: #f5f5ff; - border-left: 1px solid #e5e5ee; - z-index: -1; -} -#jump_to, #jump_page { - background: white; - -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; - -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; - font: 10px Arial; - text-transform: uppercase; - cursor: pointer; - text-align: right; -} -#jump_to, #jump_wrapper { - position: fixed; - right: 0; top: 0; - padding: 5px 10px; -} - #jump_wrapper { - padding: 0; - display: none; - } - #jump_to:hover #jump_wrapper { - display: block; - } - #jump_page { - padding: 5px 0 3px; - margin: 0 0 25px 25px; - } - #jump_page .source { - display: block; - padding: 5px 10px; - text-decoration: none; - border-top: 1px solid #eee; - } - #jump_page .source:hover { - background: #f5f5ff; - } - #jump_page .source:first-child { - } -table td { - border: 0; - outline: 0; -} - td.docs, th.docs { - max-width: 450px; - min-width: 450px; - min-height: 5px; - padding: 10px 25px 1px 50px; - overflow-x: hidden; - vertical-align: top; - text-align: left; - } - .docs pre { - margin: 15px 0 15px; - padding-left: 15px; - } - .docs p tt, .docs p code { - background: #f8f8ff; - border: 1px solid #dedede; - font-size: 12px; - padding: 0 0.2em; - } - .pilwrap { - position: relative; - } - .pilcrow { - font: 12px Arial; - text-decoration: none; - color: #454545; - position: absolute; - top: 3px; left: -20px; - padding: 1px 2px; - opacity: 0; - -webkit-transition: opacity 0.2s linear; - } - td.docs:hover .pilcrow { - opacity: 1; - } - td.code, th.code { - padding: 14px 15px 16px 25px; - width: 100%; - vertical-align: top; - background: #f5f5ff; - border-left: 1px solid #e5e5ee; - } - pre, tt, code { - font-size: 12px; line-height: 18px; - font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; - margin: 0; padding: 0; - } - - -/*---------------------- Syntax Highlighting -----------------------------*/ -td.linenos { background-color: #f0f0f0; padding-right: 10px; } -span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } -body .hll { background-color: #ffffcc } -body .c { color: #408080; font-style: italic } /* Comment */ -body .err { border: 1px solid #FF0000 } /* Error */ -body .k { color: #954121 } /* Keyword */ -body .o { color: #666666 } /* Operator */ -body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ -body .cp { color: #BC7A00 } /* Comment.Preproc */ -body .c1 { color: #408080; font-style: italic } /* Comment.Single */ -body .cs { color: #408080; font-style: italic } /* Comment.Special */ -body .gd { color: #A00000 } /* Generic.Deleted */ -body .ge { font-style: italic } /* Generic.Emph */ -body .gr { color: #FF0000 } /* Generic.Error */ -body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -body .gi { color: #00A000 } /* Generic.Inserted */ -body .go { color: #808080 } /* Generic.Output */ -body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -body .gs { font-weight: bold } /* Generic.Strong */ -body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -body .gt { color: #0040D0 } /* Generic.Traceback */ -body .kc { color: #954121 } /* Keyword.Constant */ -body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ -body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ -body .kp { color: #954121 } /* Keyword.Pseudo */ -body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ -body .kt { color: #B00040 } /* Keyword.Type */ -body .m { color: #666666 } /* Literal.Number */ -body .s { color: #219161 } /* Literal.String */ -body .na { color: #7D9029 } /* Name.Attribute */ -body .nb { color: #954121 } /* Name.Builtin */ -body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ -body .no { color: #880000 } /* Name.Constant */ -body .nd { color: #AA22FF } /* Name.Decorator */ -body .ni { color: #999999; font-weight: bold } /* Name.Entity */ -body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -body .nf { color: #0000FF } /* Name.Function */ -body .nl { color: #A0A000 } /* Name.Label */ -body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ -body .nt { color: #954121; font-weight: bold } /* Name.Tag */ -body .nv { color: #19469D } /* Name.Variable */ -body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ -body .w { color: #bbbbbb } /* Text.Whitespace */ -body .mf { color: #666666 } /* Literal.Number.Float */ -body .mh { color: #666666 } /* Literal.Number.Hex */ -body .mi { color: #666666 } /* Literal.Number.Integer */ -body .mo { color: #666666 } /* Literal.Number.Oct */ -body .sb { color: #219161 } /* Literal.String.Backtick */ -body .sc { color: #219161 } /* Literal.String.Char */ -body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ -body .s2 { color: #219161 } /* Literal.String.Double */ -body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -body .sh { color: #219161 } /* Literal.String.Heredoc */ -body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -body .sx { color: #954121 } /* Literal.String.Other */ -body .sr { color: #BB6688 } /* Literal.String.Regex */ -body .s1 { color: #219161 } /* Literal.String.Single */ -body .ss { color: #19469D } /* Literal.String.Symbol */ -body .bp { color: #954121 } /* Name.Builtin.Pseudo */ -body .vc { color: #19469D } /* Name.Variable.Class */ -body .vg { color: #19469D } /* Name.Variable.Global */ -body .vi { color: #19469D } /* Name.Variable.Instance */ -body .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/docs/node-http-proxy.html b/docs/node-http-proxy.html deleted file mode 100644 index 4b74c779c..000000000 --- a/docs/node-http-proxy.html +++ /dev/null @@ -1,591 +0,0 @@ - node-http-proxy.js

node-http-proxy.js

/*
-  node-http-proxy.js: http proxy for node.js
-
-  Copyright (c) 2010 Charlie Robbins, Mikeal Rogers, Marak Squires, Fedor Indutny 
-
-  Permission is hereby granted, free of charge, to any person obtaining
-  a copy of this software and associated documentation files (the
-  "Software"), to deal in the Software without restriction, including
-  without limitation the rights to use, copy, modify, merge, publish,
-  distribute, sublicense, and/or sell copies of the Software, and to
-  permit persons to whom the Software is furnished to do so, subject to
-  the following conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-*/
-
-var util = require('util'),
-    http = require('http'),
-    https = require('https'),
-    events = require('events'),
-    ProxyTable = require('./proxy-table').ProxyTable,
-    maxSockets = 100;

Version 0.5.7 // 5/19/2011

exports.version = [0, 5, 7];

Track our own list of agents internal to node-http-proxy

var _agents = {};

function _getAgent (host, port, secure)

- -

@host {string} Host of the agent to get

- -

@port {number} Port of the agent to get

- -

@secure {boolean} Value indicating whether or not to use HTTPS

- -

Retreives an agent from the http or https module -and sets the maxSockets property appropriately.

function _getAgent (host, port, secure) {
-  var Agent, id = [host, port].join(':');
-  
-  if (!port) {
-    port = secure ? 443 : 80;
-  }
-  
-  if (!_agents[id]) {
-    Agent = secure ? https.Agent : http.Agent;
-
-    _agents[id] = new Agent({ 
-      host: host, 
-      port: port,
-      maxSockets: maxSockets
-    });
-  }
-
-  return _agents[id];
-}

function _getProtocol (secure, outgoing)

- -

@secure {Object|boolean} Settings for https

- -

@outgoing {Object} Outgoing request options

- -

Returns the appropriate protocol based on the settings in -secure. If the protocol is https this function will update -the options in outgoing as appropriate by adding ca, key, -and cert if they exist in secure.

function _getProtocol (secure, outgoing) {
-  var protocol = secure ? https : http;
-  
-  if (typeof secure === 'object') {
-    outgoing = outgoing || {};
-    ['ca', 'cert', 'key'].forEach(function (prop) {
-      if (secure[prop]) {
-        outgoing[prop] = secure[prop];
-      }
-    })
-  }
-  
-  return protocol;
-}

function getMaxSockets ()

- -

Returns the maximum number of sockets -allowed on every outgoing request -made by all instances of HttpProxy

exports.getMaxSockets = function () {
-  return maxSockets;
-};

function setMaxSockets ()

- -

Sets the maximum number of sockets -allowed on every outgoing request -made by all instances of HttpProxy

exports.setMaxSockets = function (value) {
-  maxSockets = value;
-};

function createServer ([port, host, options, handler])

- -

@port {number} Optional Port to use on the proxy target host.

- -

@host {string} Optional Host of the proxy target.

- -

@options {Object} Optional Options for the HttpProxy instance used

- -

@handler {function} Optional Request handler for the server

- -

Returns a server that manages an instance of HttpProxy. Flexible arguments allow for:

- -
    -
  • httpProxy.createServer(9000, 'localhost')
  • -
  • `httpProxy.createServer(9000, 'localhost', options)
  • -
  • httpPRoxy.createServer(function (req, res, proxy) { ... })
  • -
exports.createServer = function () {
-  var args = Array.prototype.slice.call(arguments), 
-      callback = typeof args[0] === 'function' && args.shift(),
-      options = {}, port, host, forward, silent, proxy, server;
-  
-  if (args.length >= 2) {
-    port = args[0];
-    host = args[1];
-    options = args[2] || {};
-  } 
-  else if (args.length === 1) {
-    options = args[0] || {};
-    if (!options.router && !callback) {
-      throw new Error('Cannot create server with no router and no callback');
-    }
-  }
-
-  proxy = new HttpProxy(options);
-  
-  handler = function (req, res) {
-    if (callback) {

If we were passed a callback to process the request -or response in some way, then call it.

      callback(req, res, proxy);
-    } 
-    else if (port && host) {

If we have a target host and port for the request -then proxy to the specified location.

      proxy.proxyRequest(req, res, {
-        port: port, 
-        host: host
-      });
-    }
-    else if (proxy.proxyTable) {

If the proxy is configured with a ProxyTable -instance then use that before failing.

      proxy.proxyRequest(req, res);
-    }
-    else {

Otherwise this server is improperly configured.

      throw new Error('Cannot proxy without port, host, or router.')
-    }
-  };
-  
-  server = options.https 
-    ? https.createServer(options.https, handler)
-    : http.createServer(handler);
-  
-  server.on('close', function () {
-    proxy.close();
-  });
-  
-  proxy.on('routes', function (routes) {
-    server.emit('routes', routes);
-  });
-
-  if (!callback) {

WebSocket support: if callback is empty tunnel -websocket request automatically

    server.on('upgrade', function (req, socket, head) {

Tunnel websocket requests too

      
-      proxy.proxyWebSocketRequest(req, socket, head, {
-        port: port,
-        host: host
-      });
-    });
-  }
-  

Set the proxy on the server so it is available -to the consumer of the server

  server.proxy = proxy;
-  
-  return server;
-};

function HttpProxy (options)

- -

@options {Object} Options for this instance.

- -

Constructor function for new instances of HttpProxy responsible -for managing the life-cycle of streaming reverse proxyied HTTP requests.

- -

Example options:

- -
 {
-   router: {
-     'foo.com': 'localhost:8080',
-     'bar.com': 'localhost:8081'
-   },
-   forward: {
-     host: 'localhost',
-     port: 9001
-   }
- } 
-
var HttpProxy = exports.HttpProxy = function (options) {
-  events.EventEmitter.call(this);
-  
-  var self          = this;
-  options           = options || {};
-  

Setup basic proxying options

  this.https        = options.https;
-  this.forward      = options.forward;
-  this.target       = options.target || {};
-  

Setup additional options for WebSocket proxying. When forcing -the WebSocket handshake to change the sec-websocket-location -and sec-websocket-origin headers options.source MUST -be provided or the operation will fail with an origin mismatch -by definition.

  this.source       = options.source || { host: 'localhost', port: 8000 };
-  this.changeOrigin = options.changeOrigin || false;
-  
-  if (options.router) {
-    this.proxyTable = new ProxyTable(options.router, options.silent, options.hostnameOnly);
-    this.proxyTable.on('routes', function (routes) {
-      self.emit('routes', routes);
-    });
-  }
-};

Inherit from events.EventEmitter

util.inherits(HttpProxy, events.EventEmitter);

function buffer (obj)

- -

@obj {Object} Object to pause events from

- -

Buffer data and end events from the given obj. -Consumers of HttpProxy performing async tasks -must utilize this utility, to re-emit data once -the async operation has completed, otherwise these -events will be lost.

- -
 var buffer = httpProxy.buffer(req);
- fs.readFile(path, function(){
-    httpProxy.proxyRequest(req, res, host, port, buffer);
- });
-
- -

Attribution: This approach is based heavily on -Connect. -However, this is not a big leap from the implementation in node-http-proxy < 0.4.0. -This simply chooses to manage the scope of the events on a new Object literal as opposed to -on the HttpProxy instance.

HttpProxy.prototype.buffer = function (obj) {
-  var onData, onEnd, events = [];
-
-  obj.on('data', onData = function (data, encoding) {
-    events.push(['data', data, encoding]);
-  });
-
-  obj.on('end', onEnd = function (data, encoding) {
-    events.push(['end', data, encoding]);
-  });
-
-  return {
-    end: function () {
-      obj.removeListener('data', onData);
-      obj.removeListener('end', onEnd);
-    },
-    resume: function () {
-      this.end();
-      for (var i = 0, len = events.length; i < len; ++i) {
-        obj.emit.apply(obj, events[i]);
-      }
-    }
-  };
-};

function close ()

- -

Frees the resources associated with this instance, -if they exist.

HttpProxy.prototype.close = function () {
-  if (this.proxyTable) this.proxyTable.close();
-};

function proxyRequest (req, res, [port, host, paused])

- -

@req {ServerRequest} Incoming HTTP Request to proxy.

- -

@res {ServerResponse} Outgoing HTTP Request to write proxied data to.

- -

@options {Object} Options for the outgoing proxy request.

- -
options.port {number} Port to use on the proxy target host.
-options.host {string} Host of the proxy target.
-options.buffer {Object} Result from `httpProxy.buffer(req)`
-options.https {Object|boolean} Settings for https.
-
HttpProxy.prototype.proxyRequest = function (req, res, options) {
-  var self = this, errState = false, location, outgoing, protocol, reverseProxy;
-  

Create an empty options hash if none is passed. -If default options have been passed to the constructor -of this instance, use them by default.

  options      = options || {};
-  options.host = options.host || this.target.host;
-  options.port = options.port || this.target.port;
-  

Check the proxy table for this instance to see if we need -to get the proxy location for the request supplied. We will -always ignore the proxyTable if an explicit port and host -arguments are supplied to proxyRequest.

  if (this.proxyTable && !options.host) {
-    location = this.proxyTable.getProxyLocation(req);
-    

If no location is returned from the ProxyTable instance -then respond with 404 since we do not have a valid proxy target.

    if (!location) {
-      res.writeHead(404);
-      return res.end();
-    }
-    

When using the ProxyTable in conjunction with an HttpProxy instance -only the following arguments are valid:

- -
    -
  • proxy.proxyRequest(req, res, { host: 'localhost' }): This will be skipped
  • -
  • proxy.proxyRequest(req, res, { buffer: buffer }): Buffer will get updated appropriately
  • -
  • proxy.proxyRequest(req, res): Options will be assigned appropriately.
  • -
    options.port = location.port;
-    options.host = location.host;
-  }
-  

Add common proxy headers to the request so that they can -be availible to the proxy target server:

- -
    -
  • x-forwarded-for: IP Address of the original request
  • -
  • x-forwarded-proto: Protocol of the original request
  • -
  • x-forwarded-port: Port of the original request.
  • -
  req.headers['x-forwarded-for']   = req.connection.remoteAddress || req.connection.socket.remoteAddress;
-  req.headers['x-forwarded-port']  = req.connection.remotePort || req.connection.socket.remotePort;
-  req.headers['x-forwarded-proto'] = res.connection.pair ? 'https' : 'http';
-  

Emit the start event indicating that we have begun the proxy operation.

  this.emit('start', req, res, options);
-  

If forwarding is enabled for this instance, foward proxy the -specified request to the address provided in this.forward

  if (this.forward) {
-    this.emit('forward', req, res, this.forward);
-    this._forwardRequest(req);
-  }
-  

function proxyError (err)

- -

@err {Error} Error contacting the proxy target

- -

Short-circuits res in the event of any error when -contacting the proxy target at host / port.

  function proxyError(err) {
-    errState = true;
-    

Emit an error event, allowing the application to use custom -error handling. The error handler should end the response.

    if (self.emit('proxyError', err, req, res)) {
-      return;
-    }
-
-    res.writeHead(500, { 'Content-Type': 'text/plain' });
-
-    if (req.method !== 'HEAD') {

This NODE_ENV=production behavior is mimics Express and -Connect.

      if (process.env.NODE_ENV === 'production') {
-        res.write('Internal Server Error');
-      }
-      else {
-        res.write('An error has occurred: ' + JSON.stringify(err));
-      }
-    }
-  
-    res.end();
-  }
-  
-  outgoing = {
-    host: options.host,
-    port: options.port,
-    agent: _getAgent(options.host, options.port, options.https || this.target.https),
-    method: req.method,
-    path: req.url,
-    headers: req.headers
-  };
-  
-  protocol = _getProtocol(options.https || this.target.https, outgoing);
-  

Open new HTTP request to internal resource with will act as a reverse proxy pass

  reverseProxy = protocol.request(outgoing, function (response) {
-    

Process the reverseProxy response when it's received.

    if (response.headers.connection) {
-      if (req.headers.connection) response.headers.connection = req.headers.connection;
-      else response.headers.connection = 'close';
-    }

Set the headers of the client response

    res.writeHead(response.statusCode, response.headers);

response.statusCode === 304: No 'data' event and no 'end'

    if (response.statusCode === 304) {
-      return res.end();
-    }

For each data chunk received from the reverseProxy -response write it to the outgoing res.

    response.on('data', function (chunk) {
-      if (req.method !== 'HEAD') {
-        res.write(chunk);
-      }
-    });

When the reverseProxy response ends, end the -corresponding outgoing res unless we have entered -an error state. In which case, assume res.end() has -already been called and the 'error' event listener -removed.

    response.on('end', function () {
-      if (!errState) {
-        reverseProxy.removeListener('error', proxyError);
-        res.end();
-        

Emit the end event now that we have completed proxying

        self.emit('end', req, res);
-      }
-    });
-  });
-  

Handle 'error' events from the reverseProxy.

  reverseProxy.once('error', proxyError);
-  

For each data chunk received from the incoming -req write it to the reverseProxy request.

  req.on('data', function (chunk) {
-    if (!errState) {
-      reverseProxy.write(chunk);
-    }
-  });

When the incoming req ends, end the corresponding reverseProxy -request unless we have entered an error state.

  req.on('end', function () {
-    if (!errState) {
-      reverseProxy.end();
-    }
-  });

If we have been passed buffered data, resume it.

  if (options.buffer && !errState) {
-    options.buffer.resume();
-  }
-};
-  

@private function _forwardRequest (req)

- -

@req {ServerRequest} Incoming HTTP Request to proxy.

- -

Forwards the specified req to the location specified -by this.forward ignoring errors and the subsequent response.

HttpProxy.prototype._forwardRequest = function (req) {
-  var self = this, port, host, outgoing, protocol, forwardProxy;
-
-  port = this.forward.port;
-  host = this.forward.host;
-  
-  outgoing = {
-    host: host,
-    port: port,
-    agent: _getAgent(host, port, this.forward.https),
-    method: req.method,
-    path: req.url,
-    headers: req.headers
-  };
-  

Force the connection header to be 'close' until -node.js core re-implements 'keep-alive'.

  outgoing.headers['connection'] = 'close';
-  
-  protocol = _getProtocol(this.forward.https, outgoing);
-  

Open new HTTP request to internal resource with will act as a reverse proxy pass

  forwardProxy = protocol.request(outgoing, function (response) {

Ignore the response from the forward proxy since this is a 'fire-and-forget' proxy. -Remark (indexzero): We will eventually emit a 'forward' event here for performance tuning.

  });
-  

Add a listener for the connection timeout event.

- -

Remark: Ignoring this error in the event - forward target doesn't exist.

  forwardProxy.once('error', function (err) { });

Chunk the client request body as chunks from the proxied request come in

  req.on('data', function (chunk) {
-    forwardProxy.write(chunk);
-  })

At the end of the client request, we are going to stop the proxied request

  req.on('end', function () {
-    forwardProxy.end();
-  });
-};

function proxyWebSocketRequest (req, socket, head, options)

- -

@req {ServerRequest} Websocket request to proxy.

- -

@socket {net.Socket} Socket for the underlying HTTP request

- -

@head {string} Headers for the Websocket request.

- -

@options {Object} Options to use when proxying this request.

- -
options.port {number} Port to use on the proxy target host.
-options.host {string} Host of the proxy target.
-options.buffer {Object} Result from `httpProxy.buffer(req)`
-options.https {Object|boolean} Settings for https.
-
HttpProxy.prototype.proxyWebSocketRequest = function (req, socket, head, options) {
-  var self      = this, 
-      listeners = {},
-      errState  = false, 
-      CRLF      = '\r\n',
-      outgoing;

WebSocket requests must have the GET method and -the upgrade:websocket header

  if (req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket') {

This request is not WebSocket request

    return;
-  }
-  

Helper function for setting appropriate socket values: -1. Turn of all bufferings -2. For server set KeepAlive -3. For client set encoding

  function _socket(socket, keepAlive) {
-    socket.setTimeout(0);
-    socket.setNoDelay(true);
-    if (keepAlive) {
-      if (socket.setKeepAlive) {
-        socket.setKeepAlive(true, 0);
-      }
-      else if (socket.pair.cleartext.socket.setKeepAlive) {
-        socket.pair.cleartext.socket.setKeepAlive(true, 0);
-      }
-    } 
-    else {
-      socket.setEncoding('utf8');
-    }
-  }
-  

On upgrade from the Agent socket, listen to -the appropriate events.

  function onUpgrade (reverseProxy, proxySocket) {
-    if (!reverseProxy) {
-      proxySocket.end();
-      socket.end();
-      return;
-    }
-    

Any incoming data on this WebSocket to the proxy target -will be written to the reverseProxy socket.

    proxySocket.on('data', listeners.onIncoming = function (data) {
-      if (reverseProxy.incoming.socket.writable) {
-        try {
-          self.emit('websocket:outgoing', req, socket, head, data);
-          reverseProxy.incoming.socket.write(data);
-        } 
-        catch (e) {
-          reverseProxy.incoming.socket.end();
-          proxySocket.end();
-        }
-      }
-    });

Any outgoing data on this Websocket from the proxy target -will be written to the proxySocket socket.

    reverseProxy.incoming.socket.on('data', listeners.onOutgoing = function(data) {
-      try {
-        self.emit('websocket:incoming', reverseProxy, reverseProxy.incoming, head, data);
-        proxySocket.write(data);
-      } 
-      catch (e) {
-        proxySocket.end();
-        socket.end();
-      }
-    });
-    

Helper function to detach all event listeners -from reverseProxy and proxySocket.

    function detach() {
-      proxySocket.removeListener('end', listeners.onIncomingClose);
-      proxySocket.removeListener('data', listeners.onIncoming);
-      reverseProxy.incoming.socket.removeListener('end', listeners.onOutgoingClose);
-      reverseProxy.incoming.socket.removeListener('data', listeners.onOutgoing);
-    }

If the incoming proxySocket socket closes, then -detach all event listeners.

    proxySocket.on('end', listeners.onIncomingClose = function() {
-      reverseProxy.incoming.socket.end();
-      detach();
-      

Emit the end event now that we have completed proxying

      self.emit('websocket:end', req, socket, head);
-    });

If the reverseProxy socket closes, then detach all -event listeners.

    reverseProxy.incoming.socket.on('end', listeners.onOutgoingClose = function() {
-      proxySocket.end();
-      detach();
-    });
-  };

Setup the incoming client socket.

  _socket(socket);
-  
-  function getPort (port) {
-    port = port || 80;
-    return port - 80 === 0 ? '' : ':' + port
-  }
-  

Get the protocol, and host for this request and create an instance -of http.Agent or https.Agent from the pool managed by node-http-proxy.

  var protocolName = options.https || this.target.https ? 'https' : 'http',
-      portUri      = getPort(this.source.port),
-      remoteHost   = options.host + portUri,
-      agent        = _getAgent(options.host, options.port, options.https || this.target.https);

Change headers (if requested).

  if (this.changeOrigin) {
-    req.headers.host   = remoteHost;
-    req.headers.origin = protocolName + '://' + remoteHost;
-  }
-  

Make the outgoing WebSocket request

  outgoing = {
-    host: options.host,
-    port: options.port,
-    method: 'GET',
-    path: req.url,
-    headers: req.headers,
-  };
-  var reverseProxy = agent.appendMessage(outgoing);

On any errors from the reverseProxy emit the -webSocketProxyError and close the appropriate -connections.

  function proxyError (err) {
-    reverseProxy.end();
-    if (self.emit('webSocketProxyError', req, socket, head)) {
-      return;
-    }
-    
-    socket.end();
-  }

Here we set the incoming req, socket and head data to the outgoing -request so that we can reuse this data later on in the closure scope -available to the upgrade event. This bookkeeping is not tracked anywhere -in nodejs core and is very specific to proxying WebSockets.

  reverseProxy.agent = agent;
-  reverseProxy.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 (_, remoteSocket, head) {

Prepare the socket for the reverseProxy request and begin to -stream data between the two sockets. Here it is important to -note that remoteSocket._httpMessage === reverseProxy.

      _socket(remoteSocket, true);
-      onUpgrade(remoteSocket._httpMessage, remoteSocket);
-    });
-  }
-  

If the reverseProxy connection has an underlying socket, -then execute the WebSocket handshake.

  if (typeof reverseProxy.socket !== 'undefined') {
-    reverseProxy.socket.on('data', function handshake (data) {

Ok, kind of harmfull part of code. Socket.IO sends a hash -at the end of handshake if protocol === 76, but we need -to replace 'host' and 'origin' in response so we split -data to printable data and to non-printable. (Non-printable -will come after double-CRLF).

      var sdata = data.toString();

Get the Printable data

      sdata = sdata.substr(0, sdata.search(CRLF + CRLF));

Get the Non-Printable data

      data = data.slice(Buffer.byteLength(sdata), data.length);
-      
-      if (self.https && !self.target.https) {

If the proxy server is running HTTPS but the client is running -HTTP then replace ws with wss in the data sent back to the client.

        sdata = sdata.replace('ws:', 'wss:');
-      }
-
-      try {

Write the printable and non-printable data to the socket -from the original incoming request.

        self.emit('websocket:handshake', req, socket, head, sdata, data);
-        socket.write(sdata);
-        socket.write(data);
-      } 
-      catch (ex) {
-        proxyError(ex)
-      }

Catch socket errors

      socket.on('error', proxyError);

Remove data listener now that the 'handshake' is complete

      reverseProxy.socket.removeListener('data', handshake);
-    });
-  }
-  
-  reverseProxy.on('error', proxyError);
-
-  try {

Attempt to write the upgrade-head to the reverseProxy request.

    reverseProxy.write(head);
-  } 
-  catch (ex) {
-    proxyError(ex);
-  }
-  

If we have been passed buffered data, resume it.

  if (options.buffer && !errState) {
-    options.buffer.resume();
-  }
-};
-
-
\ No newline at end of file diff --git a/docs/proxy-table.html b/docs/proxy-table.html deleted file mode 100644 index d03364740..000000000 --- a/docs/proxy-table.html +++ /dev/null @@ -1,136 +0,0 @@ - proxy-table.js

proxy-table.js

/*
-  node-http-proxy.js: Lookup table for proxy targets in node.js
-
-  Copyright (c) 2010 Charlie Robbins 
-
-  Permission is hereby granted, free of charge, to any person obtaining
-  a copy of this software and associated documentation files (the
-  "Software"), to deal in the Software without restriction, including
-  without limitation the rights to use, copy, modify, merge, publish,
-  distribute, sublicense, and/or sell copies of the Software, and to
-  permit persons to whom the Software is furnished to do so, subject to
-  the following conditions:
-
-  The above copyright notice and this permission notice shall be
-  included in all copies or substantial portions of the Software.
-
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-*/
-
-var util = require('util'),
-    events = require('events'),
-    fs = require('fs');

function ProxyTable (router, silent)

- -

@router {Object} Object containing the host based routes

- -

@silent {Boolean} Value indicating whether we should suppress logs

- -

@hostnameOnly {Boolean} Value indicating if we should route based on hostname string only

- -

Constructor function for the ProxyTable responsible for getting -locations of proxy targets based on ServerRequest headers; specifically -the HTTP host header.

var ProxyTable = exports.ProxyTable = function (router, silent, hostnameOnly) {
-  events.EventEmitter.call(this);
-  
-  this.silent = typeof silent !== 'undefined' ? silent : true;
-  this.hostnameOnly = typeof hostnameOnly !== 'undefined' ? hostnameOnly : false;
-  
-  if (typeof router === 'object') {

If we are passed an object literal setup -the routes with RegExps from the router

    this.setRoutes(router);
-  }
-  else if (typeof router === 'string') {

If we are passed a string then assume it is a -file path, parse that file and watch it for changes

    var self = this;
-    this.routeFile = router;
-    this.setRoutes(JSON.parse(fs.readFileSync(router)).router);
-    
-    fs.watchFile(this.routeFile, function () {
-      fs.readFile(self.routeFile, function (err, data) {
-        if (err) throw err;
-        self.setRoutes(JSON.parse(data).router);
-        self.emit('routes', self.hostnameOnly === false ? self.routes : self.router);
-      });
-    });
-  }
-  else {
-    throw new Error('Cannot parse router with unknown type: ' + typeof router);
-  }
-};

Inherit from events.EventEmitter

util.inherits(ProxyTable, events.EventEmitter);

function setRoutes (router)

- -

@router {Object} Object containing the host based routes

- -

Sets the host-based routes to be used by this instance.

ProxyTable.prototype.setRoutes = function (router) {
-  if (!router) throw new Error('Cannot update ProxyTable routes without router.');
-  
-  this.router = router;
-  
-  if (this.hostnameOnly === false) {
-    var self = this;
-    this.routes = [];
-
-    Object.keys(router).forEach(function (path) {
-      var route = new RegExp(path, 'i');
-
-      self.routes.push({
-        route: route,
-        target: router[path]
-      });
-    });
-  }
-};

function getProxyLocation (req)

- -

@req {ServerRequest} The incoming server request to get proxy information about.

- -

Returns the proxy location based on the HTTP Headers in the ServerRequest req -available to this instance.

ProxyTable.prototype.getProxyLocation = function (req) {
-  if (!req || !req.headers || !req.headers.host) {
-    return null;
-  }
-  
-  var target = req.headers.host.split(':')[0];
-  if (this.hostnameOnly == true) {
-    if (this.router.hasOwnProperty(target)) {
-      var location = this.router[target].split(':'),
-          host = location[0],
-          port = location.length === 1 ? 80 : location[1];
-      
-      return {
-        port: port,
-        host: host
-      };
-    }
-  }
-  else {
-    target += req.url;
-    for (var i in this.routes) {
-      var match, route = this.routes[i];
-      if (match = target.match(route.route)) {
-        var location = route.target.split(':'),
-            host = location[0],
-            port = location.length === 1 ? 80 : location[1];
-
-        return {
-          port: port,
-          host: host
-        };
-      }
-    }
-  }
-  
-  return null;
-};

close function ()

- -

Cleans up the event listeneners maintained -by this instance.

ProxyTable.prototype.close = function () {
-  if (typeof this.routeFile === 'string') {
-    fs.unwatchFile(this.routeFile);
-  }
-};
-
-
\ No newline at end of file