koa 2.10.0 → 2.13.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/History.md +53 -0
- package/Readme.md +0 -1
- package/dist/koa.mjs +4 -0
- package/lib/application.js +26 -11
- package/lib/context.js +14 -5
- package/lib/request.js +15 -12
- package/lib/response.js +54 -30
- package/package.json +19 -8
package/History.md
CHANGED
|
@@ -1,4 +1,57 @@
|
|
|
1
1
|
|
|
2
|
+
2.13.0 / 2020-06-21
|
|
3
|
+
==================
|
|
4
|
+
|
|
5
|
+
**features**
|
|
6
|
+
* [[`bbcde76`](http://github.com/koajs/koa/commit/bbcde76f5cb5b67bbcd3201791cf0ef648fd3a8b)] - feat: support esm (#1474) (ZYSzys <<zhangyongsheng@youzan.com>>)
|
|
7
|
+
|
|
8
|
+
**others**
|
|
9
|
+
* [[`20e58cf`](http://github.com/koajs/koa/commit/20e58cf3e4f20fc5d5886df1d0ac6dd8c33bd202)] - test: imporve coverage to 100% (dead-horse <<dead_horse@qq.com>>)
|
|
10
|
+
* [[`4a40d63`](http://github.com/koajs/koa/commit/4a40d633c4b4a203c6656078f9952ccef65c5875)] - build: use prepare instead of prepublish (dead-horse <<dead_horse@qq.com>>)
|
|
11
|
+
* [[`226ba8c`](http://github.com/koajs/koa/commit/226ba8c8e81e83da48e7bf137be3f146d03f40b8)] - build: use prepublish instead of prepack (dead-horse <<dead_horse@qq.com>>)
|
|
12
|
+
|
|
13
|
+
2.12.1 / 2020-06-13
|
|
14
|
+
==================
|
|
15
|
+
|
|
16
|
+
**fixes**
|
|
17
|
+
* [[`e2030c7`](http://github.com/koajs/koa/commit/e2030c7249c7ae24e28158d8eae405a02fefc9f8)] - fix: Improve checks for Error in onerror handlers (#1468) (Julien Wajsberg <<felash@gmail.com>>)
|
|
18
|
+
|
|
19
|
+
**others**
|
|
20
|
+
* [[`5208c5e`](http://github.com/koajs/koa/commit/5208c5e15d35b3653fce6b8ed68d09865abea843)] - chore: Use single console.error() statement in error handler (#1471) (Mike Vosseller <<michael.vosseller@gmail.com>>)
|
|
21
|
+
|
|
22
|
+
2.12.0 / 2020-05-18
|
|
23
|
+
==================
|
|
24
|
+
|
|
25
|
+
**features**
|
|
26
|
+
* [[`0d2f421`](http://github.com/koajs/koa/commit/0d2f421c265350d3d84e1bc261572954479f27d3)] - feat: error handler treat err.statusCode as the same as err.status (#1460) (Vijay Krishnavanshi <<vijaykrishnavanshi@gmail.com>>)
|
|
27
|
+
* [[`8d52105`](http://github.com/koajs/koa/commit/8d52105a34234be9e771ff3b76b43e4e30328943)] - feat: allow bodyless responses for non empty status codes (#1447) (ejose19 <<8742215+ejose19@users.noreply.github.com>>)
|
|
28
|
+
|
|
29
|
+
**others**
|
|
30
|
+
* [[`faeaff5`](http://github.com/koajs/koa/commit/faeaff5c149a81a188ab8e5af0b994029e45acbb)] - fox: remove `error-inject` and fix error handling (#1409) (Konstantin Vyatkin <<tino@vtkn.io>>)
|
|
31
|
+
* [[`f7c732f`](http://github.com/koajs/koa/commit/f7c732fd06f724505e9090add4d977e667da55a8)] - docs: fixed incorrect onerror example (#1459) (Paul Annekov <<paul.annekov@gmail.com>>)
|
|
32
|
+
* [[`143d8f7`](http://github.com/koajs/koa/commit/143d8f72f2a232b4c97eac00e7811015911e4f7c)] - Always use strict equality. (#1225) (Yazan Medanat <<medanat@gmail.com>>)
|
|
33
|
+
* [[`6b6b0dd`](http://github.com/koajs/koa/commit/6b6b0ddf7aff073e65493c6efaffab8331c0331c)] - docs(api): add app.use chainability note (#1449) (Zac Anger <<zac@zacanger.com>>)
|
|
34
|
+
* [[`8ddab48`](http://github.com/koajs/koa/commit/8ddab48cbdbca1e6d1cc8c3ddae45491db524d51)] - docs: Document response status with empty body (#1445) (Marc-Aurèle DARCHE <<152407+madarche@users.noreply.github.com>>)
|
|
35
|
+
* [[`7deedb2`](http://github.com/koajs/koa/commit/7deedb235274223f1b9da46dee296545b23598de)] - docs: Updating context.md with the latest cookies opts (#1433) (Brad Ito <<phlogisticfugu@users.noreply.github.com>>)
|
|
36
|
+
* [[`3e97a10`](http://github.com/koajs/koa/commit/3e97a106bb846d9337737011bb85149ddd797229)] - docs(links): remove Google+ link (#1439) (laffachan <<45162759+laffachan@users.noreply.github.com>>)
|
|
37
|
+
* [[`eda2760`](http://github.com/koajs/koa/commit/eda27608f7d39ede86d7b402aae64b1867ce31c6)] - build: Drop unused Travis sudo: false directive (#1416) (Olle Jonsson <<olle.jonsson@gmail.com>>)
|
|
38
|
+
|
|
39
|
+
2.11.0 / 2019-10-28
|
|
40
|
+
==================
|
|
41
|
+
|
|
42
|
+
**features**
|
|
43
|
+
* [[`422e539`](http://github.com/koajs/koa/commit/422e539e8989e65ba43ecc39ddbaa3c4f755d465)] - feat: support app.proxyIPHeader and app.maxIpsCount to make ctx.ips more security (Yiyu He <<dead_horse@qq.com>>)
|
|
44
|
+
* [[`d48d88e`](http://github.com/koajs/koa/commit/d48d88ee17b780c02123e6d657274cab456e943e)] - feat: implement response.has (#1397) (Konstantin Vyatkin <<tino@vtkn.io>>)
|
|
45
|
+
|
|
46
|
+
**others**
|
|
47
|
+
* [[`4dc56f6`](http://github.com/koajs/koa/commit/4dc56f6d04e8f5fe12ba53a8a776653b3d7b60ed)] - chore: update ESLint and plugins/configs (#1407) (Konstantin Vyatkin <<tino@vtkn.io>>)
|
|
48
|
+
* [[`be7d334`](http://github.com/koajs/koa/commit/be7d334778481639294cdf87f5c359a230aeb65b)] - chore: removes code duplication at handling HEAD method (#1400) (Konstantin Vyatkin <<tino@vtkn.io>>)
|
|
49
|
+
* [[`f155785`](http://github.com/koajs/koa/commit/f155785e2bb42b5ddf0a8156401c6dafdf57ba8b)] - chore: support `writableEnded` (#1402) (Konstantin Vyatkin <<tino@vtkn.io>>)
|
|
50
|
+
* [[`b968688`](http://github.com/koajs/koa/commit/b968688afe2c727ae141f50aa983d481dbc1dbbf)] - chore: add FUNDING.yml (#1403) (Konstantin Vyatkin <<tino@vtkn.io>>)
|
|
51
|
+
* [[`4f96829`](http://github.com/koajs/koa/commit/4f968298f97394e488297ec32c8e927a3a322076)] - chore: remove isJSON in res.length (#1399) (Konstantin Vyatkin <<tino@vtkn.io>>)
|
|
52
|
+
* [[`8be5626`](http://github.com/koajs/koa/commit/8be5626bbb54e6c899a1b71d22411709126d9fea)] - build: enable codecov partial coverage and use bash uploader (#1396) (Konstantin Vyatkin <<tino@vtkn.io>>)
|
|
53
|
+
* [[`ef5c43b`](http://github.com/koajs/koa/commit/ef5c43bcbcf31819e032c3b7ae7654b7f8e9358b)] - chore: use rest params (#1393) (Konstantin Vyatkin <<tino@vtkn.io>>)
|
|
54
|
+
|
|
2
55
|
2.10.0 / 2019-10-12
|
|
3
56
|
==================
|
|
4
57
|
|
package/Readme.md
CHANGED
|
@@ -221,7 +221,6 @@ See [AUTHORS](AUTHORS).
|
|
|
221
221
|
- [Examples](https://github.com/koajs/examples)
|
|
222
222
|
- [Middleware](https://github.com/koajs/koa/wiki) list
|
|
223
223
|
- [Wiki](https://github.com/koajs/koa/wiki)
|
|
224
|
-
- [G+ Community](https://plus.google.com/communities/101845768320796750641)
|
|
225
224
|
- [Reddit Community](https://www.reddit.com/r/koajs)
|
|
226
225
|
- [Mailing list](https://groups.google.com/forum/#!forum/koajs)
|
|
227
226
|
- [中文文档 v1.x](https://github.com/guo-yu/koa-guide)
|
package/dist/koa.mjs
ADDED
package/lib/application.js
CHANGED
|
@@ -10,7 +10,6 @@ const debug = require('debug')('koa:application');
|
|
|
10
10
|
const onFinished = require('on-finished');
|
|
11
11
|
const response = require('./response');
|
|
12
12
|
const compose = require('koa-compose');
|
|
13
|
-
const isJSON = require('koa-is-json');
|
|
14
13
|
const context = require('./context');
|
|
15
14
|
const request = require('./request');
|
|
16
15
|
const statuses = require('statuses');
|
|
@@ -42,6 +41,8 @@ module.exports = class Application extends Emitter {
|
|
|
42
41
|
* @param {string[]} [options.keys] Signed cookie keys
|
|
43
42
|
* @param {boolean} [options.proxy] Trust proxy headers
|
|
44
43
|
* @param {number} [options.subdomainOffset] Subdomain offset
|
|
44
|
+
* @param {boolean} [options.proxyIpHeader] proxy ip header, default to X-Forwarded-For
|
|
45
|
+
* @param {boolean} [options.maxIpsCount] max ips read from proxy ip header, default to 0 (means infinity)
|
|
45
46
|
*
|
|
46
47
|
*/
|
|
47
48
|
|
|
@@ -50,12 +51,16 @@ module.exports = class Application extends Emitter {
|
|
|
50
51
|
options = options || {};
|
|
51
52
|
this.proxy = options.proxy || false;
|
|
52
53
|
this.subdomainOffset = options.subdomainOffset || 2;
|
|
54
|
+
this.proxyIpHeader = options.proxyIpHeader || 'X-Forwarded-For';
|
|
55
|
+
this.maxIpsCount = options.maxIpsCount || 0;
|
|
53
56
|
this.env = options.env || process.env.NODE_ENV || 'development';
|
|
54
57
|
if (options.keys) this.keys = options.keys;
|
|
55
58
|
this.middleware = [];
|
|
56
59
|
this.context = Object.create(context);
|
|
57
60
|
this.request = Object.create(request);
|
|
58
61
|
this.response = Object.create(response);
|
|
62
|
+
// util.inspect.custom support for node 6+
|
|
63
|
+
/* istanbul ignore else */
|
|
59
64
|
if (util.inspect.custom) {
|
|
60
65
|
this[util.inspect.custom] = this.inspect;
|
|
61
66
|
}
|
|
@@ -192,15 +197,19 @@ module.exports = class Application extends Emitter {
|
|
|
192
197
|
*/
|
|
193
198
|
|
|
194
199
|
onerror(err) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
200
|
+
// When dealing with cross-globals a normal `instanceof` check doesn't work properly.
|
|
201
|
+
// See https://github.com/koajs/koa/issues/1466
|
|
202
|
+
// We can probably remove it once jest fixes https://github.com/facebook/jest/issues/2549.
|
|
203
|
+
const isNativeError =
|
|
204
|
+
Object.prototype.toString.call(err) === '[object Error]' ||
|
|
205
|
+
err instanceof Error;
|
|
206
|
+
if (!isNativeError) throw new TypeError(util.format('non-error thrown: %j', err));
|
|
207
|
+
|
|
208
|
+
if (404 === err.status || err.expose) return;
|
|
198
209
|
if (this.silent) return;
|
|
199
210
|
|
|
200
211
|
const msg = err.stack || err.toString();
|
|
201
|
-
console.error();
|
|
202
|
-
console.error(msg.replace(/^/gm, ' '));
|
|
203
|
-
console.error();
|
|
212
|
+
console.error(`\n${msg.replace(/^/gm, ' ')}\n`);
|
|
204
213
|
}
|
|
205
214
|
};
|
|
206
215
|
|
|
@@ -225,15 +234,21 @@ function respond(ctx) {
|
|
|
225
234
|
return res.end();
|
|
226
235
|
}
|
|
227
236
|
|
|
228
|
-
if ('HEAD'
|
|
229
|
-
if (!res.headersSent &&
|
|
230
|
-
|
|
237
|
+
if ('HEAD' === ctx.method) {
|
|
238
|
+
if (!res.headersSent && !ctx.response.has('Content-Length')) {
|
|
239
|
+
const { length } = ctx.response;
|
|
240
|
+
if (Number.isInteger(length)) ctx.length = length;
|
|
231
241
|
}
|
|
232
242
|
return res.end();
|
|
233
243
|
}
|
|
234
244
|
|
|
235
245
|
// status body
|
|
236
246
|
if (null == body) {
|
|
247
|
+
if (ctx.response._explicitNullBody) {
|
|
248
|
+
ctx.response.remove('Content-Type');
|
|
249
|
+
ctx.response.remove('Transfer-Encoding');
|
|
250
|
+
return res.end();
|
|
251
|
+
}
|
|
237
252
|
if (ctx.req.httpVersionMajor >= 2) {
|
|
238
253
|
body = String(code);
|
|
239
254
|
} else {
|
|
@@ -248,7 +263,7 @@ function respond(ctx) {
|
|
|
248
263
|
|
|
249
264
|
// responses
|
|
250
265
|
if (Buffer.isBuffer(body)) return res.end(body);
|
|
251
|
-
if ('string'
|
|
266
|
+
if ('string' === typeof body) return res.end(body);
|
|
252
267
|
if (body instanceof Stream) return body.pipe(res);
|
|
253
268
|
|
|
254
269
|
// body: json
|
package/lib/context.js
CHANGED
|
@@ -110,7 +110,13 @@ const proto = module.exports = {
|
|
|
110
110
|
// to node-style callbacks.
|
|
111
111
|
if (null == err) return;
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
// When dealing with cross-globals a normal `instanceof` check doesn't work properly.
|
|
114
|
+
// See https://github.com/koajs/koa/issues/1466
|
|
115
|
+
// We can probably remove it once jest fixes https://github.com/facebook/jest/issues/2549.
|
|
116
|
+
const isNativeError =
|
|
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));
|
|
114
120
|
|
|
115
121
|
let headerSent = false;
|
|
116
122
|
if (this.headerSent || !this.writable) {
|
|
@@ -143,16 +149,18 @@ const proto = module.exports = {
|
|
|
143
149
|
// force text/plain
|
|
144
150
|
this.type = 'text';
|
|
145
151
|
|
|
152
|
+
let statusCode = err.status || err.statusCode;
|
|
153
|
+
|
|
146
154
|
// ENOENT support
|
|
147
|
-
if ('ENOENT'
|
|
155
|
+
if ('ENOENT' === err.code) statusCode = 404;
|
|
148
156
|
|
|
149
157
|
// default to 500
|
|
150
|
-
if ('number'
|
|
158
|
+
if ('number' !== typeof statusCode || !statuses[statusCode]) statusCode = 500;
|
|
151
159
|
|
|
152
160
|
// respond
|
|
153
|
-
const code = statuses[
|
|
161
|
+
const code = statuses[statusCode];
|
|
154
162
|
const msg = err.expose ? err.message : code;
|
|
155
|
-
this.status = err.status;
|
|
163
|
+
this.status = err.status = statusCode;
|
|
156
164
|
this.length = Buffer.byteLength(msg);
|
|
157
165
|
res.end(msg);
|
|
158
166
|
},
|
|
@@ -193,6 +201,7 @@ delegate(proto, 'response')
|
|
|
193
201
|
.method('redirect')
|
|
194
202
|
.method('remove')
|
|
195
203
|
.method('vary')
|
|
204
|
+
.method('has')
|
|
196
205
|
.method('set')
|
|
197
206
|
.method('append')
|
|
198
207
|
.method('flushHeaders')
|
package/lib/request.js
CHANGED
|
@@ -272,7 +272,7 @@ module.exports = {
|
|
|
272
272
|
get hostname() {
|
|
273
273
|
const host = this.host;
|
|
274
274
|
if (!host) return '';
|
|
275
|
-
if ('['
|
|
275
|
+
if ('[' === host[0]) return this.URL.hostname || ''; // IPv6
|
|
276
276
|
return host.split(':', 1)[0];
|
|
277
277
|
},
|
|
278
278
|
|
|
@@ -311,10 +311,10 @@ module.exports = {
|
|
|
311
311
|
const s = this.ctx.status;
|
|
312
312
|
|
|
313
313
|
// GET or HEAD for weak freshness validation only
|
|
314
|
-
if ('GET'
|
|
314
|
+
if ('GET' !== method && 'HEAD' !== method) return false;
|
|
315
315
|
|
|
316
316
|
// 2xx or 304 as per rfc2616 14.26
|
|
317
|
-
if ((s >= 200 && s < 300) || 304
|
|
317
|
+
if ((s >= 200 && s < 300) || 304 === s) {
|
|
318
318
|
return fresh(this.header, this.response.header);
|
|
319
319
|
}
|
|
320
320
|
|
|
@@ -382,7 +382,7 @@ module.exports = {
|
|
|
382
382
|
|
|
383
383
|
get length() {
|
|
384
384
|
const len = this.get('Content-Length');
|
|
385
|
-
if (len
|
|
385
|
+
if (len === '') return;
|
|
386
386
|
return ~~len;
|
|
387
387
|
},
|
|
388
388
|
|
|
@@ -415,7 +415,7 @@ module.exports = {
|
|
|
415
415
|
*/
|
|
416
416
|
|
|
417
417
|
get secure() {
|
|
418
|
-
return 'https'
|
|
418
|
+
return 'https' === this.protocol;
|
|
419
419
|
},
|
|
420
420
|
|
|
421
421
|
/**
|
|
@@ -432,10 +432,14 @@ module.exports = {
|
|
|
432
432
|
|
|
433
433
|
get ips() {
|
|
434
434
|
const proxy = this.app.proxy;
|
|
435
|
-
const val = this.get(
|
|
436
|
-
|
|
435
|
+
const val = this.get(this.app.proxyIpHeader);
|
|
436
|
+
let ips = proxy && val
|
|
437
437
|
? val.split(/\s*,\s*/)
|
|
438
438
|
: [];
|
|
439
|
+
if (this.app.maxIpsCount > 0) {
|
|
440
|
+
ips = ips.slice(-this.app.maxIpsCount);
|
|
441
|
+
}
|
|
442
|
+
return ips;
|
|
439
443
|
},
|
|
440
444
|
|
|
441
445
|
/**
|
|
@@ -622,15 +626,14 @@ module.exports = {
|
|
|
622
626
|
*
|
|
623
627
|
* this.is('html'); // => false
|
|
624
628
|
*
|
|
625
|
-
* @param {String|
|
|
629
|
+
* @param {String|String[]} [type]
|
|
630
|
+
* @param {String[]} [types]
|
|
626
631
|
* @return {String|false|null}
|
|
627
632
|
* @api public
|
|
628
633
|
*/
|
|
629
634
|
|
|
630
|
-
is(types) {
|
|
631
|
-
|
|
632
|
-
if (!Array.isArray(types)) types = [].slice.call(arguments);
|
|
633
|
-
return typeis(this.req, types);
|
|
635
|
+
is(type, ...types) {
|
|
636
|
+
return typeis(this.req, type, ...types);
|
|
634
637
|
},
|
|
635
638
|
|
|
636
639
|
/**
|
package/lib/response.js
CHANGED
|
@@ -6,10 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const contentDisposition = require('content-disposition');
|
|
9
|
-
const ensureErrorHandler = require('error-inject');
|
|
10
9
|
const getType = require('cache-content-type');
|
|
11
10
|
const onFinish = require('on-finished');
|
|
12
|
-
const isJSON = require('koa-is-json');
|
|
13
11
|
const escape = require('escape-html');
|
|
14
12
|
const typeis = require('type-is').is;
|
|
15
13
|
const statuses = require('statuses');
|
|
@@ -20,6 +18,7 @@ const vary = require('vary');
|
|
|
20
18
|
const only = require('only');
|
|
21
19
|
const util = require('util');
|
|
22
20
|
const encodeUrl = require('encodeurl');
|
|
21
|
+
const Stream = require('stream');
|
|
23
22
|
|
|
24
23
|
/**
|
|
25
24
|
* Prototype.
|
|
@@ -139,6 +138,7 @@ module.exports = {
|
|
|
139
138
|
// no content
|
|
140
139
|
if (null == val) {
|
|
141
140
|
if (!statuses.empty[this.status]) this.status = 204;
|
|
141
|
+
if (val === null) this._explicitNullBody = true;
|
|
142
142
|
this.remove('Content-Type');
|
|
143
143
|
this.remove('Content-Length');
|
|
144
144
|
this.remove('Transfer-Encoding');
|
|
@@ -149,10 +149,10 @@ module.exports = {
|
|
|
149
149
|
if (!this._explicitStatus) this.status = 200;
|
|
150
150
|
|
|
151
151
|
// set the content-type only if not yet set
|
|
152
|
-
const setType = !this.
|
|
152
|
+
const setType = !this.has('Content-Type');
|
|
153
153
|
|
|
154
154
|
// string
|
|
155
|
-
if ('string'
|
|
155
|
+
if ('string' === typeof val) {
|
|
156
156
|
if (setType) this.type = /^\s*</.test(val) ? 'html' : 'text';
|
|
157
157
|
this.length = Buffer.byteLength(val);
|
|
158
158
|
return;
|
|
@@ -166,12 +166,13 @@ module.exports = {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
// stream
|
|
169
|
-
if (
|
|
169
|
+
if (val instanceof Stream) {
|
|
170
170
|
onFinish(this.res, destroy.bind(null, val));
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
if (original != val) {
|
|
172
|
+
val.once('error', err => this.ctx.onerror(err));
|
|
173
|
+
// overwriting
|
|
174
|
+
if (null != original) this.remove('Content-Length');
|
|
175
|
+
}
|
|
175
176
|
|
|
176
177
|
if (setType) this.type = 'bin';
|
|
177
178
|
return;
|
|
@@ -201,18 +202,15 @@ module.exports = {
|
|
|
201
202
|
*/
|
|
202
203
|
|
|
203
204
|
get length() {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (null == len) {
|
|
208
|
-
if (!body) return;
|
|
209
|
-
if ('string' == typeof body) return Buffer.byteLength(body);
|
|
210
|
-
if (Buffer.isBuffer(body)) return body.length;
|
|
211
|
-
if (isJSON(body)) return Buffer.byteLength(JSON.stringify(body));
|
|
212
|
-
return;
|
|
205
|
+
if (this.has('Content-Length')) {
|
|
206
|
+
return parseInt(this.get('Content-Length'), 10) || 0;
|
|
213
207
|
}
|
|
214
208
|
|
|
215
|
-
|
|
209
|
+
const { body } = this;
|
|
210
|
+
if (!body || body instanceof Stream) return undefined;
|
|
211
|
+
if ('string' === typeof body) return Buffer.byteLength(body);
|
|
212
|
+
if (Buffer.isBuffer(body)) return body.length;
|
|
213
|
+
return Buffer.byteLength(JSON.stringify(body));
|
|
216
214
|
},
|
|
217
215
|
|
|
218
216
|
/**
|
|
@@ -260,7 +258,7 @@ module.exports = {
|
|
|
260
258
|
|
|
261
259
|
redirect(url, alt) {
|
|
262
260
|
// location
|
|
263
|
-
if ('back'
|
|
261
|
+
if ('back' === url) url = this.ctx.get('Referrer') || alt || '/';
|
|
264
262
|
this.set('Location', encodeUrl(url));
|
|
265
263
|
|
|
266
264
|
// status
|
|
@@ -327,7 +325,7 @@ module.exports = {
|
|
|
327
325
|
*/
|
|
328
326
|
|
|
329
327
|
set lastModified(val) {
|
|
330
|
-
if ('string'
|
|
328
|
+
if ('string' === typeof val) val = new Date(val);
|
|
331
329
|
this.set('Last-Modified', val.toUTCString());
|
|
332
330
|
},
|
|
333
331
|
|
|
@@ -389,16 +387,14 @@ module.exports = {
|
|
|
389
387
|
* Check whether the response is one of the listed types.
|
|
390
388
|
* Pretty much the same as `this.request.is()`.
|
|
391
389
|
*
|
|
392
|
-
* @param {String|
|
|
390
|
+
* @param {String|String[]} [type]
|
|
391
|
+
* @param {String[]} [types]
|
|
393
392
|
* @return {String|false}
|
|
394
393
|
* @api public
|
|
395
394
|
*/
|
|
396
395
|
|
|
397
|
-
is(types) {
|
|
398
|
-
|
|
399
|
-
if (!types) return type || false;
|
|
400
|
-
if (!Array.isArray(types)) types = [].slice.call(arguments);
|
|
401
|
-
return typeis(type, types);
|
|
396
|
+
is(type, ...types) {
|
|
397
|
+
return typeis(this.type, type, ...types);
|
|
402
398
|
},
|
|
403
399
|
|
|
404
400
|
/**
|
|
@@ -421,6 +417,29 @@ module.exports = {
|
|
|
421
417
|
return this.header[field.toLowerCase()] || '';
|
|
422
418
|
},
|
|
423
419
|
|
|
420
|
+
/**
|
|
421
|
+
* Returns true if the header identified by name is currently set in the outgoing headers.
|
|
422
|
+
* The header name matching is case-insensitive.
|
|
423
|
+
*
|
|
424
|
+
* Examples:
|
|
425
|
+
*
|
|
426
|
+
* this.has('Content-Type');
|
|
427
|
+
* // => true
|
|
428
|
+
*
|
|
429
|
+
* this.get('content-type');
|
|
430
|
+
* // => true
|
|
431
|
+
*
|
|
432
|
+
* @param {String} field
|
|
433
|
+
* @return {boolean}
|
|
434
|
+
* @api public
|
|
435
|
+
*/
|
|
436
|
+
has(field) {
|
|
437
|
+
return typeof this.res.hasHeader === 'function'
|
|
438
|
+
? this.res.hasHeader(field)
|
|
439
|
+
// Node < 7.7
|
|
440
|
+
: field.toLowerCase() in this.headers;
|
|
441
|
+
},
|
|
442
|
+
|
|
424
443
|
/**
|
|
425
444
|
* Set header `field` to `val`, or pass
|
|
426
445
|
* an object of header fields.
|
|
@@ -439,7 +458,7 @@ module.exports = {
|
|
|
439
458
|
set(field, val) {
|
|
440
459
|
if (this.headerSent) return;
|
|
441
460
|
|
|
442
|
-
if (2
|
|
461
|
+
if (2 === arguments.length) {
|
|
443
462
|
if (Array.isArray(val)) val = val.map(v => typeof v === 'string' ? v : String(v));
|
|
444
463
|
else if (typeof val !== 'string') val = String(val);
|
|
445
464
|
this.res.setHeader(field, val);
|
|
@@ -502,7 +521,11 @@ module.exports = {
|
|
|
502
521
|
|
|
503
522
|
get writable() {
|
|
504
523
|
// can't write any more after response finished
|
|
505
|
-
|
|
524
|
+
// response.writableEnded is available since Node > 12.9
|
|
525
|
+
// https://nodejs.org/api/http.html#http_response_writableended
|
|
526
|
+
// response.finished is undocumented feature of previous Node versions
|
|
527
|
+
// https://stackoverflow.com/questions/16254385/undocumented-response-finished-in-node-js
|
|
528
|
+
if (this.res.writableEnded || this.res.finished) return false;
|
|
506
529
|
|
|
507
530
|
const socket = this.res.socket;
|
|
508
531
|
// There are already pending outgoing res, but still writable
|
|
@@ -549,11 +572,12 @@ module.exports = {
|
|
|
549
572
|
};
|
|
550
573
|
|
|
551
574
|
/**
|
|
552
|
-
* Custom inspection implementation for
|
|
575
|
+
* Custom inspection implementation for node 6+.
|
|
553
576
|
*
|
|
554
577
|
* @return {Object}
|
|
555
578
|
* @api public
|
|
556
579
|
*/
|
|
580
|
+
/* istanbul ignore else */
|
|
557
581
|
if (util.inspect.custom) {
|
|
558
582
|
module.exports[util.inspect.custom] = module.exports.inspect;
|
|
559
583
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koa",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"description": "Koa web app framework",
|
|
5
5
|
"main": "lib/application.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"require": "./lib/application.js",
|
|
9
|
+
"import": "./dist/koa.mjs"
|
|
10
|
+
},
|
|
11
|
+
"./": "./"
|
|
12
|
+
},
|
|
6
13
|
"scripts": {
|
|
7
14
|
"test": "egg-bin test test",
|
|
8
15
|
"test-cov": "egg-bin cov test",
|
|
9
16
|
"lint": "eslint benchmarks lib test",
|
|
10
17
|
"bench": "make -C benchmarks",
|
|
11
|
-
"authors": "git log --format='%aN <%aE>' | sort -u > AUTHORS"
|
|
18
|
+
"authors": "git log --format='%aN <%aE>' | sort -u > AUTHORS",
|
|
19
|
+
"build": "gen-esm-wrapper . ./dist/koa.mjs",
|
|
20
|
+
"prepare": "npm run build"
|
|
12
21
|
},
|
|
13
22
|
"repository": "koajs/koa",
|
|
14
23
|
"keywords": [
|
|
@@ -32,7 +41,6 @@
|
|
|
32
41
|
"depd": "^1.1.2",
|
|
33
42
|
"destroy": "^1.0.4",
|
|
34
43
|
"encodeurl": "^1.0.2",
|
|
35
|
-
"error-inject": "^1.0.0",
|
|
36
44
|
"escape-html": "^1.0.3",
|
|
37
45
|
"fresh": "~0.5.2",
|
|
38
46
|
"http-assert": "^1.3.0",
|
|
@@ -40,7 +48,6 @@
|
|
|
40
48
|
"is-generator-function": "^1.0.7",
|
|
41
49
|
"koa-compose": "^4.1.0",
|
|
42
50
|
"koa-convert": "^1.2.0",
|
|
43
|
-
"koa-is-json": "^1.0.0",
|
|
44
51
|
"on-finished": "^2.3.0",
|
|
45
52
|
"only": "~0.0.2",
|
|
46
53
|
"parseurl": "^1.3.2",
|
|
@@ -50,11 +57,14 @@
|
|
|
50
57
|
},
|
|
51
58
|
"devDependencies": {
|
|
52
59
|
"egg-bin": "^4.13.0",
|
|
53
|
-
"eslint": "^6.
|
|
60
|
+
"eslint": "^6.5.1",
|
|
54
61
|
"eslint-config-koa": "^2.0.0",
|
|
55
|
-
"eslint-config-standard": "^
|
|
56
|
-
"eslint-plugin-
|
|
57
|
-
"eslint-plugin-
|
|
62
|
+
"eslint-config-standard": "^14.1.0",
|
|
63
|
+
"eslint-plugin-import": "^2.18.2",
|
|
64
|
+
"eslint-plugin-node": "^10.0.0",
|
|
65
|
+
"eslint-plugin-promise": "^4.2.1",
|
|
66
|
+
"eslint-plugin-standard": "^4.0.1",
|
|
67
|
+
"gen-esm-wrapper": "^1.0.6",
|
|
58
68
|
"mm": "^2.5.0",
|
|
59
69
|
"supertest": "^3.1.0"
|
|
60
70
|
},
|
|
@@ -62,6 +72,7 @@
|
|
|
62
72
|
"node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4"
|
|
63
73
|
},
|
|
64
74
|
"files": [
|
|
75
|
+
"dist",
|
|
65
76
|
"lib"
|
|
66
77
|
]
|
|
67
78
|
}
|