ultimate-express 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/.github/workflows/test.yml +27 -0
  2. package/EXPRESS_LICENSE +26 -0
  3. package/README.md +269 -0
  4. package/package.json +76 -0
  5. package/src/application.js +295 -0
  6. package/src/index.js +23 -0
  7. package/src/middlewares.js +95 -0
  8. package/src/request.js +324 -0
  9. package/src/response.js +686 -0
  10. package/src/router.js +490 -0
  11. package/src/utils.js +285 -0
  12. package/src/view.js +103 -0
  13. package/src/workers/fs.js +14 -0
  14. package/tests/index.js +64 -0
  15. package/tests/parts/.test/index.html +11 -0
  16. package/tests/parts/big.jpg +0 -0
  17. package/tests/parts/index.art +12 -0
  18. package/tests/parts/index.dot +12 -0
  19. package/tests/parts/index.ejs +12 -0
  20. package/tests/parts/index.handlebars +2 -0
  21. package/tests/parts/index.html +12 -0
  22. package/tests/parts/index.mustache +12 -0
  23. package/tests/parts/index.pug +6 -0
  24. package/tests/parts/index.swig +12 -0
  25. package/tests/parts/layouts/main.handlebars +12 -0
  26. package/tests/preload.cjs +5 -0
  27. package/tests/singular.js +41 -0
  28. package/tests/tests/app/app-engine.js +8 -0
  29. package/tests/tests/app/app-on-mount.js +24 -0
  30. package/tests/tests/app/app-path.js +21 -0
  31. package/tests/tests/app/app-route.js +30 -0
  32. package/tests/tests/app/options.js +16 -0
  33. package/tests/tests/app/setting-inheritance.js +16 -0
  34. package/tests/tests/engines/art-template.js +33 -0
  35. package/tests/tests/engines/dot.js +28 -0
  36. package/tests/tests/engines/ejs.js +25 -0
  37. package/tests/tests/engines/handlebars.js +28 -0
  38. package/tests/tests/engines/mustache.js +28 -0
  39. package/tests/tests/engines/pug.js +25 -0
  40. package/tests/tests/engines/swig.js +28 -0
  41. package/tests/tests/errors/error-handling-middleware.js +22 -0
  42. package/tests/tests/errors/next-error-optimized.js +26 -0
  43. package/tests/tests/errors/next-error.js +26 -0
  44. package/tests/tests/errors/unexpected-error-handling.js +18 -0
  45. package/tests/tests/listen/listen-random.js +11 -0
  46. package/tests/tests/listen/listen-specific.js +17 -0
  47. package/tests/tests/middlewares/body-json.js +31 -0
  48. package/tests/tests/middlewares/body-raw-deflate.js +43 -0
  49. package/tests/tests/middlewares/body-raw-gzip.js +43 -0
  50. package/tests/tests/middlewares/body-raw.js +41 -0
  51. package/tests/tests/middlewares/body-text.js +27 -0
  52. package/tests/tests/middlewares/body-urlencoded.js +30 -0
  53. package/tests/tests/middlewares/cookie-parser-signed.js +31 -0
  54. package/tests/tests/middlewares/cookie-parser.js +28 -0
  55. package/tests/tests/middlewares/cookie-session.js +40 -0
  56. package/tests/tests/middlewares/cors.js +29 -0
  57. package/tests/tests/middlewares/errorhandler.js +26 -0
  58. package/tests/tests/middlewares/express-fileupload-temp.js +46 -0
  59. package/tests/tests/middlewares/express-fileupload.js +28 -0
  60. package/tests/tests/middlewares/express-rate-limit.js +33 -0
  61. package/tests/tests/middlewares/express-session.js +37 -0
  62. package/tests/tests/middlewares/express-static-options.js +72 -0
  63. package/tests/tests/middlewares/express-static.js +40 -0
  64. package/tests/tests/middlewares/method-override.js +33 -0
  65. package/tests/tests/middlewares/multer.js +43 -0
  66. package/tests/tests/middlewares/multiple-middlewares.js +37 -0
  67. package/tests/tests/middlewares/response-time.js +29 -0
  68. package/tests/tests/middlewares/serve-index.js +38 -0
  69. package/tests/tests/middlewares/serve-static.js +38 -0
  70. package/tests/tests/middlewares/vhost.js +50 -0
  71. package/tests/tests/params/array-param.js +30 -0
  72. package/tests/tests/params/nested-params.js +24 -0
  73. package/tests/tests/params/param-errors.js +56 -0
  74. package/tests/tests/params/param-function.js +49 -0
  75. package/tests/tests/params/param-next-route.js +48 -0
  76. package/tests/tests/params/param-optimized.js +38 -0
  77. package/tests/tests/params/param-use.js +39 -0
  78. package/tests/tests/params/param.js +68 -0
  79. package/tests/tests/params/params-regex.js +26 -0
  80. package/tests/tests/params/params-use.js +20 -0
  81. package/tests/tests/params/params.js +35 -0
  82. package/tests/tests/req/req-accepts-charsets.js +40 -0
  83. package/tests/tests/req/req-accepts-encodings.js +36 -0
  84. package/tests/tests/req/req-accepts-languages.js +41 -0
  85. package/tests/tests/req/req-accepts.js +41 -0
  86. package/tests/tests/req/req-app.js +17 -0
  87. package/tests/tests/req/req-baseurl.js +38 -0
  88. package/tests/tests/req/req-connection.js +19 -0
  89. package/tests/tests/req/req-fresh.js +59 -0
  90. package/tests/tests/req/req-get.js +78 -0
  91. package/tests/tests/req/req-headers-distinct.js +72 -0
  92. package/tests/tests/req/req-headers.js +72 -0
  93. package/tests/tests/req/req-host.js +45 -0
  94. package/tests/tests/req/req-hostname.js +45 -0
  95. package/tests/tests/req/req-ip.js +19 -0
  96. package/tests/tests/req/req-is.js +44 -0
  97. package/tests/tests/req/req-original-url.js +29 -0
  98. package/tests/tests/req/req-param.js +29 -0
  99. package/tests/tests/req/req-protocol.js +20 -0
  100. package/tests/tests/req/req-query.js +23 -0
  101. package/tests/tests/req/req-range.js +48 -0
  102. package/tests/tests/req/req-raw-headers.js +72 -0
  103. package/tests/tests/req/req-subdomains.js +48 -0
  104. package/tests/tests/req/req-url-nested.js +27 -0
  105. package/tests/tests/req/req-url-optimized-router.js +26 -0
  106. package/tests/tests/req/req-url-optimized.js +23 -0
  107. package/tests/tests/req/req-url.js +36 -0
  108. package/tests/tests/req/req-xhr.js +23 -0
  109. package/tests/tests/res/head-content-length.js +18 -0
  110. package/tests/tests/res/head.js +47 -0
  111. package/tests/tests/res/injecting.js +25 -0
  112. package/tests/tests/res/piping.js +23 -0
  113. package/tests/tests/res/res-app.js +17 -0
  114. package/tests/tests/res/res-append.js +24 -0
  115. package/tests/tests/res/res-attachment.js +19 -0
  116. package/tests/tests/res/res-clear-cookie.js +18 -0
  117. package/tests/tests/res/res-cookie.js +22 -0
  118. package/tests/tests/res/res-download.js +36 -0
  119. package/tests/tests/res/res-format.js +57 -0
  120. package/tests/tests/res/res-get.js +18 -0
  121. package/tests/tests/res/res-headers-sent.js +18 -0
  122. package/tests/tests/res/res-json.js +17 -0
  123. package/tests/tests/res/res-jsonp.js +25 -0
  124. package/tests/tests/res/res-links.js +21 -0
  125. package/tests/tests/res/res-location.js +34 -0
  126. package/tests/tests/res/res-redirect.js +46 -0
  127. package/tests/tests/res/res-remove-header.js +19 -0
  128. package/tests/tests/res/res-send-file.js +17 -0
  129. package/tests/tests/res/res-send-status.js +17 -0
  130. package/tests/tests/res/res-send.js +69 -0
  131. package/tests/tests/res/res-set.js +28 -0
  132. package/tests/tests/res/res-status.js +18 -0
  133. package/tests/tests/res/res-type.js +19 -0
  134. package/tests/tests/res/res-vary.js +19 -0
  135. package/tests/tests/res/res-write.js +29 -0
  136. package/tests/tests/routers/complex-routers.js +34 -0
  137. package/tests/tests/routers/empty-router.js +25 -0
  138. package/tests/tests/routers/lot-of-routes.js +38 -0
  139. package/tests/tests/routers/mergeparams.js +42 -0
  140. package/tests/tests/routers/nested-routers.js +52 -0
  141. package/tests/tests/routers/router-options.js +68 -0
  142. package/tests/tests/routers/routers.js +45 -0
  143. package/tests/tests/routers/simple-routers.js +35 -0
  144. package/tests/tests/routing/all.js +47 -0
  145. package/tests/tests/routing/array-arguments.js +35 -0
  146. package/tests/tests/routing/array-use.js +33 -0
  147. package/tests/tests/routing/async-use.js +25 -0
  148. package/tests/tests/routing/complex-routes.js +50 -0
  149. package/tests/tests/routing/lot-of-param-routes.js +26 -0
  150. package/tests/tests/routing/lot-of-routes.js +59 -0
  151. package/tests/tests/routing/next-existent-optimized-route.js +29 -0
  152. package/tests/tests/routing/next-existent-route.js +29 -0
  153. package/tests/tests/routing/next-nonexistent-optimized-route.js +19 -0
  154. package/tests/tests/routing/next-nonexistent-route.js +19 -0
  155. package/tests/tests/routing/next-special-cases.js +54 -0
  156. package/tests/tests/routing/next-unoptimized.js +39 -0
  157. package/tests/tests/routing/no-path-use.js +29 -0
  158. package/tests/tests/routing/non-string-routes.js +27 -0
  159. package/tests/tests/routing/req-multiple-mountpaths.js +34 -0
  160. package/tests/tests/routing/simple-routes.js +29 -0
  161. package/tests/tests/routing/simple-use.js +52 -0
  162. package/tests/tests/routing/some-middlewares.js +27 -0
  163. package/tests/tests/routing/special-characters.js +28 -0
  164. package/tests/tests/routing/star.js +31 -0
  165. package/tests/tests/routing/sub-apps.js +32 -0
  166. package/tests/tests/routing/trailing-slash.js +37 -0
  167. package/tests/tests/routing/weird-route-start.js +18 -0
  168. package/tests/tests/send-file/accept-ranges.js +26 -0
  169. package/tests/tests/send-file/callback.js +23 -0
  170. package/tests/tests/send-file/default-error-routing.js +21 -0
  171. package/tests/tests/send-file/dotfiles.js +24 -0
  172. package/tests/tests/send-file/etag.js +19 -0
  173. package/tests/tests/send-file/fs-threads.js +39 -0
  174. package/tests/tests/send-file/head.js +49 -0
  175. package/tests/tests/send-file/headers.js +23 -0
  176. package/tests/tests/send-file/if-match.js +31 -0
  177. package/tests/tests/send-file/if-range.js +37 -0
  178. package/tests/tests/send-file/if-unmodified-since.js +32 -0
  179. package/tests/tests/send-file/immutable.js +22 -0
  180. package/tests/tests/send-file/large-file.js +19 -0
  181. package/tests/tests/send-file/last-modified.js +21 -0
  182. package/tests/tests/send-file/max-age.js +21 -0
  183. package/tests/tests/send-file/path-traversal.js +35 -0
  184. package/tests/tests/send-file/range.js +57 -0
  185. package/tests/tests/send-file/simple.js +18 -0
  186. package/tests/tests/settings/case-sensitive-routing.js +48 -0
  187. package/tests/tests/settings/env-errors.js +38 -0
  188. package/tests/tests/settings/etag.js +36 -0
  189. package/tests/tests/settings/json-escape.js +45 -0
  190. package/tests/tests/settings/json-replacer.js +50 -0
  191. package/tests/tests/settings/json-spaces.js +44 -0
  192. package/tests/tests/settings/query-parser.js +45 -0
  193. package/tests/tests/settings/strict-routing.js +64 -0
  194. package/tests/tests/settings/subdomain-offset.js +38 -0
  195. package/tests/tests/settings/trust-proxy-host.js +58 -0
  196. package/tests/tests/settings/trust-proxy-ip.js +58 -0
  197. package/tests/tests/settings/trust-proxy-ips.js +58 -0
  198. package/tests/tests/settings/trust-proxy-protocol.js +46 -0
  199. package/tests/tests/settings/x-powered-by.js +32 -0
  200. package/tests/uws.js +14 -0
