'use strict'; /** * Module dependencies. */ var createError = require('http-errors'); var httpAssert = require('http-assert'); var delegate = require('delegates'); var statuses = require('statuses'); /** * Context prototype. */ var proto = module.exports = { /** * util.inspect() implementation, which * just returns the JSON output. * * @return {Object} * @api public */ inspect: function(){ 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 */ toJSON: function(){ return { request: this.request.toJSON(), response: this.response.toJSON(), app: this.app.toJSON(), originalUrl: this.originalUrl, req: '<original node req>', res: '<original node res>', 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 `msg` and optional `status` * defaulting to 500. Note that these are user-level * errors, and the message may be exposed to the client. * * this.throw(403) * this.throw('name required', 400) * this.throw(400, 'name required') * this.throw('something exploded') * this.throw(new Error('invalid'), 400); * this.throw(400, new Error('invalid')); * * See: https://github.com/jshttp/http-errors * * @param {String|Number|Error} err, msg or status * @param {String|Number|Error} [err, msg or status] * @param {Object} [props] * @api public */ throw: function(){ throw createError.apply(null, arguments); }, /** * Default error handling. * * @param {Error} err * @api private */ onerror: function(err){ // don't do anything if there is no error. // this allows you to pass `this.onerror` // to node-style callbacks. if (null == err) return; if (!(err instanceof Error)) err = new Error('non-error thrown: ' + err); // delegate this.app.emit('error', err, this); // nothing we can do here other // than delegate to the app-level // handler and log. if (this.headerSent || !this.writable) { err.headerSent = true; return; } // unset all headers this.res._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 var code = statuses[err.status]; var msg = err.expose ? err.message : code; this.status = err.status; this.length = Buffer.byteLength(msg); this.res.end(msg); } }; /** * Response delegation. */ delegate(proto, 'response') .method('attachment') .method('redirect') .method('remove') .method('vary') .method('set') .method('append') .access('status') .access('message') .access('body') .access('length') .access('type') .access('lastModified') .access('etag') .getter('headerSent') .getter('writable'); /** * Request delegation. */ 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') .access('query') .access('path') .access('url') .getter('origin') .getter('href') .getter('subdomains') .getter('protocol') .getter('host') .getter('hostname') .getter('header') .getter('headers') .getter('secure') .getter('stale') .getter('fresh') .getter('ips') .getter('ip');