@eggjs/koa 2.14.2 → 2.15.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/lib/request.js CHANGED
@@ -1,726 +1,527 @@
1
-
2
- 'use strict';
3
-
4
- /**
5
- * Module dependencies.
6
- */
7
-
8
- const URL = require('url').URL;
9
- const net = require('net');
10
- const accepts = require('accepts');
11
- const contentType = require('content-type');
12
- const stringify = require('url').format;
13
- const parse = require('parseurl');
14
- const qs = require('querystring');
15
- const typeis = require('type-is');
16
- const fresh = require('fresh');
17
- const only = require('only');
18
- const util = require('util');
19
-
20
- const IP = Symbol('context#ip');
21
-
22
- /**
23
- * Prototype.
24
- */
25
-
26
- module.exports = {
27
-
28
- /**
29
- * Return request header.
30
- *
31
- * @return {Object}
32
- * @api public
33
- */
34
-
35
- get header() {
36
- return this.req.headers;
37
- },
38
-
39
- /**
40
- * Set request header.
41
- *
42
- * @api public
43
- */
44
-
45
- set header(val) {
46
- this.req.headers = val;
47
- },
48
-
49
- /**
50
- * Return request header, alias as request.header
51
- *
52
- * @return {Object}
53
- * @api public
54
- */
55
-
56
- get headers() {
57
- return this.req.headers;
58
- },
59
-
60
- /**
61
- * Set request header, alias as request.header
62
- *
63
- * @api public
64
- */
65
-
66
- set headers(val) {
67
- this.req.headers = val;
68
- },
69
-
70
- /**
71
- * Get request URL.
72
- *
73
- * @return {String}
74
- * @api public
75
- */
76
-
77
- get url() {
78
- return this.req.url;
79
- },
80
-
81
- /**
82
- * Set request URL.
83
- *
84
- * @api public
85
- */
86
-
87
- set url(val) {
88
- this.req.url = val;
89
- },
90
-
91
- /**
92
- * Get origin of URL.
93
- *
94
- * @return {String}
95
- * @api public
96
- */
97
-
98
- get origin() {
99
- return `${this.protocol}://${this.host}`;
100
- },
101
-
102
- /**
103
- * Get full request URL.
104
- *
105
- * @return {String}
106
- * @api public
107
- */
108
-
109
- get href() {
110
- // support: `GET http://example.com/foo`
111
- if (/^https?:\/\//i.test(this.originalUrl)) return this.originalUrl;
112
- return this.origin + this.originalUrl;
113
- },
114
-
115
- /**
116
- * Get request method.
117
- *
118
- * @return {String}
119
- * @api public
120
- */
121
-
122
- get method() {
123
- return this.req.method;
124
- },
125
-
126
- /**
127
- * Set request method.
128
- *
129
- * @param {String} val
130
- * @api public
131
- */
132
-
133
- set method(val) {
134
- this.req.method = val;
135
- },
136
-
137
- /**
138
- * Get request pathname.
139
- *
140
- * @return {String}
141
- * @api public
142
- */
143
-
144
- get path() {
145
- return parse(this.req).pathname;
146
- },
147
-
148
- /**
149
- * Set pathname, retaining the query string when present.
150
- *
151
- * @param {String} path
152
- * @api public
153
- */
154
-
155
- set path(path) {
156
- const url = parse(this.req);
157
- if (url.pathname === path) return;
158
-
159
- url.pathname = path;
160
- url.path = null;
161
-
162
- this.url = stringify(url);
163
- },
164
-
165
- /**
166
- * Get parsed query string.
167
- *
168
- * @return {Object}
169
- * @api public
170
- */
171
-
172
- get query() {
173
- const str = this.querystring;
174
- const c = this._querycache = this._querycache || {};
175
- return c[str] || (c[str] = qs.parse(str));
176
- },
177
-
178
- /**
179
- * Set query string as an object.
180
- *
181
- * @param {Object} obj
182
- * @api public
183
- */
184
-
185
- set query(obj) {
186
- this.querystring = qs.stringify(obj);
187
- },
188
-
189
- /**
190
- * Get query string.
191
- *
192
- * @return {String}
193
- * @api public
194
- */
195
-
196
- get querystring() {
197
- if (!this.req) return '';
198
- return parse(this.req).query || '';
199
- },
200
-
201
- /**
202
- * Set query string.
203
- *
204
- * @param {String} str
205
- * @api public
206
- */
207
-
208
- set querystring(str) {
209
- const url = parse(this.req);
210
- if (url.search === `?${str}`) return;
211
-
212
- url.search = str;
213
- url.path = null;
214
-
215
- this.url = stringify(url);
216
- },
217
-
218
- /**
219
- * Get the search string. Same as the query string
220
- * except it includes the leading ?.
221
- *
222
- * @return {String}
223
- * @api public
224
- */
225
-
226
- get search() {
227
- if (!this.querystring) return '';
228
- return `?${this.querystring}`;
229
- },
230
-
231
- /**
232
- * Set the search string. Same as
233
- * request.querystring= but included for ubiquity.
234
- *
235
- * @param {String} str
236
- * @api public
237
- */
238
-
239
- set search(str) {
240
- this.querystring = str;
241
- },
242
-
243
- /**
244
- * Parse the "Host" header field host
245
- * and support X-Forwarded-Host when a
246
- * proxy is enabled.
247
- *
248
- * @return {String} hostname:port
249
- * @api public
250
- */
251
-
252
- get host() {
253
- const proxy = this.app.proxy;
254
- let host = proxy && this.get('X-Forwarded-Host');
255
- if (!host) {
256
- if (this.req.httpVersionMajor >= 2) host = this.get(':authority');
257
- if (!host) host = this.get('Host');
258
- }
259
- if (!host) return '';
260
- return host.split(/\s*,\s*/, 1)[0];
261
- },
262
-
263
- /**
264
- * Parse the "Host" header field hostname
265
- * and support X-Forwarded-Host when a
266
- * proxy is enabled.
267
- *
268
- * @return {String} hostname
269
- * @api public
270
- */
271
-
272
- get hostname() {
273
- const host = this.host;
274
- if (!host) return '';
275
- if ('[' === host[0]) return this.URL.hostname || ''; // IPv6
276
- return host.split(':', 1)[0];
277
- },
278
-
279
- /**
280
- * Get WHATWG parsed URL.
281
- * Lazily memoized.
282
- *
283
- * @return {URL|Object}
284
- * @api public
285
- */
286
-
287
- get URL() {
288
- /* istanbul ignore else */
289
- if (!this.memoizedURL) {
290
- const originalUrl = this.originalUrl || ''; // avoid undefined in template string
291
- try {
292
- this.memoizedURL = new URL(`${this.origin}${originalUrl}`);
293
- } catch (err) {
294
- this.memoizedURL = Object.create(null);
295
- }
296
- }
297
- return this.memoizedURL;
298
- },
299
-
300
- /**
301
- * Check if the request is fresh, aka
302
- * Last-Modified and/or the ETag
303
- * still match.
304
- *
305
- * @return {Boolean}
306
- * @api public
307
- */
308
-
309
- get fresh() {
310
- const method = this.method;
311
- const s = this.ctx.status;
312
-
313
- // GET or HEAD for weak freshness validation only
314
- if ('GET' !== method && 'HEAD' !== method) return false;
315
-
316
- // 2xx or 304 as per rfc2616 14.26
317
- if ((s >= 200 && s < 300) || 304 === s) {
318
- return fresh(this.header, this.response.header);
319
- }
320
-
321
- return false;
322
- },
323
-
324
- /**
325
- * Check if the request is stale, aka
326
- * "Last-Modified" and / or the "ETag" for the
327
- * resource has changed.
328
- *
329
- * @return {Boolean}
330
- * @api public
331
- */
332
-
333
- get stale() {
334
- return !this.fresh;
335
- },
336
-
337
- /**
338
- * Check if the request is idempotent.
339
- *
340
- * @return {Boolean}
341
- * @api public
342
- */
343
-
344
- get idempotent() {
345
- const methods = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'];
346
- return !!~methods.indexOf(this.method);
347
- },
348
-
349
- /**
350
- * Return the request socket.
351
- *
352
- * @return {Connection}
353
- * @api public
354
- */
355
-
356
- get socket() {
357
- return this.req.socket;
358
- },
359
-
360
- /**
361
- * Get the charset when present or undefined.
362
- *
363
- * @return {String}
364
- * @api public
365
- */
366
-
367
- get charset() {
368
- try {
369
- const { parameters } = contentType.parse(this.req);
370
- return parameters.charset || '';
371
- } catch (e) {
372
- return '';
373
- }
374
- },
375
-
376
- /**
377
- * Return parsed Content-Length when present.
378
- *
379
- * @return {Number}
380
- * @api public
381
- */
382
-
383
- get length() {
384
- const len = this.get('Content-Length');
385
- if (len === '') return;
386
- return ~~len;
387
- },
388
-
389
- /**
390
- * Return the protocol string "http" or "https"
391
- * when requested with TLS. When the proxy setting
392
- * is enabled the "X-Forwarded-Proto" header
393
- * field will be trusted. If you're running behind
394
- * a reverse proxy that supplies https for you this
395
- * may be enabled.
396
- *
397
- * @return {String}
398
- * @api public
399
- */
400
-
401
- get protocol() {
402
- if (this.socket.encrypted) return 'https';
403
- if (!this.app.proxy) return 'http';
404
- const proto = this.get('X-Forwarded-Proto');
405
- return proto ? proto.split(/\s*,\s*/, 1)[0] : 'http';
406
- },
407
-
408
- /**
409
- * Shorthand for:
410
- *
411
- * this.protocol == 'https'
412
- *
413
- * @return {Boolean}
414
- * @api public
415
- */
416
-
417
- get secure() {
418
- return 'https' === this.protocol;
419
- },
420
-
421
- /**
422
- * When `app.proxy` is `true`, parse
423
- * the "X-Forwarded-For" ip address list.
424
- *
425
- * For example if the value was "client, proxy1, proxy2"
426
- * you would receive the array `["client", "proxy1", "proxy2"]`
427
- * where "proxy2" is the furthest down-stream.
428
- *
429
- * @return {Array}
430
- * @api public
431
- */
432
-
433
- get ips() {
434
- const proxy = this.app.proxy;
435
- const val = this.get(this.app.proxyIpHeader);
436
- let ips = proxy && val
437
- ? val.split(/\s*,\s*/)
438
- : [];
439
- if (this.app.maxIpsCount > 0) {
440
- ips = ips.slice(-this.app.maxIpsCount);
441
- }
442
- return ips;
443
- },
444
-
445
- /**
446
- * Return request's remote address
447
- * When `app.proxy` is `true`, parse
448
- * the "X-Forwarded-For" ip address list and return the first one
449
- *
450
- * @return {String}
451
- * @api public
452
- */
453
-
454
- get ip() {
455
- if (!this[IP]) {
456
- this[IP] = this.ips[0] || this.socket.remoteAddress || '';
457
- }
458
- return this[IP];
459
- },
460
-
461
- set ip(_ip) {
462
- this[IP] = _ip;
463
- },
464
-
465
- /**
466
- * Return subdomains as an array.
467
- *
468
- * Subdomains are the dot-separated parts of the host before the main domain
469
- * of the app. By default, the domain of the app is assumed to be the last two
470
- * parts of the host. This can be changed by setting `app.subdomainOffset`.
471
- *
472
- * For example, if the domain is "tobi.ferrets.example.com":
473
- * If `app.subdomainOffset` is not set, this.subdomains is
474
- * `["ferrets", "tobi"]`.
475
- * If `app.subdomainOffset` is 3, this.subdomains is `["tobi"]`.
476
- *
477
- * @return {Array}
478
- * @api public
479
- */
480
-
481
- get subdomains() {
482
- const offset = this.app.subdomainOffset;
483
- const hostname = this.hostname;
484
- if (net.isIP(hostname)) return [];
485
- return hostname
486
- .split('.')
487
- .reverse()
488
- .slice(offset);
489
- },
490
-
491
- /**
492
- * Get accept object.
493
- * Lazily memoized.
494
- *
495
- * @return {Object}
496
- * @api private
497
- */
498
-
499
- get accept() {
500
- return this._accept || (this._accept = accepts(this.req));
501
- },
502
-
503
- /**
504
- * Set accept object.
505
- *
506
- * @param {Object}
507
- * @api private
508
- */
509
-
510
- set accept(obj) {
511
- this._accept = obj;
512
- },
513
-
514
- /**
515
- * Check if the given `type(s)` is acceptable, returning
516
- * the best match when true, otherwise `false`, in which
517
- * case you should respond with 406 "Not Acceptable".
518
- *
519
- * The `type` value may be a single mime type string
520
- * such as "application/json", the extension name
521
- * such as "json" or an array `["json", "html", "text/plain"]`. When a list
522
- * or array is given the _best_ match, if any is returned.
523
- *
524
- * Examples:
525
- *
526
- * // Accept: text/html
527
- * this.accepts('html');
528
- * // => "html"
529
- *
530
- * // Accept: text/*, application/json
531
- * this.accepts('html');
532
- * // => "html"
533
- * this.accepts('text/html');
534
- * // => "text/html"
535
- * this.accepts('json', 'text');
536
- * // => "json"
537
- * this.accepts('application/json');
538
- * // => "application/json"
539
- *
540
- * // Accept: text/*, application/json
541
- * this.accepts('image/png');
542
- * this.accepts('png');
543
- * // => false
544
- *
545
- * // Accept: text/*;q=.5, application/json
546
- * this.accepts(['html', 'json']);
547
- * this.accepts('html', 'json');
548
- * // => "json"
549
- *
550
- * @param {String|Array} type(s)...
551
- * @return {String|Array|false}
552
- * @api public
553
- */
554
-
555
- accepts(...args) {
556
- return this.accept.types(...args);
557
- },
558
-
559
- /**
560
- * Return accepted encodings or best fit based on `encodings`.
561
- *
562
- * Given `Accept-Encoding: gzip, deflate`
563
- * an array sorted by quality is returned:
564
- *
565
- * ['gzip', 'deflate']
566
- *
567
- * @param {String|Array} encoding(s)...
568
- * @return {String|Array}
569
- * @api public
570
- */
571
-
572
- acceptsEncodings(...args) {
573
- return this.accept.encodings(...args);
574
- },
575
-
576
- /**
577
- * Return accepted charsets or best fit based on `charsets`.
578
- *
579
- * Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
580
- * an array sorted by quality is returned:
581
- *
582
- * ['utf-8', 'utf-7', 'iso-8859-1']
583
- *
584
- * @param {String|Array} charset(s)...
585
- * @return {String|Array}
586
- * @api public
587
- */
588
-
589
- acceptsCharsets(...args) {
590
- return this.accept.charsets(...args);
591
- },
592
-
593
- /**
594
- * Return accepted languages or best fit based on `langs`.
595
- *
596
- * Given `Accept-Language: en;q=0.8, es, pt`
597
- * an array sorted by quality is returned:
598
- *
599
- * ['es', 'pt', 'en']
600
- *
601
- * @param {String|Array} lang(s)...
602
- * @return {Array|String}
603
- * @api public
604
- */
605
-
606
- acceptsLanguages(...args) {
607
- return this.accept.languages(...args);
608
- },
609
-
610
- /**
611
- * Check if the incoming request contains the "Content-Type"
612
- * header field and if it contains any of the given mime `type`s.
613
- * If there is no request body, `null` is returned.
614
- * If there is no content type, `false` is returned.
615
- * Otherwise, it returns the first `type` that matches.
616
- *
617
- * Examples:
618
- *
619
- * // With Content-Type: text/html; charset=utf-8
620
- * this.is('html'); // => 'html'
621
- * this.is('text/html'); // => 'text/html'
622
- * this.is('text/*', 'application/json'); // => 'text/html'
623
- *
624
- * // When Content-Type is application/json
625
- * this.is('json', 'urlencoded'); // => 'json'
626
- * this.is('application/json'); // => 'application/json'
627
- * this.is('html', 'application/*'); // => 'application/json'
628
- *
629
- * this.is('html'); // => false
630
- *
631
- * @param {String|String[]} [type]
632
- * @param {String[]} [types]
633
- * @return {String|false|null}
634
- * @api public
635
- */
636
-
637
- is(type, ...types) {
638
- return typeis(this.req, type, ...types);
639
- },
640
-
641
- /**
642
- * Return the request mime type void of
643
- * parameters such as "charset".
644
- *
645
- * @return {String}
646
- * @api public
647
- */
648
-
649
- get type() {
650
- const type = this.get('Content-Type');
651
- if (!type) return '';
652
- return type.split(';')[0];
653
- },
654
-
655
- /**
656
- * Return request header.
657
- *
658
- * The `Referrer` header field is special-cased,
659
- * both `Referrer` and `Referer` are interchangeable.
660
- *
661
- * Examples:
662
- *
663
- * this.get('Content-Type');
664
- * // => "text/plain"
665
- *
666
- * this.get('content-type');
667
- * // => "text/plain"
668
- *
669
- * this.get('Something');
670
- * // => ''
671
- *
672
- * @param {String} field
673
- * @return {String}
674
- * @api public
675
- */
676
-
677
- get(field) {
678
- const req = this.req;
679
- switch (field = field.toLowerCase()) {
680
- case 'referer':
681
- case 'referrer':
682
- return req.headers.referrer || req.headers.referer || '';
683
- default:
684
- return req.headers[field] || '';
685
- }
686
- },
687
-
688
- /**
689
- * Inspect implementation.
690
- *
691
- * @return {Object}
692
- * @api public
693
- */
694
-
695
- inspect() {
696
- if (!this.req) return;
697
- return this.toJSON();
698
- },
699
-
700
- /**
701
- * Return JSON representation.
702
- *
703
- * @return {Object}
704
- * @api public
705
- */
706
-
707
- toJSON() {
708
- return only(this, [
709
- 'method',
710
- 'url',
711
- 'header'
712
- ]);
713
- }
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
714
4
  };
715
-
716
- /**
717
- * Custom inspection implementation for newer Node.js versions.
718
- *
719
- * @return {Object}
720
- * @api public
721
- */
722
-
723
- /* istanbul ignore else */
724
- if (util.inspect.custom) {
725
- module.exports[util.inspect.custom] = module.exports.inspect;
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const node_net_1 = __importDefault(require("node:net"));
7
+ const node_url_1 = require("node:url");
8
+ const node_querystring_1 = __importDefault(require("node:querystring"));
9
+ const node_util_1 = __importDefault(require("node:util"));
10
+ const accepts_1 = __importDefault(require("accepts"));
11
+ const content_type_1 = __importDefault(require("content-type"));
12
+ const parseurl_1 = __importDefault(require("parseurl"));
13
+ const type_is_1 = __importDefault(require("type-is"));
14
+ const fresh_1 = __importDefault(require("fresh"));
15
+ const only_1 = __importDefault(require("only"));
16
+ class Request {
17
+ app;
18
+ req;
19
+ res;
20
+ ctx;
21
+ response;
22
+ originalUrl;
23
+ constructor(app, ctx, req, res) {
24
+ this.app = app;
25
+ this.req = req;
26
+ this.res = res;
27
+ this.ctx = ctx;
28
+ this.originalUrl = req.url;
29
+ }
30
+ /**
31
+ * Return request header.
32
+ */
33
+ get header() {
34
+ return this.req.headers;
35
+ }
36
+ /**
37
+ * Set request header.
38
+ */
39
+ set header(val) {
40
+ this.req.headers = val;
41
+ }
42
+ /**
43
+ * Return request header, alias as request.header
44
+ */
45
+ get headers() {
46
+ return this.req.headers;
47
+ }
48
+ /**
49
+ * Set request header, alias as request.header
50
+ */
51
+ set headers(val) {
52
+ this.req.headers = val;
53
+ }
54
+ /**
55
+ * Get request URL.
56
+ */
57
+ get url() {
58
+ return this.req.url;
59
+ }
60
+ /**
61
+ * Set request URL.
62
+ */
63
+ set url(val) {
64
+ this.req.url = val;
65
+ }
66
+ /**
67
+ * Get origin of URL.
68
+ */
69
+ get origin() {
70
+ return `${this.protocol}://${this.host}`;
71
+ }
72
+ /**
73
+ * Get full request URL.
74
+ */
75
+ get href() {
76
+ // support: `GET http://example.com/foo`
77
+ if (/^https?:\/\//i.test(this.originalUrl))
78
+ return this.originalUrl;
79
+ return this.origin + this.originalUrl;
80
+ }
81
+ /**
82
+ * Get request method.
83
+ */
84
+ get method() {
85
+ return this.req.method;
86
+ }
87
+ /**
88
+ * Set request method.
89
+ */
90
+ set method(val) {
91
+ this.req.method = val;
92
+ }
93
+ /**
94
+ * Get request pathname.
95
+ */
96
+ get path() {
97
+ return (0, parseurl_1.default)(this.req).pathname;
98
+ }
99
+ /**
100
+ * Set pathname, retaining the query string when present.
101
+ */
102
+ set path(path) {
103
+ const url = (0, parseurl_1.default)(this.req);
104
+ if (url.pathname === path)
105
+ return;
106
+ url.pathname = path;
107
+ url.path = null;
108
+ this.url = (0, node_url_1.format)(url);
109
+ }
110
+ #parsedUrlQueryCache;
111
+ /**
112
+ * Get parsed query string.
113
+ */
114
+ get query() {
115
+ const str = this.querystring;
116
+ if (!this.#parsedUrlQueryCache) {
117
+ this.#parsedUrlQueryCache = {};
118
+ }
119
+ let parsedUrlQuery = this.#parsedUrlQueryCache[str];
120
+ if (!parsedUrlQuery) {
121
+ parsedUrlQuery = this.#parsedUrlQueryCache[str] = node_querystring_1.default.parse(str);
122
+ }
123
+ return parsedUrlQuery;
124
+ }
125
+ /**
126
+ * Set query string as an object.
127
+ */
128
+ set query(obj) {
129
+ this.querystring = node_querystring_1.default.stringify(obj);
130
+ }
131
+ /**
132
+ * Get query string.
133
+ */
134
+ get querystring() {
135
+ if (!this.req)
136
+ return '';
137
+ return (0, parseurl_1.default)(this.req).query || '';
138
+ }
139
+ /**
140
+ * Set query string.
141
+ */
142
+ set querystring(str) {
143
+ const url = (0, parseurl_1.default)(this.req);
144
+ if (url.search === `?${str}`)
145
+ return;
146
+ url.search = str;
147
+ url.path = null;
148
+ this.url = (0, node_url_1.format)(url);
149
+ }
150
+ /**
151
+ * Get the search string. Same as the query string
152
+ * except it includes the leading ?.
153
+ */
154
+ get search() {
155
+ if (!this.querystring)
156
+ return '';
157
+ return `?${this.querystring}`;
158
+ }
159
+ /**
160
+ * Set the search string. Same as
161
+ * request.querystring= but included for ubiquity.
162
+ */
163
+ set search(str) {
164
+ this.querystring = str;
165
+ }
166
+ /**
167
+ * Parse the "Host" header field host
168
+ * and support X-Forwarded-Host when a
169
+ * proxy is enabled.
170
+ * return `hostname:port` format
171
+ */
172
+ get host() {
173
+ const proxy = this.app.proxy;
174
+ let host = proxy ? this.get('X-Forwarded-Host') : '';
175
+ if (!host) {
176
+ if (this.req.httpVersionMajor >= 2)
177
+ host = this.get(':authority');
178
+ if (!host)
179
+ host = this.get('Host');
180
+ }
181
+ if (!host)
182
+ return '';
183
+ return host.split(/\s*,\s*/, 1)[0];
184
+ }
185
+ /**
186
+ * Parse the "Host" header field hostname
187
+ * and support X-Forwarded-Host when a
188
+ * proxy is enabled.
189
+ */
190
+ get hostname() {
191
+ const host = this.host;
192
+ if (!host)
193
+ return '';
194
+ if (host[0] === '[')
195
+ return this.URL.hostname || ''; // IPv6
196
+ return host.split(':', 1)[0];
197
+ }
198
+ #memoizedURL;
199
+ /**
200
+ * Get WHATWG parsed URL.
201
+ * Lazily memoized.
202
+ */
203
+ get URL() {
204
+ if (!this.#memoizedURL) {
205
+ const originalUrl = this.originalUrl || ''; // avoid undefined in template string
206
+ try {
207
+ this.#memoizedURL = new URL(`${this.origin}${originalUrl}`);
208
+ }
209
+ catch {
210
+ this.#memoizedURL = Object.create(null);
211
+ }
212
+ }
213
+ return this.#memoizedURL;
214
+ }
215
+ /**
216
+ * Check if the request is fresh, aka
217
+ * Last-Modified and/or the ETag
218
+ * still match.
219
+ */
220
+ get fresh() {
221
+ const method = this.method;
222
+ const status = this.response.status;
223
+ // GET or HEAD for weak freshness validation only
224
+ if (method !== 'GET' && method !== 'HEAD')
225
+ return false;
226
+ // 2xx or 304 as per rfc2616 14.26
227
+ if ((status >= 200 && status < 300) || status === 304) {
228
+ return (0, fresh_1.default)(this.header, this.response.header);
229
+ }
230
+ return false;
231
+ }
232
+ /**
233
+ * Check if the request is stale, aka
234
+ * "Last-Modified" and / or the "ETag" for the
235
+ * resource has changed.
236
+ */
237
+ get stale() {
238
+ return !this.fresh;
239
+ }
240
+ /**
241
+ * Check if the request is idempotent.
242
+ */
243
+ get idempotent() {
244
+ const methods = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'];
245
+ return methods.includes(this.method);
246
+ }
247
+ /**
248
+ * Return the request socket.
249
+ */
250
+ get socket() {
251
+ return this.req.socket;
252
+ }
253
+ /**
254
+ * Get the charset when present or undefined.
255
+ */
256
+ get charset() {
257
+ try {
258
+ const { parameters } = content_type_1.default.parse(this.req);
259
+ return parameters.charset || '';
260
+ }
261
+ catch {
262
+ return '';
263
+ }
264
+ }
265
+ /**
266
+ * Return parsed Content-Length when present.
267
+ */
268
+ get length() {
269
+ const len = this.get('Content-Length');
270
+ if (len === '')
271
+ return;
272
+ return parseInt(len);
273
+ }
274
+ /**
275
+ * Return the protocol string "http" or "https"
276
+ * when requested with TLS. When the proxy setting
277
+ * is enabled the "X-Forwarded-Proto" header
278
+ * field will be trusted. If you're running behind
279
+ * a reverse proxy that supplies https for you this
280
+ * may be enabled.
281
+ */
282
+ get protocol() {
283
+ if (this.socket.encrypted)
284
+ return 'https';
285
+ if (!this.app.proxy)
286
+ return 'http';
287
+ const proto = this.get('X-Forwarded-Proto');
288
+ return proto ? proto.split(/\s*,\s*/, 1)[0] : 'http';
289
+ }
290
+ /**
291
+ * Shorthand for:
292
+ *
293
+ * this.protocol == 'https'
294
+ */
295
+ get secure() {
296
+ return this.protocol === 'https';
297
+ }
298
+ /**
299
+ * When `app.proxy` is `true`, parse
300
+ * the "X-Forwarded-For" ip address list.
301
+ *
302
+ * For example if the value was "client, proxy1, proxy2"
303
+ * you would receive the array `["client", "proxy1", "proxy2"]`
304
+ * where "proxy2" is the furthest down-stream.
305
+ */
306
+ get ips() {
307
+ const proxy = this.app.proxy;
308
+ const val = this.get(this.app.proxyIpHeader);
309
+ let ips = proxy && val
310
+ ? val.split(/\s*,\s*/)
311
+ : [];
312
+ if (this.app.maxIpsCount > 0) {
313
+ ips = ips.slice(-this.app.maxIpsCount);
314
+ }
315
+ return ips;
316
+ }
317
+ #ip;
318
+ /**
319
+ * Return request's remote address
320
+ * When `app.proxy` is `true`, parse
321
+ * the "X-Forwarded-For" ip address list and return the first one
322
+ */
323
+ get ip() {
324
+ if (!this.#ip) {
325
+ this.#ip = this.ips[0] || this.socket.remoteAddress || '';
326
+ }
327
+ return this.#ip;
328
+ }
329
+ set ip(ip) {
330
+ this.#ip = ip;
331
+ }
332
+ /**
333
+ * Return subdomains as an array.
334
+ *
335
+ * Subdomains are the dot-separated parts of the host before the main domain
336
+ * of the app. By default, the domain of the app is assumed to be the last two
337
+ * parts of the host. This can be changed by setting `app.subdomainOffset`.
338
+ *
339
+ * For example, if the domain is "tobi.ferrets.example.com":
340
+ * If `app.subdomainOffset` is not set, this.subdomains is
341
+ * `["ferrets", "tobi"]`.
342
+ * If `app.subdomainOffset` is 3, this.subdomains is `["tobi"]`.
343
+ */
344
+ get subdomains() {
345
+ const offset = this.app.subdomainOffset;
346
+ const hostname = this.hostname;
347
+ if (node_net_1.default.isIP(hostname))
348
+ return [];
349
+ return hostname
350
+ .split('.')
351
+ .reverse()
352
+ .slice(offset);
353
+ }
354
+ #accept;
355
+ /**
356
+ * Get accept object.
357
+ * Lazily memoized.
358
+ */
359
+ get accept() {
360
+ return this.#accept || (this.#accept = (0, accepts_1.default)(this.req));
361
+ }
362
+ /**
363
+ * Set accept object.
364
+ */
365
+ set accept(obj) {
366
+ this.#accept = obj;
367
+ }
368
+ /**
369
+ * Check if the given `type(s)` is acceptable, returning
370
+ * the best match when true, otherwise `false`, in which
371
+ * case you should respond with 406 "Not Acceptable".
372
+ *
373
+ * The `type` value may be a single mime type string
374
+ * such as "application/json", the extension name
375
+ * such as "json" or an array `["json", "html", "text/plain"]`. When a list
376
+ * or array is given the _best_ match, if any is returned.
377
+ *
378
+ * Examples:
379
+ *
380
+ * // Accept: text/html
381
+ * this.accepts('html');
382
+ * // => "html"
383
+ *
384
+ * // Accept: text/*, application/json
385
+ * this.accepts('html');
386
+ * // => "html"
387
+ * this.accepts('text/html');
388
+ * // => "text/html"
389
+ * this.accepts('json', 'text');
390
+ * // => "json"
391
+ * this.accepts('application/json');
392
+ * // => "application/json"
393
+ *
394
+ * // Accept: text/*, application/json
395
+ * this.accepts('image/png');
396
+ * this.accepts('png');
397
+ * // => false
398
+ *
399
+ * // Accept: text/*;q=.5, application/json
400
+ * this.accepts(['html', 'json']);
401
+ * this.accepts('html', 'json');
402
+ * // => "json"
403
+ */
404
+ accepts(...args) {
405
+ return this.accept.types(...args);
406
+ }
407
+ /**
408
+ * Return accepted encodings or best fit based on `encodings`.
409
+ *
410
+ * Given `Accept-Encoding: gzip, deflate`
411
+ * an array sorted by quality is returned:
412
+ *
413
+ * ['gzip', 'deflate']
414
+ */
415
+ acceptsEncodings(...args) {
416
+ return this.accept.encodings(...args);
417
+ }
418
+ /**
419
+ * Return accepted charsets or best fit based on `charsets`.
420
+ *
421
+ * Given `Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5`
422
+ * an array sorted by quality is returned:
423
+ *
424
+ * ['utf-8', 'utf-7', 'iso-8859-1']
425
+ */
426
+ acceptsCharsets(...args) {
427
+ return this.accept.charsets(...args);
428
+ }
429
+ /**
430
+ * Return accepted languages or best fit based on `langs`.
431
+ *
432
+ * Given `Accept-Language: en;q=0.8, es, pt`
433
+ * an array sorted by quality is returned:
434
+ *
435
+ * ['es', 'pt', 'en']
436
+ */
437
+ acceptsLanguages(...args) {
438
+ return this.accept.languages(...args);
439
+ }
440
+ /**
441
+ * Check if the incoming request contains the "Content-Type"
442
+ * header field and if it contains any of the given mime `type`s.
443
+ * If there is no request body, `null` is returned.
444
+ * If there is no content type, `false` is returned.
445
+ * Otherwise, it returns the first `type` that matches.
446
+ *
447
+ * Examples:
448
+ *
449
+ * // With Content-Type: text/html; charset=utf-8
450
+ * this.is('html'); // => 'html'
451
+ * this.is('text/html'); // => 'text/html'
452
+ * this.is('text/*', 'application/json'); // => 'text/html'
453
+ *
454
+ * // When Content-Type is application/json
455
+ * this.is('json', 'urlencoded'); // => 'json'
456
+ * this.is('application/json'); // => 'application/json'
457
+ * this.is('html', 'application/*'); // => 'application/json'
458
+ *
459
+ * this.is('html'); // => false
460
+ */
461
+ is(type, ...types) {
462
+ return (0, type_is_1.default)(this.req, type, ...types);
463
+ }
464
+ /**
465
+ * Return the request mime type void of
466
+ * parameters such as "charset".
467
+ */
468
+ get type() {
469
+ const type = this.get('Content-Type');
470
+ if (!type)
471
+ return '';
472
+ return type.split(';')[0];
473
+ }
474
+ /**
475
+ * Return request header.
476
+ *
477
+ * The `Referrer` header field is special-cased,
478
+ * both `Referrer` and `Referer` are interchangeable.
479
+ *
480
+ * Examples:
481
+ *
482
+ * this.get('Content-Type');
483
+ * // => "text/plain"
484
+ *
485
+ * this.get('content-type');
486
+ * // => "text/plain"
487
+ *
488
+ * this.get('Something');
489
+ * // => ''
490
+ */
491
+ get(field) {
492
+ const req = this.req;
493
+ switch (field = field.toLowerCase()) {
494
+ case 'referer':
495
+ case 'referrer':
496
+ return (req.headers.referrer || req.headers.referer || '');
497
+ default:
498
+ return (req.headers[field] || '');
499
+ }
500
+ }
501
+ /**
502
+ * Inspect implementation.
503
+ */
504
+ inspect() {
505
+ if (!this.req)
506
+ return;
507
+ return this.toJSON();
508
+ }
509
+ /**
510
+ * Custom inspection implementation for newer Node.js versions.
511
+ */
512
+ [node_util_1.default.inspect.custom]() {
513
+ return this.inspect();
514
+ }
515
+ /**
516
+ * Return JSON representation.
517
+ */
518
+ toJSON() {
519
+ return (0, only_1.default)(this, [
520
+ 'method',
521
+ 'url',
522
+ 'header',
523
+ ]);
524
+ }
726
525
  }
526
+ exports.default = Request;
527
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9yZXF1ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0RBQTJCO0FBRTNCLHVDQUErQztBQUMvQyx3RUFBa0M7QUFDbEMsMERBQTZCO0FBRzdCLHNEQUE4QjtBQUM5QixnRUFBdUM7QUFDdkMsd0RBQTZCO0FBQzdCLHNEQUE2QjtBQUM3QixrREFBMEI7QUFDMUIsZ0RBQXdCO0FBS3hCLE1BQXFCLE9BQU87SUFDMUIsR0FBRyxDQUFjO0lBQ2pCLEdBQUcsQ0FBa0I7SUFDckIsR0FBRyxDQUFpQjtJQUNwQixHQUFHLENBQVU7SUFDYixRQUFRLENBQVc7SUFDbkIsV0FBVyxDQUFTO0lBRXBCLFlBQVksR0FBZ0IsRUFBRSxHQUFZLEVBQUUsR0FBb0IsRUFBRSxHQUFtQjtRQUNuRixJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUNmLElBQUksQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO1FBQ2YsSUFBSSxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUM7UUFDZixJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUNmLElBQUksQ0FBQyxXQUFXLEdBQUcsR0FBRyxDQUFDLEdBQUksQ0FBQztJQUM5QixDQUFDO0lBRUQ7O09BRUc7SUFFSCxJQUFJLE1BQU07UUFDUixPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDO0lBQzFCLENBQUM7SUFFRDs7T0FFRztJQUVILElBQUksTUFBTSxDQUFDLEdBQUc7UUFDWixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sR0FBRyxHQUFHLENBQUM7SUFDekIsQ0FBQztJQUVEOztPQUVHO0lBRUgsSUFBSSxPQUFPO1FBQ1QsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQztJQUMxQixDQUFDO0lBRUQ7O09BRUc7SUFFSCxJQUFJLE9BQU8sQ0FBQyxHQUFHO1FBQ2IsSUFBSSxDQUFDLEdBQUcs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