routup 0.14.2 → 1.0.0-alpha.2
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 +9 -3
- package/dist/config/index.d.ts +2 -0
- package/dist/config/module.d.ts +8 -0
- package/dist/config/type.d.ts +34 -0
- package/dist/constants.d.ts +39 -0
- package/dist/handler/index.d.ts +0 -1
- package/dist/handler/utils.d.ts +1 -2
- package/dist/helpers/index.d.ts +3 -0
- package/dist/helpers/request/body.d.ts +5 -0
- package/dist/helpers/request/cache.d.ts +2 -0
- package/dist/helpers/request/cookie.d.ts +8 -0
- package/dist/helpers/request/env.d.ts +6 -0
- package/dist/helpers/request/header-accept-charset.d.ts +3 -0
- package/dist/helpers/request/header-accept-encoding.d.ts +4 -0
- package/dist/helpers/request/header-accept-language.d.ts +3 -0
- package/dist/helpers/request/header-accept.d.ts +3 -0
- package/dist/helpers/request/header-content-type.d.ts +2 -0
- package/dist/helpers/request/header.d.ts +5 -0
- package/dist/helpers/request/hostname.d.ts +7 -0
- package/dist/helpers/request/index.d.ts +18 -0
- package/dist/helpers/request/ip.d.ts +7 -0
- package/dist/helpers/request/mount-path.d.ts +3 -0
- package/dist/helpers/request/negotiator.d.ts +3 -0
- package/dist/helpers/request/params.d.ts +5 -0
- package/dist/helpers/request/path.d.ts +2 -0
- package/dist/helpers/request/protocol.d.ts +8 -0
- package/dist/helpers/request/query.d.ts +8 -0
- package/dist/helpers/response/cache.d.ts +7 -0
- package/dist/helpers/response/header-attachment.d.ts +2 -0
- package/dist/helpers/response/header-content-type.d.ts +2 -0
- package/dist/helpers/response/header.d.ts +5 -0
- package/dist/helpers/response/index.d.ts +12 -0
- package/dist/helpers/response/send-accepted.d.ts +2 -0
- package/dist/helpers/response/send-created.d.ts +2 -0
- package/dist/helpers/response/send-file.d.ts +9 -0
- package/dist/helpers/response/send-format.d.ts +6 -0
- package/dist/helpers/response/send-redirect.d.ts +2 -0
- package/dist/helpers/response/send-stream.d.ts +4 -0
- package/dist/helpers/response/send.d.ts +2 -0
- package/dist/helpers/response/utils.d.ts +3 -0
- package/dist/helpers/type.d.ts +3 -0
- package/dist/index.cjs +1085 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +991 -4
- package/dist/index.mjs.map +1 -1
- package/dist/layer/index.d.ts +0 -1
- package/dist/layer/module.d.ts +1 -3
- package/dist/layer/type.d.ts +0 -1
- package/dist/layer/utils.d.ts +0 -1
- package/dist/path/index.d.ts +0 -1
- package/dist/path/matcher.d.ts +0 -1
- package/dist/path/type.d.ts +0 -1
- package/dist/route/index.d.ts +0 -1
- package/dist/route/module.d.ts +2 -4
- package/dist/route/type.d.ts +0 -1
- package/dist/route/utils.d.ts +0 -1
- package/dist/router/index.d.ts +0 -1
- package/dist/router/module.d.ts +1 -3
- package/dist/router/type.d.ts +0 -1
- package/dist/type.d.ts +9 -1
- package/dist/utils/etag/index.d.ts +2 -0
- package/dist/utils/etag/module.d.ts +12 -0
- package/dist/utils/etag/type.d.ts +16 -0
- package/dist/utils/etag/utils.d.ts +2 -0
- package/dist/utils/index.d.ts +5 -1
- package/dist/utils/is-instance.d.ts +0 -1
- package/dist/utils/mime.d.ts +2 -0
- package/dist/utils/object.d.ts +1 -0
- package/dist/utils/path.d.ts +0 -1
- package/dist/utils/promise.d.ts +0 -1
- package/dist/utils/request.d.ts +1 -2
- package/dist/utils/trust-proxy/index.d.ts +2 -0
- package/dist/utils/trust-proxy/module.d.ts +2 -0
- package/dist/utils/trust-proxy/type.d.ts +2 -0
- package/dist/utils/url.d.ts +7 -0
- package/package.json +30 -13
- package/dist/handler/index.d.ts.map +0 -1
- package/dist/handler/utils.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/layer/index.d.ts.map +0 -1
- package/dist/layer/module.d.ts.map +0 -1
- package/dist/layer/type.d.ts.map +0 -1
- package/dist/layer/utils.d.ts.map +0 -1
- package/dist/path/index.d.ts.map +0 -1
- package/dist/path/matcher.d.ts.map +0 -1
- package/dist/path/type.d.ts.map +0 -1
- package/dist/route/index.d.ts.map +0 -1
- package/dist/route/module.d.ts.map +0 -1
- package/dist/route/type.d.ts.map +0 -1
- package/dist/route/utils.d.ts.map +0 -1
- package/dist/router/index.d.ts.map +0 -1
- package/dist/router/module.d.ts.map +0 -1
- package/dist/router/type.d.ts.map +0 -1
- package/dist/type.d.ts.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/is-instance.d.ts.map +0 -1
- package/dist/utils/path.d.ts.map +0 -1
- package/dist/utils/promise.d.ts.map +0 -1
- package/dist/utils/request.d.ts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,110 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import
|
|
1
|
+
import { Continu } from 'continu';
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
import zod from 'zod';
|
|
4
|
+
import { merge, hasOwnProperty, mergeArrays } from 'smob';
|
|
5
|
+
import crypto from 'node:crypto';
|
|
6
|
+
import { Stats, stat, createReadStream } from 'node:fs';
|
|
7
|
+
import proxyAddr from 'proxy-addr';
|
|
8
|
+
import { getType, get } from 'mime-explorer';
|
|
4
9
|
import { GatewayTimeoutErrorOptions, BadRequestError } from '@ebec/http';
|
|
10
|
+
import Negotiator from 'negotiator';
|
|
11
|
+
import { URL } from 'node:url';
|
|
12
|
+
import path from 'node:path';
|
|
5
13
|
import { pathToRegexp } from 'path-to-regexp';
|
|
6
14
|
import { createServer } from 'node:http';
|
|
7
15
|
|
|
16
|
+
/*
|
|
17
|
+
* Copyright (c) 2022-2023.
|
|
18
|
+
* Author Peter Placzek (tada5hi)
|
|
19
|
+
* For the full copyright and license information,
|
|
20
|
+
* view the LICENSE file that was distributed with this source code.
|
|
21
|
+
*/ function isObject(item) {
|
|
22
|
+
return !!item && typeof item === 'object' && !Array.isArray(item);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Determine if object is a Stats object.
|
|
27
|
+
*
|
|
28
|
+
* @param {object} obj
|
|
29
|
+
* @return {boolean}
|
|
30
|
+
* @api private
|
|
31
|
+
*/ function isStatsObject(obj) {
|
|
32
|
+
// genuine fs.Stats
|
|
33
|
+
if (typeof Stats === 'function' && obj instanceof Stats) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
// quack quack
|
|
37
|
+
return !!obj && typeof obj === 'object' && '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';
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Generate an ETag.
|
|
41
|
+
*/ function generateETag(input) {
|
|
42
|
+
if (isStatsObject(input)) {
|
|
43
|
+
const mtime = input.mtime.getTime().toString(16);
|
|
44
|
+
const size = input.size.toString(16);
|
|
45
|
+
return `"${size}-${mtime}"`;
|
|
46
|
+
}
|
|
47
|
+
if (input.length === 0) {
|
|
48
|
+
// fast-path empty
|
|
49
|
+
return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
|
|
50
|
+
}
|
|
51
|
+
const entity = Buffer.isBuffer(input) ? input.toString('utf-8') : input;
|
|
52
|
+
// compute hash of entity
|
|
53
|
+
const hash = crypto.createHash('sha1').update(entity, 'utf8').digest('base64').substring(0, 27);
|
|
54
|
+
return `"${entity.length.toString(16)}-${hash}"`;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create a simple ETag.
|
|
58
|
+
*/ function createEtag(input, options) {
|
|
59
|
+
options = options || {};
|
|
60
|
+
const weak = typeof options.weak === 'boolean' ? options.weak : isStatsObject(input);
|
|
61
|
+
// generate entity tag
|
|
62
|
+
const tag = generateETag(input);
|
|
63
|
+
return weak ? `W/${tag}` : tag;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function buildEtagFn(input) {
|
|
67
|
+
if (typeof input === 'function') {
|
|
68
|
+
return input;
|
|
69
|
+
}
|
|
70
|
+
input = input ?? true;
|
|
71
|
+
if (input === false) {
|
|
72
|
+
return ()=>undefined;
|
|
73
|
+
}
|
|
74
|
+
let options = {
|
|
75
|
+
weak: true
|
|
76
|
+
};
|
|
77
|
+
if (isObject(input)) {
|
|
78
|
+
options = merge(input, options);
|
|
79
|
+
}
|
|
80
|
+
return (body, encoding, size)=>{
|
|
81
|
+
const buff = Buffer.isBuffer(body) ? body : Buffer.from(body, encoding);
|
|
82
|
+
if (typeof options.threshold !== 'undefined') {
|
|
83
|
+
size = size ?? Buffer.byteLength(buff);
|
|
84
|
+
if (size <= options.threshold) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return createEtag(buff, options);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function buildTrustProxyFn(input) {
|
|
93
|
+
if (typeof input === 'function') {
|
|
94
|
+
return input;
|
|
95
|
+
}
|
|
96
|
+
if (input === true) {
|
|
97
|
+
return ()=>true;
|
|
98
|
+
}
|
|
99
|
+
if (typeof input === 'number') {
|
|
100
|
+
return (_address, hop)=>hop < input;
|
|
101
|
+
}
|
|
102
|
+
if (typeof input === 'string') {
|
|
103
|
+
input = input.split(',').map((value)=>value.trim());
|
|
104
|
+
}
|
|
105
|
+
return proxyAddr.compile(input || []);
|
|
106
|
+
}
|
|
107
|
+
|
|
8
108
|
/*
|
|
9
109
|
* Copyright (c) 2022-2022.
|
|
10
110
|
* Author Peter Placzek (tada5hi)
|
|
@@ -14,6 +114,23 @@ import { createServer } from 'node:http';
|
|
|
14
114
|
return typeof input === 'object' && input !== null && input['@instanceof'] === Symbol.for(name);
|
|
15
115
|
}
|
|
16
116
|
|
|
117
|
+
function getMimeType(type) {
|
|
118
|
+
if (type.indexOf('/') !== -1) {
|
|
119
|
+
return type;
|
|
120
|
+
}
|
|
121
|
+
return getType(type);
|
|
122
|
+
}
|
|
123
|
+
function getCharsetForMimeType(type) {
|
|
124
|
+
if (/^text\/|^application\/(javascript|json)/.test(type)) {
|
|
125
|
+
return 'utf-8';
|
|
126
|
+
}
|
|
127
|
+
const meta = get(type);
|
|
128
|
+
if (meta && meta.charset) {
|
|
129
|
+
return meta.charset.toLowerCase();
|
|
130
|
+
}
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
17
134
|
/*
|
|
18
135
|
* Copyright (c) 2022.
|
|
19
136
|
* Author Peter Placzek (tada5hi)
|
|
@@ -49,6 +166,876 @@ function isPromise(p) {
|
|
|
49
166
|
});
|
|
50
167
|
}
|
|
51
168
|
|
|
169
|
+
/*
|
|
170
|
+
* Copyright (c) 2022-2023.
|
|
171
|
+
* Author Peter Placzek (tada5hi)
|
|
172
|
+
* For the full copyright and license information,
|
|
173
|
+
* view the LICENSE file that was distributed with this source code.
|
|
174
|
+
*/ const TRAILING_SLASH_RE = /\/$|\/\?/;
|
|
175
|
+
function hasTrailingSlash(input = '', queryParams = false) {
|
|
176
|
+
if (!queryParams) {
|
|
177
|
+
return input.endsWith('/');
|
|
178
|
+
}
|
|
179
|
+
return TRAILING_SLASH_RE.test(input);
|
|
180
|
+
}
|
|
181
|
+
function withoutTrailingSlash(input = '', queryParams = false) {
|
|
182
|
+
if (!queryParams) {
|
|
183
|
+
return (hasTrailingSlash(input) ? input.slice(0, -1) : input) || '/';
|
|
184
|
+
}
|
|
185
|
+
if (!hasTrailingSlash(input, true)) {
|
|
186
|
+
return input || '/';
|
|
187
|
+
}
|
|
188
|
+
const [s0, ...s] = input.split('?');
|
|
189
|
+
return (s0.slice(0, -1) || '/') + (s.length ? `?${s.join('?')}` : '');
|
|
190
|
+
}
|
|
191
|
+
function withTrailingSlash(input = '', queryParams = false) {
|
|
192
|
+
if (!queryParams) {
|
|
193
|
+
return input.endsWith('/') ? input : `${input}/`;
|
|
194
|
+
}
|
|
195
|
+
if (hasTrailingSlash(input, true)) {
|
|
196
|
+
return input || '/';
|
|
197
|
+
}
|
|
198
|
+
const [s0, ...s] = input.split('?');
|
|
199
|
+
return `${s0}/${s.length ? `?${s.join('?')}` : ''}`;
|
|
200
|
+
}
|
|
201
|
+
function hasLeadingSlash(input = '') {
|
|
202
|
+
return input.startsWith('/');
|
|
203
|
+
}
|
|
204
|
+
function withoutLeadingSlash(input = '') {
|
|
205
|
+
return (hasLeadingSlash(input) ? input.substr(1) : input) || '/';
|
|
206
|
+
}
|
|
207
|
+
function withLeadingSlash(input = '') {
|
|
208
|
+
return hasLeadingSlash(input) ? input : `/${input}`;
|
|
209
|
+
}
|
|
210
|
+
function cleanDoubleSlashes(input = '') {
|
|
211
|
+
return input.split('://').map((str)=>str.replace(/\/{2,}/g, '/')).join('://');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
let instance;
|
|
215
|
+
function buildConfig() {
|
|
216
|
+
return new Continu({
|
|
217
|
+
defaults: {
|
|
218
|
+
env: process.env.NODE_ENV || 'development',
|
|
219
|
+
trustProxy: ()=>false,
|
|
220
|
+
subdomainOffset: 2,
|
|
221
|
+
etag: buildEtagFn(),
|
|
222
|
+
proxyIpMax: 0
|
|
223
|
+
},
|
|
224
|
+
transformers: {
|
|
225
|
+
etag: (value)=>buildEtagFn(value),
|
|
226
|
+
trustProxy: (value)=>buildTrustProxyFn(value)
|
|
227
|
+
},
|
|
228
|
+
validators: {
|
|
229
|
+
env: (value)=>zod.string().safeParse(value),
|
|
230
|
+
trustProxy: (value)=>zod.any().safeParse(value),
|
|
231
|
+
subdomainOffset: (value)=>zod.number().nonnegative().safeParse(value),
|
|
232
|
+
etag: (value)=>zod.any().safeParse(value),
|
|
233
|
+
proxyIpMax: (value)=>zod.number().nonnegative().safeParse(value)
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
function useConfig() {
|
|
238
|
+
if (typeof instance !== 'undefined') {
|
|
239
|
+
return instance;
|
|
240
|
+
}
|
|
241
|
+
instance = buildConfig();
|
|
242
|
+
return instance;
|
|
243
|
+
}
|
|
244
|
+
function setConfig(config) {
|
|
245
|
+
instance = config;
|
|
246
|
+
}
|
|
247
|
+
function setConfigOption(key, value) {
|
|
248
|
+
const config = useConfig();
|
|
249
|
+
config.setRaw(key, value);
|
|
250
|
+
return config.get();
|
|
251
|
+
}
|
|
252
|
+
function getConfigOption(key) {
|
|
253
|
+
const config = useConfig();
|
|
254
|
+
return config.get(key);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/*
|
|
258
|
+
* Copyright (c) 2022-2023.
|
|
259
|
+
* Author Peter Placzek (tada5hi)
|
|
260
|
+
* For the full copyright and license information,
|
|
261
|
+
* view the LICENSE file that was distributed with this source code.
|
|
262
|
+
*/ var Method;
|
|
263
|
+
(function(Method) {
|
|
264
|
+
Method["GET"] = 'get';
|
|
265
|
+
Method["POST"] = 'post';
|
|
266
|
+
Method["PUT"] = 'put';
|
|
267
|
+
Method["PATCH"] = 'patch';
|
|
268
|
+
Method["DELETE"] = 'delete';
|
|
269
|
+
Method["OPTIONS"] = 'options';
|
|
270
|
+
Method["HEAD"] = 'head';
|
|
271
|
+
})(Method || (Method = {}));
|
|
272
|
+
var HeaderName;
|
|
273
|
+
(function(HeaderName) {
|
|
274
|
+
HeaderName["ACCEPT"] = 'accept';
|
|
275
|
+
HeaderName["ACCEPT_CHARSET"] = 'accept-charset';
|
|
276
|
+
HeaderName["ACCEPT_ENCODING"] = 'accept-encoding';
|
|
277
|
+
HeaderName["ACCEPT_LANGUAGE"] = 'accept-language';
|
|
278
|
+
HeaderName["ACCEPT_RANGES"] = 'accept-ranges';
|
|
279
|
+
HeaderName["ALLOW"] = 'allow';
|
|
280
|
+
HeaderName["CACHE_CONTROL"] = 'cache-control';
|
|
281
|
+
HeaderName["CONTENT_DISPOSITION"] = 'content-disposition';
|
|
282
|
+
HeaderName["CONTENT_ENCODING"] = 'content-encoding';
|
|
283
|
+
HeaderName["CONTENT_LENGTH"] = 'content-length';
|
|
284
|
+
HeaderName["CONTENT_RANGE"] = 'content-range';
|
|
285
|
+
HeaderName["CONTENT_TYPE"] = 'content-type';
|
|
286
|
+
HeaderName["COOKIE"] = 'cookie';
|
|
287
|
+
HeaderName["ETag"] = 'etag';
|
|
288
|
+
HeaderName["HOST"] = 'host';
|
|
289
|
+
HeaderName["IF_NONE_MATCH"] = 'if-none-match';
|
|
290
|
+
HeaderName["LAST_MODIFIED"] = 'last-modified';
|
|
291
|
+
HeaderName["LOCATION"] = 'location';
|
|
292
|
+
HeaderName["RANGE"] = 'range';
|
|
293
|
+
HeaderName["RATE_LIMIT_LIMIT"] = 'ratelimit-limit';
|
|
294
|
+
HeaderName["RATE_LIMIT_REMAINING"] = 'ratelimit-remaining';
|
|
295
|
+
HeaderName["RATE_LIMIT_RESET"] = 'ratelimit-reset';
|
|
296
|
+
HeaderName["RETRY_AFTER"] = 'retry-after';
|
|
297
|
+
HeaderName["SET_COOKIE"] = 'set-cookie';
|
|
298
|
+
HeaderName["TRANSFER_ENCODING"] = 'transfer-encoding';
|
|
299
|
+
HeaderName["X_FORWARDED_HOST"] = 'x-forwarded-host';
|
|
300
|
+
HeaderName["X_FORWARDED_FOR"] = 'x-forwarded-for';
|
|
301
|
+
HeaderName["X_FORWARDED_PROTO"] = 'x-forwarded-proto';
|
|
302
|
+
})(HeaderName || (HeaderName = {}));
|
|
303
|
+
|
|
304
|
+
const BodySymbol = Symbol.for('ReqBody');
|
|
305
|
+
function useRequestBody(req, key) {
|
|
306
|
+
let body;
|
|
307
|
+
/* istanbul ignore next */ if ('body' in req) {
|
|
308
|
+
body = req.body;
|
|
309
|
+
}
|
|
310
|
+
if (BodySymbol in req) {
|
|
311
|
+
if (body) {
|
|
312
|
+
body = merge({}, req[BodySymbol], body);
|
|
313
|
+
} else {
|
|
314
|
+
body = req[BodySymbol];
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (body) {
|
|
318
|
+
if (typeof key === 'string') {
|
|
319
|
+
return body[key];
|
|
320
|
+
}
|
|
321
|
+
return body;
|
|
322
|
+
}
|
|
323
|
+
return typeof key === 'string' ? undefined : {};
|
|
324
|
+
}
|
|
325
|
+
function setRequestBody(req, key, value) {
|
|
326
|
+
if (BodySymbol in req) {
|
|
327
|
+
if (typeof key === 'object') {
|
|
328
|
+
if (value) {
|
|
329
|
+
req[BodySymbol] = merge(req[BodySymbol], key);
|
|
330
|
+
} else {
|
|
331
|
+
req[BodySymbol] = key;
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
req[BodySymbol][key] = value;
|
|
335
|
+
}
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (typeof key === 'object') {
|
|
339
|
+
req[BodySymbol] = key;
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
req[BodySymbol] = {
|
|
343
|
+
[key]: value
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/*
|
|
348
|
+
* Copyright (c) 2022.
|
|
349
|
+
* Author Peter Placzek (tada5hi)
|
|
350
|
+
* For the full copyright and license information,
|
|
351
|
+
* view the LICENSE file that was distributed with this source code.
|
|
352
|
+
*/ function isRequestCacheable(req, modifiedTime) {
|
|
353
|
+
const modifiedSince = req.headers['if-modified-since'];
|
|
354
|
+
if (!modifiedSince) {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
modifiedTime = typeof modifiedTime === 'string' ? new Date(modifiedTime) : modifiedTime;
|
|
358
|
+
return new Date(modifiedSince) >= modifiedTime;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const CookieSymbol = Symbol.for('ReqCookie');
|
|
362
|
+
let requestFn$1;
|
|
363
|
+
function setRequestCookieFn(fn) {
|
|
364
|
+
requestFn$1 = fn;
|
|
365
|
+
}
|
|
366
|
+
function useRequestCookies(req) {
|
|
367
|
+
if (!(CookieSymbol in req) && typeof requestFn$1 !== 'undefined') {
|
|
368
|
+
req[CookieSymbol] = requestFn$1(req);
|
|
369
|
+
}
|
|
370
|
+
if (CookieSymbol in req) {
|
|
371
|
+
return req[CookieSymbol];
|
|
372
|
+
}
|
|
373
|
+
return {};
|
|
374
|
+
}
|
|
375
|
+
function hasRequestCookies(req) {
|
|
376
|
+
return CookieSymbol in req && isObject(req[CookieSymbol]);
|
|
377
|
+
}
|
|
378
|
+
function useRequestCookie(req, name) {
|
|
379
|
+
return useRequestCookies(req)[name];
|
|
380
|
+
}
|
|
381
|
+
function setRequestCookies(req, record, mergeIt) {
|
|
382
|
+
if (CookieSymbol in req) {
|
|
383
|
+
if (mergeIt) {
|
|
384
|
+
req[CookieSymbol] = merge(req[CookieSymbol], record);
|
|
385
|
+
}
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
req[CookieSymbol] = record;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const envSymbol = Symbol.for('ReqEnv');
|
|
392
|
+
function setRequestEnv(req, key, value) {
|
|
393
|
+
if (envSymbol in req) {
|
|
394
|
+
if (typeof key === 'object') {
|
|
395
|
+
if (value) {
|
|
396
|
+
req[envSymbol] = merge(req[envSymbol], key);
|
|
397
|
+
} else {
|
|
398
|
+
req[envSymbol] = key;
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
req[envSymbol][key] = value;
|
|
402
|
+
}
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (typeof key === 'object') {
|
|
406
|
+
req[envSymbol] = key;
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
req[envSymbol] = {
|
|
410
|
+
[key]: value
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function useRequestEnv(req, key) {
|
|
414
|
+
if (envSymbol in req) {
|
|
415
|
+
if (typeof key === 'string') {
|
|
416
|
+
return req[envSymbol][key];
|
|
417
|
+
}
|
|
418
|
+
return req[envSymbol];
|
|
419
|
+
}
|
|
420
|
+
if (typeof key === 'string') {
|
|
421
|
+
return undefined;
|
|
422
|
+
}
|
|
423
|
+
return {};
|
|
424
|
+
}
|
|
425
|
+
function unsetRequestEnv(req, key) {
|
|
426
|
+
if (envSymbol in req) {
|
|
427
|
+
if (hasOwnProperty(req[envSymbol], key)) {
|
|
428
|
+
delete req[envSymbol][key];
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/*
|
|
434
|
+
* Copyright (c) 2022.
|
|
435
|
+
* Author Peter Placzek (tada5hi)
|
|
436
|
+
* For the full copyright and license information,
|
|
437
|
+
* view the LICENSE file that was distributed with this source code.
|
|
438
|
+
*/ function getRequestHeader(req, name) {
|
|
439
|
+
return req.headers[name];
|
|
440
|
+
}
|
|
441
|
+
function setRequestHeader(req, name, value) {
|
|
442
|
+
req.headers[name] = value;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const NegotiatorSymbol = Symbol.for('ReqNegotiator');
|
|
446
|
+
function useRequestNegotiator(req) {
|
|
447
|
+
if (NegotiatorSymbol in req) {
|
|
448
|
+
return req[NegotiatorSymbol];
|
|
449
|
+
}
|
|
450
|
+
return new Negotiator(req);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function getRequestAcceptableContentTypes(req) {
|
|
454
|
+
const negotiator = useRequestNegotiator(req);
|
|
455
|
+
return negotiator.mediaTypes();
|
|
456
|
+
}
|
|
457
|
+
function getRequestAcceptableContentType(req, input) {
|
|
458
|
+
input = input || [];
|
|
459
|
+
const items = Array.isArray(input) ? input : [
|
|
460
|
+
input
|
|
461
|
+
];
|
|
462
|
+
if (items.length === 0) {
|
|
463
|
+
return getRequestAcceptableContentTypes(req).shift();
|
|
464
|
+
}
|
|
465
|
+
const header = getRequestHeader(req, HeaderName.ACCEPT);
|
|
466
|
+
if (!header) {
|
|
467
|
+
return items[0];
|
|
468
|
+
}
|
|
469
|
+
let polluted = false;
|
|
470
|
+
const mimeTypes = [];
|
|
471
|
+
for(let i = 0; i < items.length; i++){
|
|
472
|
+
const mimeType = getMimeType(items[i]);
|
|
473
|
+
if (mimeType) {
|
|
474
|
+
mimeTypes.push(mimeType);
|
|
475
|
+
} else {
|
|
476
|
+
polluted = true;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const negotiator = useRequestNegotiator(req);
|
|
480
|
+
const matches = negotiator.mediaTypes(mimeTypes);
|
|
481
|
+
if (matches.length > 0) {
|
|
482
|
+
if (polluted) {
|
|
483
|
+
return items[0];
|
|
484
|
+
}
|
|
485
|
+
return items[mimeTypes.indexOf(matches[0])];
|
|
486
|
+
}
|
|
487
|
+
return undefined;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function getRequestAcceptableCharsets(req) {
|
|
491
|
+
const negotiator = useRequestNegotiator(req);
|
|
492
|
+
return negotiator.charsets();
|
|
493
|
+
}
|
|
494
|
+
function getRequestAcceptableCharset(req, input) {
|
|
495
|
+
input = input || [];
|
|
496
|
+
const items = Array.isArray(input) ? input : [
|
|
497
|
+
input
|
|
498
|
+
];
|
|
499
|
+
if (items.length === 0) {
|
|
500
|
+
return getRequestAcceptableCharsets(req).shift();
|
|
501
|
+
}
|
|
502
|
+
const negotiator = useRequestNegotiator(req);
|
|
503
|
+
return negotiator.charsets(items).shift() || undefined;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function getRequestAcceptableEncodings(req) {
|
|
507
|
+
const negotiator = useRequestNegotiator(req);
|
|
508
|
+
return negotiator.encodings();
|
|
509
|
+
}
|
|
510
|
+
function getRequestAcceptableEncoding(req, input) {
|
|
511
|
+
input = input || [];
|
|
512
|
+
const items = Array.isArray(input) ? input : [
|
|
513
|
+
input
|
|
514
|
+
];
|
|
515
|
+
if (items.length === 0) {
|
|
516
|
+
return getRequestAcceptableEncodings(req).shift();
|
|
517
|
+
}
|
|
518
|
+
const negotiator = useRequestNegotiator(req);
|
|
519
|
+
return negotiator.encodings(items).shift() || undefined;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function getRequestAcceptableLanguages(req) {
|
|
523
|
+
const negotiator = useRequestNegotiator(req);
|
|
524
|
+
return negotiator.languages();
|
|
525
|
+
}
|
|
526
|
+
function getRequestAcceptableLanguage(req, input) {
|
|
527
|
+
input = input || [];
|
|
528
|
+
const items = Array.isArray(input) ? input : [
|
|
529
|
+
input
|
|
530
|
+
];
|
|
531
|
+
if (items.length === 0) {
|
|
532
|
+
return getRequestAcceptableLanguages(req).shift();
|
|
533
|
+
}
|
|
534
|
+
const negotiator = useRequestNegotiator(req);
|
|
535
|
+
return negotiator.languages(items).shift() || undefined;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function matchRequestContentType(req, contentType) {
|
|
539
|
+
const header = getRequestHeader(req, HeaderName.CONTENT_TYPE);
|
|
540
|
+
if (!header) {
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
/* istanbul ignore next */ if (Array.isArray(header)) {
|
|
544
|
+
if (header.length === 0) {
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
return header[0] === getMimeType(contentType);
|
|
548
|
+
}
|
|
549
|
+
return header.split('; ').shift() === getMimeType(contentType);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function getRequestHostName(req, options) {
|
|
553
|
+
options = options || {};
|
|
554
|
+
let trustProxy;
|
|
555
|
+
if (typeof options.trustProxy !== 'undefined') {
|
|
556
|
+
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
557
|
+
} else {
|
|
558
|
+
const config = useConfig();
|
|
559
|
+
trustProxy = config.get('trustProxy');
|
|
560
|
+
}
|
|
561
|
+
let hostname = req.headers[HeaderName.X_FORWARDED_HOST];
|
|
562
|
+
if (!hostname || !req.socket.remoteAddress || !trustProxy(req.socket.remoteAddress, 0)) {
|
|
563
|
+
hostname = req.headers[HeaderName.HOST];
|
|
564
|
+
} else {
|
|
565
|
+
hostname = Array.isArray(hostname) ? hostname.pop() : hostname;
|
|
566
|
+
if (hostname && hostname.indexOf(',') !== -1) {
|
|
567
|
+
hostname = hostname.substring(0, hostname.indexOf(',')).trimEnd();
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
if (!hostname) {
|
|
571
|
+
return undefined;
|
|
572
|
+
}
|
|
573
|
+
// IPv6 literal support
|
|
574
|
+
const offset = hostname[0] === '[' ? hostname.indexOf(']') + 1 : 0;
|
|
575
|
+
const index = hostname.indexOf(':', offset);
|
|
576
|
+
return index !== -1 ? hostname.substring(0, index) : hostname;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function getRequestIP(req, options) {
|
|
580
|
+
options = options || {};
|
|
581
|
+
let trustProxy;
|
|
582
|
+
if (typeof options.trustProxy !== 'undefined') {
|
|
583
|
+
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
584
|
+
} else {
|
|
585
|
+
const config = useConfig();
|
|
586
|
+
trustProxy = config.get('trustProxy');
|
|
587
|
+
}
|
|
588
|
+
return proxyAddr(req, trustProxy);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/*
|
|
592
|
+
* Copyright (c) 2022.
|
|
593
|
+
* Author Peter Placzek (tada5hi)
|
|
594
|
+
* For the full copyright and license information,
|
|
595
|
+
* view the LICENSE file that was distributed with this source code.
|
|
596
|
+
*/ const ReqMountPathSymbol = Symbol.for('ReqMountPath');
|
|
597
|
+
function useRequestMountPath(req) {
|
|
598
|
+
if (ReqMountPathSymbol in req) {
|
|
599
|
+
return req[ReqMountPathSymbol];
|
|
600
|
+
}
|
|
601
|
+
return '/';
|
|
602
|
+
}
|
|
603
|
+
function setRequestMountPath(req, basePath) {
|
|
604
|
+
req[ReqMountPathSymbol] = basePath;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/*
|
|
608
|
+
* Copyright (c) 2022.
|
|
609
|
+
* Author Peter Placzek (tada5hi)
|
|
610
|
+
* For the full copyright and license information,
|
|
611
|
+
* view the LICENSE file that was distributed with this source code.
|
|
612
|
+
*/ const ParamsSymbol = Symbol.for('ReqParams');
|
|
613
|
+
function useRequestParams(req) {
|
|
614
|
+
if ('params' in req) {
|
|
615
|
+
return req.params;
|
|
616
|
+
}
|
|
617
|
+
if (ParamsSymbol in req) {
|
|
618
|
+
return req[ParamsSymbol];
|
|
619
|
+
}
|
|
620
|
+
return {};
|
|
621
|
+
}
|
|
622
|
+
function useRequestParam(req, key) {
|
|
623
|
+
return useRequestParams(req)[key];
|
|
624
|
+
}
|
|
625
|
+
function setRequestParams(req, data) {
|
|
626
|
+
req[ParamsSymbol] = data;
|
|
627
|
+
}
|
|
628
|
+
function setRequestParam(req, key, value) {
|
|
629
|
+
const params = useRequestParams(req);
|
|
630
|
+
params[key] = value;
|
|
631
|
+
setRequestParams(req, params);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function useRequestPath(req) {
|
|
635
|
+
if ('path' in req) {
|
|
636
|
+
return req.path;
|
|
637
|
+
}
|
|
638
|
+
if (typeof req.url === 'undefined') {
|
|
639
|
+
return '/';
|
|
640
|
+
}
|
|
641
|
+
const parsed = new URL(req.url, 'http://localhost/');
|
|
642
|
+
return parsed.pathname;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function getRequestProtocol(req, options) {
|
|
646
|
+
options = options || {};
|
|
647
|
+
let trustProxy;
|
|
648
|
+
if (typeof options.trustProxy !== 'undefined') {
|
|
649
|
+
trustProxy = buildTrustProxyFn(options.trustProxy);
|
|
650
|
+
} else {
|
|
651
|
+
const config = useConfig();
|
|
652
|
+
trustProxy = config.get('trustProxy');
|
|
653
|
+
}
|
|
654
|
+
let protocol = options.default;
|
|
655
|
+
/* istanbul ignore next */ if (hasOwnProperty(req.socket, 'encrypted') && !!req.socket.encrypted) {
|
|
656
|
+
protocol = 'https';
|
|
657
|
+
} else if (!protocol) {
|
|
658
|
+
protocol = 'http';
|
|
659
|
+
}
|
|
660
|
+
if (!req.socket.remoteAddress || !trustProxy(req.socket.remoteAddress, 0)) {
|
|
661
|
+
return protocol;
|
|
662
|
+
}
|
|
663
|
+
let header = req.headers[HeaderName.X_FORWARDED_PROTO];
|
|
664
|
+
/* istanbul ignore next */ if (Array.isArray(header)) {
|
|
665
|
+
header = header.pop();
|
|
666
|
+
}
|
|
667
|
+
if (!header) {
|
|
668
|
+
return protocol;
|
|
669
|
+
}
|
|
670
|
+
const index = header.indexOf(',');
|
|
671
|
+
return index !== -1 ? header.substring(0, index).trim() : header.trim();
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
const QuerySymbol = Symbol.for('ReqQuery');
|
|
675
|
+
let requestFn;
|
|
676
|
+
function setRequestQueryFn(fn) {
|
|
677
|
+
requestFn = fn;
|
|
678
|
+
}
|
|
679
|
+
function useRequestQuery(req, key) {
|
|
680
|
+
/* istanbul ignore if */ if ('query' in req) {
|
|
681
|
+
if (typeof key === 'string') {
|
|
682
|
+
return req.query[key];
|
|
683
|
+
}
|
|
684
|
+
return req.query;
|
|
685
|
+
}
|
|
686
|
+
if (!(QuerySymbol in req) && typeof requestFn !== 'undefined') {
|
|
687
|
+
req[QuerySymbol] = requestFn(req);
|
|
688
|
+
}
|
|
689
|
+
if (QuerySymbol in req) {
|
|
690
|
+
if (typeof key === 'string') {
|
|
691
|
+
return req[QuerySymbol][key];
|
|
692
|
+
}
|
|
693
|
+
return req[QuerySymbol];
|
|
694
|
+
}
|
|
695
|
+
return {};
|
|
696
|
+
}
|
|
697
|
+
function hasRequestQuery(req) {
|
|
698
|
+
return QuerySymbol in req && isObject(req[QuerySymbol]);
|
|
699
|
+
}
|
|
700
|
+
function setRequestQuery(req, key, value) {
|
|
701
|
+
if (QuerySymbol in req) {
|
|
702
|
+
if (typeof key === 'object') {
|
|
703
|
+
if (value) {
|
|
704
|
+
req[QuerySymbol] = merge(req[QuerySymbol], key);
|
|
705
|
+
} else {
|
|
706
|
+
req[QuerySymbol] = key;
|
|
707
|
+
}
|
|
708
|
+
} else {
|
|
709
|
+
req[QuerySymbol][key] = value;
|
|
710
|
+
}
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
if (typeof key === 'object') {
|
|
714
|
+
req[QuerySymbol] = key;
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
req[QuerySymbol] = {
|
|
718
|
+
[key]: value
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/*
|
|
723
|
+
* Copyright (c) 2022.
|
|
724
|
+
* Author Peter Placzek (tada5hi)
|
|
725
|
+
* For the full copyright and license information,
|
|
726
|
+
* view the LICENSE file that was distributed with this source code.
|
|
727
|
+
*/ function setResponseCacheHeaders(res, options) {
|
|
728
|
+
options = options || {};
|
|
729
|
+
const cacheControls = [
|
|
730
|
+
'public'
|
|
731
|
+
].concat(options.cacheControls || []);
|
|
732
|
+
if (options.maxAge !== undefined) {
|
|
733
|
+
cacheControls.push(`max-age=${+options.maxAge}`, `s-maxage=${+options.maxAge}`);
|
|
734
|
+
}
|
|
735
|
+
if (options.modifiedTime) {
|
|
736
|
+
const modifiedTime = typeof options.modifiedTime === 'string' ? new Date(options.modifiedTime) : options.modifiedTime;
|
|
737
|
+
res.setHeader('last-modified', modifiedTime.toUTCString());
|
|
738
|
+
}
|
|
739
|
+
res.setHeader('cache-control', cacheControls.join(', '));
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/*
|
|
743
|
+
* Copyright (c) 2022.
|
|
744
|
+
* Author Peter Placzek (tada5hi)
|
|
745
|
+
* For the full copyright and license information,
|
|
746
|
+
* view the LICENSE file that was distributed with this source code.
|
|
747
|
+
*/ function appendResponseHeader(res, name, value) {
|
|
748
|
+
let header = res.getHeader(name);
|
|
749
|
+
if (!header) {
|
|
750
|
+
res.setHeader(name, value);
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
if (!Array.isArray(header)) {
|
|
754
|
+
header = [
|
|
755
|
+
header.toString()
|
|
756
|
+
];
|
|
757
|
+
}
|
|
758
|
+
res.setHeader(name, [
|
|
759
|
+
...header,
|
|
760
|
+
value
|
|
761
|
+
]);
|
|
762
|
+
}
|
|
763
|
+
function appendResponseHeaderDirective(res, name, value) {
|
|
764
|
+
let header = res.getHeader(name);
|
|
765
|
+
if (!header) {
|
|
766
|
+
if (Array.isArray(value)) {
|
|
767
|
+
res.setHeader(name, value.join('; '));
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
res.setHeader(name, value);
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
if (!Array.isArray(header)) {
|
|
774
|
+
if (typeof header === 'string') {
|
|
775
|
+
// split header by directive(s)
|
|
776
|
+
header = header.split('; ');
|
|
777
|
+
}
|
|
778
|
+
if (typeof header === 'number') {
|
|
779
|
+
header = [
|
|
780
|
+
header.toString()
|
|
781
|
+
];
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (Array.isArray(value)) {
|
|
785
|
+
header.push(...value);
|
|
786
|
+
} else {
|
|
787
|
+
header.push(`${value}`);
|
|
788
|
+
}
|
|
789
|
+
header = [
|
|
790
|
+
...new Set(header)
|
|
791
|
+
];
|
|
792
|
+
res.setHeader(name, header.join('; '));
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
function setResponseContentTypeByFileName(res, fileName) {
|
|
796
|
+
const ext = path.extname(fileName);
|
|
797
|
+
if (ext) {
|
|
798
|
+
let type = getMimeType(ext.substring(1));
|
|
799
|
+
if (type) {
|
|
800
|
+
const charset = getCharsetForMimeType(type);
|
|
801
|
+
if (charset) {
|
|
802
|
+
type += `; charset=${charset}`;
|
|
803
|
+
}
|
|
804
|
+
res.setHeader(HeaderName.CONTENT_TYPE, type);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
function onResponseFinished(res, cb) {
|
|
809
|
+
let called;
|
|
810
|
+
const callCallback = (err)=>{
|
|
811
|
+
if (called) return;
|
|
812
|
+
called = true;
|
|
813
|
+
cb(err);
|
|
814
|
+
};
|
|
815
|
+
res.on('finish', async ()=>{
|
|
816
|
+
callCallback();
|
|
817
|
+
});
|
|
818
|
+
res.on('close', async ()=>{
|
|
819
|
+
callCallback();
|
|
820
|
+
});
|
|
821
|
+
res.on('error', async (err)=>{
|
|
822
|
+
callCallback(err);
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
function setResponseHeaderAttachment(res, filename) {
|
|
827
|
+
if (typeof filename === 'string') {
|
|
828
|
+
setResponseContentTypeByFileName(res, filename);
|
|
829
|
+
}
|
|
830
|
+
res.setHeader(HeaderName.CONTENT_DISPOSITION, `attachment${filename ? `; filename="${filename}"` : ''}`);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function setResponseHeaderContentType(res, input, ifNotExists) {
|
|
834
|
+
if (ifNotExists) {
|
|
835
|
+
const header = res.getHeader(HeaderName.CONTENT_TYPE);
|
|
836
|
+
if (header) {
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
const contentType = getMimeType(input);
|
|
841
|
+
if (contentType) {
|
|
842
|
+
res.setHeader(HeaderName.CONTENT_TYPE, contentType);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function send(res, chunk) {
|
|
847
|
+
switch(typeof chunk){
|
|
848
|
+
case 'string':
|
|
849
|
+
{
|
|
850
|
+
setResponseHeaderContentType(res, 'html', true);
|
|
851
|
+
break;
|
|
852
|
+
}
|
|
853
|
+
case 'boolean':
|
|
854
|
+
case 'number':
|
|
855
|
+
case 'object':
|
|
856
|
+
{
|
|
857
|
+
if (chunk === null) {
|
|
858
|
+
chunk = '';
|
|
859
|
+
} else if (Buffer.isBuffer(chunk)) {
|
|
860
|
+
setResponseHeaderContentType(res, 'bin', true);
|
|
861
|
+
} else {
|
|
862
|
+
chunk = JSON.stringify(chunk);
|
|
863
|
+
setResponseHeaderContentType(res, 'application/json', true);
|
|
864
|
+
}
|
|
865
|
+
break;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
let encoding;
|
|
869
|
+
if (typeof chunk === 'string') {
|
|
870
|
+
res.setHeader(HeaderName.CONTENT_ENCODING, 'utf-8');
|
|
871
|
+
appendResponseHeaderDirective(res, HeaderName.CONTENT_TYPE, 'charset=utf-8');
|
|
872
|
+
encoding = 'utf-8';
|
|
873
|
+
}
|
|
874
|
+
// populate Content-Length
|
|
875
|
+
let len;
|
|
876
|
+
if (chunk !== undefined) {
|
|
877
|
+
if (Buffer.isBuffer(chunk)) {
|
|
878
|
+
// get length of Buffer
|
|
879
|
+
len = chunk.length;
|
|
880
|
+
} else if (chunk.length < 1000) {
|
|
881
|
+
// just calculate length when no ETag + small chunk
|
|
882
|
+
len = Buffer.byteLength(chunk, encoding);
|
|
883
|
+
} else {
|
|
884
|
+
// convert chunk to Buffer and calculate
|
|
885
|
+
chunk = Buffer.from(chunk, encoding);
|
|
886
|
+
encoding = undefined;
|
|
887
|
+
len = chunk.length;
|
|
888
|
+
}
|
|
889
|
+
res.setHeader(HeaderName.CONTENT_LENGTH, `${len}`);
|
|
890
|
+
}
|
|
891
|
+
const config = useConfig();
|
|
892
|
+
const etagFn = config.get('etag');
|
|
893
|
+
if (typeof len !== 'undefined') {
|
|
894
|
+
const chunkHash = etagFn(chunk, encoding, len);
|
|
895
|
+
if (typeof chunkHash === 'string') {
|
|
896
|
+
res.setHeader(HeaderName.ETag, chunkHash);
|
|
897
|
+
if (res.req.headers[HeaderName.IF_NONE_MATCH] === chunkHash) {
|
|
898
|
+
res.statusCode = 304;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
// strip irrelevant headers
|
|
903
|
+
if (res.statusCode === 204 || res.statusCode === 304) {
|
|
904
|
+
res.removeHeader(HeaderName.CONTENT_TYPE);
|
|
905
|
+
res.removeHeader(HeaderName.CONTENT_LENGTH);
|
|
906
|
+
res.removeHeader(HeaderName.TRANSFER_ENCODING);
|
|
907
|
+
chunk = '';
|
|
908
|
+
}
|
|
909
|
+
// alter headers for 205
|
|
910
|
+
if (res.statusCode === 205) {
|
|
911
|
+
res.setHeader(HeaderName.CONTENT_LENGTH, 0);
|
|
912
|
+
res.removeHeader(HeaderName.TRANSFER_ENCODING);
|
|
913
|
+
chunk = '';
|
|
914
|
+
}
|
|
915
|
+
if (res.req.method === 'HEAD') {
|
|
916
|
+
// skip body for HEAD
|
|
917
|
+
res.end();
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
if (typeof encoding !== 'undefined') {
|
|
921
|
+
res.end(chunk, encoding);
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
res.end(chunk);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
function sendAccepted(res, chunk) {
|
|
928
|
+
res.statusCode = 202;
|
|
929
|
+
res.statusMessage = 'Accepted';
|
|
930
|
+
return send(res, chunk);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
function sendCreated(res, chunk) {
|
|
934
|
+
res.statusCode = 201;
|
|
935
|
+
res.statusMessage = 'Created';
|
|
936
|
+
return send(res, chunk);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/*
|
|
940
|
+
* Copyright (c) 2022.
|
|
941
|
+
* Author Peter Placzek (tada5hi)
|
|
942
|
+
* For the full copyright and license information,
|
|
943
|
+
* view the LICENSE file that was distributed with this source code.
|
|
944
|
+
*/ function sendStream(res, stream, fn) {
|
|
945
|
+
stream.on('open', ()=>{
|
|
946
|
+
stream.pipe(res);
|
|
947
|
+
});
|
|
948
|
+
stream.on('error', (err)=>{
|
|
949
|
+
if (typeof fn === 'function') {
|
|
950
|
+
fn(err);
|
|
951
|
+
} else {
|
|
952
|
+
res.statusCode = 400;
|
|
953
|
+
res.end();
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
stream.on('close', ()=>{
|
|
957
|
+
if (typeof fn === 'function') {
|
|
958
|
+
fn();
|
|
959
|
+
} else {
|
|
960
|
+
res.end();
|
|
961
|
+
}
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function resolveStats(options, cb) {
|
|
966
|
+
if (options.stats) {
|
|
967
|
+
cb(null, options.stats);
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
stat(options.filePath, (err, stats)=>cb(err, stats));
|
|
971
|
+
}
|
|
972
|
+
function sendFile(res, filePath, fn) {
|
|
973
|
+
let options;
|
|
974
|
+
if (typeof filePath === 'string') {
|
|
975
|
+
options = {
|
|
976
|
+
filePath
|
|
977
|
+
};
|
|
978
|
+
} else {
|
|
979
|
+
options = filePath;
|
|
980
|
+
}
|
|
981
|
+
const fileName = path.basename(options.filePath);
|
|
982
|
+
if (options.attachment) {
|
|
983
|
+
const dispositionHeader = res.getHeader(HeaderName.CONTENT_DISPOSITION);
|
|
984
|
+
if (!dispositionHeader) {
|
|
985
|
+
setResponseHeaderAttachment(res, fileName);
|
|
986
|
+
}
|
|
987
|
+
} else {
|
|
988
|
+
setResponseContentTypeByFileName(res, fileName);
|
|
989
|
+
}
|
|
990
|
+
resolveStats(options, (err, stats)=>{
|
|
991
|
+
if (err) {
|
|
992
|
+
if (typeof fn === 'function') {
|
|
993
|
+
fn(err);
|
|
994
|
+
} else {
|
|
995
|
+
res.statusCode = 404;
|
|
996
|
+
res.end();
|
|
997
|
+
}
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
const streamOptions = {};
|
|
1001
|
+
const rangeHeader = res.req.headers[HeaderName.RANGE];
|
|
1002
|
+
if (rangeHeader) {
|
|
1003
|
+
const [x, y] = rangeHeader.replace('bytes=', '').split('-');
|
|
1004
|
+
streamOptions.end = Math.min(parseInt(y, 10) || stats.size - 1, stats.size - 1);
|
|
1005
|
+
streamOptions.start = parseInt(x, 10) || 0;
|
|
1006
|
+
if (streamOptions.start >= stats.size || streamOptions.end >= stats.size) {
|
|
1007
|
+
res.setHeader(HeaderName.CONTENT_RANGE, `bytes */${stats.size}`);
|
|
1008
|
+
res.statusCode = 416;
|
|
1009
|
+
res.end();
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
res.setHeader(HeaderName.CONTENT_RANGE, `bytes ${streamOptions.start}-${streamOptions.end}/${stats.size}`);
|
|
1013
|
+
res.setHeader(HeaderName.CONTENT_LENGTH, streamOptions.end - streamOptions.start + 1);
|
|
1014
|
+
} else {
|
|
1015
|
+
res.setHeader(HeaderName.CONTENT_LENGTH, stats.size);
|
|
1016
|
+
}
|
|
1017
|
+
res.setHeader(HeaderName.ACCEPT_RANGES, 'bytes');
|
|
1018
|
+
res.setHeader(HeaderName.LAST_MODIFIED, stats.mtime.toUTCString());
|
|
1019
|
+
res.setHeader(HeaderName.ETag, `W/"${stats.size}-${stats.mtime.getTime()}"`);
|
|
1020
|
+
sendStream(res, createReadStream(options?.filePath, streamOptions), fn);
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/*
|
|
1025
|
+
* Copyright (c) 2022.
|
|
1026
|
+
* Author Peter Placzek (tada5hi)
|
|
1027
|
+
* For the full copyright and license information,
|
|
1028
|
+
* view the LICENSE file that was distributed with this source code.
|
|
1029
|
+
*/ function sendFormat(_res, _format) {}
|
|
1030
|
+
|
|
1031
|
+
function sendRedirect(res, location, statusCode = 302) {
|
|
1032
|
+
res.statusCode = statusCode;
|
|
1033
|
+
res.setHeader('location', location);
|
|
1034
|
+
const encodedLoc = location.replace(/"/g, '%22');
|
|
1035
|
+
const html = `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`;
|
|
1036
|
+
return send(res, html);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
52
1039
|
function processHandlerExecutionOutput(res, next, output) {
|
|
53
1040
|
if (isPromise(output)) {
|
|
54
1041
|
output.then((r)=>{
|
|
@@ -557,5 +1544,5 @@ class Router {
|
|
|
557
1544
|
}
|
|
558
1545
|
}
|
|
559
1546
|
|
|
560
|
-
export { Layer, PathMatcher, Route, Router, createRequestTimeout, isInstance, isLayerInstance, isPath, isPromise, isRouteInstance, isRouterInstance, processHandlerExecutionOutput };
|
|
1547
|
+
export { HeaderName, Layer, Method, PathMatcher, Route, Router, appendResponseHeader, appendResponseHeaderDirective, buildConfig, buildEtagFn, buildTrustProxyFn, cleanDoubleSlashes, createRequestTimeout, getCharsetForMimeType, getConfigOption, getMimeType, getRequestAcceptableCharset, getRequestAcceptableCharsets, getRequestAcceptableContentType, getRequestAcceptableContentTypes, getRequestAcceptableEncoding, getRequestAcceptableEncodings, getRequestAcceptableLanguage, getRequestAcceptableLanguages, getRequestHeader, getRequestHostName, getRequestIP, getRequestProtocol, hasLeadingSlash, hasRequestCookies, hasRequestQuery, hasTrailingSlash, isInstance, isLayerInstance, isObject, isPath, isPromise, isRequestCacheable, isRouteInstance, isRouterInstance, matchRequestContentType, onResponseFinished, processHandlerExecutionOutput, send, sendAccepted, sendCreated, sendFile, sendFormat, sendRedirect, sendStream, setConfig, setConfigOption, setRequestBody, setRequestCookieFn, setRequestCookies, setRequestEnv, setRequestHeader, setRequestMountPath, setRequestParam, setRequestParams, setRequestQuery, setRequestQueryFn, setResponseCacheHeaders, setResponseContentTypeByFileName, setResponseHeaderAttachment, setResponseHeaderContentType, unsetRequestEnv, useConfig, useRequestBody, useRequestCookie, useRequestCookies, useRequestEnv, useRequestMountPath, useRequestNegotiator, useRequestParam, useRequestParams, useRequestPath, useRequestQuery, withLeadingSlash, withTrailingSlash, withoutLeadingSlash, withoutTrailingSlash };
|
|
561
1548
|
//# sourceMappingURL=index.mjs.map
|