routup 2.0.0 → 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/README.md +88 -35
- package/dist/dispatcher/adapters/node/module.d.ts +2 -1
- package/dist/dispatcher/type.d.ts +8 -6
- package/dist/dispatcher/utils.d.ts +2 -1
- package/dist/error/create.d.ts +11 -0
- package/dist/error/index.d.ts +3 -0
- package/dist/error/is.d.ts +2 -0
- package/dist/error/module.d.ts +3 -0
- package/dist/handler/constants.d.ts +4 -0
- package/dist/handler/core/define.d.ts +3 -0
- package/dist/handler/core/index.d.ts +2 -0
- package/dist/handler/core/types.d.ts +10 -0
- package/dist/handler/error/define.d.ts +3 -0
- package/dist/handler/error/index.d.ts +2 -0
- package/dist/handler/error/types.d.ts +11 -0
- package/dist/handler/index.d.ts +6 -0
- package/dist/handler/is.d.ts +2 -0
- package/dist/handler/types-base.d.ts +6 -0
- package/dist/handler/types.d.ts +5 -0
- package/dist/index.cjs +732 -695
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.mjs +724 -693
- package/dist/index.mjs.map +1 -1
- package/dist/layer/constants.d.ts +1 -0
- package/dist/layer/module.d.ts +9 -7
- package/dist/layer/type.d.ts +6 -3
- package/dist/layer/utils.d.ts +1 -1
- package/dist/path/matcher.d.ts +4 -4
- package/dist/plugin/index.d.ts +2 -0
- package/dist/plugin/is.d.ts +2 -0
- package/dist/plugin/types.d.ts +32 -0
- package/dist/request/helpers/body.d.ts +1 -1
- package/dist/request/helpers/cache.d.ts +1 -1
- package/dist/request/helpers/cookie.d.ts +1 -1
- package/dist/request/helpers/env.d.ts +1 -1
- package/dist/request/helpers/header-accept-charset.d.ts +1 -1
- package/dist/request/helpers/header-accept-language.d.ts +1 -1
- package/dist/request/helpers/header-accept.d.ts +1 -1
- package/dist/request/helpers/header-content-type.d.ts +1 -1
- package/dist/request/helpers/header.d.ts +1 -1
- package/dist/request/helpers/hostname.d.ts +1 -1
- package/dist/request/helpers/ip.d.ts +1 -1
- package/dist/request/helpers/mount-path.d.ts +1 -1
- package/dist/request/helpers/negotiator.d.ts +1 -1
- package/dist/request/helpers/params.d.ts +1 -1
- package/dist/request/helpers/path.d.ts +1 -1
- package/dist/request/helpers/protocol.d.ts +1 -1
- package/dist/request/helpers/query.d.ts +1 -1
- package/dist/request/helpers/router.d.ts +3 -3
- package/dist/request/types.d.ts +4 -0
- package/dist/response/helpers/cache.d.ts +1 -1
- package/dist/response/helpers/gone.d.ts +1 -1
- package/dist/response/helpers/header-attachment.d.ts +1 -1
- package/dist/response/helpers/header-content-type.d.ts +1 -1
- package/dist/response/helpers/header.d.ts +1 -1
- package/dist/response/helpers/send-accepted.d.ts +1 -1
- package/dist/response/helpers/send-created.d.ts +1 -1
- package/dist/response/helpers/send-file.d.ts +1 -1
- package/dist/response/helpers/send-format.d.ts +1 -1
- package/dist/response/helpers/send-redirect.d.ts +1 -1
- package/dist/response/helpers/send-stream.d.ts +2 -1
- package/dist/response/helpers/send-web-blob.d.ts +2 -1
- package/dist/response/helpers/send-web-response.d.ts +2 -1
- package/dist/response/helpers/send.d.ts +1 -1
- package/dist/response/helpers/utils.d.ts +1 -1
- package/dist/response/index.d.ts +1 -0
- package/dist/response/module.d.ts +2 -1
- package/dist/response/types.d.ts +4 -0
- package/dist/router/constants.d.ts +1 -0
- package/dist/router/index.d.ts +1 -0
- package/dist/router/module.d.ts +26 -23
- package/dist/router/utils.d.ts +2 -0
- package/dist/router-options/module.d.ts +1 -1
- package/dist/router-options/type.d.ts +3 -12
- package/dist/types.d.ts +0 -9
- package/dist/utils/is-instance.d.ts +1 -1
- package/package.json +15 -14
- package/dist/error.d.ts +0 -1
- package/dist/route/index.d.ts +0 -3
- package/dist/route/module.d.ts +0 -28
- package/dist/route/type.d.ts +0 -6
- package/dist/route/utils.d.ts +0 -2
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var http = require('@ebec/http');
|
|
4
|
+
var smob = require('smob');
|
|
3
5
|
var buffer = require('buffer');
|
|
4
6
|
var uncrypto = require('uncrypto');
|
|
5
|
-
var smob = require('smob');
|
|
6
7
|
var proxyAddr = require('proxy-addr');
|
|
7
8
|
var mimeExplorer = require('mime-explorer');
|
|
8
9
|
var Negotiator = require('negotiator');
|
|
@@ -11,119 +12,71 @@ var pathToRegexp = require('path-to-regexp');
|
|
|
11
12
|
|
|
12
13
|
exports.MethodName = void 0;
|
|
13
14
|
(function(MethodName) {
|
|
14
|
-
MethodName["GET"] =
|
|
15
|
-
MethodName["POST"] =
|
|
16
|
-
MethodName["PUT"] =
|
|
17
|
-
MethodName["PATCH"] =
|
|
18
|
-
MethodName["DELETE"] =
|
|
19
|
-
MethodName["OPTIONS"] =
|
|
20
|
-
MethodName["HEAD"] =
|
|
15
|
+
MethodName["GET"] = "get";
|
|
16
|
+
MethodName["POST"] = "post";
|
|
17
|
+
MethodName["PUT"] = "put";
|
|
18
|
+
MethodName["PATCH"] = "patch";
|
|
19
|
+
MethodName["DELETE"] = "delete";
|
|
20
|
+
MethodName["OPTIONS"] = "options";
|
|
21
|
+
MethodName["HEAD"] = "head";
|
|
21
22
|
})(exports.MethodName || (exports.MethodName = {}));
|
|
22
23
|
exports.HeaderName = void 0;
|
|
23
24
|
(function(HeaderName) {
|
|
24
|
-
HeaderName["ACCEPT"] =
|
|
25
|
-
HeaderName["ACCEPT_CHARSET"] =
|
|
26
|
-
HeaderName["ACCEPT_ENCODING"] =
|
|
27
|
-
HeaderName["ACCEPT_LANGUAGE"] =
|
|
28
|
-
HeaderName["ACCEPT_RANGES"] =
|
|
29
|
-
HeaderName["ALLOW"] =
|
|
30
|
-
HeaderName["CACHE_CONTROL"] =
|
|
31
|
-
HeaderName["CONTENT_DISPOSITION"] =
|
|
32
|
-
HeaderName["CONTENT_ENCODING"] =
|
|
33
|
-
HeaderName["CONTENT_LENGTH"] =
|
|
34
|
-
HeaderName["CONTENT_RANGE"] =
|
|
35
|
-
HeaderName["CONTENT_TYPE"] =
|
|
36
|
-
HeaderName["COOKIE"] =
|
|
37
|
-
HeaderName["ETag"] =
|
|
38
|
-
HeaderName["HOST"] =
|
|
39
|
-
HeaderName["IF_MODIFIED_SINCE"] =
|
|
40
|
-
HeaderName["IF_NONE_MATCH"] =
|
|
41
|
-
HeaderName["LAST_MODIFIED"] =
|
|
42
|
-
HeaderName["LOCATION"] =
|
|
43
|
-
HeaderName["RANGE"] =
|
|
44
|
-
HeaderName["RATE_LIMIT_LIMIT"] =
|
|
45
|
-
HeaderName["RATE_LIMIT_REMAINING"] =
|
|
46
|
-
HeaderName["RATE_LIMIT_RESET"] =
|
|
47
|
-
HeaderName["RETRY_AFTER"] =
|
|
48
|
-
HeaderName["SET_COOKIE"] =
|
|
49
|
-
HeaderName["TRANSFER_ENCODING"] =
|
|
50
|
-
HeaderName["X_FORWARDED_HOST"] =
|
|
51
|
-
HeaderName["X_FORWARDED_FOR"] =
|
|
52
|
-
HeaderName["X_FORWARDED_PROTO"] =
|
|
25
|
+
HeaderName["ACCEPT"] = "accept";
|
|
26
|
+
HeaderName["ACCEPT_CHARSET"] = "accept-charset";
|
|
27
|
+
HeaderName["ACCEPT_ENCODING"] = "accept-encoding";
|
|
28
|
+
HeaderName["ACCEPT_LANGUAGE"] = "accept-language";
|
|
29
|
+
HeaderName["ACCEPT_RANGES"] = "accept-ranges";
|
|
30
|
+
HeaderName["ALLOW"] = "allow";
|
|
31
|
+
HeaderName["CACHE_CONTROL"] = "cache-control";
|
|
32
|
+
HeaderName["CONTENT_DISPOSITION"] = "content-disposition";
|
|
33
|
+
HeaderName["CONTENT_ENCODING"] = "content-encoding";
|
|
34
|
+
HeaderName["CONTENT_LENGTH"] = "content-length";
|
|
35
|
+
HeaderName["CONTENT_RANGE"] = "content-range";
|
|
36
|
+
HeaderName["CONTENT_TYPE"] = "content-type";
|
|
37
|
+
HeaderName["COOKIE"] = "cookie";
|
|
38
|
+
HeaderName["ETag"] = "etag";
|
|
39
|
+
HeaderName["HOST"] = "host";
|
|
40
|
+
HeaderName["IF_MODIFIED_SINCE"] = "if-modified-since";
|
|
41
|
+
HeaderName["IF_NONE_MATCH"] = "if-none-match";
|
|
42
|
+
HeaderName["LAST_MODIFIED"] = "last-modified";
|
|
43
|
+
HeaderName["LOCATION"] = "location";
|
|
44
|
+
HeaderName["RANGE"] = "range";
|
|
45
|
+
HeaderName["RATE_LIMIT_LIMIT"] = "ratelimit-limit";
|
|
46
|
+
HeaderName["RATE_LIMIT_REMAINING"] = "ratelimit-remaining";
|
|
47
|
+
HeaderName["RATE_LIMIT_RESET"] = "ratelimit-reset";
|
|
48
|
+
HeaderName["RETRY_AFTER"] = "retry-after";
|
|
49
|
+
HeaderName["SET_COOKIE"] = "set-cookie";
|
|
50
|
+
HeaderName["TRANSFER_ENCODING"] = "transfer-encoding";
|
|
51
|
+
HeaderName["X_FORWARDED_HOST"] = "x-forwarded-host";
|
|
52
|
+
HeaderName["X_FORWARDED_FOR"] = "x-forwarded-for";
|
|
53
|
+
HeaderName["X_FORWARDED_PROTO"] = "x-forwarded-proto";
|
|
53
54
|
})(exports.HeaderName || (exports.HeaderName = {}));
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
options = options || {};
|
|
57
|
-
const cacheControls = [
|
|
58
|
-
'public'
|
|
59
|
-
].concat(options.cacheControls || []);
|
|
60
|
-
if (options.maxAge !== undefined) {
|
|
61
|
-
cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);
|
|
62
|
-
}
|
|
63
|
-
if (options.modifiedTime) {
|
|
64
|
-
const modifiedTime = typeof options.modifiedTime === 'string' ? new Date(options.modifiedTime) : options.modifiedTime;
|
|
65
|
-
res.setHeader('last-modified', modifiedTime.toUTCString());
|
|
66
|
-
}
|
|
67
|
-
res.setHeader('cache-control', cacheControls.join(', '));
|
|
56
|
+
class ErrorProxy extends http.HTTPError {
|
|
68
57
|
}
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (res.headersSent || res.writableEnded) {
|
|
73
|
-
return true;
|
|
74
|
-
}
|
|
75
|
-
if (GoneSymbol in res) {
|
|
76
|
-
return res[GoneSymbol];
|
|
77
|
-
}
|
|
78
|
-
return false;
|
|
59
|
+
function isError(input) {
|
|
60
|
+
return input instanceof ErrorProxy;
|
|
79
61
|
}
|
|
80
62
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
res.setHeader(name, [
|
|
93
|
-
...header,
|
|
94
|
-
value
|
|
95
|
-
]);
|
|
96
|
-
}
|
|
97
|
-
function appendResponseHeaderDirective(res, name, value) {
|
|
98
|
-
let header = res.getHeader(name);
|
|
99
|
-
if (!header) {
|
|
100
|
-
if (Array.isArray(value)) {
|
|
101
|
-
res.setHeader(name, value.join('; '));
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
res.setHeader(name, value);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
if (!Array.isArray(header)) {
|
|
108
|
-
if (typeof header === 'string') {
|
|
109
|
-
// split header by directive(s)
|
|
110
|
-
header = header.split('; ');
|
|
111
|
-
}
|
|
112
|
-
if (typeof header === 'number') {
|
|
113
|
-
header = [
|
|
114
|
-
header.toString()
|
|
115
|
-
];
|
|
116
|
-
}
|
|
63
|
+
/**
|
|
64
|
+
* Create an error proxy by
|
|
65
|
+
* - an existing error (accessible via cause property)
|
|
66
|
+
* - options
|
|
67
|
+
* - message
|
|
68
|
+
*
|
|
69
|
+
* @param input
|
|
70
|
+
*/ function createError(input) {
|
|
71
|
+
if (isError(input)) {
|
|
72
|
+
return input;
|
|
117
73
|
}
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
} else {
|
|
121
|
-
header.push(`${value}`);
|
|
74
|
+
if (typeof input === 'string') {
|
|
75
|
+
return new ErrorProxy(input);
|
|
122
76
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
res.setHeader(name, header.join('; '));
|
|
77
|
+
return new ErrorProxy({
|
|
78
|
+
cause: input
|
|
79
|
+
}, input);
|
|
127
80
|
}
|
|
128
81
|
|
|
129
82
|
/*
|
|
@@ -313,8 +266,11 @@ function buildTrustProxyFn(input) {
|
|
|
313
266
|
return proxyAddr.compile(input || []);
|
|
314
267
|
}
|
|
315
268
|
|
|
316
|
-
function isInstance(input,
|
|
317
|
-
|
|
269
|
+
function isInstance(input, sym) {
|
|
270
|
+
if (!isObject(input)) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
return input['@instanceof'] === sym;
|
|
318
274
|
}
|
|
319
275
|
|
|
320
276
|
function getMimeType(type) {
|
|
@@ -395,7 +351,10 @@ function withLeadingSlash(input = '') {
|
|
|
395
351
|
return hasLeadingSlash(input) ? input : `/${input}`;
|
|
396
352
|
}
|
|
397
353
|
function cleanDoubleSlashes(input = '') {
|
|
398
|
-
|
|
354
|
+
if (input.indexOf('://') !== -1) {
|
|
355
|
+
return input.split('://').map((str)=>cleanDoubleSlashes(str)).join('://');
|
|
356
|
+
}
|
|
357
|
+
return input.replace(/\/+/g, '/');
|
|
399
358
|
}
|
|
400
359
|
|
|
401
360
|
function isWebBlob(input) {
|
|
@@ -405,67 +364,6 @@ function isWebResponse(input) {
|
|
|
405
364
|
return typeof Response !== 'undefined' && input instanceof Response;
|
|
406
365
|
}
|
|
407
366
|
|
|
408
|
-
function setResponseContentTypeByFileName(res, fileName) {
|
|
409
|
-
const ext = extname(fileName);
|
|
410
|
-
if (ext) {
|
|
411
|
-
let type = getMimeType(ext.substring(1));
|
|
412
|
-
if (type) {
|
|
413
|
-
const charset = getCharsetForMimeType(type);
|
|
414
|
-
if (charset) {
|
|
415
|
-
type += `; charset=${charset}`;
|
|
416
|
-
}
|
|
417
|
-
res.setHeader(exports.HeaderName.CONTENT_TYPE, type);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
function setResponseHeaderAttachment(res, filename) {
|
|
423
|
-
if (typeof filename === 'string') {
|
|
424
|
-
setResponseContentTypeByFileName(res, filename);
|
|
425
|
-
}
|
|
426
|
-
res.setHeader(exports.HeaderName.CONTENT_DISPOSITION, `attachment${filename ? `; filename="${filename}"` : ''}`);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
function setResponseHeaderContentType(res, input, ifNotExists) {
|
|
430
|
-
if (ifNotExists) {
|
|
431
|
-
const header = res.getHeader(exports.HeaderName.CONTENT_TYPE);
|
|
432
|
-
if (header) {
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
const contentType = getMimeType(input);
|
|
437
|
-
if (contentType) {
|
|
438
|
-
res.setHeader(exports.HeaderName.CONTENT_TYPE, contentType);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
const defaults = {
|
|
443
|
-
trustProxy: ()=>false,
|
|
444
|
-
subdomainOffset: 2,
|
|
445
|
-
etag: buildEtagFn(),
|
|
446
|
-
proxyIpMax: 0
|
|
447
|
-
};
|
|
448
|
-
const instances = {};
|
|
449
|
-
function setRouterOptions(id, input) {
|
|
450
|
-
instances[id] = input;
|
|
451
|
-
}
|
|
452
|
-
function findRouterOption(key, id) {
|
|
453
|
-
if (!id) {
|
|
454
|
-
return defaults[key];
|
|
455
|
-
}
|
|
456
|
-
const ids = Array.isArray(id) ? id : [
|
|
457
|
-
id
|
|
458
|
-
];
|
|
459
|
-
if (ids.length > 0) {
|
|
460
|
-
for(let i = ids.length; i >= 0; i--){
|
|
461
|
-
if (smob.hasOwnProperty(instances, ids[i]) && typeof instances[ids[i]][key] !== 'undefined') {
|
|
462
|
-
return instances[ids[i]][key];
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
return defaults[key];
|
|
467
|
-
}
|
|
468
|
-
|
|
469
367
|
const BodySymbol = Symbol.for('ReqBody');
|
|
470
368
|
function useRequestBody(req, key) {
|
|
471
369
|
let body;
|
|
@@ -727,11 +625,35 @@ function matchRequestContentType(req, contentType) {
|
|
|
727
625
|
return header.split('; ').shift() === getMimeType(contentType);
|
|
728
626
|
}
|
|
729
627
|
|
|
628
|
+
const defaults = {
|
|
629
|
+
trustProxy: ()=>false,
|
|
630
|
+
subdomainOffset: 2,
|
|
631
|
+
etag: buildEtagFn(),
|
|
632
|
+
proxyIpMax: 0
|
|
633
|
+
};
|
|
634
|
+
const instances = {};
|
|
635
|
+
function setRouterOptions(id, input) {
|
|
636
|
+
instances[id] = input;
|
|
637
|
+
}
|
|
638
|
+
function findRouterOption(key, path) {
|
|
639
|
+
if (!path || path.length === 0) {
|
|
640
|
+
return defaults[key];
|
|
641
|
+
}
|
|
642
|
+
if (path.length > 0) {
|
|
643
|
+
for(let i = path.length; i >= 0; i--){
|
|
644
|
+
if (smob.hasOwnProperty(instances, path[i]) && typeof instances[path[i]][key] !== 'undefined') {
|
|
645
|
+
return instances[path[i]][key];
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return defaults[key];
|
|
650
|
+
}
|
|
651
|
+
|
|
730
652
|
const routerSymbol = Symbol.for('ReqRouterID');
|
|
731
|
-
function
|
|
732
|
-
req[routerSymbol] =
|
|
653
|
+
function setRequestRouterPath(req, path) {
|
|
654
|
+
req[routerSymbol] = path;
|
|
733
655
|
}
|
|
734
|
-
function
|
|
656
|
+
function useRequestRouterPath(req) {
|
|
735
657
|
if (routerSymbol in req) {
|
|
736
658
|
return req[routerSymbol];
|
|
737
659
|
}
|
|
@@ -744,7 +666,7 @@ function getRequestHostName(req, options) {
|
|
|
744
666
|
if (typeof options.trustProxy !== 'undefined') {
|
|
745
667
|
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
746
668
|
} else {
|
|
747
|
-
trustProxy = findRouterOption('trustProxy',
|
|
669
|
+
trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
|
|
748
670
|
}
|
|
749
671
|
let hostname = req.headers[exports.HeaderName.X_FORWARDED_HOST];
|
|
750
672
|
if (!hostname || !req.socket.remoteAddress || !trustProxy(req.socket.remoteAddress, 0)) {
|
|
@@ -770,7 +692,7 @@ function getRequestIP(req, options) {
|
|
|
770
692
|
if (typeof options.trustProxy !== 'undefined') {
|
|
771
693
|
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
772
694
|
} else {
|
|
773
|
-
trustProxy = findRouterOption('trustProxy',
|
|
695
|
+
trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
|
|
774
696
|
}
|
|
775
697
|
const addrs = proxyAddr.all(req, trustProxy);
|
|
776
698
|
return addrs[addrs.length - 1];
|
|
@@ -831,7 +753,7 @@ function getRequestProtocol(req, options) {
|
|
|
831
753
|
if (typeof options.trustProxy !== 'undefined') {
|
|
832
754
|
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
833
755
|
} else {
|
|
834
|
-
trustProxy = findRouterOption('trustProxy',
|
|
756
|
+
trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
|
|
835
757
|
}
|
|
836
758
|
let protocol = options.default;
|
|
837
759
|
/* istanbul ignore next */ if (smob.hasOwnProperty(req.socket, 'encrypted') && !!req.socket.encrypted) {
|
|
@@ -899,100 +821,280 @@ function extendRequestQuery(req, key, value) {
|
|
|
899
821
|
setRequestQuery(req, key, value);
|
|
900
822
|
}
|
|
901
823
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
break;
|
|
908
|
-
}
|
|
909
|
-
case 'boolean':
|
|
910
|
-
case 'number':
|
|
911
|
-
case 'object':
|
|
912
|
-
{
|
|
913
|
-
if (chunk === null) {
|
|
914
|
-
chunk = '';
|
|
915
|
-
} else if (buffer.Buffer.isBuffer(chunk)) {
|
|
916
|
-
setResponseHeaderContentType(res, 'bin', true);
|
|
917
|
-
} else {
|
|
918
|
-
chunk = JSON.stringify(chunk);
|
|
919
|
-
setResponseHeaderContentType(res, 'application/json', true);
|
|
920
|
-
}
|
|
921
|
-
break;
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
let encoding;
|
|
925
|
-
if (typeof chunk === 'string') {
|
|
926
|
-
res.setHeader(exports.HeaderName.CONTENT_ENCODING, 'utf-8');
|
|
927
|
-
appendResponseHeaderDirective(res, exports.HeaderName.CONTENT_TYPE, 'charset=utf-8');
|
|
928
|
-
encoding = 'utf-8';
|
|
929
|
-
}
|
|
930
|
-
// populate Content-Length
|
|
931
|
-
let len;
|
|
932
|
-
if (chunk !== undefined) {
|
|
933
|
-
if (buffer.Buffer.isBuffer(chunk)) {
|
|
934
|
-
// get length of Buffer
|
|
935
|
-
len = chunk.length;
|
|
936
|
-
} else if (chunk.length < 1000) {
|
|
937
|
-
// just calculate length when no ETag + small chunk
|
|
938
|
-
len = buffer.Buffer.byteLength(chunk, encoding);
|
|
824
|
+
function createRequest(context) {
|
|
825
|
+
let readable;
|
|
826
|
+
if (context.body) {
|
|
827
|
+
if (isWebStream(context.body)) {
|
|
828
|
+
readable = readableStream.Readable.fromWeb(context.body);
|
|
939
829
|
} else {
|
|
940
|
-
|
|
941
|
-
chunk = buffer.Buffer.from(chunk, encoding);
|
|
942
|
-
encoding = undefined;
|
|
943
|
-
len = chunk.length;
|
|
830
|
+
readable = readableStream.Readable.from(context.body);
|
|
944
831
|
}
|
|
945
|
-
|
|
832
|
+
} else {
|
|
833
|
+
readable = new readableStream.Readable();
|
|
946
834
|
}
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
if (res.req.headers[exports.HeaderName.IF_NONE_MATCH] === chunkHash) {
|
|
956
|
-
res.statusCode = 304;
|
|
835
|
+
const headers = context.headers || {};
|
|
836
|
+
const rawHeaders = [];
|
|
837
|
+
let keys = Object.keys(headers);
|
|
838
|
+
for(let i = 0; i < keys.length; i++){
|
|
839
|
+
const header = headers[keys[i]];
|
|
840
|
+
if (Array.isArray(header)) {
|
|
841
|
+
for(let j = 0; j < header.length; j++){
|
|
842
|
+
rawHeaders.push(keys[i], header[j]);
|
|
957
843
|
}
|
|
844
|
+
} else if (typeof header === 'string') {
|
|
845
|
+
rawHeaders.push(keys[i], header);
|
|
958
846
|
}
|
|
959
847
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
}
|
|
973
|
-
if (isResponseGone(res)) {
|
|
974
|
-
return Promise.resolve();
|
|
975
|
-
}
|
|
976
|
-
if (res.req.method === 'HEAD') {
|
|
977
|
-
// skip body for HEAD
|
|
978
|
-
res.end();
|
|
979
|
-
return Promise.resolve();
|
|
980
|
-
}
|
|
981
|
-
if (typeof encoding !== 'undefined') {
|
|
982
|
-
res.end(chunk, encoding);
|
|
983
|
-
return Promise.resolve();
|
|
848
|
+
const headersDistinct = {};
|
|
849
|
+
keys = Object.keys(headers);
|
|
850
|
+
for(let i = 0; i < keys.length; i++){
|
|
851
|
+
const header = headers[keys[i]];
|
|
852
|
+
if (Array.isArray(header)) {
|
|
853
|
+
headersDistinct[keys[i]] = header;
|
|
854
|
+
}
|
|
855
|
+
if (typeof header === 'string') {
|
|
856
|
+
headersDistinct[keys[i]] = [
|
|
857
|
+
header
|
|
858
|
+
];
|
|
859
|
+
}
|
|
984
860
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
861
|
+
Object.defineProperty(readable, 'connection', {
|
|
862
|
+
get () {
|
|
863
|
+
return {
|
|
864
|
+
remoteAddress: '127.0.0.1'
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
Object.defineProperty(readable, 'socket', {
|
|
869
|
+
get () {
|
|
870
|
+
return {
|
|
871
|
+
remoteAddress: '127.0.0.1'
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
Object.assign(readable, {
|
|
876
|
+
aborted: false,
|
|
877
|
+
complete: true,
|
|
878
|
+
headers,
|
|
879
|
+
headersDistinct,
|
|
880
|
+
httpVersion: '1.1',
|
|
881
|
+
httpVersionMajor: 1,
|
|
882
|
+
httpVersionMinor: 1,
|
|
883
|
+
method: context.method || 'GET',
|
|
884
|
+
rawHeaders,
|
|
885
|
+
rawTrailers: [],
|
|
886
|
+
trailers: {},
|
|
887
|
+
trailersDistinct: {},
|
|
888
|
+
url: context.url || '/',
|
|
889
|
+
setTimeout (_msecs, _callback) {
|
|
890
|
+
return this;
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
return readable;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
function setResponseCacheHeaders(res, options) {
|
|
897
|
+
options = options || {};
|
|
898
|
+
const cacheControls = [
|
|
899
|
+
'public'
|
|
900
|
+
].concat(options.cacheControls || []);
|
|
901
|
+
if (options.maxAge !== undefined) {
|
|
902
|
+
cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);
|
|
903
|
+
}
|
|
904
|
+
if (options.modifiedTime) {
|
|
905
|
+
const modifiedTime = typeof options.modifiedTime === 'string' ? new Date(options.modifiedTime) : options.modifiedTime;
|
|
906
|
+
res.setHeader('last-modified', modifiedTime.toUTCString());
|
|
907
|
+
}
|
|
908
|
+
res.setHeader('cache-control', cacheControls.join(', '));
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
const GoneSymbol = Symbol.for('ResGone');
|
|
912
|
+
function isResponseGone(res) {
|
|
913
|
+
if (res.headersSent || res.writableEnded) {
|
|
914
|
+
return true;
|
|
915
|
+
}
|
|
916
|
+
if (GoneSymbol in res) {
|
|
917
|
+
return res[GoneSymbol];
|
|
918
|
+
}
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function appendResponseHeader(res, name, value) {
|
|
923
|
+
let header = res.getHeader(name);
|
|
924
|
+
if (!header) {
|
|
925
|
+
res.setHeader(name, value);
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
if (!Array.isArray(header)) {
|
|
929
|
+
header = [
|
|
930
|
+
header.toString()
|
|
931
|
+
];
|
|
932
|
+
}
|
|
933
|
+
res.setHeader(name, [
|
|
934
|
+
...header,
|
|
935
|
+
value
|
|
936
|
+
]);
|
|
937
|
+
}
|
|
938
|
+
function appendResponseHeaderDirective(res, name, value) {
|
|
939
|
+
let header = res.getHeader(name);
|
|
940
|
+
if (!header) {
|
|
941
|
+
if (Array.isArray(value)) {
|
|
942
|
+
res.setHeader(name, value.join('; '));
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
res.setHeader(name, value);
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
if (!Array.isArray(header)) {
|
|
949
|
+
if (typeof header === 'string') {
|
|
950
|
+
// split header by directive(s)
|
|
951
|
+
header = header.split('; ');
|
|
952
|
+
}
|
|
953
|
+
if (typeof header === 'number') {
|
|
954
|
+
header = [
|
|
955
|
+
header.toString()
|
|
956
|
+
];
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
if (Array.isArray(value)) {
|
|
960
|
+
header.push(...value);
|
|
961
|
+
} else {
|
|
962
|
+
header.push(`${value}`);
|
|
963
|
+
}
|
|
964
|
+
header = [
|
|
965
|
+
...new Set(header)
|
|
966
|
+
];
|
|
967
|
+
res.setHeader(name, header.join('; '));
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
function setResponseContentTypeByFileName(res, fileName) {
|
|
971
|
+
const ext = extname(fileName);
|
|
972
|
+
if (ext) {
|
|
973
|
+
let type = getMimeType(ext.substring(1));
|
|
974
|
+
if (type) {
|
|
975
|
+
const charset = getCharsetForMimeType(type);
|
|
976
|
+
if (charset) {
|
|
977
|
+
type += `; charset=${charset}`;
|
|
978
|
+
}
|
|
979
|
+
res.setHeader(exports.HeaderName.CONTENT_TYPE, type);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
function setResponseHeaderAttachment(res, filename) {
|
|
985
|
+
if (typeof filename === 'string') {
|
|
986
|
+
setResponseContentTypeByFileName(res, filename);
|
|
987
|
+
}
|
|
988
|
+
res.setHeader(exports.HeaderName.CONTENT_DISPOSITION, `attachment${filename ? `; filename="${filename}"` : ''}`);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
function setResponseHeaderContentType(res, input, ifNotExists) {
|
|
992
|
+
if (ifNotExists) {
|
|
993
|
+
const header = res.getHeader(exports.HeaderName.CONTENT_TYPE);
|
|
994
|
+
if (header) {
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
const contentType = getMimeType(input);
|
|
999
|
+
if (contentType) {
|
|
1000
|
+
res.setHeader(exports.HeaderName.CONTENT_TYPE, contentType);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
async function send(res, chunk) {
|
|
1005
|
+
switch(typeof chunk){
|
|
1006
|
+
case 'string':
|
|
1007
|
+
{
|
|
1008
|
+
setResponseHeaderContentType(res, 'html', true);
|
|
1009
|
+
break;
|
|
1010
|
+
}
|
|
1011
|
+
case 'boolean':
|
|
1012
|
+
case 'number':
|
|
1013
|
+
case 'object':
|
|
1014
|
+
{
|
|
1015
|
+
if (buffer.Buffer.isBuffer(chunk)) {
|
|
1016
|
+
setResponseHeaderContentType(res, 'bin', true);
|
|
1017
|
+
} else if (chunk !== null) {
|
|
1018
|
+
chunk = JSON.stringify(chunk);
|
|
1019
|
+
setResponseHeaderContentType(res, 'application/json', true);
|
|
1020
|
+
}
|
|
1021
|
+
break;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
let encoding;
|
|
1025
|
+
if (typeof chunk === 'string') {
|
|
1026
|
+
res.setHeader(exports.HeaderName.CONTENT_ENCODING, 'utf-8');
|
|
1027
|
+
appendResponseHeaderDirective(res, exports.HeaderName.CONTENT_TYPE, 'charset=utf-8');
|
|
1028
|
+
encoding = 'utf-8';
|
|
1029
|
+
}
|
|
1030
|
+
// populate Content-Length
|
|
1031
|
+
let len;
|
|
1032
|
+
if (chunk !== undefined && chunk !== null) {
|
|
1033
|
+
if (buffer.Buffer.isBuffer(chunk)) {
|
|
1034
|
+
// get length of Buffer
|
|
1035
|
+
len = chunk.length;
|
|
1036
|
+
} else if (chunk.length < 1000) {
|
|
1037
|
+
// just calculate length when no ETag + small chunk
|
|
1038
|
+
len = buffer.Buffer.byteLength(chunk, encoding);
|
|
1039
|
+
} else {
|
|
1040
|
+
// convert chunk to Buffer and calculate
|
|
1041
|
+
chunk = buffer.Buffer.from(chunk, encoding);
|
|
1042
|
+
encoding = undefined;
|
|
1043
|
+
len = chunk.length;
|
|
1044
|
+
}
|
|
1045
|
+
res.setHeader(exports.HeaderName.CONTENT_LENGTH, `${len}`);
|
|
1046
|
+
}
|
|
1047
|
+
if (typeof len !== 'undefined') {
|
|
1048
|
+
const etagFn = findRouterOption('etag', useRequestRouterPath(res.req));
|
|
1049
|
+
const chunkHash = await etagFn(chunk, encoding, len);
|
|
1050
|
+
if (isResponseGone(res)) {
|
|
1051
|
+
return Promise.resolve();
|
|
1052
|
+
}
|
|
1053
|
+
if (typeof chunkHash === 'string') {
|
|
1054
|
+
res.setHeader(exports.HeaderName.ETag, chunkHash);
|
|
1055
|
+
if (res.req.headers[exports.HeaderName.IF_NONE_MATCH] === chunkHash) {
|
|
1056
|
+
res.statusCode = 304;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
// strip irrelevant headers
|
|
1061
|
+
if (res.statusCode === 204 || res.statusCode === 304) {
|
|
1062
|
+
res.removeHeader(exports.HeaderName.CONTENT_TYPE);
|
|
1063
|
+
res.removeHeader(exports.HeaderName.CONTENT_LENGTH);
|
|
1064
|
+
res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
|
|
1065
|
+
}
|
|
1066
|
+
// alter headers for 205
|
|
1067
|
+
if (res.statusCode === 205) {
|
|
1068
|
+
res.setHeader(exports.HeaderName.CONTENT_LENGTH, 0);
|
|
1069
|
+
res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
|
|
1070
|
+
}
|
|
1071
|
+
if (isResponseGone(res)) {
|
|
1072
|
+
return Promise.resolve();
|
|
1073
|
+
}
|
|
1074
|
+
if (res.req.method === 'HEAD') {
|
|
1075
|
+
// skip body for HEAD
|
|
1076
|
+
res.end();
|
|
1077
|
+
return Promise.resolve();
|
|
1078
|
+
}
|
|
1079
|
+
if (typeof chunk === 'undefined' || chunk === null) {
|
|
1080
|
+
res.end();
|
|
1081
|
+
return Promise.resolve();
|
|
1082
|
+
}
|
|
1083
|
+
if (typeof encoding !== 'undefined') {
|
|
1084
|
+
res.end(chunk, encoding);
|
|
1085
|
+
return Promise.resolve();
|
|
1086
|
+
}
|
|
1087
|
+
res.end(chunk);
|
|
1088
|
+
return Promise.resolve();
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
function sendAccepted(res, chunk) {
|
|
1092
|
+
res.statusCode = 202;
|
|
1093
|
+
res.statusMessage = 'Accepted';
|
|
1094
|
+
return send(res, chunk);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
function sendCreated(res, chunk) {
|
|
996
1098
|
res.statusCode = 201;
|
|
997
1099
|
res.statusMessage = 'Created';
|
|
998
1100
|
return send(res, chunk);
|
|
@@ -1303,99 +1405,90 @@ function createResponse(request) {
|
|
|
1303
1405
|
return writable;
|
|
1304
1406
|
}
|
|
1305
1407
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
if (dispatched) {
|
|
1313
|
-
return;
|
|
1314
|
-
}
|
|
1315
|
-
if (!isResponseGone(res)) {
|
|
1316
|
-
res.statusCode = 404;
|
|
1317
|
-
res.end();
|
|
1318
|
-
}
|
|
1319
|
-
} catch (e) {
|
|
1320
|
-
if (!isResponseGone(res)) {
|
|
1321
|
-
res.statusCode = 500;
|
|
1322
|
-
res.end();
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
function createNodeDispatcher(router) {
|
|
1327
|
-
return (req, res)=>{
|
|
1328
|
-
// eslint-disable-next-line no-void
|
|
1329
|
-
void dispatchNodeRequest(router, req, res);
|
|
1408
|
+
function buildDispatcherMeta(input) {
|
|
1409
|
+
return {
|
|
1410
|
+
mountPath: input.mountPath || '/',
|
|
1411
|
+
params: input.params || {},
|
|
1412
|
+
path: input.path || '/',
|
|
1413
|
+
routerPath: []
|
|
1330
1414
|
};
|
|
1331
1415
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1416
|
+
function cloneDispatcherMeta(input) {
|
|
1417
|
+
return {
|
|
1418
|
+
path: input.path,
|
|
1419
|
+
mountPath: input.mountPath,
|
|
1420
|
+
error: input.error,
|
|
1421
|
+
routerPath: [
|
|
1422
|
+
...input.routerPath
|
|
1423
|
+
],
|
|
1424
|
+
params: cloneDispatcherMetaParams(input.params)
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
function cloneDispatcherMetaParams(input) {
|
|
1428
|
+
if (typeof input === 'undefined') {
|
|
1429
|
+
return {};
|
|
1343
1430
|
}
|
|
1344
|
-
const
|
|
1345
|
-
|
|
1346
|
-
|
|
1431
|
+
const keys = Object.keys(input);
|
|
1432
|
+
if (keys.length === 0) {
|
|
1433
|
+
return {};
|
|
1434
|
+
}
|
|
1435
|
+
const output = {};
|
|
1347
1436
|
for(let i = 0; i < keys.length; i++){
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1437
|
+
output[keys[i]] = input[keys[i]];
|
|
1438
|
+
}
|
|
1439
|
+
return output;
|
|
1440
|
+
}
|
|
1441
|
+
function mergeDispatcherMetaParams(t1, t2) {
|
|
1442
|
+
if (!t1 && !t2) {
|
|
1443
|
+
return {};
|
|
1444
|
+
}
|
|
1445
|
+
if (!t1 || !t2) {
|
|
1446
|
+
return t1 || t2;
|
|
1447
|
+
}
|
|
1448
|
+
const keys = Object.keys(t2);
|
|
1449
|
+
if (keys.length === 0) {
|
|
1450
|
+
return t1;
|
|
1356
1451
|
}
|
|
1357
|
-
const headersDistinct = {};
|
|
1358
|
-
keys = Object.keys(headers);
|
|
1359
1452
|
for(let i = 0; i < keys.length; i++){
|
|
1360
|
-
|
|
1361
|
-
if (Array.isArray(header)) {
|
|
1362
|
-
headersDistinct[keys[i]] = header;
|
|
1363
|
-
}
|
|
1364
|
-
if (typeof header === 'string') {
|
|
1365
|
-
headersDistinct[keys[i]] = [
|
|
1366
|
-
header
|
|
1367
|
-
];
|
|
1368
|
-
}
|
|
1453
|
+
t1[keys[i]] = t2[keys[i]];
|
|
1369
1454
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1455
|
+
return t1;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
async function dispatchNodeRequest(router, req, res) {
|
|
1459
|
+
try {
|
|
1460
|
+
const dispatched = await router.dispatch({
|
|
1461
|
+
req,
|
|
1462
|
+
res
|
|
1463
|
+
}, buildDispatcherMeta({
|
|
1464
|
+
path: useRequestPath(req)
|
|
1465
|
+
}));
|
|
1466
|
+
if (dispatched) {
|
|
1467
|
+
return;
|
|
1373
1468
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
return {};
|
|
1469
|
+
if (!isResponseGone(res)) {
|
|
1470
|
+
res.statusCode = 404;
|
|
1471
|
+
res.end();
|
|
1378
1472
|
}
|
|
1379
|
-
})
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
rawTrailers: [],
|
|
1391
|
-
trailers: {},
|
|
1392
|
-
trailersDistinct: {},
|
|
1393
|
-
url: context.url || '/',
|
|
1394
|
-
setTimeout (_msecs, _callback) {
|
|
1395
|
-
return this;
|
|
1473
|
+
} catch (e) {
|
|
1474
|
+
if (!isResponseGone(res)) {
|
|
1475
|
+
if (isError(e)) {
|
|
1476
|
+
res.statusCode = e.statusCode;
|
|
1477
|
+
if (e.statusMessage) {
|
|
1478
|
+
res.statusMessage = e.statusMessage;
|
|
1479
|
+
}
|
|
1480
|
+
} else {
|
|
1481
|
+
res.statusCode = 500;
|
|
1482
|
+
}
|
|
1483
|
+
res.end();
|
|
1396
1484
|
}
|
|
1397
|
-
}
|
|
1398
|
-
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
function createNodeDispatcher(router) {
|
|
1488
|
+
return (req, res)=>{
|
|
1489
|
+
// eslint-disable-next-line no-void
|
|
1490
|
+
void dispatchNodeRequest(router, req, res);
|
|
1491
|
+
};
|
|
1399
1492
|
}
|
|
1400
1493
|
|
|
1401
1494
|
async function dispatchRawRequest(router, request, options = {}) {
|
|
@@ -1420,33 +1513,38 @@ async function dispatchRawRequest(router, request, options = {}) {
|
|
|
1420
1513
|
}
|
|
1421
1514
|
return output;
|
|
1422
1515
|
};
|
|
1516
|
+
const createRawResponse = (input = {})=>({
|
|
1517
|
+
status: input.status || res.statusCode,
|
|
1518
|
+
statusMessage: input.statusMessage || res.statusMessage,
|
|
1519
|
+
headers: getHeaders(),
|
|
1520
|
+
body: res.body
|
|
1521
|
+
});
|
|
1423
1522
|
try {
|
|
1424
1523
|
const dispatched = await router.dispatch({
|
|
1425
1524
|
req,
|
|
1426
1525
|
res
|
|
1427
|
-
}
|
|
1526
|
+
}, buildDispatcherMeta({
|
|
1527
|
+
path: useRequestPath(req)
|
|
1528
|
+
}));
|
|
1428
1529
|
if (dispatched) {
|
|
1429
|
-
return
|
|
1430
|
-
status: res.statusCode,
|
|
1431
|
-
statusMessage: res.statusMessage,
|
|
1432
|
-
headers: getHeaders(),
|
|
1433
|
-
body: res.body
|
|
1434
|
-
};
|
|
1530
|
+
return createRawResponse();
|
|
1435
1531
|
}
|
|
1436
|
-
return {
|
|
1437
|
-
status: 404
|
|
1438
|
-
|
|
1439
|
-
body: res.body
|
|
1440
|
-
};
|
|
1532
|
+
return createRawResponse({
|
|
1533
|
+
status: 404
|
|
1534
|
+
});
|
|
1441
1535
|
} catch (e) {
|
|
1442
1536
|
if (options.throwOnError) {
|
|
1443
1537
|
throw e;
|
|
1444
1538
|
}
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1539
|
+
if (isError(e)) {
|
|
1540
|
+
return createRawResponse({
|
|
1541
|
+
status: e.statusCode,
|
|
1542
|
+
statusMessage: e.statusMessage
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
return createRawResponse({
|
|
1546
|
+
status: 500
|
|
1547
|
+
});
|
|
1450
1548
|
}
|
|
1451
1549
|
}
|
|
1452
1550
|
function createRawDispatcher(router) {
|
|
@@ -1481,54 +1579,40 @@ function createWebDispatcher(router) {
|
|
|
1481
1579
|
return async (request)=>dispatchWebRequest(router, request);
|
|
1482
1580
|
}
|
|
1483
1581
|
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1582
|
+
exports.HandlerType = void 0;
|
|
1583
|
+
(function(HandlerType) {
|
|
1584
|
+
HandlerType["CORE"] = "core";
|
|
1585
|
+
HandlerType["ERROR"] = "error";
|
|
1586
|
+
})(exports.HandlerType || (exports.HandlerType = {}));
|
|
1587
|
+
|
|
1588
|
+
function coreHandler(input) {
|
|
1589
|
+
if (typeof input === 'function') {
|
|
1590
|
+
return {
|
|
1591
|
+
type: exports.HandlerType.CORE,
|
|
1592
|
+
fn: input
|
|
1593
|
+
};
|
|
1487
1594
|
}
|
|
1488
1595
|
return {
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
error: input.error,
|
|
1492
|
-
routerIds: [
|
|
1493
|
-
...input.routerIds || []
|
|
1494
|
-
],
|
|
1495
|
-
params: cloneDispatcherMetaParams(input.params)
|
|
1596
|
+
type: exports.HandlerType.CORE,
|
|
1597
|
+
...input
|
|
1496
1598
|
};
|
|
1497
1599
|
}
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
output[keys[i]] = input[keys[i]];
|
|
1506
|
-
}
|
|
1507
|
-
return output;
|
|
1508
|
-
}
|
|
1509
|
-
function mergeDispatcherMetaParams(t1, t2) {
|
|
1510
|
-
if (!t1 && !t2) {
|
|
1511
|
-
return {};
|
|
1512
|
-
}
|
|
1513
|
-
if (!t1 || !t2) {
|
|
1514
|
-
return t1 || t2;
|
|
1515
|
-
}
|
|
1516
|
-
const keys = Object.keys(t2);
|
|
1517
|
-
for(let i = 0; i < keys.length; i++){
|
|
1518
|
-
t1[keys[i]] = t2[keys[i]];
|
|
1600
|
+
|
|
1601
|
+
function errorHandler(input) {
|
|
1602
|
+
if (typeof input === 'function') {
|
|
1603
|
+
return {
|
|
1604
|
+
type: exports.HandlerType.ERROR,
|
|
1605
|
+
fn: input
|
|
1606
|
+
};
|
|
1519
1607
|
}
|
|
1520
|
-
return
|
|
1608
|
+
return {
|
|
1609
|
+
type: exports.HandlerType.ERROR,
|
|
1610
|
+
...input
|
|
1611
|
+
};
|
|
1521
1612
|
}
|
|
1522
1613
|
|
|
1523
|
-
function
|
|
1524
|
-
|
|
1525
|
-
return input;
|
|
1526
|
-
}
|
|
1527
|
-
const error = new Error();
|
|
1528
|
-
if (typeof input.message === 'string') {
|
|
1529
|
-
error.message = input.message;
|
|
1530
|
-
}
|
|
1531
|
-
return error;
|
|
1614
|
+
function isHandler(input) {
|
|
1615
|
+
return isObject(input) && typeof input.fn === 'function' && typeof input.type === 'string';
|
|
1532
1616
|
}
|
|
1533
1617
|
|
|
1534
1618
|
function decodeParam(val) {
|
|
@@ -1539,56 +1623,46 @@ function decodeParam(val) {
|
|
|
1539
1623
|
}
|
|
1540
1624
|
class PathMatcher {
|
|
1541
1625
|
test(path) {
|
|
1542
|
-
const fastSlash = this.path === '/' && this.regexpOptions.end === false;
|
|
1543
|
-
if (fastSlash) {
|
|
1544
|
-
return true;
|
|
1545
|
-
}
|
|
1546
1626
|
return this.regexp.test(path);
|
|
1547
1627
|
}
|
|
1548
1628
|
exec(path) {
|
|
1549
|
-
|
|
1550
|
-
const fastSlash = this.path === '/' && this.regexpOptions.end === false;
|
|
1551
|
-
if (fastSlash) {
|
|
1629
|
+
if (this.path === '/' && this.regexpOptions.end === false) {
|
|
1552
1630
|
return {
|
|
1553
1631
|
path: '/',
|
|
1554
1632
|
params: {}
|
|
1555
1633
|
};
|
|
1556
1634
|
}
|
|
1557
|
-
|
|
1558
|
-
if (!match) {
|
|
1559
|
-
return undefined;
|
|
1560
|
-
}
|
|
1561
|
-
if (this.path instanceof RegExp) {
|
|
1635
|
+
if (this.path === '*') {
|
|
1562
1636
|
return {
|
|
1563
1637
|
path,
|
|
1564
1638
|
params: {
|
|
1565
|
-
0: decodeParam(
|
|
1639
|
+
0: decodeParam(path)
|
|
1566
1640
|
}
|
|
1567
1641
|
};
|
|
1568
1642
|
}
|
|
1569
|
-
const
|
|
1643
|
+
const match = this.regexp.exec(path);
|
|
1644
|
+
if (!match) {
|
|
1645
|
+
return undefined;
|
|
1646
|
+
}
|
|
1647
|
+
const params = {};
|
|
1570
1648
|
for(let i = 1; i < match.length; i++){
|
|
1571
1649
|
const key = this.regexpKeys[i - 1];
|
|
1572
1650
|
const prop = key.name;
|
|
1573
1651
|
const val = decodeParam(match[i]);
|
|
1574
1652
|
if (typeof val !== 'undefined') {
|
|
1575
|
-
|
|
1653
|
+
params[prop] = val;
|
|
1576
1654
|
}
|
|
1577
1655
|
}
|
|
1578
1656
|
return {
|
|
1579
1657
|
path: match[0],
|
|
1580
|
-
params
|
|
1658
|
+
params
|
|
1581
1659
|
};
|
|
1582
1660
|
}
|
|
1583
1661
|
constructor(path, options){
|
|
1584
1662
|
this.regexpKeys = [];
|
|
1585
1663
|
this.path = path;
|
|
1586
1664
|
this.regexpOptions = options || {};
|
|
1587
|
-
|
|
1588
|
-
this.regexp = path;
|
|
1589
|
-
} else {
|
|
1590
|
-
this.regexp = pathToRegexp.pathToRegexp(path, this.regexpKeys, options);
|
|
1591
|
-
}
|
|
1665
|
+
this.regexp = pathToRegexp.pathToRegexp(path, this.regexpKeys, options);
|
|
1592
1666
|
}
|
|
1593
1667
|
}
|
|
1594
1668
|
|
|
@@ -1596,27 +1670,33 @@ function isPath(input) {
|
|
|
1596
1670
|
return typeof input === 'string' || input instanceof RegExp;
|
|
1597
1671
|
}
|
|
1598
1672
|
|
|
1673
|
+
const LayerSymbol = Symbol.for('Layer');
|
|
1674
|
+
|
|
1599
1675
|
class Layer {
|
|
1600
1676
|
// --------------------------------------------------
|
|
1601
|
-
|
|
1602
|
-
return this.
|
|
1677
|
+
get type() {
|
|
1678
|
+
return this.handler.type;
|
|
1679
|
+
}
|
|
1680
|
+
get path() {
|
|
1681
|
+
return this.handler.path;
|
|
1682
|
+
}
|
|
1683
|
+
get method() {
|
|
1684
|
+
return this.handler.method ? this.handler.method.toLowerCase() : undefined;
|
|
1603
1685
|
}
|
|
1604
1686
|
// --------------------------------------------------
|
|
1605
1687
|
dispatch(event, meta) {
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1688
|
+
if (this.pathMatcher) {
|
|
1689
|
+
const pathMatch = this.pathMatcher.exec(meta.path);
|
|
1690
|
+
if (pathMatch) {
|
|
1691
|
+
meta.params = mergeDispatcherMetaParams(meta.params, pathMatch.params);
|
|
1692
|
+
}
|
|
1611
1693
|
}
|
|
1612
|
-
|
|
1694
|
+
setRequestParams(event.req, meta.params);
|
|
1695
|
+
setRequestMountPath(event.req, meta.mountPath);
|
|
1696
|
+
setRequestRouterPath(event.req, meta.routerPath);
|
|
1613
1697
|
return new Promise((resolve, reject)=>{
|
|
1614
|
-
let timeoutInstance;
|
|
1615
1698
|
let handled = false;
|
|
1616
1699
|
const unsubscribe = ()=>{
|
|
1617
|
-
if (timeoutInstance) {
|
|
1618
|
-
clearTimeout(timeoutInstance);
|
|
1619
|
-
}
|
|
1620
1700
|
event.res.off('close', onFinished);
|
|
1621
1701
|
event.res.off('error', onFinished);
|
|
1622
1702
|
};
|
|
@@ -1636,30 +1716,23 @@ class Layer {
|
|
|
1636
1716
|
const onNext = (err)=>shutdown(false, err);
|
|
1637
1717
|
event.res.once('close', onFinished);
|
|
1638
1718
|
event.res.once('error', onFinished);
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
}
|
|
1719
|
+
const handle = (data)=>{
|
|
1720
|
+
if (typeof data === 'undefined' || handled) {
|
|
1721
|
+
return Promise.resolve();
|
|
1722
|
+
}
|
|
1723
|
+
handled = true;
|
|
1724
|
+
unsubscribe();
|
|
1725
|
+
return this.sendOutput(event.res, data).then(()=>resolve(true)).catch((e)=>reject(createError(e)));
|
|
1726
|
+
};
|
|
1648
1727
|
try {
|
|
1649
1728
|
let output;
|
|
1650
|
-
if (
|
|
1651
|
-
|
|
1729
|
+
if (this.handler.type === exports.HandlerType.ERROR) {
|
|
1730
|
+
if (meta.error) {
|
|
1731
|
+
output = this.handler.fn(meta.error, event.req, event.res, onNext);
|
|
1732
|
+
}
|
|
1652
1733
|
} else {
|
|
1653
|
-
output = this.fn(event.req, event.res, onNext);
|
|
1734
|
+
output = this.handler.fn(event.req, event.res, onNext);
|
|
1654
1735
|
}
|
|
1655
|
-
const handle = (data)=>{
|
|
1656
|
-
if (typeof data === 'undefined' || handled) {
|
|
1657
|
-
return Promise.resolve();
|
|
1658
|
-
}
|
|
1659
|
-
handled = true;
|
|
1660
|
-
unsubscribe();
|
|
1661
|
-
return this.sendOutput(event.res, data).then(()=>resolve(true)).catch((e)=>reject(createError(e)));
|
|
1662
|
-
};
|
|
1663
1736
|
if (isPromise(output)) {
|
|
1664
1737
|
output.then((r)=>handle(r)).catch((e)=>reject(createError(e)));
|
|
1665
1738
|
return;
|
|
@@ -1672,7 +1745,7 @@ class Layer {
|
|
|
1672
1745
|
}
|
|
1673
1746
|
sendOutput(res, input) {
|
|
1674
1747
|
if (input instanceof Error) {
|
|
1675
|
-
return Promise.reject(input);
|
|
1748
|
+
return Promise.reject(createError(input));
|
|
1676
1749
|
}
|
|
1677
1750
|
if (isStream(input)) {
|
|
1678
1751
|
return sendStream(res, input);
|
|
@@ -1687,143 +1760,45 @@ class Layer {
|
|
|
1687
1760
|
}
|
|
1688
1761
|
// --------------------------------------------------
|
|
1689
1762
|
matchPath(path) {
|
|
1763
|
+
if (!this.pathMatcher) {
|
|
1764
|
+
return true;
|
|
1765
|
+
}
|
|
1690
1766
|
return this.pathMatcher.test(path);
|
|
1691
1767
|
}
|
|
1692
|
-
|
|
1693
|
-
|
|
1768
|
+
matchMethod(method) {
|
|
1769
|
+
if (!this.method) {
|
|
1770
|
+
return true;
|
|
1771
|
+
}
|
|
1772
|
+
const name = method.toLowerCase();
|
|
1773
|
+
if (name === this.method) {
|
|
1774
|
+
return true;
|
|
1775
|
+
}
|
|
1776
|
+
return name === exports.MethodName.HEAD && this.method === exports.MethodName.GET;
|
|
1694
1777
|
}
|
|
1695
1778
|
// --------------------------------------------------
|
|
1696
|
-
constructor(
|
|
1697
|
-
this['@instanceof'] =
|
|
1698
|
-
this.
|
|
1699
|
-
|
|
1779
|
+
constructor(handler){
|
|
1780
|
+
this['@instanceof'] = LayerSymbol;
|
|
1781
|
+
this.handler = handler;
|
|
1782
|
+
if (handler.path) {
|
|
1783
|
+
this.pathMatcher = new PathMatcher(handler.path, {
|
|
1784
|
+
end: !!handler.method
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1700
1787
|
}
|
|
1701
1788
|
}
|
|
1702
1789
|
|
|
1703
1790
|
function isLayerInstance(input) {
|
|
1704
|
-
|
|
1705
|
-
return true;
|
|
1706
|
-
}
|
|
1707
|
-
return isInstance(input, 'Layer');
|
|
1791
|
+
return isInstance(input, LayerSymbol);
|
|
1708
1792
|
}
|
|
1709
1793
|
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
matchPath(path) {
|
|
1713
|
-
return this.pathMatcher.test(path);
|
|
1714
|
-
}
|
|
1715
|
-
matchMethod(method) {
|
|
1716
|
-
let name = method.toLowerCase();
|
|
1717
|
-
if (name === exports.MethodName.HEAD && !smob.hasOwnProperty(this.layers, name)) {
|
|
1718
|
-
name = exports.MethodName.GET;
|
|
1719
|
-
}
|
|
1720
|
-
return Object.prototype.hasOwnProperty.call(this.layers, name);
|
|
1721
|
-
}
|
|
1722
|
-
// --------------------------------------------------
|
|
1723
|
-
getMethods() {
|
|
1724
|
-
const keys = Object.keys(this.layers);
|
|
1725
|
-
if (smob.hasOwnProperty(this.layers, exports.MethodName.GET) && !smob.hasOwnProperty(this.layers, exports.MethodName.HEAD)) {
|
|
1726
|
-
keys.push(exports.MethodName.HEAD);
|
|
1727
|
-
}
|
|
1728
|
-
return keys;
|
|
1729
|
-
}
|
|
1730
|
-
// --------------------------------------------------
|
|
1731
|
-
async dispatch(event, meta) {
|
|
1732
|
-
/* istanbul ignore next */ if (!event.req.method) {
|
|
1733
|
-
return false;
|
|
1734
|
-
}
|
|
1735
|
-
let name = event.req.method.toLowerCase();
|
|
1736
|
-
if (name === exports.MethodName.HEAD && !smob.hasOwnProperty(this.layers, name)) {
|
|
1737
|
-
name = exports.MethodName.GET;
|
|
1738
|
-
}
|
|
1739
|
-
const layers = this.layers[name];
|
|
1740
|
-
/* istanbul ignore next */ if (typeof layers === 'undefined' || layers.length === 0 || typeof meta.path === 'undefined') {
|
|
1741
|
-
return false;
|
|
1742
|
-
}
|
|
1743
|
-
const layerMeta = cloneDispatcherMeta(meta);
|
|
1744
|
-
const output = this.pathMatcher.exec(meta.path);
|
|
1745
|
-
if (output) {
|
|
1746
|
-
layerMeta.params = mergeDispatcherMetaParams(layerMeta.params, output.params);
|
|
1747
|
-
}
|
|
1748
|
-
let err;
|
|
1749
|
-
for(let i = 0; i < layers.length; i++){
|
|
1750
|
-
const layer = layers[i];
|
|
1751
|
-
if (err && !layer.isError()) {
|
|
1752
|
-
continue;
|
|
1753
|
-
}
|
|
1754
|
-
try {
|
|
1755
|
-
const dispatched = await layer.dispatch(event, {
|
|
1756
|
-
...layerMeta
|
|
1757
|
-
});
|
|
1758
|
-
if (dispatched) {
|
|
1759
|
-
return true;
|
|
1760
|
-
}
|
|
1761
|
-
} catch (e) {
|
|
1762
|
-
if (e instanceof Error) {
|
|
1763
|
-
err = e;
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
if (err) {
|
|
1768
|
-
throw err;
|
|
1769
|
-
}
|
|
1794
|
+
function isPluginInstallContext(input) {
|
|
1795
|
+
if (!isObject(input) || !isObject(input.options)) {
|
|
1770
1796
|
return false;
|
|
1771
1797
|
}
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
this.layers[method] = [];
|
|
1775
|
-
for(let i = 0; i < handlers.length; i++){
|
|
1776
|
-
const layer = new Layer({
|
|
1777
|
-
path: this.path,
|
|
1778
|
-
pathMatcher: this.pathMatcherOptions
|
|
1779
|
-
}, handlers[i]);
|
|
1780
|
-
this.layers[method].push(layer);
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1783
|
-
get(...handlers) {
|
|
1784
|
-
return this.register(exports.MethodName.GET, ...handlers);
|
|
1785
|
-
}
|
|
1786
|
-
post(...handlers) {
|
|
1787
|
-
return this.register(exports.MethodName.POST, ...handlers);
|
|
1788
|
-
}
|
|
1789
|
-
put(...handlers) {
|
|
1790
|
-
return this.register(exports.MethodName.PUT, ...handlers);
|
|
1791
|
-
}
|
|
1792
|
-
patch(...handlers) {
|
|
1793
|
-
return this.register(exports.MethodName.PATCH, ...handlers);
|
|
1794
|
-
}
|
|
1795
|
-
delete(...handlers) {
|
|
1796
|
-
return this.register(exports.MethodName.DELETE, ...handlers);
|
|
1797
|
-
}
|
|
1798
|
-
head(...handlers) {
|
|
1799
|
-
return this.register(exports.MethodName.HEAD, ...handlers);
|
|
1800
|
-
}
|
|
1801
|
-
options(...handlers) {
|
|
1802
|
-
return this.register(exports.MethodName.OPTIONS, ...handlers);
|
|
1803
|
-
}
|
|
1804
|
-
// --------------------------------------------------
|
|
1805
|
-
isStrictPath() {
|
|
1806
|
-
return typeof this.path !== 'string' || this.path !== '/' && this.path.length !== 0;
|
|
1807
|
-
}
|
|
1808
|
-
// --------------------------------------------------
|
|
1809
|
-
constructor(options){
|
|
1810
|
-
this['@instanceof'] = Symbol.for('Route');
|
|
1811
|
-
this.layers = {};
|
|
1812
|
-
this.path = options.path;
|
|
1813
|
-
this.pathMatcherOptions = {
|
|
1814
|
-
end: true,
|
|
1815
|
-
strict: this.isStrictPath(),
|
|
1816
|
-
...options.pathMatcher
|
|
1817
|
-
};
|
|
1818
|
-
this.pathMatcher = new PathMatcher(this.path, this.pathMatcherOptions);
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
|
|
1822
|
-
function isRouteInstance(input) {
|
|
1823
|
-
if (input instanceof Route) {
|
|
1824
|
-
return true;
|
|
1798
|
+
if (typeof input.name !== 'undefined' && typeof input.name !== 'string') {
|
|
1799
|
+
return false;
|
|
1825
1800
|
}
|
|
1826
|
-
return
|
|
1801
|
+
return typeof input.path === 'undefined' || isPath(input.path);
|
|
1827
1802
|
}
|
|
1828
1803
|
|
|
1829
1804
|
function transformRouterOptions(input) {
|
|
@@ -1836,17 +1811,16 @@ function transformRouterOptions(input) {
|
|
|
1836
1811
|
return input;
|
|
1837
1812
|
}
|
|
1838
1813
|
|
|
1814
|
+
const RouterSymbol = Symbol.for('Router');
|
|
1815
|
+
|
|
1839
1816
|
let nextId = 0;
|
|
1840
1817
|
function generateRouterID() {
|
|
1841
1818
|
return ++nextId;
|
|
1842
1819
|
}
|
|
1843
|
-
|
|
1844
1820
|
function isRouterInstance(input) {
|
|
1845
|
-
|
|
1846
|
-
return true;
|
|
1847
|
-
}
|
|
1848
|
-
return isInstance(input, 'Router');
|
|
1821
|
+
return isInstance(input, RouterSymbol);
|
|
1849
1822
|
}
|
|
1823
|
+
|
|
1850
1824
|
class Router {
|
|
1851
1825
|
// --------------------------------------------------
|
|
1852
1826
|
setPath(value) {
|
|
@@ -1860,9 +1834,7 @@ class Router {
|
|
|
1860
1834
|
path = value;
|
|
1861
1835
|
}
|
|
1862
1836
|
this.pathMatcher = new PathMatcher(path, {
|
|
1863
|
-
end: false
|
|
1864
|
-
sensitive: false,
|
|
1865
|
-
...this.pathMatcherOptions ? this.pathMatcherOptions : {}
|
|
1837
|
+
end: false
|
|
1866
1838
|
});
|
|
1867
1839
|
}
|
|
1868
1840
|
// --------------------------------------------------
|
|
@@ -1873,78 +1845,60 @@ class Router {
|
|
|
1873
1845
|
return true;
|
|
1874
1846
|
}
|
|
1875
1847
|
// --------------------------------------------------
|
|
1876
|
-
async dispatch(event, meta
|
|
1848
|
+
async dispatch(event, meta) {
|
|
1877
1849
|
const allowedMethods = [];
|
|
1878
|
-
let path = meta.path || useRequestPath(event.req);
|
|
1879
1850
|
if (this.pathMatcher) {
|
|
1880
|
-
const output = this.pathMatcher.exec(path);
|
|
1851
|
+
const output = this.pathMatcher.exec(meta.path);
|
|
1881
1852
|
if (typeof output !== 'undefined') {
|
|
1882
|
-
meta.mountPath = cleanDoubleSlashes(`${meta.mountPath
|
|
1883
|
-
if (path === output.path) {
|
|
1884
|
-
path = '/';
|
|
1853
|
+
meta.mountPath = cleanDoubleSlashes(`${meta.mountPath}/${output.path}`);
|
|
1854
|
+
if (meta.path === output.path) {
|
|
1855
|
+
meta.path = '/';
|
|
1885
1856
|
} else {
|
|
1886
|
-
path = withLeadingSlash(path.substring(output.path.length));
|
|
1857
|
+
meta.path = withLeadingSlash(meta.path.substring(output.path.length));
|
|
1887
1858
|
}
|
|
1888
|
-
meta.params =
|
|
1859
|
+
meta.params = {
|
|
1860
|
+
...meta.params,
|
|
1861
|
+
...output.params
|
|
1862
|
+
};
|
|
1889
1863
|
}
|
|
1890
1864
|
}
|
|
1891
|
-
meta.
|
|
1892
|
-
if (meta.routerIds) {
|
|
1893
|
-
meta.routerIds.push(this.id);
|
|
1894
|
-
} else {
|
|
1895
|
-
meta.routerIds = [
|
|
1896
|
-
this.id
|
|
1897
|
-
];
|
|
1898
|
-
}
|
|
1899
|
-
if (!meta.mountPath) {
|
|
1900
|
-
meta.mountPath = '/';
|
|
1901
|
-
}
|
|
1865
|
+
meta.routerPath.push(this.id);
|
|
1902
1866
|
let err;
|
|
1903
|
-
let
|
|
1867
|
+
let item;
|
|
1868
|
+
let itemMeta;
|
|
1904
1869
|
let match = false;
|
|
1905
1870
|
for(let i = 0; i < this.stack.length; i++){
|
|
1906
|
-
|
|
1907
|
-
if (
|
|
1908
|
-
if (
|
|
1871
|
+
item = this.stack[i];
|
|
1872
|
+
if (isLayerInstance(item)) {
|
|
1873
|
+
if (item.type !== exports.HandlerType.ERROR && err) {
|
|
1909
1874
|
continue;
|
|
1910
1875
|
}
|
|
1911
|
-
match =
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
if (event.req.method && !layer.matchMethod(event.req.method)) {
|
|
1919
|
-
match = false;
|
|
1920
|
-
if (event.req.method.toLowerCase() === exports.MethodName.OPTIONS) {
|
|
1921
|
-
allowedMethods.push(...layer.getMethods());
|
|
1876
|
+
match = item.matchPath(meta.path);
|
|
1877
|
+
if (match && event.req.method) {
|
|
1878
|
+
if (!item.matchMethod(event.req.method)) {
|
|
1879
|
+
match = false;
|
|
1880
|
+
}
|
|
1881
|
+
if (item.method) {
|
|
1882
|
+
allowedMethods.push(item.method);
|
|
1922
1883
|
}
|
|
1923
1884
|
}
|
|
1885
|
+
} else if (isRouterInstance(item)) {
|
|
1886
|
+
match = item.matchPath(meta.path);
|
|
1924
1887
|
}
|
|
1925
1888
|
if (!match) {
|
|
1926
1889
|
continue;
|
|
1927
1890
|
}
|
|
1928
|
-
|
|
1929
|
-
if (
|
|
1930
|
-
|
|
1931
|
-
if (output) {
|
|
1932
|
-
layerMeta.params = mergeDispatcherMetaParams(layerMeta.params, output.params);
|
|
1933
|
-
layerMeta.mountPath = cleanDoubleSlashes(`${layerMeta.mountPath || ''}/${output.path}`);
|
|
1934
|
-
}
|
|
1935
|
-
if (err) {
|
|
1936
|
-
layerMeta.error = err;
|
|
1937
|
-
}
|
|
1938
|
-
} else if (err) {
|
|
1939
|
-
continue;
|
|
1891
|
+
itemMeta = cloneDispatcherMeta(meta);
|
|
1892
|
+
if (err) {
|
|
1893
|
+
itemMeta.error = err;
|
|
1940
1894
|
}
|
|
1941
1895
|
try {
|
|
1942
|
-
const dispatched = await
|
|
1896
|
+
const dispatched = await item.dispatch(event, itemMeta);
|
|
1943
1897
|
if (dispatched) {
|
|
1944
1898
|
return true;
|
|
1945
1899
|
}
|
|
1946
1900
|
} catch (e) {
|
|
1947
|
-
if (e
|
|
1901
|
+
if (isError(e)) {
|
|
1948
1902
|
err = e;
|
|
1949
1903
|
}
|
|
1950
1904
|
}
|
|
@@ -1953,7 +1907,11 @@ class Router {
|
|
|
1953
1907
|
throw err;
|
|
1954
1908
|
}
|
|
1955
1909
|
if (event.req.method && event.req.method.toLowerCase() === exports.MethodName.OPTIONS) {
|
|
1956
|
-
|
|
1910
|
+
if (allowedMethods.indexOf(exports.MethodName.GET) !== -1) {
|
|
1911
|
+
allowedMethods.push(exports.MethodName.HEAD);
|
|
1912
|
+
}
|
|
1913
|
+
smob.distinctArray(allowedMethods);
|
|
1914
|
+
const options = allowedMethods.map((key)=>key.toUpperCase()).join(',');
|
|
1957
1915
|
if (!isResponseGone(event.res)) {
|
|
1958
1916
|
event.res.setHeader(exports.HeaderName.ALLOW, options);
|
|
1959
1917
|
await send(event.res, options);
|
|
@@ -1962,71 +1920,128 @@ class Router {
|
|
|
1962
1920
|
}
|
|
1963
1921
|
return false;
|
|
1964
1922
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1923
|
+
delete(path, handler) {
|
|
1924
|
+
if (isPath(path)) {
|
|
1925
|
+
this.use({
|
|
1926
|
+
...handler,
|
|
1927
|
+
method: exports.MethodName.DELETE,
|
|
1928
|
+
path
|
|
1929
|
+
});
|
|
1930
|
+
return this;
|
|
1969
1931
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
}
|
|
1974
|
-
const route = new Route({
|
|
1975
|
-
path,
|
|
1976
|
-
pathMatcher: {
|
|
1977
|
-
...this.pathMatcherOptions ? {
|
|
1978
|
-
sensitive: this.pathMatcherOptions.sensitive
|
|
1979
|
-
} : {}
|
|
1980
|
-
}
|
|
1932
|
+
this.use({
|
|
1933
|
+
...path,
|
|
1934
|
+
method: exports.MethodName.DELETE
|
|
1981
1935
|
});
|
|
1982
|
-
this.stack.push(route);
|
|
1983
|
-
return route;
|
|
1984
|
-
}
|
|
1985
|
-
delete(path, ...handlers) {
|
|
1986
|
-
const route = this.route(path);
|
|
1987
|
-
route.delete(...handlers);
|
|
1988
1936
|
return this;
|
|
1989
1937
|
}
|
|
1990
|
-
get(path,
|
|
1991
|
-
|
|
1992
|
-
|
|
1938
|
+
get(path, handler) {
|
|
1939
|
+
if (isPath(path)) {
|
|
1940
|
+
this.use({
|
|
1941
|
+
...handler,
|
|
1942
|
+
method: exports.MethodName.GET,
|
|
1943
|
+
path
|
|
1944
|
+
});
|
|
1945
|
+
return this;
|
|
1946
|
+
}
|
|
1947
|
+
this.use({
|
|
1948
|
+
...path,
|
|
1949
|
+
method: exports.MethodName.GET
|
|
1950
|
+
});
|
|
1993
1951
|
return this;
|
|
1994
1952
|
}
|
|
1995
|
-
post(path,
|
|
1996
|
-
|
|
1997
|
-
|
|
1953
|
+
post(path, handler) {
|
|
1954
|
+
if (isPath(path)) {
|
|
1955
|
+
this.use({
|
|
1956
|
+
...handler,
|
|
1957
|
+
method: exports.MethodName.POST,
|
|
1958
|
+
path
|
|
1959
|
+
});
|
|
1960
|
+
return this;
|
|
1961
|
+
}
|
|
1962
|
+
this.use({
|
|
1963
|
+
...path,
|
|
1964
|
+
method: exports.MethodName.POST
|
|
1965
|
+
});
|
|
1998
1966
|
return this;
|
|
1999
1967
|
}
|
|
2000
|
-
put(path,
|
|
2001
|
-
|
|
2002
|
-
|
|
1968
|
+
put(path, handler) {
|
|
1969
|
+
if (isPath(path)) {
|
|
1970
|
+
this.use({
|
|
1971
|
+
...handler,
|
|
1972
|
+
method: exports.MethodName.PUT,
|
|
1973
|
+
path
|
|
1974
|
+
});
|
|
1975
|
+
return this;
|
|
1976
|
+
}
|
|
1977
|
+
this.use({
|
|
1978
|
+
...path,
|
|
1979
|
+
method: exports.MethodName.PUT
|
|
1980
|
+
});
|
|
2003
1981
|
return this;
|
|
2004
1982
|
}
|
|
2005
|
-
patch(path,
|
|
2006
|
-
|
|
2007
|
-
|
|
1983
|
+
patch(path, handler) {
|
|
1984
|
+
if (isPath(path)) {
|
|
1985
|
+
this.use({
|
|
1986
|
+
...handler,
|
|
1987
|
+
method: exports.MethodName.PATCH,
|
|
1988
|
+
path
|
|
1989
|
+
});
|
|
1990
|
+
return this;
|
|
1991
|
+
}
|
|
1992
|
+
this.use({
|
|
1993
|
+
...path,
|
|
1994
|
+
method: exports.MethodName.PATCH
|
|
1995
|
+
});
|
|
2008
1996
|
return this;
|
|
2009
1997
|
}
|
|
2010
|
-
head(path,
|
|
2011
|
-
|
|
2012
|
-
|
|
1998
|
+
head(path, handler) {
|
|
1999
|
+
if (isPath(path)) {
|
|
2000
|
+
this.use({
|
|
2001
|
+
...handler,
|
|
2002
|
+
method: exports.MethodName.HEAD,
|
|
2003
|
+
path
|
|
2004
|
+
});
|
|
2005
|
+
return this;
|
|
2006
|
+
}
|
|
2007
|
+
this.use({
|
|
2008
|
+
...path,
|
|
2009
|
+
method: exports.MethodName.HEAD
|
|
2010
|
+
});
|
|
2013
2011
|
return this;
|
|
2014
2012
|
}
|
|
2015
|
-
options(path,
|
|
2016
|
-
|
|
2017
|
-
|
|
2013
|
+
options(path, handler) {
|
|
2014
|
+
if (isPath(path)) {
|
|
2015
|
+
this.use({
|
|
2016
|
+
...handler,
|
|
2017
|
+
method: exports.MethodName.OPTIONS,
|
|
2018
|
+
path
|
|
2019
|
+
});
|
|
2020
|
+
return this;
|
|
2021
|
+
}
|
|
2022
|
+
this.use({
|
|
2023
|
+
...path,
|
|
2024
|
+
method: exports.MethodName.OPTIONS
|
|
2025
|
+
});
|
|
2018
2026
|
return this;
|
|
2019
2027
|
}
|
|
2020
2028
|
use(...input) {
|
|
2021
2029
|
/* istanbul ignore next */ if (input.length === 0) {
|
|
2022
2030
|
return this;
|
|
2023
2031
|
}
|
|
2032
|
+
const modifyPath = (input)=>{
|
|
2033
|
+
if (typeof input === 'string') {
|
|
2034
|
+
return withLeadingSlash(input);
|
|
2035
|
+
}
|
|
2036
|
+
return input;
|
|
2037
|
+
};
|
|
2024
2038
|
let path;
|
|
2025
|
-
if (isPath(input[0])) {
|
|
2026
|
-
path = input.shift();
|
|
2027
|
-
}
|
|
2028
2039
|
for(let i = 0; i < input.length; i++){
|
|
2029
2040
|
const item = input[i];
|
|
2041
|
+
if (isPath(item)) {
|
|
2042
|
+
path = modifyPath(item);
|
|
2043
|
+
continue;
|
|
2044
|
+
}
|
|
2030
2045
|
if (isRouterInstance(item)) {
|
|
2031
2046
|
if (path) {
|
|
2032
2047
|
item.setPath(path);
|
|
@@ -2034,44 +2049,63 @@ class Router {
|
|
|
2034
2049
|
this.stack.push(item);
|
|
2035
2050
|
continue;
|
|
2036
2051
|
}
|
|
2037
|
-
if (
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
pathMatcher: {
|
|
2041
|
-
strict: false,
|
|
2042
|
-
end: false,
|
|
2043
|
-
...this.pathMatcherOptions ? {
|
|
2044
|
-
sensitive: this.pathMatcherOptions.sensitive
|
|
2045
|
-
} : {}
|
|
2046
|
-
}
|
|
2047
|
-
}, item));
|
|
2052
|
+
if (isHandler(item)) {
|
|
2053
|
+
item.path = path || modifyPath(item.path);
|
|
2054
|
+
this.stack.push(new Layer(item));
|
|
2048
2055
|
}
|
|
2049
2056
|
}
|
|
2050
2057
|
return this;
|
|
2051
2058
|
}
|
|
2052
2059
|
// --------------------------------------------------
|
|
2060
|
+
install(plugin, context) {
|
|
2061
|
+
if (isPluginInstallContext(context)) {
|
|
2062
|
+
const name = context.name || plugin.name;
|
|
2063
|
+
if (context.path) {
|
|
2064
|
+
const router = new Router({
|
|
2065
|
+
name
|
|
2066
|
+
});
|
|
2067
|
+
plugin.install(router, context.options);
|
|
2068
|
+
this.use(context.path, router);
|
|
2069
|
+
return this;
|
|
2070
|
+
}
|
|
2071
|
+
plugin.install(this, context.options);
|
|
2072
|
+
return this;
|
|
2073
|
+
}
|
|
2074
|
+
plugin.install(this, context);
|
|
2075
|
+
return this;
|
|
2076
|
+
}
|
|
2077
|
+
uninstall(name) {
|
|
2078
|
+
const index = this.stack.findIndex((el)=>isRouterInstance(el) && el.name === name);
|
|
2079
|
+
if (index !== -1) {
|
|
2080
|
+
this.stack.splice(index, 1);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
// --------------------------------------------------
|
|
2053
2084
|
constructor(options = {}){
|
|
2054
|
-
this['@instanceof'] =
|
|
2085
|
+
this['@instanceof'] = RouterSymbol;
|
|
2055
2086
|
/**
|
|
2056
2087
|
* Array of mounted layers, routes & routers.
|
|
2057
2088
|
*
|
|
2058
2089
|
* @protected
|
|
2059
2090
|
*/ this.stack = [];
|
|
2060
2091
|
this.id = generateRouterID();
|
|
2061
|
-
this.
|
|
2092
|
+
this.name = options.name;
|
|
2062
2093
|
this.setPath(options.path);
|
|
2063
2094
|
setRouterOptions(this.id, transformRouterOptions(options));
|
|
2064
2095
|
}
|
|
2065
2096
|
}
|
|
2066
2097
|
|
|
2098
|
+
exports.ErrorProxy = ErrorProxy;
|
|
2067
2099
|
exports.Layer = Layer;
|
|
2068
2100
|
exports.PathMatcher = PathMatcher;
|
|
2069
|
-
exports.Route = Route;
|
|
2070
2101
|
exports.Router = Router;
|
|
2071
2102
|
exports.appendResponseHeader = appendResponseHeader;
|
|
2072
2103
|
exports.appendResponseHeaderDirective = appendResponseHeaderDirective;
|
|
2104
|
+
exports.buildDispatcherMeta = buildDispatcherMeta;
|
|
2073
2105
|
exports.cloneDispatcherMeta = cloneDispatcherMeta;
|
|
2074
2106
|
exports.cloneDispatcherMetaParams = cloneDispatcherMetaParams;
|
|
2107
|
+
exports.coreHandler = coreHandler;
|
|
2108
|
+
exports.createError = createError;
|
|
2075
2109
|
exports.createNodeDispatcher = createNodeDispatcher;
|
|
2076
2110
|
exports.createRawDispatcher = createRawDispatcher;
|
|
2077
2111
|
exports.createRequest = createRequest;
|
|
@@ -2080,6 +2114,7 @@ exports.createWebDispatcher = createWebDispatcher;
|
|
|
2080
2114
|
exports.dispatchNodeRequest = dispatchNodeRequest;
|
|
2081
2115
|
exports.dispatchRawRequest = dispatchRawRequest;
|
|
2082
2116
|
exports.dispatchWebRequest = dispatchWebRequest;
|
|
2117
|
+
exports.errorHandler = errorHandler;
|
|
2083
2118
|
exports.extendRequestBody = extendRequestBody;
|
|
2084
2119
|
exports.extendRequestCookies = extendRequestCookies;
|
|
2085
2120
|
exports.extendRequestQuery = extendRequestQuery;
|
|
@@ -2098,11 +2133,13 @@ exports.getRequestProtocol = getRequestProtocol;
|
|
|
2098
2133
|
exports.hasRequestBody = hasRequestBody;
|
|
2099
2134
|
exports.hasRequestCookies = hasRequestCookies;
|
|
2100
2135
|
exports.hasRequestQuery = hasRequestQuery;
|
|
2136
|
+
exports.isError = isError;
|
|
2137
|
+
exports.isHandler = isHandler;
|
|
2101
2138
|
exports.isLayerInstance = isLayerInstance;
|
|
2102
2139
|
exports.isPath = isPath;
|
|
2140
|
+
exports.isPluginInstallContext = isPluginInstallContext;
|
|
2103
2141
|
exports.isRequestCacheable = isRequestCacheable;
|
|
2104
2142
|
exports.isResponseGone = isResponseGone;
|
|
2105
|
-
exports.isRouteInstance = isRouteInstance;
|
|
2106
2143
|
exports.isRouterInstance = isRouterInstance;
|
|
2107
2144
|
exports.matchRequestContentType = matchRequestContentType;
|
|
2108
2145
|
exports.mergeDispatcherMetaParams = mergeDispatcherMetaParams;
|
|
@@ -2123,7 +2160,7 @@ exports.setRequestMountPath = setRequestMountPath;
|
|
|
2123
2160
|
exports.setRequestParam = setRequestParam;
|
|
2124
2161
|
exports.setRequestParams = setRequestParams;
|
|
2125
2162
|
exports.setRequestQuery = setRequestQuery;
|
|
2126
|
-
exports.
|
|
2163
|
+
exports.setRequestRouterPath = setRequestRouterPath;
|
|
2127
2164
|
exports.setResponseCacheHeaders = setResponseCacheHeaders;
|
|
2128
2165
|
exports.setResponseContentTypeByFileName = setResponseContentTypeByFileName;
|
|
2129
2166
|
exports.setResponseHeaderAttachment = setResponseHeaderAttachment;
|
|
@@ -2139,5 +2176,5 @@ exports.useRequestParam = useRequestParam;
|
|
|
2139
2176
|
exports.useRequestParams = useRequestParams;
|
|
2140
2177
|
exports.useRequestPath = useRequestPath;
|
|
2141
2178
|
exports.useRequestQuery = useRequestQuery;
|
|
2142
|
-
exports.
|
|
2179
|
+
exports.useRequestRouterPath = useRequestRouterPath;
|
|
2143
2180
|
//# sourceMappingURL=index.cjs.map
|