koa 2.14.1 → 3.0.0-alpha.0
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/Readme.md +6 -7
- package/lib/application.js +142 -132
- package/lib/context.js +45 -45
- package/lib/request.js +153 -153
- package/lib/response.js +154 -148
- package/package.json +7 -16
- package/History.md +0 -696
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,29 +58,30 @@ 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()
|
|
72
|
-
this.use(this.createAsyncCtxStorageMiddleware())
|
|
81
|
+
const { AsyncLocalStorage } = require('async_hooks')
|
|
82
|
+
assert(AsyncLocalStorage, 'Requires node 12.17.0 or higher to enable asyncLocalStorage')
|
|
83
|
+
this.ctxStorage = new AsyncLocalStorage()
|
|
84
|
+
this.use(this.createAsyncCtxStorageMiddleware())
|
|
73
85
|
}
|
|
74
86
|
}
|
|
75
87
|
|
|
@@ -79,14 +91,14 @@ module.exports = class Application extends Emitter {
|
|
|
79
91
|
* http.createServer(app.callback()).listen(...)
|
|
80
92
|
*
|
|
81
93
|
* @param {Mixed} ...
|
|
82
|
-
* @return {Server}
|
|
94
|
+
* @return {import('http').Server}
|
|
83
95
|
* @api public
|
|
84
96
|
*/
|
|
85
97
|
|
|
86
|
-
listen(...args) {
|
|
87
|
-
debug('listen')
|
|
88
|
-
const server = http.createServer(this.callback())
|
|
89
|
-
return server.listen(...args)
|
|
98
|
+
listen (...args) {
|
|
99
|
+
debug('listen')
|
|
100
|
+
const server = http.createServer(this.callback())
|
|
101
|
+
return server.listen(...args)
|
|
90
102
|
}
|
|
91
103
|
|
|
92
104
|
/**
|
|
@@ -97,12 +109,12 @@ module.exports = class Application extends Emitter {
|
|
|
97
109
|
* @api public
|
|
98
110
|
*/
|
|
99
111
|
|
|
100
|
-
toJSON() {
|
|
112
|
+
toJSON () {
|
|
101
113
|
return only(this, [
|
|
102
114
|
'subdomainOffset',
|
|
103
115
|
'proxy',
|
|
104
116
|
'env'
|
|
105
|
-
])
|
|
117
|
+
])
|
|
106
118
|
}
|
|
107
119
|
|
|
108
120
|
/**
|
|
@@ -112,8 +124,8 @@ module.exports = class Application extends Emitter {
|
|
|
112
124
|
* @api public
|
|
113
125
|
*/
|
|
114
126
|
|
|
115
|
-
inspect() {
|
|
116
|
-
return this.toJSON()
|
|
127
|
+
inspect () {
|
|
128
|
+
return this.toJSON()
|
|
117
129
|
}
|
|
118
130
|
|
|
119
131
|
/**
|
|
@@ -121,22 +133,16 @@ module.exports = class Application extends Emitter {
|
|
|
121
133
|
*
|
|
122
134
|
* Old-style middleware will be converted.
|
|
123
135
|
*
|
|
124
|
-
* @param {
|
|
136
|
+
* @param {(context: Context) => Promise<any | void>} fn
|
|
125
137
|
* @return {Application} self
|
|
126
138
|
* @api public
|
|
127
139
|
*/
|
|
128
140
|
|
|
129
|
-
use(fn) {
|
|
130
|
-
if (typeof fn !== 'function') throw new TypeError('middleware must be a function!')
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
'https://github.com/koajs/koa/blob/master/docs/migration.md');
|
|
135
|
-
fn = convert(fn);
|
|
136
|
-
}
|
|
137
|
-
debug('use %s', fn._name || fn.name || '-');
|
|
138
|
-
this.middleware.push(fn);
|
|
139
|
-
return this;
|
|
141
|
+
use (fn) {
|
|
142
|
+
if (typeof fn !== 'function') throw new TypeError('middleware must be a function!')
|
|
143
|
+
debug('use %s', fn._name || fn.name || '-')
|
|
144
|
+
this.middleware.push(fn)
|
|
145
|
+
return this
|
|
140
146
|
}
|
|
141
147
|
|
|
142
148
|
/**
|
|
@@ -147,24 +153,24 @@ module.exports = class Application extends Emitter {
|
|
|
147
153
|
* @api public
|
|
148
154
|
*/
|
|
149
155
|
|
|
150
|
-
callback() {
|
|
151
|
-
const fn = compose(this.middleware)
|
|
156
|
+
callback () {
|
|
157
|
+
const fn = this.compose(this.middleware)
|
|
152
158
|
|
|
153
|
-
if (!this.listenerCount('error')) this.on('error', this.onerror)
|
|
159
|
+
if (!this.listenerCount('error')) this.on('error', this.onerror)
|
|
154
160
|
|
|
155
161
|
const handleRequest = (req, res) => {
|
|
156
|
-
const ctx = this.createContext(req, res)
|
|
157
|
-
return this.handleRequest(ctx, fn)
|
|
158
|
-
}
|
|
162
|
+
const ctx = this.createContext(req, res)
|
|
163
|
+
return this.handleRequest(ctx, fn)
|
|
164
|
+
}
|
|
159
165
|
|
|
160
|
-
return handleRequest
|
|
166
|
+
return handleRequest
|
|
161
167
|
}
|
|
162
168
|
|
|
163
169
|
/**
|
|
164
|
-
* return
|
|
170
|
+
* return current context from async local storage
|
|
165
171
|
*/
|
|
166
|
-
get currentContext() {
|
|
167
|
-
if (this.ctxStorage) return this.ctxStorage.getStore()
|
|
172
|
+
get currentContext () {
|
|
173
|
+
if (this.ctxStorage) return this.ctxStorage.getStore()
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
/**
|
|
@@ -173,13 +179,13 @@ module.exports = class Application extends Emitter {
|
|
|
173
179
|
* @api private
|
|
174
180
|
*/
|
|
175
181
|
|
|
176
|
-
handleRequest(ctx, fnMiddleware) {
|
|
177
|
-
const res = ctx.res
|
|
178
|
-
res.statusCode = 404
|
|
179
|
-
const onerror = err => ctx.onerror(err)
|
|
180
|
-
const handleResponse = () => respond(ctx)
|
|
181
|
-
onFinished(res, onerror)
|
|
182
|
-
return fnMiddleware(ctx).then(handleResponse).catch(onerror)
|
|
182
|
+
handleRequest (ctx, fnMiddleware) {
|
|
183
|
+
const res = ctx.res
|
|
184
|
+
res.statusCode = 404
|
|
185
|
+
const onerror = err => ctx.onerror(err)
|
|
186
|
+
const handleResponse = () => respond(ctx)
|
|
187
|
+
onFinished(res, onerror)
|
|
188
|
+
return fnMiddleware(ctx).then(handleResponse).catch(onerror)
|
|
183
189
|
}
|
|
184
190
|
|
|
185
191
|
/**
|
|
@@ -188,19 +194,22 @@ module.exports = class Application extends Emitter {
|
|
|
188
194
|
* @api private
|
|
189
195
|
*/
|
|
190
196
|
|
|
191
|
-
createContext(req, res) {
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
request.
|
|
199
|
-
request.response =
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
197
|
+
createContext (req, res) {
|
|
198
|
+
/** @type {Context} */
|
|
199
|
+
const context = Object.create(this.context)
|
|
200
|
+
/** @type {KoaRequest} */
|
|
201
|
+
const request = context.request = Object.create(this.request)
|
|
202
|
+
/** @type {KoaResponse} */
|
|
203
|
+
const response = context.response = Object.create(this.response)
|
|
204
|
+
context.app = request.app = response.app = this
|
|
205
|
+
context.req = request.req = response.req = req
|
|
206
|
+
context.res = request.res = response.res = res
|
|
207
|
+
request.ctx = response.ctx = context
|
|
208
|
+
request.response = response
|
|
209
|
+
response.request = request
|
|
210
|
+
context.originalUrl = request.originalUrl = req.url
|
|
211
|
+
context.state = {}
|
|
212
|
+
return context
|
|
204
213
|
}
|
|
205
214
|
|
|
206
215
|
/**
|
|
@@ -210,20 +219,20 @@ module.exports = class Application extends Emitter {
|
|
|
210
219
|
* @api private
|
|
211
220
|
*/
|
|
212
221
|
|
|
213
|
-
onerror(err) {
|
|
222
|
+
onerror (err) {
|
|
214
223
|
// When dealing with cross-globals a normal `instanceof` check doesn't work properly.
|
|
215
224
|
// See https://github.com/koajs/koa/issues/1466
|
|
216
225
|
// We can probably remove it once jest fixes https://github.com/facebook/jest/issues/2549.
|
|
217
226
|
const isNativeError =
|
|
218
227
|
Object.prototype.toString.call(err) === '[object Error]' ||
|
|
219
|
-
err instanceof Error
|
|
220
|
-
if (!isNativeError) throw new TypeError(util.format('non-error thrown: %j', err))
|
|
228
|
+
err instanceof Error
|
|
229
|
+
if (!isNativeError) throw new TypeError(util.format('non-error thrown: %j', err))
|
|
221
230
|
|
|
222
|
-
if (
|
|
223
|
-
if (this.silent) return
|
|
231
|
+
if (err.status === 404 || err.expose) return
|
|
232
|
+
if (this.silent) return
|
|
224
233
|
|
|
225
|
-
const msg = err.stack || err.toString()
|
|
226
|
-
console.error(`\n${msg.replace(/^/gm, ' ')}\n`)
|
|
234
|
+
const msg = err.stack || err.toString()
|
|
235
|
+
console.error(`\n${msg.replace(/^/gm, ' ')}\n`)
|
|
227
236
|
}
|
|
228
237
|
|
|
229
238
|
/**
|
|
@@ -231,79 +240,80 @@ module.exports = class Application extends Emitter {
|
|
|
231
240
|
* @see https://github.com/koajs/koa/issues/1513
|
|
232
241
|
*/
|
|
233
242
|
|
|
234
|
-
static get default() {
|
|
235
|
-
return Application
|
|
243
|
+
static get default () {
|
|
244
|
+
return Application
|
|
236
245
|
}
|
|
237
246
|
|
|
238
|
-
createAsyncCtxStorageMiddleware() {
|
|
239
|
-
const app = this
|
|
240
|
-
return async function asyncCtxStorage(ctx, next) {
|
|
241
|
-
await app.ctxStorage.run(ctx, async() => {
|
|
242
|
-
return await next()
|
|
243
|
-
})
|
|
244
|
-
}
|
|
247
|
+
createAsyncCtxStorageMiddleware () {
|
|
248
|
+
const app = this
|
|
249
|
+
return async function asyncCtxStorage (ctx, next) {
|
|
250
|
+
await app.ctxStorage.run(ctx, async () => {
|
|
251
|
+
return await next()
|
|
252
|
+
})
|
|
253
|
+
}
|
|
245
254
|
}
|
|
246
|
-
}
|
|
255
|
+
}
|
|
247
256
|
|
|
248
257
|
/**
|
|
249
258
|
* Response helper.
|
|
250
259
|
*/
|
|
251
260
|
|
|
252
|
-
function respond(ctx) {
|
|
261
|
+
function respond (ctx) {
|
|
253
262
|
// allow bypassing koa
|
|
254
|
-
if (
|
|
263
|
+
if (ctx.respond === false) return
|
|
255
264
|
|
|
256
|
-
if (!ctx.writable) return
|
|
265
|
+
if (!ctx.writable) return
|
|
257
266
|
|
|
258
|
-
const res = ctx.res
|
|
259
|
-
let body = ctx.body
|
|
260
|
-
const code = ctx.status
|
|
267
|
+
const res = ctx.res
|
|
268
|
+
let body = ctx.body
|
|
269
|
+
const code = ctx.status
|
|
261
270
|
|
|
262
271
|
// ignore body
|
|
263
272
|
if (statuses.empty[code]) {
|
|
264
273
|
// strip headers
|
|
265
|
-
ctx.body = null
|
|
266
|
-
return res.end()
|
|
274
|
+
ctx.body = null
|
|
275
|
+
return res.end()
|
|
267
276
|
}
|
|
268
277
|
|
|
269
|
-
if ('HEAD'
|
|
278
|
+
if (ctx.method === 'HEAD') {
|
|
270
279
|
if (!res.headersSent && !ctx.response.has('Content-Length')) {
|
|
271
|
-
const { length } = ctx.response
|
|
272
|
-
if (Number.isInteger(length)) ctx.length = length
|
|
280
|
+
const { length } = ctx.response
|
|
281
|
+
if (Number.isInteger(length)) ctx.length = length
|
|
273
282
|
}
|
|
274
|
-
return res.end()
|
|
283
|
+
return res.end()
|
|
275
284
|
}
|
|
276
285
|
|
|
277
286
|
// status body
|
|
278
|
-
if (
|
|
287
|
+
if (body == null) {
|
|
279
288
|
if (ctx.response._explicitNullBody) {
|
|
280
|
-
ctx.response.remove('Content-Type')
|
|
281
|
-
ctx.response.remove('Transfer-Encoding')
|
|
282
|
-
|
|
289
|
+
ctx.response.remove('Content-Type')
|
|
290
|
+
ctx.response.remove('Transfer-Encoding')
|
|
291
|
+
ctx.length = 0
|
|
292
|
+
return res.end()
|
|
283
293
|
}
|
|
284
294
|
if (ctx.req.httpVersionMajor >= 2) {
|
|
285
|
-
body = String(code)
|
|
295
|
+
body = String(code)
|
|
286
296
|
} else {
|
|
287
|
-
body = ctx.message || String(code)
|
|
297
|
+
body = ctx.message || String(code)
|
|
288
298
|
}
|
|
289
299
|
if (!res.headersSent) {
|
|
290
|
-
ctx.type = 'text'
|
|
291
|
-
ctx.length = Buffer.byteLength(body)
|
|
300
|
+
ctx.type = 'text'
|
|
301
|
+
ctx.length = Buffer.byteLength(body)
|
|
292
302
|
}
|
|
293
|
-
return res.end(body)
|
|
303
|
+
return res.end(body)
|
|
294
304
|
}
|
|
295
305
|
|
|
296
306
|
// responses
|
|
297
|
-
if (Buffer.isBuffer(body)) return res.end(body)
|
|
298
|
-
if ('string'
|
|
299
|
-
if (body instanceof Stream) return body.pipe(res)
|
|
307
|
+
if (Buffer.isBuffer(body)) return res.end(body)
|
|
308
|
+
if (typeof body === 'string') return res.end(body)
|
|
309
|
+
if (body instanceof Stream) return body.pipe(res)
|
|
300
310
|
|
|
301
311
|
// body: json
|
|
302
|
-
body = JSON.stringify(body)
|
|
312
|
+
body = JSON.stringify(body)
|
|
303
313
|
if (!res.headersSent) {
|
|
304
|
-
ctx.length = Buffer.byteLength(body)
|
|
314
|
+
ctx.length = Buffer.byteLength(body)
|
|
305
315
|
}
|
|
306
|
-
res.end(body)
|
|
316
|
+
res.end(body)
|
|
307
317
|
}
|
|
308
318
|
|
|
309
319
|
/**
|
|
@@ -311,4 +321,4 @@ function respond(ctx) {
|
|
|
311
321
|
* have a direct dependency upon `http-errors`
|
|
312
322
|
*/
|
|
313
323
|
|
|
314
|
-
module.exports.HttpError = HttpError
|
|
324
|
+
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')
|