arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/www/node_modules/union/lib/routing-stream.js
www/node_modules/union/lib/routing-stream.jsRaw
  1/*
  2 * routing-stream.js: A Stream focused on connecting an arbitrary RequestStream and
  3 * ResponseStream through a given Router.
  4 *
  5 * (C) 2011, Charlie Robbins & the Contributors
  6 * MIT LICENSE
  7 *
  8 */
  9
 10var util = require('util'),
 11    union = require('./index'),
 12    RequestStream = require('./request-stream'),
 13    ResponseStream = require('./response-stream');
 14
 15//
 16// ### function RoutingStream (options)
 17//
 18//
 19var RoutingStream = module.exports = function (options) {
 20  options = options || {};
 21  RequestStream.call(this, options);
 22
 23  this.before = options.before || [];
 24  this.after = options.after || [];
 25  this.response = options.response || options.res;
 26  this.headers = options.headers || {
 27    'x-powered-by': 'union ' + union.version
 28  };
 29
 30  this.target = new ResponseStream({
 31    response: this.response,
 32    headers: this.headers
 33  });
 34
 35  this.once('pipe', this.route);
 36};
 37
 38util.inherits(RoutingStream, RequestStream);
 39
 40//
 41// Called when this instance is piped to **by another stream**
 42//
 43RoutingStream.prototype.route = function (req) {
 44  //
 45  // When a `RoutingStream` is piped to:
 46  //
 47  // 1. Setup the pipe-chain between the `after` middleware, the abstract response
 48  //    and the concrete response.
 49  // 2. Attempt to dispatch to the `before` middleware, which represent things such as
 50  //    favicon, static files, application routing.
 51  // 3. If no match is found then pipe to the 404Stream
 52  //
 53  var self = this,
 54      after,
 55      error,
 56      i;
 57
 58  //
 59  // Don't allow `this.target` to be writable on HEAD requests
 60  //
 61  this.target.writable = req.method !== 'HEAD';
 62
 63  //
 64  // 1. Setup the pipe-chain between the `after` middleware, the abstract response
 65  //    and the concrete response.
 66  //
 67  after = [this.target].concat(this.after, this.response);
 68  for (i = 0; i < after.length - 1; i++) {
 69    //
 70    // attach req and res to all streams
 71    //
 72    after[i].req     = req;
 73    after[i + 1].req = req;
 74    after[i].res     = this.response;
 75    after[i + 1].res = this.response;
 76    after[i].pipe(after[i + 1]);
 77
 78    //
 79    // prevent multiple responses and memory leaks
 80    //
 81    after[i].on('error', this.onError);
 82  }
 83
 84  //
 85  // Helper function for dispatching to the 404 stream.
 86  //
 87  function notFound() {
 88    error = new Error('Not found');
 89    error.status = 404;
 90    self.onError(error);
 91  }
 92
 93  //
 94  // 2. Attempt to dispatch to the `before` middleware, which represent things such as
 95  //    favicon, static files, application routing.
 96  //
 97  (function dispatch(i) {
 98    if (self.target.modified) {
 99      return;
100    }
101    else if (++i === self.before.length) {
102      //
103      // 3. If no match is found then pipe to the 404Stream
104      //
105      return notFound();
106    }
107
108    self.target.once('next', dispatch.bind(null, i));
109    if (self.before[i].length === 3) {
110      self.before[i](self, self.target, function (err) {
111        if (err) {
112          self.onError(err);
113        } else {
114          self.target.emit('next');
115        }
116      });
117    }
118    else {
119      self.before[i](self, self.target);
120    }
121  })(-1);
122};
123
124RoutingStream.prototype.onError = function (err) {
125  this.emit('error', err);
126};