koa 2.14.2 → 3.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/History.md +674 -0
- package/Readme.md +6 -7
- package/lib/application.js +144 -134
- package/lib/context.js +45 -45
- package/lib/request.js +153 -153
- package/lib/response.js +154 -148
- package/package.json +7 -16
package/Readme.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[![gitter][gitter-image]][gitter-url]
|
|
4
4
|
[![NPM version][npm-image]][npm-url]
|
|
5
|
-
[![build status][
|
|
5
|
+
[![build status][github-action-image]][github-action-url]
|
|
6
6
|
[![Test coverage][coveralls-image]][coveralls-url]
|
|
7
7
|
[![OpenCollective Backers][backers-image]](#backers)
|
|
8
8
|
[![OpenCollective Sponsors][sponsors-image]](#sponsors)
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
-
Koa requires __node
|
|
20
|
+
Koa requires __node v12.17.0__ or higher for ES2015 and async function support.
|
|
21
21
|
|
|
22
22
|
```
|
|
23
23
|
$ npm install koa
|
|
@@ -40,9 +40,7 @@ app.listen(3000);
|
|
|
40
40
|
## Getting started
|
|
41
41
|
|
|
42
42
|
- [Kick-Off-Koa](https://github.com/koajs/kick-off-koa) - An intro to Koa via a set of self-guided workshops.
|
|
43
|
-
- [
|
|
44
|
-
- [Introduction Screencast](https://knowthen.com/episode-3-koajs-quickstart-guide/) - An introduction to installing and getting started with Koa
|
|
45
|
-
|
|
43
|
+
- [Guide](docs/guide.md) - Go straight to the docs.
|
|
46
44
|
|
|
47
45
|
## Middleware
|
|
48
46
|
|
|
@@ -181,6 +179,7 @@ See [AUTHORS](AUTHORS).
|
|
|
181
179
|
|
|
182
180
|
## Community
|
|
183
181
|
|
|
182
|
+
- [KoaJS Slack Group](https://join.slack.com/t/koa-js/shared_invite/zt-5pjgthmb-1JeKDbByqqcARtlPbtf~vQ)
|
|
184
183
|
- [Badgeboard](https://koajs.github.io/badgeboard) and list of official modules
|
|
185
184
|
- [Examples](https://github.com/koajs/examples)
|
|
186
185
|
- [Middleware](https://github.com/koajs/koa/wiki) list
|
|
@@ -276,8 +275,8 @@ Become a sponsor and get your logo on our README on Github with a link to your s
|
|
|
276
275
|
|
|
277
276
|
[npm-image]: https://img.shields.io/npm/v/koa.svg?style=flat-square
|
|
278
277
|
[npm-url]: https://www.npmjs.com/package/koa
|
|
279
|
-
[
|
|
280
|
-
[
|
|
278
|
+
[github-action-image]: https://github.com/koajs/koa/actions/workflows/node.js.yml/badge.svg
|
|
279
|
+
[github-action-url]: https://github.com/koajs/koa/actions/workflows/node.js.yml
|
|
281
280
|
[coveralls-image]: https://img.shields.io/codecov/c/github/koajs/koa.svg?style=flat-square
|
|
282
281
|
[coveralls-url]: https://codecov.io/github/koajs/koa?branch=master
|
|
283
282
|
[backers-image]: https://opencollective.com/koajs/backers/badge.svg?style=flat-square
|
package/lib/application.js
CHANGED
|
@@ -1,27 +1,38 @@
|
|
|
1
1
|
|
|
2
|
-
'use strict'
|
|
2
|
+
'use strict'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Module dependencies.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const onFinished = require('on-finished')
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
8
|
+
const debug = require('debug')('koa:application')
|
|
9
|
+
const assert = require('assert')
|
|
10
|
+
const onFinished = require('on-finished')
|
|
11
|
+
const response = require('./response')
|
|
12
|
+
const compose = require('koa-compose')
|
|
13
|
+
const context = require('./context')
|
|
14
|
+
const request = require('./request')
|
|
15
|
+
const statuses = require('statuses')
|
|
16
|
+
const Emitter = require('events')
|
|
17
|
+
const util = require('util')
|
|
18
|
+
const Stream = require('stream')
|
|
19
|
+
const http = require('http')
|
|
20
|
+
const only = require('only')
|
|
21
|
+
const { HttpError } = require('http-errors')
|
|
22
|
+
|
|
23
|
+
/** @typedef {typeof import ('./context') & {
|
|
24
|
+
* app: Application
|
|
25
|
+
* req: import('http').IncomingMessage
|
|
26
|
+
* res: import('http').ServerResponse
|
|
27
|
+
* request: KoaRequest
|
|
28
|
+
* response: KoaResponse
|
|
29
|
+
* state: any
|
|
30
|
+
* originalUrl: string
|
|
31
|
+
* }} Context */
|
|
32
|
+
|
|
33
|
+
/** @typedef {typeof import('./request')} KoaRequest */
|
|
34
|
+
|
|
35
|
+
/** @typedef {typeof import('./response')} KoaResponse */
|
|
25
36
|
|
|
26
37
|
/**
|
|
27
38
|
* Expose `Application` class.
|
|
@@ -47,28 +58,29 @@ module.exports = class Application extends Emitter {
|
|
|
47
58
|
*
|
|
48
59
|
*/
|
|
49
60
|
|
|
50
|
-
constructor(options) {
|
|
51
|
-
super()
|
|
52
|
-
options = options || {}
|
|
53
|
-
this.proxy = options.proxy || false
|
|
54
|
-
this.subdomainOffset = options.subdomainOffset || 2
|
|
55
|
-
this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For'
|
|
56
|
-
this.maxIpsCount = options.maxIpsCount || 0
|
|
57
|
-
this.env = options.env || process.env.NODE_ENV || 'development'
|
|
58
|
-
|
|
59
|
-
this.
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
this.
|
|
61
|
+
constructor (options) {
|
|
62
|
+
super()
|
|
63
|
+
options = options || {}
|
|
64
|
+
this.proxy = options.proxy || false
|
|
65
|
+
this.subdomainOffset = options.subdomainOffset || 2
|
|
66
|
+
this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For'
|
|
67
|
+
this.maxIpsCount = options.maxIpsCount || 0
|
|
68
|
+
this.env = options.env || process.env.NODE_ENV || 'development'
|
|
69
|
+
this.compose = options.compose || compose
|
|
70
|
+
if (options.keys) this.keys = options.keys
|
|
71
|
+
this.middleware = []
|
|
72
|
+
this.context = Object.create(context)
|
|
73
|
+
this.request = Object.create(request)
|
|
74
|
+
this.response = Object.create(response)
|
|
63
75
|
// util.inspect.custom support for node 6+
|
|
64
76
|
/* istanbul ignore else */
|
|
65
77
|
if (util.inspect.custom) {
|
|
66
|
-
this[util.inspect.custom] = this.inspect
|
|
78
|
+
this[util.inspect.custom] = this.inspect
|
|
67
79
|
}
|
|
68
80
|
if (options.asyncLocalStorage) {
|
|
69
|
-
const { AsyncLocalStorage } = require('async_hooks')
|
|
70
|
-
assert(AsyncLocalStorage, 'Requires node 12.17.0 or higher to enable asyncLocalStorage')
|
|
71
|
-
this.ctxStorage = new AsyncLocalStorage()
|
|
81
|
+
const { AsyncLocalStorage } = require('async_hooks')
|
|
82
|
+
assert(AsyncLocalStorage, 'Requires node 12.17.0 or higher to enable asyncLocalStorage')
|
|
83
|
+
this.ctxStorage = new AsyncLocalStorage()
|
|
72
84
|
}
|
|
73
85
|
}
|
|
74
86
|
|
|
@@ -78,14 +90,14 @@ module.exports = class Application extends Emitter {
|
|
|
78
90
|
* http.createServer(app.callback()).listen(...)
|
|
79
91
|
*
|
|
80
92
|
* @param {Mixed} ...
|
|
81
|
-
* @return {Server}
|
|
93
|
+
* @return {import('http').Server}
|
|
82
94
|
* @api public
|
|
83
95
|
*/
|
|
84
96
|
|
|
85
|
-
listen(...args) {
|
|
86
|
-
debug('listen')
|
|
87
|
-
const server = http.createServer(this.callback())
|
|
88
|
-
return server.listen(...args)
|
|
97
|
+
listen (...args) {
|
|
98
|
+
debug('listen')
|
|
99
|
+
const server = http.createServer(this.callback())
|
|
100
|
+
return server.listen(...args)
|
|
89
101
|
}
|
|
90
102
|
|
|
91
103
|
/**
|
|
@@ -96,12 +108,12 @@ module.exports = class Application extends Emitter {
|
|
|
96
108
|
* @api public
|
|
97
109
|
*/
|
|
98
110
|
|
|
99
|
-
toJSON() {
|
|
111
|
+
toJSON () {
|
|
100
112
|
return only(this, [
|
|
101
113
|
'subdomainOffset',
|
|
102
114
|
'proxy',
|
|
103
115
|
'env'
|
|
104
|
-
])
|
|
116
|
+
])
|
|
105
117
|
}
|
|
106
118
|
|
|
107
119
|
/**
|
|
@@ -111,8 +123,8 @@ module.exports = class Application extends Emitter {
|
|
|
111
123
|
* @api public
|
|
112
124
|
*/
|
|
113
125
|
|
|
114
|
-
inspect() {
|
|
115
|
-
return this.toJSON()
|
|
126
|
+
inspect () {
|
|
127
|
+
return this.toJSON()
|
|
116
128
|
}
|
|
117
129
|
|
|
118
130
|
/**
|
|
@@ -120,22 +132,16 @@ module.exports = class Application extends Emitter {
|
|
|
120
132
|
*
|
|
121
133
|
* Old-style middleware will be converted.
|
|
122
134
|
*
|
|
123
|
-
* @param {
|
|
135
|
+
* @param {(context: Context) => Promise<any | void>} fn
|
|
124
136
|
* @return {Application} self
|
|
125
137
|
* @api public
|
|
126
138
|
*/
|
|
127
139
|
|
|
128
|
-
use(fn) {
|
|
129
|
-
if (typeof fn !== 'function') throw new TypeError('middleware must be a function!')
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
'https://github.com/koajs/koa/blob/master/docs/migration.md');
|
|
134
|
-
fn = convert(fn);
|
|
135
|
-
}
|
|
136
|
-
debug('use %s', fn._name || fn.name || '-');
|
|
137
|
-
this.middleware.push(fn);
|
|
138
|
-
return this;
|
|
140
|
+
use (fn) {
|
|
141
|
+
if (typeof fn !== 'function') throw new TypeError('middleware must be a function!')
|
|
142
|
+
debug('use %s', fn._name || fn.name || '-')
|
|
143
|
+
this.middleware.push(fn)
|
|
144
|
+
return this
|
|
139
145
|
}
|
|
140
146
|
|
|
141
147
|
/**
|
|
@@ -146,29 +152,29 @@ module.exports = class Application extends Emitter {
|
|
|
146
152
|
* @api public
|
|
147
153
|
*/
|
|
148
154
|
|
|
149
|
-
callback() {
|
|
150
|
-
const fn = compose(this.middleware)
|
|
155
|
+
callback () {
|
|
156
|
+
const fn = this.compose(this.middleware)
|
|
151
157
|
|
|
152
|
-
if (!this.listenerCount('error')) this.on('error', this.onerror)
|
|
158
|
+
if (!this.listenerCount('error')) this.on('error', this.onerror)
|
|
153
159
|
|
|
154
160
|
const handleRequest = (req, res) => {
|
|
155
|
-
const ctx = this.createContext(req, res)
|
|
161
|
+
const ctx = this.createContext(req, res)
|
|
156
162
|
if (!this.ctxStorage) {
|
|
157
|
-
return this.handleRequest(ctx, fn)
|
|
163
|
+
return this.handleRequest(ctx, fn)
|
|
158
164
|
}
|
|
159
|
-
return this.ctxStorage.run(ctx, async() => {
|
|
160
|
-
return await this.handleRequest(ctx, fn)
|
|
161
|
-
})
|
|
162
|
-
}
|
|
165
|
+
return this.ctxStorage.run(ctx, async () => {
|
|
166
|
+
return await this.handleRequest(ctx, fn)
|
|
167
|
+
})
|
|
168
|
+
}
|
|
163
169
|
|
|
164
|
-
return handleRequest
|
|
170
|
+
return handleRequest
|
|
165
171
|
}
|
|
166
172
|
|
|
167
173
|
/**
|
|
168
|
-
* return
|
|
174
|
+
* return current context from async local storage
|
|
169
175
|
*/
|
|
170
|
-
get currentContext() {
|
|
171
|
-
if (this.ctxStorage) return this.ctxStorage.getStore()
|
|
176
|
+
get currentContext () {
|
|
177
|
+
if (this.ctxStorage) return this.ctxStorage.getStore()
|
|
172
178
|
}
|
|
173
179
|
|
|
174
180
|
/**
|
|
@@ -177,13 +183,13 @@ module.exports = class Application extends Emitter {
|
|
|
177
183
|
* @api private
|
|
178
184
|
*/
|
|
179
185
|
|
|
180
|
-
handleRequest(ctx, fnMiddleware) {
|
|
181
|
-
const res = ctx.res
|
|
182
|
-
res.statusCode = 404
|
|
183
|
-
const onerror = err => ctx.onerror(err)
|
|
184
|
-
const handleResponse = () => respond(ctx)
|
|
185
|
-
onFinished(res, onerror)
|
|
186
|
-
return fnMiddleware(ctx).then(handleResponse).catch(onerror)
|
|
186
|
+
handleRequest (ctx, fnMiddleware) {
|
|
187
|
+
const res = ctx.res
|
|
188
|
+
res.statusCode = 404
|
|
189
|
+
const onerror = err => ctx.onerror(err)
|
|
190
|
+
const handleResponse = () => respond(ctx)
|
|
191
|
+
onFinished(res, onerror)
|
|
192
|
+
return fnMiddleware(ctx).then(handleResponse).catch(onerror)
|
|
187
193
|
}
|
|
188
194
|
|
|
189
195
|
/**
|
|
@@ -192,19 +198,22 @@ module.exports = class Application extends Emitter {
|
|
|
192
198
|
* @api private
|
|
193
199
|
*/
|
|
194
200
|
|
|
195
|
-
createContext(req, res) {
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
request.
|
|
203
|
-
request.response =
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
201
|
+
createContext (req, res) {
|
|
202
|
+
/** @type {Context} */
|
|
203
|
+
const context = Object.create(this.context)
|
|
204
|
+
/** @type {KoaRequest} */
|
|
205
|
+
const request = context.request = Object.create(this.request)
|
|
206
|
+
/** @type {KoaResponse} */
|
|
207
|
+
const response = context.response = Object.create(this.response)
|
|
208
|
+
context.app = request.app = response.app = this
|
|
209
|
+
context.req = request.req = response.req = req
|
|
210
|
+
context.res = request.res = response.res = res
|
|
211
|
+
request.ctx = response.ctx = context
|
|
212
|
+
request.response = response
|
|
213
|
+
response.request = request
|
|
214
|
+
context.originalUrl = request.originalUrl = req.url
|
|
215
|
+
context.state = {}
|
|
216
|
+
return context
|
|
208
217
|
}
|
|
209
218
|
|
|
210
219
|
/**
|
|
@@ -214,20 +223,20 @@ module.exports = class Application extends Emitter {
|
|
|
214
223
|
* @api private
|
|
215
224
|
*/
|
|
216
225
|
|
|
217
|
-
onerror(err) {
|
|
226
|
+
onerror (err) {
|
|
218
227
|
// When dealing with cross-globals a normal `instanceof` check doesn't work properly.
|
|
219
228
|
// See https://github.com/koajs/koa/issues/1466
|
|
220
229
|
// We can probably remove it once jest fixes https://github.com/facebook/jest/issues/2549.
|
|
221
230
|
const isNativeError =
|
|
222
231
|
Object.prototype.toString.call(err) === '[object Error]' ||
|
|
223
|
-
err instanceof Error
|
|
224
|
-
if (!isNativeError) throw new TypeError(util.format('non-error thrown: %j', err))
|
|
232
|
+
err instanceof Error
|
|
233
|
+
if (!isNativeError) throw new TypeError(util.format('non-error thrown: %j', err))
|
|
225
234
|
|
|
226
|
-
if (
|
|
227
|
-
if (this.silent) return
|
|
235
|
+
if (err.status === 404 || err.expose) return
|
|
236
|
+
if (this.silent) return
|
|
228
237
|
|
|
229
|
-
const msg = err.stack || err.toString()
|
|
230
|
-
console.error(`\n${msg.replace(/^/gm, ' ')}\n`)
|
|
238
|
+
const msg = err.stack || err.toString()
|
|
239
|
+
console.error(`\n${msg.replace(/^/gm, ' ')}\n`)
|
|
231
240
|
}
|
|
232
241
|
|
|
233
242
|
/**
|
|
@@ -235,79 +244,80 @@ module.exports = class Application extends Emitter {
|
|
|
235
244
|
* @see https://github.com/koajs/koa/issues/1513
|
|
236
245
|
*/
|
|
237
246
|
|
|
238
|
-
static get default() {
|
|
239
|
-
return Application
|
|
247
|
+
static get default () {
|
|
248
|
+
return Application
|
|
240
249
|
}
|
|
241
250
|
|
|
242
|
-
createAsyncCtxStorageMiddleware() {
|
|
243
|
-
const app = this
|
|
244
|
-
return async function asyncCtxStorage(ctx, next) {
|
|
245
|
-
await app.ctxStorage.run(ctx, async() => {
|
|
246
|
-
return await next()
|
|
247
|
-
})
|
|
248
|
-
}
|
|
251
|
+
createAsyncCtxStorageMiddleware () {
|
|
252
|
+
const app = this
|
|
253
|
+
return async function asyncCtxStorage (ctx, next) {
|
|
254
|
+
await app.ctxStorage.run(ctx, async () => {
|
|
255
|
+
return await next()
|
|
256
|
+
})
|
|
257
|
+
}
|
|
249
258
|
}
|
|
250
|
-
}
|
|
259
|
+
}
|
|
251
260
|
|
|
252
261
|
/**
|
|
253
262
|
* Response helper.
|
|
254
263
|
*/
|
|
255
264
|
|
|
256
|
-
function respond(ctx) {
|
|
265
|
+
function respond (ctx) {
|
|
257
266
|
// allow bypassing koa
|
|
258
|
-
if (
|
|
267
|
+
if (ctx.respond === false) return
|
|
259
268
|
|
|
260
|
-
if (!ctx.writable) return
|
|
269
|
+
if (!ctx.writable) return
|
|
261
270
|
|
|
262
|
-
const res = ctx.res
|
|
263
|
-
let body = ctx.body
|
|
264
|
-
const code = ctx.status
|
|
271
|
+
const res = ctx.res
|
|
272
|
+
let body = ctx.body
|
|
273
|
+
const code = ctx.status
|
|
265
274
|
|
|
266
275
|
// ignore body
|
|
267
276
|
if (statuses.empty[code]) {
|
|
268
277
|
// strip headers
|
|
269
|
-
ctx.body = null
|
|
270
|
-
return res.end()
|
|
278
|
+
ctx.body = null
|
|
279
|
+
return res.end()
|
|
271
280
|
}
|
|
272
281
|
|
|
273
|
-
if ('HEAD'
|
|
282
|
+
if (ctx.method === 'HEAD') {
|
|
274
283
|
if (!res.headersSent && !ctx.response.has('Content-Length')) {
|
|
275
|
-
const { length } = ctx.response
|
|
276
|
-
if (Number.isInteger(length)) ctx.length = length
|
|
284
|
+
const { length } = ctx.response
|
|
285
|
+
if (Number.isInteger(length)) ctx.length = length
|
|
277
286
|
}
|
|
278
|
-
return res.end()
|
|
287
|
+
return res.end()
|
|
279
288
|
}
|
|
280
289
|
|
|
281
290
|
// status body
|
|
282
|
-
if (
|
|
291
|
+
if (body == null) {
|
|
283
292
|
if (ctx.response._explicitNullBody) {
|
|
284
|
-
ctx.response.remove('Content-Type')
|
|
285
|
-
ctx.response.remove('Transfer-Encoding')
|
|
286
|
-
|
|
293
|
+
ctx.response.remove('Content-Type')
|
|
294
|
+
ctx.response.remove('Transfer-Encoding')
|
|
295
|
+
ctx.length = 0
|
|
296
|
+
return res.end()
|
|
287
297
|
}
|
|
288
298
|
if (ctx.req.httpVersionMajor >= 2) {
|
|
289
|
-
body = String(code)
|
|
299
|
+
body = String(code)
|
|
290
300
|
} else {
|
|
291
|
-
body = ctx.message || String(code)
|
|
301
|
+
body = ctx.message || String(code)
|
|
292
302
|
}
|
|
293
303
|
if (!res.headersSent) {
|
|
294
|
-
ctx.type = 'text'
|
|
295
|
-
ctx.length = Buffer.byteLength(body)
|
|
304
|
+
ctx.type = 'text'
|
|
305
|
+
ctx.length = Buffer.byteLength(body)
|
|
296
306
|
}
|
|
297
|
-
return res.end(body)
|
|
307
|
+
return res.end(body)
|
|
298
308
|
}
|
|
299
309
|
|
|
300
310
|
// responses
|
|
301
|
-
if (Buffer.isBuffer(body)) return res.end(body)
|
|
302
|
-
if ('string'
|
|
303
|
-
if (body instanceof Stream) return body.pipe(res)
|
|
311
|
+
if (Buffer.isBuffer(body)) return res.end(body)
|
|
312
|
+
if (typeof body === 'string') return res.end(body)
|
|
313
|
+
if (body instanceof Stream) return body.pipe(res)
|
|
304
314
|
|
|
305
315
|
// body: json
|
|
306
|
-
body = JSON.stringify(body)
|
|
316
|
+
body = JSON.stringify(body)
|
|
307
317
|
if (!res.headersSent) {
|
|
308
|
-
ctx.length = Buffer.byteLength(body)
|
|
318
|
+
ctx.length = Buffer.byteLength(body)
|
|
309
319
|
}
|
|
310
|
-
res.end(body)
|
|
320
|
+
res.end(body)
|
|
311
321
|
}
|
|
312
322
|
|
|
313
323
|
/**
|
|
@@ -315,4 +325,4 @@ function respond(ctx) {
|
|
|
315
325
|
* have a direct dependency upon `http-errors`
|
|
316
326
|
*/
|
|
317
327
|
|
|
318
|
-
module.exports.HttpError = HttpError
|
|
328
|
+
module.exports.HttpError = HttpError
|
package/lib/context.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
|
|
2
|
-
'use strict'
|
|
2
|
+
'use strict'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Module dependencies.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const util = require('util')
|
|
9
|
-
const createError = require('http-errors')
|
|
10
|
-
const httpAssert = require('http-assert')
|
|
11
|
-
const delegate = require('delegates')
|
|
12
|
-
const statuses = require('statuses')
|
|
13
|
-
const Cookies = require('cookies')
|
|
8
|
+
const util = require('util')
|
|
9
|
+
const createError = require('http-errors')
|
|
10
|
+
const httpAssert = require('http-assert')
|
|
11
|
+
const delegate = require('delegates')
|
|
12
|
+
const statuses = require('statuses')
|
|
13
|
+
const Cookies = require('cookies')
|
|
14
14
|
|
|
15
|
-
const COOKIES = Symbol('context#cookies')
|
|
15
|
+
const COOKIES = Symbol('context#cookies')
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Context prototype.
|
|
@@ -28,9 +28,9 @@ const proto = module.exports = {
|
|
|
28
28
|
* @api public
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
inspect() {
|
|
32
|
-
if (this === proto) return this
|
|
33
|
-
return this.toJSON()
|
|
31
|
+
inspect () {
|
|
32
|
+
if (this === proto) return this
|
|
33
|
+
return this.toJSON()
|
|
34
34
|
},
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -45,7 +45,7 @@ const proto = module.exports = {
|
|
|
45
45
|
* @api public
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
|
-
toJSON() {
|
|
48
|
+
toJSON () {
|
|
49
49
|
return {
|
|
50
50
|
request: this.request.toJSON(),
|
|
51
51
|
response: this.response.toJSON(),
|
|
@@ -54,7 +54,7 @@ const proto = module.exports = {
|
|
|
54
54
|
req: '<original node req>',
|
|
55
55
|
res: '<original node res>',
|
|
56
56
|
socket: '<original node socket>'
|
|
57
|
-
}
|
|
57
|
+
}
|
|
58
58
|
},
|
|
59
59
|
|
|
60
60
|
/**
|
|
@@ -93,8 +93,8 @@ const proto = module.exports = {
|
|
|
93
93
|
* @api public
|
|
94
94
|
*/
|
|
95
95
|
|
|
96
|
-
throw(...args) {
|
|
97
|
-
throw createError(...args)
|
|
96
|
+
throw (...args) {
|
|
97
|
+
throw createError(...args)
|
|
98
98
|
},
|
|
99
99
|
|
|
100
100
|
/**
|
|
@@ -104,81 +104,81 @@ const proto = module.exports = {
|
|
|
104
104
|
* @api private
|
|
105
105
|
*/
|
|
106
106
|
|
|
107
|
-
onerror(err) {
|
|
107
|
+
onerror (err) {
|
|
108
108
|
// don't do anything if there is no error.
|
|
109
109
|
// this allows you to pass `this.onerror`
|
|
110
110
|
// to node-style callbacks.
|
|
111
|
-
if (
|
|
111
|
+
if (err == null) return
|
|
112
112
|
|
|
113
113
|
// When dealing with cross-globals a normal `instanceof` check doesn't work properly.
|
|
114
114
|
// See https://github.com/koajs/koa/issues/1466
|
|
115
115
|
// We can probably remove it once jest fixes https://github.com/facebook/jest/issues/2549.
|
|
116
116
|
const isNativeError =
|
|
117
117
|
Object.prototype.toString.call(err) === '[object Error]' ||
|
|
118
|
-
err instanceof Error
|
|
119
|
-
if (!isNativeError) err = new Error(util.format('non-error thrown: %j', err))
|
|
118
|
+
err instanceof Error
|
|
119
|
+
if (!isNativeError) err = new Error(util.format('non-error thrown: %j', err))
|
|
120
120
|
|
|
121
|
-
let headerSent = false
|
|
121
|
+
let headerSent = false
|
|
122
122
|
if (this.headerSent || !this.writable) {
|
|
123
|
-
headerSent = err.headerSent = true
|
|
123
|
+
headerSent = err.headerSent = true
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
// delegate
|
|
127
|
-
this.app.emit('error', err, this)
|
|
127
|
+
this.app.emit('error', err, this)
|
|
128
128
|
|
|
129
129
|
// nothing we can do here other
|
|
130
130
|
// than delegate to the app-level
|
|
131
131
|
// handler and log.
|
|
132
132
|
if (headerSent) {
|
|
133
|
-
return
|
|
133
|
+
return
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
const { res } = this
|
|
136
|
+
const { res } = this
|
|
137
137
|
|
|
138
138
|
// first unset all headers
|
|
139
139
|
/* istanbul ignore else */
|
|
140
140
|
if (typeof res.getHeaderNames === 'function') {
|
|
141
|
-
res.getHeaderNames().forEach(name => res.removeHeader(name))
|
|
141
|
+
res.getHeaderNames().forEach(name => res.removeHeader(name))
|
|
142
142
|
} else {
|
|
143
|
-
res._headers = {}
|
|
143
|
+
res._headers = {} // Node < 7.7
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// then set those specified
|
|
147
|
-
this.set(err.headers)
|
|
147
|
+
this.set(err.headers)
|
|
148
148
|
|
|
149
149
|
// force text/plain
|
|
150
|
-
this.type = 'text'
|
|
150
|
+
this.type = 'text'
|
|
151
151
|
|
|
152
|
-
let statusCode = err.status || err.statusCode
|
|
152
|
+
let statusCode = err.status || err.statusCode
|
|
153
153
|
|
|
154
154
|
// ENOENT support
|
|
155
|
-
if ('ENOENT'
|
|
155
|
+
if (err.code === 'ENOENT') statusCode = 404
|
|
156
156
|
|
|
157
157
|
// default to 500
|
|
158
|
-
if ('number'
|
|
158
|
+
if (typeof statusCode !== 'number' || !statuses[statusCode]) statusCode = 500
|
|
159
159
|
|
|
160
160
|
// respond
|
|
161
|
-
const code = statuses[statusCode]
|
|
162
|
-
const msg = err.expose ? err.message : code
|
|
163
|
-
this.status = err.status = statusCode
|
|
164
|
-
this.length = Buffer.byteLength(msg)
|
|
165
|
-
res.end(msg)
|
|
161
|
+
const code = statuses[statusCode]
|
|
162
|
+
const msg = err.expose ? err.message : code
|
|
163
|
+
this.status = err.status = statusCode
|
|
164
|
+
this.length = Buffer.byteLength(msg)
|
|
165
|
+
res.end(msg)
|
|
166
166
|
},
|
|
167
167
|
|
|
168
|
-
get cookies() {
|
|
168
|
+
get cookies () {
|
|
169
169
|
if (!this[COOKIES]) {
|
|
170
170
|
this[COOKIES] = new Cookies(this.req, this.res, {
|
|
171
171
|
keys: this.app.keys,
|
|
172
172
|
secure: this.request.secure
|
|
173
|
-
})
|
|
173
|
+
})
|
|
174
174
|
}
|
|
175
|
-
return this[COOKIES]
|
|
175
|
+
return this[COOKIES]
|
|
176
176
|
},
|
|
177
177
|
|
|
178
|
-
set cookies(_cookies) {
|
|
179
|
-
this[COOKIES] = _cookies
|
|
178
|
+
set cookies (_cookies) {
|
|
179
|
+
this[COOKIES] = _cookies
|
|
180
180
|
}
|
|
181
|
-
}
|
|
181
|
+
}
|
|
182
182
|
|
|
183
183
|
/**
|
|
184
184
|
* Custom inspection implementation for newer Node.js versions.
|
|
@@ -189,7 +189,7 @@ const proto = module.exports = {
|
|
|
189
189
|
|
|
190
190
|
/* istanbul ignore else */
|
|
191
191
|
if (util.inspect.custom) {
|
|
192
|
-
module.exports[util.inspect.custom] = module.exports.inspect
|
|
192
|
+
module.exports[util.inspect.custom] = module.exports.inspect
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
/**
|
|
@@ -213,7 +213,7 @@ delegate(proto, 'response')
|
|
|
213
213
|
.access('lastModified')
|
|
214
214
|
.access('etag')
|
|
215
215
|
.getter('headerSent')
|
|
216
|
-
.getter('writable')
|
|
216
|
+
.getter('writable')
|
|
217
217
|
|
|
218
218
|
/**
|
|
219
219
|
* Request delegation.
|
|
@@ -248,4 +248,4 @@ delegate(proto, 'request')
|
|
|
248
248
|
.getter('stale')
|
|
249
249
|
.getter('fresh')
|
|
250
250
|
.getter('ips')
|
|
251
|
-
.getter('ip')
|
|
251
|
+
.getter('ip')
|