routup 1.0.3 → 3.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -26
- 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 +7 -0
- package/dist/dispatcher/adapters/raw/module.d.ts +4 -0
- package/dist/dispatcher/adapters/raw/type.d.ts +18 -0
- package/dist/{route → dispatcher/adapters/web}/index.d.ts +0 -1
- 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 +32 -0
- package/dist/dispatcher/utils.d.ts +5 -0
- package/dist/error/create.d.ts +11 -0
- package/dist/error/index.d.ts +3 -0
- package/dist/error/is.d.ts +2 -0
- package/dist/error/module.d.ts +3 -0
- package/dist/handler/constants.d.ts +4 -0
- package/dist/handler/core/define.d.ts +3 -0
- package/dist/handler/core/index.d.ts +2 -0
- package/dist/handler/core/types.d.ts +10 -0
- package/dist/handler/error/define.d.ts +3 -0
- package/dist/handler/error/index.d.ts +2 -0
- package/dist/handler/error/types.d.ts +11 -0
- package/dist/handler/index.d.ts +6 -1
- package/dist/handler/is.d.ts +2 -0
- package/dist/handler/types-base.d.ts +6 -0
- package/dist/handler/types.d.ts +5 -0
- package/dist/index.cjs +1202 -629
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.mjs +1172 -597
- package/dist/index.mjs.map +1 -1
- package/dist/layer/constants.d.ts +1 -0
- package/dist/layer/module.d.ts +13 -10
- package/dist/layer/type.d.ts +6 -4
- package/dist/path/index.d.ts +1 -0
- package/dist/path/matcher.d.ts +5 -6
- package/dist/path/type.d.ts +1 -0
- package/dist/path/utils.d.ts +2 -0
- package/dist/plugin/index.d.ts +2 -0
- package/dist/plugin/is.d.ts +2 -0
- package/dist/plugin/types.d.ts +32 -0
- package/dist/{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 +13 -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 +3 -0
- package/dist/response/helpers/send-web-blob.d.ts +3 -0
- package/dist/response/helpers/send-web-response.d.ts +3 -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 +3 -0
- package/dist/response/module.d.ts +3 -0
- package/dist/response/types.d.ts +4 -0
- package/dist/router/constants.d.ts +1 -0
- package/dist/router/index.d.ts +1 -1
- package/dist/router/module.d.ts +34 -50
- package/dist/router/utils.d.ts +3 -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 +41 -0
- package/dist/types.d.ts +10 -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/is-instance.d.ts +1 -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 +21 -19
- package/dist/config/module.d.ts +0 -8
- package/dist/config/type.d.ts +0 -34
- 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/route/module.d.ts +0 -27
- package/dist/route/type.d.ts +0 -6
- package/dist/route/utils.d.ts +0 -2
- 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,186 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var process = require('node:process');
|
|
5
|
-
var zod = require('zod');
|
|
6
|
-
var crypto = require('node:crypto');
|
|
7
|
-
var node_fs = require('node:fs');
|
|
3
|
+
var http = require('@ebec/http');
|
|
8
4
|
var smob = require('smob');
|
|
5
|
+
var buffer = require('buffer');
|
|
6
|
+
var uncrypto = require('uncrypto');
|
|
9
7
|
var proxyAddr = require('proxy-addr');
|
|
10
8
|
var mimeExplorer = require('mime-explorer');
|
|
11
|
-
var http = require('@ebec/http');
|
|
12
9
|
var Negotiator = require('negotiator');
|
|
13
|
-
var
|
|
14
|
-
var path = require('node:path');
|
|
10
|
+
var readableStream = require('readable-stream');
|
|
15
11
|
var pathToRegexp = require('path-to-regexp');
|
|
16
|
-
|
|
12
|
+
|
|
13
|
+
exports.MethodName = void 0;
|
|
14
|
+
(function(MethodName) {
|
|
15
|
+
MethodName["GET"] = "get";
|
|
16
|
+
MethodName["POST"] = "post";
|
|
17
|
+
MethodName["PUT"] = "put";
|
|
18
|
+
MethodName["PATCH"] = "patch";
|
|
19
|
+
MethodName["DELETE"] = "delete";
|
|
20
|
+
MethodName["OPTIONS"] = "options";
|
|
21
|
+
MethodName["HEAD"] = "head";
|
|
22
|
+
})(exports.MethodName || (exports.MethodName = {}));
|
|
23
|
+
exports.HeaderName = void 0;
|
|
24
|
+
(function(HeaderName) {
|
|
25
|
+
HeaderName["ACCEPT"] = "accept";
|
|
26
|
+
HeaderName["ACCEPT_CHARSET"] = "accept-charset";
|
|
27
|
+
HeaderName["ACCEPT_ENCODING"] = "accept-encoding";
|
|
28
|
+
HeaderName["ACCEPT_LANGUAGE"] = "accept-language";
|
|
29
|
+
HeaderName["ACCEPT_RANGES"] = "accept-ranges";
|
|
30
|
+
HeaderName["ALLOW"] = "allow";
|
|
31
|
+
HeaderName["CACHE_CONTROL"] = "cache-control";
|
|
32
|
+
HeaderName["CONTENT_DISPOSITION"] = "content-disposition";
|
|
33
|
+
HeaderName["CONTENT_ENCODING"] = "content-encoding";
|
|
34
|
+
HeaderName["CONTENT_LENGTH"] = "content-length";
|
|
35
|
+
HeaderName["CONTENT_RANGE"] = "content-range";
|
|
36
|
+
HeaderName["CONTENT_TYPE"] = "content-type";
|
|
37
|
+
HeaderName["COOKIE"] = "cookie";
|
|
38
|
+
HeaderName["ETag"] = "etag";
|
|
39
|
+
HeaderName["HOST"] = "host";
|
|
40
|
+
HeaderName["IF_MODIFIED_SINCE"] = "if-modified-since";
|
|
41
|
+
HeaderName["IF_NONE_MATCH"] = "if-none-match";
|
|
42
|
+
HeaderName["LAST_MODIFIED"] = "last-modified";
|
|
43
|
+
HeaderName["LOCATION"] = "location";
|
|
44
|
+
HeaderName["RANGE"] = "range";
|
|
45
|
+
HeaderName["RATE_LIMIT_LIMIT"] = "ratelimit-limit";
|
|
46
|
+
HeaderName["RATE_LIMIT_REMAINING"] = "ratelimit-remaining";
|
|
47
|
+
HeaderName["RATE_LIMIT_RESET"] = "ratelimit-reset";
|
|
48
|
+
HeaderName["RETRY_AFTER"] = "retry-after";
|
|
49
|
+
HeaderName["SET_COOKIE"] = "set-cookie";
|
|
50
|
+
HeaderName["TRANSFER_ENCODING"] = "transfer-encoding";
|
|
51
|
+
HeaderName["X_FORWARDED_HOST"] = "x-forwarded-host";
|
|
52
|
+
HeaderName["X_FORWARDED_FOR"] = "x-forwarded-for";
|
|
53
|
+
HeaderName["X_FORWARDED_PROTO"] = "x-forwarded-proto";
|
|
54
|
+
})(exports.HeaderName || (exports.HeaderName = {}));
|
|
55
|
+
|
|
56
|
+
class ErrorProxy extends http.HTTPError {
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function isError(input) {
|
|
60
|
+
return input instanceof ErrorProxy;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create an error proxy by
|
|
65
|
+
* - an existing error (accessible via cause property)
|
|
66
|
+
* - options
|
|
67
|
+
* - message
|
|
68
|
+
*
|
|
69
|
+
* @param input
|
|
70
|
+
*/ function createError(input) {
|
|
71
|
+
if (isError(input)) {
|
|
72
|
+
return input;
|
|
73
|
+
}
|
|
74
|
+
if (typeof input === 'string') {
|
|
75
|
+
return new ErrorProxy(input);
|
|
76
|
+
}
|
|
77
|
+
return new ErrorProxy({
|
|
78
|
+
cause: input
|
|
79
|
+
}, input);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
Set-Cookie header field-values are sometimes comma joined in one string. This splits them without choking on commas
|
|
84
|
+
that are within a single set-cookie field-value, such as in the Expires portion.
|
|
85
|
+
|
|
86
|
+
This is uncommon, but explicitly allowed - see https://tools.ietf.org/html/rfc2616#section-4.2
|
|
87
|
+
Node.js does this for every header *except* set-cookie - see https://github.com/nodejs/node/blob/d5e363b77ebaf1caf67cd7528224b651c86815c1/lib/_http_incoming.js#L128
|
|
88
|
+
React Native's fetch does this for *every* header, including set-cookie.
|
|
89
|
+
|
|
90
|
+
Based on: https://github.com/google/j2objc/commit/16820fdbc8f76ca0c33472810ce0cb03d20efe25
|
|
91
|
+
Credits to: https://github.com/tomball for original and https://github.com/chrusart for JavaScript implementation
|
|
92
|
+
*/ function splitCookiesString(input) {
|
|
93
|
+
if (Array.isArray(input)) {
|
|
94
|
+
return input.flatMap((el)=>splitCookiesString(el));
|
|
95
|
+
}
|
|
96
|
+
if (typeof input !== 'string') {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
const cookiesStrings = [];
|
|
100
|
+
let pos = 0;
|
|
101
|
+
let start;
|
|
102
|
+
let ch;
|
|
103
|
+
let lastComma;
|
|
104
|
+
let nextStart;
|
|
105
|
+
let cookiesSeparatorFound;
|
|
106
|
+
const skipWhitespace = ()=>{
|
|
107
|
+
while(pos < input.length && /\s/.test(input.charAt(pos))){
|
|
108
|
+
pos += 1;
|
|
109
|
+
}
|
|
110
|
+
return pos < input.length;
|
|
111
|
+
};
|
|
112
|
+
const notSpecialChar = ()=>{
|
|
113
|
+
ch = input.charAt(pos);
|
|
114
|
+
return ch !== '=' && ch !== ';' && ch !== ',';
|
|
115
|
+
};
|
|
116
|
+
while(pos < input.length){
|
|
117
|
+
start = pos;
|
|
118
|
+
cookiesSeparatorFound = false;
|
|
119
|
+
while(skipWhitespace()){
|
|
120
|
+
ch = input.charAt(pos);
|
|
121
|
+
if (ch === ',') {
|
|
122
|
+
// ',' is a cookie separator if we have later first '=', not ';' or ','
|
|
123
|
+
lastComma = pos;
|
|
124
|
+
pos += 1;
|
|
125
|
+
skipWhitespace();
|
|
126
|
+
nextStart = pos;
|
|
127
|
+
while(pos < input.length && notSpecialChar()){
|
|
128
|
+
pos += 1;
|
|
129
|
+
}
|
|
130
|
+
// currently special character
|
|
131
|
+
if (pos < input.length && input.charAt(pos) === '=') {
|
|
132
|
+
// we found cookies separator
|
|
133
|
+
cookiesSeparatorFound = true;
|
|
134
|
+
// pos is inside the next cookie, so back up and return it.
|
|
135
|
+
pos = nextStart;
|
|
136
|
+
cookiesStrings.push(input.substring(start, lastComma));
|
|
137
|
+
start = pos;
|
|
138
|
+
} else {
|
|
139
|
+
// in param ',' or param separator ';',
|
|
140
|
+
// we continue from that comma
|
|
141
|
+
pos = lastComma + 1;
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
pos += 1;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (!cookiesSeparatorFound || pos >= input.length) {
|
|
148
|
+
cookiesStrings.push(input.substring(start, input.length));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return cookiesStrings;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function transformHeaderToTuples(key, value) {
|
|
155
|
+
const output = [];
|
|
156
|
+
if (Array.isArray(value)) {
|
|
157
|
+
for(let j = 0; j < value.length; j++){
|
|
158
|
+
output.push([
|
|
159
|
+
key,
|
|
160
|
+
value[j]
|
|
161
|
+
]);
|
|
162
|
+
}
|
|
163
|
+
} else if (value !== undefined) {
|
|
164
|
+
output.push([
|
|
165
|
+
key,
|
|
166
|
+
String(value)
|
|
167
|
+
]);
|
|
168
|
+
}
|
|
169
|
+
return output;
|
|
170
|
+
}
|
|
171
|
+
function transformHeadersToTuples(input) {
|
|
172
|
+
const output = [];
|
|
173
|
+
const keys = Object.keys(input);
|
|
174
|
+
for(let i = 0; i < keys.length; i++){
|
|
175
|
+
const key = keys[i].toLowerCase();
|
|
176
|
+
output.push(...transformHeaderToTuples(key, input[key]));
|
|
177
|
+
}
|
|
178
|
+
return output;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function isObject(item) {
|
|
182
|
+
return !!item && typeof item === 'object' && !Array.isArray(item);
|
|
183
|
+
}
|
|
17
184
|
|
|
18
185
|
/**
|
|
19
186
|
* Determine if object is a Stats object.
|
|
@@ -22,15 +189,17 @@ var node_http = require('node:http');
|
|
|
22
189
|
* @return {boolean}
|
|
23
190
|
* @api private
|
|
24
191
|
*/ function isStatsObject(obj) {
|
|
25
|
-
/* istanbul ignore next */ if (typeof node_fs.Stats === 'function' && obj instanceof node_fs.Stats) {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
192
|
// quack quack
|
|
29
|
-
return
|
|
193
|
+
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';
|
|
194
|
+
}
|
|
195
|
+
async function sha1(str) {
|
|
196
|
+
const enc = new TextEncoder();
|
|
197
|
+
const hash = await uncrypto.subtle.digest('SHA-1', enc.encode(str));
|
|
198
|
+
return btoa(String.fromCharCode(...new Uint8Array(hash)));
|
|
30
199
|
}
|
|
31
200
|
/**
|
|
32
201
|
* Generate an ETag.
|
|
33
|
-
*/ function generateETag(input) {
|
|
202
|
+
*/ async function generateETag(input) {
|
|
34
203
|
if (isStatsObject(input)) {
|
|
35
204
|
const mtime = input.mtime.getTime().toString(16);
|
|
36
205
|
const size = input.size.toString(16);
|
|
@@ -40,32 +209,28 @@ var node_http = require('node:http');
|
|
|
40
209
|
// fast-path empty
|
|
41
210
|
return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
|
|
42
211
|
}
|
|
43
|
-
const entity = Buffer.isBuffer(input) ? input.toString('utf-8') : input;
|
|
212
|
+
const entity = buffer.Buffer.isBuffer(input) ? input.toString('utf-8') : input;
|
|
44
213
|
// compute hash of entity
|
|
45
|
-
const hash =
|
|
46
|
-
return `"${entity.length.toString(16)}-${hash}"`;
|
|
214
|
+
const hash = await sha1(entity);
|
|
215
|
+
return `"${entity.length.toString(16)}-${hash.substring(0, 27)}"`;
|
|
47
216
|
}
|
|
48
217
|
/**
|
|
49
218
|
* Create a simple ETag.
|
|
50
|
-
*/ function createEtag(input, options) {
|
|
219
|
+
*/ async function createEtag(input, options) {
|
|
51
220
|
options = options || {};
|
|
52
221
|
const weak = typeof options.weak === 'boolean' ? options.weak : isStatsObject(input);
|
|
53
222
|
// generate entity tag
|
|
54
|
-
const tag = generateETag(input);
|
|
223
|
+
const tag = await generateETag(input);
|
|
55
224
|
return weak ? `W/${tag}` : tag;
|
|
56
225
|
}
|
|
57
226
|
|
|
58
|
-
function isObject(item) {
|
|
59
|
-
return !!item && typeof item === 'object' && !Array.isArray(item);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
227
|
function buildEtagFn(input) {
|
|
63
228
|
if (typeof input === 'function') {
|
|
64
229
|
return input;
|
|
65
230
|
}
|
|
66
231
|
input = input ?? true;
|
|
67
232
|
if (input === false) {
|
|
68
|
-
return ()=>undefined;
|
|
233
|
+
return ()=>Promise.resolve(undefined);
|
|
69
234
|
}
|
|
70
235
|
let options = {
|
|
71
236
|
weak: true
|
|
@@ -73,10 +238,10 @@ function buildEtagFn(input) {
|
|
|
73
238
|
if (isObject(input)) {
|
|
74
239
|
options = smob.merge(input, options);
|
|
75
240
|
}
|
|
76
|
-
return (body, encoding, size)=>{
|
|
77
|
-
const buff = Buffer.isBuffer(body) ? body : Buffer.from(body, encoding);
|
|
241
|
+
return async (body, encoding, size)=>{
|
|
242
|
+
const buff = buffer.Buffer.isBuffer(body) ? body : buffer.Buffer.from(body, encoding);
|
|
78
243
|
if (typeof options.threshold !== 'undefined') {
|
|
79
|
-
size = size ?? Buffer.byteLength(buff);
|
|
244
|
+
size = size ?? buffer.Buffer.byteLength(buff);
|
|
80
245
|
if (size <= options.threshold) {
|
|
81
246
|
return undefined;
|
|
82
247
|
}
|
|
@@ -101,8 +266,11 @@ function buildTrustProxyFn(input) {
|
|
|
101
266
|
return proxyAddr.compile(input || []);
|
|
102
267
|
}
|
|
103
268
|
|
|
104
|
-
function isInstance(input,
|
|
105
|
-
|
|
269
|
+
function isInstance(input, sym) {
|
|
270
|
+
if (!isObject(input)) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
return input['@instanceof'] === sym;
|
|
106
274
|
}
|
|
107
275
|
|
|
108
276
|
function getMimeType(type) {
|
|
@@ -122,8 +290,25 @@ function getCharsetForMimeType(type) {
|
|
|
122
290
|
return undefined;
|
|
123
291
|
}
|
|
124
292
|
|
|
125
|
-
|
|
126
|
-
|
|
293
|
+
/**
|
|
294
|
+
* Based on https://github.com/unjs/pathe v1.1.1 (055f50a6f1131f4e5c56cf259dd8816168fba329)
|
|
295
|
+
*/ function normalizeWindowsPath(input = '') {
|
|
296
|
+
if (!input || !input.includes('\\')) {
|
|
297
|
+
return input;
|
|
298
|
+
}
|
|
299
|
+
return input.replace(/\\/g, '/');
|
|
300
|
+
}
|
|
301
|
+
const EXTNAME_RE = /.(\.[^./]+)$/;
|
|
302
|
+
function extname(input) {
|
|
303
|
+
const match = EXTNAME_RE.exec(normalizeWindowsPath(input));
|
|
304
|
+
return match && match[1] || '';
|
|
305
|
+
}
|
|
306
|
+
function basename(input, extension) {
|
|
307
|
+
const lastSegment = normalizeWindowsPath(input).split('/').pop();
|
|
308
|
+
if (!lastSegment) {
|
|
309
|
+
return input;
|
|
310
|
+
}
|
|
311
|
+
return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
|
|
127
312
|
}
|
|
128
313
|
|
|
129
314
|
function isPromise(p) {
|
|
@@ -132,24 +317,14 @@ function isPromise(p) {
|
|
|
132
317
|
typeof p.then === 'function');
|
|
133
318
|
}
|
|
134
319
|
|
|
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
|
-
});
|
|
320
|
+
function isNodeStream(input) {
|
|
321
|
+
return isObject(input) && typeof input.pipe === 'function' && typeof input.read === 'function';
|
|
322
|
+
}
|
|
323
|
+
function isWebStream(input) {
|
|
324
|
+
return isObject(input) && typeof input.pipeTo === 'function';
|
|
325
|
+
}
|
|
326
|
+
function isStream(data) {
|
|
327
|
+
return isNodeStream(data) || isWebStream(data);
|
|
153
328
|
}
|
|
154
329
|
|
|
155
330
|
const TRAILING_SLASH_RE = /\/$|\/\?/;
|
|
@@ -169,115 +344,26 @@ function withoutTrailingSlash(input = '', queryParams = false) {
|
|
|
169
344
|
const [s0, ...s] = input.split('?');
|
|
170
345
|
return (s0.slice(0, -1) || '/') + (s.length ? `?${s.join('?')}` : '');
|
|
171
346
|
}
|
|
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
347
|
function hasLeadingSlash(input = '') {
|
|
183
348
|
return input.startsWith('/');
|
|
184
349
|
}
|
|
185
|
-
function withoutLeadingSlash(input = '') {
|
|
186
|
-
return (hasLeadingSlash(input) ? input.substr(1) : input) || '/';
|
|
187
|
-
}
|
|
188
350
|
function withLeadingSlash(input = '') {
|
|
189
351
|
return hasLeadingSlash(input) ? input : `/${input}`;
|
|
190
352
|
}
|
|
191
353
|
function cleanDoubleSlashes(input = '') {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
let instance;
|
|
196
|
-
function buildConfig() {
|
|
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
|
-
});
|
|
217
|
-
}
|
|
218
|
-
function useConfig() {
|
|
219
|
-
if (typeof instance !== 'undefined') {
|
|
220
|
-
return instance;
|
|
354
|
+
if (input.indexOf('://') !== -1) {
|
|
355
|
+
return input.split('://').map((str)=>cleanDoubleSlashes(str)).join('://');
|
|
221
356
|
}
|
|
222
|
-
|
|
223
|
-
return instance;
|
|
357
|
+
return input.replace(/\/+/g, '/');
|
|
224
358
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
function setConfigOption(key, value) {
|
|
229
|
-
const config = useConfig();
|
|
230
|
-
config.setRaw(key, value);
|
|
231
|
-
return config.get();
|
|
359
|
+
|
|
360
|
+
function isWebBlob(input) {
|
|
361
|
+
return typeof Blob !== 'undefined' && input instanceof Blob;
|
|
232
362
|
}
|
|
233
|
-
function
|
|
234
|
-
|
|
235
|
-
return config.get(key);
|
|
363
|
+
function isWebResponse(input) {
|
|
364
|
+
return typeof Response !== 'undefined' && input instanceof Response;
|
|
236
365
|
}
|
|
237
366
|
|
|
238
|
-
exports.MethodName = void 0;
|
|
239
|
-
(function(MethodName) {
|
|
240
|
-
MethodName["GET"] = 'get';
|
|
241
|
-
MethodName["POST"] = 'post';
|
|
242
|
-
MethodName["PUT"] = 'put';
|
|
243
|
-
MethodName["PATCH"] = 'patch';
|
|
244
|
-
MethodName["DELETE"] = 'delete';
|
|
245
|
-
MethodName["OPTIONS"] = 'options';
|
|
246
|
-
MethodName["HEAD"] = 'head';
|
|
247
|
-
})(exports.MethodName || (exports.MethodName = {}));
|
|
248
|
-
exports.HeaderName = void 0;
|
|
249
|
-
(function(HeaderName) {
|
|
250
|
-
HeaderName["ACCEPT"] = 'accept';
|
|
251
|
-
HeaderName["ACCEPT_CHARSET"] = 'accept-charset';
|
|
252
|
-
HeaderName["ACCEPT_ENCODING"] = 'accept-encoding';
|
|
253
|
-
HeaderName["ACCEPT_LANGUAGE"] = 'accept-language';
|
|
254
|
-
HeaderName["ACCEPT_RANGES"] = 'accept-ranges';
|
|
255
|
-
HeaderName["ALLOW"] = 'allow';
|
|
256
|
-
HeaderName["CACHE_CONTROL"] = 'cache-control';
|
|
257
|
-
HeaderName["CONTENT_DISPOSITION"] = 'content-disposition';
|
|
258
|
-
HeaderName["CONTENT_ENCODING"] = 'content-encoding';
|
|
259
|
-
HeaderName["CONTENT_LENGTH"] = 'content-length';
|
|
260
|
-
HeaderName["CONTENT_RANGE"] = 'content-range';
|
|
261
|
-
HeaderName["CONTENT_TYPE"] = 'content-type';
|
|
262
|
-
HeaderName["COOKIE"] = 'cookie';
|
|
263
|
-
HeaderName["ETag"] = 'etag';
|
|
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 = {}));
|
|
280
|
-
|
|
281
367
|
const BodySymbol = Symbol.for('ReqBody');
|
|
282
368
|
function useRequestBody(req, key) {
|
|
283
369
|
let body;
|
|
@@ -539,14 +625,48 @@ function matchRequestContentType(req, contentType) {
|
|
|
539
625
|
return header.split('; ').shift() === getMimeType(contentType);
|
|
540
626
|
}
|
|
541
627
|
|
|
628
|
+
const defaults = {
|
|
629
|
+
trustProxy: ()=>false,
|
|
630
|
+
subdomainOffset: 2,
|
|
631
|
+
etag: buildEtagFn(),
|
|
632
|
+
proxyIpMax: 0
|
|
633
|
+
};
|
|
634
|
+
const instances = {};
|
|
635
|
+
function setRouterOptions(id, input) {
|
|
636
|
+
instances[id] = input;
|
|
637
|
+
}
|
|
638
|
+
function findRouterOption(key, path) {
|
|
639
|
+
if (!path || path.length === 0) {
|
|
640
|
+
return defaults[key];
|
|
641
|
+
}
|
|
642
|
+
if (path.length > 0) {
|
|
643
|
+
for(let i = path.length; i >= 0; i--){
|
|
644
|
+
if (smob.hasOwnProperty(instances, path[i]) && typeof instances[path[i]][key] !== 'undefined') {
|
|
645
|
+
return instances[path[i]][key];
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return defaults[key];
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
const routerSymbol = Symbol.for('ReqRouterID');
|
|
653
|
+
function setRequestRouterPath(req, path) {
|
|
654
|
+
req[routerSymbol] = path;
|
|
655
|
+
}
|
|
656
|
+
function useRequestRouterPath(req) {
|
|
657
|
+
if (routerSymbol in req) {
|
|
658
|
+
return req[routerSymbol];
|
|
659
|
+
}
|
|
660
|
+
return undefined;
|
|
661
|
+
}
|
|
662
|
+
|
|
542
663
|
function getRequestHostName(req, options) {
|
|
543
664
|
options = options || {};
|
|
544
665
|
let trustProxy;
|
|
545
666
|
if (typeof options.trustProxy !== 'undefined') {
|
|
546
667
|
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
547
668
|
} else {
|
|
548
|
-
|
|
549
|
-
trustProxy = config.get('trustProxy');
|
|
669
|
+
trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
|
|
550
670
|
}
|
|
551
671
|
let hostname = req.headers[exports.HeaderName.X_FORWARDED_HOST];
|
|
552
672
|
if (!hostname || !req.socket.remoteAddress || !trustProxy(req.socket.remoteAddress, 0)) {
|
|
@@ -572,8 +692,7 @@ function getRequestIP(req, options) {
|
|
|
572
692
|
if (typeof options.trustProxy !== 'undefined') {
|
|
573
693
|
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
574
694
|
} else {
|
|
575
|
-
|
|
576
|
-
trustProxy = config.get('trustProxy');
|
|
695
|
+
trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
|
|
577
696
|
}
|
|
578
697
|
const addrs = proxyAddr.all(req, trustProxy);
|
|
579
698
|
return addrs[addrs.length - 1];
|
|
@@ -623,7 +742,7 @@ function useRequestPath(req) {
|
|
|
623
742
|
if (typeof req.url === 'undefined') {
|
|
624
743
|
return '/';
|
|
625
744
|
}
|
|
626
|
-
const parsed = new
|
|
745
|
+
const parsed = new URL(req.url, 'http://localhost/');
|
|
627
746
|
req[PathSymbol] = parsed.pathname;
|
|
628
747
|
return req[PathSymbol];
|
|
629
748
|
}
|
|
@@ -634,8 +753,7 @@ function getRequestProtocol(req, options) {
|
|
|
634
753
|
if (typeof options.trustProxy !== 'undefined') {
|
|
635
754
|
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
636
755
|
} else {
|
|
637
|
-
|
|
638
|
-
trustProxy = config.get('trustProxy');
|
|
756
|
+
trustProxy = findRouterOption('trustProxy', useRequestRouterPath(req));
|
|
639
757
|
}
|
|
640
758
|
let protocol = options.default;
|
|
641
759
|
/* istanbul ignore next */ if (smob.hasOwnProperty(req.socket, 'encrypted') && !!req.socket.encrypted) {
|
|
@@ -703,6 +821,78 @@ function extendRequestQuery(req, key, value) {
|
|
|
703
821
|
setRequestQuery(req, key, value);
|
|
704
822
|
}
|
|
705
823
|
|
|
824
|
+
function createRequest(context) {
|
|
825
|
+
let readable;
|
|
826
|
+
if (context.body) {
|
|
827
|
+
if (isWebStream(context.body)) {
|
|
828
|
+
readable = readableStream.Readable.fromWeb(context.body);
|
|
829
|
+
} else {
|
|
830
|
+
readable = readableStream.Readable.from(context.body);
|
|
831
|
+
}
|
|
832
|
+
} else {
|
|
833
|
+
readable = new readableStream.Readable();
|
|
834
|
+
}
|
|
835
|
+
const headers = context.headers || {};
|
|
836
|
+
const rawHeaders = [];
|
|
837
|
+
let keys = Object.keys(headers);
|
|
838
|
+
for(let i = 0; i < keys.length; i++){
|
|
839
|
+
const header = headers[keys[i]];
|
|
840
|
+
if (Array.isArray(header)) {
|
|
841
|
+
for(let j = 0; j < header.length; j++){
|
|
842
|
+
rawHeaders.push(keys[i], header[j]);
|
|
843
|
+
}
|
|
844
|
+
} else if (typeof header === 'string') {
|
|
845
|
+
rawHeaders.push(keys[i], header);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
const headersDistinct = {};
|
|
849
|
+
keys = Object.keys(headers);
|
|
850
|
+
for(let i = 0; i < keys.length; i++){
|
|
851
|
+
const header = headers[keys[i]];
|
|
852
|
+
if (Array.isArray(header)) {
|
|
853
|
+
headersDistinct[keys[i]] = header;
|
|
854
|
+
}
|
|
855
|
+
if (typeof header === 'string') {
|
|
856
|
+
headersDistinct[keys[i]] = [
|
|
857
|
+
header
|
|
858
|
+
];
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
Object.defineProperty(readable, 'connection', {
|
|
862
|
+
get () {
|
|
863
|
+
return {
|
|
864
|
+
remoteAddress: '127.0.0.1'
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
Object.defineProperty(readable, 'socket', {
|
|
869
|
+
get () {
|
|
870
|
+
return {
|
|
871
|
+
remoteAddress: '127.0.0.1'
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
Object.assign(readable, {
|
|
876
|
+
aborted: false,
|
|
877
|
+
complete: true,
|
|
878
|
+
headers,
|
|
879
|
+
headersDistinct,
|
|
880
|
+
httpVersion: '1.1',
|
|
881
|
+
httpVersionMajor: 1,
|
|
882
|
+
httpVersionMinor: 1,
|
|
883
|
+
method: context.method || 'GET',
|
|
884
|
+
rawHeaders,
|
|
885
|
+
rawTrailers: [],
|
|
886
|
+
trailers: {},
|
|
887
|
+
trailersDistinct: {},
|
|
888
|
+
url: context.url || '/',
|
|
889
|
+
setTimeout (_msecs, _callback) {
|
|
890
|
+
return this;
|
|
891
|
+
}
|
|
892
|
+
});
|
|
893
|
+
return readable;
|
|
894
|
+
}
|
|
895
|
+
|
|
706
896
|
function setResponseCacheHeaders(res, options) {
|
|
707
897
|
options = options || {};
|
|
708
898
|
const cacheControls = [
|
|
@@ -718,6 +908,17 @@ function setResponseCacheHeaders(res, options) {
|
|
|
718
908
|
res.setHeader('cache-control', cacheControls.join(', '));
|
|
719
909
|
}
|
|
720
910
|
|
|
911
|
+
const GoneSymbol = Symbol.for('ResGone');
|
|
912
|
+
function isResponseGone(res) {
|
|
913
|
+
if (res.headersSent || res.writableEnded) {
|
|
914
|
+
return true;
|
|
915
|
+
}
|
|
916
|
+
if (GoneSymbol in res) {
|
|
917
|
+
return res[GoneSymbol];
|
|
918
|
+
}
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
|
|
721
922
|
function appendResponseHeader(res, name, value) {
|
|
722
923
|
let header = res.getHeader(name);
|
|
723
924
|
if (!header) {
|
|
@@ -767,7 +968,7 @@ function appendResponseHeaderDirective(res, name, value) {
|
|
|
767
968
|
}
|
|
768
969
|
|
|
769
970
|
function setResponseContentTypeByFileName(res, fileName) {
|
|
770
|
-
const ext =
|
|
971
|
+
const ext = extname(fileName);
|
|
771
972
|
if (ext) {
|
|
772
973
|
let type = getMimeType(ext.substring(1));
|
|
773
974
|
if (type) {
|
|
@@ -779,23 +980,6 @@ function setResponseContentTypeByFileName(res, fileName) {
|
|
|
779
980
|
}
|
|
780
981
|
}
|
|
781
982
|
}
|
|
782
|
-
/* istanbul ignore next */ function onResponseFinished(res, cb) {
|
|
783
|
-
let called;
|
|
784
|
-
const callCallback = (err)=>{
|
|
785
|
-
if (called) return;
|
|
786
|
-
called = true;
|
|
787
|
-
cb(err);
|
|
788
|
-
};
|
|
789
|
-
res.on('finish', ()=>{
|
|
790
|
-
callCallback();
|
|
791
|
-
});
|
|
792
|
-
res.on('close', ()=>{
|
|
793
|
-
callCallback();
|
|
794
|
-
});
|
|
795
|
-
res.on('error', (err)=>{
|
|
796
|
-
callCallback(err);
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
983
|
|
|
800
984
|
function setResponseHeaderAttachment(res, filename) {
|
|
801
985
|
if (typeof filename === 'string') {
|
|
@@ -817,7 +1001,7 @@ function setResponseHeaderContentType(res, input, ifNotExists) {
|
|
|
817
1001
|
}
|
|
818
1002
|
}
|
|
819
1003
|
|
|
820
|
-
function send(res, chunk) {
|
|
1004
|
+
async function send(res, chunk) {
|
|
821
1005
|
switch(typeof chunk){
|
|
822
1006
|
case 'string':
|
|
823
1007
|
{
|
|
@@ -828,11 +1012,9 @@ function send(res, chunk) {
|
|
|
828
1012
|
case 'number':
|
|
829
1013
|
case 'object':
|
|
830
1014
|
{
|
|
831
|
-
if (chunk
|
|
832
|
-
chunk = '';
|
|
833
|
-
} else if (Buffer.isBuffer(chunk)) {
|
|
1015
|
+
if (buffer.Buffer.isBuffer(chunk)) {
|
|
834
1016
|
setResponseHeaderContentType(res, 'bin', true);
|
|
835
|
-
} else {
|
|
1017
|
+
} else if (chunk !== null) {
|
|
836
1018
|
chunk = JSON.stringify(chunk);
|
|
837
1019
|
setResponseHeaderContentType(res, 'application/json', true);
|
|
838
1020
|
}
|
|
@@ -847,25 +1029,27 @@ function send(res, chunk) {
|
|
|
847
1029
|
}
|
|
848
1030
|
// populate Content-Length
|
|
849
1031
|
let len;
|
|
850
|
-
if (chunk !== undefined) {
|
|
851
|
-
if (Buffer.isBuffer(chunk)) {
|
|
1032
|
+
if (chunk !== undefined && chunk !== null) {
|
|
1033
|
+
if (buffer.Buffer.isBuffer(chunk)) {
|
|
852
1034
|
// get length of Buffer
|
|
853
1035
|
len = chunk.length;
|
|
854
1036
|
} else if (chunk.length < 1000) {
|
|
855
1037
|
// just calculate length when no ETag + small chunk
|
|
856
|
-
len = Buffer.byteLength(chunk, encoding);
|
|
1038
|
+
len = buffer.Buffer.byteLength(chunk, encoding);
|
|
857
1039
|
} else {
|
|
858
1040
|
// convert chunk to Buffer and calculate
|
|
859
|
-
chunk = Buffer.from(chunk, encoding);
|
|
1041
|
+
chunk = buffer.Buffer.from(chunk, encoding);
|
|
860
1042
|
encoding = undefined;
|
|
861
1043
|
len = chunk.length;
|
|
862
1044
|
}
|
|
863
1045
|
res.setHeader(exports.HeaderName.CONTENT_LENGTH, `${len}`);
|
|
864
1046
|
}
|
|
865
|
-
const config = useConfig();
|
|
866
|
-
const etagFn = config.get('etag');
|
|
867
1047
|
if (typeof len !== 'undefined') {
|
|
868
|
-
const
|
|
1048
|
+
const etagFn = findRouterOption('etag', useRequestRouterPath(res.req));
|
|
1049
|
+
const chunkHash = await etagFn(chunk, encoding, len);
|
|
1050
|
+
if (isResponseGone(res)) {
|
|
1051
|
+
return Promise.resolve();
|
|
1052
|
+
}
|
|
869
1053
|
if (typeof chunkHash === 'string') {
|
|
870
1054
|
res.setHeader(exports.HeaderName.ETag, chunkHash);
|
|
871
1055
|
if (res.req.headers[exports.HeaderName.IF_NONE_MATCH] === chunkHash) {
|
|
@@ -878,24 +1062,30 @@ function send(res, chunk) {
|
|
|
878
1062
|
res.removeHeader(exports.HeaderName.CONTENT_TYPE);
|
|
879
1063
|
res.removeHeader(exports.HeaderName.CONTENT_LENGTH);
|
|
880
1064
|
res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
|
|
881
|
-
chunk = '';
|
|
882
1065
|
}
|
|
883
1066
|
// alter headers for 205
|
|
884
1067
|
if (res.statusCode === 205) {
|
|
885
1068
|
res.setHeader(exports.HeaderName.CONTENT_LENGTH, 0);
|
|
886
1069
|
res.removeHeader(exports.HeaderName.TRANSFER_ENCODING);
|
|
887
|
-
|
|
1070
|
+
}
|
|
1071
|
+
if (isResponseGone(res)) {
|
|
1072
|
+
return Promise.resolve();
|
|
888
1073
|
}
|
|
889
1074
|
if (res.req.method === 'HEAD') {
|
|
890
1075
|
// skip body for HEAD
|
|
891
1076
|
res.end();
|
|
892
|
-
return;
|
|
1077
|
+
return Promise.resolve();
|
|
1078
|
+
}
|
|
1079
|
+
if (typeof chunk === 'undefined' || chunk === null) {
|
|
1080
|
+
res.end();
|
|
1081
|
+
return Promise.resolve();
|
|
893
1082
|
}
|
|
894
1083
|
if (typeof encoding !== 'undefined') {
|
|
895
1084
|
res.end(chunk, encoding);
|
|
896
|
-
return;
|
|
1085
|
+
return Promise.resolve();
|
|
897
1086
|
}
|
|
898
1087
|
res.end(chunk);
|
|
1088
|
+
return Promise.resolve();
|
|
899
1089
|
}
|
|
900
1090
|
|
|
901
1091
|
function sendAccepted(res, chunk) {
|
|
@@ -910,87 +1100,116 @@ function sendCreated(res, chunk) {
|
|
|
910
1100
|
return send(res, chunk);
|
|
911
1101
|
}
|
|
912
1102
|
|
|
913
|
-
function sendStream(res, stream,
|
|
914
|
-
|
|
915
|
-
stream.
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1103
|
+
async function sendStream(res, stream, next) {
|
|
1104
|
+
if (isWebStream(stream)) {
|
|
1105
|
+
return stream.pipeTo(new WritableStream({
|
|
1106
|
+
write (chunk) {
|
|
1107
|
+
res.write(chunk);
|
|
1108
|
+
}
|
|
1109
|
+
})).then(()=>{
|
|
1110
|
+
if (next) {
|
|
1111
|
+
return next();
|
|
1112
|
+
}
|
|
922
1113
|
res.end();
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1114
|
+
return Promise.resolve();
|
|
1115
|
+
}).catch((err)=>{
|
|
1116
|
+
if (next) {
|
|
1117
|
+
return next(err);
|
|
1118
|
+
}
|
|
1119
|
+
return Promise.reject(err);
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
return new Promise((resolve, reject)=>{
|
|
1123
|
+
stream.on('open', ()=>{
|
|
1124
|
+
stream.pipe(res);
|
|
1125
|
+
});
|
|
1126
|
+
/* istanbul ignore next */ stream.on('error', (err)=>{
|
|
1127
|
+
if (next) {
|
|
1128
|
+
Promise.resolve().then(()=>next(err)).then(()=>resolve()).catch((e)=>reject(e));
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
929
1131
|
res.end();
|
|
930
|
-
|
|
1132
|
+
reject(err);
|
|
1133
|
+
});
|
|
1134
|
+
stream.on('close', ()=>{
|
|
1135
|
+
if (next) {
|
|
1136
|
+
Promise.resolve().then(()=>next()).then(()=>resolve()).catch((e)=>reject(e));
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
res.end();
|
|
1140
|
+
resolve();
|
|
1141
|
+
});
|
|
931
1142
|
});
|
|
932
1143
|
}
|
|
933
1144
|
|
|
934
|
-
function
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
function sendFile(res, filePath, fn) {
|
|
942
|
-
let options;
|
|
943
|
-
if (typeof filePath === 'string') {
|
|
944
|
-
options = {
|
|
945
|
-
filePath
|
|
946
|
-
};
|
|
947
|
-
} else {
|
|
948
|
-
options = filePath;
|
|
949
|
-
}
|
|
950
|
-
const fileName = path.basename(options.filePath);
|
|
951
|
-
if (options.attachment) {
|
|
952
|
-
const dispositionHeader = res.getHeader(exports.HeaderName.CONTENT_DISPOSITION);
|
|
953
|
-
if (!dispositionHeader) {
|
|
954
|
-
setResponseHeaderAttachment(res, fileName);
|
|
1145
|
+
async function sendFile(res, options, next) {
|
|
1146
|
+
let stats;
|
|
1147
|
+
try {
|
|
1148
|
+
stats = await options.stats();
|
|
1149
|
+
} catch (e) {
|
|
1150
|
+
if (next) {
|
|
1151
|
+
return next(e);
|
|
955
1152
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1153
|
+
if (isResponseGone(res)) {
|
|
1154
|
+
return Promise.resolve();
|
|
1155
|
+
}
|
|
1156
|
+
return Promise.reject(e);
|
|
1157
|
+
}
|
|
1158
|
+
const name = options.name || stats.name;
|
|
1159
|
+
if (name) {
|
|
1160
|
+
const fileName = basename(name);
|
|
1161
|
+
if (options.attachment) {
|
|
1162
|
+
const dispositionHeader = res.getHeader(exports.HeaderName.CONTENT_DISPOSITION);
|
|
1163
|
+
if (!dispositionHeader) {
|
|
1164
|
+
setResponseHeaderAttachment(res, fileName);
|
|
966
1165
|
}
|
|
967
|
-
|
|
1166
|
+
} else {
|
|
1167
|
+
setResponseContentTypeByFileName(res, fileName);
|
|
968
1168
|
}
|
|
969
|
-
|
|
1169
|
+
}
|
|
1170
|
+
const contentOptions = {};
|
|
1171
|
+
if (stats.size) {
|
|
970
1172
|
const rangeHeader = res.req.headers[exports.HeaderName.RANGE];
|
|
971
1173
|
if (rangeHeader) {
|
|
972
1174
|
const [x, y] = rangeHeader.replace('bytes=', '').split('-');
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
if (
|
|
976
|
-
|
|
1175
|
+
contentOptions.end = Math.min(parseInt(y, 10) || stats.size - 1, stats.size - 1);
|
|
1176
|
+
contentOptions.start = parseInt(x, 10) || 0;
|
|
1177
|
+
if (contentOptions.end >= stats.size) {
|
|
1178
|
+
contentOptions.end = stats.size - 1;
|
|
977
1179
|
}
|
|
978
|
-
if (
|
|
1180
|
+
if (contentOptions.start >= stats.size) {
|
|
979
1181
|
res.setHeader(exports.HeaderName.CONTENT_RANGE, `bytes */${stats.size}`);
|
|
980
1182
|
res.statusCode = 416;
|
|
981
1183
|
res.end();
|
|
982
|
-
return;
|
|
1184
|
+
return Promise.resolve();
|
|
983
1185
|
}
|
|
984
|
-
res.setHeader(exports.HeaderName.CONTENT_RANGE, `bytes ${
|
|
985
|
-
res.setHeader(exports.HeaderName.CONTENT_LENGTH,
|
|
1186
|
+
res.setHeader(exports.HeaderName.CONTENT_RANGE, `bytes ${contentOptions.start}-${contentOptions.end}/${stats.size}`);
|
|
1187
|
+
res.setHeader(exports.HeaderName.CONTENT_LENGTH, contentOptions.end - contentOptions.start + 1);
|
|
986
1188
|
} else {
|
|
987
1189
|
res.setHeader(exports.HeaderName.CONTENT_LENGTH, stats.size);
|
|
988
1190
|
}
|
|
989
1191
|
res.setHeader(exports.HeaderName.ACCEPT_RANGES, 'bytes');
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1192
|
+
if (stats.mtime) {
|
|
1193
|
+
const mtime = new Date(stats.mtime);
|
|
1194
|
+
res.setHeader(exports.HeaderName.LAST_MODIFIED, mtime.toUTCString());
|
|
1195
|
+
res.setHeader(exports.HeaderName.ETag, `W/"${stats.size}-${mtime.getTime()}"`);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
try {
|
|
1199
|
+
const content = await options.content(contentOptions);
|
|
1200
|
+
if (isStream(content)) {
|
|
1201
|
+
return await sendStream(res, content, next);
|
|
1202
|
+
}
|
|
1203
|
+
return await send(res, content);
|
|
1204
|
+
} catch (e) {
|
|
1205
|
+
if (next) {
|
|
1206
|
+
return next(e);
|
|
1207
|
+
}
|
|
1208
|
+
if (isResponseGone(res)) {
|
|
1209
|
+
return Promise.resolve();
|
|
1210
|
+
}
|
|
1211
|
+
return Promise.reject(e);
|
|
1212
|
+
}
|
|
994
1213
|
}
|
|
995
1214
|
|
|
996
1215
|
function sendFormat(res, input) {
|
|
@@ -1012,20 +1231,389 @@ function sendRedirect(res, location, statusCode = 302) {
|
|
|
1012
1231
|
return send(res, html);
|
|
1013
1232
|
}
|
|
1014
1233
|
|
|
1015
|
-
function
|
|
1016
|
-
if (
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1234
|
+
function sendWebResponse(res, webResponse) {
|
|
1235
|
+
if (webResponse.redirected) {
|
|
1236
|
+
res.setHeader(exports.HeaderName.LOCATION, webResponse.url);
|
|
1237
|
+
}
|
|
1238
|
+
if (webResponse.status) {
|
|
1239
|
+
res.statusCode = webResponse.status;
|
|
1240
|
+
}
|
|
1241
|
+
if (webResponse.statusText) {
|
|
1242
|
+
res.statusMessage = webResponse.statusText;
|
|
1243
|
+
}
|
|
1244
|
+
webResponse.headers.forEach((value, key)=>{
|
|
1245
|
+
if (key === exports.HeaderName.SET_COOKIE) {
|
|
1246
|
+
res.appendHeader(key, splitCookiesString(value));
|
|
1247
|
+
} else {
|
|
1248
|
+
res.setHeader(key, value);
|
|
1249
|
+
}
|
|
1250
|
+
});
|
|
1251
|
+
if (webResponse.body) {
|
|
1252
|
+
return sendStream(res, webResponse.body);
|
|
1253
|
+
}
|
|
1254
|
+
res.end();
|
|
1255
|
+
return Promise.resolve();
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
function sendWebBlob(res, blob) {
|
|
1259
|
+
setResponseHeaderContentType(res, blob.type);
|
|
1260
|
+
return sendStream(res, blob.stream());
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
function createResponse(request) {
|
|
1264
|
+
let output;
|
|
1265
|
+
let encoding;
|
|
1266
|
+
const write = (chunk, chunkEncoding, callback)=>{
|
|
1267
|
+
if (typeof chunk !== 'undefined') {
|
|
1268
|
+
const chunkEncoded = typeof chunk === 'string' ? buffer.Buffer.from(chunk, chunkEncoding || encoding || 'utf8') : chunk;
|
|
1269
|
+
if (typeof output !== 'undefined') {
|
|
1270
|
+
output = buffer.Buffer.concat([
|
|
1271
|
+
output,
|
|
1272
|
+
chunkEncoded
|
|
1273
|
+
]);
|
|
1274
|
+
} else {
|
|
1275
|
+
output = chunkEncoded;
|
|
1020
1276
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1277
|
+
}
|
|
1278
|
+
encoding = chunkEncoding;
|
|
1279
|
+
if (callback) {
|
|
1280
|
+
callback();
|
|
1281
|
+
}
|
|
1282
|
+
};
|
|
1283
|
+
const writable = new readableStream.Writable({
|
|
1284
|
+
decodeStrings: false,
|
|
1285
|
+
write (chunk, arg2, arg3) {
|
|
1286
|
+
const chunkEncoding = typeof arg2 === 'string' ? encoding : 'utf-8';
|
|
1287
|
+
let cb;
|
|
1288
|
+
if (typeof arg2 === 'function') {
|
|
1289
|
+
cb = arg2;
|
|
1290
|
+
} else if (typeof arg3 === 'function') {
|
|
1291
|
+
cb = arg3;
|
|
1292
|
+
}
|
|
1293
|
+
write(chunk, chunkEncoding, cb);
|
|
1294
|
+
return true;
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1297
|
+
Object.defineProperty(writable, 'body', {
|
|
1298
|
+
get () {
|
|
1299
|
+
if (output) {
|
|
1300
|
+
const arrayBuffer = new ArrayBuffer(output.length);
|
|
1301
|
+
const view = new Uint8Array(arrayBuffer);
|
|
1302
|
+
for(let i = 0; i < output.length; ++i){
|
|
1303
|
+
view[i] = output[i];
|
|
1304
|
+
}
|
|
1305
|
+
return arrayBuffer;
|
|
1306
|
+
}
|
|
1307
|
+
return new ArrayBuffer(0);
|
|
1308
|
+
}
|
|
1309
|
+
});
|
|
1310
|
+
const headers = {};
|
|
1311
|
+
Object.assign(writable, {
|
|
1312
|
+
req: request,
|
|
1313
|
+
chunkedEncoding: false,
|
|
1314
|
+
connection: null,
|
|
1315
|
+
headersSent: false,
|
|
1316
|
+
sendDate: false,
|
|
1317
|
+
shouldKeepAlive: false,
|
|
1318
|
+
socket: null,
|
|
1319
|
+
statusCode: 200,
|
|
1320
|
+
statusMessage: '',
|
|
1321
|
+
strictContentLength: false,
|
|
1322
|
+
useChunkedEncodingByDefault: false,
|
|
1323
|
+
finished: false,
|
|
1324
|
+
addTrailers (_headers) {},
|
|
1325
|
+
appendHeader (name, value) {
|
|
1326
|
+
if (name === exports.HeaderName.SET_COOKIE) {
|
|
1327
|
+
value = splitCookiesString(value);
|
|
1328
|
+
}
|
|
1329
|
+
name = name.toLowerCase();
|
|
1330
|
+
const current = headers[name];
|
|
1331
|
+
const all = [
|
|
1332
|
+
...Array.isArray(current) ? current : [
|
|
1333
|
+
current
|
|
1334
|
+
],
|
|
1335
|
+
...Array.isArray(value) ? value : [
|
|
1336
|
+
value
|
|
1337
|
+
]
|
|
1338
|
+
].filter(Boolean);
|
|
1339
|
+
headers[name] = all.length > 1 ? all : all[0];
|
|
1340
|
+
return this;
|
|
1341
|
+
},
|
|
1342
|
+
assignSocket (_socket) {},
|
|
1343
|
+
detachSocket (_socket) {},
|
|
1344
|
+
flushHeaders () {},
|
|
1345
|
+
getHeader (name) {
|
|
1346
|
+
return headers[name.toLowerCase()];
|
|
1347
|
+
},
|
|
1348
|
+
getHeaderNames () {
|
|
1349
|
+
return Object.keys(headers);
|
|
1350
|
+
},
|
|
1351
|
+
getHeaders () {
|
|
1352
|
+
return headers;
|
|
1353
|
+
},
|
|
1354
|
+
hasHeader (name) {
|
|
1355
|
+
return smob.hasOwnProperty(headers, name.toLowerCase());
|
|
1356
|
+
},
|
|
1357
|
+
removeHeader (name) {
|
|
1358
|
+
delete headers[name.toLowerCase()];
|
|
1359
|
+
},
|
|
1360
|
+
setHeader (name, value) {
|
|
1361
|
+
if (name === exports.HeaderName.SET_COOKIE && typeof value !== 'number') {
|
|
1362
|
+
value = splitCookiesString(value);
|
|
1363
|
+
}
|
|
1364
|
+
headers[name.toLowerCase()] = value;
|
|
1365
|
+
return this;
|
|
1366
|
+
},
|
|
1367
|
+
setTimeout (_msecs, _callback) {
|
|
1368
|
+
return this;
|
|
1369
|
+
},
|
|
1370
|
+
writeContinue (_callback) {},
|
|
1371
|
+
writeEarlyHints (_hints, callback) {
|
|
1372
|
+
if (typeof callback !== 'undefined') {
|
|
1373
|
+
callback();
|
|
1374
|
+
}
|
|
1375
|
+
},
|
|
1376
|
+
writeProcessing () {},
|
|
1377
|
+
writeHead (statusCode, arg1, arg2) {
|
|
1378
|
+
this.statusCode = statusCode;
|
|
1379
|
+
if (typeof arg1 === 'string') {
|
|
1380
|
+
this.statusMessage = arg1;
|
|
1381
|
+
arg1 = undefined;
|
|
1382
|
+
}
|
|
1383
|
+
const headers = arg2 || arg1;
|
|
1384
|
+
if (headers) {
|
|
1385
|
+
if (Array.isArray(headers)) {
|
|
1386
|
+
for(let i = 0; i < headers.length; i++){
|
|
1387
|
+
const keys = Object.keys(headers[i]);
|
|
1388
|
+
for(let j = 0; j < keys.length; j++){
|
|
1389
|
+
this.setHeader(keys[i], headers[i][keys[j]]);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
} else {
|
|
1393
|
+
const keys = Object.keys(headers);
|
|
1394
|
+
for(let i = 0; i < keys.length; i++){
|
|
1395
|
+
this.setHeader(keys[i], headers[keys[i]]);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1400
|
+
// @ts-ignore
|
|
1401
|
+
this.headersSent = true;
|
|
1402
|
+
return this;
|
|
1403
|
+
}
|
|
1404
|
+
});
|
|
1405
|
+
return writable;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
function buildDispatcherMeta(input) {
|
|
1409
|
+
return {
|
|
1410
|
+
mountPath: input.mountPath || '/',
|
|
1411
|
+
params: input.params || {},
|
|
1412
|
+
path: input.path || '/',
|
|
1413
|
+
routerPath: []
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
function cloneDispatcherMeta(input) {
|
|
1417
|
+
return {
|
|
1418
|
+
path: input.path,
|
|
1419
|
+
mountPath: input.mountPath,
|
|
1420
|
+
error: input.error,
|
|
1421
|
+
routerPath: [
|
|
1422
|
+
...input.routerPath
|
|
1423
|
+
],
|
|
1424
|
+
params: cloneDispatcherMetaParams(input.params)
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
function cloneDispatcherMetaParams(input) {
|
|
1428
|
+
if (typeof input === 'undefined') {
|
|
1429
|
+
return {};
|
|
1430
|
+
}
|
|
1431
|
+
const keys = Object.keys(input);
|
|
1432
|
+
if (keys.length === 0) {
|
|
1433
|
+
return {};
|
|
1434
|
+
}
|
|
1435
|
+
const output = {};
|
|
1436
|
+
for(let i = 0; i < keys.length; i++){
|
|
1437
|
+
output[keys[i]] = input[keys[i]];
|
|
1438
|
+
}
|
|
1439
|
+
return output;
|
|
1440
|
+
}
|
|
1441
|
+
function mergeDispatcherMetaParams(t1, t2) {
|
|
1442
|
+
if (!t1 && !t2) {
|
|
1443
|
+
return {};
|
|
1444
|
+
}
|
|
1445
|
+
if (!t1 || !t2) {
|
|
1446
|
+
return t1 || t2;
|
|
1024
1447
|
}
|
|
1025
|
-
|
|
1026
|
-
|
|
1448
|
+
const keys = Object.keys(t2);
|
|
1449
|
+
if (keys.length === 0) {
|
|
1450
|
+
return t1;
|
|
1451
|
+
}
|
|
1452
|
+
for(let i = 0; i < keys.length; i++){
|
|
1453
|
+
t1[keys[i]] = t2[keys[i]];
|
|
1454
|
+
}
|
|
1455
|
+
return t1;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
async function dispatchNodeRequest(router, req, res) {
|
|
1459
|
+
try {
|
|
1460
|
+
const dispatched = await router.dispatch({
|
|
1461
|
+
req,
|
|
1462
|
+
res
|
|
1463
|
+
}, buildDispatcherMeta({
|
|
1464
|
+
path: useRequestPath(req)
|
|
1465
|
+
}));
|
|
1466
|
+
if (dispatched) {
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
if (!isResponseGone(res)) {
|
|
1470
|
+
res.statusCode = 404;
|
|
1471
|
+
res.end();
|
|
1472
|
+
}
|
|
1473
|
+
} catch (e) {
|
|
1474
|
+
if (!isResponseGone(res)) {
|
|
1475
|
+
if (isError(e)) {
|
|
1476
|
+
res.statusCode = e.statusCode;
|
|
1477
|
+
if (e.statusMessage) {
|
|
1478
|
+
res.statusMessage = e.statusMessage;
|
|
1479
|
+
}
|
|
1480
|
+
} else {
|
|
1481
|
+
res.statusCode = 500;
|
|
1482
|
+
}
|
|
1483
|
+
res.end();
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
function createNodeDispatcher(router) {
|
|
1488
|
+
return (req, res)=>{
|
|
1489
|
+
// eslint-disable-next-line no-void
|
|
1490
|
+
void dispatchNodeRequest(router, req, res);
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
async function dispatchRawRequest(router, request, options = {}) {
|
|
1495
|
+
const req = createRequest({
|
|
1496
|
+
url: request.path,
|
|
1497
|
+
method: request.method,
|
|
1498
|
+
body: request.body,
|
|
1499
|
+
headers: request.headers
|
|
1500
|
+
});
|
|
1501
|
+
const res = createResponse(req);
|
|
1502
|
+
const getHeaders = ()=>{
|
|
1503
|
+
const output = {};
|
|
1504
|
+
const headers = res.getHeaders();
|
|
1505
|
+
const keys = Object.keys(headers);
|
|
1506
|
+
for(let i = 0; i < keys.length; i++){
|
|
1507
|
+
const header = headers[keys[i]];
|
|
1508
|
+
if (typeof header === 'number') {
|
|
1509
|
+
output[keys[i]] = `${header}`;
|
|
1510
|
+
} else if (header) {
|
|
1511
|
+
output[keys[i]] = header;
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
return output;
|
|
1515
|
+
};
|
|
1516
|
+
const createRawResponse = (input = {})=>({
|
|
1517
|
+
status: input.status || res.statusCode,
|
|
1518
|
+
statusMessage: input.statusMessage || res.statusMessage,
|
|
1519
|
+
headers: getHeaders(),
|
|
1520
|
+
body: res.body
|
|
1521
|
+
});
|
|
1522
|
+
try {
|
|
1523
|
+
const dispatched = await router.dispatch({
|
|
1524
|
+
req,
|
|
1525
|
+
res
|
|
1526
|
+
}, buildDispatcherMeta({
|
|
1527
|
+
path: useRequestPath(req)
|
|
1528
|
+
}));
|
|
1529
|
+
if (dispatched) {
|
|
1530
|
+
return createRawResponse();
|
|
1531
|
+
}
|
|
1532
|
+
return createRawResponse({
|
|
1533
|
+
status: 404
|
|
1534
|
+
});
|
|
1535
|
+
} catch (e) {
|
|
1536
|
+
if (options.throwOnError) {
|
|
1537
|
+
throw e;
|
|
1538
|
+
}
|
|
1539
|
+
if (isError(e)) {
|
|
1540
|
+
return createRawResponse({
|
|
1541
|
+
status: e.statusCode,
|
|
1542
|
+
statusMessage: e.statusMessage
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
return createRawResponse({
|
|
1546
|
+
status: 500
|
|
1547
|
+
});
|
|
1027
1548
|
}
|
|
1028
1549
|
}
|
|
1550
|
+
function createRawDispatcher(router) {
|
|
1551
|
+
return async (request)=>dispatchRawRequest(router, request);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
async function dispatchWebRequest(router, request, options = {}) {
|
|
1555
|
+
const url = new URL(request.url);
|
|
1556
|
+
const headers = {};
|
|
1557
|
+
request.headers.forEach((value, key)=>{
|
|
1558
|
+
headers[key] = value;
|
|
1559
|
+
});
|
|
1560
|
+
const res = await dispatchRawRequest(router, {
|
|
1561
|
+
method: request.method,
|
|
1562
|
+
path: url.pathname + url.search,
|
|
1563
|
+
headers,
|
|
1564
|
+
body: request.body
|
|
1565
|
+
}, options);
|
|
1566
|
+
let body;
|
|
1567
|
+
if (request.method === exports.MethodName.HEAD || res.status === 304 || res.status === 101 || res.status === 204 || res.status === 205) {
|
|
1568
|
+
body = null;
|
|
1569
|
+
} else {
|
|
1570
|
+
body = res.body;
|
|
1571
|
+
}
|
|
1572
|
+
return new Response(body, {
|
|
1573
|
+
headers: transformHeadersToTuples(res.headers),
|
|
1574
|
+
status: res.status,
|
|
1575
|
+
statusText: res.statusMessage
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
function createWebDispatcher(router) {
|
|
1579
|
+
return async (request)=>dispatchWebRequest(router, request);
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
exports.HandlerType = void 0;
|
|
1583
|
+
(function(HandlerType) {
|
|
1584
|
+
HandlerType["CORE"] = "core";
|
|
1585
|
+
HandlerType["ERROR"] = "error";
|
|
1586
|
+
})(exports.HandlerType || (exports.HandlerType = {}));
|
|
1587
|
+
|
|
1588
|
+
function coreHandler(input) {
|
|
1589
|
+
if (typeof input === 'function') {
|
|
1590
|
+
return {
|
|
1591
|
+
type: exports.HandlerType.CORE,
|
|
1592
|
+
fn: input
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
return {
|
|
1596
|
+
type: exports.HandlerType.CORE,
|
|
1597
|
+
...input
|
|
1598
|
+
};
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
function errorHandler(input) {
|
|
1602
|
+
if (typeof input === 'function') {
|
|
1603
|
+
return {
|
|
1604
|
+
type: exports.HandlerType.ERROR,
|
|
1605
|
+
fn: input
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
return {
|
|
1609
|
+
type: exports.HandlerType.ERROR,
|
|
1610
|
+
...input
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
function isHandler(input) {
|
|
1615
|
+
return isObject(input) && typeof input.fn === 'function' && typeof input.type === 'string';
|
|
1616
|
+
}
|
|
1029
1617
|
|
|
1030
1618
|
function decodeParam(val) {
|
|
1031
1619
|
/* istanbul ignore next */ if (typeof val !== 'string' || val.length === 0) {
|
|
@@ -1035,268 +1623,219 @@ function decodeParam(val) {
|
|
|
1035
1623
|
}
|
|
1036
1624
|
class PathMatcher {
|
|
1037
1625
|
test(path) {
|
|
1038
|
-
const fastSlash = this.path === '/' && this.regexpOptions.end === false;
|
|
1039
|
-
if (fastSlash) {
|
|
1040
|
-
return true;
|
|
1041
|
-
}
|
|
1042
1626
|
return this.regexp.test(path);
|
|
1043
1627
|
}
|
|
1044
1628
|
exec(path) {
|
|
1045
|
-
|
|
1046
|
-
const fastSlash = this.path === '/' && this.regexpOptions.end === false;
|
|
1047
|
-
if (fastSlash) {
|
|
1629
|
+
if (this.path === '/' && this.regexpOptions.end === false) {
|
|
1048
1630
|
return {
|
|
1049
1631
|
path: '/',
|
|
1050
1632
|
params: {}
|
|
1051
1633
|
};
|
|
1052
1634
|
}
|
|
1053
|
-
|
|
1054
|
-
if (!match) {
|
|
1055
|
-
return undefined;
|
|
1056
|
-
}
|
|
1057
|
-
if (this.path instanceof RegExp) {
|
|
1635
|
+
if (this.path === '*') {
|
|
1058
1636
|
return {
|
|
1059
1637
|
path,
|
|
1060
1638
|
params: {
|
|
1061
|
-
0: decodeParam(
|
|
1639
|
+
0: decodeParam(path)
|
|
1062
1640
|
}
|
|
1063
1641
|
};
|
|
1064
1642
|
}
|
|
1065
|
-
const
|
|
1643
|
+
const match = this.regexp.exec(path);
|
|
1644
|
+
if (!match) {
|
|
1645
|
+
return undefined;
|
|
1646
|
+
}
|
|
1647
|
+
const params = {};
|
|
1066
1648
|
for(let i = 1; i < match.length; i++){
|
|
1067
1649
|
const key = this.regexpKeys[i - 1];
|
|
1068
1650
|
const prop = key.name;
|
|
1069
1651
|
const val = decodeParam(match[i]);
|
|
1070
1652
|
if (typeof val !== 'undefined') {
|
|
1071
|
-
|
|
1653
|
+
params[prop] = val;
|
|
1072
1654
|
}
|
|
1073
1655
|
}
|
|
1074
1656
|
return {
|
|
1075
1657
|
path: match[0],
|
|
1076
|
-
params
|
|
1658
|
+
params
|
|
1077
1659
|
};
|
|
1078
1660
|
}
|
|
1079
1661
|
constructor(path, options){
|
|
1080
1662
|
this.regexpKeys = [];
|
|
1081
1663
|
this.path = path;
|
|
1082
1664
|
this.regexpOptions = options || {};
|
|
1083
|
-
|
|
1084
|
-
this.regexp = path;
|
|
1085
|
-
} else {
|
|
1086
|
-
this.regexp = pathToRegexp.pathToRegexp(path, this.regexpKeys, options);
|
|
1087
|
-
}
|
|
1665
|
+
this.regexp = pathToRegexp.pathToRegexp(path, this.regexpKeys, options);
|
|
1088
1666
|
}
|
|
1089
1667
|
}
|
|
1090
1668
|
|
|
1669
|
+
function isPath(input) {
|
|
1670
|
+
return typeof input === 'string' || input instanceof RegExp;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
const LayerSymbol = Symbol.for('Layer');
|
|
1674
|
+
|
|
1091
1675
|
class Layer {
|
|
1092
1676
|
// --------------------------------------------------
|
|
1093
|
-
|
|
1094
|
-
return this.
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1677
|
+
get type() {
|
|
1678
|
+
return this.handler.type;
|
|
1679
|
+
}
|
|
1680
|
+
get path() {
|
|
1681
|
+
return this.handler.path;
|
|
1682
|
+
}
|
|
1683
|
+
get method() {
|
|
1684
|
+
return this.handler.method ? this.handler.method.toLowerCase() : undefined;
|
|
1685
|
+
}
|
|
1686
|
+
// --------------------------------------------------
|
|
1687
|
+
dispatch(event, meta) {
|
|
1688
|
+
if (this.pathMatcher) {
|
|
1689
|
+
const pathMatch = this.pathMatcher.exec(meta.path);
|
|
1690
|
+
if (pathMatch) {
|
|
1691
|
+
meta.params = mergeDispatcherMetaParams(meta.params, pathMatch.params);
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
setRequestParams(event.req, meta.params);
|
|
1695
|
+
setRequestMountPath(event.req, meta.mountPath);
|
|
1696
|
+
setRequestRouterPath(event.req, meta.routerPath);
|
|
1697
|
+
return new Promise((resolve, reject)=>{
|
|
1698
|
+
let handled = false;
|
|
1699
|
+
const unsubscribe = ()=>{
|
|
1700
|
+
event.res.off('close', onFinished);
|
|
1701
|
+
event.res.off('error', onFinished);
|
|
1702
|
+
};
|
|
1703
|
+
const shutdown = (dispatched, err)=>{
|
|
1704
|
+
if (handled) {
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1707
|
+
handled = true;
|
|
1708
|
+
unsubscribe();
|
|
1709
|
+
if (err) {
|
|
1710
|
+
reject(createError(err));
|
|
1711
|
+
} else {
|
|
1712
|
+
resolve(dispatched);
|
|
1713
|
+
}
|
|
1714
|
+
};
|
|
1715
|
+
const onFinished = (err)=>shutdown(true, err);
|
|
1716
|
+
const onNext = (err)=>shutdown(false, err);
|
|
1717
|
+
event.res.once('close', onFinished);
|
|
1718
|
+
event.res.once('error', onFinished);
|
|
1719
|
+
const handle = (data)=>{
|
|
1720
|
+
if (typeof data === 'undefined' || handled) {
|
|
1721
|
+
return Promise.resolve();
|
|
1722
|
+
}
|
|
1723
|
+
handled = true;
|
|
1724
|
+
unsubscribe();
|
|
1725
|
+
return this.sendOutput(event.res, data).then(()=>resolve(true)).catch((e)=>reject(createError(e)));
|
|
1726
|
+
};
|
|
1727
|
+
try {
|
|
1728
|
+
let output;
|
|
1729
|
+
if (this.handler.type === exports.HandlerType.ERROR) {
|
|
1730
|
+
if (meta.error) {
|
|
1731
|
+
output = this.handler.fn(meta.error, event.req, event.res, onNext);
|
|
1110
1732
|
}
|
|
1733
|
+
} else {
|
|
1734
|
+
output = this.handler.fn(event.req, event.res, onNext);
|
|
1111
1735
|
}
|
|
1112
|
-
|
|
1736
|
+
if (isPromise(output)) {
|
|
1737
|
+
output.then((r)=>handle(r)).catch((e)=>reject(createError(e)));
|
|
1738
|
+
return;
|
|
1739
|
+
}
|
|
1740
|
+
Promise.resolve().then(()=>handle(output)).catch((e)=>reject(createError(e)));
|
|
1741
|
+
} catch (error) {
|
|
1742
|
+
onNext(error);
|
|
1113
1743
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
sendOutput(res, input) {
|
|
1747
|
+
if (input instanceof Error) {
|
|
1748
|
+
return Promise.reject(createError(input));
|
|
1116
1749
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
return;
|
|
1750
|
+
if (isStream(input)) {
|
|
1751
|
+
return sendStream(res, input);
|
|
1120
1752
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
processHandlerExecutionOutput(res, next, output);
|
|
1124
|
-
} catch (e) {
|
|
1125
|
-
/* istanbul ignore next */ if (e instanceof Error) {
|
|
1126
|
-
next(e);
|
|
1127
|
-
} else {
|
|
1128
|
-
next(new http.BadRequestError({
|
|
1129
|
-
message: 'The request could not be processed by the handler.'
|
|
1130
|
-
}));
|
|
1131
|
-
}
|
|
1753
|
+
if (isWebBlob(input)) {
|
|
1754
|
+
return sendWebBlob(res, input);
|
|
1132
1755
|
}
|
|
1756
|
+
if (isWebResponse(input)) {
|
|
1757
|
+
return sendWebResponse(res, input);
|
|
1758
|
+
}
|
|
1759
|
+
return send(res, input);
|
|
1133
1760
|
}
|
|
1134
1761
|
// --------------------------------------------------
|
|
1135
1762
|
matchPath(path) {
|
|
1763
|
+
if (!this.pathMatcher) {
|
|
1764
|
+
return true;
|
|
1765
|
+
}
|
|
1136
1766
|
return this.pathMatcher.test(path);
|
|
1137
1767
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1768
|
+
matchMethod(method) {
|
|
1769
|
+
if (!this.method) {
|
|
1770
|
+
return true;
|
|
1771
|
+
}
|
|
1772
|
+
const name = method.toLowerCase();
|
|
1773
|
+
if (name === this.method) {
|
|
1774
|
+
return true;
|
|
1775
|
+
}
|
|
1776
|
+
return name === exports.MethodName.HEAD && this.method === exports.MethodName.GET;
|
|
1140
1777
|
}
|
|
1141
1778
|
// --------------------------------------------------
|
|
1142
|
-
constructor(
|
|
1143
|
-
this['@instanceof'] =
|
|
1144
|
-
this.
|
|
1145
|
-
|
|
1779
|
+
constructor(handler){
|
|
1780
|
+
this['@instanceof'] = LayerSymbol;
|
|
1781
|
+
this.handler = handler;
|
|
1782
|
+
if (handler.path) {
|
|
1783
|
+
this.pathMatcher = new PathMatcher(handler.path, {
|
|
1784
|
+
end: !!handler.method
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1146
1787
|
}
|
|
1147
1788
|
}
|
|
1148
1789
|
|
|
1149
1790
|
function isLayerInstance(input) {
|
|
1150
|
-
return isInstance(input,
|
|
1791
|
+
return isInstance(input, LayerSymbol);
|
|
1151
1792
|
}
|
|
1152
1793
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
return this.pathMatcher.test(path);
|
|
1157
|
-
}
|
|
1158
|
-
matchMethod(method) {
|
|
1159
|
-
let name = method.toLowerCase();
|
|
1160
|
-
if (name === exports.MethodName.HEAD && !smob.hasOwnProperty(this.layers, name)) {
|
|
1161
|
-
name = exports.MethodName.GET;
|
|
1162
|
-
}
|
|
1163
|
-
return Object.prototype.hasOwnProperty.call(this.layers, name);
|
|
1164
|
-
}
|
|
1165
|
-
// --------------------------------------------------
|
|
1166
|
-
getMethods() {
|
|
1167
|
-
const keys = Object.keys(this.layers);
|
|
1168
|
-
if (smob.hasOwnProperty(this.layers, exports.MethodName.GET) && !smob.hasOwnProperty(this.layers, exports.MethodName.HEAD)) {
|
|
1169
|
-
keys.push(exports.MethodName.HEAD);
|
|
1170
|
-
}
|
|
1171
|
-
return keys;
|
|
1172
|
-
}
|
|
1173
|
-
// --------------------------------------------------
|
|
1174
|
-
dispatch(req, res, meta, done) {
|
|
1175
|
-
/* istanbul ignore next */ if (!req.method) {
|
|
1176
|
-
done();
|
|
1177
|
-
return;
|
|
1178
|
-
}
|
|
1179
|
-
let name = req.method.toLowerCase();
|
|
1180
|
-
if (name === exports.MethodName.HEAD && !smob.hasOwnProperty(this.layers, name)) {
|
|
1181
|
-
name = exports.MethodName.GET;
|
|
1182
|
-
}
|
|
1183
|
-
const layers = this.layers[name];
|
|
1184
|
-
/* istanbul ignore next */ if (typeof layers === 'undefined' || layers.length === 0 || typeof meta.path === 'undefined') {
|
|
1185
|
-
done();
|
|
1186
|
-
return;
|
|
1187
|
-
}
|
|
1188
|
-
const layerMeta = {
|
|
1189
|
-
...meta
|
|
1190
|
-
};
|
|
1191
|
-
const output = this.pathMatcher.exec(meta.path);
|
|
1192
|
-
if (output) {
|
|
1193
|
-
layerMeta.params = smob.merge({}, meta.params || {}, output.params);
|
|
1194
|
-
}
|
|
1195
|
-
let index = -1;
|
|
1196
|
-
const next = (err)=>{
|
|
1197
|
-
index++;
|
|
1198
|
-
if (index >= layers.length) {
|
|
1199
|
-
setImmediate(done, err);
|
|
1200
|
-
return;
|
|
1201
|
-
}
|
|
1202
|
-
const layer = layers[index];
|
|
1203
|
-
if (err && !layer.isError()) {
|
|
1204
|
-
next(err);
|
|
1205
|
-
return;
|
|
1206
|
-
}
|
|
1207
|
-
layer.dispatch(req, res, {
|
|
1208
|
-
...layerMeta
|
|
1209
|
-
}, next);
|
|
1210
|
-
};
|
|
1211
|
-
next();
|
|
1212
|
-
}
|
|
1213
|
-
// --------------------------------------------------
|
|
1214
|
-
register(method, ...handlers) {
|
|
1215
|
-
this.layers[method] = [];
|
|
1216
|
-
for(let i = 0; i < handlers.length; i++){
|
|
1217
|
-
const layer = new Layer({
|
|
1218
|
-
path: this.path,
|
|
1219
|
-
pathMatcher: this.pathMatcherOptions
|
|
1220
|
-
}, handlers[i]);
|
|
1221
|
-
this.layers[method].push(layer);
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
get(...handlers) {
|
|
1225
|
-
return this.register(exports.MethodName.GET, ...handlers);
|
|
1226
|
-
}
|
|
1227
|
-
post(...handlers) {
|
|
1228
|
-
return this.register(exports.MethodName.POST, ...handlers);
|
|
1229
|
-
}
|
|
1230
|
-
put(...handlers) {
|
|
1231
|
-
return this.register(exports.MethodName.PUT, ...handlers);
|
|
1232
|
-
}
|
|
1233
|
-
patch(...handlers) {
|
|
1234
|
-
return this.register(exports.MethodName.PATCH, ...handlers);
|
|
1235
|
-
}
|
|
1236
|
-
delete(...handlers) {
|
|
1237
|
-
return this.register(exports.MethodName.DELETE, ...handlers);
|
|
1238
|
-
}
|
|
1239
|
-
head(...handlers) {
|
|
1240
|
-
return this.register(exports.MethodName.HEAD, ...handlers);
|
|
1794
|
+
function isPluginInstallContext(input) {
|
|
1795
|
+
if (!isObject(input) || !isObject(input.options)) {
|
|
1796
|
+
return false;
|
|
1241
1797
|
}
|
|
1242
|
-
|
|
1243
|
-
return
|
|
1798
|
+
if (typeof input.name !== 'undefined' && typeof input.name !== 'string') {
|
|
1799
|
+
return false;
|
|
1244
1800
|
}
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1801
|
+
return typeof input.path === 'undefined' || isPath(input.path);
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
function transformRouterOptions(input) {
|
|
1805
|
+
if (typeof input.etag !== 'undefined') {
|
|
1806
|
+
input.etag = buildEtagFn(input.etag);
|
|
1248
1807
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
this['@instanceof'] = Symbol.for('Route');
|
|
1252
|
-
this.layers = {};
|
|
1253
|
-
this.path = options.path;
|
|
1254
|
-
this.pathMatcherOptions = {
|
|
1255
|
-
end: true,
|
|
1256
|
-
strict: this.isStrictPath(),
|
|
1257
|
-
...options.pathMatcher
|
|
1258
|
-
};
|
|
1259
|
-
this.pathMatcher = new PathMatcher(this.path, this.pathMatcherOptions);
|
|
1808
|
+
if (typeof input.trustProxy !== 'undefined') {
|
|
1809
|
+
input.trustProxy = buildTrustProxyFn(input.trustProxy);
|
|
1260
1810
|
}
|
|
1811
|
+
return input;
|
|
1261
1812
|
}
|
|
1262
1813
|
|
|
1263
|
-
|
|
1264
|
-
return isInstance(input, 'Route');
|
|
1265
|
-
}
|
|
1814
|
+
const RouterSymbol = Symbol.for('Router');
|
|
1266
1815
|
|
|
1816
|
+
let nextId = 0;
|
|
1817
|
+
function generateRouterID() {
|
|
1818
|
+
return ++nextId;
|
|
1819
|
+
}
|
|
1267
1820
|
function isRouterInstance(input) {
|
|
1268
|
-
return isInstance(input,
|
|
1821
|
+
return isInstance(input, RouterSymbol);
|
|
1269
1822
|
}
|
|
1823
|
+
|
|
1270
1824
|
class Router {
|
|
1271
1825
|
// --------------------------------------------------
|
|
1272
|
-
setPathMatcherOptions(input) {
|
|
1273
|
-
this.pathMatcherOptions = input;
|
|
1274
|
-
if (this.pathMatcher) {
|
|
1275
|
-
this.pathMatcher.regexpOptions = this.pathMatcherOptions;
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
1826
|
setPath(value) {
|
|
1279
1827
|
if (value === '/' || !isPath(value)) {
|
|
1280
|
-
this.path = '/';
|
|
1281
1828
|
return;
|
|
1282
1829
|
}
|
|
1830
|
+
let path;
|
|
1283
1831
|
if (typeof value === 'string') {
|
|
1284
|
-
|
|
1832
|
+
path = withLeadingSlash(withoutTrailingSlash(`${value}`));
|
|
1285
1833
|
} else {
|
|
1286
|
-
|
|
1834
|
+
path = value;
|
|
1287
1835
|
}
|
|
1288
|
-
this.pathMatcher = new PathMatcher(
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
createListener() {
|
|
1292
|
-
this.isRoot = true;
|
|
1293
|
-
return (req, res)=>{
|
|
1294
|
-
this.dispatch(req, res);
|
|
1295
|
-
};
|
|
1296
|
-
}
|
|
1297
|
-
/* istanbul ignore next */ listen(port) {
|
|
1298
|
-
const server = node_http.createServer(this.createListener());
|
|
1299
|
-
return server.listen(port);
|
|
1836
|
+
this.pathMatcher = new PathMatcher(path, {
|
|
1837
|
+
end: false
|
|
1838
|
+
});
|
|
1300
1839
|
}
|
|
1301
1840
|
// --------------------------------------------------
|
|
1302
1841
|
matchPath(path) {
|
|
@@ -1306,239 +1845,279 @@ class Router {
|
|
|
1306
1845
|
return true;
|
|
1307
1846
|
}
|
|
1308
1847
|
// --------------------------------------------------
|
|
1309
|
-
dispatch(
|
|
1310
|
-
|
|
1311
|
-
meta = meta || {};
|
|
1312
|
-
let allowedMethods = [];
|
|
1313
|
-
if (this.isRoot && typeof this.timeout === 'number') {
|
|
1314
|
-
createRequestTimeout(res, this.timeout, done);
|
|
1315
|
-
}
|
|
1316
|
-
const fn = (err)=>{
|
|
1317
|
-
/* istanbul ignore if */ if (!this.isRoot) {
|
|
1318
|
-
if (typeof done !== 'undefined') {
|
|
1319
|
-
setImmediate(()=>done(err));
|
|
1320
|
-
}
|
|
1321
|
-
return;
|
|
1322
|
-
}
|
|
1323
|
-
if (typeof err !== 'undefined') {
|
|
1324
|
-
res.statusCode = 400;
|
|
1325
|
-
res.end();
|
|
1326
|
-
return;
|
|
1327
|
-
}
|
|
1328
|
-
if (req.method && req.method.toLowerCase() === exports.MethodName.OPTIONS) {
|
|
1329
|
-
const options = allowedMethods.map((key)=>key.toUpperCase()).join(',');
|
|
1330
|
-
res.setHeader(exports.HeaderName.ALLOW, options);
|
|
1331
|
-
send(res, options);
|
|
1332
|
-
return;
|
|
1333
|
-
}
|
|
1334
|
-
res.statusCode = 404;
|
|
1335
|
-
res.end();
|
|
1336
|
-
};
|
|
1337
|
-
let path = meta.path || useRequestPath(req);
|
|
1848
|
+
async dispatch(event, meta) {
|
|
1849
|
+
const allowedMethods = [];
|
|
1338
1850
|
if (this.pathMatcher) {
|
|
1339
|
-
const output = this.pathMatcher.exec(path);
|
|
1851
|
+
const output = this.pathMatcher.exec(meta.path);
|
|
1340
1852
|
if (typeof output !== 'undefined') {
|
|
1341
|
-
meta.mountPath = cleanDoubleSlashes(`${meta.mountPath
|
|
1342
|
-
if (path === output.path) {
|
|
1343
|
-
path = '/';
|
|
1853
|
+
meta.mountPath = cleanDoubleSlashes(`${meta.mountPath}/${output.path}`);
|
|
1854
|
+
if (meta.path === output.path) {
|
|
1855
|
+
meta.path = '/';
|
|
1344
1856
|
} else {
|
|
1345
|
-
path = withLeadingSlash(path.substring(output.path.length));
|
|
1857
|
+
meta.path = withLeadingSlash(meta.path.substring(output.path.length));
|
|
1346
1858
|
}
|
|
1347
|
-
meta.params =
|
|
1859
|
+
meta.params = {
|
|
1860
|
+
...meta.params,
|
|
1861
|
+
...output.params
|
|
1862
|
+
};
|
|
1348
1863
|
}
|
|
1349
1864
|
}
|
|
1350
|
-
meta.
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
let match = false;
|
|
1361
|
-
while(!match && index < this.stack.length){
|
|
1362
|
-
index++;
|
|
1363
|
-
layer = this.stack[index];
|
|
1364
|
-
if (isLayerInstance(layer)) {
|
|
1365
|
-
if (!layer.isError() && err) {
|
|
1366
|
-
continue;
|
|
1367
|
-
}
|
|
1368
|
-
match = layer.matchPath(path);
|
|
1865
|
+
meta.routerPath.push(this.id);
|
|
1866
|
+
let err;
|
|
1867
|
+
let item;
|
|
1868
|
+
let itemMeta;
|
|
1869
|
+
let match = false;
|
|
1870
|
+
for(let i = 0; i < this.stack.length; i++){
|
|
1871
|
+
item = this.stack[i];
|
|
1872
|
+
if (isLayerInstance(item)) {
|
|
1873
|
+
if (item.type !== exports.HandlerType.ERROR && err) {
|
|
1874
|
+
continue;
|
|
1369
1875
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
if (isRouteInstance(layer)) {
|
|
1374
|
-
match = layer.matchPath(path);
|
|
1375
|
-
if (req.method && !layer.matchMethod(req.method)) {
|
|
1876
|
+
match = item.matchPath(meta.path);
|
|
1877
|
+
if (match && event.req.method) {
|
|
1878
|
+
if (!item.matchMethod(event.req.method)) {
|
|
1376
1879
|
match = false;
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1880
|
+
}
|
|
1881
|
+
if (item.method) {
|
|
1882
|
+
allowedMethods.push(item.method);
|
|
1380
1883
|
}
|
|
1381
1884
|
}
|
|
1885
|
+
} else if (isRouterInstance(item)) {
|
|
1886
|
+
match = item.matchPath(meta.path);
|
|
1382
1887
|
}
|
|
1383
|
-
if (!match
|
|
1384
|
-
|
|
1385
|
-
return;
|
|
1386
|
-
}
|
|
1387
|
-
const layerMeta = {
|
|
1388
|
-
...meta
|
|
1389
|
-
};
|
|
1390
|
-
if (isLayerInstance(layer)) {
|
|
1391
|
-
const output = layer.exec(path);
|
|
1392
|
-
if (output) {
|
|
1393
|
-
layerMeta.params = smob.merge(output.params, layerMeta.params || {});
|
|
1394
|
-
layerMeta.mountPath = cleanDoubleSlashes(`${layerMeta.mountPath || ''}/${output.path}`);
|
|
1395
|
-
}
|
|
1888
|
+
if (!match) {
|
|
1889
|
+
continue;
|
|
1396
1890
|
}
|
|
1891
|
+
itemMeta = cloneDispatcherMeta(meta);
|
|
1397
1892
|
if (err) {
|
|
1398
|
-
|
|
1399
|
-
layer.dispatch(req, res, layerMeta, next, err);
|
|
1400
|
-
return;
|
|
1401
|
-
}
|
|
1402
|
-
/* istanbul ignore next */ setImmediate(next, err);
|
|
1403
|
-
return;
|
|
1893
|
+
itemMeta.error = err;
|
|
1404
1894
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
/* istanbul ignore next */ dispatchAsync(req, res) {
|
|
1410
|
-
return new Promise((resolve, reject)=>{
|
|
1411
|
-
this.dispatch(req, res, {}, (err)=>{
|
|
1412
|
-
if (err) {
|
|
1413
|
-
reject(err);
|
|
1414
|
-
return;
|
|
1895
|
+
try {
|
|
1896
|
+
const dispatched = await item.dispatch(event, itemMeta);
|
|
1897
|
+
if (dispatched) {
|
|
1898
|
+
return true;
|
|
1415
1899
|
}
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
route(path) {
|
|
1422
|
-
if (typeof path === 'string' && path.length > 0) {
|
|
1423
|
-
path = withLeadingSlash(path);
|
|
1900
|
+
} catch (e) {
|
|
1901
|
+
if (isError(e)) {
|
|
1902
|
+
err = e;
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1424
1905
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
return this.stack[index];
|
|
1906
|
+
if (err) {
|
|
1907
|
+
throw err;
|
|
1428
1908
|
}
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
sensitive: this.pathMatcherOptions.sensitive
|
|
1909
|
+
if (event.req.method && event.req.method.toLowerCase() === exports.MethodName.OPTIONS) {
|
|
1910
|
+
if (allowedMethods.indexOf(exports.MethodName.GET) !== -1) {
|
|
1911
|
+
allowedMethods.push(exports.MethodName.HEAD);
|
|
1433
1912
|
}
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1913
|
+
smob.distinctArray(allowedMethods);
|
|
1914
|
+
const options = allowedMethods.map((key)=>key.toUpperCase()).join(',');
|
|
1915
|
+
if (!isResponseGone(event.res)) {
|
|
1916
|
+
event.res.setHeader(exports.HeaderName.ALLOW, options);
|
|
1917
|
+
await send(event.res, options);
|
|
1918
|
+
}
|
|
1919
|
+
return true;
|
|
1920
|
+
}
|
|
1921
|
+
return false;
|
|
1437
1922
|
}
|
|
1438
|
-
delete(path,
|
|
1439
|
-
|
|
1440
|
-
|
|
1923
|
+
delete(path, handler) {
|
|
1924
|
+
if (isPath(path)) {
|
|
1925
|
+
this.use({
|
|
1926
|
+
...handler,
|
|
1927
|
+
method: exports.MethodName.DELETE,
|
|
1928
|
+
path
|
|
1929
|
+
});
|
|
1930
|
+
return this;
|
|
1931
|
+
}
|
|
1932
|
+
this.use({
|
|
1933
|
+
...path,
|
|
1934
|
+
method: exports.MethodName.DELETE
|
|
1935
|
+
});
|
|
1441
1936
|
return this;
|
|
1442
1937
|
}
|
|
1443
|
-
get(path,
|
|
1444
|
-
|
|
1445
|
-
|
|
1938
|
+
get(path, handler) {
|
|
1939
|
+
if (isPath(path)) {
|
|
1940
|
+
this.use({
|
|
1941
|
+
...handler,
|
|
1942
|
+
method: exports.MethodName.GET,
|
|
1943
|
+
path
|
|
1944
|
+
});
|
|
1945
|
+
return this;
|
|
1946
|
+
}
|
|
1947
|
+
this.use({
|
|
1948
|
+
...path,
|
|
1949
|
+
method: exports.MethodName.GET
|
|
1950
|
+
});
|
|
1446
1951
|
return this;
|
|
1447
1952
|
}
|
|
1448
|
-
post(path,
|
|
1449
|
-
|
|
1450
|
-
|
|
1953
|
+
post(path, handler) {
|
|
1954
|
+
if (isPath(path)) {
|
|
1955
|
+
this.use({
|
|
1956
|
+
...handler,
|
|
1957
|
+
method: exports.MethodName.POST,
|
|
1958
|
+
path
|
|
1959
|
+
});
|
|
1960
|
+
return this;
|
|
1961
|
+
}
|
|
1962
|
+
this.use({
|
|
1963
|
+
...path,
|
|
1964
|
+
method: exports.MethodName.POST
|
|
1965
|
+
});
|
|
1451
1966
|
return this;
|
|
1452
1967
|
}
|
|
1453
|
-
put(path,
|
|
1454
|
-
|
|
1455
|
-
|
|
1968
|
+
put(path, handler) {
|
|
1969
|
+
if (isPath(path)) {
|
|
1970
|
+
this.use({
|
|
1971
|
+
...handler,
|
|
1972
|
+
method: exports.MethodName.PUT,
|
|
1973
|
+
path
|
|
1974
|
+
});
|
|
1975
|
+
return this;
|
|
1976
|
+
}
|
|
1977
|
+
this.use({
|
|
1978
|
+
...path,
|
|
1979
|
+
method: exports.MethodName.PUT
|
|
1980
|
+
});
|
|
1456
1981
|
return this;
|
|
1457
1982
|
}
|
|
1458
|
-
patch(path,
|
|
1459
|
-
|
|
1460
|
-
|
|
1983
|
+
patch(path, handler) {
|
|
1984
|
+
if (isPath(path)) {
|
|
1985
|
+
this.use({
|
|
1986
|
+
...handler,
|
|
1987
|
+
method: exports.MethodName.PATCH,
|
|
1988
|
+
path
|
|
1989
|
+
});
|
|
1990
|
+
return this;
|
|
1991
|
+
}
|
|
1992
|
+
this.use({
|
|
1993
|
+
...path,
|
|
1994
|
+
method: exports.MethodName.PATCH
|
|
1995
|
+
});
|
|
1461
1996
|
return this;
|
|
1462
1997
|
}
|
|
1463
|
-
head(path,
|
|
1464
|
-
|
|
1465
|
-
|
|
1998
|
+
head(path, handler) {
|
|
1999
|
+
if (isPath(path)) {
|
|
2000
|
+
this.use({
|
|
2001
|
+
...handler,
|
|
2002
|
+
method: exports.MethodName.HEAD,
|
|
2003
|
+
path
|
|
2004
|
+
});
|
|
2005
|
+
return this;
|
|
2006
|
+
}
|
|
2007
|
+
this.use({
|
|
2008
|
+
...path,
|
|
2009
|
+
method: exports.MethodName.HEAD
|
|
2010
|
+
});
|
|
1466
2011
|
return this;
|
|
1467
2012
|
}
|
|
1468
|
-
options(path,
|
|
1469
|
-
|
|
1470
|
-
|
|
2013
|
+
options(path, handler) {
|
|
2014
|
+
if (isPath(path)) {
|
|
2015
|
+
this.use({
|
|
2016
|
+
...handler,
|
|
2017
|
+
method: exports.MethodName.OPTIONS,
|
|
2018
|
+
path
|
|
2019
|
+
});
|
|
2020
|
+
return this;
|
|
2021
|
+
}
|
|
2022
|
+
this.use({
|
|
2023
|
+
...path,
|
|
2024
|
+
method: exports.MethodName.OPTIONS
|
|
2025
|
+
});
|
|
1471
2026
|
return this;
|
|
1472
2027
|
}
|
|
1473
2028
|
use(...input) {
|
|
1474
2029
|
/* istanbul ignore next */ if (input.length === 0) {
|
|
1475
2030
|
return this;
|
|
1476
2031
|
}
|
|
2032
|
+
const modifyPath = (input)=>{
|
|
2033
|
+
if (typeof input === 'string') {
|
|
2034
|
+
return withLeadingSlash(input);
|
|
2035
|
+
}
|
|
2036
|
+
return input;
|
|
2037
|
+
};
|
|
1477
2038
|
let path;
|
|
1478
|
-
if (isPath(input[0])) {
|
|
1479
|
-
path = input.shift();
|
|
1480
|
-
}
|
|
1481
2039
|
for(let i = 0; i < input.length; i++){
|
|
1482
2040
|
const item = input[i];
|
|
2041
|
+
if (isPath(item)) {
|
|
2042
|
+
path = modifyPath(item);
|
|
2043
|
+
continue;
|
|
2044
|
+
}
|
|
1483
2045
|
if (isRouterInstance(item)) {
|
|
1484
2046
|
if (path) {
|
|
1485
2047
|
item.setPath(path);
|
|
1486
2048
|
}
|
|
1487
|
-
item.setPathMatcherOptions(this.pathMatcherOptions);
|
|
1488
2049
|
this.stack.push(item);
|
|
1489
2050
|
continue;
|
|
1490
2051
|
}
|
|
1491
|
-
if (
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
pathMatcher: {
|
|
1495
|
-
strict: false,
|
|
1496
|
-
end: false,
|
|
1497
|
-
sensitive: this.pathMatcherOptions.sensitive
|
|
1498
|
-
}
|
|
1499
|
-
}, item));
|
|
2052
|
+
if (isHandler(item)) {
|
|
2053
|
+
item.path = path || modifyPath(item.path);
|
|
2054
|
+
this.stack.push(new Layer(item));
|
|
1500
2055
|
}
|
|
1501
2056
|
}
|
|
1502
2057
|
return this;
|
|
1503
2058
|
}
|
|
1504
2059
|
// --------------------------------------------------
|
|
1505
|
-
|
|
1506
|
-
|
|
2060
|
+
install(plugin, context) {
|
|
2061
|
+
if (isPluginInstallContext(context)) {
|
|
2062
|
+
const name = context.name || plugin.name;
|
|
2063
|
+
if (context.path) {
|
|
2064
|
+
const router = new Router({
|
|
2065
|
+
name
|
|
2066
|
+
});
|
|
2067
|
+
plugin.install(router, context.options);
|
|
2068
|
+
this.use(context.path, router);
|
|
2069
|
+
return this;
|
|
2070
|
+
}
|
|
2071
|
+
plugin.install(this, context.options);
|
|
2072
|
+
return this;
|
|
2073
|
+
}
|
|
2074
|
+
plugin.install(this, context);
|
|
2075
|
+
return this;
|
|
2076
|
+
}
|
|
2077
|
+
uninstall(name) {
|
|
2078
|
+
const index = this.stack.findIndex((el)=>isRouterInstance(el) && el.name === name);
|
|
2079
|
+
if (index !== -1) {
|
|
2080
|
+
this.stack.splice(index, 1);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
// --------------------------------------------------
|
|
2084
|
+
constructor(options = {}){
|
|
2085
|
+
this['@instanceof'] = RouterSymbol;
|
|
1507
2086
|
/**
|
|
1508
2087
|
* Array of mounted layers, routes & routers.
|
|
1509
2088
|
*
|
|
1510
2089
|
* @protected
|
|
1511
2090
|
*/ this.stack = [];
|
|
1512
|
-
|
|
1513
|
-
this.
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
...ctx.pathMatcher || {}
|
|
1517
|
-
};
|
|
1518
|
-
this.timeout = ctx.timeout;
|
|
1519
|
-
this.setPath(ctx.path || '/');
|
|
2091
|
+
this.id = generateRouterID();
|
|
2092
|
+
this.name = options.name;
|
|
2093
|
+
this.setPath(options.path);
|
|
2094
|
+
setRouterOptions(this.id, transformRouterOptions(options));
|
|
1520
2095
|
}
|
|
1521
2096
|
}
|
|
1522
2097
|
|
|
2098
|
+
exports.ErrorProxy = ErrorProxy;
|
|
1523
2099
|
exports.Layer = Layer;
|
|
1524
2100
|
exports.PathMatcher = PathMatcher;
|
|
1525
|
-
exports.Route = Route;
|
|
1526
2101
|
exports.Router = Router;
|
|
1527
2102
|
exports.appendResponseHeader = appendResponseHeader;
|
|
1528
2103
|
exports.appendResponseHeaderDirective = appendResponseHeaderDirective;
|
|
1529
|
-
exports.
|
|
1530
|
-
exports.
|
|
1531
|
-
exports.
|
|
1532
|
-
exports.
|
|
1533
|
-
exports.
|
|
1534
|
-
exports.
|
|
2104
|
+
exports.buildDispatcherMeta = buildDispatcherMeta;
|
|
2105
|
+
exports.cloneDispatcherMeta = cloneDispatcherMeta;
|
|
2106
|
+
exports.cloneDispatcherMetaParams = cloneDispatcherMetaParams;
|
|
2107
|
+
exports.coreHandler = coreHandler;
|
|
2108
|
+
exports.createError = createError;
|
|
2109
|
+
exports.createNodeDispatcher = createNodeDispatcher;
|
|
2110
|
+
exports.createRawDispatcher = createRawDispatcher;
|
|
2111
|
+
exports.createRequest = createRequest;
|
|
2112
|
+
exports.createResponse = createResponse;
|
|
2113
|
+
exports.createWebDispatcher = createWebDispatcher;
|
|
2114
|
+
exports.dispatchNodeRequest = dispatchNodeRequest;
|
|
2115
|
+
exports.dispatchRawRequest = dispatchRawRequest;
|
|
2116
|
+
exports.dispatchWebRequest = dispatchWebRequest;
|
|
2117
|
+
exports.errorHandler = errorHandler;
|
|
1535
2118
|
exports.extendRequestBody = extendRequestBody;
|
|
1536
2119
|
exports.extendRequestCookies = extendRequestCookies;
|
|
1537
2120
|
exports.extendRequestQuery = extendRequestQuery;
|
|
1538
|
-
exports.generateETag = generateETag;
|
|
1539
|
-
exports.getCharsetForMimeType = getCharsetForMimeType;
|
|
1540
|
-
exports.getConfigOption = getConfigOption;
|
|
1541
|
-
exports.getMimeType = getMimeType;
|
|
1542
2121
|
exports.getRequestAcceptableCharset = getRequestAcceptableCharset;
|
|
1543
2122
|
exports.getRequestAcceptableCharsets = getRequestAcceptableCharsets;
|
|
1544
2123
|
exports.getRequestAcceptableContentType = getRequestAcceptableContentType;
|
|
@@ -1551,22 +2130,19 @@ exports.getRequestHeader = getRequestHeader;
|
|
|
1551
2130
|
exports.getRequestHostName = getRequestHostName;
|
|
1552
2131
|
exports.getRequestIP = getRequestIP;
|
|
1553
2132
|
exports.getRequestProtocol = getRequestProtocol;
|
|
1554
|
-
exports.hasLeadingSlash = hasLeadingSlash;
|
|
1555
2133
|
exports.hasRequestBody = hasRequestBody;
|
|
1556
2134
|
exports.hasRequestCookies = hasRequestCookies;
|
|
1557
2135
|
exports.hasRequestQuery = hasRequestQuery;
|
|
1558
|
-
exports.
|
|
1559
|
-
exports.
|
|
2136
|
+
exports.isError = isError;
|
|
2137
|
+
exports.isHandler = isHandler;
|
|
1560
2138
|
exports.isLayerInstance = isLayerInstance;
|
|
1561
|
-
exports.isObject = isObject;
|
|
1562
2139
|
exports.isPath = isPath;
|
|
1563
|
-
exports.
|
|
2140
|
+
exports.isPluginInstallContext = isPluginInstallContext;
|
|
1564
2141
|
exports.isRequestCacheable = isRequestCacheable;
|
|
1565
|
-
exports.
|
|
2142
|
+
exports.isResponseGone = isResponseGone;
|
|
1566
2143
|
exports.isRouterInstance = isRouterInstance;
|
|
1567
2144
|
exports.matchRequestContentType = matchRequestContentType;
|
|
1568
|
-
exports.
|
|
1569
|
-
exports.processHandlerExecutionOutput = processHandlerExecutionOutput;
|
|
2145
|
+
exports.mergeDispatcherMetaParams = mergeDispatcherMetaParams;
|
|
1570
2146
|
exports.send = send;
|
|
1571
2147
|
exports.sendAccepted = sendAccepted;
|
|
1572
2148
|
exports.sendCreated = sendCreated;
|
|
@@ -1574,8 +2150,8 @@ exports.sendFile = sendFile;
|
|
|
1574
2150
|
exports.sendFormat = sendFormat;
|
|
1575
2151
|
exports.sendRedirect = sendRedirect;
|
|
1576
2152
|
exports.sendStream = sendStream;
|
|
1577
|
-
exports.
|
|
1578
|
-
exports.
|
|
2153
|
+
exports.sendWebBlob = sendWebBlob;
|
|
2154
|
+
exports.sendWebResponse = sendWebResponse;
|
|
1579
2155
|
exports.setRequestBody = setRequestBody;
|
|
1580
2156
|
exports.setRequestCookies = setRequestCookies;
|
|
1581
2157
|
exports.setRequestEnv = setRequestEnv;
|
|
@@ -1584,12 +2160,12 @@ exports.setRequestMountPath = setRequestMountPath;
|
|
|
1584
2160
|
exports.setRequestParam = setRequestParam;
|
|
1585
2161
|
exports.setRequestParams = setRequestParams;
|
|
1586
2162
|
exports.setRequestQuery = setRequestQuery;
|
|
2163
|
+
exports.setRequestRouterPath = setRequestRouterPath;
|
|
1587
2164
|
exports.setResponseCacheHeaders = setResponseCacheHeaders;
|
|
1588
2165
|
exports.setResponseContentTypeByFileName = setResponseContentTypeByFileName;
|
|
1589
2166
|
exports.setResponseHeaderAttachment = setResponseHeaderAttachment;
|
|
1590
2167
|
exports.setResponseHeaderContentType = setResponseHeaderContentType;
|
|
1591
2168
|
exports.unsetRequestEnv = unsetRequestEnv;
|
|
1592
|
-
exports.useConfig = useConfig;
|
|
1593
2169
|
exports.useRequestBody = useRequestBody;
|
|
1594
2170
|
exports.useRequestCookie = useRequestCookie;
|
|
1595
2171
|
exports.useRequestCookies = useRequestCookies;
|
|
@@ -1600,8 +2176,5 @@ exports.useRequestParam = useRequestParam;
|
|
|
1600
2176
|
exports.useRequestParams = useRequestParams;
|
|
1601
2177
|
exports.useRequestPath = useRequestPath;
|
|
1602
2178
|
exports.useRequestQuery = useRequestQuery;
|
|
1603
|
-
exports.
|
|
1604
|
-
exports.withTrailingSlash = withTrailingSlash;
|
|
1605
|
-
exports.withoutLeadingSlash = withoutLeadingSlash;
|
|
1606
|
-
exports.withoutTrailingSlash = withoutTrailingSlash;
|
|
2179
|
+
exports.useRequestRouterPath = useRequestRouterPath;
|
|
1607
2180
|
//# sourceMappingURL=index.cjs.map
|