2013-11-13 17:01:15 +00:00
|
|
|
|
2015-10-11 22:59:51 +00:00
|
|
|
'use strict';
|
|
|
|
|
2013-08-17 07:15:57 +00:00
|
|
|
/**
|
|
|
|
* Module dependencies.
|
|
|
|
*/
|
|
|
|
|
2015-10-05 18:23:47 +00:00
|
|
|
const createError = require('http-errors');
|
|
|
|
const httpAssert = require('http-assert');
|
|
|
|
const delegate = require('delegates');
|
|
|
|
const statuses = require('statuses');
|
2013-08-17 07:15:57 +00:00
|
|
|
|
|
|
|
/**
|
2014-01-13 14:36:10 +00:00
|
|
|
* Context prototype.
|
2013-08-17 07:15:57 +00:00
|
|
|
*/
|
|
|
|
|
2015-10-05 18:23:47 +00:00
|
|
|
const proto = module.exports = {
|
2013-08-17 07:15:57 +00:00
|
|
|
|
2014-08-02 11:10:07 +00:00
|
|
|
/**
|
|
|
|
* util.inspect() implementation, which
|
|
|
|
* just returns the JSON output.
|
|
|
|
*
|
|
|
|
* @return {Object}
|
|
|
|
* @api public
|
|
|
|
*/
|
|
|
|
|
2015-10-12 06:51:31 +00:00
|
|
|
inspect() {
|
2014-08-02 11:10:07 +00:00
|
|
|
return this.toJSON();
|
|
|
|
},
|
|
|
|
|
2013-11-19 01:33:41 +00:00
|
|
|
/**
|
|
|
|
* Return JSON representation.
|
|
|
|
*
|
2013-12-29 18:19:21 +00:00
|
|
|
* Here we explicitly invoke .toJSON() on each
|
|
|
|
* object, as iteration will otherwise fail due
|
|
|
|
* to the getters and cause utilities such as
|
|
|
|
* clone() to fail.
|
|
|
|
*
|
2013-11-19 01:33:41 +00:00
|
|
|
* @return {Object}
|
|
|
|
* @api public
|
|
|
|
*/
|
|
|
|
|
2015-10-12 06:51:31 +00:00
|
|
|
toJSON() {
|
2013-11-19 01:33:41 +00:00
|
|
|
return {
|
2013-12-29 18:19:21 +00:00
|
|
|
request: this.request.toJSON(),
|
2014-08-02 11:10:07 +00:00
|
|
|
response: this.response.toJSON(),
|
|
|
|
app: this.app.toJSON(),
|
|
|
|
originalUrl: this.originalUrl,
|
|
|
|
req: '<original node req>',
|
|
|
|
res: '<original node res>',
|
2015-10-12 20:36:03 +00:00
|
|
|
socket: '<original node socket>'
|
|
|
|
};
|
2013-11-19 01:33:41 +00:00
|
|
|
},
|
|
|
|
|
2014-09-09 05:07:10 +00:00
|
|
|
/**
|
|
|
|
* Similar to .throw(), adds assertion.
|
|
|
|
*
|
|
|
|
* this.assert(this.user, 401, 'Please login!');
|
|
|
|
*
|
|
|
|
* See: https://github.com/jshttp/http-assert
|
|
|
|
*
|
|
|
|
* @param {Mixed} test
|
|
|
|
* @param {Number} status
|
|
|
|
* @param {String} message
|
|
|
|
* @api public
|
|
|
|
*/
|
|
|
|
|
|
|
|
assert: httpAssert,
|
|
|
|
|
2013-11-19 01:33:41 +00:00
|
|
|
/**
|
|
|
|
* Throw an error with `msg` and optional `status`
|
|
|
|
* defaulting to 500. Note that these are user-level
|
|
|
|
* errors, and the message may be exposed to the client.
|
|
|
|
*
|
2013-11-19 01:38:12 +00:00
|
|
|
* this.throw(403)
|
|
|
|
* this.throw('name required', 400)
|
2013-12-20 23:34:16 +00:00
|
|
|
* this.throw(400, 'name required')
|
2013-11-19 01:38:12 +00:00
|
|
|
* this.throw('something exploded')
|
2014-01-04 08:23:39 +00:00
|
|
|
* this.throw(new Error('invalid'), 400);
|
|
|
|
* this.throw(400, new Error('invalid'));
|
2013-11-19 01:33:41 +00:00
|
|
|
*
|
2014-09-09 05:07:10 +00:00
|
|
|
* See: https://github.com/jshttp/http-errors
|
|
|
|
*
|
2014-01-04 08:23:39 +00:00
|
|
|
* @param {String|Number|Error} err, msg or status
|
2014-08-12 20:19:14 +00:00
|
|
|
* @param {String|Number|Error} [err, msg or status]
|
2014-08-08 19:37:04 +00:00
|
|
|
* @param {Object} [props]
|
2013-11-19 01:33:41 +00:00
|
|
|
* @api public
|
|
|
|
*/
|
|
|
|
|
2017-04-23 23:14:16 +00:00
|
|
|
throw(...args) {
|
|
|
|
throw createError(...args);
|
2013-11-19 01:33:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Default error handling.
|
|
|
|
*
|
|
|
|
* @param {Error} err
|
|
|
|
* @api private
|
|
|
|
*/
|
|
|
|
|
2015-10-12 06:51:31 +00:00
|
|
|
onerror(err) {
|
2013-11-19 01:33:41 +00:00
|
|
|
// don't do anything if there is no error.
|
|
|
|
// this allows you to pass `this.onerror`
|
|
|
|
// to node-style callbacks.
|
2014-04-25 00:58:37 +00:00
|
|
|
if (null == err) return;
|
2014-04-24 17:08:08 +00:00
|
|
|
|
2015-10-09 04:01:32 +00:00
|
|
|
if (!(err instanceof Error)) err = new Error(`non-error thrown: ${err}`);
|
2013-11-19 01:33:41 +00:00
|
|
|
|
2017-02-28 02:52:54 +00:00
|
|
|
let headerSent = false;
|
|
|
|
if (this.headerSent || !this.writable) {
|
|
|
|
headerSent = err.headerSent = true;
|
|
|
|
}
|
|
|
|
|
2014-05-23 13:15:03 +00:00
|
|
|
// delegate
|
|
|
|
this.app.emit('error', err, this);
|
|
|
|
|
2013-11-19 01:33:41 +00:00
|
|
|
// nothing we can do here other
|
|
|
|
// than delegate to the app-level
|
|
|
|
// handler and log.
|
2017-02-28 02:52:54 +00:00
|
|
|
if (headerSent) {
|
2013-11-19 01:33:41 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-08 06:59:24 +00:00
|
|
|
const { res } = this;
|
|
|
|
|
|
|
|
// first unset all headers
|
|
|
|
if (typeof res.getHeaderNames === 'function') {
|
|
|
|
res.getHeaderNames().forEach(name => res.removeHeader(name));
|
|
|
|
} else {
|
|
|
|
res._headers = {}; // Node < 7.7
|
|
|
|
}
|
|
|
|
|
|
|
|
// then set those specified
|
2016-02-29 20:22:59 +00:00
|
|
|
this.set(err.headers);
|
2014-01-24 22:29:57 +00:00
|
|
|
|
2013-11-19 01:33:41 +00:00
|
|
|
// force text/plain
|
|
|
|
this.type = 'text';
|
|
|
|
|
|
|
|
// ENOENT support
|
|
|
|
if ('ENOENT' == err.code) err.status = 404;
|
|
|
|
|
|
|
|
// default to 500
|
2014-10-01 12:12:20 +00:00
|
|
|
if ('number' != typeof err.status || !statuses[err.status]) err.status = 500;
|
2013-11-19 01:33:41 +00:00
|
|
|
|
|
|
|
// respond
|
2015-10-05 18:23:47 +00:00
|
|
|
const code = statuses[err.status];
|
|
|
|
const msg = err.expose ? err.message : code;
|
2013-11-19 01:33:41 +00:00
|
|
|
this.status = err.status;
|
2014-01-24 22:29:57 +00:00
|
|
|
this.length = Buffer.byteLength(msg);
|
2013-11-19 01:33:41 +00:00
|
|
|
this.res.end(msg);
|
2014-01-13 14:36:10 +00:00
|
|
|
}
|
|
|
|
};
|
2013-11-13 17:01:15 +00:00
|
|
|
|
2014-01-13 14:36:10 +00:00
|
|
|
/**
|
|
|
|
* Response delegation.
|
|
|
|
*/
|
2013-11-13 17:01:15 +00:00
|
|
|
|
2014-01-13 14:36:10 +00:00
|
|
|
delegate(proto, 'response')
|
|
|
|
.method('attachment')
|
|
|
|
.method('redirect')
|
|
|
|
.method('remove')
|
|
|
|
.method('vary')
|
2014-01-13 14:36:49 +00:00
|
|
|
.method('set')
|
2015-01-25 17:53:55 +00:00
|
|
|
.method('append')
|
2016-03-04 03:57:52 +00:00
|
|
|
.method('flushHeaders')
|
2014-01-13 14:36:10 +00:00
|
|
|
.access('status')
|
2014-10-01 12:12:20 +00:00
|
|
|
.access('message')
|
2014-01-13 14:36:10 +00:00
|
|
|
.access('body')
|
2014-02-14 17:16:39 +00:00
|
|
|
.access('length')
|
|
|
|
.access('type')
|
2014-06-05 23:19:29 +00:00
|
|
|
.access('lastModified')
|
|
|
|
.access('etag')
|
2014-01-13 14:36:10 +00:00
|
|
|
.getter('headerSent')
|
2014-06-05 23:19:29 +00:00
|
|
|
.getter('writable');
|
2013-11-13 17:01:15 +00:00
|
|
|
|
2014-01-13 14:36:10 +00:00
|
|
|
/**
|
|
|
|
* Request delegation.
|
|
|
|
*/
|
2013-11-13 17:01:15 +00:00
|
|
|
|
2014-01-13 14:36:10 +00:00
|
|
|
delegate(proto, 'request')
|
|
|
|
.method('acceptsLanguages')
|
|
|
|
.method('acceptsEncodings')
|
|
|
|
.method('acceptsCharsets')
|
|
|
|
.method('accepts')
|
|
|
|
.method('get')
|
|
|
|
.method('is')
|
|
|
|
.access('querystring')
|
|
|
|
.access('idempotent')
|
|
|
|
.access('socket')
|
|
|
|
.access('search')
|
|
|
|
.access('method')
|
2014-01-13 14:36:49 +00:00
|
|
|
.access('query')
|
2014-01-13 14:36:10 +00:00
|
|
|
.access('path')
|
|
|
|
.access('url')
|
2015-09-20 06:23:42 +00:00
|
|
|
.getter('origin')
|
2014-11-23 08:00:17 +00:00
|
|
|
.getter('href')
|
2014-01-13 14:36:10 +00:00
|
|
|
.getter('subdomains')
|
|
|
|
.getter('protocol')
|
2014-05-04 14:43:58 +00:00
|
|
|
.getter('host')
|
2014-02-26 06:03:05 +00:00
|
|
|
.getter('hostname')
|
2017-06-20 16:57:30 +00:00
|
|
|
.getter('URL')
|
2014-01-13 14:36:10 +00:00
|
|
|
.getter('header')
|
2014-08-04 03:26:07 +00:00
|
|
|
.getter('headers')
|
2014-01-13 14:36:49 +00:00
|
|
|
.getter('secure')
|
2014-01-13 14:36:10 +00:00
|
|
|
.getter('stale')
|
|
|
|
.getter('fresh')
|
|
|
|
.getter('ips')
|
2014-01-13 14:36:49 +00:00
|
|
|
.getter('ip');
|