routup 1.0.2 → 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 +1075 -538
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.mjs +1054 -509
- 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 +17 -16
- 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,10 +770,10 @@ 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);
|
|
776
|
+
return addrs[addrs.length - 1];
|
|
579
777
|
}
|
|
580
778
|
|
|
581
779
|
const ReqMountPathSymbol = Symbol.for('ReqMountPath');
|
|
@@ -622,7 +820,7 @@ function useRequestPath(req) {
|
|
|
622
820
|
if (typeof req.url === 'undefined') {
|
|
623
821
|
return '/';
|
|
624
822
|
}
|
|
625
|
-
const parsed = new
|
|
823
|
+
const parsed = new URL(req.url, 'http://localhost/');
|
|
626
824
|
req[PathSymbol] = parsed.pathname;
|
|
627
825
|
return req[PathSymbol];
|
|
628
826
|
}
|
|
@@ -633,8 +831,7 @@ function getRequestProtocol(req, options) {
|
|
|
633
831
|
if (typeof options.trustProxy !== 'undefined') {
|
|
634
832
|
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
635
833
|
} else {
|
|
636
|
-
|
|
637
|
-
trustProxy = config.get('trustProxy');
|
|
834
|
+
trustProxy = findRouterOption('trustProxy', useRequestRouterIds(req));
|
|
638
835
|
}
|
|
639
836
|
let protocol = options.default;
|
|
640
837
|
/* istanbul ignore next */ if (smob.hasOwnProperty(req.socket, 'encrypted') && !!req.socket.encrypted) {
|
|
@@ -702,121 +899,7 @@ function extendRequestQuery(req, key, value) {
|
|
|
702
899
|
setRequestQuery(req, key, value);
|
|
703
900
|
}
|
|
704
901
|
|
|
705
|
-
function
|
|
706
|
-
options = options || {};
|
|
707
|
-
const cacheControls = [
|
|
708
|
-
'public'
|
|
709
|
-
].concat(options.cacheControls || []);
|
|
710
|
-
if (options.maxAge !== undefined) {
|
|
711
|
-
cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);
|
|
712
|
-
}
|
|
713
|
-
if (options.modifiedTime) {
|
|
714
|
-
const modifiedTime = typeof options.modifiedTime === 'string' ? new Date(options.modifiedTime) : options.modifiedTime;
|
|
715
|
-
res.setHeader('last-modified', modifiedTime.toUTCString());
|
|
716
|
-
}
|
|
717
|
-
res.setHeader('cache-control', cacheControls.join(', '));
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
function appendResponseHeader(res, name, value) {
|
|
721
|
-
let header = res.getHeader(name);
|
|
722
|
-
if (!header) {
|
|
723
|
-
res.setHeader(name, value);
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
if (!Array.isArray(header)) {
|
|
727
|
-
header = [
|
|
728
|
-
header.toString()
|
|
729
|
-
];
|
|
730
|
-
}
|
|
731
|
-
res.setHeader(name, [
|
|
732
|
-
...header,
|
|
733
|
-
value
|
|
734
|
-
]);
|
|
735
|
-
}
|
|
736
|
-
function appendResponseHeaderDirective(res, name, value) {
|
|
737
|
-
let header = res.getHeader(name);
|
|
738
|
-
if (!header) {
|
|
739
|
-
if (Array.isArray(value)) {
|
|
740
|
-
res.setHeader(name, value.join('; '));
|
|
741
|
-
return;
|
|
742
|
-
}
|
|
743
|
-
res.setHeader(name, value);
|
|
744
|
-
return;
|
|
745
|
-
}
|
|
746
|
-
if (!Array.isArray(header)) {
|
|
747
|
-
if (typeof header === 'string') {
|
|
748
|
-
// split header by directive(s)
|
|
749
|
-
header = header.split('; ');
|
|
750
|
-
}
|
|
751
|
-
if (typeof header === 'number') {
|
|
752
|
-
header = [
|
|
753
|
-
header.toString()
|
|
754
|
-
];
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
if (Array.isArray(value)) {
|
|
758
|
-
header.push(...value);
|
|
759
|
-
} else {
|
|
760
|
-
header.push(`${value}`);
|
|
761
|
-
}
|
|
762
|
-
header = [
|
|
763
|
-
...new Set(header)
|
|
764
|
-
];
|
|
765
|
-
res.setHeader(name, header.join('; '));
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
function setResponseContentTypeByFileName(res, fileName) {
|
|
769
|
-
const ext = path.extname(fileName);
|
|
770
|
-
if (ext) {
|
|
771
|
-
let type = getMimeType(ext.substring(1));
|
|
772
|
-
if (type) {
|
|
773
|
-
const charset = getCharsetForMimeType(type);
|
|
774
|
-
if (charset) {
|
|
775
|
-
type += `; charset=${charset}`;
|
|
776
|
-
}
|
|
777
|
-
res.setHeader(exports.HeaderName.CONTENT_TYPE, type);
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
/* istanbul ignore next */ function onResponseFinished(res, cb) {
|
|
782
|
-
let called;
|
|
783
|
-
const callCallback = (err)=>{
|
|
784
|
-
if (called) return;
|
|
785
|
-
called = true;
|
|
786
|
-
cb(err);
|
|
787
|
-
};
|
|
788
|
-
res.on('finish', ()=>{
|
|
789
|
-
callCallback();
|
|
790
|
-
});
|
|
791
|
-
res.on('close', ()=>{
|
|
792
|
-
callCallback();
|
|
793
|
-
});
|
|
794
|
-
res.on('error', (err)=>{
|
|
795
|
-
callCallback(err);
|
|
796
|
-
});
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
function setResponseHeaderAttachment(res, filename) {
|
|
800
|
-
if (typeof filename === 'string') {
|
|
801
|
-
setResponseContentTypeByFileName(res, filename);
|
|
802
|
-
}
|
|
803
|
-
res.setHeader(exports.HeaderName.CONTENT_DISPOSITION, `attachment${filename ? `; filename="${filename}"` : ''}`);
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
function setResponseHeaderContentType(res, input, ifNotExists) {
|
|
807
|
-
if (ifNotExists) {
|
|
808
|
-
const header = res.getHeader(exports.HeaderName.CONTENT_TYPE);
|
|
809
|
-
if (header) {
|
|
810
|
-
return;
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
const contentType = getMimeType(input);
|
|
814
|
-
if (contentType) {
|
|
815
|
-
res.setHeader(exports.HeaderName.CONTENT_TYPE, contentType);
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
function send(res, chunk) {
|
|
902
|
+
async function send(res, chunk) {
|
|
820
903
|
switch(typeof chunk){
|
|
821
904
|
case 'string':
|
|
822
905
|
{
|
|
@@ -829,7 +912,7 @@ function send(res, chunk) {
|
|
|
829
912
|
{
|
|
830
913
|
if (chunk === null) {
|
|
831
914
|
chunk = '';
|
|
832
|
-
} else if (Buffer.isBuffer(chunk)) {
|
|
915
|
+
} else if (buffer.Buffer.isBuffer(chunk)) {
|
|
833
916
|
setResponseHeaderContentType(res, 'bin', true);
|
|
834
917
|
} else {
|
|
835
918
|
chunk = JSON.stringify(chunk);
|
|
@@ -847,24 +930,26 @@ function send(res, chunk) {
|
|
|
847
930
|
// populate Content-Length
|
|
848
931
|
let len;
|
|
849
932
|
if (chunk !== undefined) {
|
|
850
|
-
if (Buffer.isBuffer(chunk)) {
|
|
933
|
+
if (buffer.Buffer.isBuffer(chunk)) {
|
|
851
934
|
// get length of Buffer
|
|
852
935
|
len = chunk.length;
|
|
853
936
|
} else if (chunk.length < 1000) {
|
|
854
937
|
// just calculate length when no ETag + small chunk
|
|
855
|
-
len = Buffer.byteLength(chunk, encoding);
|
|
938
|
+
len = buffer.Buffer.byteLength(chunk, encoding);
|
|
856
939
|
} else {
|
|
857
940
|
// convert chunk to Buffer and calculate
|
|
858
|
-
chunk = Buffer.from(chunk, encoding);
|
|
941
|
+
chunk = buffer.Buffer.from(chunk, encoding);
|
|
859
942
|
encoding = undefined;
|
|
860
943
|
len = chunk.length;
|
|
861
944
|
}
|
|
862
945
|
res.setHeader(exports.HeaderName.CONTENT_LENGTH, `${len}`);
|
|
863
946
|
}
|
|
864
|
-
const config = useConfig();
|
|
865
|
-
const etagFn = config.get('etag');
|
|
866
947
|
if (typeof len !== 'undefined') {
|
|
867
|
-
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
|
+
}
|
|
868
953
|
if (typeof chunkHash === 'string') {
|
|
869
954
|
res.setHeader(exports.HeaderName.ETag, chunkHash);
|
|
870
955
|
if (res.req.headers[exports.HeaderName.IF_NONE_MATCH] === chunkHash) {
|
|
@@ -885,16 +970,20 @@ function send(res, chunk) {
|
|
|
885
970
|
res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
|
|
886
971
|
chunk = '';
|
|
887
972
|
}
|
|
973
|
+
if (isResponseGone(res)) {
|
|
974
|
+
return Promise.resolve();
|
|
975
|
+
}
|
|
888
976
|
if (res.req.method === 'HEAD') {
|
|
889
977
|
// skip body for HEAD
|
|
890
978
|
res.end();
|
|
891
|
-
return;
|
|
979
|
+
return Promise.resolve();
|
|
892
980
|
}
|
|
893
981
|
if (typeof encoding !== 'undefined') {
|
|
894
982
|
res.end(chunk, encoding);
|
|
895
|
-
return;
|
|
983
|
+
return Promise.resolve();
|
|
896
984
|
}
|
|
897
985
|
res.end(chunk);
|
|
986
|
+
return Promise.resolve();
|
|
898
987
|
}
|
|
899
988
|
|
|
900
989
|
function sendAccepted(res, chunk) {
|
|
@@ -909,87 +998,116 @@ function sendCreated(res, chunk) {
|
|
|
909
998
|
return send(res, chunk);
|
|
910
999
|
}
|
|
911
1000
|
|
|
912
|
-
function sendStream(res, stream,
|
|
913
|
-
|
|
914
|
-
stream.
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
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
|
+
}
|
|
921
1011
|
res.end();
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
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
|
+
}
|
|
928
1029
|
res.end();
|
|
929
|
-
|
|
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
|
+
});
|
|
930
1040
|
});
|
|
931
1041
|
}
|
|
932
1042
|
|
|
933
|
-
function
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
function sendFile(res, filePath, fn) {
|
|
941
|
-
let options;
|
|
942
|
-
if (typeof filePath === 'string') {
|
|
943
|
-
options = {
|
|
944
|
-
filePath
|
|
945
|
-
};
|
|
946
|
-
} else {
|
|
947
|
-
options = filePath;
|
|
948
|
-
}
|
|
949
|
-
const fileName = path.basename(options.filePath);
|
|
950
|
-
if (options.attachment) {
|
|
951
|
-
const dispositionHeader = res.getHeader(exports.HeaderName.CONTENT_DISPOSITION);
|
|
952
|
-
if (!dispositionHeader) {
|
|
953
|
-
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);
|
|
954
1050
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
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);
|
|
965
1063
|
}
|
|
966
|
-
|
|
1064
|
+
} else {
|
|
1065
|
+
setResponseContentTypeByFileName(res, fileName);
|
|
967
1066
|
}
|
|
968
|
-
|
|
1067
|
+
}
|
|
1068
|
+
const contentOptions = {};
|
|
1069
|
+
if (stats.size) {
|
|
969
1070
|
const rangeHeader = res.req.headers[exports.HeaderName.RANGE];
|
|
970
1071
|
if (rangeHeader) {
|
|
971
1072
|
const [x, y] = rangeHeader.replace('bytes=', '').split('-');
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
if (
|
|
975
|
-
|
|
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;
|
|
976
1077
|
}
|
|
977
|
-
if (
|
|
1078
|
+
if (contentOptions.start >= stats.size) {
|
|
978
1079
|
res.setHeader(exports.HeaderName.CONTENT_RANGE, `bytes */${stats.size}`);
|
|
979
1080
|
res.statusCode = 416;
|
|
980
1081
|
res.end();
|
|
981
|
-
return;
|
|
1082
|
+
return Promise.resolve();
|
|
982
1083
|
}
|
|
983
|
-
res.setHeader(exports.HeaderName.CONTENT_RANGE, `bytes ${
|
|
984
|
-
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);
|
|
985
1086
|
} else {
|
|
986
1087
|
res.setHeader(exports.HeaderName.CONTENT_LENGTH, stats.size);
|
|
987
1088
|
}
|
|
988
1089
|
res.setHeader(exports.HeaderName.ACCEPT_RANGES, 'bytes');
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
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
|
+
}
|
|
993
1111
|
}
|
|
994
1112
|
|
|
995
1113
|
function sendFormat(res, input) {
|
|
@@ -1011,19 +1129,406 @@ function sendRedirect(res, location, statusCode = 302) {
|
|
|
1011
1129
|
return send(res, html);
|
|
1012
1130
|
}
|
|
1013
1131
|
|
|
1014
|
-
function
|
|
1015
|
-
if (
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
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;
|
|
1019
1174
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
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
|
+
};
|
|
1023
1450
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
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;
|
|
1026
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;
|
|
1027
1532
|
}
|
|
1028
1533
|
|
|
1029
1534
|
function decodeParam(val) {
|
|
@@ -1087,48 +1592,98 @@ class PathMatcher {
|
|
|
1087
1592
|
}
|
|
1088
1593
|
}
|
|
1089
1594
|
|
|
1595
|
+
function isPath(input) {
|
|
1596
|
+
return typeof input === 'string' || input instanceof RegExp;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1090
1599
|
class Layer {
|
|
1091
1600
|
// --------------------------------------------------
|
|
1092
1601
|
isError() {
|
|
1093
1602
|
return this.fn.length === 4;
|
|
1094
1603
|
}
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
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();
|
|
1109
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;
|
|
1110
1666
|
}
|
|
1111
|
-
|
|
1667
|
+
Promise.resolve().then(()=>handle(output)).catch((e)=>reject(createError(e)));
|
|
1668
|
+
} catch (error) {
|
|
1669
|
+
onNext(error);
|
|
1112
1670
|
}
|
|
1113
|
-
|
|
1114
|
-
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
sendOutput(res, input) {
|
|
1674
|
+
if (input instanceof Error) {
|
|
1675
|
+
return Promise.reject(input);
|
|
1115
1676
|
}
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
return;
|
|
1677
|
+
if (isStream(input)) {
|
|
1678
|
+
return sendStream(res, input);
|
|
1119
1679
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
next(e);
|
|
1126
|
-
} else {
|
|
1127
|
-
next(new http.BadRequestError({
|
|
1128
|
-
message: 'The request could not be processed by the handler.'
|
|
1129
|
-
}));
|
|
1130
|
-
}
|
|
1680
|
+
if (isWebBlob(input)) {
|
|
1681
|
+
return sendWebBlob(res, input);
|
|
1682
|
+
}
|
|
1683
|
+
if (isWebResponse(input)) {
|
|
1684
|
+
return sendWebResponse(res, input);
|
|
1131
1685
|
}
|
|
1686
|
+
return send(res, input);
|
|
1132
1687
|
}
|
|
1133
1688
|
// --------------------------------------------------
|
|
1134
1689
|
matchPath(path) {
|
|
@@ -1146,6 +1701,9 @@ class Layer {
|
|
|
1146
1701
|
}
|
|
1147
1702
|
|
|
1148
1703
|
function isLayerInstance(input) {
|
|
1704
|
+
if (input instanceof Layer) {
|
|
1705
|
+
return true;
|
|
1706
|
+
}
|
|
1149
1707
|
return isInstance(input, 'Layer');
|
|
1150
1708
|
}
|
|
1151
1709
|
|
|
@@ -1170,44 +1728,46 @@ class Route {
|
|
|
1170
1728
|
return keys;
|
|
1171
1729
|
}
|
|
1172
1730
|
// --------------------------------------------------
|
|
1173
|
-
dispatch(
|
|
1174
|
-
/* istanbul ignore next */ if (!req.method) {
|
|
1175
|
-
|
|
1176
|
-
return;
|
|
1731
|
+
async dispatch(event, meta) {
|
|
1732
|
+
/* istanbul ignore next */ if (!event.req.method) {
|
|
1733
|
+
return false;
|
|
1177
1734
|
}
|
|
1178
|
-
let name = req.method.toLowerCase();
|
|
1735
|
+
let name = event.req.method.toLowerCase();
|
|
1179
1736
|
if (name === exports.MethodName.HEAD && !smob.hasOwnProperty(this.layers, name)) {
|
|
1180
1737
|
name = exports.MethodName.GET;
|
|
1181
1738
|
}
|
|
1182
1739
|
const layers = this.layers[name];
|
|
1183
1740
|
/* istanbul ignore next */ if (typeof layers === 'undefined' || layers.length === 0 || typeof meta.path === 'undefined') {
|
|
1184
|
-
|
|
1185
|
-
return;
|
|
1741
|
+
return false;
|
|
1186
1742
|
}
|
|
1187
|
-
const layerMeta =
|
|
1188
|
-
...meta
|
|
1189
|
-
};
|
|
1743
|
+
const layerMeta = cloneDispatcherMeta(meta);
|
|
1190
1744
|
const output = this.pathMatcher.exec(meta.path);
|
|
1191
1745
|
if (output) {
|
|
1192
|
-
layerMeta.params =
|
|
1746
|
+
layerMeta.params = mergeDispatcherMetaParams(layerMeta.params, output.params);
|
|
1193
1747
|
}
|
|
1194
|
-
let
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
if (index >= layers.length) {
|
|
1198
|
-
setImmediate(done, err);
|
|
1199
|
-
return;
|
|
1200
|
-
}
|
|
1201
|
-
const layer = layers[index];
|
|
1748
|
+
let err;
|
|
1749
|
+
for(let i = 0; i < layers.length; i++){
|
|
1750
|
+
const layer = layers[i];
|
|
1202
1751
|
if (err && !layer.isError()) {
|
|
1203
|
-
|
|
1204
|
-
return;
|
|
1752
|
+
continue;
|
|
1205
1753
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
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;
|
|
1211
1771
|
}
|
|
1212
1772
|
// --------------------------------------------------
|
|
1213
1773
|
register(method, ...handlers) {
|
|
@@ -1260,42 +1820,50 @@ class Route {
|
|
|
1260
1820
|
}
|
|
1261
1821
|
|
|
1262
1822
|
function isRouteInstance(input) {
|
|
1823
|
+
if (input instanceof Route) {
|
|
1824
|
+
return true;
|
|
1825
|
+
}
|
|
1263
1826
|
return isInstance(input, 'Route');
|
|
1264
1827
|
}
|
|
1265
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
|
+
|
|
1266
1844
|
function isRouterInstance(input) {
|
|
1845
|
+
if (input instanceof Router) {
|
|
1846
|
+
return true;
|
|
1847
|
+
}
|
|
1267
1848
|
return isInstance(input, 'Router');
|
|
1268
1849
|
}
|
|
1269
1850
|
class Router {
|
|
1270
1851
|
// --------------------------------------------------
|
|
1271
|
-
setPathMatcherOptions(input) {
|
|
1272
|
-
this.pathMatcherOptions = input;
|
|
1273
|
-
if (this.pathMatcher) {
|
|
1274
|
-
this.pathMatcher.regexpOptions = this.pathMatcherOptions;
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
1852
|
setPath(value) {
|
|
1278
1853
|
if (value === '/' || !isPath(value)) {
|
|
1279
|
-
this.path = '/';
|
|
1280
1854
|
return;
|
|
1281
1855
|
}
|
|
1856
|
+
let path;
|
|
1282
1857
|
if (typeof value === 'string') {
|
|
1283
|
-
|
|
1858
|
+
path = withLeadingSlash(withoutTrailingSlash(`${value}`));
|
|
1284
1859
|
} else {
|
|
1285
|
-
|
|
1860
|
+
path = value;
|
|
1286
1861
|
}
|
|
1287
|
-
this.pathMatcher = new PathMatcher(
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
return (req, res)=>{
|
|
1293
|
-
this.dispatch(req, res);
|
|
1294
|
-
};
|
|
1295
|
-
}
|
|
1296
|
-
/* istanbul ignore next */ listen(port) {
|
|
1297
|
-
const server = node_http.createServer(this.createListener());
|
|
1298
|
-
return server.listen(port);
|
|
1862
|
+
this.pathMatcher = new PathMatcher(path, {
|
|
1863
|
+
end: false,
|
|
1864
|
+
sensitive: false,
|
|
1865
|
+
...this.pathMatcherOptions ? this.pathMatcherOptions : {}
|
|
1866
|
+
});
|
|
1299
1867
|
}
|
|
1300
1868
|
// --------------------------------------------------
|
|
1301
1869
|
matchPath(path) {
|
|
@@ -1305,35 +1873,9 @@ class Router {
|
|
|
1305
1873
|
return true;
|
|
1306
1874
|
}
|
|
1307
1875
|
// --------------------------------------------------
|
|
1308
|
-
dispatch(
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
let allowedMethods = [];
|
|
1312
|
-
if (this.isRoot && typeof this.timeout === 'number') {
|
|
1313
|
-
createRequestTimeout(res, this.timeout, done);
|
|
1314
|
-
}
|
|
1315
|
-
const fn = (err)=>{
|
|
1316
|
-
/* istanbul ignore if */ if (!this.isRoot) {
|
|
1317
|
-
if (typeof done !== 'undefined') {
|
|
1318
|
-
setImmediate(()=>done(err));
|
|
1319
|
-
}
|
|
1320
|
-
return;
|
|
1321
|
-
}
|
|
1322
|
-
if (typeof err !== 'undefined') {
|
|
1323
|
-
res.statusCode = 400;
|
|
1324
|
-
res.end();
|
|
1325
|
-
return;
|
|
1326
|
-
}
|
|
1327
|
-
if (req.method && req.method.toLowerCase() === exports.MethodName.OPTIONS) {
|
|
1328
|
-
const options = allowedMethods.map((key)=>key.toUpperCase()).join(',');
|
|
1329
|
-
res.setHeader(exports.HeaderName.ALLOW, options);
|
|
1330
|
-
send(res, options);
|
|
1331
|
-
return;
|
|
1332
|
-
}
|
|
1333
|
-
res.statusCode = 404;
|
|
1334
|
-
res.end();
|
|
1335
|
-
};
|
|
1336
|
-
let path = meta.path || useRequestPath(req);
|
|
1876
|
+
async dispatch(event, meta = {}) {
|
|
1877
|
+
const allowedMethods = [];
|
|
1878
|
+
let path = meta.path || useRequestPath(event.req);
|
|
1337
1879
|
if (this.pathMatcher) {
|
|
1338
1880
|
const output = this.pathMatcher.exec(path);
|
|
1339
1881
|
if (typeof output !== 'undefined') {
|
|
@@ -1347,74 +1889,78 @@ class Router {
|
|
|
1347
1889
|
}
|
|
1348
1890
|
}
|
|
1349
1891
|
meta.path = path;
|
|
1892
|
+
if (meta.routerIds) {
|
|
1893
|
+
meta.routerIds.push(this.id);
|
|
1894
|
+
} else {
|
|
1895
|
+
meta.routerIds = [
|
|
1896
|
+
this.id
|
|
1897
|
+
];
|
|
1898
|
+
}
|
|
1350
1899
|
if (!meta.mountPath) {
|
|
1351
1900
|
meta.mountPath = '/';
|
|
1352
1901
|
}
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
index++;
|
|
1362
|
-
layer = this.stack[index];
|
|
1363
|
-
if (isLayerInstance(layer)) {
|
|
1364
|
-
if (!layer.isError() && err) {
|
|
1365
|
-
continue;
|
|
1366
|
-
}
|
|
1367
|
-
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;
|
|
1368
1910
|
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
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());
|
|
1379
1922
|
}
|
|
1380
1923
|
}
|
|
1381
1924
|
}
|
|
1382
|
-
if (!match
|
|
1383
|
-
|
|
1384
|
-
return;
|
|
1925
|
+
if (!match) {
|
|
1926
|
+
continue;
|
|
1385
1927
|
}
|
|
1386
|
-
const layerMeta =
|
|
1387
|
-
...meta
|
|
1388
|
-
};
|
|
1928
|
+
const layerMeta = cloneDispatcherMeta(meta);
|
|
1389
1929
|
if (isLayerInstance(layer)) {
|
|
1390
1930
|
const output = layer.exec(path);
|
|
1391
1931
|
if (output) {
|
|
1392
|
-
layerMeta.params =
|
|
1932
|
+
layerMeta.params = mergeDispatcherMetaParams(layerMeta.params, output.params);
|
|
1393
1933
|
layerMeta.mountPath = cleanDoubleSlashes(`${layerMeta.mountPath || ''}/${output.path}`);
|
|
1394
1934
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
if (isLayerInstance(layer) && layer.isError()) {
|
|
1398
|
-
layer.dispatch(req, res, layerMeta, next, err);
|
|
1399
|
-
return;
|
|
1935
|
+
if (err) {
|
|
1936
|
+
layerMeta.error = err;
|
|
1400
1937
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1938
|
+
} else if (err) {
|
|
1939
|
+
continue;
|
|
1403
1940
|
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
/* istanbul ignore next */ dispatchAsync(req, res) {
|
|
1409
|
-
return new Promise((resolve, reject)=>{
|
|
1410
|
-
this.dispatch(req, res, {}, (err)=>{
|
|
1411
|
-
if (err) {
|
|
1412
|
-
reject(err);
|
|
1413
|
-
return;
|
|
1941
|
+
try {
|
|
1942
|
+
const dispatched = await layer.dispatch(event, layerMeta);
|
|
1943
|
+
if (dispatched) {
|
|
1944
|
+
return true;
|
|
1414
1945
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
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;
|
|
1418
1964
|
}
|
|
1419
1965
|
// --------------------------------------------------
|
|
1420
1966
|
route(path) {
|
|
@@ -1428,7 +1974,9 @@ class Router {
|
|
|
1428
1974
|
const route = new Route({
|
|
1429
1975
|
path,
|
|
1430
1976
|
pathMatcher: {
|
|
1431
|
-
|
|
1977
|
+
...this.pathMatcherOptions ? {
|
|
1978
|
+
sensitive: this.pathMatcherOptions.sensitive
|
|
1979
|
+
} : {}
|
|
1432
1980
|
}
|
|
1433
1981
|
});
|
|
1434
1982
|
this.stack.push(route);
|
|
@@ -1483,7 +2031,6 @@ class Router {
|
|
|
1483
2031
|
if (path) {
|
|
1484
2032
|
item.setPath(path);
|
|
1485
2033
|
}
|
|
1486
|
-
item.setPathMatcherOptions(this.pathMatcherOptions);
|
|
1487
2034
|
this.stack.push(item);
|
|
1488
2035
|
continue;
|
|
1489
2036
|
}
|
|
@@ -1493,7 +2040,9 @@ class Router {
|
|
|
1493
2040
|
pathMatcher: {
|
|
1494
2041
|
strict: false,
|
|
1495
2042
|
end: false,
|
|
1496
|
-
|
|
2043
|
+
...this.pathMatcherOptions ? {
|
|
2044
|
+
sensitive: this.pathMatcherOptions.sensitive
|
|
2045
|
+
} : {}
|
|
1497
2046
|
}
|
|
1498
2047
|
}, item));
|
|
1499
2048
|
}
|
|
@@ -1501,21 +2050,17 @@ class Router {
|
|
|
1501
2050
|
return this;
|
|
1502
2051
|
}
|
|
1503
2052
|
// --------------------------------------------------
|
|
1504
|
-
constructor(
|
|
2053
|
+
constructor(options = {}){
|
|
1505
2054
|
this['@instanceof'] = Symbol.for('Router');
|
|
1506
2055
|
/**
|
|
1507
2056
|
* Array of mounted layers, routes & routers.
|
|
1508
2057
|
*
|
|
1509
2058
|
* @protected
|
|
1510
2059
|
*/ this.stack = [];
|
|
1511
|
-
|
|
1512
|
-
this.pathMatcherOptions =
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
...ctx.pathMatcher || {}
|
|
1516
|
-
};
|
|
1517
|
-
this.timeout = ctx.timeout;
|
|
1518
|
-
this.setPath(ctx.path || '/');
|
|
2060
|
+
this.id = generateRouterID();
|
|
2061
|
+
this.pathMatcherOptions = options.pathMatcher;
|
|
2062
|
+
this.setPath(options.path);
|
|
2063
|
+
setRouterOptions(this.id, transformRouterOptions(options));
|
|
1519
2064
|
}
|
|
1520
2065
|
}
|
|
1521
2066
|
|
|
@@ -1525,19 +2070,19 @@ exports.Route = Route;
|
|
|
1525
2070
|
exports.Router = Router;
|
|
1526
2071
|
exports.appendResponseHeader = appendResponseHeader;
|
|
1527
2072
|
exports.appendResponseHeaderDirective = appendResponseHeaderDirective;
|
|
1528
|
-
exports.
|
|
1529
|
-
exports.
|
|
1530
|
-
exports.
|
|
1531
|
-
exports.
|
|
1532
|
-
exports.
|
|
1533
|
-
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;
|
|
1534
2083
|
exports.extendRequestBody = extendRequestBody;
|
|
1535
2084
|
exports.extendRequestCookies = extendRequestCookies;
|
|
1536
2085
|
exports.extendRequestQuery = extendRequestQuery;
|
|
1537
|
-
exports.generateETag = generateETag;
|
|
1538
|
-
exports.getCharsetForMimeType = getCharsetForMimeType;
|
|
1539
|
-
exports.getConfigOption = getConfigOption;
|
|
1540
|
-
exports.getMimeType = getMimeType;
|
|
1541
2086
|
exports.getRequestAcceptableCharset = getRequestAcceptableCharset;
|
|
1542
2087
|
exports.getRequestAcceptableCharsets = getRequestAcceptableCharsets;
|
|
1543
2088
|
exports.getRequestAcceptableContentType = getRequestAcceptableContentType;
|
|
@@ -1550,22 +2095,17 @@ exports.getRequestHeader = getRequestHeader;
|
|
|
1550
2095
|
exports.getRequestHostName = getRequestHostName;
|
|
1551
2096
|
exports.getRequestIP = getRequestIP;
|
|
1552
2097
|
exports.getRequestProtocol = getRequestProtocol;
|
|
1553
|
-
exports.hasLeadingSlash = hasLeadingSlash;
|
|
1554
2098
|
exports.hasRequestBody = hasRequestBody;
|
|
1555
2099
|
exports.hasRequestCookies = hasRequestCookies;
|
|
1556
2100
|
exports.hasRequestQuery = hasRequestQuery;
|
|
1557
|
-
exports.hasTrailingSlash = hasTrailingSlash;
|
|
1558
|
-
exports.isInstance = isInstance;
|
|
1559
2101
|
exports.isLayerInstance = isLayerInstance;
|
|
1560
|
-
exports.isObject = isObject;
|
|
1561
2102
|
exports.isPath = isPath;
|
|
1562
|
-
exports.isPromise = isPromise;
|
|
1563
2103
|
exports.isRequestCacheable = isRequestCacheable;
|
|
2104
|
+
exports.isResponseGone = isResponseGone;
|
|
1564
2105
|
exports.isRouteInstance = isRouteInstance;
|
|
1565
2106
|
exports.isRouterInstance = isRouterInstance;
|
|
1566
2107
|
exports.matchRequestContentType = matchRequestContentType;
|
|
1567
|
-
exports.
|
|
1568
|
-
exports.processHandlerExecutionOutput = processHandlerExecutionOutput;
|
|
2108
|
+
exports.mergeDispatcherMetaParams = mergeDispatcherMetaParams;
|
|
1569
2109
|
exports.send = send;
|
|
1570
2110
|
exports.sendAccepted = sendAccepted;
|
|
1571
2111
|
exports.sendCreated = sendCreated;
|
|
@@ -1573,8 +2113,8 @@ exports.sendFile = sendFile;
|
|
|
1573
2113
|
exports.sendFormat = sendFormat;
|
|
1574
2114
|
exports.sendRedirect = sendRedirect;
|
|
1575
2115
|
exports.sendStream = sendStream;
|
|
1576
|
-
exports.
|
|
1577
|
-
exports.
|
|
2116
|
+
exports.sendWebBlob = sendWebBlob;
|
|
2117
|
+
exports.sendWebResponse = sendWebResponse;
|
|
1578
2118
|
exports.setRequestBody = setRequestBody;
|
|
1579
2119
|
exports.setRequestCookies = setRequestCookies;
|
|
1580
2120
|
exports.setRequestEnv = setRequestEnv;
|
|
@@ -1583,12 +2123,12 @@ exports.setRequestMountPath = setRequestMountPath;
|
|
|
1583
2123
|
exports.setRequestParam = setRequestParam;
|
|
1584
2124
|
exports.setRequestParams = setRequestParams;
|
|
1585
2125
|
exports.setRequestQuery = setRequestQuery;
|
|
2126
|
+
exports.setRequestRouterIds = setRequestRouterIds;
|
|
1586
2127
|
exports.setResponseCacheHeaders = setResponseCacheHeaders;
|
|
1587
2128
|
exports.setResponseContentTypeByFileName = setResponseContentTypeByFileName;
|
|
1588
2129
|
exports.setResponseHeaderAttachment = setResponseHeaderAttachment;
|
|
1589
2130
|
exports.setResponseHeaderContentType = setResponseHeaderContentType;
|
|
1590
2131
|
exports.unsetRequestEnv = unsetRequestEnv;
|
|
1591
|
-
exports.useConfig = useConfig;
|
|
1592
2132
|
exports.useRequestBody = useRequestBody;
|
|
1593
2133
|
exports.useRequestCookie = useRequestCookie;
|
|
1594
2134
|
exports.useRequestCookies = useRequestCookies;
|
|
@@ -1599,8 +2139,5 @@ exports.useRequestParam = useRequestParam;
|
|
|
1599
2139
|
exports.useRequestParams = useRequestParams;
|
|
1600
2140
|
exports.useRequestPath = useRequestPath;
|
|
1601
2141
|
exports.useRequestQuery = useRequestQuery;
|
|
1602
|
-
exports.
|
|
1603
|
-
exports.withTrailingSlash = withTrailingSlash;
|
|
1604
|
-
exports.withoutLeadingSlash = withoutLeadingSlash;
|
|
1605
|
-
exports.withoutTrailingSlash = withoutTrailingSlash;
|
|
2142
|
+
exports.useRequestRouterIds = useRequestRouterIds;
|
|
1606
2143
|
//# sourceMappingURL=index.cjs.map
|