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