routup 1.0.3 → 2.0.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 +92 -8
- package/dist/dispatcher/adapters/index.d.ts +3 -0
- package/dist/dispatcher/adapters/node/index.d.ts +1 -0
- package/dist/dispatcher/adapters/node/module.d.ts +6 -0
- package/dist/dispatcher/adapters/raw/module.d.ts +4 -0
- package/dist/dispatcher/adapters/raw/type.d.ts +18 -0
- package/dist/dispatcher/adapters/web/index.d.ts +2 -0
- package/dist/dispatcher/adapters/web/module.d.ts +5 -0
- package/dist/dispatcher/adapters/web/type.d.ts +3 -0
- package/dist/dispatcher/index.d.ts +3 -0
- package/dist/dispatcher/type.d.ts +30 -0
- package/dist/dispatcher/utils.d.ts +4 -0
- package/dist/error.d.ts +1 -0
- package/dist/index.cjs +1073 -537
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.mjs +1050 -506
- package/dist/index.mjs.map +1 -1
- package/dist/layer/module.d.ts +5 -4
- package/dist/layer/type.d.ts +1 -2
- package/dist/layer/utils.d.ts +1 -1
- package/dist/path/index.d.ts +1 -0
- package/dist/path/matcher.d.ts +1 -2
- package/dist/path/type.d.ts +1 -0
- package/dist/path/utils.d.ts +2 -0
- package/dist/{helpers/request → request/helpers}/body.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/cache.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/cookie.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/env.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/header-accept-charset.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/header-accept-language.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/header-accept.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/header-content-type.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/header.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/hostname.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/index.d.ts +1 -0
- package/dist/{helpers/request → request/helpers}/ip.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/mount-path.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/negotiator.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/params.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/path.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/protocol.d.ts +1 -1
- package/dist/{helpers/request → request/helpers}/query.d.ts +1 -1
- package/dist/request/helpers/router.d.ts +3 -0
- package/dist/request/index.d.ts +3 -0
- package/dist/request/module.d.ts +4 -0
- package/dist/request/types.d.ts +9 -0
- package/dist/{helpers/response → response/helpers}/cache.d.ts +1 -1
- package/dist/response/helpers/gone.d.ts +2 -0
- package/dist/{helpers/response → response/helpers}/header-attachment.d.ts +1 -1
- package/dist/{helpers/response → response/helpers}/header-content-type.d.ts +1 -1
- package/dist/{helpers/response → response/helpers}/header.d.ts +1 -1
- package/dist/{helpers/response → response/helpers}/index.d.ts +3 -0
- package/dist/{helpers/response → response/helpers}/send-accepted.d.ts +2 -2
- package/dist/{helpers/response → response/helpers}/send-created.d.ts +2 -2
- package/dist/response/helpers/send-file.d.ts +17 -0
- package/dist/{helpers/response → response/helpers}/send-format.d.ts +1 -1
- package/dist/response/helpers/send-redirect.d.ts +2 -0
- package/dist/response/helpers/send-stream.d.ts +2 -0
- package/dist/response/helpers/send-web-blob.d.ts +2 -0
- package/dist/response/helpers/send-web-response.d.ts +2 -0
- package/dist/response/helpers/send.d.ts +2 -0
- package/dist/response/helpers/utils.d.ts +2 -0
- package/dist/response/index.d.ts +2 -0
- package/dist/response/module.d.ts +2 -0
- package/dist/route/module.d.ts +6 -5
- package/dist/route/type.d.ts +1 -1
- package/dist/route/utils.d.ts +1 -1
- package/dist/router/index.d.ts +0 -1
- package/dist/router/module.d.ts +13 -32
- package/dist/router/utils.d.ts +1 -0
- package/dist/router-options/index.d.ts +2 -0
- package/dist/router-options/module.d.ts +4 -0
- package/dist/router-options/transform.d.ts +2 -0
- package/dist/router-options/type.d.ts +50 -0
- package/dist/types.d.ts +19 -0
- package/dist/utils/cookie.d.ts +1 -0
- package/dist/utils/etag/module.d.ts +4 -3
- package/dist/utils/etag/type.d.ts +1 -1
- package/dist/utils/header.d.ts +3 -0
- package/dist/utils/index.d.ts +4 -1
- package/dist/utils/path.d.ts +5 -2
- package/dist/utils/stream.d.ts +8 -0
- package/dist/utils/web.d.ts +3 -0
- package/package.json +13 -12
- package/dist/config/module.d.ts +0 -8
- package/dist/config/type.d.ts +0 -34
- package/dist/handler/index.d.ts +0 -1
- package/dist/handler/utils.d.ts +0 -2
- package/dist/helpers/index.d.ts +0 -2
- package/dist/helpers/response/send-file.d.ts +0 -9
- package/dist/helpers/response/send-redirect.d.ts +0 -2
- package/dist/helpers/response/send-stream.d.ts +0 -4
- package/dist/helpers/response/send.d.ts +0 -2
- package/dist/helpers/response/utils.d.ts +0 -3
- package/dist/router/type.d.ts +0 -24
- package/dist/type.d.ts +0 -24
- package/dist/utils/request.d.ts +0 -2
- /package/dist/{config → dispatcher/adapters/raw}/index.d.ts +0 -0
- /package/dist/{helpers/request → request/helpers}/header-accept-encoding.d.ts +0 -0
package/dist/index.cjs
CHANGED
|
@@ -1,19 +1,233 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var zod = require('zod');
|
|
6
|
-
var crypto = require('node:crypto');
|
|
7
|
-
var node_fs = require('node:fs');
|
|
3
|
+
var buffer = require('buffer');
|
|
4
|
+
var uncrypto = require('uncrypto');
|
|
8
5
|
var smob = require('smob');
|
|
9
6
|
var proxyAddr = require('proxy-addr');
|
|
10
7
|
var mimeExplorer = require('mime-explorer');
|
|
11
|
-
var http = require('@ebec/http');
|
|
12
8
|
var Negotiator = require('negotiator');
|
|
13
|
-
var
|
|
14
|
-
var path = require('node:path');
|
|
9
|
+
var readableStream = require('readable-stream');
|
|
15
10
|
var pathToRegexp = require('path-to-regexp');
|
|
16
|
-
|
|
11
|
+
|
|
12
|
+
exports.MethodName = void 0;
|
|
13
|
+
(function(MethodName) {
|
|
14
|
+
MethodName["GET"] = 'get';
|
|
15
|
+
MethodName["POST"] = 'post';
|
|
16
|
+
MethodName["PUT"] = 'put';
|
|
17
|
+
MethodName["PATCH"] = 'patch';
|
|
18
|
+
MethodName["DELETE"] = 'delete';
|
|
19
|
+
MethodName["OPTIONS"] = 'options';
|
|
20
|
+
MethodName["HEAD"] = 'head';
|
|
21
|
+
})(exports.MethodName || (exports.MethodName = {}));
|
|
22
|
+
exports.HeaderName = void 0;
|
|
23
|
+
(function(HeaderName) {
|
|
24
|
+
HeaderName["ACCEPT"] = 'accept';
|
|
25
|
+
HeaderName["ACCEPT_CHARSET"] = 'accept-charset';
|
|
26
|
+
HeaderName["ACCEPT_ENCODING"] = 'accept-encoding';
|
|
27
|
+
HeaderName["ACCEPT_LANGUAGE"] = 'accept-language';
|
|
28
|
+
HeaderName["ACCEPT_RANGES"] = 'accept-ranges';
|
|
29
|
+
HeaderName["ALLOW"] = 'allow';
|
|
30
|
+
HeaderName["CACHE_CONTROL"] = 'cache-control';
|
|
31
|
+
HeaderName["CONTENT_DISPOSITION"] = 'content-disposition';
|
|
32
|
+
HeaderName["CONTENT_ENCODING"] = 'content-encoding';
|
|
33
|
+
HeaderName["CONTENT_LENGTH"] = 'content-length';
|
|
34
|
+
HeaderName["CONTENT_RANGE"] = 'content-range';
|
|
35
|
+
HeaderName["CONTENT_TYPE"] = 'content-type';
|
|
36
|
+
HeaderName["COOKIE"] = 'cookie';
|
|
37
|
+
HeaderName["ETag"] = 'etag';
|
|
38
|
+
HeaderName["HOST"] = 'host';
|
|
39
|
+
HeaderName["IF_MODIFIED_SINCE"] = 'if-modified-since';
|
|
40
|
+
HeaderName["IF_NONE_MATCH"] = 'if-none-match';
|
|
41
|
+
HeaderName["LAST_MODIFIED"] = 'last-modified';
|
|
42
|
+
HeaderName["LOCATION"] = 'location';
|
|
43
|
+
HeaderName["RANGE"] = 'range';
|
|
44
|
+
HeaderName["RATE_LIMIT_LIMIT"] = 'ratelimit-limit';
|
|
45
|
+
HeaderName["RATE_LIMIT_REMAINING"] = 'ratelimit-remaining';
|
|
46
|
+
HeaderName["RATE_LIMIT_RESET"] = 'ratelimit-reset';
|
|
47
|
+
HeaderName["RETRY_AFTER"] = 'retry-after';
|
|
48
|
+
HeaderName["SET_COOKIE"] = 'set-cookie';
|
|
49
|
+
HeaderName["TRANSFER_ENCODING"] = 'transfer-encoding';
|
|
50
|
+
HeaderName["X_FORWARDED_HOST"] = 'x-forwarded-host';
|
|
51
|
+
HeaderName["X_FORWARDED_FOR"] = 'x-forwarded-for';
|
|
52
|
+
HeaderName["X_FORWARDED_PROTO"] = 'x-forwarded-proto';
|
|
53
|
+
})(exports.HeaderName || (exports.HeaderName = {}));
|
|
54
|
+
|
|
55
|
+
function setResponseCacheHeaders(res, options) {
|
|
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(', '));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const GoneSymbol = Symbol.for('ResGone');
|
|
71
|
+
function isResponseGone(res) {
|
|
72
|
+
if (res.headersSent || res.writableEnded) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
if (GoneSymbol in res) {
|
|
76
|
+
return res[GoneSymbol];
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function appendResponseHeader(res, name, value) {
|
|
82
|
+
let header = res.getHeader(name);
|
|
83
|
+
if (!header) {
|
|
84
|
+
res.setHeader(name, value);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (!Array.isArray(header)) {
|
|
88
|
+
header = [
|
|
89
|
+
header.toString()
|
|
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
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (Array.isArray(value)) {
|
|
119
|
+
header.push(...value);
|
|
120
|
+
} else {
|
|
121
|
+
header.push(`${value}`);
|
|
122
|
+
}
|
|
123
|
+
header = [
|
|
124
|
+
...new Set(header)
|
|
125
|
+
];
|
|
126
|
+
res.setHeader(name, header.join('; '));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/*
|
|
130
|
+
Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas
|
|
131
|
+
that are within a single set-cookie field-value, such as in the Expires portion.
|
|
132
|
+
|
|
133
|
+
This is uncommon, but explicitly allowed - see https://tools.ietf.org/html/rfc2616#section-4.2
|
|
134
|
+
Node.js does this for every header *except* set-cookie - see https://github.com/nodejs/node/blob/d5e363b77ebaf1caf67cd7528224b651c86815c1/lib/_http_incoming.js#L128
|
|
135
|
+
React Native's fetch does this for *every* header, including set-cookie.
|
|
136
|
+
|
|
137
|
+
Based on: https://github.com/google/j2objc/commit/16820fdbc8f76ca0c33472810ce0cb03d20efe25
|
|
138
|
+
Credits to: https://github.com/tomball for original and https://github.com/chrusart for JavaScript implementation
|
|
139
|
+
*/ function splitCookiesString(input) {
|
|
140
|
+
if (Array.isArray(input)) {
|
|
141
|
+
return input.flatMap((el)=>splitCookiesString(el));
|
|
142
|
+
}
|
|
143
|
+
if (typeof input !== 'string') {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
const cookiesStrings = [];
|
|
147
|
+
let pos = 0;
|
|
148
|
+
let start;
|
|
149
|
+
let ch;
|
|
150
|
+
let lastComma;
|
|
151
|
+
let nextStart;
|
|
152
|
+
let cookiesSeparatorFound;
|
|
153
|
+
const skipWhitespace = ()=>{
|
|
154
|
+
while(pos < input.length && /\s/.test(input.charAt(pos))){
|
|
155
|
+
pos += 1;
|
|
156
|
+
}
|
|
157
|
+
return pos < input.length;
|
|
158
|
+
};
|
|
159
|
+
const notSpecialChar = ()=>{
|
|
160
|
+
ch = input.charAt(pos);
|
|
161
|
+
return ch !== '=' && ch !== ';' && ch !== ',';
|
|
162
|
+
};
|
|
163
|
+
while(pos < input.length){
|
|
164
|
+
start = pos;
|
|
165
|
+
cookiesSeparatorFound = false;
|
|
166
|
+
while(skipWhitespace()){
|
|
167
|
+
ch = input.charAt(pos);
|
|
168
|
+
if (ch === ',') {
|
|
169
|
+
// ',' is a cookie separator if we have later first '=', not ';' or ','
|
|
170
|
+
lastComma = pos;
|
|
171
|
+
pos += 1;
|
|
172
|
+
skipWhitespace();
|
|
173
|
+
nextStart = pos;
|
|
174
|
+
while(pos < input.length && notSpecialChar()){
|
|
175
|
+
pos += 1;
|
|
176
|
+
}
|
|
177
|
+
// currently special character
|
|
178
|
+
if (pos < input.length && input.charAt(pos) === '=') {
|
|
179
|
+
// we found cookies separator
|
|
180
|
+
cookiesSeparatorFound = true;
|
|
181
|
+
// pos is inside the next cookie, so back up and return it.
|
|
182
|
+
pos = nextStart;
|
|
183
|
+
cookiesStrings.push(input.substring(start, lastComma));
|
|
184
|
+
start = pos;
|
|
185
|
+
} else {
|
|
186
|
+
// in param ',' or param separator ';',
|
|
187
|
+
// we continue from that comma
|
|
188
|
+
pos = lastComma + 1;
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
pos += 1;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (!cookiesSeparatorFound || pos >= input.length) {
|
|
195
|
+
cookiesStrings.push(input.substring(start, input.length));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return cookiesStrings;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function transformHeaderToTuples(key, value) {
|
|
202
|
+
const output = [];
|
|
203
|
+
if (Array.isArray(value)) {
|
|
204
|
+
for(let j = 0; j < value.length; j++){
|
|
205
|
+
output.push([
|
|
206
|
+
key,
|
|
207
|
+
value[j]
|
|
208
|
+
]);
|
|
209
|
+
}
|
|
210
|
+
} else if (value !== undefined) {
|
|
211
|
+
output.push([
|
|
212
|
+
key,
|
|
213
|
+
String(value)
|
|
214
|
+
]);
|
|
215
|
+
}
|
|
216
|
+
return output;
|
|
217
|
+
}
|
|
218
|
+
function transformHeadersToTuples(input) {
|
|
219
|
+
const output = [];
|
|
220
|
+
const keys = Object.keys(input);
|
|
221
|
+
for(let i = 0; i < keys.length; i++){
|
|
222
|
+
const key = keys[i].toLowerCase();
|
|
223
|
+
output.push(...transformHeaderToTuples(key, input[key]));
|
|
224
|
+
}
|
|
225
|
+
return output;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function isObject(item) {
|
|
229
|
+
return !!item && typeof item === 'object' && !Array.isArray(item);
|
|
230
|
+
}
|
|
17
231
|
|
|
18
232
|
/**
|
|
19
233
|
* Determine if object is a Stats object.
|
|
@@ -22,15 +236,17 @@ var node_http = require('node:http');
|
|
|
22
236
|
* @return {boolean}
|
|
23
237
|
* @api private
|
|
24
238
|
*/ function isStatsObject(obj) {
|
|
25
|
-
/* istanbul ignore next */ if (typeof node_fs.Stats === 'function' && obj instanceof node_fs.Stats) {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
239
|
// quack quack
|
|
29
|
-
return
|
|
240
|
+
return isObject(obj) && 'ctime' in obj && Object.prototype.toString.call(obj.ctime) === '[object Date]' && 'mtime' in obj && Object.prototype.toString.call(obj.mtime) === '[object Date]' && 'ino' in obj && typeof obj.ino === 'number' && 'size' in obj && typeof obj.size === 'number';
|
|
241
|
+
}
|
|
242
|
+
async function sha1(str) {
|
|
243
|
+
const enc = new TextEncoder();
|
|
244
|
+
const hash = await uncrypto.subtle.digest('SHA-1', enc.encode(str));
|
|
245
|
+
return btoa(String.fromCharCode(...new Uint8Array(hash)));
|
|
30
246
|
}
|
|
31
247
|
/**
|
|
32
248
|
* Generate an ETag.
|
|
33
|
-
*/ function generateETag(input) {
|
|
249
|
+
*/ async function generateETag(input) {
|
|
34
250
|
if (isStatsObject(input)) {
|
|
35
251
|
const mtime = input.mtime.getTime().toString(16);
|
|
36
252
|
const size = input.size.toString(16);
|
|
@@ -40,32 +256,28 @@ var node_http = require('node:http');
|
|
|
40
256
|
// fast-path empty
|
|
41
257
|
return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
|
|
42
258
|
}
|
|
43
|
-
const entity = Buffer.isBuffer(input) ? input.toString('utf-8') : input;
|
|
259
|
+
const entity = buffer.Buffer.isBuffer(input) ? input.toString('utf-8') : input;
|
|
44
260
|
// compute hash of entity
|
|
45
|
-
const hash =
|
|
46
|
-
return `"${entity.length.toString(16)}-${hash}"`;
|
|
261
|
+
const hash = await sha1(entity);
|
|
262
|
+
return `"${entity.length.toString(16)}-${hash.substring(0, 27)}"`;
|
|
47
263
|
}
|
|
48
264
|
/**
|
|
49
265
|
* Create a simple ETag.
|
|
50
|
-
*/ function createEtag(input, options) {
|
|
266
|
+
*/ async function createEtag(input, options) {
|
|
51
267
|
options = options || {};
|
|
52
268
|
const weak = typeof options.weak === 'boolean' ? options.weak : isStatsObject(input);
|
|
53
269
|
// generate entity tag
|
|
54
|
-
const tag = generateETag(input);
|
|
270
|
+
const tag = await generateETag(input);
|
|
55
271
|
return weak ? `W/${tag}` : tag;
|
|
56
272
|
}
|
|
57
273
|
|
|
58
|
-
function isObject(item) {
|
|
59
|
-
return !!item && typeof item === 'object' && !Array.isArray(item);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
274
|
function buildEtagFn(input) {
|
|
63
275
|
if (typeof input === 'function') {
|
|
64
276
|
return input;
|
|
65
277
|
}
|
|
66
278
|
input = input ?? true;
|
|
67
279
|
if (input === false) {
|
|
68
|
-
return ()=>undefined;
|
|
280
|
+
return ()=>Promise.resolve(undefined);
|
|
69
281
|
}
|
|
70
282
|
let options = {
|
|
71
283
|
weak: true
|
|
@@ -73,10 +285,10 @@ function buildEtagFn(input) {
|
|
|
73
285
|
if (isObject(input)) {
|
|
74
286
|
options = smob.merge(input, options);
|
|
75
287
|
}
|
|
76
|
-
return (body, encoding, size)=>{
|
|
77
|
-
const buff = Buffer.isBuffer(body) ? body : Buffer.from(body, encoding);
|
|
288
|
+
return async (body, encoding, size)=>{
|
|
289
|
+
const buff = buffer.Buffer.isBuffer(body) ? body : buffer.Buffer.from(body, encoding);
|
|
78
290
|
if (typeof options.threshold !== 'undefined') {
|
|
79
|
-
size = size ?? Buffer.byteLength(buff);
|
|
291
|
+
size = size ?? buffer.Buffer.byteLength(buff);
|
|
80
292
|
if (size <= options.threshold) {
|
|
81
293
|
return undefined;
|
|
82
294
|
}
|
|
@@ -102,7 +314,7 @@ function buildTrustProxyFn(input) {
|
|
|
102
314
|
}
|
|
103
315
|
|
|
104
316
|
function isInstance(input, name) {
|
|
105
|
-
return
|
|
317
|
+
return isObject(input) && input['@instanceof'] === Symbol.for(name);
|
|
106
318
|
}
|
|
107
319
|
|
|
108
320
|
function getMimeType(type) {
|
|
@@ -122,8 +334,25 @@ function getCharsetForMimeType(type) {
|
|
|
122
334
|
return undefined;
|
|
123
335
|
}
|
|
124
336
|
|
|
125
|
-
|
|
126
|
-
|
|
337
|
+
/**
|
|
338
|
+
* Based on https://github.com/unjs/pathe v1.1.1 (055f50a6f1131f4e5c56cf259dd8816168fba329)
|
|
339
|
+
*/ function normalizeWindowsPath(input = '') {
|
|
340
|
+
if (!input || !input.includes('\\')) {
|
|
341
|
+
return input;
|
|
342
|
+
}
|
|
343
|
+
return input.replace(/\\/g, '/');
|
|
344
|
+
}
|
|
345
|
+
const EXTNAME_RE = /.(\.[^./]+)$/;
|
|
346
|
+
function extname(input) {
|
|
347
|
+
const match = EXTNAME_RE.exec(normalizeWindowsPath(input));
|
|
348
|
+
return match && match[1] || '';
|
|
349
|
+
}
|
|
350
|
+
function basename(input, extension) {
|
|
351
|
+
const lastSegment = normalizeWindowsPath(input).split('/').pop();
|
|
352
|
+
if (!lastSegment) {
|
|
353
|
+
return input;
|
|
354
|
+
}
|
|
355
|
+
return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
|
|
127
356
|
}
|
|
128
357
|
|
|
129
358
|
function isPromise(p) {
|
|
@@ -132,24 +361,14 @@ function isPromise(p) {
|
|
|
132
361
|
typeof p.then === 'function');
|
|
133
362
|
}
|
|
134
363
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
/* istanbul ignore next */ if (typeof done === 'function') {
|
|
144
|
-
done();
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
/* istanbul ignore next */ res.once('error', (e)=>{
|
|
148
|
-
clearTimeout(instance);
|
|
149
|
-
if (typeof done === 'function') {
|
|
150
|
-
done(e);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
364
|
+
function isNodeStream(input) {
|
|
365
|
+
return isObject(input) && typeof input.pipe === 'function' && typeof input.read === 'function';
|
|
366
|
+
}
|
|
367
|
+
function isWebStream(input) {
|
|
368
|
+
return isObject(input) && typeof input.pipeTo === 'function';
|
|
369
|
+
}
|
|
370
|
+
function isStream(data) {
|
|
371
|
+
return isNodeStream(data) || isWebStream(data);
|
|
153
372
|
}
|
|
154
373
|
|
|
155
374
|
const TRAILING_SLASH_RE = /\/$|\/\?/;
|
|
@@ -169,22 +388,9 @@ function withoutTrailingSlash(input = '', queryParams = false) {
|
|
|
169
388
|
const [s0, ...s] = input.split('?');
|
|
170
389
|
return (s0.slice(0, -1) || '/') + (s.length ? `?${s.join('?')}` : '');
|
|
171
390
|
}
|
|
172
|
-
function withTrailingSlash(input = '', queryParams = false) {
|
|
173
|
-
if (!queryParams) {
|
|
174
|
-
return input.endsWith('/') ? input : `${input}/`;
|
|
175
|
-
}
|
|
176
|
-
if (hasTrailingSlash(input, true)) {
|
|
177
|
-
return input || '/';
|
|
178
|
-
}
|
|
179
|
-
const [s0, ...s] = input.split('?');
|
|
180
|
-
return `${s0}/${s.length ? `?${s.join('?')}` : ''}`;
|
|
181
|
-
}
|
|
182
391
|
function hasLeadingSlash(input = '') {
|
|
183
392
|
return input.startsWith('/');
|
|
184
393
|
}
|
|
185
|
-
function withoutLeadingSlash(input = '') {
|
|
186
|
-
return (hasLeadingSlash(input) ? input.substr(1) : input) || '/';
|
|
187
|
-
}
|
|
188
394
|
function withLeadingSlash(input = '') {
|
|
189
395
|
return hasLeadingSlash(input) ? input : `/${input}`;
|
|
190
396
|
}
|
|
@@ -192,91 +398,73 @@ function cleanDoubleSlashes(input = '') {
|
|
|
192
398
|
return input.split('://').map((str)=>str.replace(/\/{2,}/g, '/')).join('://');
|
|
193
399
|
}
|
|
194
400
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return new continu.Continu({
|
|
198
|
-
defaults: {
|
|
199
|
-
env: process.env.NODE_ENV || 'development',
|
|
200
|
-
trustProxy: ()=>false,
|
|
201
|
-
subdomainOffset: 2,
|
|
202
|
-
etag: buildEtagFn(),
|
|
203
|
-
proxyIpMax: 0
|
|
204
|
-
},
|
|
205
|
-
transformers: {
|
|
206
|
-
etag: (value)=>buildEtagFn(value),
|
|
207
|
-
trustProxy: (value)=>buildTrustProxyFn(value)
|
|
208
|
-
},
|
|
209
|
-
validators: {
|
|
210
|
-
env: (value)=>zod.string().safeParse(value),
|
|
211
|
-
trustProxy: (value)=>zod.any().safeParse(value),
|
|
212
|
-
subdomainOffset: (value)=>zod.number().nonnegative().safeParse(value),
|
|
213
|
-
etag: (value)=>zod.any().safeParse(value),
|
|
214
|
-
proxyIpMax: (value)=>zod.number().nonnegative().safeParse(value)
|
|
215
|
-
}
|
|
216
|
-
});
|
|
401
|
+
function isWebBlob(input) {
|
|
402
|
+
return typeof Blob !== 'undefined' && input instanceof Blob;
|
|
217
403
|
}
|
|
218
|
-
function
|
|
219
|
-
|
|
220
|
-
return instance;
|
|
221
|
-
}
|
|
222
|
-
instance = buildConfig();
|
|
223
|
-
return instance;
|
|
404
|
+
function isWebResponse(input) {
|
|
405
|
+
return typeof Response !== 'undefined' && input instanceof Response;
|
|
224
406
|
}
|
|
225
|
-
|
|
226
|
-
|
|
407
|
+
|
|
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
|
+
}
|
|
227
420
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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}"` : ''}`);
|
|
232
427
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
+
}
|
|
236
440
|
}
|
|
237
441
|
|
|
238
|
-
|
|
239
|
-
(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
HeaderName["HOST"] = 'host';
|
|
265
|
-
HeaderName["IF_MODIFIED_SINCE"] = 'if-modified-since';
|
|
266
|
-
HeaderName["IF_NONE_MATCH"] = 'if-none-match';
|
|
267
|
-
HeaderName["LAST_MODIFIED"] = 'last-modified';
|
|
268
|
-
HeaderName["LOCATION"] = 'location';
|
|
269
|
-
HeaderName["RANGE"] = 'range';
|
|
270
|
-
HeaderName["RATE_LIMIT_LIMIT"] = 'ratelimit-limit';
|
|
271
|
-
HeaderName["RATE_LIMIT_REMAINING"] = 'ratelimit-remaining';
|
|
272
|
-
HeaderName["RATE_LIMIT_RESET"] = 'ratelimit-reset';
|
|
273
|
-
HeaderName["RETRY_AFTER"] = 'retry-after';
|
|
274
|
-
HeaderName["SET_COOKIE"] = 'set-cookie';
|
|
275
|
-
HeaderName["TRANSFER_ENCODING"] = 'transfer-encoding';
|
|
276
|
-
HeaderName["X_FORWARDED_HOST"] = 'x-forwarded-host';
|
|
277
|
-
HeaderName["X_FORWARDED_FOR"] = 'x-forwarded-for';
|
|
278
|
-
HeaderName["X_FORWARDED_PROTO"] = 'x-forwarded-proto';
|
|
279
|
-
})(exports.HeaderName || (exports.HeaderName = {}));
|
|
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
|
+
}
|
|
280
468
|
|
|
281
469
|
const BodySymbol = Symbol.for('ReqBody');
|
|
282
470
|
function useRequestBody(req, key) {
|
|
@@ -539,14 +727,24 @@ function matchRequestContentType(req, contentType) {
|
|
|
539
727
|
return header.split('; ').shift() === getMimeType(contentType);
|
|
540
728
|
}
|
|
541
729
|
|
|
730
|
+
const routerSymbol = Symbol.for('ReqRouterID');
|
|
731
|
+
function setRequestRouterIds(req, ids) {
|
|
732
|
+
req[routerSymbol] = ids;
|
|
733
|
+
}
|
|
734
|
+
function useRequestRouterIds(req) {
|
|
735
|
+
if (routerSymbol in req) {
|
|
736
|
+
return req[routerSymbol];
|
|
737
|
+
}
|
|
738
|
+
return undefined;
|
|
739
|
+
}
|
|
740
|
+
|
|
542
741
|
function getRequestHostName(req, options) {
|
|
543
742
|
options = options || {};
|
|
544
743
|
let trustProxy;
|
|
545
744
|
if (typeof options.trustProxy !== 'undefined') {
|
|
546
745
|
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
547
746
|
} else {
|
|
548
|
-
|
|
549
|
-
trustProxy = config.get('trustProxy');
|
|
747
|
+
trustProxy = findRouterOption('trustProxy', useRequestRouterIds(req));
|
|
550
748
|
}
|
|
551
749
|
let hostname = req.headers[exports.HeaderName.X_FORWARDED_HOST];
|
|
552
750
|
if (!hostname || !req.socket.remoteAddress || !trustProxy(req.socket.remoteAddress, 0)) {
|
|
@@ -572,8 +770,7 @@ function getRequestIP(req, options) {
|
|
|
572
770
|
if (typeof options.trustProxy !== 'undefined') {
|
|
573
771
|
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
574
772
|
} else {
|
|
575
|
-
|
|
576
|
-
trustProxy = config.get('trustProxy');
|
|
773
|
+
trustProxy = findRouterOption('trustProxy', useRequestRouterIds(req));
|
|
577
774
|
}
|
|
578
775
|
const addrs = proxyAddr.all(req, trustProxy);
|
|
579
776
|
return addrs[addrs.length - 1];
|
|
@@ -623,7 +820,7 @@ function useRequestPath(req) {
|
|
|
623
820
|
if (typeof req.url === 'undefined') {
|
|
624
821
|
return '/';
|
|
625
822
|
}
|
|
626
|
-
const parsed = new
|
|
823
|
+
const parsed = new URL(req.url, 'http://localhost/');
|
|
627
824
|
req[PathSymbol] = parsed.pathname;
|
|
628
825
|
return req[PathSymbol];
|
|
629
826
|
}
|
|
@@ -634,8 +831,7 @@ function getRequestProtocol(req, options) {
|
|
|
634
831
|
if (typeof options.trustProxy !== 'undefined') {
|
|
635
832
|
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
636
833
|
} else {
|
|
637
|
-
|
|
638
|
-
trustProxy = config.get('trustProxy');
|
|
834
|
+
trustProxy = findRouterOption('trustProxy', useRequestRouterIds(req));
|
|
639
835
|
}
|
|
640
836
|
let protocol = options.default;
|
|
641
837
|
/* istanbul ignore next */ if (smob.hasOwnProperty(req.socket, 'encrypted') && !!req.socket.encrypted) {
|
|
@@ -703,121 +899,7 @@ function extendRequestQuery(req, key, value) {
|
|
|
703
899
|
setRequestQuery(req, key, value);
|
|
704
900
|
}
|
|
705
901
|
|
|
706
|
-
function
|
|
707
|
-
options = options || {};
|
|
708
|
-
const cacheControls = [
|
|
709
|
-
'public'
|
|
710
|
-
].concat(options.cacheControls || []);
|
|
711
|
-
if (options.maxAge !== undefined) {
|
|
712
|
-
cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);
|
|
713
|
-
}
|
|
714
|
-
if (options.modifiedTime) {
|
|
715
|
-
const modifiedTime = typeof options.modifiedTime === 'string' ? new Date(options.modifiedTime) : options.modifiedTime;
|
|
716
|
-
res.setHeader('last-modified', modifiedTime.toUTCString());
|
|
717
|
-
}
|
|
718
|
-
res.setHeader('cache-control', cacheControls.join(', '));
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
function appendResponseHeader(res, name, value) {
|
|
722
|
-
let header = res.getHeader(name);
|
|
723
|
-
if (!header) {
|
|
724
|
-
res.setHeader(name, value);
|
|
725
|
-
return;
|
|
726
|
-
}
|
|
727
|
-
if (!Array.isArray(header)) {
|
|
728
|
-
header = [
|
|
729
|
-
header.toString()
|
|
730
|
-
];
|
|
731
|
-
}
|
|
732
|
-
res.setHeader(name, [
|
|
733
|
-
...header,
|
|
734
|
-
value
|
|
735
|
-
]);
|
|
736
|
-
}
|
|
737
|
-
function appendResponseHeaderDirective(res, name, value) {
|
|
738
|
-
let header = res.getHeader(name);
|
|
739
|
-
if (!header) {
|
|
740
|
-
if (Array.isArray(value)) {
|
|
741
|
-
res.setHeader(name, value.join('; '));
|
|
742
|
-
return;
|
|
743
|
-
}
|
|
744
|
-
res.setHeader(name, value);
|
|
745
|
-
return;
|
|
746
|
-
}
|
|
747
|
-
if (!Array.isArray(header)) {
|
|
748
|
-
if (typeof header === 'string') {
|
|
749
|
-
// split header by directive(s)
|
|
750
|
-
header = header.split('; ');
|
|
751
|
-
}
|
|
752
|
-
if (typeof header === 'number') {
|
|
753
|
-
header = [
|
|
754
|
-
header.toString()
|
|
755
|
-
];
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
if (Array.isArray(value)) {
|
|
759
|
-
header.push(...value);
|
|
760
|
-
} else {
|
|
761
|
-
header.push(`${value}`);
|
|
762
|
-
}
|
|
763
|
-
header = [
|
|
764
|
-
...new Set(header)
|
|
765
|
-
];
|
|
766
|
-
res.setHeader(name, header.join('; '));
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
function setResponseContentTypeByFileName(res, fileName) {
|
|
770
|
-
const ext = path.extname(fileName);
|
|
771
|
-
if (ext) {
|
|
772
|
-
let type = getMimeType(ext.substring(1));
|
|
773
|
-
if (type) {
|
|
774
|
-
const charset = getCharsetForMimeType(type);
|
|
775
|
-
if (charset) {
|
|
776
|
-
type += `; charset=${charset}`;
|
|
777
|
-
}
|
|
778
|
-
res.setHeader(exports.HeaderName.CONTENT_TYPE, type);
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
/* istanbul ignore next */ function onResponseFinished(res, cb) {
|
|
783
|
-
let called;
|
|
784
|
-
const callCallback = (err)=>{
|
|
785
|
-
if (called) return;
|
|
786
|
-
called = true;
|
|
787
|
-
cb(err);
|
|
788
|
-
};
|
|
789
|
-
res.on('finish', ()=>{
|
|
790
|
-
callCallback();
|
|
791
|
-
});
|
|
792
|
-
res.on('close', ()=>{
|
|
793
|
-
callCallback();
|
|
794
|
-
});
|
|
795
|
-
res.on('error', (err)=>{
|
|
796
|
-
callCallback(err);
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
function setResponseHeaderAttachment(res, filename) {
|
|
801
|
-
if (typeof filename === 'string') {
|
|
802
|
-
setResponseContentTypeByFileName(res, filename);
|
|
803
|
-
}
|
|
804
|
-
res.setHeader(exports.HeaderName.CONTENT_DISPOSITION, `attachment${filename ? `; filename="${filename}"` : ''}`);
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
function setResponseHeaderContentType(res, input, ifNotExists) {
|
|
808
|
-
if (ifNotExists) {
|
|
809
|
-
const header = res.getHeader(exports.HeaderName.CONTENT_TYPE);
|
|
810
|
-
if (header) {
|
|
811
|
-
return;
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
const contentType = getMimeType(input);
|
|
815
|
-
if (contentType) {
|
|
816
|
-
res.setHeader(exports.HeaderName.CONTENT_TYPE, contentType);
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
function send(res, chunk) {
|
|
902
|
+
async function send(res, chunk) {
|
|
821
903
|
switch(typeof chunk){
|
|
822
904
|
case 'string':
|
|
823
905
|
{
|
|
@@ -830,7 +912,7 @@ function send(res, chunk) {
|
|
|
830
912
|
{
|
|
831
913
|
if (chunk === null) {
|
|
832
914
|
chunk = '';
|
|
833
|
-
} else if (Buffer.isBuffer(chunk)) {
|
|
915
|
+
} else if (buffer.Buffer.isBuffer(chunk)) {
|
|
834
916
|
setResponseHeaderContentType(res, 'bin', true);
|
|
835
917
|
} else {
|
|
836
918
|
chunk = JSON.stringify(chunk);
|
|
@@ -848,24 +930,26 @@ function send(res, chunk) {
|
|
|
848
930
|
// populate Content-Length
|
|
849
931
|
let len;
|
|
850
932
|
if (chunk !== undefined) {
|
|
851
|
-
if (Buffer.isBuffer(chunk)) {
|
|
933
|
+
if (buffer.Buffer.isBuffer(chunk)) {
|
|
852
934
|
// get length of Buffer
|
|
853
935
|
len = chunk.length;
|
|
854
936
|
} else if (chunk.length < 1000) {
|
|
855
937
|
// just calculate length when no ETag + small chunk
|
|
856
|
-
len = Buffer.byteLength(chunk, encoding);
|
|
938
|
+
len = buffer.Buffer.byteLength(chunk, encoding);
|
|
857
939
|
} else {
|
|
858
940
|
// convert chunk to Buffer and calculate
|
|
859
|
-
chunk = Buffer.from(chunk, encoding);
|
|
941
|
+
chunk = buffer.Buffer.from(chunk, encoding);
|
|
860
942
|
encoding = undefined;
|
|
861
943
|
len = chunk.length;
|
|
862
944
|
}
|
|
863
945
|
res.setHeader(exports.HeaderName.CONTENT_LENGTH, `${len}`);
|
|
864
946
|
}
|
|
865
|
-
const config = useConfig();
|
|
866
|
-
const etagFn = config.get('etag');
|
|
867
947
|
if (typeof len !== 'undefined') {
|
|
868
|
-
const
|
|
948
|
+
const etagFn = findRouterOption('etag', useRequestRouterIds(res.req));
|
|
949
|
+
const chunkHash = await etagFn(chunk, encoding, len);
|
|
950
|
+
if (isResponseGone(res)) {
|
|
951
|
+
return Promise.resolve();
|
|
952
|
+
}
|
|
869
953
|
if (typeof chunkHash === 'string') {
|
|
870
954
|
res.setHeader(exports.HeaderName.ETag, chunkHash);
|
|
871
955
|
if (res.req.headers[exports.HeaderName.IF_NONE_MATCH] === chunkHash) {
|
|
@@ -886,16 +970,20 @@ function send(res, chunk) {
|
|
|
886
970
|
res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
|
|
887
971
|
chunk = '';
|
|
888
972
|
}
|
|
973
|
+
if (isResponseGone(res)) {
|
|
974
|
+
return Promise.resolve();
|
|
975
|
+
}
|
|
889
976
|
if (res.req.method === 'HEAD') {
|
|
890
977
|
// skip body for HEAD
|
|
891
978
|
res.end();
|
|
892
|
-
return;
|
|
979
|
+
return Promise.resolve();
|
|
893
980
|
}
|
|
894
981
|
if (typeof encoding !== 'undefined') {
|
|
895
982
|
res.end(chunk, encoding);
|
|
896
|
-
return;
|
|
983
|
+
return Promise.resolve();
|
|
897
984
|
}
|
|
898
985
|
res.end(chunk);
|
|
986
|
+
return Promise.resolve();
|
|
899
987
|
}
|
|
900
988
|
|
|
901
989
|
function sendAccepted(res, chunk) {
|
|
@@ -910,87 +998,116 @@ function sendCreated(res, chunk) {
|
|
|
910
998
|
return send(res, chunk);
|
|
911
999
|
}
|
|
912
1000
|
|
|
913
|
-
function sendStream(res, stream,
|
|
914
|
-
|
|
915
|
-
stream.
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1001
|
+
async function sendStream(res, stream, next) {
|
|
1002
|
+
if (isWebStream(stream)) {
|
|
1003
|
+
return stream.pipeTo(new WritableStream({
|
|
1004
|
+
write (chunk) {
|
|
1005
|
+
res.write(chunk);
|
|
1006
|
+
}
|
|
1007
|
+
})).then(()=>{
|
|
1008
|
+
if (next) {
|
|
1009
|
+
return next();
|
|
1010
|
+
}
|
|
922
1011
|
res.end();
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1012
|
+
return Promise.resolve();
|
|
1013
|
+
}).catch((err)=>{
|
|
1014
|
+
if (next) {
|
|
1015
|
+
return next(err);
|
|
1016
|
+
}
|
|
1017
|
+
return Promise.reject(err);
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
return new Promise((resolve, reject)=>{
|
|
1021
|
+
stream.on('open', ()=>{
|
|
1022
|
+
stream.pipe(res);
|
|
1023
|
+
});
|
|
1024
|
+
/* istanbul ignore next */ stream.on('error', (err)=>{
|
|
1025
|
+
if (next) {
|
|
1026
|
+
Promise.resolve().then(()=>next(err)).then(()=>resolve()).catch((e)=>reject(e));
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
929
1029
|
res.end();
|
|
930
|
-
|
|
1030
|
+
reject(err);
|
|
1031
|
+
});
|
|
1032
|
+
stream.on('close', ()=>{
|
|
1033
|
+
if (next) {
|
|
1034
|
+
Promise.resolve().then(()=>next()).then(()=>resolve()).catch((e)=>reject(e));
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
res.end();
|
|
1038
|
+
resolve();
|
|
1039
|
+
});
|
|
931
1040
|
});
|
|
932
1041
|
}
|
|
933
1042
|
|
|
934
|
-
function
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
function sendFile(res, filePath, fn) {
|
|
942
|
-
let options;
|
|
943
|
-
if (typeof filePath === 'string') {
|
|
944
|
-
options = {
|
|
945
|
-
filePath
|
|
946
|
-
};
|
|
947
|
-
} else {
|
|
948
|
-
options = filePath;
|
|
949
|
-
}
|
|
950
|
-
const fileName = path.basename(options.filePath);
|
|
951
|
-
if (options.attachment) {
|
|
952
|
-
const dispositionHeader = res.getHeader(exports.HeaderName.CONTENT_DISPOSITION);
|
|
953
|
-
if (!dispositionHeader) {
|
|
954
|
-
setResponseHeaderAttachment(res, fileName);
|
|
1043
|
+
async function sendFile(res, options, next) {
|
|
1044
|
+
let stats;
|
|
1045
|
+
try {
|
|
1046
|
+
stats = await options.stats();
|
|
1047
|
+
} catch (e) {
|
|
1048
|
+
if (next) {
|
|
1049
|
+
return next(e);
|
|
955
1050
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1051
|
+
if (isResponseGone(res)) {
|
|
1052
|
+
return Promise.resolve();
|
|
1053
|
+
}
|
|
1054
|
+
return Promise.reject(e);
|
|
1055
|
+
}
|
|
1056
|
+
const name = options.name || stats.name;
|
|
1057
|
+
if (name) {
|
|
1058
|
+
const fileName = basename(name);
|
|
1059
|
+
if (options.attachment) {
|
|
1060
|
+
const dispositionHeader = res.getHeader(exports.HeaderName.CONTENT_DISPOSITION);
|
|
1061
|
+
if (!dispositionHeader) {
|
|
1062
|
+
setResponseHeaderAttachment(res, fileName);
|
|
966
1063
|
}
|
|
967
|
-
|
|
1064
|
+
} else {
|
|
1065
|
+
setResponseContentTypeByFileName(res, fileName);
|
|
968
1066
|
}
|
|
969
|
-
|
|
1067
|
+
}
|
|
1068
|
+
const contentOptions = {};
|
|
1069
|
+
if (stats.size) {
|
|
970
1070
|
const rangeHeader = res.req.headers[exports.HeaderName.RANGE];
|
|
971
1071
|
if (rangeHeader) {
|
|
972
1072
|
const [x, y] = rangeHeader.replace('bytes=', '').split('-');
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
if (
|
|
976
|
-
|
|
1073
|
+
contentOptions.end = Math.min(parseInt(y, 10) || stats.size - 1, stats.size - 1);
|
|
1074
|
+
contentOptions.start = parseInt(x, 10) || 0;
|
|
1075
|
+
if (contentOptions.end >= stats.size) {
|
|
1076
|
+
contentOptions.end = stats.size - 1;
|
|
977
1077
|
}
|
|
978
|
-
if (
|
|
1078
|
+
if (contentOptions.start >= stats.size) {
|
|
979
1079
|
res.setHeader(exports.HeaderName.CONTENT_RANGE, `bytes */${stats.size}`);
|
|
980
1080
|
res.statusCode = 416;
|
|
981
1081
|
res.end();
|
|
982
|
-
return;
|
|
1082
|
+
return Promise.resolve();
|
|
983
1083
|
}
|
|
984
|
-
res.setHeader(exports.HeaderName.CONTENT_RANGE, `bytes ${
|
|
985
|
-
res.setHeader(exports.HeaderName.CONTENT_LENGTH,
|
|
1084
|
+
res.setHeader(exports.HeaderName.CONTENT_RANGE, `bytes ${contentOptions.start}-${contentOptions.end}/${stats.size}`);
|
|
1085
|
+
res.setHeader(exports.HeaderName.CONTENT_LENGTH, contentOptions.end - contentOptions.start + 1);
|
|
986
1086
|
} else {
|
|
987
1087
|
res.setHeader(exports.HeaderName.CONTENT_LENGTH, stats.size);
|
|
988
1088
|
}
|
|
989
1089
|
res.setHeader(exports.HeaderName.ACCEPT_RANGES, 'bytes');
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1090
|
+
if (stats.mtime) {
|
|
1091
|
+
const mtime = new Date(stats.mtime);
|
|
1092
|
+
res.setHeader(exports.HeaderName.LAST_MODIFIED, mtime.toUTCString());
|
|
1093
|
+
res.setHeader(exports.HeaderName.ETag, `W/"${stats.size}-${mtime.getTime()}"`);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
try {
|
|
1097
|
+
const content = await options.content(contentOptions);
|
|
1098
|
+
if (isStream(content)) {
|
|
1099
|
+
return await sendStream(res, content, next);
|
|
1100
|
+
}
|
|
1101
|
+
return await send(res, content);
|
|
1102
|
+
} catch (e) {
|
|
1103
|
+
if (next) {
|
|
1104
|
+
return next(e);
|
|
1105
|
+
}
|
|
1106
|
+
if (isResponseGone(res)) {
|
|
1107
|
+
return Promise.resolve();
|
|
1108
|
+
}
|
|
1109
|
+
return Promise.reject(e);
|
|
1110
|
+
}
|
|
994
1111
|
}
|
|
995
1112
|
|
|
996
1113
|
function sendFormat(res, input) {
|
|
@@ -1012,19 +1129,406 @@ function sendRedirect(res, location, statusCode = 302) {
|
|
|
1012
1129
|
return send(res, html);
|
|
1013
1130
|
}
|
|
1014
1131
|
|
|
1015
|
-
function
|
|
1016
|
-
if (
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1132
|
+
function sendWebResponse(res, webResponse) {
|
|
1133
|
+
if (webResponse.redirected) {
|
|
1134
|
+
res.setHeader(exports.HeaderName.LOCATION, webResponse.url);
|
|
1135
|
+
}
|
|
1136
|
+
if (webResponse.status) {
|
|
1137
|
+
res.statusCode = webResponse.status;
|
|
1138
|
+
}
|
|
1139
|
+
if (webResponse.statusText) {
|
|
1140
|
+
res.statusMessage = webResponse.statusText;
|
|
1141
|
+
}
|
|
1142
|
+
webResponse.headers.forEach((value, key)=>{
|
|
1143
|
+
if (key === exports.HeaderName.SET_COOKIE) {
|
|
1144
|
+
res.appendHeader(key, splitCookiesString(value));
|
|
1145
|
+
} else {
|
|
1146
|
+
res.setHeader(key, value);
|
|
1147
|
+
}
|
|
1148
|
+
});
|
|
1149
|
+
if (webResponse.body) {
|
|
1150
|
+
return sendStream(res, webResponse.body);
|
|
1151
|
+
}
|
|
1152
|
+
res.end();
|
|
1153
|
+
return Promise.resolve();
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
function sendWebBlob(res, blob) {
|
|
1157
|
+
setResponseHeaderContentType(res, blob.type);
|
|
1158
|
+
return sendStream(res, blob.stream());
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
function createResponse(request) {
|
|
1162
|
+
let output;
|
|
1163
|
+
let encoding;
|
|
1164
|
+
const write = (chunk, chunkEncoding, callback)=>{
|
|
1165
|
+
if (typeof chunk !== 'undefined') {
|
|
1166
|
+
const chunkEncoded = typeof chunk === 'string' ? buffer.Buffer.from(chunk, chunkEncoding || encoding || 'utf8') : chunk;
|
|
1167
|
+
if (typeof output !== 'undefined') {
|
|
1168
|
+
output = buffer.Buffer.concat([
|
|
1169
|
+
output,
|
|
1170
|
+
chunkEncoded
|
|
1171
|
+
]);
|
|
1172
|
+
} else {
|
|
1173
|
+
output = chunkEncoded;
|
|
1020
1174
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1175
|
+
}
|
|
1176
|
+
encoding = chunkEncoding;
|
|
1177
|
+
if (callback) {
|
|
1178
|
+
callback();
|
|
1179
|
+
}
|
|
1180
|
+
};
|
|
1181
|
+
const writable = new readableStream.Writable({
|
|
1182
|
+
decodeStrings: false,
|
|
1183
|
+
write (chunk, arg2, arg3) {
|
|
1184
|
+
const chunkEncoding = typeof arg2 === 'string' ? encoding : 'utf-8';
|
|
1185
|
+
let cb;
|
|
1186
|
+
if (typeof arg2 === 'function') {
|
|
1187
|
+
cb = arg2;
|
|
1188
|
+
} else if (typeof arg3 === 'function') {
|
|
1189
|
+
cb = arg3;
|
|
1190
|
+
}
|
|
1191
|
+
write(chunk, chunkEncoding, cb);
|
|
1192
|
+
return true;
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1195
|
+
Object.defineProperty(writable, 'body', {
|
|
1196
|
+
get () {
|
|
1197
|
+
if (output) {
|
|
1198
|
+
const arrayBuffer = new ArrayBuffer(output.length);
|
|
1199
|
+
const view = new Uint8Array(arrayBuffer);
|
|
1200
|
+
for(let i = 0; i < output.length; ++i){
|
|
1201
|
+
view[i] = output[i];
|
|
1202
|
+
}
|
|
1203
|
+
return arrayBuffer;
|
|
1204
|
+
}
|
|
1205
|
+
return new ArrayBuffer(0);
|
|
1206
|
+
}
|
|
1207
|
+
});
|
|
1208
|
+
const headers = {};
|
|
1209
|
+
Object.assign(writable, {
|
|
1210
|
+
req: request,
|
|
1211
|
+
chunkedEncoding: false,
|
|
1212
|
+
connection: null,
|
|
1213
|
+
headersSent: false,
|
|
1214
|
+
sendDate: false,
|
|
1215
|
+
shouldKeepAlive: false,
|
|
1216
|
+
socket: null,
|
|
1217
|
+
statusCode: 200,
|
|
1218
|
+
statusMessage: '',
|
|
1219
|
+
strictContentLength: false,
|
|
1220
|
+
useChunkedEncodingByDefault: false,
|
|
1221
|
+
finished: false,
|
|
1222
|
+
addTrailers (_headers) {},
|
|
1223
|
+
appendHeader (name, value) {
|
|
1224
|
+
if (name === exports.HeaderName.SET_COOKIE) {
|
|
1225
|
+
value = splitCookiesString(value);
|
|
1226
|
+
}
|
|
1227
|
+
name = name.toLowerCase();
|
|
1228
|
+
const current = headers[name];
|
|
1229
|
+
const all = [
|
|
1230
|
+
...Array.isArray(current) ? current : [
|
|
1231
|
+
current
|
|
1232
|
+
],
|
|
1233
|
+
...Array.isArray(value) ? value : [
|
|
1234
|
+
value
|
|
1235
|
+
]
|
|
1236
|
+
].filter(Boolean);
|
|
1237
|
+
headers[name] = all.length > 1 ? all : all[0];
|
|
1238
|
+
return this;
|
|
1239
|
+
},
|
|
1240
|
+
assignSocket (_socket) {},
|
|
1241
|
+
detachSocket (_socket) {},
|
|
1242
|
+
flushHeaders () {},
|
|
1243
|
+
getHeader (name) {
|
|
1244
|
+
return headers[name.toLowerCase()];
|
|
1245
|
+
},
|
|
1246
|
+
getHeaderNames () {
|
|
1247
|
+
return Object.keys(headers);
|
|
1248
|
+
},
|
|
1249
|
+
getHeaders () {
|
|
1250
|
+
return headers;
|
|
1251
|
+
},
|
|
1252
|
+
hasHeader (name) {
|
|
1253
|
+
return smob.hasOwnProperty(headers, name.toLowerCase());
|
|
1254
|
+
},
|
|
1255
|
+
removeHeader (name) {
|
|
1256
|
+
delete headers[name.toLowerCase()];
|
|
1257
|
+
},
|
|
1258
|
+
setHeader (name, value) {
|
|
1259
|
+
if (name === exports.HeaderName.SET_COOKIE && typeof value !== 'number') {
|
|
1260
|
+
value = splitCookiesString(value);
|
|
1261
|
+
}
|
|
1262
|
+
headers[name.toLowerCase()] = value;
|
|
1263
|
+
return this;
|
|
1264
|
+
},
|
|
1265
|
+
setTimeout (_msecs, _callback) {
|
|
1266
|
+
return this;
|
|
1267
|
+
},
|
|
1268
|
+
writeContinue (_callback) {},
|
|
1269
|
+
writeEarlyHints (_hints, callback) {
|
|
1270
|
+
if (typeof callback !== 'undefined') {
|
|
1271
|
+
callback();
|
|
1272
|
+
}
|
|
1273
|
+
},
|
|
1274
|
+
writeProcessing () {},
|
|
1275
|
+
writeHead (statusCode, arg1, arg2) {
|
|
1276
|
+
this.statusCode = statusCode;
|
|
1277
|
+
if (typeof arg1 === 'string') {
|
|
1278
|
+
this.statusMessage = arg1;
|
|
1279
|
+
arg1 = undefined;
|
|
1280
|
+
}
|
|
1281
|
+
const headers = arg2 || arg1;
|
|
1282
|
+
if (headers) {
|
|
1283
|
+
if (Array.isArray(headers)) {
|
|
1284
|
+
for(let i = 0; i < headers.length; i++){
|
|
1285
|
+
const keys = Object.keys(headers[i]);
|
|
1286
|
+
for(let j = 0; j < keys.length; j++){
|
|
1287
|
+
this.setHeader(keys[i], headers[i][keys[j]]);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
} else {
|
|
1291
|
+
const keys = Object.keys(headers);
|
|
1292
|
+
for(let i = 0; i < keys.length; i++){
|
|
1293
|
+
this.setHeader(keys[i], headers[keys[i]]);
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1298
|
+
// @ts-ignore
|
|
1299
|
+
this.headersSent = true;
|
|
1300
|
+
return this;
|
|
1301
|
+
}
|
|
1302
|
+
});
|
|
1303
|
+
return writable;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
async function dispatchNodeRequest(router, req, res) {
|
|
1307
|
+
try {
|
|
1308
|
+
const dispatched = await router.dispatch({
|
|
1309
|
+
req,
|
|
1310
|
+
res
|
|
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);
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
function createRequest(context) {
|
|
1334
|
+
let readable;
|
|
1335
|
+
if (context.body) {
|
|
1336
|
+
if (isWebStream(context.body)) {
|
|
1337
|
+
readable = readableStream.Readable.fromWeb(context.body);
|
|
1338
|
+
} else {
|
|
1339
|
+
readable = readableStream.Readable.from(context.body);
|
|
1340
|
+
}
|
|
1341
|
+
} else {
|
|
1342
|
+
readable = new readableStream.Readable();
|
|
1343
|
+
}
|
|
1344
|
+
const headers = context.headers || {};
|
|
1345
|
+
const rawHeaders = [];
|
|
1346
|
+
let keys = Object.keys(headers);
|
|
1347
|
+
for(let i = 0; i < keys.length; i++){
|
|
1348
|
+
const header = headers[keys[i]];
|
|
1349
|
+
if (Array.isArray(header)) {
|
|
1350
|
+
for(let j = 0; j < header.length; j++){
|
|
1351
|
+
rawHeaders.push(keys[i], header[j]);
|
|
1352
|
+
}
|
|
1353
|
+
} else if (typeof header === 'string') {
|
|
1354
|
+
rawHeaders.push(keys[i], header);
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
const headersDistinct = {};
|
|
1358
|
+
keys = Object.keys(headers);
|
|
1359
|
+
for(let i = 0; i < keys.length; i++){
|
|
1360
|
+
const header = headers[keys[i]];
|
|
1361
|
+
if (Array.isArray(header)) {
|
|
1362
|
+
headersDistinct[keys[i]] = header;
|
|
1363
|
+
}
|
|
1364
|
+
if (typeof header === 'string') {
|
|
1365
|
+
headersDistinct[keys[i]] = [
|
|
1366
|
+
header
|
|
1367
|
+
];
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
Object.defineProperty(readable, 'connection', {
|
|
1371
|
+
get () {
|
|
1372
|
+
return {};
|
|
1373
|
+
}
|
|
1374
|
+
});
|
|
1375
|
+
Object.defineProperty(readable, 'socket', {
|
|
1376
|
+
get () {
|
|
1377
|
+
return {};
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1380
|
+
Object.assign(readable, {
|
|
1381
|
+
aborted: false,
|
|
1382
|
+
complete: true,
|
|
1383
|
+
headers,
|
|
1384
|
+
headersDistinct,
|
|
1385
|
+
httpVersion: '1.1',
|
|
1386
|
+
httpVersionMajor: 1,
|
|
1387
|
+
httpVersionMinor: 1,
|
|
1388
|
+
method: context.method || 'GET',
|
|
1389
|
+
rawHeaders,
|
|
1390
|
+
rawTrailers: [],
|
|
1391
|
+
trailers: {},
|
|
1392
|
+
trailersDistinct: {},
|
|
1393
|
+
url: context.url || '/',
|
|
1394
|
+
setTimeout (_msecs, _callback) {
|
|
1395
|
+
return this;
|
|
1396
|
+
}
|
|
1397
|
+
});
|
|
1398
|
+
return readable;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
async function dispatchRawRequest(router, request, options = {}) {
|
|
1402
|
+
const req = createRequest({
|
|
1403
|
+
url: request.path,
|
|
1404
|
+
method: request.method,
|
|
1405
|
+
body: request.body,
|
|
1406
|
+
headers: request.headers
|
|
1407
|
+
});
|
|
1408
|
+
const res = createResponse(req);
|
|
1409
|
+
const getHeaders = ()=>{
|
|
1410
|
+
const output = {};
|
|
1411
|
+
const headers = res.getHeaders();
|
|
1412
|
+
const keys = Object.keys(headers);
|
|
1413
|
+
for(let i = 0; i < keys.length; i++){
|
|
1414
|
+
const header = headers[keys[i]];
|
|
1415
|
+
if (typeof header === 'number') {
|
|
1416
|
+
output[keys[i]] = `${header}`;
|
|
1417
|
+
} else if (header) {
|
|
1418
|
+
output[keys[i]] = header;
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
return output;
|
|
1422
|
+
};
|
|
1423
|
+
try {
|
|
1424
|
+
const dispatched = await router.dispatch({
|
|
1425
|
+
req,
|
|
1426
|
+
res
|
|
1427
|
+
});
|
|
1428
|
+
if (dispatched) {
|
|
1429
|
+
return {
|
|
1430
|
+
status: res.statusCode,
|
|
1431
|
+
statusMessage: res.statusMessage,
|
|
1432
|
+
headers: getHeaders(),
|
|
1433
|
+
body: res.body
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
return {
|
|
1437
|
+
status: 404,
|
|
1438
|
+
headers: getHeaders(),
|
|
1439
|
+
body: res.body
|
|
1440
|
+
};
|
|
1441
|
+
} catch (e) {
|
|
1442
|
+
if (options.throwOnError) {
|
|
1443
|
+
throw e;
|
|
1444
|
+
}
|
|
1445
|
+
return {
|
|
1446
|
+
status: 500,
|
|
1447
|
+
headers: getHeaders(),
|
|
1448
|
+
body: res.body
|
|
1449
|
+
};
|
|
1024
1450
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1451
|
+
}
|
|
1452
|
+
function createRawDispatcher(router) {
|
|
1453
|
+
return async (request)=>dispatchRawRequest(router, request);
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
async function dispatchWebRequest(router, request, options = {}) {
|
|
1457
|
+
const url = new URL(request.url);
|
|
1458
|
+
const headers = {};
|
|
1459
|
+
request.headers.forEach((value, key)=>{
|
|
1460
|
+
headers[key] = value;
|
|
1461
|
+
});
|
|
1462
|
+
const res = await dispatchRawRequest(router, {
|
|
1463
|
+
method: request.method,
|
|
1464
|
+
path: url.pathname + url.search,
|
|
1465
|
+
headers,
|
|
1466
|
+
body: request.body
|
|
1467
|
+
}, options);
|
|
1468
|
+
let body;
|
|
1469
|
+
if (request.method === exports.MethodName.HEAD || res.status === 304 || res.status === 101 || res.status === 204 || res.status === 205) {
|
|
1470
|
+
body = null;
|
|
1471
|
+
} else {
|
|
1472
|
+
body = res.body;
|
|
1027
1473
|
}
|
|
1474
|
+
return new Response(body, {
|
|
1475
|
+
headers: transformHeadersToTuples(res.headers),
|
|
1476
|
+
status: res.status,
|
|
1477
|
+
statusText: res.statusMessage
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
function createWebDispatcher(router) {
|
|
1481
|
+
return async (request)=>dispatchWebRequest(router, request);
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
function cloneDispatcherMeta(input) {
|
|
1485
|
+
if (!input) {
|
|
1486
|
+
return {};
|
|
1487
|
+
}
|
|
1488
|
+
return {
|
|
1489
|
+
path: input.path,
|
|
1490
|
+
mountPath: input.mountPath,
|
|
1491
|
+
error: input.error,
|
|
1492
|
+
routerIds: [
|
|
1493
|
+
...input.routerIds || []
|
|
1494
|
+
],
|
|
1495
|
+
params: cloneDispatcherMetaParams(input.params)
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
function cloneDispatcherMetaParams(input) {
|
|
1499
|
+
if (typeof input === 'undefined') {
|
|
1500
|
+
return {};
|
|
1501
|
+
}
|
|
1502
|
+
const keys = Object.keys(input);
|
|
1503
|
+
const output = {};
|
|
1504
|
+
for(let i = 0; i < keys.length; i++){
|
|
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]];
|
|
1519
|
+
}
|
|
1520
|
+
return t1;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
function createError(input) {
|
|
1524
|
+
if (input instanceof Error) {
|
|
1525
|
+
return input;
|
|
1526
|
+
}
|
|
1527
|
+
const error = new Error();
|
|
1528
|
+
if (typeof input.message === 'string') {
|
|
1529
|
+
error.message = input.message;
|
|
1530
|
+
}
|
|
1531
|
+
return error;
|
|
1028
1532
|
}
|
|
1029
1533
|
|
|
1030
1534
|
function decodeParam(val) {
|
|
@@ -1088,48 +1592,98 @@ class PathMatcher {
|
|
|
1088
1592
|
}
|
|
1089
1593
|
}
|
|
1090
1594
|
|
|
1595
|
+
function isPath(input) {
|
|
1596
|
+
return typeof input === 'string' || input instanceof RegExp;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1091
1599
|
class Layer {
|
|
1092
1600
|
// --------------------------------------------------
|
|
1093
1601
|
isError() {
|
|
1094
1602
|
return this.fn.length === 4;
|
|
1095
1603
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1604
|
+
// --------------------------------------------------
|
|
1605
|
+
dispatch(event, meta) {
|
|
1606
|
+
setRequestParams(event.req, meta.params || {});
|
|
1607
|
+
setRequestMountPath(event.req, meta.mountPath || '/');
|
|
1608
|
+
setRequestRouterIds(event.req, meta.routerIds || []);
|
|
1609
|
+
if (this.fn.length !== 4 && meta.error || this.fn.length === 4 && !meta.error) {
|
|
1610
|
+
return Promise.reject(meta.error);
|
|
1611
|
+
}
|
|
1612
|
+
const timeout = findRouterOption('timeout', meta.routerIds);
|
|
1613
|
+
return new Promise((resolve, reject)=>{
|
|
1614
|
+
let timeoutInstance;
|
|
1615
|
+
let handled = false;
|
|
1616
|
+
const unsubscribe = ()=>{
|
|
1617
|
+
if (timeoutInstance) {
|
|
1618
|
+
clearTimeout(timeoutInstance);
|
|
1619
|
+
}
|
|
1620
|
+
event.res.off('close', onFinished);
|
|
1621
|
+
event.res.off('error', onFinished);
|
|
1622
|
+
};
|
|
1623
|
+
const shutdown = (dispatched, err)=>{
|
|
1624
|
+
if (handled) {
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
handled = true;
|
|
1628
|
+
unsubscribe();
|
|
1629
|
+
if (err) {
|
|
1630
|
+
reject(createError(err));
|
|
1631
|
+
} else {
|
|
1632
|
+
resolve(dispatched);
|
|
1633
|
+
}
|
|
1634
|
+
};
|
|
1635
|
+
const onFinished = (err)=>shutdown(true, err);
|
|
1636
|
+
const onNext = (err)=>shutdown(false, err);
|
|
1637
|
+
event.res.once('close', onFinished);
|
|
1638
|
+
event.res.once('error', onFinished);
|
|
1639
|
+
if (timeout) {
|
|
1640
|
+
timeoutInstance = setTimeout(()=>{
|
|
1641
|
+
handled = true;
|
|
1642
|
+
unsubscribe();
|
|
1643
|
+
event.res.statusCode = 504;
|
|
1644
|
+
event.res.statusMessage = 'Gateway Timeout';
|
|
1645
|
+
event.res.end();
|
|
1646
|
+
}, timeout);
|
|
1647
|
+
}
|
|
1648
|
+
try {
|
|
1649
|
+
let output;
|
|
1650
|
+
if (meta.error) {
|
|
1651
|
+
output = this.fn(meta.error, event.req, event.res, onNext);
|
|
1652
|
+
} else {
|
|
1653
|
+
output = this.fn(event.req, event.res, onNext);
|
|
1654
|
+
}
|
|
1655
|
+
const handle = (data)=>{
|
|
1656
|
+
if (typeof data === 'undefined' || handled) {
|
|
1657
|
+
return Promise.resolve();
|
|
1110
1658
|
}
|
|
1659
|
+
handled = true;
|
|
1660
|
+
unsubscribe();
|
|
1661
|
+
return this.sendOutput(event.res, data).then(()=>resolve(true)).catch((e)=>reject(createError(e)));
|
|
1662
|
+
};
|
|
1663
|
+
if (isPromise(output)) {
|
|
1664
|
+
output.then((r)=>handle(r)).catch((e)=>reject(createError(e)));
|
|
1665
|
+
return;
|
|
1111
1666
|
}
|
|
1112
|
-
|
|
1667
|
+
Promise.resolve().then(()=>handle(output)).catch((e)=>reject(createError(e)));
|
|
1668
|
+
} catch (error) {
|
|
1669
|
+
onNext(error);
|
|
1113
1670
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
sendOutput(res, input) {
|
|
1674
|
+
if (input instanceof Error) {
|
|
1675
|
+
return Promise.reject(input);
|
|
1116
1676
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
return;
|
|
1677
|
+
if (isStream(input)) {
|
|
1678
|
+
return sendStream(res, input);
|
|
1120
1679
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
next(e);
|
|
1127
|
-
} else {
|
|
1128
|
-
next(new http.BadRequestError({
|
|
1129
|
-
message: 'The request could not be processed by the handler.'
|
|
1130
|
-
}));
|
|
1131
|
-
}
|
|
1680
|
+
if (isWebBlob(input)) {
|
|
1681
|
+
return sendWebBlob(res, input);
|
|
1682
|
+
}
|
|
1683
|
+
if (isWebResponse(input)) {
|
|
1684
|
+
return sendWebResponse(res, input);
|
|
1132
1685
|
}
|
|
1686
|
+
return send(res, input);
|
|
1133
1687
|
}
|
|
1134
1688
|
// --------------------------------------------------
|
|
1135
1689
|
matchPath(path) {
|
|
@@ -1147,6 +1701,9 @@ class Layer {
|
|
|
1147
1701
|
}
|
|
1148
1702
|
|
|
1149
1703
|
function isLayerInstance(input) {
|
|
1704
|
+
if (input instanceof Layer) {
|
|
1705
|
+
return true;
|
|
1706
|
+
}
|
|
1150
1707
|
return isInstance(input, 'Layer');
|
|
1151
1708
|
}
|
|
1152
1709
|
|
|
@@ -1171,44 +1728,46 @@ class Route {
|
|
|
1171
1728
|
return keys;
|
|
1172
1729
|
}
|
|
1173
1730
|
// --------------------------------------------------
|
|
1174
|
-
dispatch(
|
|
1175
|
-
/* istanbul ignore next */ if (!req.method) {
|
|
1176
|
-
|
|
1177
|
-
return;
|
|
1731
|
+
async dispatch(event, meta) {
|
|
1732
|
+
/* istanbul ignore next */ if (!event.req.method) {
|
|
1733
|
+
return false;
|
|
1178
1734
|
}
|
|
1179
|
-
let name = req.method.toLowerCase();
|
|
1735
|
+
let name = event.req.method.toLowerCase();
|
|
1180
1736
|
if (name === exports.MethodName.HEAD && !smob.hasOwnProperty(this.layers, name)) {
|
|
1181
1737
|
name = exports.MethodName.GET;
|
|
1182
1738
|
}
|
|
1183
1739
|
const layers = this.layers[name];
|
|
1184
1740
|
/* istanbul ignore next */ if (typeof layers === 'undefined' || layers.length === 0 || typeof meta.path === 'undefined') {
|
|
1185
|
-
|
|
1186
|
-
return;
|
|
1741
|
+
return false;
|
|
1187
1742
|
}
|
|
1188
|
-
const layerMeta =
|
|
1189
|
-
...meta
|
|
1190
|
-
};
|
|
1743
|
+
const layerMeta = cloneDispatcherMeta(meta);
|
|
1191
1744
|
const output = this.pathMatcher.exec(meta.path);
|
|
1192
1745
|
if (output) {
|
|
1193
|
-
layerMeta.params =
|
|
1746
|
+
layerMeta.params = mergeDispatcherMetaParams(layerMeta.params, output.params);
|
|
1194
1747
|
}
|
|
1195
|
-
let
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
if (index >= layers.length) {
|
|
1199
|
-
setImmediate(done, err);
|
|
1200
|
-
return;
|
|
1201
|
-
}
|
|
1202
|
-
const layer = layers[index];
|
|
1748
|
+
let err;
|
|
1749
|
+
for(let i = 0; i < layers.length; i++){
|
|
1750
|
+
const layer = layers[i];
|
|
1203
1751
|
if (err && !layer.isError()) {
|
|
1204
|
-
|
|
1205
|
-
return;
|
|
1752
|
+
continue;
|
|
1206
1753
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
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
|
+
}
|
|
1770
|
+
return false;
|
|
1212
1771
|
}
|
|
1213
1772
|
// --------------------------------------------------
|
|
1214
1773
|
register(method, ...handlers) {
|
|
@@ -1261,42 +1820,50 @@ class Route {
|
|
|
1261
1820
|
}
|
|
1262
1821
|
|
|
1263
1822
|
function isRouteInstance(input) {
|
|
1823
|
+
if (input instanceof Route) {
|
|
1824
|
+
return true;
|
|
1825
|
+
}
|
|
1264
1826
|
return isInstance(input, 'Route');
|
|
1265
1827
|
}
|
|
1266
1828
|
|
|
1829
|
+
function transformRouterOptions(input) {
|
|
1830
|
+
if (typeof input.etag !== 'undefined') {
|
|
1831
|
+
input.etag = buildEtagFn(input.etag);
|
|
1832
|
+
}
|
|
1833
|
+
if (typeof input.trustProxy !== 'undefined') {
|
|
1834
|
+
input.trustProxy = buildTrustProxyFn(input.trustProxy);
|
|
1835
|
+
}
|
|
1836
|
+
return input;
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
let nextId = 0;
|
|
1840
|
+
function generateRouterID() {
|
|
1841
|
+
return ++nextId;
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1267
1844
|
function isRouterInstance(input) {
|
|
1845
|
+
if (input instanceof Router) {
|
|
1846
|
+
return true;
|
|
1847
|
+
}
|
|
1268
1848
|
return isInstance(input, 'Router');
|
|
1269
1849
|
}
|
|
1270
1850
|
class Router {
|
|
1271
1851
|
// --------------------------------------------------
|
|
1272
|
-
setPathMatcherOptions(input) {
|
|
1273
|
-
this.pathMatcherOptions = input;
|
|
1274
|
-
if (this.pathMatcher) {
|
|
1275
|
-
this.pathMatcher.regexpOptions = this.pathMatcherOptions;
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
1852
|
setPath(value) {
|
|
1279
1853
|
if (value === '/' || !isPath(value)) {
|
|
1280
|
-
this.path = '/';
|
|
1281
1854
|
return;
|
|
1282
1855
|
}
|
|
1856
|
+
let path;
|
|
1283
1857
|
if (typeof value === 'string') {
|
|
1284
|
-
|
|
1858
|
+
path = withLeadingSlash(withoutTrailingSlash(`${value}`));
|
|
1285
1859
|
} else {
|
|
1286
|
-
|
|
1860
|
+
path = value;
|
|
1287
1861
|
}
|
|
1288
|
-
this.pathMatcher = new PathMatcher(
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
return (req, res)=>{
|
|
1294
|
-
this.dispatch(req, res);
|
|
1295
|
-
};
|
|
1296
|
-
}
|
|
1297
|
-
/* istanbul ignore next */ listen(port) {
|
|
1298
|
-
const server = node_http.createServer(this.createListener());
|
|
1299
|
-
return server.listen(port);
|
|
1862
|
+
this.pathMatcher = new PathMatcher(path, {
|
|
1863
|
+
end: false,
|
|
1864
|
+
sensitive: false,
|
|
1865
|
+
...this.pathMatcherOptions ? this.pathMatcherOptions : {}
|
|
1866
|
+
});
|
|
1300
1867
|
}
|
|
1301
1868
|
// --------------------------------------------------
|
|
1302
1869
|
matchPath(path) {
|
|
@@ -1306,35 +1873,9 @@ class Router {
|
|
|
1306
1873
|
return true;
|
|
1307
1874
|
}
|
|
1308
1875
|
// --------------------------------------------------
|
|
1309
|
-
dispatch(
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
let allowedMethods = [];
|
|
1313
|
-
if (this.isRoot && typeof this.timeout === 'number') {
|
|
1314
|
-
createRequestTimeout(res, this.timeout, done);
|
|
1315
|
-
}
|
|
1316
|
-
const fn = (err)=>{
|
|
1317
|
-
/* istanbul ignore if */ if (!this.isRoot) {
|
|
1318
|
-
if (typeof done !== 'undefined') {
|
|
1319
|
-
setImmediate(()=>done(err));
|
|
1320
|
-
}
|
|
1321
|
-
return;
|
|
1322
|
-
}
|
|
1323
|
-
if (typeof err !== 'undefined') {
|
|
1324
|
-
res.statusCode = 400;
|
|
1325
|
-
res.end();
|
|
1326
|
-
return;
|
|
1327
|
-
}
|
|
1328
|
-
if (req.method && req.method.toLowerCase() === exports.MethodName.OPTIONS) {
|
|
1329
|
-
const options = allowedMethods.map((key)=>key.toUpperCase()).join(',');
|
|
1330
|
-
res.setHeader(exports.HeaderName.ALLOW, options);
|
|
1331
|
-
send(res, options);
|
|
1332
|
-
return;
|
|
1333
|
-
}
|
|
1334
|
-
res.statusCode = 404;
|
|
1335
|
-
res.end();
|
|
1336
|
-
};
|
|
1337
|
-
let path = meta.path || useRequestPath(req);
|
|
1876
|
+
async dispatch(event, meta = {}) {
|
|
1877
|
+
const allowedMethods = [];
|
|
1878
|
+
let path = meta.path || useRequestPath(event.req);
|
|
1338
1879
|
if (this.pathMatcher) {
|
|
1339
1880
|
const output = this.pathMatcher.exec(path);
|
|
1340
1881
|
if (typeof output !== 'undefined') {
|
|
@@ -1348,74 +1889,78 @@ class Router {
|
|
|
1348
1889
|
}
|
|
1349
1890
|
}
|
|
1350
1891
|
meta.path = path;
|
|
1892
|
+
if (meta.routerIds) {
|
|
1893
|
+
meta.routerIds.push(this.id);
|
|
1894
|
+
} else {
|
|
1895
|
+
meta.routerIds = [
|
|
1896
|
+
this.id
|
|
1897
|
+
];
|
|
1898
|
+
}
|
|
1351
1899
|
if (!meta.mountPath) {
|
|
1352
1900
|
meta.mountPath = '/';
|
|
1353
1901
|
}
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
index++;
|
|
1363
|
-
layer = this.stack[index];
|
|
1364
|
-
if (isLayerInstance(layer)) {
|
|
1365
|
-
if (!layer.isError() && err) {
|
|
1366
|
-
continue;
|
|
1367
|
-
}
|
|
1368
|
-
match = layer.matchPath(path);
|
|
1902
|
+
let err;
|
|
1903
|
+
let layer;
|
|
1904
|
+
let match = false;
|
|
1905
|
+
for(let i = 0; i < this.stack.length; i++){
|
|
1906
|
+
layer = this.stack[i];
|
|
1907
|
+
if (layer instanceof Layer) {
|
|
1908
|
+
if (!layer.isError() && err) {
|
|
1909
|
+
continue;
|
|
1369
1910
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1911
|
+
match = layer.matchPath(path);
|
|
1912
|
+
}
|
|
1913
|
+
if (isRouterInstance(layer)) {
|
|
1914
|
+
match = layer.matchPath(path);
|
|
1915
|
+
}
|
|
1916
|
+
if (isRouteInstance(layer)) {
|
|
1917
|
+
match = layer.matchPath(path);
|
|
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());
|
|
1380
1922
|
}
|
|
1381
1923
|
}
|
|
1382
1924
|
}
|
|
1383
|
-
if (!match
|
|
1384
|
-
|
|
1385
|
-
return;
|
|
1925
|
+
if (!match) {
|
|
1926
|
+
continue;
|
|
1386
1927
|
}
|
|
1387
|
-
const layerMeta =
|
|
1388
|
-
...meta
|
|
1389
|
-
};
|
|
1928
|
+
const layerMeta = cloneDispatcherMeta(meta);
|
|
1390
1929
|
if (isLayerInstance(layer)) {
|
|
1391
1930
|
const output = layer.exec(path);
|
|
1392
1931
|
if (output) {
|
|
1393
|
-
layerMeta.params =
|
|
1932
|
+
layerMeta.params = mergeDispatcherMetaParams(layerMeta.params, output.params);
|
|
1394
1933
|
layerMeta.mountPath = cleanDoubleSlashes(`${layerMeta.mountPath || ''}/${output.path}`);
|
|
1395
1934
|
}
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
if (isLayerInstance(layer) && layer.isError()) {
|
|
1399
|
-
layer.dispatch(req, res, layerMeta, next, err);
|
|
1400
|
-
return;
|
|
1935
|
+
if (err) {
|
|
1936
|
+
layerMeta.error = err;
|
|
1401
1937
|
}
|
|
1402
|
-
|
|
1403
|
-
|
|
1938
|
+
} else if (err) {
|
|
1939
|
+
continue;
|
|
1404
1940
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
/* istanbul ignore next */ dispatchAsync(req, res) {
|
|
1410
|
-
return new Promise((resolve, reject)=>{
|
|
1411
|
-
this.dispatch(req, res, {}, (err)=>{
|
|
1412
|
-
if (err) {
|
|
1413
|
-
reject(err);
|
|
1414
|
-
return;
|
|
1941
|
+
try {
|
|
1942
|
+
const dispatched = await layer.dispatch(event, layerMeta);
|
|
1943
|
+
if (dispatched) {
|
|
1944
|
+
return true;
|
|
1415
1945
|
}
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1946
|
+
} catch (e) {
|
|
1947
|
+
if (e instanceof Error) {
|
|
1948
|
+
err = e;
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
if (err) {
|
|
1953
|
+
throw err;
|
|
1954
|
+
}
|
|
1955
|
+
if (event.req.method && event.req.method.toLowerCase() === exports.MethodName.OPTIONS) {
|
|
1956
|
+
const options = smob.distinctArray(allowedMethods).map((key)=>key.toUpperCase()).join(',');
|
|
1957
|
+
if (!isResponseGone(event.res)) {
|
|
1958
|
+
event.res.setHeader(exports.HeaderName.ALLOW, options);
|
|
1959
|
+
await send(event.res, options);
|
|
1960
|
+
}
|
|
1961
|
+
return true;
|
|
1962
|
+
}
|
|
1963
|
+
return false;
|
|
1419
1964
|
}
|
|
1420
1965
|
// --------------------------------------------------
|
|
1421
1966
|
route(path) {
|
|
@@ -1429,7 +1974,9 @@ class Router {
|
|
|
1429
1974
|
const route = new Route({
|
|
1430
1975
|
path,
|
|
1431
1976
|
pathMatcher: {
|
|
1432
|
-
|
|
1977
|
+
...this.pathMatcherOptions ? {
|
|
1978
|
+
sensitive: this.pathMatcherOptions.sensitive
|
|
1979
|
+
} : {}
|
|
1433
1980
|
}
|
|
1434
1981
|
});
|
|
1435
1982
|
this.stack.push(route);
|
|
@@ -1484,7 +2031,6 @@ class Router {
|
|
|
1484
2031
|
if (path) {
|
|
1485
2032
|
item.setPath(path);
|
|
1486
2033
|
}
|
|
1487
|
-
item.setPathMatcherOptions(this.pathMatcherOptions);
|
|
1488
2034
|
this.stack.push(item);
|
|
1489
2035
|
continue;
|
|
1490
2036
|
}
|
|
@@ -1494,7 +2040,9 @@ class Router {
|
|
|
1494
2040
|
pathMatcher: {
|
|
1495
2041
|
strict: false,
|
|
1496
2042
|
end: false,
|
|
1497
|
-
|
|
2043
|
+
...this.pathMatcherOptions ? {
|
|
2044
|
+
sensitive: this.pathMatcherOptions.sensitive
|
|
2045
|
+
} : {}
|
|
1498
2046
|
}
|
|
1499
2047
|
}, item));
|
|
1500
2048
|
}
|
|
@@ -1502,21 +2050,17 @@ class Router {
|
|
|
1502
2050
|
return this;
|
|
1503
2051
|
}
|
|
1504
2052
|
// --------------------------------------------------
|
|
1505
|
-
constructor(
|
|
2053
|
+
constructor(options = {}){
|
|
1506
2054
|
this['@instanceof'] = Symbol.for('Router');
|
|
1507
2055
|
/**
|
|
1508
2056
|
* Array of mounted layers, routes & routers.
|
|
1509
2057
|
*
|
|
1510
2058
|
* @protected
|
|
1511
2059
|
*/ this.stack = [];
|
|
1512
|
-
|
|
1513
|
-
this.pathMatcherOptions =
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
...ctx.pathMatcher || {}
|
|
1517
|
-
};
|
|
1518
|
-
this.timeout = ctx.timeout;
|
|
1519
|
-
this.setPath(ctx.path || '/');
|
|
2060
|
+
this.id = generateRouterID();
|
|
2061
|
+
this.pathMatcherOptions = options.pathMatcher;
|
|
2062
|
+
this.setPath(options.path);
|
|
2063
|
+
setRouterOptions(this.id, transformRouterOptions(options));
|
|
1520
2064
|
}
|
|
1521
2065
|
}
|
|
1522
2066
|
|
|
@@ -1526,19 +2070,19 @@ exports.Route = Route;
|
|
|
1526
2070
|
exports.Router = Router;
|
|
1527
2071
|
exports.appendResponseHeader = appendResponseHeader;
|
|
1528
2072
|
exports.appendResponseHeaderDirective = appendResponseHeaderDirective;
|
|
1529
|
-
exports.
|
|
1530
|
-
exports.
|
|
1531
|
-
exports.
|
|
1532
|
-
exports.
|
|
1533
|
-
exports.
|
|
1534
|
-
exports.
|
|
2073
|
+
exports.cloneDispatcherMeta = cloneDispatcherMeta;
|
|
2074
|
+
exports.cloneDispatcherMetaParams = cloneDispatcherMetaParams;
|
|
2075
|
+
exports.createNodeDispatcher = createNodeDispatcher;
|
|
2076
|
+
exports.createRawDispatcher = createRawDispatcher;
|
|
2077
|
+
exports.createRequest = createRequest;
|
|
2078
|
+
exports.createResponse = createResponse;
|
|
2079
|
+
exports.createWebDispatcher = createWebDispatcher;
|
|
2080
|
+
exports.dispatchNodeRequest = dispatchNodeRequest;
|
|
2081
|
+
exports.dispatchRawRequest = dispatchRawRequest;
|
|
2082
|
+
exports.dispatchWebRequest = dispatchWebRequest;
|
|
1535
2083
|
exports.extendRequestBody = extendRequestBody;
|
|
1536
2084
|
exports.extendRequestCookies = extendRequestCookies;
|
|
1537
2085
|
exports.extendRequestQuery = extendRequestQuery;
|
|
1538
|
-
exports.generateETag = generateETag;
|
|
1539
|
-
exports.getCharsetForMimeType = getCharsetForMimeType;
|
|
1540
|
-
exports.getConfigOption = getConfigOption;
|
|
1541
|
-
exports.getMimeType = getMimeType;
|
|
1542
2086
|
exports.getRequestAcceptableCharset = getRequestAcceptableCharset;
|
|
1543
2087
|
exports.getRequestAcceptableCharsets = getRequestAcceptableCharsets;
|
|
1544
2088
|
exports.getRequestAcceptableContentType = getRequestAcceptableContentType;
|
|
@@ -1551,22 +2095,17 @@ exports.getRequestHeader = getRequestHeader;
|
|
|
1551
2095
|
exports.getRequestHostName = getRequestHostName;
|
|
1552
2096
|
exports.getRequestIP = getRequestIP;
|
|
1553
2097
|
exports.getRequestProtocol = getRequestProtocol;
|
|
1554
|
-
exports.hasLeadingSlash = hasLeadingSlash;
|
|
1555
2098
|
exports.hasRequestBody = hasRequestBody;
|
|
1556
2099
|
exports.hasRequestCookies = hasRequestCookies;
|
|
1557
2100
|
exports.hasRequestQuery = hasRequestQuery;
|
|
1558
|
-
exports.hasTrailingSlash = hasTrailingSlash;
|
|
1559
|
-
exports.isInstance = isInstance;
|
|
1560
2101
|
exports.isLayerInstance = isLayerInstance;
|
|
1561
|
-
exports.isObject = isObject;
|
|
1562
2102
|
exports.isPath = isPath;
|
|
1563
|
-
exports.isPromise = isPromise;
|
|
1564
2103
|
exports.isRequestCacheable = isRequestCacheable;
|
|
2104
|
+
exports.isResponseGone = isResponseGone;
|
|
1565
2105
|
exports.isRouteInstance = isRouteInstance;
|
|
1566
2106
|
exports.isRouterInstance = isRouterInstance;
|
|
1567
2107
|
exports.matchRequestContentType = matchRequestContentType;
|
|
1568
|
-
exports.
|
|
1569
|
-
exports.processHandlerExecutionOutput = processHandlerExecutionOutput;
|
|
2108
|
+
exports.mergeDispatcherMetaParams = mergeDispatcherMetaParams;
|
|
1570
2109
|
exports.send = send;
|
|
1571
2110
|
exports.sendAccepted = sendAccepted;
|
|
1572
2111
|
exports.sendCreated = sendCreated;
|
|
@@ -1574,8 +2113,8 @@ exports.sendFile = sendFile;
|
|
|
1574
2113
|
exports.sendFormat = sendFormat;
|
|
1575
2114
|
exports.sendRedirect = sendRedirect;
|
|
1576
2115
|
exports.sendStream = sendStream;
|
|
1577
|
-
exports.
|
|
1578
|
-
exports.
|
|
2116
|
+
exports.sendWebBlob = sendWebBlob;
|
|
2117
|
+
exports.sendWebResponse = sendWebResponse;
|
|
1579
2118
|
exports.setRequestBody = setRequestBody;
|
|
1580
2119
|
exports.setRequestCookies = setRequestCookies;
|
|
1581
2120
|
exports.setRequestEnv = setRequestEnv;
|
|
@@ -1584,12 +2123,12 @@ exports.setRequestMountPath = setRequestMountPath;
|
|
|
1584
2123
|
exports.setRequestParam = setRequestParam;
|
|
1585
2124
|
exports.setRequestParams = setRequestParams;
|
|
1586
2125
|
exports.setRequestQuery = setRequestQuery;
|
|
2126
|
+
exports.setRequestRouterIds = setRequestRouterIds;
|
|
1587
2127
|
exports.setResponseCacheHeaders = setResponseCacheHeaders;
|
|
1588
2128
|
exports.setResponseContentTypeByFileName = setResponseContentTypeByFileName;
|
|
1589
2129
|
exports.setResponseHeaderAttachment = setResponseHeaderAttachment;
|
|
1590
2130
|
exports.setResponseHeaderContentType = setResponseHeaderContentType;
|
|
1591
2131
|
exports.unsetRequestEnv = unsetRequestEnv;
|
|
1592
|
-
exports.useConfig = useConfig;
|
|
1593
2132
|
exports.useRequestBody = useRequestBody;
|
|
1594
2133
|
exports.useRequestCookie = useRequestCookie;
|
|
1595
2134
|
exports.useRequestCookies = useRequestCookies;
|
|
@@ -1600,8 +2139,5 @@ exports.useRequestParam = useRequestParam;
|
|
|
1600
2139
|
exports.useRequestParams = useRequestParams;
|
|
1601
2140
|
exports.useRequestPath = useRequestPath;
|
|
1602
2141
|
exports.useRequestQuery = useRequestQuery;
|
|
1603
|
-
exports.
|
|
1604
|
-
exports.withTrailingSlash = withTrailingSlash;
|
|
1605
|
-
exports.withoutLeadingSlash = withoutLeadingSlash;
|
|
1606
|
-
exports.withoutTrailingSlash = withoutTrailingSlash;
|
|
2142
|
+
exports.useRequestRouterIds = useRequestRouterIds;
|
|
1607
2143
|
//# sourceMappingURL=index.cjs.map
|