package/src/index.js ADDED
@@ -0,0 +1,23 @@
1
+ const Application = require("./application.js");
2
+ const Router = require("./router.js");
3
+ const bodyParser = require("body-parser");
4
+ const { static } = require("./middlewares.js");
5
+ const Request = require("./request.js");
6
+ const Response = require("./response.js");
7
+
8
+ Application.Router = function(options) {
9
+
10
+ return new Router(options);
11
+ }
12
+
13
+ Application.request = Request.prototype;
14
+ Application.response = Response.prototype;
15
+
16
+ Application.static = static;
17
+
18
+ Application.json = bodyParser.json;
19
+ Application.urlencoded = bodyParser.urlencoded;
20
+ Application.text = bodyParser.text;
21
+ Application.raw = bodyParser.raw;
22
+
23
+ module.exports = Application;
@@ -0,0 +1,95 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ function static(root, options) {
5
+ if(!options) options = {};
6
+ if(typeof options.index === 'undefined') options.index = 'index.html';
7
+ if(typeof options.redirect === 'undefined') options.redirect = true;
8
+ if(typeof options.fallthrough === 'undefined') options.fallthrough = true;
9
+ if(options.extensions) {
10
+ if(typeof options.extensions !== 'string' && !Array.isArray(options.extensions)) {
11
+ throw new Error('extensions must be a string or an array');
12
+ }
13
+ if(!Array.isArray(options.extensions)) {
14
+ options.extensions = [options.extensions];
15
+ }
16
+ options.extensions = options.extensions.map(ext => ext.startsWith('.') ? ext.slice(1) : ext);
17
+ }
18
+ options.root = root;
19
+
20
+ return (req, res, next) => {
21
+ const iq = req.url.indexOf('?');
22
+ let url = iq !== -1 ? req.url.substring(0, iq) : req.url;
23
+ let _path = url;
24
+ let fullpath = path.resolve(path.join(options.root, url));
25
+ if(options.root && !fullpath.startsWith(path.resolve(options.root))) {
26
+ if(!options.fallthrough) {
27
+ res.status(403);
28
+ return next(new Error('Forbidden'));
29
+ } else return next();
30
+ }
31
+
32
+ let stat;
33
+ try {
34
+ stat = fs.statSync(fullpath);
35
+ } catch(err) {
36
+ const ext = path.extname(fullpath);
37
+ let i = 0;
38
+ if(ext === '' && options.extensions) {
39
+ while(i < options.extensions.length) {
40
+ try {
41
+ stat = fs.statSync(fullpath + '.' + options.extensions[i]);
42
+ _path = url + '.' + options.extensions[i];
43
+ break;
44
+ } catch(err) {
45
+ i++;
46
+ }
47
+ }
48
+ }
49
+ if(!stat) {
50
+ if(!options.fallthrough) {
51
+ res.status(404);
52
+ return next(err.message);
53
+ } else return next();
54
+ }
55
+ }
56
+
57
+ if(stat.isDirectory()) {
58
+ if(!req.endsWithSlash) {
59
+ if(options.redirect) return res.redirect(301, req.path + '/');
60
+ else {
61
+ if(!options.fallthrough) {
62
+ res.status(404);
63
+ return next(new Error('Not found'));
64
+ } else return next();
65
+ }
66
+ }
67
+ if(options.index) {
68
+ try {
69
+ stat = fs.statSync(path.join(fullpath, options.index));
70
+ _path = path.join(url, options.index);
71
+ } catch(err) {
72
+ if(!options.fallthrough) {
73
+ res.status(404);
74
+ return next(new Error('Not found'));
75
+ } else return next();
76
+ }
77
+ } else {
78
+
79
+ return next();
80
+ }
81
+ }
82
+
83
+ options._stat = stat;
84
+
85
+ return res.sendFile(_path, options, e => {
86
+ if(e) {
87
+ next(!options.fallthrough ? e : undefined);
88
+ }
89
+ });
90
+ }
91
+ }
92
+
93
+ module.exports = {
94
+ static
95
+ };
package/src/request.js ADDED
@@ -0,0 +1,324 @@
1
+ const { patternToRegex, deprecated } = require("./utils.js");
2
+ const accepts = require("accepts");
3
+ const typeis = require("type-is");
4
+ const parseRange = require("range-parser");
5
+ const proxyaddr = require("proxy-addr");
6
+ const fresh = require("fresh");
7
+ const { Readable } = require("stream");
8
+
9
+ const discardedDuplicates = [
10
+ "age", "authorization", "content-length", "content-type", "etag", "expires",
11
+ "from", "host", "if-modified-since", "if-unmodified-since", "last-modified",
12
+ "location", "max-forwards", "proxy-authorization", "referer", "retry-after",
13
+ "server", "user-agent"
14
+ ];
15
+
16
+ module.exports = class Request extends Readable {
17
+ #cachedQuery = null;
18
+ #cachedHeaders = null;
19
+ #cachedDistinctHeaders = null;
20
+ #rawHeadersEntries = [];
21
+ constructor(req, res, app) {
22
+ super();
23
+ this._res = res;
24
+ this._req = req;
25
+ this.readable = true;
26
+ this._req.forEach((key, value) => {
27
+ this.#rawHeadersEntries.push([key, value]);
28
+ });
29
+ this.app = app;
30
+ this.urlQuery = req.getQuery() ?? '';
31
+ if(this.urlQuery) {
32
+ this.urlQuery = '?' + this.urlQuery;
33
+ }
34
+ this.originalUrl = req.getUrl() + this.urlQuery;
35
+ this.url = this.originalUrl;
36
+ const iq = this.url.indexOf('?');
37
+ this.path = iq !== -1 ? this.url.substring(0, iq) : this.url;
38
+ this.endsWithSlash = this.path[this.path.length - 1] === '/';
39
+ this._opPath = this.path;
40
+ if(this.endsWithSlash && this.path !== '/' && !this.app.get('strict routing')) {
41
+ this._opPath = this._opPath.slice(0, -1);
42
+ }
43
+ this.method = req.getMethod().toUpperCase();
44
+ this.params = {};
45
+
46
+ this._gotParams = new Set();
47
+ this._stack = [];
48
+ this._paramStack = [];
49
+ this.bufferedData = Buffer.alloc(0);
50
+ this.receivedData = false;
51
+
52
+ const additionalMethods = this.app.get('body methods');
53
+ // skip reading body for non-POST requests
54
+ // this makes it +10k req/sec faster
55
+ if(
56
+ this.method === 'POST' ||
57
+ this.method === 'PUT' ||
58
+ this.method === 'PATCH' ||
59
+ (additionalMethods && additionalMethods.includes(this.method))
60
+ ) {
61
+ this._res.onData((ab, isLast) => {
62
+ // make stream actually readable
63
+ this.receivedData = true;
64
+ // instead of pushing data immediately, buffer it
65
+ // because writable streams cant handle the amount of data uWS gives (usually 512kb+)
66
+ const chunk = Buffer.from(ab);
67
+ this.bufferedData = Buffer.concat([this.bufferedData, chunk]);
68
+ if(isLast) {
69
+ // once its done start pushing data
70
+ this._read();
71
+ }
72
+ });
73
+ } else {
74
+ this.receivedData = true;
75
+ }
76
+ }
77
+
78
+ async _read() {
79
+ if(!this.receivedData) {
80
+ return;
81
+ }
82
+ if(this.bufferedData.length > 0) {
83
+ // push 64kb chunks
84
+ const chunk = this.bufferedData.subarray(0, 1024 * 64);
85
+ this.bufferedData = this.bufferedData.subarray(1024 * 64);
86
+ this.push(chunk);
87
+ } else {
88
+ this.push(null);
89
+ }
90
+ }
91
+
92
+ get baseUrl() {
93
+ let match = this.path.match(patternToRegex(this._stack.join(""), true));
94
+ return match ? match[0] : '';
95
+ }
96
+
97
+ get #host() {
98
+ const trust = this.app.get('trust proxy fn');
99
+ if(!trust) {
100
+ return this.get('host');
101
+ }
102
+ let val = this.headers['x-forwarded-host'];
103
+ if (!val || !trust(this.connection.remoteAddress, 0)) {
104
+ val = this.headers['host'];
105
+ } else if (val.indexOf(',') !== -1) {
106
+ // Note: X-Forwarded-Host is normally only ever a
107
+ // single value, but this is to be safe.
108
+ val = val.substring(0, val.indexOf(',')).trimRight()
109
+ }
110
+
111
+ return val ? val.split(':')[0] : undefined;
112
+ }
113
+
114
+ get host() {
115
+ deprecated('req.host', 'req.hostname');
116
+ return this.hostname;
117
+ }
118
+
119
+ get hostname() {
120
+ const host = this.#host;
121
+ if(!host) return this.headers['host'].split(':')[0];
122
+ const offset = host[0] === '[' ? host.indexOf(']') + 1 : 0;
123
+ const index = host.indexOf(':', offset);
124
+ return index !== -1 ? host.slice(0, index) : host;
125
+ }
126
+
127
+ get ip() {
128
+ const trust = this.app.get('trust proxy fn');
129
+ if(!trust) {
130
+ return Buffer.from(this._res.getRemoteAddressAsText()).toString();
131
+ }
132
+ return proxyaddr(this, trust);
133
+ }
134
+
135
+ get ips() {
136
+ const trust = this.app.get('trust proxy fn');
137
+ if(!trust) {
138
+ return [];
139
+ }
140
+ const addrs = proxyaddr.all(this, trust);
141
+ addrs.reverse().pop();
142
+ return addrs;
143
+ }
144
+
145
+ get protocol() {
146
+ const proto = this.app.ssl ? 'https' : 'http';
147
+ const trust = this.app.get('trust proxy fn');
148
+ if(!trust) {
149
+ return proto;
150
+ }
151
+ if(!trust(this.connection.remoteAddress, 0)) {
152
+ return proto;
153
+ }
154
+ const header = this.headers['x-forwarded-proto'] || proto;
155
+ const index = header.indexOf(',');
156
+
157
+ return index !== -1 ? header.slice(0, index).trim() : header.trim();
158
+ }
159
+
160
+ get query() {
161
+ if(this.#cachedQuery) {
162
+ return this.#cachedQuery;
163
+ }
164
+ const qp = this.app.get('query parser fn');
165
+ if(qp) {
166
+ this.#cachedQuery = qp(this.urlQuery.slice(1));
167
+ } else {
168
+ this.#cachedQuery = {};
169
+ }
170
+ return this.#cachedQuery;
171
+ }
172
+
173
+ get secure() {
174
+ return this.protocol === 'https';
175
+ }
176
+
177
+ get subdomains() {
178
+ let host = this.hostname;
179
+ let subdomains = host.split('.');
180
+ const so = this.app.get('subdomain offset');
181
+ if(so === 0) {
182
+ return subdomains.reverse();
183
+ }
184
+ return subdomains.slice(0, -so).reverse();
185
+ }
186
+
187
+ get xhr() {
188
+ return this.headers['x-requested-with'] === 'XMLHttpRequest';
189
+ }
190
+
191
+ get connection() {
192
+ return {
193
+ remoteAddress: Buffer.from(this.res._res.getRemoteAddressAsText()).toString(),
194
+ localPort: this.app.port,
195
+ remotePort: this.app.port,
196
+ encrypted: this.app.ssl,
197
+ };
198
+ }
199
+
200
+ get fresh() {
201
+ if(this.method !== 'HEAD' && this.method !== 'GET') {
202
+ return false;
203
+ }
204
+ if((this.res.statusCode >= 200 && this.res.statusCode < 300) || this.res.statusCode === 304) {
205
+ return fresh(this.headers, {
206
+ 'etag': this.res.headers['etag'],
207
+ 'last-modified': this.res.headers['last-modified'],
208
+ });
209
+ }
210
+ return false;
211
+ }
212
+
213
+ get stale() {
214
+ return !this.fresh;
215
+ }
216
+
217
+ get(field) {
218
+ field = field.toLowerCase();
219
+ if(field === 'referrer' || field === 'referer') {
220
+ const res = this.headers['referrer'];
221
+ if(!res) {
222
+ return this.headers['referer'];
223
+ }
224
+ return res;
225
+ }
226
+ return this.headers[field];
227
+ }
228
+
229
+ accepts(...types) {
230
+ const accept = accepts({ headers: this.headers });
231
+ return accept.types(...types);
232
+ }
233
+
234
+ acceptsCharsets(...charsets) {
235
+ const accept = accepts({ headers: this.headers });
236
+ return accept.charsets(...charsets);
237
+ }
238
+
239
+ acceptsEncodings(...encodings) {
240
+ const accept = accepts({ headers: this.headers });
241
+ return accept.encodings(...encodings);
242
+ }
243
+
244
+ acceptsLanguages(...languages) {
245
+ const accept = accepts({ headers: this.headers });
246
+ return accept.languages(...languages);
247
+ }
248
+
249
+ is(type) {
250
+ return typeis(this, type);
251
+ }
252
+
253
+ param(name, defaultValue) {
254
+ deprecated('req.param(name)', 'req.params, req.body, or req.query');
255
+ if(this.params[name]) {
256
+ return this.params[name];
257
+ }
258
+ if(this.body && this.body[name]) {
259
+ return this.body[name];
260
+ }
261
+ return this.query[name] ?? defaultValue;
262
+ }
263
+
264
+ range(size, options) {
265
+ const range = this.headers['range'];
266
+ if(!range) return;
267
+ return parseRange(size, range, options);
268
+ }
269
+
270
+ get headers() {
271
+ // https://nodejs.org/api/http.html#messageheaders
272
+ if(this.#cachedHeaders) {
273
+ return this.#cachedHeaders;
274
+ }
275
+ let headers = {};
276
+ this.#rawHeadersEntries.forEach((val) => {
277
+ const key = val[0].toLowerCase();
278
+ const value = val[1];
279
+ if(headers[key]) {
280
+ if(discardedDuplicates.includes(key)) {
281
+ return;
282
+ }
283
+ if(key === 'cookie') {
284
+ headers[key] += '; ' + value;
285
+ } else if(key === 'set-cookie') {
286
+ headers[key].push(value);
287
+ } else {
288
+ headers[key] += ', ' + value;
289
+ }
290
+ return;
291
+ }
292
+ if(key === 'set-cookie') {
293
+ headers[key] = [value];
294
+ } else {
295
+ headers[key] = value;
296
+ }
297
+ });
298
+ this.#cachedHeaders = headers;
299
+ return headers;
300
+ }
301
+
302
+ get headersDistinct() {
303
+ if(this.#cachedDistinctHeaders) {
304
+ return this.#cachedDistinctHeaders;
305
+ }
306
+ let headers = {};
307
+ this.#rawHeadersEntries.forEach((val) => {
308
+ if(!headers[val[0]]) {
309
+ headers[val[0]] = [];
310
+ }
311
+ headers[val[0]].push(val[1]);
312
+ });
313
+ this.#cachedDistinctHeaders = headers;
314
+ return headers;
315
+ }
316
+
317
+ get rawHeaders() {
318
+ const res = [];
319
+ this.#rawHeadersEntries.forEach((val) => {
320
+ res.push(val[0], val[1]);
321
+ });
322
+ return res;
323
+ }
324
+ }