wooks 0.0.1-beta.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 (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +522 -0
  3. package/dist/src/composables/body.d.ts +17 -0
  4. package/dist/src/composables/body.d.ts.map +1 -0
  5. package/dist/src/composables/cookies.d.ts +13 -0
  6. package/dist/src/composables/cookies.d.ts.map +1 -0
  7. package/dist/src/composables/core-test.d.ts +19 -0
  8. package/dist/src/composables/core-test.d.ts.map +1 -0
  9. package/dist/src/composables/core.d.ts +30 -0
  10. package/dist/src/composables/core.d.ts.map +1 -0
  11. package/dist/src/composables/header-accept.d.ts +9 -0
  12. package/dist/src/composables/header-accept.d.ts.map +1 -0
  13. package/dist/src/composables/header-authorization.d.ts +20 -0
  14. package/dist/src/composables/header-authorization.d.ts.map +1 -0
  15. package/dist/src/composables/header-set-cache-control.d.ts +9 -0
  16. package/dist/src/composables/header-set-cache-control.d.ts.map +1 -0
  17. package/dist/src/composables/headers.d.ts +11 -0
  18. package/dist/src/composables/headers.d.ts.map +1 -0
  19. package/dist/src/composables/index.d.ts +11 -0
  20. package/dist/src/composables/index.d.ts.map +1 -0
  21. package/dist/src/composables/req-res.d.ts +34 -0
  22. package/dist/src/composables/req-res.d.ts.map +1 -0
  23. package/dist/src/composables/search-params.d.ts +13 -0
  24. package/dist/src/composables/search-params.d.ts.map +1 -0
  25. package/dist/src/composables/tests/body.spec.d.ts +2 -0
  26. package/dist/src/composables/tests/body.spec.d.ts.map +1 -0
  27. package/dist/src/composables/tests/cookies.spec.d.ts +2 -0
  28. package/dist/src/composables/tests/cookies.spec.d.ts.map +1 -0
  29. package/dist/src/composables/tests/core.spec.d.ts +2 -0
  30. package/dist/src/composables/tests/core.spec.d.ts.map +1 -0
  31. package/dist/src/composables/tests/headers.spec.d.ts +2 -0
  32. package/dist/src/composables/tests/headers.spec.d.ts.map +1 -0
  33. package/dist/src/composables/tests/req-res.spec.d.ts +2 -0
  34. package/dist/src/composables/tests/req-res.spec.d.ts.map +1 -0
  35. package/dist/src/composables/tests/search-params.spec.d.ts +2 -0
  36. package/dist/src/composables/tests/search-params.spec.d.ts.map +1 -0
  37. package/dist/src/content-types/index.d.ts +97 -0
  38. package/dist/src/content-types/index.d.ts.map +1 -0
  39. package/dist/src/e2e.spec.d.ts +2 -0
  40. package/dist/src/e2e.spec.d.ts.map +1 -0
  41. package/dist/src/errors/error-renderer.d.ts +9 -0
  42. package/dist/src/errors/error-renderer.d.ts.map +1 -0
  43. package/dist/src/errors/errors.spec.d.ts +2 -0
  44. package/dist/src/errors/errors.spec.d.ts.map +1 -0
  45. package/dist/src/errors/index.d.ts +3 -0
  46. package/dist/src/errors/index.d.ts.map +1 -0
  47. package/dist/src/errors/wooks-error.d.ts +20 -0
  48. package/dist/src/errors/wooks-error.d.ts.map +1 -0
  49. package/dist/src/http.d.ts +7 -0
  50. package/dist/src/http.d.ts.map +1 -0
  51. package/dist/src/index.d.ts +8 -0
  52. package/dist/src/index.d.ts.map +1 -0
  53. package/dist/src/mime/extensions.d.ts +1184 -0
  54. package/dist/src/mime/extensions.d.ts.map +1 -0
  55. package/dist/src/mime/index.d.ts +2 -0
  56. package/dist/src/mime/index.d.ts.map +1 -0
  57. package/dist/src/mime/mime.spec.d.ts +2 -0
  58. package/dist/src/mime/mime.spec.d.ts.map +1 -0
  59. package/dist/src/response/core.d.ts +30 -0
  60. package/dist/src/response/core.d.ts.map +1 -0
  61. package/dist/src/response/factory.d.ts +4 -0
  62. package/dist/src/response/factory.d.ts.map +1 -0
  63. package/dist/src/response/index.d.ts +4 -0
  64. package/dist/src/response/index.d.ts.map +1 -0
  65. package/dist/src/response/renderer.d.ts +8 -0
  66. package/dist/src/response/renderer.d.ts.map +1 -0
  67. package/dist/src/response/response.spec.d.ts +2 -0
  68. package/dist/src/response/response.spec.d.ts.map +1 -0
  69. package/dist/src/serve-file/serve-file.d.ts +20 -0
  70. package/dist/src/serve-file/serve-file.d.ts.map +1 -0
  71. package/dist/src/serve-file/serve-file.spec.d.ts +2 -0
  72. package/dist/src/serve-file/serve-file.spec.d.ts.map +1 -0
  73. package/dist/src/server.d.ts +26 -0
  74. package/dist/src/server.d.ts.map +1 -0
  75. package/dist/src/status-codes/index.d.ts +135 -0
  76. package/dist/src/status-codes/index.d.ts.map +1 -0
  77. package/dist/src/types.d.ts +5 -0
  78. package/dist/src/types.d.ts.map +1 -0
  79. package/dist/src/utils/banner.d.ts +2 -0
  80. package/dist/src/utils/banner.d.ts.map +1 -0
  81. package/dist/src/utils/body-compressor.d.ts +8 -0
  82. package/dist/src/utils/body-compressor.d.ts.map +1 -0
  83. package/dist/src/utils/cache-control.d.ts +14 -0
  84. package/dist/src/utils/cache-control.d.ts.map +1 -0
  85. package/dist/src/utils/panic.d.ts +2 -0
  86. package/dist/src/utils/panic.d.ts.map +1 -0
  87. package/dist/src/utils/set-cookie.d.ts +16 -0
  88. package/dist/src/utils/set-cookie.d.ts.map +1 -0
  89. package/dist/src/utils/tests/body-compressor.spec.d.ts +2 -0
  90. package/dist/src/utils/tests/body-compressor.spec.d.ts.map +1 -0
  91. package/dist/src/utils/tests/set-cookie.spec.d.ts +2 -0
  92. package/dist/src/utils/tests/set-cookie.spec.d.ts.map +1 -0
  93. package/dist/src/utils/tests/time.spec.d.ts +2 -0
  94. package/dist/src/utils/tests/time.spec.d.ts.map +1 -0
  95. package/dist/src/utils/tests/url-search-params.spec.d.ts +2 -0
  96. package/dist/src/utils/tests/url-search-params.spec.d.ts.map +1 -0
  97. package/dist/src/utils/time.d.ts +5 -0
  98. package/dist/src/utils/time.d.ts.map +1 -0
  99. package/dist/src/utils/url-search-params.d.ts +6 -0
  100. package/dist/src/utils/url-search-params.d.ts.map +1 -0
  101. package/dist/wooks.cjs.prod.js +2679 -0
  102. package/dist/wooks.d.ts +550 -0
  103. package/dist/wooks.esm-bundler.js +2644 -0
  104. package/index.js +2 -0
  105. package/package.json +86 -0
@@ -0,0 +1,2644 @@
1
+ import { escapeRegex, safeDecodeURIComponent, ProstoRouter } from '@prostojs/router';
2
+ import http, { IncomingMessage, ServerResponse } from 'http';
3
+ import { randomUUID } from 'crypto';
4
+ import { Readable } from 'stream';
5
+ import { createReadStream, promises } from 'fs';
6
+ import path from 'path';
7
+ import { URLSearchParams } from 'url';
8
+ import { Socket } from 'net';
9
+
10
+ const banner = () => `[wooks][${new Date().toISOString().replace('T', ' ').replace(/\.\d{3}z$/i, '')}] `;
11
+
12
+ function panic(error) {
13
+ console.error('' + '' + banner() + error + '');
14
+ return new Error(error);
15
+ }
16
+
17
+ let currentHttpContext = null;
18
+ function useCurrentWooksContext() {
19
+ if (!currentHttpContext) {
20
+ throw panic('Use HTTP hooks only synchronously within the runtime of the request.');
21
+ }
22
+ const cc = currentHttpContext;
23
+ return {
24
+ getCtx: () => cc,
25
+ restoreCtx: () => setCurrentWooksContext(cc.req, cc.res, cc.params, cc.customContext),
26
+ };
27
+ }
28
+ function clearCurrentWooksContext() {
29
+ currentHttpContext = null;
30
+ }
31
+ function setCurrentWooksContext(req, res, params, customContext) {
32
+ currentHttpContext = { req, res, params, customContext };
33
+ }
34
+ const innerCacheSymbols = {
35
+ searchParams: Symbol('searchParams'),
36
+ cookies: Symbol('cookies'),
37
+ accept: Symbol('accept'),
38
+ authorization: Symbol('authorization'),
39
+ setHeader: Symbol('setHeader'),
40
+ setCookies: Symbol('setCookies'),
41
+ status: Symbol('status'),
42
+ response: Symbol('response'),
43
+ request: Symbol('request'),
44
+ };
45
+ function useCacheObject(name) {
46
+ const cc = useCurrentWooksContext().getCtx().customContext;
47
+ const cache = cc[name] = (cc[name] || {});
48
+ return cache;
49
+ }
50
+ function clearCacheObject(name) {
51
+ const cc = useCurrentWooksContext().getCtx().customContext;
52
+ const o = cc[name];
53
+ switch (typeof o) {
54
+ case 'object':
55
+ if (Array.isArray(o)) {
56
+ o.splice(0, o.length);
57
+ }
58
+ else {
59
+ for (const key in o) {
60
+ delete o[key];
61
+ }
62
+ }
63
+ break;
64
+ case 'string':
65
+ cc[name] = '';
66
+ break;
67
+ default: cc[name] = {};
68
+ }
69
+ }
70
+
71
+ function createServer(opts, cb, hostname, onListen) {
72
+ const server = http.createServer(cb);
73
+ if (hostname) {
74
+ server.listen(opts.port, hostname, onListen);
75
+ }
76
+ else {
77
+ server.listen(opts.port, onListen);
78
+ }
79
+ return server;
80
+ }
81
+
82
+ const contentTypes = {
83
+ application: {
84
+ atomXml: 'application/atom+xml',
85
+ ediX12: 'application/EDI-X12',
86
+ edifact: 'application/EDIFACT',
87
+ json: 'application/json',
88
+ javascript: 'application/javascript',
89
+ octetStream: 'application/octet-stream',
90
+ ogg: 'application/ogg',
91
+ pdf: 'application/pdf',
92
+ postscript: 'application/postscript',
93
+ soapXml: 'application/soap+xml',
94
+ fontWoff: 'application/font-woff',
95
+ xhtmlXml: 'application/xhtml+xml',
96
+ xmlDtd: 'application/xml-dtd',
97
+ xopXml: 'application/xop+xml',
98
+ zip: 'application/zip',
99
+ gzip: 'application/gzip',
100
+ xBittorrent: 'application/x-bittorrent',
101
+ xTex: 'application/x-tex',
102
+ xml: 'application/xml',
103
+ msword: 'application/msword',
104
+ xWwwFormUrlencoded: 'application/x-www-form-urlencoded',
105
+ xDvi: 'application/x-dvi',
106
+ xLatex: 'application/x-latex',
107
+ xFontTtf: 'application/x-font-ttf',
108
+ xShockwaveFlash: 'application/x-shockwave-flash',
109
+ xStuffit: 'application/x-stuffit',
110
+ xRarCompressed: 'application/x-rar-compressed',
111
+ xTar: 'application/x-tar',
112
+ xJavascript: 'application/x-javascript',
113
+ },
114
+ audio: {
115
+ basic: 'audio/basic',
116
+ L24: 'audio/L24',
117
+ mp4: 'audio/mp4',
118
+ aac: 'audio/aac',
119
+ mpeg: 'audio/mpeg',
120
+ ogg: 'audio/ogg',
121
+ vorbis: 'audio/vorbis',
122
+ xMsWma: 'audio/x-ms-wma',
123
+ xMsWax: 'audio/x-ms-wax',
124
+ vndRnRealaudio: 'audio/vnd.rn-realaudio',
125
+ vndWave: 'audio/vnd.wave',
126
+ webm: 'audio/webm',
127
+ },
128
+ image: {
129
+ gif: 'image/gif',
130
+ jpeg: 'image/jpeg',
131
+ pjpeg: 'image/pjpeg',
132
+ png: 'image/png',
133
+ svgXml: 'image/svg+xml',
134
+ tiff: 'image/tiff',
135
+ vndMicrosoftIcon: 'image/vnd.microsoft.icon',
136
+ vndWapWbmp: 'image/vnd.wap.wbmp',
137
+ webp: 'image/webp',
138
+ },
139
+ message: {
140
+ http: 'message/http',
141
+ imdnXml: 'message/imdn+xml',
142
+ partial: 'message/partial',
143
+ rfc822: 'message/rfc822',
144
+ },
145
+ model: {
146
+ example: 'model/example',
147
+ iges: 'model/iges',
148
+ mesh: 'model/mesh',
149
+ vrml: 'model/vrml',
150
+ x3dBinary: 'model/x3d+binary',
151
+ x3dVrml: 'model/x3d+vrml',
152
+ x3dXml: 'model/x3d+xml',
153
+ },
154
+ text: {
155
+ cmd: 'text/cmd',
156
+ css: 'text/css',
157
+ csv: 'text/csv',
158
+ html: 'text/html',
159
+ plain: 'text/plain',
160
+ php: 'text/php',
161
+ xml: 'text/xml',
162
+ markdown: 'text/markdown',
163
+ cacheManifest: 'text/cache-manifest',
164
+ },
165
+ video: {
166
+ mpeg: 'video/mpeg',
167
+ mp4: 'video/mp4',
168
+ ogg: 'video/ogg',
169
+ quicktime: 'video/quicktime',
170
+ webm: 'video/webm',
171
+ xMsWmv: 'video/x-ms-wmv',
172
+ xFlv: 'video/x-flv',
173
+ xMsvideo: 'video/x-msvideo',
174
+ threeGpp: 'video/3gpp',
175
+ threeGpp2: 'video/3gpp2',
176
+ },
177
+ };
178
+
179
+ class BaseWooksResponseRenderer {
180
+ render(response) {
181
+ if (typeof response.body === 'string' || typeof response.body === 'boolean' || typeof response.body === 'number') {
182
+ if (!response.getContentType())
183
+ response.setContentType(contentTypes.text.plain);
184
+ return response.body.toString();
185
+ }
186
+ if (typeof response.body === 'undefined') {
187
+ return '';
188
+ }
189
+ if (typeof response.body === 'object') {
190
+ if (!response.getContentType())
191
+ response.setContentType(contentTypes.application.json);
192
+ return JSON.stringify(response.body);
193
+ }
194
+ throw panic('Unsupported body format "' + typeof response.body + '"');
195
+ }
196
+ }
197
+
198
+ const xForwardedFor = 'x-forwarded-for';
199
+ function useRequest() {
200
+ const reqCache = useCacheObject(innerCacheSymbols.request);
201
+ const { req, customContext } = useCurrentWooksContext().getCtx();
202
+ async function rawBody() {
203
+ if (typeof reqCache.rawBody === 'undefined') {
204
+ reqCache.rawBody = new Promise((resolve, reject) => {
205
+ let body = Buffer.from('');
206
+ req.on('data', function (chunk) {
207
+ body = Buffer.concat([body, chunk]);
208
+ });
209
+ req.on('error', function (err) {
210
+ reject(err);
211
+ });
212
+ req.on('end', function () {
213
+ resolve(body);
214
+ });
215
+ });
216
+ }
217
+ return reqCache.rawBody;
218
+ }
219
+ function reqId() {
220
+ if (!reqCache.reqId) {
221
+ reqCache.reqId = randomUUID();
222
+ }
223
+ return reqCache.reqId;
224
+ }
225
+ function getIp(options) {
226
+ var _a, _b, _c;
227
+ if (options === null || options === void 0 ? void 0 : options.trustProxy) {
228
+ if (typeof reqCache.forwardedIp !== 'string') {
229
+ if (typeof req.headers[xForwardedFor] === 'string' && req.headers[xForwardedFor]) {
230
+ reqCache.forwardedIp = (_a = req.headers[xForwardedFor].split(',').shift()) === null || _a === void 0 ? void 0 : _a.trim();
231
+ }
232
+ else {
233
+ return getIp();
234
+ }
235
+ }
236
+ return reqCache.forwardedIp || '';
237
+ }
238
+ else {
239
+ if (typeof reqCache.remoteIp !== 'string') {
240
+ reqCache.remoteIp = ((_b = req.socket) === null || _b === void 0 ? void 0 : _b.remoteAddress) || ((_c = req.connection) === null || _c === void 0 ? void 0 : _c.remoteAddress) || '';
241
+ }
242
+ return reqCache.remoteIp;
243
+ }
244
+ }
245
+ function getIpList() {
246
+ var _a, _b;
247
+ if (!reqCache.ipList) {
248
+ reqCache.ipList = {
249
+ remoteIp: ((_a = req.socket) === null || _a === void 0 ? void 0 : _a.remoteAddress) || ((_b = req.connection) === null || _b === void 0 ? void 0 : _b.remoteAddress) || '',
250
+ forwarded: (req.headers[xForwardedFor] || '').split(',').map(s => s.trim()),
251
+ };
252
+ }
253
+ return reqCache.ipList;
254
+ }
255
+ return {
256
+ rawRequest: req,
257
+ url: req.url,
258
+ method: req.method,
259
+ headers: req.headers,
260
+ rawBody,
261
+ reqId,
262
+ getIp,
263
+ getIpList,
264
+ customContext,
265
+ };
266
+ }
267
+ function useResponse() {
268
+ const cache = useCacheObject(innerCacheSymbols.response);
269
+ const res = useCurrentWooksContext().getCtx().res;
270
+ const statusCache = useCacheObject(innerCacheSymbols.status);
271
+ function status(code) {
272
+ if (code) {
273
+ statusCache.code = code;
274
+ }
275
+ return statusCache.code;
276
+ }
277
+ const rawResponse = (options) => {
278
+ if (!options || !options.passthrough)
279
+ cache.responded = true;
280
+ return res;
281
+ };
282
+ const hasResponded = () => cache.responded;
283
+ return {
284
+ rawResponse,
285
+ hasResponded,
286
+ status,
287
+ };
288
+ }
289
+ function useRouteParams() {
290
+ const routeParams = useCurrentWooksContext().getCtx().params;
291
+ function getRouteParam(name) {
292
+ return routeParams[name];
293
+ }
294
+ return {
295
+ routeParams,
296
+ getRouteParam,
297
+ };
298
+ }
299
+
300
+ function useHeaders() {
301
+ return useRequest().headers;
302
+ }
303
+ function useSetHeaders() {
304
+ const cache = useCacheObject(innerCacheSymbols.setHeader);
305
+ function setHeader(name, value) {
306
+ cache[name] = value.toString();
307
+ }
308
+ function removeHeader(name) {
309
+ delete cache[name];
310
+ }
311
+ function setContentType(value) {
312
+ setHeader('Content-Type', value);
313
+ }
314
+ function enableCors(origin = '*') {
315
+ setHeader('Access-Control-Allow-Origin', origin);
316
+ }
317
+ return {
318
+ setHeader,
319
+ removeHeader,
320
+ setContentType,
321
+ headers: cache,
322
+ enableCors,
323
+ };
324
+ }
325
+
326
+ function useAccept() {
327
+ const { accept } = useHeaders();
328
+ const cache = useCacheObject(innerCacheSymbols.accept);
329
+ const accepts = (mime) => {
330
+ if (typeof cache[mime] !== 'boolean') {
331
+ cache[mime] = !!(accept && (accept === '*/*' || accept.indexOf(mime) >= 0));
332
+ }
333
+ return cache[mime];
334
+ };
335
+ return {
336
+ accept,
337
+ accepts,
338
+ acceptsJson: () => accepts(contentTypes.application.json),
339
+ acceptsXml: () => accepts(contentTypes.application.xml),
340
+ acceptsText: () => accepts(contentTypes.text.plain),
341
+ acceptsHtml: () => accepts(contentTypes.text.html),
342
+ };
343
+ }
344
+
345
+ function useAuthorization() {
346
+ const { authorization } = useHeaders();
347
+ const cache = useCacheObject(innerCacheSymbols.authorization);
348
+ const authType = () => {
349
+ if (authorization) {
350
+ if (typeof cache.type === 'undefined') {
351
+ const space = authorization.indexOf(' ');
352
+ cache.type = authorization.slice(0, space);
353
+ }
354
+ return cache.type;
355
+ }
356
+ return null;
357
+ };
358
+ const authRawCredentials = () => {
359
+ if (authorization) {
360
+ if (typeof cache.credentials === 'undefined') {
361
+ const space = authorization.indexOf(' ');
362
+ cache.credentials = authorization.slice(space + 1);
363
+ }
364
+ return cache.credentials;
365
+ }
366
+ return null;
367
+ };
368
+ return {
369
+ authorization,
370
+ authType,
371
+ authRawCredentials,
372
+ isBasic: () => { var _a; return ((_a = authType()) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase()) === 'basic'; },
373
+ isBearer: () => { var _a; return ((_a = authType()) === null || _a === void 0 ? void 0 : _a.toLocaleLowerCase()) === 'bearer'; },
374
+ basicCredentials: () => {
375
+ if (authorization) {
376
+ if (typeof cache.basicCredentials === 'undefined') {
377
+ const type = authType();
378
+ if ((type === null || type === void 0 ? void 0 : type.toLocaleLowerCase()) === 'basic') {
379
+ const creds = Buffer.from(authRawCredentials() || '', 'base64').toString('ascii');
380
+ const [username, password] = creds.split(':');
381
+ cache.basicCredentials = { username, password };
382
+ }
383
+ }
384
+ return cache.basicCredentials;
385
+ }
386
+ return null;
387
+ },
388
+ };
389
+ }
390
+
391
+ function convertTime(time, unit = 'ms') {
392
+ if (typeof time === 'number')
393
+ return time / units[unit];
394
+ const rg = /(\d+)(\w+)/g;
395
+ let t = 0;
396
+ let r;
397
+ while (r = rg.exec(time)) {
398
+ t += Number(r[1]) * (units[r[2]] || 0);
399
+ }
400
+ return t / units[unit];
401
+ }
402
+ const units = {
403
+ ms: 1,
404
+ s: 1000,
405
+ m: 1000 * 60,
406
+ h: 1000 * 60 * 60,
407
+ d: 1000 * 60 * 60 * 24,
408
+ w: 1000 * 60 * 60 * 24 * 7,
409
+ M: 1000 * 60 * 60 * 24 * 30,
410
+ Y: 1000 * 60 * 60 * 24 * 365,
411
+ };
412
+
413
+ function renderCacheControl(data) {
414
+ let attrs = '';
415
+ for (const [a, v] of Object.entries(data)) {
416
+ if (typeof v === 'undefined')
417
+ continue;
418
+ const func = cacheControlFunc[a];
419
+ if (typeof func === 'function') {
420
+ const val = func(v);
421
+ if (val) {
422
+ attrs += attrs ? ', ' + val : val;
423
+ }
424
+ }
425
+ else {
426
+ panic('Unknown Cache-Control attribute ' + a);
427
+ }
428
+ }
429
+ return attrs;
430
+ }
431
+ const cacheControlFunc = {
432
+ mustRevalidate: (v) => v ? 'must-revalidate' : '',
433
+ noCache: (v) => v ? (typeof v === 'string' ? `no-cache="${v}"` : 'no-cache') : '',
434
+ noStore: (v) => v ? 'no-store' : '',
435
+ noTransform: (v) => v ? 'no-transform' : '',
436
+ public: (v) => v ? 'public' : '',
437
+ private: (v) => v ? (typeof v === 'string' ? `private="${v}"` : 'private') : '',
438
+ proxyRevalidate: (v) => v ? 'proxy-revalidate' : '',
439
+ maxAge: (v) => 'max-age=' + convertTime(v, 's').toString(),
440
+ sMaxage: (v) => 's-maxage=' + convertTime(v, 's').toString(),
441
+ };
442
+
443
+ const renderAge = (v) => convertTime(v, 's').toString();
444
+ const renderExpires = (v) => (typeof v === 'string' || typeof v === 'number' ? new Date(v).toUTCString() : v.toUTCString());
445
+ const renderPragmaNoCache = (v) => v ? 'no-cache' : '';
446
+ function useSetCacheControl() {
447
+ const { setHeader } = useSetHeaders();
448
+ const setAge = (value) => {
449
+ setHeader('Age', renderAge(value));
450
+ };
451
+ const setExpires = (value) => {
452
+ setHeader('Expires', renderExpires(value));
453
+ };
454
+ const setPragmaNoCache = (value = true) => {
455
+ setHeader('Pragma', renderPragmaNoCache(value));
456
+ };
457
+ const setCacheControl = (data) => {
458
+ setHeader('Cache-Control', renderCacheControl(data));
459
+ };
460
+ return {
461
+ setExpires,
462
+ setAge,
463
+ setPragmaNoCache,
464
+ setCacheControl,
465
+ };
466
+ }
467
+
468
+ function renderCookie(key, data) {
469
+ let attrs = '';
470
+ for (const [a, v] of Object.entries(data.attrs)) {
471
+ const func = cookieAttrFunc[a];
472
+ if (typeof func === 'function') {
473
+ const val = func(v);
474
+ attrs += val ? '; ' + val : '';
475
+ }
476
+ else {
477
+ panic('Unknown Set-Cookie attribute ' + a);
478
+ }
479
+ }
480
+ return `${key}=${encodeURIComponent(data.value)}${attrs}`;
481
+ }
482
+ const cookieAttrFunc = {
483
+ expires: (v) => 'Expires=' + (typeof v === 'string' || typeof v === 'number' ? new Date(v).toUTCString() : v.toUTCString()),
484
+ maxAge: (v) => 'Max-Age=' + convertTime(v, 's').toString(),
485
+ domain: (v) => 'Domain=' + v,
486
+ path: (v) => 'Path=' + v,
487
+ secure: (v) => v ? 'Secure' : '',
488
+ httpOnly: (v) => v ? 'HttpOnly' : '',
489
+ sameSite: (v) => v ? 'SameSite=' + (typeof v === 'string' ? v : 'Strict') : '',
490
+ };
491
+
492
+ function useCookies() {
493
+ const cache = useCacheObject(innerCacheSymbols.cookies);
494
+ const { cookie } = useHeaders();
495
+ function getCookie(name) {
496
+ if (typeof cache[name] === 'undefined') {
497
+ if (cookie) {
498
+ const result = new RegExp(`(?:^|; )${escapeRegex(name)}=(.*?)(?:;?$|; )`, 'i').exec(cookie);
499
+ cache[name] = result && result[1] ? safeDecodeURIComponent(result[1]) : null;
500
+ }
501
+ else {
502
+ cache[name] = null;
503
+ }
504
+ }
505
+ return cache[name];
506
+ }
507
+ return {
508
+ rawCookies: cookie,
509
+ getCookie,
510
+ };
511
+ }
512
+ function useSetCookies() {
513
+ const cache = useCacheObject(innerCacheSymbols.setCookies);
514
+ function setCookie(name, value, attrs) {
515
+ cache[name] = {
516
+ value,
517
+ attrs: attrs || {},
518
+ };
519
+ }
520
+ function cookies() {
521
+ return Object.entries(cache).map(([key, value]) => renderCookie(key, value));
522
+ }
523
+ function removeCookie(name) {
524
+ delete cache[name];
525
+ }
526
+ function clearCookies() {
527
+ clearCacheObject(innerCacheSymbols.setCookies);
528
+ }
529
+ return {
530
+ setCookie,
531
+ removeCookie,
532
+ clearCookies,
533
+ cookies,
534
+ };
535
+ }
536
+
537
+ class ProstoURLSearchParams extends URLSearchParams {
538
+ toJson() {
539
+ const json = {};
540
+ for (const [key, value] of this.entries()) {
541
+ if (isArrayParam(key)) {
542
+ const a = json[key] = (json[key] || []);
543
+ a.push(value);
544
+ }
545
+ else {
546
+ json[key] = value;
547
+ }
548
+ }
549
+ return json;
550
+ }
551
+ }
552
+ function isArrayParam(name) {
553
+ return name.endsWith('[]');
554
+ }
555
+
556
+ function useSearchParams() {
557
+ const url = useRequest().url || '';
558
+ const cache = useCacheObject(innerCacheSymbols.searchParams);
559
+ function rawSearchParams() {
560
+ if (typeof cache.raw === 'undefined') {
561
+ const i = url.indexOf('?');
562
+ cache.raw = i >= 0 ? url.slice(i) : '';
563
+ }
564
+ return cache.raw;
565
+ }
566
+ function urlSearchParams() {
567
+ if (!cache.urlSearchParams) {
568
+ cache.urlSearchParams = new ProstoURLSearchParams(rawSearchParams());
569
+ }
570
+ return cache.urlSearchParams;
571
+ }
572
+ return {
573
+ rawSearchParams,
574
+ urlSearchParams,
575
+ jsonSearchParams: () => urlSearchParams().toJson(),
576
+ };
577
+ }
578
+
579
+ const compressors = {
580
+ identity: {
581
+ compress: v => v,
582
+ uncompress: v => v,
583
+ },
584
+ };
585
+ async function uncompressBody(encodings, body) {
586
+ let newBody = body;
587
+ for (const e of encodings.reverse()) {
588
+ if (!compressors[e]) {
589
+ throw panic(`Usupported compression type "${e}".`);
590
+ }
591
+ newBody = await compressors[e].uncompress(body);
592
+ }
593
+ return newBody;
594
+ }
595
+
596
+ function useBody() {
597
+ const cache = useCacheObject(innerCacheSymbols.request);
598
+ const { rawBody } = useRequest();
599
+ const { 'content-type': contentType, 'content-encoding': contentEncoding } = useHeaders();
600
+ function contentIs(type) {
601
+ return (contentType || '').indexOf(type) >= 0;
602
+ }
603
+ function isJson() {
604
+ if (typeof cache.isJson === 'undefined') {
605
+ cache.isJson = contentIs(contentTypes.application.json);
606
+ }
607
+ return cache.isJson;
608
+ }
609
+ function isHtml() {
610
+ if (typeof cache.isHtml === 'undefined') {
611
+ cache.isHtml = contentIs(contentTypes.text.html);
612
+ }
613
+ return cache.isHtml;
614
+ }
615
+ function isXml() {
616
+ if (typeof cache.isXml === 'undefined') {
617
+ cache.isXml = contentIs(contentTypes.text.xml);
618
+ }
619
+ return cache.isXml;
620
+ }
621
+ function isText() {
622
+ if (typeof cache.isText === 'undefined') {
623
+ cache.isText = contentIs(contentTypes.text.plain);
624
+ }
625
+ return cache.isText;
626
+ }
627
+ function isBinary() {
628
+ if (typeof cache.isBinary === 'undefined') {
629
+ cache.isBinary = contentIs(contentTypes.application.octetStream);
630
+ }
631
+ return cache.isBinary;
632
+ }
633
+ function isFormData() {
634
+ if (typeof cache.isFormData === 'undefined') {
635
+ cache.isFormData = contentIs('multipart/form-data');
636
+ }
637
+ return cache.isFormData;
638
+ }
639
+ function isUrlencoded() {
640
+ if (typeof cache.isUrlencoded === 'undefined') {
641
+ cache.isUrlencoded = contentIs(contentTypes.application.xWwwFormUrlencoded);
642
+ }
643
+ return cache.isUrlencoded;
644
+ }
645
+ function isCompressed() {
646
+ if (typeof cache.isCompressed === 'undefined') {
647
+ const parts = contentEncodings();
648
+ for (const p of parts) {
649
+ cache.isCompressed = ['deflate', 'gzip', 'br'].includes(p);
650
+ if (cache.isCompressed)
651
+ break;
652
+ }
653
+ }
654
+ return cache.isCompressed;
655
+ }
656
+ function contentEncodings() {
657
+ if (typeof cache.contentEncodings === 'undefined') {
658
+ cache.contentEncodings = (contentEncoding || '').split(',').map(p => p.trim()).filter(p => !!p);
659
+ }
660
+ return cache.contentEncodings;
661
+ }
662
+ async function parseBody() {
663
+ if (typeof cache.parsed === 'undefined') {
664
+ const body = await uncompressBody(contentEncodings(), (await rawBody()).toString());
665
+ if (isJson()) {
666
+ cache.parsed = jsonParser(body);
667
+ }
668
+ else if (isFormData()) {
669
+ cache.parsed = formDataParser(body);
670
+ }
671
+ else if (isUrlencoded()) {
672
+ cache.parsed = urlEncodedParser(body);
673
+ }
674
+ else if (isBinary()) {
675
+ cache.parsed = textParser(body);
676
+ }
677
+ else {
678
+ cache.parsed = textParser(body);
679
+ }
680
+ }
681
+ return cache.parsed;
682
+ }
683
+ function jsonParser(v) {
684
+ try {
685
+ return JSON.parse(v);
686
+ }
687
+ catch (e) {
688
+ throw new WooksError(400, e.message);
689
+ }
690
+ }
691
+ function textParser(v) {
692
+ return v;
693
+ }
694
+ function formDataParser(v) {
695
+ const boundary = '--' + (/boundary=([^;]+)(?:;|$)/.exec(contentType || '') || [, ''])[1];
696
+ if (!boundary)
697
+ throw new WooksError(EHttpStatusCode.BadRequest, 'form-data boundary not recognized');
698
+ const parts = v.trim().split(boundary);
699
+ const result = {};
700
+ let key = '';
701
+ let partContentType = 'text/plain';
702
+ for (const part of parts) {
703
+ parsePart();
704
+ key = '';
705
+ partContentType = 'text/plain';
706
+ let valueMode = false;
707
+ const lines = part.trim().split(/\n/g).map(s => s.trim());
708
+ for (const line of lines) {
709
+ if (valueMode) {
710
+ if (!result[key]) {
711
+ result[key] = line;
712
+ }
713
+ else {
714
+ result[key] += '\n' + line;
715
+ }
716
+ }
717
+ else {
718
+ if (!line || line === '--') {
719
+ valueMode = !!key;
720
+ if (valueMode) {
721
+ key = key.replace(/^["']/, '').replace(/["']$/, '');
722
+ }
723
+ continue;
724
+ }
725
+ if (line.toLowerCase().startsWith('content-disposition: form-data;')) {
726
+ key = (/name=([^;]+)/.exec(line) || [])[1];
727
+ if (!key)
728
+ throw new WooksError(EHttpStatusCode.BadRequest, 'Could not read multipart name: ' + line);
729
+ continue;
730
+ }
731
+ if (line.toLowerCase().startsWith('content-type:')) {
732
+ partContentType = (/content-type:\s?([^;]+)/i.exec(line) || [])[1];
733
+ if (!partContentType)
734
+ throw new WooksError(EHttpStatusCode.BadRequest, 'Could not read content-type: ' + line);
735
+ continue;
736
+ }
737
+ }
738
+ }
739
+ }
740
+ parsePart();
741
+ function parsePart() {
742
+ if (key) {
743
+ if (partContentType.indexOf(contentTypes.application.json) >= 0) {
744
+ result[key] = JSON.parse(result[key]);
745
+ }
746
+ }
747
+ }
748
+ return result;
749
+ }
750
+ function urlEncodedParser(v) {
751
+ return new ProstoURLSearchParams(v.trim()).toJson();
752
+ }
753
+ return {
754
+ isJson,
755
+ isHtml,
756
+ isXml,
757
+ isText,
758
+ isBinary,
759
+ isFormData,
760
+ isUrlencoded,
761
+ isCompressed,
762
+ contentEncodings,
763
+ parseBody,
764
+ rawBody,
765
+ };
766
+ }
767
+ function registerBodyCompressor(name, compressor) {
768
+ if (compressors[name]) {
769
+ throw panic(`Body compressor "${name}" already registered.`);
770
+ }
771
+ compressors[name] = compressor;
772
+ }
773
+
774
+ function setTestHttpContext(options) {
775
+ const req = new IncomingMessage(new Socket({}));
776
+ req.method = options.method || 'GET';
777
+ req.headers = options.headers || {};
778
+ req.url = options.url;
779
+ const res = new ServerResponse(req);
780
+ const cache = {};
781
+ if (options.cachedContext) {
782
+ const fromInnerContext = [
783
+ 'cookies',
784
+ 'authorization',
785
+ ];
786
+ for (const key of Object.keys(options.cachedContext)) {
787
+ if (fromInnerContext.includes(key)) {
788
+ cache[innerCacheSymbols[key]] = options.cachedContext[key];
789
+ }
790
+ else if (key === 'body') {
791
+ cache[innerCacheSymbols.request] = cache[innerCacheSymbols.request] || {};
792
+ Object.assign(cache[innerCacheSymbols.request], { parsed: options.cachedContext[key] });
793
+ }
794
+ else if (key === 'rawBody') {
795
+ cache[innerCacheSymbols.request] = cache[innerCacheSymbols.request] || {};
796
+ Object.assign(cache[innerCacheSymbols.request], { rawBody: options.cachedContext[key] });
797
+ }
798
+ else {
799
+ cache[key] = options.cachedContext[key];
800
+ }
801
+ }
802
+ }
803
+ setCurrentWooksContext(req, res, options.params || {}, cache);
804
+ }
805
+
806
+ const httpStatusCodes = {
807
+ [100]: 'Continue',
808
+ [101]: 'Switching protocols',
809
+ [102]: 'Processing',
810
+ [103]: 'Early Hints',
811
+ [200]: 'OK',
812
+ [201]: 'Created',
813
+ [202]: 'Accepted',
814
+ [203]: 'Non-Authoritative Information',
815
+ [204]: 'No Content',
816
+ [205]: 'Reset Content',
817
+ [206]: 'Partial Content',
818
+ [207]: 'Multi-Status',
819
+ [208]: 'Already Reported',
820
+ [226]: 'IM Used',
821
+ [300]: 'Multiple Choices',
822
+ [301]: 'Moved Permanently',
823
+ [302]: 'Found (Previously "Moved Temporarily")',
824
+ [303]: 'See Other',
825
+ [304]: 'Not Modified',
826
+ [305]: 'Use Proxy',
827
+ [306]: 'Switch Proxy',
828
+ [307]: 'Temporary Redirect',
829
+ [308]: 'Permanent Redirect',
830
+ [400]: 'Bad Request',
831
+ [401]: 'Unauthorized',
832
+ [402]: 'Payment Required',
833
+ [403]: 'Forbidden',
834
+ [404]: 'Not Found',
835
+ [405]: 'Method Not Allowed',
836
+ [406]: 'Not Acceptable',
837
+ [407]: 'Proxy Authentication Required',
838
+ [408]: 'Request Timeout',
839
+ [409]: 'Conflict',
840
+ [410]: 'Gone',
841
+ [411]: 'Length Required',
842
+ [412]: 'Precondition Failed',
843
+ [413]: 'Payload Too Large',
844
+ [414]: 'URI Too Long',
845
+ [415]: 'Unsupported Media Type',
846
+ [416]: 'Range Not Satisfiable',
847
+ [417]: 'Expectation Failed',
848
+ [418]: 'I\'m a Teapot',
849
+ [421]: 'Misdirected Request',
850
+ [422]: 'Unprocessable Entity',
851
+ [423]: 'Locked',
852
+ [424]: 'Failed Dependency',
853
+ [425]: 'Too Early',
854
+ [426]: 'Upgrade Required',
855
+ [428]: 'Precondition Required',
856
+ [429]: 'Too Many Requests',
857
+ [431]: 'Request Header Fields Too Large',
858
+ [451]: 'Unavailable For Legal Reasons',
859
+ [500]: 'Internal Server Error',
860
+ [501]: 'Not Implemented',
861
+ [502]: 'Bad Gateway',
862
+ [503]: 'Service Unavailable',
863
+ [504]: 'Gateway Timeout',
864
+ [505]: 'HTTP Version Not Supported',
865
+ [506]: 'Variant Also Negotiates',
866
+ [507]: 'Insufficient Storage',
867
+ [508]: 'Loop Detected',
868
+ [510]: 'Not Extended',
869
+ [511]: 'Network Authentication Required',
870
+ };
871
+ var EHttpStatusCode;
872
+ (function (EHttpStatusCode) {
873
+ EHttpStatusCode[EHttpStatusCode["Continue"] = 100] = "Continue";
874
+ EHttpStatusCode[EHttpStatusCode["SwitchingProtocols"] = 101] = "SwitchingProtocols";
875
+ EHttpStatusCode[EHttpStatusCode["Processing"] = 102] = "Processing";
876
+ EHttpStatusCode[EHttpStatusCode["EarlyHints"] = 103] = "EarlyHints";
877
+ EHttpStatusCode[EHttpStatusCode["OK"] = 200] = "OK";
878
+ EHttpStatusCode[EHttpStatusCode["Created"] = 201] = "Created";
879
+ EHttpStatusCode[EHttpStatusCode["Accepted"] = 202] = "Accepted";
880
+ EHttpStatusCode[EHttpStatusCode["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
881
+ EHttpStatusCode[EHttpStatusCode["NoContent"] = 204] = "NoContent";
882
+ EHttpStatusCode[EHttpStatusCode["ResetContent"] = 205] = "ResetContent";
883
+ EHttpStatusCode[EHttpStatusCode["PartialContent"] = 206] = "PartialContent";
884
+ EHttpStatusCode[EHttpStatusCode["MultiStatus"] = 207] = "MultiStatus";
885
+ EHttpStatusCode[EHttpStatusCode["AlreadyReported"] = 208] = "AlreadyReported";
886
+ EHttpStatusCode[EHttpStatusCode["IMUsed"] = 226] = "IMUsed";
887
+ EHttpStatusCode[EHttpStatusCode["MultipleChoices"] = 300] = "MultipleChoices";
888
+ EHttpStatusCode[EHttpStatusCode["MovedPermanently"] = 301] = "MovedPermanently";
889
+ EHttpStatusCode[EHttpStatusCode["Found"] = 302] = "Found";
890
+ EHttpStatusCode[EHttpStatusCode["SeeOther"] = 303] = "SeeOther";
891
+ EHttpStatusCode[EHttpStatusCode["NotModified"] = 304] = "NotModified";
892
+ EHttpStatusCode[EHttpStatusCode["UseProxy"] = 305] = "UseProxy";
893
+ EHttpStatusCode[EHttpStatusCode["SwitchProxy"] = 306] = "SwitchProxy";
894
+ EHttpStatusCode[EHttpStatusCode["TemporaryRedirect"] = 307] = "TemporaryRedirect";
895
+ EHttpStatusCode[EHttpStatusCode["PermanentRedirect"] = 308] = "PermanentRedirect";
896
+ EHttpStatusCode[EHttpStatusCode["BadRequest"] = 400] = "BadRequest";
897
+ EHttpStatusCode[EHttpStatusCode["Unauthorized"] = 401] = "Unauthorized";
898
+ EHttpStatusCode[EHttpStatusCode["PaymentRequired"] = 402] = "PaymentRequired";
899
+ EHttpStatusCode[EHttpStatusCode["Forbidden"] = 403] = "Forbidden";
900
+ EHttpStatusCode[EHttpStatusCode["NotFound"] = 404] = "NotFound";
901
+ EHttpStatusCode[EHttpStatusCode["MethodNotAllowed"] = 405] = "MethodNotAllowed";
902
+ EHttpStatusCode[EHttpStatusCode["NotAcceptable"] = 406] = "NotAcceptable";
903
+ EHttpStatusCode[EHttpStatusCode["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
904
+ EHttpStatusCode[EHttpStatusCode["RequestTimeout"] = 408] = "RequestTimeout";
905
+ EHttpStatusCode[EHttpStatusCode["Conflict"] = 409] = "Conflict";
906
+ EHttpStatusCode[EHttpStatusCode["Gone"] = 410] = "Gone";
907
+ EHttpStatusCode[EHttpStatusCode["LengthRequired"] = 411] = "LengthRequired";
908
+ EHttpStatusCode[EHttpStatusCode["PreconditionFailed"] = 412] = "PreconditionFailed";
909
+ EHttpStatusCode[EHttpStatusCode["PayloadTooLarge"] = 413] = "PayloadTooLarge";
910
+ EHttpStatusCode[EHttpStatusCode["URITooLong"] = 414] = "URITooLong";
911
+ EHttpStatusCode[EHttpStatusCode["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
912
+ EHttpStatusCode[EHttpStatusCode["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
913
+ EHttpStatusCode[EHttpStatusCode["ExpectationFailed"] = 417] = "ExpectationFailed";
914
+ EHttpStatusCode[EHttpStatusCode["ImATeapot"] = 418] = "ImATeapot";
915
+ EHttpStatusCode[EHttpStatusCode["MisdirectedRequest"] = 421] = "MisdirectedRequest";
916
+ EHttpStatusCode[EHttpStatusCode["UnprocessableEntity"] = 422] = "UnprocessableEntity";
917
+ EHttpStatusCode[EHttpStatusCode["Locked"] = 423] = "Locked";
918
+ EHttpStatusCode[EHttpStatusCode["FailedDependency"] = 424] = "FailedDependency";
919
+ EHttpStatusCode[EHttpStatusCode["TooEarly"] = 425] = "TooEarly";
920
+ EHttpStatusCode[EHttpStatusCode["UpgradeRequired"] = 426] = "UpgradeRequired";
921
+ EHttpStatusCode[EHttpStatusCode["PreconditionRequired"] = 428] = "PreconditionRequired";
922
+ EHttpStatusCode[EHttpStatusCode["TooManyRequests"] = 429] = "TooManyRequests";
923
+ EHttpStatusCode[EHttpStatusCode["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
924
+ EHttpStatusCode[EHttpStatusCode["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
925
+ EHttpStatusCode[EHttpStatusCode["InternalServerError"] = 500] = "InternalServerError";
926
+ EHttpStatusCode[EHttpStatusCode["NotImplemented"] = 501] = "NotImplemented";
927
+ EHttpStatusCode[EHttpStatusCode["BadGateway"] = 502] = "BadGateway";
928
+ EHttpStatusCode[EHttpStatusCode["ServiceUnavailable"] = 503] = "ServiceUnavailable";
929
+ EHttpStatusCode[EHttpStatusCode["GatewayTimeout"] = 504] = "GatewayTimeout";
930
+ EHttpStatusCode[EHttpStatusCode["HTTPVersionNotSupported"] = 505] = "HTTPVersionNotSupported";
931
+ EHttpStatusCode[EHttpStatusCode["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
932
+ EHttpStatusCode[EHttpStatusCode["InsufficientStorage"] = 507] = "InsufficientStorage";
933
+ EHttpStatusCode[EHttpStatusCode["LoopDetected"] = 508] = "LoopDetected";
934
+ EHttpStatusCode[EHttpStatusCode["NotExtended"] = 510] = "NotExtended";
935
+ EHttpStatusCode[EHttpStatusCode["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
936
+ })(EHttpStatusCode || (EHttpStatusCode = {}));
937
+
938
+ const defaultStatus = {
939
+ GET: EHttpStatusCode.OK,
940
+ POST: EHttpStatusCode.Created,
941
+ PUT: EHttpStatusCode.Created,
942
+ PATCH: EHttpStatusCode.Accepted,
943
+ DELETE: EHttpStatusCode.Accepted,
944
+ };
945
+ const baseRenderer = new BaseWooksResponseRenderer();
946
+ class BaseWooksResponse {
947
+ constructor(renderer = baseRenderer) {
948
+ this.renderer = renderer;
949
+ this._status = 0;
950
+ this._headers = {};
951
+ }
952
+ get status() {
953
+ return this._status;
954
+ }
955
+ set status(value) {
956
+ this._status = value;
957
+ }
958
+ get body() {
959
+ return this._body;
960
+ }
961
+ set body(value) {
962
+ this._body = value;
963
+ }
964
+ setStatus(value) {
965
+ this.status = value;
966
+ return this;
967
+ }
968
+ setBody(value) {
969
+ this.body = value;
970
+ return this;
971
+ }
972
+ getContentType() {
973
+ return this._headers['Content-Type'];
974
+ }
975
+ setContentType(value) {
976
+ this._headers['Content-Type'] = value;
977
+ return this;
978
+ }
979
+ enableCors(origin = '*') {
980
+ this._headers['Access-Control-Allow-Origin'] = origin;
981
+ return this;
982
+ }
983
+ setCookie(name, value, attrs) {
984
+ const cookies = this._headers['Set-Cookie'] = (this._headers['Set-Cookie'] || []);
985
+ cookies.push(renderCookie(name, { value, attrs: attrs || {} }));
986
+ return this;
987
+ }
988
+ setCacheControl(data) {
989
+ this.setHeader('Cache-Control', renderCacheControl(data));
990
+ }
991
+ setCookieRaw(rawValue) {
992
+ const cookies = this._headers['Set-Cookie'] = (this._headers['Set-Cookie'] || []);
993
+ cookies.push(rawValue);
994
+ return this;
995
+ }
996
+ header(name, value) {
997
+ this._headers[name] = value;
998
+ return this;
999
+ }
1000
+ setHeader(name, value) {
1001
+ return this.header(name, value);
1002
+ }
1003
+ getHeader(name) {
1004
+ return this._headers[name];
1005
+ }
1006
+ mergeHeaders() {
1007
+ const { headers } = useSetHeaders();
1008
+ const { cookies, removeCookie } = useSetCookies();
1009
+ const newCookies = (this._headers['Set-Cookie'] || []);
1010
+ for (const cookie of newCookies) {
1011
+ removeCookie(cookie.slice(0, cookie.indexOf('=')));
1012
+ }
1013
+ this._headers = {
1014
+ ...headers,
1015
+ ...this._headers,
1016
+ };
1017
+ const setCookie = [...newCookies, ...cookies()];
1018
+ if (setCookie && setCookie.length) {
1019
+ this._headers['Set-Cookie'] = setCookie;
1020
+ }
1021
+ return this;
1022
+ }
1023
+ mergeStatus(renderedBody) {
1024
+ this.status = this.status || useResponse().status();
1025
+ if (!this.status) {
1026
+ const { method } = useRequest();
1027
+ this.status = renderedBody ? defaultStatus[method] || EHttpStatusCode.OK : EHttpStatusCode.NoContent;
1028
+ }
1029
+ return this;
1030
+ }
1031
+ respond() {
1032
+ const { rawResponse, hasResponded } = useResponse();
1033
+ const { method, rawRequest } = useRequest();
1034
+ if (hasResponded()) {
1035
+ throw panic('The response was already sent.');
1036
+ }
1037
+ this.mergeHeaders();
1038
+ const res = rawResponse();
1039
+ if (this.body instanceof Readable) {
1040
+ const stream = this.body;
1041
+ this.mergeStatus('ok');
1042
+ res.writeHead(this.status, {
1043
+ ...this._headers,
1044
+ });
1045
+ rawRequest.once('close', () => {
1046
+ stream.destroy();
1047
+ });
1048
+ if (method === 'HEAD') {
1049
+ stream.destroy();
1050
+ res.end();
1051
+ }
1052
+ else {
1053
+ stream.on('error', () => {
1054
+ stream.destroy();
1055
+ res.end();
1056
+ });
1057
+ stream.on('close', () => {
1058
+ stream.destroy();
1059
+ });
1060
+ stream.pipe(res);
1061
+ }
1062
+ }
1063
+ else {
1064
+ const renderedBody = this.renderer.render(this);
1065
+ this.mergeStatus(renderedBody);
1066
+ res.writeHead(this.status, {
1067
+ 'Content-Length': Buffer.byteLength(renderedBody),
1068
+ ...this._headers,
1069
+ }).end(method !== 'HEAD' ? renderedBody : '');
1070
+ }
1071
+ }
1072
+ }
1073
+
1074
+ const preStyles = 'font-family: monospace;'
1075
+ + 'width: 100%;'
1076
+ + 'max-width: 900px;'
1077
+ + 'padding: 10px;'
1078
+ + 'margin: 20px auto;'
1079
+ + 'border-radius: 8px;'
1080
+ + 'background-color: #494949;'
1081
+ + 'box-shadow: 0px 0px 3px 2px rgb(255 255 255 / 20%);';
1082
+ class WooksErrorRenderer extends BaseWooksResponseRenderer {
1083
+ renderHtml(response) {
1084
+ const data = response.body || {};
1085
+ response.setContentType(contentTypes.text.html);
1086
+ const keys = Object.keys(data).filter(key => !['statusCode', 'error', 'message'].includes(key));
1087
+ return '<html style="background-color: #333; color: #bbb;">' +
1088
+ `<head><title>${data.statusCode} ${httpStatusCodes[data.statusCode]}</title></head>` +
1089
+ `<body><center><h1>${data.statusCode} ${httpStatusCodes[data.statusCode]}</h1></center>` +
1090
+ `<center><h4>${data.message}</h1></center><hr color="#666">` +
1091
+ `<center style="color: #666;"> wooks v${"0.0.1-alpha.10"} </center>` +
1092
+ `${keys.length ? `<pre style="${preStyles}">${JSON.stringify({ ...data, statusCode: undefined, message: undefined, error: undefined }, null, ' ')}</pre>` : ''}` +
1093
+ '</body></html>';
1094
+ }
1095
+ renderText(response) {
1096
+ const data = response.body || {};
1097
+ response.setContentType(contentTypes.text.plain);
1098
+ const keys = Object.keys(data).filter(key => !['statusCode', 'error', 'message'].includes(key));
1099
+ return `${data.statusCode} ${httpStatusCodes[data.statusCode]}\n${data.message}`
1100
+ + `\n\n${keys.length ? `${JSON.stringify({ ...data, statusCode: undefined, message: undefined, error: undefined }, null, ' ')}` : ''}`;
1101
+ }
1102
+ renderJson(response) {
1103
+ const data = response.body || {};
1104
+ response.setContentType(contentTypes.application.json);
1105
+ const keys = Object.keys(data).filter(key => !['statusCode', 'error', 'message'].includes(key));
1106
+ return `{"statusCode":${escapeQuotes(data.statusCode)},`
1107
+ + `"error":"${escapeQuotes(data.error)}",`
1108
+ + `"message":"${escapeQuotes(data.message)}"`
1109
+ + `${keys.length ? (',' + keys.map(k => `"${escapeQuotes(k)}":${JSON.stringify(data[k])}`).join(',')) : ''}}`;
1110
+ }
1111
+ render(response) {
1112
+ var _a;
1113
+ const { acceptsJson, acceptsText, acceptsHtml } = useAccept();
1114
+ response.status = ((_a = response.body) === null || _a === void 0 ? void 0 : _a.statusCode) || 500;
1115
+ if (acceptsJson()) {
1116
+ return this.renderJson(response);
1117
+ }
1118
+ else if (acceptsHtml()) {
1119
+ return this.renderHtml(response);
1120
+ }
1121
+ else if (acceptsText()) {
1122
+ return this.renderText(response);
1123
+ }
1124
+ else {
1125
+ return this.renderJson(response);
1126
+ }
1127
+ }
1128
+ }
1129
+ function escapeQuotes(s) {
1130
+ return (typeof s === 'number' ? s : (s || '')).toString().replace(/[\""]/g, '\\"');
1131
+ }
1132
+
1133
+ class WooksError extends Error {
1134
+ constructor(code = 500, _body = '') {
1135
+ super(typeof _body === 'string' ? _body : _body.message);
1136
+ this.code = code;
1137
+ this._body = _body;
1138
+ }
1139
+ get body() {
1140
+ return typeof this._body === 'string' ? {
1141
+ statusCode: this.code,
1142
+ message: this.message,
1143
+ error: httpStatusCodes[this.code],
1144
+ } : {
1145
+ ...this._body,
1146
+ statusCode: this.code,
1147
+ message: this.message,
1148
+ error: httpStatusCodes[this.code],
1149
+ };
1150
+ }
1151
+ attachRenderer(renderer) {
1152
+ this.renderer = renderer;
1153
+ }
1154
+ getRenderer() {
1155
+ return this.renderer;
1156
+ }
1157
+ }
1158
+
1159
+ function createResponseFrom(data) {
1160
+ const { hasResponded } = useResponse();
1161
+ if (hasResponded())
1162
+ return null;
1163
+ if (data instanceof Error) {
1164
+ const r = new BaseWooksResponse(new WooksErrorRenderer());
1165
+ let httpError;
1166
+ if (data instanceof WooksError) {
1167
+ httpError = data;
1168
+ }
1169
+ else {
1170
+ httpError = new WooksError(500, data.message);
1171
+ }
1172
+ r.setBody(httpError.body);
1173
+ return r;
1174
+ }
1175
+ else if (data instanceof BaseWooksResponse) {
1176
+ return data;
1177
+ }
1178
+ else {
1179
+ return new BaseWooksResponse().setBody(data);
1180
+ }
1181
+ }
1182
+
1183
+ class Wooks {
1184
+ constructor(options) {
1185
+ this.options = options;
1186
+ this.router = new ProstoRouter();
1187
+ this._uncoughtExceptionHandler = ((err) => {
1188
+ this.printError('Uncought exception: ', err);
1189
+ }).bind(this);
1190
+ }
1191
+ listen(port, hostname, cb) {
1192
+ return new Promise((resolve, reject) => {
1193
+ var _a;
1194
+ const myCb = () => {
1195
+ var _a;
1196
+ const fn = typeof hostname === 'function' ? hostname : cb;
1197
+ process.on('uncaughtException', this._uncoughtExceptionHandler);
1198
+ if (fn) {
1199
+ fn();
1200
+ }
1201
+ (_a = this.server) === null || _a === void 0 ? void 0 : _a.off('error', reject);
1202
+ resolve();
1203
+ };
1204
+ try {
1205
+ this.server = createServer({
1206
+ port,
1207
+ }, this.processRequest.bind(this), typeof hostname === 'string' ? hostname : '', myCb);
1208
+ (_a = this.server) === null || _a === void 0 ? void 0 : _a.on('error', reject);
1209
+ }
1210
+ catch (e) {
1211
+ reject(e);
1212
+ }
1213
+ });
1214
+ }
1215
+ close() {
1216
+ return new Promise((resolve, reject) => {
1217
+ var _a;
1218
+ (_a = this.server) === null || _a === void 0 ? void 0 : _a.close((err) => {
1219
+ if (err)
1220
+ return reject(err);
1221
+ process.off('uncaughtException', this._uncoughtExceptionHandler);
1222
+ resolve(this.server);
1223
+ });
1224
+ });
1225
+ }
1226
+ processRequest(req, res) {
1227
+ var _a;
1228
+ const found = this.router.lookup(req.method, req.url);
1229
+ const ctx = {
1230
+ __setHeader: {
1231
+ Server: 'wooks v' + "0.0.1-alpha.10",
1232
+ },
1233
+ };
1234
+ if (found) {
1235
+ const params = found.ctx.params;
1236
+ setCurrentWooksContext(req, res, params, ctx);
1237
+ const { restoreCtx } = useCurrentWooksContext();
1238
+ this.processHandlers(req, res, found)
1239
+ .catch((e) => {
1240
+ var _a;
1241
+ this.printError('Internal error, please report: ', e);
1242
+ restoreCtx();
1243
+ (_a = createResponseFrom(e)) === null || _a === void 0 ? void 0 : _a.respond();
1244
+ clearCurrentWooksContext();
1245
+ console.error('' + '' + banner(), e, '');
1246
+ });
1247
+ }
1248
+ else {
1249
+ setCurrentWooksContext(req, res, {}, ctx);
1250
+ (_a = createResponseFrom(new WooksError(404))) === null || _a === void 0 ? void 0 : _a.respond();
1251
+ clearCurrentWooksContext();
1252
+ }
1253
+ }
1254
+ async processHandlers(req, res, found) {
1255
+ var _a, _b;
1256
+ const { restoreCtx } = useCurrentWooksContext();
1257
+ for (const [i, handler] of found.route.handlers.entries()) {
1258
+ const last = found.route.handlers.length === i + 1;
1259
+ try {
1260
+ restoreCtx();
1261
+ const promise = handler();
1262
+ clearCurrentWooksContext();
1263
+ const result = await promise;
1264
+ restoreCtx();
1265
+ (_a = createResponseFrom(result)) === null || _a === void 0 ? void 0 : _a.respond();
1266
+ clearCurrentWooksContext();
1267
+ break;
1268
+ }
1269
+ catch (e) {
1270
+ this.printError('Uncought route handler exception: ' + (req.url || '') + '\n', e);
1271
+ if (last) {
1272
+ restoreCtx();
1273
+ (_b = createResponseFrom(e)) === null || _b === void 0 ? void 0 : _b.respond();
1274
+ clearCurrentWooksContext();
1275
+ }
1276
+ }
1277
+ }
1278
+ }
1279
+ printError(expl, e) {
1280
+ if (!(e instanceof WooksError)) {
1281
+ panic(expl + e.message);
1282
+ console.error('' + (e.stack || '') + '');
1283
+ }
1284
+ }
1285
+ get(path, handler) {
1286
+ this.router.on('HEAD', path, handler);
1287
+ return this.router.on('GET', path, handler);
1288
+ }
1289
+ post(path, handler) {
1290
+ return this.router.on('POST', path, handler);
1291
+ }
1292
+ put(path, handler) {
1293
+ return this.router.on('PUT', path, handler);
1294
+ }
1295
+ delete(path, handler) {
1296
+ return this.router.on('DELETE', path, handler);
1297
+ }
1298
+ patch(path, handler) {
1299
+ return this.router.on('PATCH', path, handler);
1300
+ }
1301
+ on(method, path, handler) {
1302
+ return this.router.on(method, path, handler);
1303
+ }
1304
+ }
1305
+
1306
+ const extensions = {
1307
+ '123': 'application/vnd.lotus-1-2-3',
1308
+ 'ez': 'application/andrew-inset',
1309
+ 'aw': 'application/applixware',
1310
+ 'atom': 'application/atom+xml',
1311
+ 'atomcat': 'application/atomcat+xml',
1312
+ 'atomdeleted': 'application/atomdeleted+xml',
1313
+ 'atomsvc': 'application/atomsvc+xml',
1314
+ 'dwd': 'application/atsc-dwd+xml',
1315
+ 'held': 'application/atsc-held+xml',
1316
+ 'rsat': 'application/atsc-rsat+xml',
1317
+ 'bdoc': 'application/x-bdoc',
1318
+ 'xcs': 'application/calendar+xml',
1319
+ 'ccxml': 'application/ccxml+xml',
1320
+ 'cdfx': 'application/cdfx+xml',
1321
+ 'cdmia': 'application/cdmi-capability',
1322
+ 'cdmic': 'application/cdmi-container',
1323
+ 'cdmid': 'application/cdmi-domain',
1324
+ 'cdmio': 'application/cdmi-object',
1325
+ 'cdmiq': 'application/cdmi-queue',
1326
+ 'cpl': 'application/cpl+xml',
1327
+ 'cu': 'application/cu-seeme',
1328
+ 'cwl': 'application/cwl',
1329
+ 'mpd': 'application/dash+xml',
1330
+ 'mpp': 'application/vnd.ms-project',
1331
+ 'davmount': 'application/davmount+xml',
1332
+ 'dbk': 'application/docbook+xml',
1333
+ 'dssc': 'application/dssc+der',
1334
+ 'xdssc': 'application/dssc+xml',
1335
+ 'ecma': 'application/ecmascript',
1336
+ 'emma': 'application/emma+xml',
1337
+ 'emotionml': 'application/emotionml+xml',
1338
+ 'epub': 'application/epub+zip',
1339
+ 'exi': 'application/exi',
1340
+ 'exp': 'application/express',
1341
+ 'fdf': 'application/vnd.fdf',
1342
+ 'fdt': 'application/fdt+xml',
1343
+ 'pfr': 'application/font-tdpfr',
1344
+ 'geojson': 'application/geo+json',
1345
+ 'gml': 'application/gml+xml',
1346
+ 'gpx': 'application/gpx+xml',
1347
+ 'gxf': 'application/gxf',
1348
+ 'gz': 'application/gzip',
1349
+ 'hjson': 'application/hjson',
1350
+ 'stk': 'application/hyperstudio',
1351
+ 'ink': 'application/inkml+xml',
1352
+ 'inkml': 'application/inkml+xml',
1353
+ 'ipfix': 'application/ipfix',
1354
+ 'its': 'application/its+xml',
1355
+ 'jar': 'application/java-archive',
1356
+ 'war': 'application/java-archive',
1357
+ 'ear': 'application/java-archive',
1358
+ 'ser': 'application/java-serialized-object',
1359
+ 'class': 'application/java-vm',
1360
+ 'js': 'application/javascript',
1361
+ 'mjs': 'application/javascript',
1362
+ 'json': 'application/json',
1363
+ 'map': 'application/json',
1364
+ 'json5': 'application/json5',
1365
+ 'jsonml': 'application/jsonml+json',
1366
+ 'jsonld': 'application/ld+json',
1367
+ 'lgr': 'application/lgr+xml',
1368
+ 'lostxml': 'application/lost+xml',
1369
+ 'hqx': 'application/mac-binhex40',
1370
+ 'cpt': 'application/mac-compactpro',
1371
+ 'mads': 'application/mads+xml',
1372
+ 'webmanifest': 'application/manifest+json',
1373
+ 'mrc': 'application/marc',
1374
+ 'mrcx': 'application/marcxml+xml',
1375
+ 'ma': 'application/mathematica',
1376
+ 'nb': 'application/mathematica',
1377
+ 'mb': 'application/mathematica',
1378
+ 'mathml': 'application/mathml+xml',
1379
+ 'mbox': 'application/mbox',
1380
+ 'mpf': 'application/media-policy-dataset+xml',
1381
+ 'mscml': 'application/mediaservercontrol+xml',
1382
+ 'metalink': 'application/metalink+xml',
1383
+ 'meta4': 'application/metalink4+xml',
1384
+ 'mets': 'application/mets+xml',
1385
+ 'maei': 'application/mmt-aei+xml',
1386
+ 'musd': 'application/mmt-usd+xml',
1387
+ 'mods': 'application/mods+xml',
1388
+ 'm21': 'application/mp21',
1389
+ 'mp21': 'application/mp21',
1390
+ 'mp4s': 'application/mp4',
1391
+ 'm4p': 'application/mp4',
1392
+ 'doc': 'application/msword',
1393
+ 'dot': 'application/msword',
1394
+ 'mxf': 'application/mxf',
1395
+ 'nq': 'application/n-quads',
1396
+ 'nt': 'application/n-triples',
1397
+ 'cjs': 'application/node',
1398
+ 'bin': 'application/octet-stream',
1399
+ 'dms': 'application/octet-stream',
1400
+ 'lrf': 'application/octet-stream',
1401
+ 'mar': 'application/octet-stream',
1402
+ 'so': 'application/octet-stream',
1403
+ 'dist': 'application/octet-stream',
1404
+ 'distz': 'application/octet-stream',
1405
+ 'pkg': 'application/octet-stream',
1406
+ 'bpk': 'application/octet-stream',
1407
+ 'dump': 'application/octet-stream',
1408
+ 'elc': 'application/octet-stream',
1409
+ 'deploy': 'application/octet-stream',
1410
+ 'exe': 'application/x-msdownload',
1411
+ 'dll': 'application/x-msdownload',
1412
+ 'deb': 'application/x-debian-package',
1413
+ 'dmg': 'application/x-apple-diskimage',
1414
+ 'iso': 'application/x-iso9660-image',
1415
+ 'img': 'application/octet-stream',
1416
+ 'msi': 'application/x-msdownload',
1417
+ 'msp': 'application/octet-stream',
1418
+ 'msm': 'application/octet-stream',
1419
+ 'buffer': 'application/octet-stream',
1420
+ 'oda': 'application/oda',
1421
+ 'opf': 'application/oebps-package+xml',
1422
+ 'ogx': 'application/ogg',
1423
+ 'omdoc': 'application/omdoc+xml',
1424
+ 'onetoc': 'application/onenote',
1425
+ 'onetoc2': 'application/onenote',
1426
+ 'onetmp': 'application/onenote',
1427
+ 'onepkg': 'application/onenote',
1428
+ 'oxps': 'application/oxps',
1429
+ 'relo': 'application/p2p-overlay+xml',
1430
+ 'xer': 'application/patch-ops-error+xml',
1431
+ 'pdf': 'application/pdf',
1432
+ 'pgp': 'application/pgp-encrypted',
1433
+ 'asc': 'application/pgp-signature',
1434
+ 'sig': 'application/pgp-signature',
1435
+ 'prf': 'application/pics-rules',
1436
+ 'p10': 'application/pkcs10',
1437
+ 'p7m': 'application/pkcs7-mime',
1438
+ 'p7c': 'application/pkcs7-mime',
1439
+ 'p7s': 'application/pkcs7-signature',
1440
+ 'p8': 'application/pkcs8',
1441
+ 'ac': 'application/vnd.nokia.n-gage.ac+xml',
1442
+ 'cer': 'application/pkix-cert',
1443
+ 'crl': 'application/pkix-crl',
1444
+ 'pkipath': 'application/pkix-pkipath',
1445
+ 'pki': 'application/pkixcmp',
1446
+ 'pls': 'application/pls+xml',
1447
+ 'ai': 'application/postscript',
1448
+ 'eps': 'application/postscript',
1449
+ 'ps': 'application/postscript',
1450
+ 'provx': 'application/provenance+xml',
1451
+ 'cww': 'application/prs.cww',
1452
+ 'pskcxml': 'application/pskc+xml',
1453
+ 'raml': 'application/raml+yaml',
1454
+ 'rdf': 'application/rdf+xml',
1455
+ 'owl': 'application/rdf+xml',
1456
+ 'rif': 'application/reginfo+xml',
1457
+ 'rnc': 'application/relax-ng-compact-syntax',
1458
+ 'rl': 'application/resource-lists+xml',
1459
+ 'rld': 'application/resource-lists-diff+xml',
1460
+ 'rs': 'application/rls-services+xml',
1461
+ 'rapd': 'application/route-apd+xml',
1462
+ 'sls': 'application/route-s-tsid+xml',
1463
+ 'rusd': 'application/route-usd+xml',
1464
+ 'gbr': 'application/rpki-ghostbusters',
1465
+ 'mft': 'application/rpki-manifest',
1466
+ 'roa': 'application/rpki-roa',
1467
+ 'rsd': 'application/rsd+xml',
1468
+ 'rss': 'application/rss+xml',
1469
+ 'rtf': 'text/rtf',
1470
+ 'sbml': 'application/sbml+xml',
1471
+ 'scq': 'application/scvp-cv-request',
1472
+ 'scs': 'application/scvp-cv-response',
1473
+ 'spq': 'application/scvp-vp-request',
1474
+ 'spp': 'application/scvp-vp-response',
1475
+ 'sdp': 'application/sdp',
1476
+ 'senmlx': 'application/senml+xml',
1477
+ 'sensmlx': 'application/sensml+xml',
1478
+ 'setpay': 'application/set-payment-initiation',
1479
+ 'setreg': 'application/set-registration-initiation',
1480
+ 'shf': 'application/shf+xml',
1481
+ 'siv': 'application/sieve',
1482
+ 'sieve': 'application/sieve',
1483
+ 'smi': 'application/smil+xml',
1484
+ 'smil': 'application/smil+xml',
1485
+ 'rq': 'application/sparql-query',
1486
+ 'srx': 'application/sparql-results+xml',
1487
+ 'gram': 'application/srgs',
1488
+ 'grxml': 'application/srgs+xml',
1489
+ 'sru': 'application/sru+xml',
1490
+ 'ssdl': 'application/ssdl+xml',
1491
+ 'ssml': 'application/ssml+xml',
1492
+ 'swidtag': 'application/swid+xml',
1493
+ 'tei': 'application/tei+xml',
1494
+ 'teicorpus': 'application/tei+xml',
1495
+ 'tfi': 'application/thraud+xml',
1496
+ 'tsd': 'application/timestamped-data',
1497
+ 'toml': 'application/toml',
1498
+ 'trig': 'application/trig',
1499
+ 'ttml': 'application/ttml+xml',
1500
+ 'ubj': 'application/ubjson',
1501
+ 'rsheet': 'application/urc-ressheet+xml',
1502
+ 'td': 'application/urc-targetdesc+xml',
1503
+ '1km': 'application/vnd.1000minds.decision-model+xml',
1504
+ 'plb': 'application/vnd.3gpp.pic-bw-large',
1505
+ 'psb': 'application/vnd.3gpp.pic-bw-small',
1506
+ 'pvb': 'application/vnd.3gpp.pic-bw-var',
1507
+ 'tcap': 'application/vnd.3gpp2.tcap',
1508
+ 'pwn': 'application/vnd.3m.post-it-notes',
1509
+ 'aso': 'application/vnd.accpac.simply.aso',
1510
+ 'imp': 'application/vnd.accpac.simply.imp',
1511
+ 'acu': 'application/vnd.acucobol',
1512
+ 'atc': 'application/vnd.acucorp',
1513
+ 'acutc': 'application/vnd.acucorp',
1514
+ 'air': 'application/vnd.adobe.air-application-installer-package+zip',
1515
+ 'fcdt': 'application/vnd.adobe.formscentral.fcdt',
1516
+ 'fxp': 'application/vnd.adobe.fxp',
1517
+ 'fxpl': 'application/vnd.adobe.fxp',
1518
+ 'xdp': 'application/vnd.adobe.xdp+xml',
1519
+ 'xfdf': 'application/xfdf',
1520
+ 'age': 'application/vnd.age',
1521
+ 'ahead': 'application/vnd.ahead.space',
1522
+ 'azf': 'application/vnd.airzip.filesecure.azf',
1523
+ 'azs': 'application/vnd.airzip.filesecure.azs',
1524
+ 'azw': 'application/vnd.amazon.ebook',
1525
+ 'acc': 'application/vnd.americandynamics.acc',
1526
+ 'ami': 'application/vnd.amiga.ami',
1527
+ 'apk': 'application/vnd.android.package-archive',
1528
+ 'cii': 'application/vnd.anser-web-certificate-issue-initiation',
1529
+ 'fti': 'application/vnd.anser-web-funds-transfer-initiation',
1530
+ 'atx': 'application/vnd.antix.game-component',
1531
+ 'mpkg': 'application/vnd.apple.installer+xml',
1532
+ 'key': 'application/x-iwork-keynote-sffkey',
1533
+ 'm3u8': 'application/vnd.apple.mpegurl',
1534
+ 'numbers': 'application/x-iwork-numbers-sffnumbers',
1535
+ 'pages': 'application/x-iwork-pages-sffpages',
1536
+ 'pkpass': 'application/vnd.apple.pkpass',
1537
+ 'swi': 'application/vnd.aristanetworks.swi',
1538
+ 'iota': 'application/vnd.astraea-software.iota',
1539
+ 'aep': 'application/vnd.audiograph',
1540
+ 'bmml': 'application/vnd.balsamiq.bmml+xml',
1541
+ 'mpm': 'application/vnd.blueice.multipass',
1542
+ 'bmi': 'application/vnd.bmi',
1543
+ 'rep': 'application/vnd.businessobjects',
1544
+ 'cdxml': 'application/vnd.chemdraw+xml',
1545
+ 'mmd': 'application/vnd.chipnuts.karaoke-mmd',
1546
+ 'cdy': 'application/vnd.cinderella',
1547
+ 'csl': 'application/vnd.citationstyles.style+xml',
1548
+ 'cla': 'application/vnd.claymore',
1549
+ 'rp9': 'application/vnd.cloanto.rp9',
1550
+ 'c4g': 'application/vnd.clonk.c4group',
1551
+ 'c4d': 'application/vnd.clonk.c4group',
1552
+ 'c4f': 'application/vnd.clonk.c4group',
1553
+ 'c4p': 'application/vnd.clonk.c4group',
1554
+ 'c4u': 'application/vnd.clonk.c4group',
1555
+ 'c11amc': 'application/vnd.cluetrust.cartomobile-config',
1556
+ 'c11amz': 'application/vnd.cluetrust.cartomobile-config-pkg',
1557
+ 'csp': 'application/vnd.commonspace',
1558
+ 'cdbcmsg': 'application/vnd.contact.cmsg',
1559
+ 'cmc': 'application/vnd.cosmocaller',
1560
+ 'clkx': 'application/vnd.crick.clicker',
1561
+ 'clkk': 'application/vnd.crick.clicker.keyboard',
1562
+ 'clkp': 'application/vnd.crick.clicker.palette',
1563
+ 'clkt': 'application/vnd.crick.clicker.template',
1564
+ 'clkw': 'application/vnd.crick.clicker.wordbank',
1565
+ 'wbs': 'application/vnd.criticaltools.wbs+xml',
1566
+ 'pml': 'application/vnd.ctc-posml',
1567
+ 'ppd': 'application/vnd.cups-ppd',
1568
+ 'car': 'application/vnd.curl.car',
1569
+ 'pcurl': 'application/vnd.curl.pcurl',
1570
+ 'dart': 'application/vnd.dart',
1571
+ 'rdz': 'application/vnd.data-vision.rdz',
1572
+ 'dbf': 'application/vnd.dbf',
1573
+ 'uvf': 'application/vnd.dece.data',
1574
+ 'uvvf': 'application/vnd.dece.data',
1575
+ 'uvd': 'application/vnd.dece.data',
1576
+ 'uvvd': 'application/vnd.dece.data',
1577
+ 'uvt': 'application/vnd.dece.ttml+xml',
1578
+ 'uvvt': 'application/vnd.dece.ttml+xml',
1579
+ 'uvx': 'application/vnd.dece.unspecified',
1580
+ 'uvvx': 'application/vnd.dece.unspecified',
1581
+ 'uvz': 'application/vnd.dece.zip',
1582
+ 'uvvz': 'application/vnd.dece.zip',
1583
+ 'fe_launch': 'application/vnd.denovo.fcselayout-link',
1584
+ 'dna': 'application/vnd.dna',
1585
+ 'mlp': 'application/vnd.dolby.mlp',
1586
+ 'dpg': 'application/vnd.dpgraph',
1587
+ 'dfac': 'application/vnd.dreamfactory',
1588
+ 'kpxx': 'application/vnd.ds-keypoint',
1589
+ 'ait': 'application/vnd.dvb.ait',
1590
+ 'svc': 'application/vnd.dvb.service',
1591
+ 'geo': 'application/vnd.dynageo',
1592
+ 'mag': 'application/vnd.ecowin.chart',
1593
+ 'nml': 'application/vnd.enliven',
1594
+ 'esf': 'application/vnd.epson.esf',
1595
+ 'msf': 'application/vnd.epson.msf',
1596
+ 'qam': 'application/vnd.epson.quickanime',
1597
+ 'slt': 'application/vnd.epson.salt',
1598
+ 'ssf': 'application/vnd.epson.ssf',
1599
+ 'es3': 'application/vnd.eszigno3+xml',
1600
+ 'et3': 'application/vnd.eszigno3+xml',
1601
+ 'ez2': 'application/vnd.ezpix-album',
1602
+ 'ez3': 'application/vnd.ezpix-package',
1603
+ 'mseed': 'application/vnd.fdsn.mseed',
1604
+ 'seed': 'application/vnd.fdsn.seed',
1605
+ 'dataless': 'application/vnd.fdsn.seed',
1606
+ 'gph': 'application/vnd.flographit',
1607
+ 'ftc': 'application/vnd.fluxtime.clip',
1608
+ 'fm': 'application/vnd.framemaker',
1609
+ 'frame': 'application/vnd.framemaker',
1610
+ 'maker': 'application/vnd.framemaker',
1611
+ 'book': 'application/vnd.framemaker',
1612
+ 'fnc': 'application/vnd.frogans.fnc',
1613
+ 'ltf': 'application/vnd.frogans.ltf',
1614
+ 'fsc': 'application/vnd.fsc.weblaunch',
1615
+ 'oas': 'application/vnd.fujitsu.oasys',
1616
+ 'oa2': 'application/vnd.fujitsu.oasys2',
1617
+ 'oa3': 'application/vnd.fujitsu.oasys3',
1618
+ 'fg5': 'application/vnd.fujitsu.oasysgp',
1619
+ 'bh2': 'application/vnd.fujitsu.oasysprs',
1620
+ 'ddd': 'application/vnd.fujixerox.ddd',
1621
+ 'xdw': 'application/vnd.fujixerox.docuworks',
1622
+ 'xbd': 'application/vnd.fujixerox.docuworks.binder',
1623
+ 'fzs': 'application/vnd.fuzzysheet',
1624
+ 'txd': 'application/vnd.genomatix.tuxedo',
1625
+ 'ggb': 'application/vnd.geogebra.file',
1626
+ 'ggt': 'application/vnd.geogebra.tool',
1627
+ 'gex': 'application/vnd.geometry-explorer',
1628
+ 'gre': 'application/vnd.geometry-explorer',
1629
+ 'gxt': 'application/vnd.geonext',
1630
+ 'g2w': 'application/vnd.geoplan',
1631
+ 'g3w': 'application/vnd.geospace',
1632
+ 'gmx': 'application/vnd.gmx',
1633
+ 'gdoc': 'application/vnd.google-apps.document',
1634
+ 'gslides': 'application/vnd.google-apps.presentation',
1635
+ 'gsheet': 'application/vnd.google-apps.spreadsheet',
1636
+ 'kml': 'application/vnd.google-earth.kml+xml',
1637
+ 'kmz': 'application/vnd.google-earth.kmz',
1638
+ 'gqf': 'application/vnd.grafeq',
1639
+ 'gqs': 'application/vnd.grafeq',
1640
+ 'gac': 'application/vnd.groove-account',
1641
+ 'ghf': 'application/vnd.groove-help',
1642
+ 'gim': 'application/vnd.groove-identity-message',
1643
+ 'grv': 'application/vnd.groove-injector',
1644
+ 'gtm': 'application/vnd.groove-tool-message',
1645
+ 'tpl': 'application/vnd.groove-tool-template',
1646
+ 'vcg': 'application/vnd.groove-vcard',
1647
+ 'hal': 'application/vnd.hal+xml',
1648
+ 'zmm': 'application/vnd.handheld-entertainment+xml',
1649
+ 'hbci': 'application/vnd.hbci',
1650
+ 'les': 'application/vnd.hhe.lesson-player',
1651
+ 'hpgl': 'application/vnd.hp-hpgl',
1652
+ 'hpid': 'application/vnd.hp-hpid',
1653
+ 'hps': 'application/vnd.hp-hps',
1654
+ 'jlt': 'application/vnd.hp-jlyt',
1655
+ 'pcl': 'application/vnd.hp-pcl',
1656
+ 'pclxl': 'application/vnd.hp-pclxl',
1657
+ 'sfd-hdstx': 'application/vnd.hydrostatix.sof-data',
1658
+ 'mpy': 'application/vnd.ibm.minipay',
1659
+ 'afp': 'application/vnd.ibm.modcap',
1660
+ 'listafp': 'application/vnd.ibm.modcap',
1661
+ 'list3820': 'application/vnd.ibm.modcap',
1662
+ 'irm': 'application/vnd.ibm.rights-management',
1663
+ 'sc': 'application/vnd.ibm.secure-container',
1664
+ 'icc': 'application/vnd.iccprofile',
1665
+ 'icm': 'application/vnd.iccprofile',
1666
+ 'igl': 'application/vnd.igloader',
1667
+ 'ivp': 'application/vnd.immervision-ivp',
1668
+ 'ivu': 'application/vnd.immervision-ivu',
1669
+ 'igm': 'application/vnd.insors.igm',
1670
+ 'xpw': 'application/vnd.intercon.formnet',
1671
+ 'xpx': 'application/vnd.intercon.formnet',
1672
+ 'i2g': 'application/vnd.intergeo',
1673
+ 'qbo': 'application/vnd.intu.qbo',
1674
+ 'qfx': 'application/vnd.intu.qfx',
1675
+ 'rcprofile': 'application/vnd.ipunplugged.rcprofile',
1676
+ 'irp': 'application/vnd.irepository.package+xml',
1677
+ 'xpr': 'application/vnd.is-xpr',
1678
+ 'fcs': 'application/vnd.isac.fcs',
1679
+ 'jam': 'application/vnd.jam',
1680
+ 'rms': 'application/vnd.jcp.javame.midlet-rms',
1681
+ 'jisp': 'application/vnd.jisp',
1682
+ 'joda': 'application/vnd.joost.joda-archive',
1683
+ 'ktz': 'application/vnd.kahootz',
1684
+ 'ktr': 'application/vnd.kahootz',
1685
+ 'karbon': 'application/vnd.kde.karbon',
1686
+ 'chrt': 'application/vnd.kde.kchart',
1687
+ 'kfo': 'application/vnd.kde.kformula',
1688
+ 'flw': 'application/vnd.kde.kivio',
1689
+ 'kon': 'application/vnd.kde.kontour',
1690
+ 'kpr': 'application/vnd.kde.kpresenter',
1691
+ 'kpt': 'application/vnd.kde.kpresenter',
1692
+ 'ksp': 'application/vnd.kde.kspread',
1693
+ 'kwd': 'application/vnd.kde.kword',
1694
+ 'kwt': 'application/vnd.kde.kword',
1695
+ 'htke': 'application/vnd.kenameaapp',
1696
+ 'kia': 'application/vnd.kidspiration',
1697
+ 'kne': 'application/vnd.kinar',
1698
+ 'knp': 'application/vnd.kinar',
1699
+ 'skp': 'application/vnd.koan',
1700
+ 'skd': 'application/vnd.koan',
1701
+ 'skt': 'application/vnd.koan',
1702
+ 'skm': 'application/vnd.koan',
1703
+ 'sse': 'application/vnd.kodak-descriptor',
1704
+ 'lasxml': 'application/vnd.las.las+xml',
1705
+ 'lbd': 'application/vnd.llamagraphics.life-balance.desktop',
1706
+ 'lbe': 'application/vnd.llamagraphics.life-balance.exchange+xml',
1707
+ 'apr': 'application/vnd.lotus-approach',
1708
+ 'pre': 'application/vnd.lotus-freelance',
1709
+ 'nsf': 'application/vnd.lotus-notes',
1710
+ 'org': 'text/x-org',
1711
+ 'scm': 'application/vnd.lotus-screencam',
1712
+ 'lwp': 'application/vnd.lotus-wordpro',
1713
+ 'portpkg': 'application/vnd.macports.portpkg',
1714
+ 'mvt': 'application/vnd.mapbox-vector-tile',
1715
+ 'mcd': 'application/vnd.mcd',
1716
+ 'mc1': 'application/vnd.medcalcdata',
1717
+ 'cdkey': 'application/vnd.mediastation.cdkey',
1718
+ 'mwf': 'application/vnd.mfer',
1719
+ 'mfm': 'application/vnd.mfmp',
1720
+ 'flo': 'application/vnd.micrografx.flo',
1721
+ 'igx': 'application/vnd.micrografx.igx',
1722
+ 'mif': 'application/vnd.mif',
1723
+ 'daf': 'application/vnd.mobius.daf',
1724
+ 'dis': 'application/vnd.mobius.dis',
1725
+ 'mbk': 'application/vnd.mobius.mbk',
1726
+ 'mqy': 'application/vnd.mobius.mqy',
1727
+ 'msl': 'application/vnd.mobius.msl',
1728
+ 'plc': 'application/vnd.mobius.plc',
1729
+ 'txf': 'application/vnd.mobius.txf',
1730
+ 'mpn': 'application/vnd.mophun.application',
1731
+ 'mpc': 'application/vnd.mophun.certificate',
1732
+ 'xul': 'application/vnd.mozilla.xul+xml',
1733
+ 'cil': 'application/vnd.ms-artgalry',
1734
+ 'cab': 'application/vnd.ms-cab-compressed',
1735
+ 'xls': 'application/vnd.ms-excel',
1736
+ 'xlm': 'application/vnd.ms-excel',
1737
+ 'xla': 'application/vnd.ms-excel',
1738
+ 'xlc': 'application/vnd.ms-excel',
1739
+ 'xlt': 'application/vnd.ms-excel',
1740
+ 'xlw': 'application/vnd.ms-excel',
1741
+ 'xlam': 'application/vnd.ms-excel.addin.macroenabled.12',
1742
+ 'xlsb': 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
1743
+ 'xlsm': 'application/vnd.ms-excel.sheet.macroenabled.12',
1744
+ 'xltm': 'application/vnd.ms-excel.template.macroenabled.12',
1745
+ 'eot': 'application/vnd.ms-fontobject',
1746
+ 'chm': 'application/vnd.ms-htmlhelp',
1747
+ 'ims': 'application/vnd.ms-ims',
1748
+ 'lrm': 'application/vnd.ms-lrm',
1749
+ 'thmx': 'application/vnd.ms-officetheme',
1750
+ 'msg': 'application/vnd.ms-outlook',
1751
+ 'cat': 'application/vnd.ms-pki.seccat',
1752
+ 'stl': 'model/stl',
1753
+ 'ppt': 'application/vnd.ms-powerpoint',
1754
+ 'pps': 'application/vnd.ms-powerpoint',
1755
+ 'pot': 'application/vnd.ms-powerpoint',
1756
+ 'ppam': 'application/vnd.ms-powerpoint.addin.macroenabled.12',
1757
+ 'pptm': 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
1758
+ 'sldm': 'application/vnd.ms-powerpoint.slide.macroenabled.12',
1759
+ 'ppsm': 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
1760
+ 'potm': 'application/vnd.ms-powerpoint.template.macroenabled.12',
1761
+ 'mpt': 'application/vnd.ms-project',
1762
+ 'docm': 'application/vnd.ms-word.document.macroenabled.12',
1763
+ 'dotm': 'application/vnd.ms-word.template.macroenabled.12',
1764
+ 'wps': 'application/vnd.ms-works',
1765
+ 'wks': 'application/vnd.ms-works',
1766
+ 'wcm': 'application/vnd.ms-works',
1767
+ 'wdb': 'application/vnd.ms-works',
1768
+ 'wpl': 'application/vnd.ms-wpl',
1769
+ 'xps': 'application/vnd.ms-xpsdocument',
1770
+ 'mseq': 'application/vnd.mseq',
1771
+ 'mus': 'application/vnd.musician',
1772
+ 'msty': 'application/vnd.muvee.style',
1773
+ 'taglet': 'application/vnd.mynfc',
1774
+ 'nlu': 'application/vnd.neurolanguage.nlu',
1775
+ 'ntf': 'application/vnd.nitf',
1776
+ 'nitf': 'application/vnd.nitf',
1777
+ 'nnd': 'application/vnd.noblenet-directory',
1778
+ 'nns': 'application/vnd.noblenet-sealer',
1779
+ 'nnw': 'application/vnd.noblenet-web',
1780
+ 'ngdat': 'application/vnd.nokia.n-gage.data',
1781
+ 'n-gage': 'application/vnd.nokia.n-gage.symbian.install',
1782
+ 'rpst': 'application/vnd.nokia.radio-preset',
1783
+ 'rpss': 'application/vnd.nokia.radio-presets',
1784
+ 'edm': 'application/vnd.novadigm.edm',
1785
+ 'edx': 'application/vnd.novadigm.edx',
1786
+ 'ext': 'application/vnd.novadigm.ext',
1787
+ 'odc': 'application/vnd.oasis.opendocument.chart',
1788
+ 'otc': 'application/vnd.oasis.opendocument.chart-template',
1789
+ 'odb': 'application/vnd.oasis.opendocument.database',
1790
+ 'odf': 'application/vnd.oasis.opendocument.formula',
1791
+ 'odft': 'application/vnd.oasis.opendocument.formula-template',
1792
+ 'odg': 'application/vnd.oasis.opendocument.graphics',
1793
+ 'otg': 'application/vnd.oasis.opendocument.graphics-template',
1794
+ 'odi': 'application/vnd.oasis.opendocument.image',
1795
+ 'oti': 'application/vnd.oasis.opendocument.image-template',
1796
+ 'odp': 'application/vnd.oasis.opendocument.presentation',
1797
+ 'otp': 'application/vnd.oasis.opendocument.presentation-template',
1798
+ 'ods': 'application/vnd.oasis.opendocument.spreadsheet',
1799
+ 'ots': 'application/vnd.oasis.opendocument.spreadsheet-template',
1800
+ 'odt': 'application/vnd.oasis.opendocument.text',
1801
+ 'odm': 'application/vnd.oasis.opendocument.text-master',
1802
+ 'ott': 'application/vnd.oasis.opendocument.text-template',
1803
+ 'oth': 'application/vnd.oasis.opendocument.text-web',
1804
+ 'xo': 'application/vnd.olpc-sugar',
1805
+ 'dd2': 'application/vnd.oma.dd2+xml',
1806
+ 'obgx': 'application/vnd.openblox.game+xml',
1807
+ 'oxt': 'application/vnd.openofficeorg.extension',
1808
+ 'osm': 'application/vnd.openstreetmap.data+xml',
1809
+ 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
1810
+ 'sldx': 'application/vnd.openxmlformats-officedocument.presentationml.slide',
1811
+ 'ppsx': 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
1812
+ 'potx': 'application/vnd.openxmlformats-officedocument.presentationml.template',
1813
+ 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
1814
+ 'xltx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
1815
+ 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
1816
+ 'dotx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
1817
+ 'mgp': 'application/vnd.osgeo.mapguide.package',
1818
+ 'dp': 'application/vnd.osgi.dp',
1819
+ 'esa': 'application/vnd.osgi.subsystem',
1820
+ 'pdb': 'application/x-pilot',
1821
+ 'pqa': 'application/vnd.palm',
1822
+ 'oprc': 'application/vnd.palm',
1823
+ 'paw': 'application/vnd.pawaafile',
1824
+ 'str': 'application/vnd.pg.format',
1825
+ 'ei6': 'application/vnd.pg.osasli',
1826
+ 'efif': 'application/vnd.picsel',
1827
+ 'wg': 'application/vnd.pmi.widget',
1828
+ 'plf': 'application/vnd.pocketlearn',
1829
+ 'pbd': 'application/vnd.powerbuilder6',
1830
+ 'box': 'application/vnd.previewsystems.box',
1831
+ 'mgz': 'application/vnd.proteus.magazine',
1832
+ 'qps': 'application/vnd.publishare-delta-tree',
1833
+ 'ptid': 'application/vnd.pvi.ptid1',
1834
+ 'qxd': 'application/vnd.quark.quarkxpress',
1835
+ 'qxt': 'application/vnd.quark.quarkxpress',
1836
+ 'qwd': 'application/vnd.quark.quarkxpress',
1837
+ 'qwt': 'application/vnd.quark.quarkxpress',
1838
+ 'qxl': 'application/vnd.quark.quarkxpress',
1839
+ 'qxb': 'application/vnd.quark.quarkxpress',
1840
+ 'rar': 'application/x-rar-compressed',
1841
+ 'bed': 'application/vnd.realvnc.bed',
1842
+ 'mxl': 'application/vnd.recordare.musicxml',
1843
+ 'musicxml': 'application/vnd.recordare.musicxml+xml',
1844
+ 'cryptonote': 'application/vnd.rig.cryptonote',
1845
+ 'cod': 'application/vnd.rim.cod',
1846
+ 'rm': 'application/vnd.rn-realmedia',
1847
+ 'rmvb': 'application/vnd.rn-realmedia-vbr',
1848
+ 'link66': 'application/vnd.route66.link66+xml',
1849
+ 'st': 'application/vnd.sailingtracker.track',
1850
+ 'see': 'application/vnd.seemail',
1851
+ 'sema': 'application/vnd.sema',
1852
+ 'semd': 'application/vnd.semd',
1853
+ 'semf': 'application/vnd.semf',
1854
+ 'ifm': 'application/vnd.shana.informed.formdata',
1855
+ 'itp': 'application/vnd.shana.informed.formtemplate',
1856
+ 'iif': 'application/vnd.shana.informed.interchange',
1857
+ 'ipk': 'application/vnd.shana.informed.package',
1858
+ 'twd': 'application/vnd.simtech-mindmapper',
1859
+ 'twds': 'application/vnd.simtech-mindmapper',
1860
+ 'mmf': 'application/vnd.smaf',
1861
+ 'teacher': 'application/vnd.smart.teacher',
1862
+ 'fo': 'application/vnd.software602.filler.form+xml',
1863
+ 'sdkm': 'application/vnd.solent.sdkm+xml',
1864
+ 'sdkd': 'application/vnd.solent.sdkm+xml',
1865
+ 'dxp': 'application/vnd.spotfire.dxp',
1866
+ 'sfs': 'application/vnd.spotfire.sfs',
1867
+ 'sdc': 'application/vnd.stardivision.calc',
1868
+ 'sda': 'application/vnd.stardivision.draw',
1869
+ 'sdd': 'application/vnd.stardivision.impress',
1870
+ 'smf': 'application/vnd.stardivision.math',
1871
+ 'sdw': 'application/vnd.stardivision.writer',
1872
+ 'vor': 'application/vnd.stardivision.writer',
1873
+ 'sgl': 'application/vnd.stardivision.writer-global',
1874
+ 'smzip': 'application/vnd.stepmania.package',
1875
+ 'sm': 'application/vnd.stepmania.stepchart',
1876
+ 'wadl': 'application/vnd.sun.wadl+xml',
1877
+ 'sxc': 'application/vnd.sun.xml.calc',
1878
+ 'stc': 'application/vnd.sun.xml.calc.template',
1879
+ 'sxd': 'application/vnd.sun.xml.draw',
1880
+ 'std': 'application/vnd.sun.xml.draw.template',
1881
+ 'sxi': 'application/vnd.sun.xml.impress',
1882
+ 'sti': 'application/vnd.sun.xml.impress.template',
1883
+ 'sxm': 'application/vnd.sun.xml.math',
1884
+ 'sxw': 'application/vnd.sun.xml.writer',
1885
+ 'sxg': 'application/vnd.sun.xml.writer.global',
1886
+ 'stw': 'application/vnd.sun.xml.writer.template',
1887
+ 'sus': 'application/vnd.sus-calendar',
1888
+ 'susp': 'application/vnd.sus-calendar',
1889
+ 'svd': 'application/vnd.svd',
1890
+ 'sis': 'application/vnd.symbian.install',
1891
+ 'sisx': 'application/vnd.symbian.install',
1892
+ 'xsm': 'application/vnd.syncml+xml',
1893
+ 'bdm': 'application/vnd.syncml.dm+wbxml',
1894
+ 'xdm': 'application/vnd.syncml.dm+xml',
1895
+ 'ddf': 'application/vnd.syncml.dmddf+xml',
1896
+ 'tao': 'application/vnd.tao.intent-module-archive',
1897
+ 'pcap': 'application/vnd.tcpdump.pcap',
1898
+ 'cap': 'application/vnd.tcpdump.pcap',
1899
+ 'dmp': 'application/vnd.tcpdump.pcap',
1900
+ 'tmo': 'application/vnd.tmobile-livetv',
1901
+ 'tpt': 'application/vnd.trid.tpt',
1902
+ 'mxs': 'application/vnd.triscape.mxs',
1903
+ 'tra': 'application/vnd.trueapp',
1904
+ 'ufd': 'application/vnd.ufdl',
1905
+ 'ufdl': 'application/vnd.ufdl',
1906
+ 'utz': 'application/vnd.uiq.theme',
1907
+ 'umj': 'application/vnd.umajin',
1908
+ 'unityweb': 'application/vnd.unity',
1909
+ 'uoml': 'application/vnd.uoml+xml',
1910
+ 'vcx': 'application/vnd.vcx',
1911
+ 'vsd': 'application/vnd.visio',
1912
+ 'vst': 'application/vnd.visio',
1913
+ 'vss': 'application/vnd.visio',
1914
+ 'vsw': 'application/vnd.visio',
1915
+ 'vis': 'application/vnd.visionary',
1916
+ 'vsf': 'application/vnd.vsf',
1917
+ 'wbxml': 'application/vnd.wap.wbxml',
1918
+ 'wmlc': 'application/vnd.wap.wmlc',
1919
+ 'wmlsc': 'application/vnd.wap.wmlscriptc',
1920
+ 'wtb': 'application/vnd.webturbo',
1921
+ 'nbp': 'application/vnd.wolfram.player',
1922
+ 'wpd': 'application/vnd.wordperfect',
1923
+ 'wqd': 'application/vnd.wqd',
1924
+ 'stf': 'application/vnd.wt.stf',
1925
+ 'xar': 'application/vnd.xara',
1926
+ 'xfdl': 'application/vnd.xfdl',
1927
+ 'hvd': 'application/vnd.yamaha.hv-dic',
1928
+ 'hvs': 'application/vnd.yamaha.hv-script',
1929
+ 'hvp': 'application/vnd.yamaha.hv-voice',
1930
+ 'osf': 'application/vnd.yamaha.openscoreformat',
1931
+ 'osfpvg': 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
1932
+ 'saf': 'application/vnd.yamaha.smaf-audio',
1933
+ 'spf': 'application/vnd.yamaha.smaf-phrase',
1934
+ 'cmp': 'application/vnd.yellowriver-custom-menu',
1935
+ 'zir': 'application/vnd.zul',
1936
+ 'zirz': 'application/vnd.zul',
1937
+ 'zaz': 'application/vnd.zzazz.deck+xml',
1938
+ 'vxml': 'application/voicexml+xml',
1939
+ 'wasm': 'application/wasm',
1940
+ 'wif': 'application/watcherinfo+xml',
1941
+ 'wgt': 'application/widget',
1942
+ 'hlp': 'application/winhlp',
1943
+ 'wsdl': 'application/wsdl+xml',
1944
+ 'wspolicy': 'application/wspolicy+xml',
1945
+ '7z': 'application/x-7z-compressed',
1946
+ 'abw': 'application/x-abiword',
1947
+ 'ace': 'application/x-ace-compressed',
1948
+ 'arj': 'application/x-arj',
1949
+ 'aab': 'application/x-authorware-bin',
1950
+ 'x32': 'application/x-authorware-bin',
1951
+ 'u32': 'application/x-authorware-bin',
1952
+ 'vox': 'application/x-authorware-bin',
1953
+ 'aam': 'application/x-authorware-map',
1954
+ 'aas': 'application/x-authorware-seg',
1955
+ 'bcpio': 'application/x-bcpio',
1956
+ 'torrent': 'application/x-bittorrent',
1957
+ 'blb': 'application/x-blorb',
1958
+ 'blorb': 'application/x-blorb',
1959
+ 'bz': 'application/x-bzip',
1960
+ 'bz2': 'application/x-bzip2',
1961
+ 'boz': 'application/x-bzip2',
1962
+ 'cbr': 'application/x-cbr',
1963
+ 'cba': 'application/x-cbr',
1964
+ 'cbt': 'application/x-cbr',
1965
+ 'cbz': 'application/x-cbr',
1966
+ 'cb7': 'application/x-cbr',
1967
+ 'vcd': 'application/x-cdlink',
1968
+ 'cfs': 'application/x-cfs-compressed',
1969
+ 'chat': 'application/x-chat',
1970
+ 'pgn': 'application/x-chess-pgn',
1971
+ 'crx': 'application/x-chrome-extension',
1972
+ 'cco': 'application/x-cocoa',
1973
+ 'nsc': 'application/x-conference',
1974
+ 'cpio': 'application/x-cpio',
1975
+ 'csh': 'application/x-csh',
1976
+ 'udeb': 'application/x-debian-package',
1977
+ 'dgc': 'application/x-dgc-compressed',
1978
+ 'dir': 'application/x-director',
1979
+ 'dcr': 'application/x-director',
1980
+ 'dxr': 'application/x-director',
1981
+ 'cst': 'application/x-director',
1982
+ 'cct': 'application/x-director',
1983
+ 'cxt': 'application/x-director',
1984
+ 'w3d': 'application/x-director',
1985
+ 'fgd': 'application/x-director',
1986
+ 'swa': 'application/x-director',
1987
+ 'wad': 'application/x-doom',
1988
+ 'ncx': 'application/x-dtbncx+xml',
1989
+ 'dtb': 'application/x-dtbook+xml',
1990
+ 'res': 'application/x-dtbresource+xml',
1991
+ 'dvi': 'application/x-dvi',
1992
+ 'evy': 'application/x-envoy',
1993
+ 'eva': 'application/x-eva',
1994
+ 'bdf': 'application/x-font-bdf',
1995
+ 'gsf': 'application/x-font-ghostscript',
1996
+ 'psf': 'application/x-font-linux-psf',
1997
+ 'pcf': 'application/x-font-pcf',
1998
+ 'snf': 'application/x-font-snf',
1999
+ 'pfa': 'application/x-font-type1',
2000
+ 'pfb': 'application/x-font-type1',
2001
+ 'pfm': 'application/x-font-type1',
2002
+ 'afm': 'application/x-font-type1',
2003
+ 'arc': 'application/x-freearc',
2004
+ 'spl': 'application/x-futuresplash',
2005
+ 'gca': 'application/x-gca-compressed',
2006
+ 'ulx': 'application/x-glulx',
2007
+ 'gnumeric': 'application/x-gnumeric',
2008
+ 'gramps': 'application/x-gramps-xml',
2009
+ 'gtar': 'application/x-gtar',
2010
+ 'hdf': 'application/x-hdf',
2011
+ 'php': 'application/x-httpd-php',
2012
+ 'install': 'application/x-install-instructions',
2013
+ 'jardiff': 'application/x-java-archive-diff',
2014
+ 'jnlp': 'application/x-java-jnlp-file',
2015
+ 'kdbx': 'application/x-keepass2',
2016
+ 'latex': 'application/x-latex',
2017
+ 'luac': 'application/x-lua-bytecode',
2018
+ 'lzh': 'application/x-lzh-compressed',
2019
+ 'lha': 'application/x-lzh-compressed',
2020
+ 'run': 'application/x-makeself',
2021
+ 'mie': 'application/x-mie',
2022
+ 'prc': 'model/prc',
2023
+ 'mobi': 'application/x-mobipocket-ebook',
2024
+ 'application': 'application/x-ms-application',
2025
+ 'lnk': 'application/x-ms-shortcut',
2026
+ 'wmd': 'application/x-ms-wmd',
2027
+ 'wmz': 'application/x-msmetafile',
2028
+ 'xbap': 'application/x-ms-xbap',
2029
+ 'mdb': 'application/x-msaccess',
2030
+ 'obd': 'application/x-msbinder',
2031
+ 'crd': 'application/x-mscardfile',
2032
+ 'clp': 'application/x-msclip',
2033
+ 'com': 'application/x-msdownload',
2034
+ 'bat': 'application/x-msdownload',
2035
+ 'mvb': 'application/x-msmediaview',
2036
+ 'm13': 'application/x-msmediaview',
2037
+ 'm14': 'application/x-msmediaview',
2038
+ 'wmf': 'image/wmf',
2039
+ 'emf': 'image/emf',
2040
+ 'emz': 'application/x-msmetafile',
2041
+ 'mny': 'application/x-msmoney',
2042
+ 'pub': 'application/x-mspublisher',
2043
+ 'scd': 'application/x-msschedule',
2044
+ 'trm': 'application/x-msterminal',
2045
+ 'wri': 'application/x-mswrite',
2046
+ 'nc': 'application/x-netcdf',
2047
+ 'cdf': 'application/x-netcdf',
2048
+ 'pac': 'application/x-ns-proxy-autoconfig',
2049
+ 'nzb': 'application/x-nzb',
2050
+ 'pl': 'application/x-perl',
2051
+ 'pm': 'application/x-perl',
2052
+ 'p12': 'application/x-pkcs12',
2053
+ 'pfx': 'application/x-pkcs12',
2054
+ 'p7b': 'application/x-pkcs7-certificates',
2055
+ 'spc': 'application/x-pkcs7-certificates',
2056
+ 'p7r': 'application/x-pkcs7-certreqresp',
2057
+ 'rpm': 'application/x-redhat-package-manager',
2058
+ 'ris': 'application/x-research-info-systems',
2059
+ 'sea': 'application/x-sea',
2060
+ 'sh': 'application/x-sh',
2061
+ 'shar': 'application/x-shar',
2062
+ 'swf': 'application/x-shockwave-flash',
2063
+ 'xap': 'application/x-silverlight-app',
2064
+ 'sql': 'application/x-sql',
2065
+ 'sit': 'application/x-stuffit',
2066
+ 'sitx': 'application/x-stuffitx',
2067
+ 'srt': 'application/x-subrip',
2068
+ 'sv4cpio': 'application/x-sv4cpio',
2069
+ 'sv4crc': 'application/x-sv4crc',
2070
+ 't3': 'application/x-t3vm-image',
2071
+ 'gam': 'application/x-tads',
2072
+ 'tar': 'application/x-tar',
2073
+ 'tcl': 'application/x-tcl',
2074
+ 'tk': 'application/x-tcl',
2075
+ 'tex': 'application/x-tex',
2076
+ 'tfm': 'application/x-tex-tfm',
2077
+ 'texinfo': 'application/x-texinfo',
2078
+ 'texi': 'application/x-texinfo',
2079
+ 'obj': 'model/obj',
2080
+ 'ustar': 'application/x-ustar',
2081
+ 'hdd': 'application/x-virtualbox-hdd',
2082
+ 'ova': 'application/x-virtualbox-ova',
2083
+ 'ovf': 'application/x-virtualbox-ovf',
2084
+ 'vbox': 'application/x-virtualbox-vbox',
2085
+ 'vbox-extpack': 'application/x-virtualbox-vbox-extpack',
2086
+ 'vdi': 'application/x-virtualbox-vdi',
2087
+ 'vhd': 'application/x-virtualbox-vhd',
2088
+ 'vmdk': 'application/x-virtualbox-vmdk',
2089
+ 'src': 'application/x-wais-source',
2090
+ 'webapp': 'application/x-web-app-manifest+json',
2091
+ 'der': 'application/x-x509-ca-cert',
2092
+ 'crt': 'application/x-x509-ca-cert',
2093
+ 'pem': 'application/x-x509-ca-cert',
2094
+ 'fig': 'application/x-xfig',
2095
+ 'xlf': 'application/xliff+xml',
2096
+ 'xpi': 'application/x-xpinstall',
2097
+ 'xz': 'application/x-xz',
2098
+ 'z1': 'application/x-zmachine',
2099
+ 'z2': 'application/x-zmachine',
2100
+ 'z3': 'application/x-zmachine',
2101
+ 'z4': 'application/x-zmachine',
2102
+ 'z5': 'application/x-zmachine',
2103
+ 'z6': 'application/x-zmachine',
2104
+ 'z7': 'application/x-zmachine',
2105
+ 'z8': 'application/x-zmachine',
2106
+ 'xaml': 'application/xaml+xml',
2107
+ 'xav': 'application/xcap-att+xml',
2108
+ 'xca': 'application/xcap-caps+xml',
2109
+ 'xdf': 'application/xcap-diff+xml',
2110
+ 'xel': 'application/xcap-el+xml',
2111
+ 'xns': 'application/xcap-ns+xml',
2112
+ 'xenc': 'application/xenc+xml',
2113
+ 'xhtml': 'application/xhtml+xml',
2114
+ 'xht': 'application/xhtml+xml',
2115
+ 'xml': 'text/xml',
2116
+ 'xsl': 'application/xslt+xml',
2117
+ 'xsd': 'application/xml',
2118
+ 'rng': 'application/xml',
2119
+ 'dtd': 'application/xml-dtd',
2120
+ 'xop': 'application/xop+xml',
2121
+ 'xpl': 'application/xproc+xml',
2122
+ 'xslt': 'application/xslt+xml',
2123
+ 'xspf': 'application/xspf+xml',
2124
+ 'mxml': 'application/xv+xml',
2125
+ 'xhvml': 'application/xv+xml',
2126
+ 'xvml': 'application/xv+xml',
2127
+ 'xvm': 'application/xv+xml',
2128
+ 'yang': 'application/yang',
2129
+ 'yin': 'application/yin+xml',
2130
+ 'zip': 'application/zip',
2131
+ '3gpp': 'video/3gpp',
2132
+ 'adp': 'audio/adpcm',
2133
+ 'amr': 'audio/amr',
2134
+ 'au': 'audio/basic',
2135
+ 'snd': 'audio/basic',
2136
+ 'mid': 'audio/midi',
2137
+ 'midi': 'audio/midi',
2138
+ 'kar': 'audio/midi',
2139
+ 'rmi': 'audio/midi',
2140
+ 'mxmf': 'audio/mobile-xmf',
2141
+ 'mp3': 'audio/mpeg',
2142
+ 'm4a': 'audio/x-m4a',
2143
+ 'mp4a': 'audio/mp4',
2144
+ 'mpga': 'audio/mpeg',
2145
+ 'mp2': 'audio/mpeg',
2146
+ 'mp2a': 'audio/mpeg',
2147
+ 'm2a': 'audio/mpeg',
2148
+ 'm3a': 'audio/mpeg',
2149
+ 'oga': 'audio/ogg',
2150
+ 'ogg': 'audio/ogg',
2151
+ 'spx': 'audio/ogg',
2152
+ 'opus': 'audio/ogg',
2153
+ 's3m': 'audio/s3m',
2154
+ 'sil': 'audio/silk',
2155
+ 'uva': 'audio/vnd.dece.audio',
2156
+ 'uvva': 'audio/vnd.dece.audio',
2157
+ 'eol': 'audio/vnd.digital-winds',
2158
+ 'dra': 'audio/vnd.dra',
2159
+ 'dts': 'audio/vnd.dts',
2160
+ 'dtshd': 'audio/vnd.dts.hd',
2161
+ 'lvp': 'audio/vnd.lucent.voice',
2162
+ 'pya': 'audio/vnd.ms-playready.media.pya',
2163
+ 'ecelp4800': 'audio/vnd.nuera.ecelp4800',
2164
+ 'ecelp7470': 'audio/vnd.nuera.ecelp7470',
2165
+ 'ecelp9600': 'audio/vnd.nuera.ecelp9600',
2166
+ 'rip': 'audio/vnd.rip',
2167
+ 'wav': 'audio/x-wav',
2168
+ 'weba': 'audio/webm',
2169
+ 'aac': 'audio/x-aac',
2170
+ 'aif': 'audio/x-aiff',
2171
+ 'aiff': 'audio/x-aiff',
2172
+ 'aifc': 'audio/x-aiff',
2173
+ 'caf': 'audio/x-caf',
2174
+ 'flac': 'audio/x-flac',
2175
+ 'mka': 'audio/x-matroska',
2176
+ 'm3u': 'audio/x-mpegurl',
2177
+ 'wax': 'audio/x-ms-wax',
2178
+ 'wma': 'audio/x-ms-wma',
2179
+ 'ram': 'audio/x-pn-realaudio',
2180
+ 'ra': 'audio/x-realaudio',
2181
+ 'rmp': 'audio/x-pn-realaudio-plugin',
2182
+ 'xm': 'audio/xm',
2183
+ 'cdx': 'chemical/x-cdx',
2184
+ 'cif': 'chemical/x-cif',
2185
+ 'cmdf': 'chemical/x-cmdf',
2186
+ 'cml': 'chemical/x-cml',
2187
+ 'csml': 'chemical/x-csml',
2188
+ 'xyz': 'chemical/x-xyz',
2189
+ 'ttc': 'font/collection',
2190
+ 'otf': 'font/otf',
2191
+ 'ttf': 'font/ttf',
2192
+ 'woff': 'font/woff',
2193
+ 'woff2': 'font/woff2',
2194
+ 'exr': 'image/aces',
2195
+ 'apng': 'image/apng',
2196
+ 'avci': 'image/avci',
2197
+ 'avcs': 'image/avcs',
2198
+ 'avif': 'image/avif',
2199
+ 'bmp': 'image/x-ms-bmp',
2200
+ 'cgm': 'image/cgm',
2201
+ 'drle': 'image/dicom-rle',
2202
+ 'fits': 'image/fits',
2203
+ 'g3': 'image/g3fax',
2204
+ 'gif': 'image/gif',
2205
+ 'heic': 'image/heic',
2206
+ 'heics': 'image/heic-sequence',
2207
+ 'heif': 'image/heif',
2208
+ 'heifs': 'image/heif-sequence',
2209
+ 'hej2': 'image/hej2k',
2210
+ 'hsj2': 'image/hsj2',
2211
+ 'ief': 'image/ief',
2212
+ 'jls': 'image/jls',
2213
+ 'jp2': 'image/jp2',
2214
+ 'jpg2': 'image/jp2',
2215
+ 'jpeg': 'image/jpeg',
2216
+ 'jpg': 'image/jpeg',
2217
+ 'jpe': 'image/jpeg',
2218
+ 'jph': 'image/jph',
2219
+ 'jhc': 'image/jphc',
2220
+ 'jpm': 'video/jpm',
2221
+ 'jpx': 'image/jpx',
2222
+ 'jpf': 'image/jpx',
2223
+ 'jxr': 'image/jxr',
2224
+ 'jxra': 'image/jxra',
2225
+ 'jxrs': 'image/jxrs',
2226
+ 'jxs': 'image/jxs',
2227
+ 'jxsc': 'image/jxsc',
2228
+ 'jxsi': 'image/jxsi',
2229
+ 'jxss': 'image/jxss',
2230
+ 'ktx': 'image/ktx',
2231
+ 'ktx2': 'image/ktx2',
2232
+ 'png': 'image/png',
2233
+ 'btif': 'image/prs.btif',
2234
+ 'pti': 'image/prs.pti',
2235
+ 'sgi': 'image/sgi',
2236
+ 'svg': 'image/svg+xml',
2237
+ 'svgz': 'image/svg+xml',
2238
+ 't38': 'image/t38',
2239
+ 'tif': 'image/tiff',
2240
+ 'tiff': 'image/tiff',
2241
+ 'tfx': 'image/tiff-fx',
2242
+ 'psd': 'image/vnd.adobe.photoshop',
2243
+ 'azv': 'image/vnd.airzip.accelerator.azv',
2244
+ 'uvi': 'image/vnd.dece.graphic',
2245
+ 'uvvi': 'image/vnd.dece.graphic',
2246
+ 'uvg': 'image/vnd.dece.graphic',
2247
+ 'uvvg': 'image/vnd.dece.graphic',
2248
+ 'djvu': 'image/vnd.djvu',
2249
+ 'djv': 'image/vnd.djvu',
2250
+ 'sub': 'text/vnd.dvb.subtitle',
2251
+ 'dwg': 'image/vnd.dwg',
2252
+ 'dxf': 'image/vnd.dxf',
2253
+ 'fbs': 'image/vnd.fastbidsheet',
2254
+ 'fpx': 'image/vnd.fpx',
2255
+ 'fst': 'image/vnd.fst',
2256
+ 'mmr': 'image/vnd.fujixerox.edmics-mmr',
2257
+ 'rlc': 'image/vnd.fujixerox.edmics-rlc',
2258
+ 'ico': 'image/x-icon',
2259
+ 'dds': 'image/vnd.ms-dds',
2260
+ 'mdi': 'image/vnd.ms-modi',
2261
+ 'wdp': 'image/vnd.ms-photo',
2262
+ 'npx': 'image/vnd.net-fpx',
2263
+ 'b16': 'image/vnd.pco.b16',
2264
+ 'tap': 'image/vnd.tencent.tap',
2265
+ 'vtf': 'image/vnd.valve.source.texture',
2266
+ 'wbmp': 'image/vnd.wap.wbmp',
2267
+ 'xif': 'image/vnd.xiff',
2268
+ 'pcx': 'image/x-pcx',
2269
+ 'webp': 'image/webp',
2270
+ '3ds': 'image/x-3ds',
2271
+ 'ras': 'image/x-cmu-raster',
2272
+ 'cmx': 'image/x-cmx',
2273
+ 'fh': 'image/x-freehand',
2274
+ 'fhc': 'image/x-freehand',
2275
+ 'fh4': 'image/x-freehand',
2276
+ 'fh5': 'image/x-freehand',
2277
+ 'fh7': 'image/x-freehand',
2278
+ 'jng': 'image/x-jng',
2279
+ 'sid': 'image/x-mrsid-image',
2280
+ 'pic': 'image/x-pict',
2281
+ 'pct': 'image/x-pict',
2282
+ 'pnm': 'image/x-portable-anymap',
2283
+ 'pbm': 'image/x-portable-bitmap',
2284
+ 'pgm': 'image/x-portable-graymap',
2285
+ 'ppm': 'image/x-portable-pixmap',
2286
+ 'rgb': 'image/x-rgb',
2287
+ 'tga': 'image/x-tga',
2288
+ 'xbm': 'image/x-xbitmap',
2289
+ 'xpm': 'image/x-xpixmap',
2290
+ 'xwd': 'image/x-xwindowdump',
2291
+ 'disposition-notification': 'message/disposition-notification',
2292
+ 'u8msg': 'message/global',
2293
+ 'u8dsn': 'message/global-delivery-status',
2294
+ 'u8mdn': 'message/global-disposition-notification',
2295
+ 'u8hdr': 'message/global-headers',
2296
+ 'eml': 'message/rfc822',
2297
+ 'mime': 'message/rfc822',
2298
+ 'wsc': 'message/vnd.wfa.wsc',
2299
+ '3mf': 'model/3mf',
2300
+ 'gltf': 'model/gltf+json',
2301
+ 'glb': 'model/gltf-binary',
2302
+ 'igs': 'model/iges',
2303
+ 'iges': 'model/iges',
2304
+ 'msh': 'model/mesh',
2305
+ 'mesh': 'model/mesh',
2306
+ 'silo': 'model/mesh',
2307
+ 'mtl': 'model/mtl',
2308
+ 'stpx': 'model/step+xml',
2309
+ 'stpz': 'model/step+zip',
2310
+ 'stpxz': 'model/step-xml+zip',
2311
+ 'u3d': 'model/u3d',
2312
+ 'dae': 'model/vnd.collada+xml',
2313
+ 'dwf': 'model/vnd.dwf',
2314
+ 'gdl': 'model/vnd.gdl',
2315
+ 'gtw': 'model/vnd.gtw',
2316
+ 'mts': 'model/vnd.mts',
2317
+ 'ogex': 'model/vnd.opengex',
2318
+ 'x_b': 'model/vnd.parasolid.transmit.binary',
2319
+ 'x_t': 'model/vnd.parasolid.transmit.text',
2320
+ 'vds': 'model/vnd.sap.vds',
2321
+ 'usdz': 'model/vnd.usdz+zip',
2322
+ 'bsp': 'model/vnd.valve.source.compiled-map',
2323
+ 'vtu': 'model/vnd.vtu',
2324
+ 'wrl': 'model/vrml',
2325
+ 'vrml': 'model/vrml',
2326
+ 'x3db': 'model/x3d+fastinfoset',
2327
+ 'x3dbz': 'model/x3d+binary',
2328
+ 'x3dv': 'model/x3d-vrml',
2329
+ 'x3dvz': 'model/x3d+vrml',
2330
+ 'x3d': 'model/x3d+xml',
2331
+ 'x3dz': 'model/x3d+xml',
2332
+ 'appcache': 'text/cache-manifest',
2333
+ 'manifest': 'text/cache-manifest',
2334
+ 'ics': 'text/calendar',
2335
+ 'ifb': 'text/calendar',
2336
+ 'coffee': 'text/coffeescript',
2337
+ 'litcoffee': 'text/coffeescript',
2338
+ 'css': 'text/css',
2339
+ 'csv': 'text/csv',
2340
+ 'html': 'text/html',
2341
+ 'htm': 'text/html',
2342
+ 'shtml': 'text/html',
2343
+ 'jade': 'text/jade',
2344
+ 'jsx': 'text/jsx',
2345
+ 'less': 'text/less',
2346
+ 'markdown': 'text/markdown',
2347
+ 'md': 'text/markdown',
2348
+ 'mml': 'text/mathml',
2349
+ 'mdx': 'text/mdx',
2350
+ 'n3': 'text/n3',
2351
+ 'txt': 'text/plain',
2352
+ 'text': 'text/plain',
2353
+ 'conf': 'text/plain',
2354
+ 'def': 'text/plain',
2355
+ 'list': 'text/plain',
2356
+ 'log': 'text/plain',
2357
+ 'in': 'text/plain',
2358
+ 'ini': 'text/plain',
2359
+ 'dsc': 'text/prs.lines.tag',
2360
+ 'rtx': 'text/richtext',
2361
+ 'sgml': 'text/sgml',
2362
+ 'sgm': 'text/sgml',
2363
+ 'shex': 'text/shex',
2364
+ 'slim': 'text/slim',
2365
+ 'slm': 'text/slim',
2366
+ 'spdx': 'text/spdx',
2367
+ 'stylus': 'text/stylus',
2368
+ 'styl': 'text/stylus',
2369
+ 'tsv': 'text/tab-separated-values',
2370
+ 't': 'text/troff',
2371
+ 'tr': 'text/troff',
2372
+ 'roff': 'text/troff',
2373
+ 'man': 'text/troff',
2374
+ 'me': 'text/troff',
2375
+ 'ms': 'text/troff',
2376
+ 'ttl': 'text/turtle',
2377
+ 'uri': 'text/uri-list',
2378
+ 'uris': 'text/uri-list',
2379
+ 'urls': 'text/uri-list',
2380
+ 'vcard': 'text/vcard',
2381
+ 'curl': 'text/vnd.curl',
2382
+ 'dcurl': 'text/vnd.curl.dcurl',
2383
+ 'mcurl': 'text/vnd.curl.mcurl',
2384
+ 'scurl': 'text/vnd.curl.scurl',
2385
+ 'ged': 'text/vnd.familysearch.gedcom',
2386
+ 'fly': 'text/vnd.fly',
2387
+ 'flx': 'text/vnd.fmi.flexstor',
2388
+ 'gv': 'text/vnd.graphviz',
2389
+ '3dml': 'text/vnd.in3d.3dml',
2390
+ 'spot': 'text/vnd.in3d.spot',
2391
+ 'jad': 'text/vnd.sun.j2me.app-descriptor',
2392
+ 'wml': 'text/vnd.wap.wml',
2393
+ 'wmls': 'text/vnd.wap.wmlscript',
2394
+ 'vtt': 'text/vtt',
2395
+ 's': 'text/x-asm',
2396
+ 'asm': 'text/x-asm',
2397
+ 'c': 'text/x-c',
2398
+ 'cc': 'text/x-c',
2399
+ 'cxx': 'text/x-c',
2400
+ 'cpp': 'text/x-c',
2401
+ 'h': 'text/x-c',
2402
+ 'hh': 'text/x-c',
2403
+ 'dic': 'text/x-c',
2404
+ 'htc': 'text/x-component',
2405
+ 'f': 'text/x-fortran',
2406
+ 'for': 'text/x-fortran',
2407
+ 'f77': 'text/x-fortran',
2408
+ 'f90': 'text/x-fortran',
2409
+ 'hbs': 'text/x-handlebars-template',
2410
+ 'java': 'text/x-java-source',
2411
+ 'lua': 'text/x-lua',
2412
+ 'mkd': 'text/x-markdown',
2413
+ 'nfo': 'text/x-nfo',
2414
+ 'opml': 'text/x-opml',
2415
+ 'p': 'text/x-pascal',
2416
+ 'pas': 'text/x-pascal',
2417
+ 'pde': 'text/x-processing',
2418
+ 'sass': 'text/x-sass',
2419
+ 'scss': 'text/x-scss',
2420
+ 'etx': 'text/x-setext',
2421
+ 'sfv': 'text/x-sfv',
2422
+ 'ymp': 'text/x-suse-ymp',
2423
+ 'uu': 'text/x-uuencode',
2424
+ 'vcs': 'text/x-vcalendar',
2425
+ 'vcf': 'text/x-vcard',
2426
+ 'yaml': 'text/yaml',
2427
+ 'yml': 'text/yaml',
2428
+ '3gp': 'video/3gpp',
2429
+ '3g2': 'video/3gpp2',
2430
+ 'h261': 'video/h261',
2431
+ 'h263': 'video/h263',
2432
+ 'h264': 'video/h264',
2433
+ 'm4s': 'video/iso.segment',
2434
+ 'jpgv': 'video/jpeg',
2435
+ 'jpgm': 'video/jpm',
2436
+ 'mj2': 'video/mj2',
2437
+ 'mjp2': 'video/mj2',
2438
+ 'ts': 'video/mp2t',
2439
+ 'mp4': 'video/mp4',
2440
+ 'mp4v': 'video/mp4',
2441
+ 'mpg4': 'video/mp4',
2442
+ 'mpeg': 'video/mpeg',
2443
+ 'mpg': 'video/mpeg',
2444
+ 'mpe': 'video/mpeg',
2445
+ 'm1v': 'video/mpeg',
2446
+ 'm2v': 'video/mpeg',
2447
+ 'ogv': 'video/ogg',
2448
+ 'qt': 'video/quicktime',
2449
+ 'mov': 'video/quicktime',
2450
+ 'uvh': 'video/vnd.dece.hd',
2451
+ 'uvvh': 'video/vnd.dece.hd',
2452
+ 'uvm': 'video/vnd.dece.mobile',
2453
+ 'uvvm': 'video/vnd.dece.mobile',
2454
+ 'uvp': 'video/vnd.dece.pd',
2455
+ 'uvvp': 'video/vnd.dece.pd',
2456
+ 'uvs': 'video/vnd.dece.sd',
2457
+ 'uvvs': 'video/vnd.dece.sd',
2458
+ 'uvv': 'video/vnd.dece.video',
2459
+ 'uvvv': 'video/vnd.dece.video',
2460
+ 'dvb': 'video/vnd.dvb.file',
2461
+ 'fvt': 'video/vnd.fvt',
2462
+ 'mxu': 'video/vnd.mpegurl',
2463
+ 'm4u': 'video/vnd.mpegurl',
2464
+ 'pyv': 'video/vnd.ms-playready.media.pyv',
2465
+ 'uvu': 'video/vnd.uvvu.mp4',
2466
+ 'uvvu': 'video/vnd.uvvu.mp4',
2467
+ 'viv': 'video/vnd.vivo',
2468
+ 'webm': 'video/webm',
2469
+ 'f4v': 'video/x-f4v',
2470
+ 'fli': 'video/x-fli',
2471
+ 'flv': 'video/x-flv',
2472
+ 'm4v': 'video/x-m4v',
2473
+ 'mkv': 'video/x-matroska',
2474
+ 'mk3d': 'video/x-matroska',
2475
+ 'mks': 'video/x-matroska',
2476
+ 'mng': 'video/x-mng',
2477
+ 'asf': 'video/x-ms-asf',
2478
+ 'asx': 'video/x-ms-asf',
2479
+ 'vob': 'video/x-ms-vob',
2480
+ 'wm': 'video/x-ms-wm',
2481
+ 'wmv': 'video/x-ms-wmv',
2482
+ 'wmx': 'video/x-ms-wmx',
2483
+ 'wvx': 'video/x-ms-wvx',
2484
+ 'avi': 'video/x-msvideo',
2485
+ 'movie': 'video/x-sgi-movie',
2486
+ 'smv': 'video/x-smv',
2487
+ 'ice': 'x-conference/x-cooltalk',
2488
+ };
2489
+
2490
+ function getMimeType(path, fallback = null) {
2491
+ const ext = (/\.([^.]+)$/.exec(path) || [])[1] || path;
2492
+ return extensions[ext] || fallback;
2493
+ }
2494
+
2495
+ const { stat, readdir } = promises;
2496
+ function statFile(path) {
2497
+ return stat(path);
2498
+ }
2499
+ async function serveFile(filePath, options = {}) {
2500
+ const { restoreCtx } = useCurrentWooksContext();
2501
+ const { status } = useResponse();
2502
+ const { setHeader, removeHeader } = useSetHeaders();
2503
+ const headers = useHeaders();
2504
+ const { method, url } = useRequest();
2505
+ const { setCacheControl, setExpires, setPragmaNoCache } = useSetCacheControl();
2506
+ const normalizedPath = path.normalize(path.join(process.cwd(), options.baseDir || '', filePath));
2507
+ let fileStats;
2508
+ try {
2509
+ fileStats = await stat(normalizedPath);
2510
+ }
2511
+ catch (e) {
2512
+ if (options.defaultExt) {
2513
+ const ext = path.extname(filePath);
2514
+ if (!ext) {
2515
+ restoreCtx();
2516
+ return serveFile(filePath + '.' + options.defaultExt);
2517
+ }
2518
+ }
2519
+ throw new WooksError(404);
2520
+ }
2521
+ status(200);
2522
+ const etag = `"${[fileStats.ino, fileStats.size, fileStats.mtime.toISOString()].join('-')}"`;
2523
+ const lastModified = new Date(fileStats.mtime);
2524
+ if (isNotModified(etag, lastModified, headers['if-none-match'] || '', headers['if-modified-since'] || '')) {
2525
+ status(304);
2526
+ return '';
2527
+ }
2528
+ setHeader('etag', etag);
2529
+ setHeader('Last-Modified', lastModified.toUTCString());
2530
+ if (options.cacheControl !== undefined) {
2531
+ setCacheControl(options.cacheControl);
2532
+ }
2533
+ if (options.expires) {
2534
+ setExpires(options.expires);
2535
+ }
2536
+ if (options.pragmaNoCache) {
2537
+ setPragmaNoCache(options.pragmaNoCache);
2538
+ }
2539
+ if (fileStats.isDirectory()) {
2540
+ if (options.listDirectory) {
2541
+ restoreCtx();
2542
+ return listDirectory(normalizedPath);
2543
+ }
2544
+ else if (options.index) {
2545
+ if (filePath[filePath.length - 1] !== '/' && url && url[url.length - 1] !== '/') {
2546
+ return new BaseWooksResponse().setStatus(302).setHeader('Location', url + '/');
2547
+ }
2548
+ restoreCtx();
2549
+ return serveFile(path.join(filePath, options.index), {
2550
+ ...options,
2551
+ index: '',
2552
+ });
2553
+ }
2554
+ removeHeader('etag');
2555
+ removeHeader('Last-Modified');
2556
+ throw new WooksError(404);
2557
+ }
2558
+ let range = headers.range;
2559
+ let start, end;
2560
+ let size = fileStats.size;
2561
+ if (range) {
2562
+ const rangeParts = range.trim().replace(/bytes=/, '').split('-');
2563
+ const [s, e] = rangeParts;
2564
+ start = parseInt(s);
2565
+ end = e ? parseInt(e) : (size - 1);
2566
+ end = Math.min(size - 1, end);
2567
+ if (start > end || isNaN(start) || isNaN(end)) {
2568
+ throw new WooksError(416);
2569
+ }
2570
+ size = (end - start) + 1;
2571
+ const ifRange = headers['if-range'] || '';
2572
+ const ifRangeTag = ifRange[0] === '"' ? ifRange : '';
2573
+ const ifRangeDate = ifRangeTag ? '' : ifRange;
2574
+ if (ifRange && !isNotModified(etag, lastModified, ifRangeTag, ifRangeDate)) {
2575
+ status(200);
2576
+ size = fileStats.size;
2577
+ range = '';
2578
+ }
2579
+ else {
2580
+ setHeader('Content-Range', `bytes ${start}-${end}/${fileStats.size}`);
2581
+ status(206);
2582
+ }
2583
+ }
2584
+ setHeader('Accept-Ranges', 'bytes');
2585
+ setHeader('Content-Type', getMimeType(normalizedPath) || 'application/octet-stream');
2586
+ setHeader('Content-Length', size);
2587
+ if (options.headers) {
2588
+ for (const header of Object.keys(options.headers)) {
2589
+ setHeader(header, options.headers[header]);
2590
+ }
2591
+ }
2592
+ return method === 'HEAD' ? '' : createReadStream(normalizedPath, !!range ? { start, end } : undefined);
2593
+ }
2594
+ function isNotModified(etag, lastModified, clientEtag, clientLM) {
2595
+ if (clientEtag) {
2596
+ const parts = clientEtag.split(',').map(v => v.trim());
2597
+ for (const p of parts) {
2598
+ if (etag === p) {
2599
+ return true;
2600
+ }
2601
+ }
2602
+ return false;
2603
+ }
2604
+ const date = new Date(clientLM);
2605
+ if (date.toString() !== 'Invalid Date' && date.getTime() > lastModified.getTime()) {
2606
+ return true;
2607
+ }
2608
+ return false;
2609
+ }
2610
+ async function listDirectory(dirPath) {
2611
+ const { setContentType } = useSetHeaders();
2612
+ const { url } = useRequest();
2613
+ const list = await readdir(dirPath);
2614
+ const promises = [];
2615
+ let detailedList = [];
2616
+ for (const item of list) {
2617
+ promises.push({ name: item, promise: stat(path.join(dirPath, item)) });
2618
+ }
2619
+ for (const item of promises) {
2620
+ const data = await item.promise;
2621
+ detailedList.push({
2622
+ name: item.name, size: data.size, mtime: data.mtime, dir: data.isDirectory(),
2623
+ });
2624
+ }
2625
+ detailedList = detailedList.sort((a, b) => a.dir === b.dir ? a.name > b.name ? 1 : -1 : a.dir > b.dir ? -1 : 1);
2626
+ detailedList.unshift({ name: '..', dir: true });
2627
+ setContentType('text/html');
2628
+ const styles = '<style type="text/css">\nhtml { font-family: monospace }\n' +
2629
+ 'span { padding: 0px 2px }\n' +
2630
+ '.text { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; }\n' +
2631
+ '.icon { width: 20px; display: inline-block; text-align: center; }\n' +
2632
+ '.name { width: 250px; display: inline-block; }\n' +
2633
+ '.size { width: 80px; display: inline-block; color: grey; text-align: right; }\n' +
2634
+ '.date { width: 200px; display: inline-block; color: grey; text-align: right; }\n' +
2635
+ '\n</style>';
2636
+ return '<html><head><title>Dir</title> ' + styles + ' </head><body><ul>' +
2637
+ detailedList.map(d => `<li> <span class="icon">${d.dir ? '&#128193;' : '&#128462;'}</span>` +
2638
+ `<a href="${path.join(url || '', d.name)}"><span class="name text">${d.name}</span></a>` +
2639
+ `<span class="size text">${d.size && (d.size > 10000 ? (Math.round(d.size / 1024 / 1024).toString() + 'Mb') : (Math.round(d.size / 1024).toString() + 'Kb')) || ''}</span>` +
2640
+ `<span class="date text">${d.mtime && d.mtime.toISOString() || ''}</li>`).join('\n') +
2641
+ '</ul></body></html>';
2642
+ }
2643
+
2644
+ export { BaseWooksResponse, BaseWooksResponseRenderer, EHttpStatusCode, Wooks, WooksError, WooksErrorRenderer, clearCacheObject, contentTypes, createResponseFrom, httpStatusCodes, registerBodyCompressor, serveFile, setTestHttpContext, statFile, useAccept, useAuthorization, useBody, useCacheObject, useCookies, useCurrentWooksContext, useHeaders, useRequest, useResponse, useRouteParams, useSearchParams, useSetCacheControl, useSetCookies, useSetHeaders };