arnaucube
arnaucube/socketioMEANseedPublic Self-hosted repository
socketioMEANseed/server/node_modules/finalhandler/index.js
server/node_modules/finalhandler/index.jsRaw
  1/*!
  2 * finalhandler
  3 * Copyright(c) 2014 Douglas Christopher Wilson
  4 * MIT Licensed
  5 */
  6
  7/**
  8 * Module dependencies.
  9 */
 10
 11var debug = require('debug')('finalhandler')
 12var escapeHtml = require('escape-html')
 13var http = require('http')
 14var onFinished = require('on-finished')
 15
 16/**
 17 * Variables.
 18 */
 19
 20/* istanbul ignore next */
 21var defer = typeof setImmediate === 'function'
 22  ? setImmediate
 23  : function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
 24var isFinished = onFinished.isFinished
 25
 26/**
 27 * Module exports.
 28 */
 29
 30module.exports = finalhandler
 31
 32/**
 33 * Final handler:
 34 *
 35 * @param {Request} req
 36 * @param {Response} res
 37 * @param {Object} [options]
 38 * @return {Function}
 39 * @api public
 40 */
 41
 42function finalhandler(req, res, options) {
 43  options = options || {}
 44
 45  // get environment
 46  var env = options.env || process.env.NODE_ENV || 'development'
 47
 48  // get error callback
 49  var onerror = options.onerror
 50
 51  return function (err) {
 52    var msg
 53
 54    // ignore 404 on in-flight response
 55    if (!err && res._header) {
 56      debug('cannot 404 after headers sent')
 57      return
 58    }
 59
 60    // unhandled error
 61    if (err) {
 62      // default status code to 500
 63      if (!res.statusCode || res.statusCode < 400) {
 64        res.statusCode = 500
 65      }
 66
 67      // respect err.status
 68      if (err.status) {
 69        res.statusCode = err.status
 70      }
 71
 72      // production gets a basic error message
 73      var msg = env === 'production'
 74        ? http.STATUS_CODES[res.statusCode]
 75        : err.stack || err.toString()
 76      msg = escapeHtml(msg)
 77        .replace(/\n/g, '<br>')
 78        .replace(/  /g, ' &nbsp;') + '\n'
 79    } else {
 80      res.statusCode = 404
 81      msg = 'Cannot ' + escapeHtml(req.method) + ' ' + escapeHtml(req.originalUrl || req.url) + '\n'
 82    }
 83
 84    debug('default %s', res.statusCode)
 85
 86    // schedule onerror callback
 87    if (err && onerror) {
 88      defer(onerror, err, req, res)
 89    }
 90
 91    // cannot actually respond
 92    if (res._header) {
 93      return req.socket.destroy()
 94    }
 95
 96    send(req, res, res.statusCode, msg)
 97  }
 98}
 99
100/**
101 * Send response.
102 *
103 * @param {IncomingMessage} req
104 * @param {OutgoingMessage} res
105 * @param {number} status
106 * @param {string} body
107 * @api private
108 */
109
110function send(req, res, status, body) {
111  function write() {
112    res.statusCode = status
113
114    // security header for content sniffing
115    res.setHeader('X-Content-Type-Options', 'nosniff')
116
117    // standard headers
118    res.setHeader('Content-Type', 'text/html; charset=utf-8')
119    res.setHeader('Content-Length', Buffer.byteLength(body, 'utf8'))
120
121    if (req.method === 'HEAD') {
122      res.end()
123      return
124    }
125
126    res.end(body, 'utf8')
127  }
128
129  if (isFinished(req)) {
130    write()
131    return
132  }
133
134  // unpipe everything from the request
135  unpipe(req)
136
137  // flush the request
138  onFinished(req, write)
139  req.resume()
140}
141
142/**
143 * Unpipe everything from a stream.
144 *
145 * @param {Object} stream
146 * @api private
147 */
148
149/* istanbul ignore next: implementation differs between versions */
150function unpipe(stream) {
151  if (typeof stream.unpipe === 'function') {
152    // new-style
153    stream.unpipe()
154    return
155  }
156
157  // Node.js 0.8 hack
158  var listener
159  var listeners = stream.listeners('close')
160
161  for (var i = 0; i < listeners.length; i++) {
162    listener = listeners[i]
163
164    if (listener.name !== 'cleanup' && listener.name !== 'onclose') {
165      continue
166    }
167
168    // invoke the listener
169    listener.call(stream)
170  }
171}