aboutsummaryrefslogtreecommitdiff
path: root/node_modules/finalhandler/index.js
diff options
context:
space:
mode:
authornanalelfe <nargiza.nosirova@mail.utoronto.ca>2016-07-18 10:54:08 +0000
committernanalelfe <nargiza.nosirova@mail.utoronto.ca>2016-07-18 10:54:08 +0000
commita35da9f9ccc1124d9b6f4461c7216ffbb0285e2f (patch)
treed5b4b8548caae36a20e1258a8341dab4b3d522d2 /node_modules/finalhandler/index.js
parent16bbc66ebafc6f1a55e47dbda3f3c0f658fe715c (diff)
parentc1ce89359a7b54ec97b54ce577e5534c180c5c4b (diff)
merged
Diffstat (limited to 'node_modules/finalhandler/index.js')
-rw-r--r--node_modules/finalhandler/index.js189
1 files changed, 189 insertions, 0 deletions
diff --git a/node_modules/finalhandler/index.js b/node_modules/finalhandler/index.js
new file mode 100644
index 0000000..884d802
--- /dev/null
+++ b/node_modules/finalhandler/index.js
@@ -0,0 +1,189 @@
+/*!
+ * finalhandler
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict'
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var debug = require('debug')('finalhandler')
+var escapeHtml = require('escape-html')
+var onFinished = require('on-finished')
+var statuses = require('statuses')
+var unpipe = require('unpipe')
+
+/**
+ * Module variables.
+ * @private
+ */
+
+/* istanbul ignore next */
+var defer = typeof setImmediate === 'function'
+ ? setImmediate
+ : function (fn) { process.nextTick(fn.bind.apply(fn, arguments)) }
+var isFinished = onFinished.isFinished
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = finalhandler
+
+/**
+ * Create a function to handle the final response.
+ *
+ * @param {Request} req
+ * @param {Response} res
+ * @param {Object} [options]
+ * @return {Function}
+ * @public
+ */
+
+function finalhandler (req, res, options) {
+ var opts = options || {}
+
+ // get environment
+ var env = opts.env || process.env.NODE_ENV || 'development'
+
+ // get error callback
+ var onerror = opts.onerror
+
+ return function (err) {
+ var headers = Object.create(null)
+ var status
+
+ // ignore 404 on in-flight response
+ if (!err && res._header) {
+ debug('cannot 404 after headers sent')
+ return
+ }
+
+ // unhandled error
+ if (err) {
+ // respect status code from error
+ status = getErrorStatusCode(err) || res.statusCode
+
+ // default status code to 500 if outside valid range
+ if (typeof status !== 'number' || status < 400 || status > 599) {
+ status = 500
+ }
+
+ // respect err.headers
+ if (err.headers && (err.status === status || err.statusCode === status)) {
+ var keys = Object.keys(err.headers)
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i]
+ headers[key] = err.headers[key]
+ }
+ }
+
+ // production gets a basic error message
+ var msg = env === 'production'
+ ? statuses[status]
+ : err.stack || err.toString()
+ msg = escapeHtml(msg)
+ .replace(/\n/g, '<br>')
+ .replace(/\x20{2}/g, ' &nbsp;') + '\n'
+ } else {
+ status = 404
+ msg = 'Cannot ' + escapeHtml(req.method) + ' ' + escapeHtml(req.originalUrl || req.url) + '\n'
+ }
+
+ debug('default %s', status)
+
+ // schedule onerror callback
+ if (err && onerror) {
+ defer(onerror, err, req, res)
+ }
+
+ // cannot actually respond
+ if (res._header) {
+ debug('cannot %d after headers sent', status)
+ req.socket.destroy()
+ return
+ }
+
+ // send response
+ send(req, res, status, headers, msg)
+ }
+}
+
+/**
+ * Get status code from Error object.
+ *
+ * @param {Error} err
+ * @return {number}
+ * @private
+ */
+
+function getErrorStatusCode (err) {
+ // check err.status
+ if (typeof err.status === 'number' && err.status >= 400 && err.status < 600) {
+ return err.status
+ }
+
+ // check err.statusCode
+ if (typeof err.statusCode === 'number' && err.statusCode >= 400 && err.statusCode < 600) {
+ return err.statusCode
+ }
+
+ return undefined
+}
+
+/**
+ * Send response.
+ *
+ * @param {IncomingMessage} req
+ * @param {OutgoingMessage} res
+ * @param {number} status
+ * @param {object} headers
+ * @param {string} body
+ * @private
+ */
+
+function send (req, res, status, headers, body) {
+ function write () {
+ // response status
+ res.statusCode = status
+ res.statusMessage = statuses[status]
+
+ // response headers
+ var keys = Object.keys(headers)
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i]
+ res.setHeader(key, headers[key])
+ }
+
+ // security header for content sniffing
+ res.setHeader('X-Content-Type-Options', 'nosniff')
+
+ // standard headers
+ res.setHeader('Content-Type', 'text/html; charset=utf-8')
+ res.setHeader('Content-Length', Buffer.byteLength(body, 'utf8'))
+
+ if (req.method === 'HEAD') {
+ res.end()
+ return
+ }
+
+ res.end(body, 'utf8')
+ }
+
+ if (isFinished(req)) {
+ write()
+ return
+ }
+
+ // unpipe everything from the request
+ unpipe(req)
+
+ // flush the request
+ onFinished(req, write)
+ req.resume()
+}