koa-lite/lib/context.js

243 lines
5 KiB
JavaScript
Raw Permalink Normal View History

'use strict';
2013-08-17 07:15:57 +00:00
/**
* Module dependencies.
*/
const util = require('util');
const createError = require('http-errors');
const httpAssert = require('http-assert');
const delegate = require('delegates');
const statuses = require('statuses');
const Cookies = require('cookies');
const COOKIES = Symbol('context#cookies');
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
*/
const proto = module.exports = {
2013-08-17 07:15:57 +00:00
/**
* util.inspect() implementation, which
* just returns the JSON output.
*
* @return {Object}
* @api public
*/
2015-10-12 06:51:31 +00:00
inspect() {
if (this === proto) return this;
return this.toJSON();
},
/**
* Return JSON representation.
*
* 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.
*
* @return {Object}
* @api public
*/
2015-10-12 06:51:31 +00:00
toJSON() {
return {
request: this.request.toJSON(),
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>'
};
},
/**
* 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,
/**
* Throw an error with `status` (default 500) and
* `msg`. Note that these are user-level
* errors, and the message may be exposed to the client.
*
* this.throw(403)
* this.throw(400, 'name required')
* this.throw('something exploded')
* this.throw(new Error('invalid'))
* this.throw(400, new Error('invalid'))
*
* See: https://github.com/jshttp/http-errors
*
* Note: `status` should only be passed as the first parameter.
*
2014-01-04 08:23:39 +00:00
* @param {String|Number|Error} err, msg or status
* @param {String|Number|Error} [err, msg or status]
* @param {Object} [props]
* @api public
*/
2017-04-23 23:14:16 +00:00
throw(...args) {
throw createError(...args);
},
/**
* Default error handling.
*
* @param {Error} err
* @api private
*/
2015-10-12 06:51:31 +00:00
onerror(err) {
// 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
if (!(err instanceof Error)) err = new Error(util.format('non-error thrown: %j', err));
let headerSent = false;
if (this.headerSent || !this.writable) {
headerSent = err.headerSent = true;
}
// delegate
this.app.emit('error', err, this);
// nothing we can do here other
// than delegate to the app-level
// handler and log.
if (headerSent) {
return;
}
const { res } = this;
// first unset all headers
2018-06-30 17:29:19 +00:00
/* istanbul ignore else */
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);
// force text/plain
this.type = 'text';
// ENOENT support
if ('ENOENT' == err.code) err.status = 404;
// default to 500
if ('number' != typeof err.status || !statuses[err.status]) err.status = 500;
// respond
const code = statuses[err.status];
const msg = err.expose ? err.message : code;
this.status = err.status;
this.length = Buffer.byteLength(msg);
res.end(msg);
},
get cookies() {
if (!this[COOKIES]) {
this[COOKIES] = new Cookies(this.req, this.res, {
keys: this.app.keys,
secure: this.request.secure
});
}
return this[COOKIES];
},
set cookies(_cookies) {
this[COOKIES] = _cookies;
2014-01-13 14:36:10 +00:00
}
};
/**
* Custom inspection implementation for newer Node.js versions.
*
* @return {Object}
* @api public
*/
2018-06-30 17:29:19 +00:00
/* istanbul ignore else */
if (util.inspect.custom) {
module.exports[util.inspect.custom] = module.exports.inspect;
}
2014-01-13 14:36:10 +00:00
/**
* Response delegation.
*/
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')
.method('append')
2016-03-04 03:57:52 +00:00
.method('flushHeaders')
2014-01-13 14:36:10 +00:00
.access('status')
.access('message')
2014-01-13 14:36:10 +00:00
.access('body')
.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');
2014-01-13 14:36:10 +00:00
/**
* Request delegation.
*/
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')
.access('accept')
2015-09-20 06:23:42 +00:00
.getter('origin')
.getter('href')
2014-01-13 14:36:10 +00:00
.getter('subdomains')
.getter('protocol')
2014-05-04 14:43:58 +00:00
.getter('host')
.getter('hostname')
.getter('URL')
2014-01-13 14:36:10 +00:00
.getter('header')
.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');