expediate 1.0.4 → 1.0.5

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 (52) hide show
  1. package/LICENSE +16 -16
  2. package/README.md +417 -30
  3. package/dist/apis.d.ts +138 -21
  4. package/dist/apis.d.ts.map +1 -1
  5. package/dist/apis.js +172 -79
  6. package/dist/apis.js.map +1 -1
  7. package/dist/cjs/apis.js +327 -0
  8. package/dist/cjs/git.js +293 -0
  9. package/dist/cjs/index.js +2583 -0
  10. package/dist/cjs/jwt-auth.js +532 -0
  11. package/dist/cjs/middleware.js +511 -0
  12. package/dist/cjs/mimetypes.json +1 -0
  13. package/dist/cjs/misc.js +787 -0
  14. package/dist/cjs/openapi.js +485 -0
  15. package/dist/cjs/package.json +1 -0
  16. package/dist/cjs/router.js +898 -0
  17. package/dist/cjs/static.js +669 -0
  18. package/dist/git.d.ts +71 -8
  19. package/dist/git.d.ts.map +1 -1
  20. package/dist/git.js +127 -72
  21. package/dist/git.js.map +1 -1
  22. package/dist/index.d.ts +17 -13
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +14 -24
  25. package/dist/index.js.map +1 -1
  26. package/dist/jwt-auth.d.ts +147 -57
  27. package/dist/jwt-auth.d.ts.map +1 -1
  28. package/dist/jwt-auth.js +445 -205
  29. package/dist/jwt-auth.js.map +1 -1
  30. package/dist/middleware.d.ts +476 -0
  31. package/dist/middleware.d.ts.map +1 -0
  32. package/dist/middleware.js +647 -0
  33. package/dist/middleware.js.map +1 -0
  34. package/dist/mimetypes.json +1 -1
  35. package/dist/misc.d.ts +112 -5
  36. package/dist/misc.d.ts.map +1 -1
  37. package/dist/misc.js +235 -102
  38. package/dist/misc.js.map +1 -1
  39. package/dist/openapi.d.ts +290 -0
  40. package/dist/openapi.d.ts.map +1 -0
  41. package/dist/openapi.js +481 -0
  42. package/dist/openapi.js.map +1 -0
  43. package/dist/router.d.ts +405 -46
  44. package/dist/router.d.ts.map +1 -1
  45. package/dist/router.js +658 -153
  46. package/dist/router.js.map +1 -1
  47. package/dist/static.d.ts +1 -1
  48. package/dist/static.d.ts.map +1 -1
  49. package/dist/static.js +88 -84
  50. package/dist/static.js.map +1 -1
  51. package/package.json +21 -4
  52. package/.npmignore +0 -16
@@ -0,0 +1,511 @@
1
+ /* Copyright 2021 Fabien Bavent
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a
4
+ * copy of this software and associated documentation files (the "Software"),
5
+ * to deal in the Software without restriction, including without limitation
6
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ * and/or sell copies of the Software, and to permit persons to whom the
8
+ * Software is furnished to do so, subject to the following conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included
11
+ * in all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ * DEALINGS IN THE SOFTWARE.
20
+ */
21
+ 'use strict';
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.compress = compress;
24
+ exports.requestId = requestId;
25
+ exports.rateLimit = rateLimit;
26
+ exports.cacheControl = cacheControl;
27
+ exports.csrf = csrf;
28
+ exports.securityHeaders = securityHeaders;
29
+ const crypto = require("crypto");
30
+ const zlib = require("zlib");
31
+ // ---------------------------------------------------------------------------
32
+ // Internal helpers
33
+ // ---------------------------------------------------------------------------
34
+ /**
35
+ * Convert a string or Buffer value to a `Buffer`.
36
+ *
37
+ * @param chunk - The data to convert.
38
+ * @param encoding - Character encoding to use when `chunk` is a string.
39
+ * @returns A `Buffer` containing the bytes of `chunk`.
40
+ */
41
+ function toBuffer(chunk, encoding = 'utf8') {
42
+ return Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding);
43
+ }
44
+ /**
45
+ * Response compression middleware.
46
+ *
47
+ * Reads the `Accept-Encoding` request header and transparently compresses the
48
+ * response body using Brotli, gzip, or deflate (tested in that preference
49
+ * order). Responses whose total body is smaller than `threshold` bytes are
50
+ * sent uncompressed to avoid wasting CPU on tiny payloads.
51
+ *
52
+ * The middleware monkey-patches `res.write` and `res.end` so that all
53
+ * downstream code (including `res.json`, `res.send`, and manual writes)
54
+ * passes through the compressor without any changes to handler code.
55
+ *
56
+ * The `Content-Encoding` and `Vary: Accept-Encoding` headers are set
57
+ * automatically. `Content-Length` is removed because the compressed length
58
+ * cannot be known in advance.
59
+ *
60
+ * @param opts - Optional compression settings.
61
+ * @returns An Express-compatible middleware function.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const app = createRouter();
66
+ * app.use(compress()); // at the top — must come first
67
+ * app.get('/api/data', (_req, res) => res.json(bigPayload));
68
+ * ```
69
+ */
70
+ function compress(opts) {
71
+ const threshold = opts?.threshold ?? 1024;
72
+ const brEnabled = opts?.br !== false;
73
+ const brotliQuality = opts?.brotliQuality ?? 4;
74
+ const gzipLevel = opts?.gzipLevel ?? zlib.constants.Z_DEFAULT_COMPRESSION;
75
+ return (req, res, next) => {
76
+ // User-supplied filter.
77
+ if (opts?.filter && !opts.filter(req, res))
78
+ return next();
79
+ const ae = req.headers['accept-encoding'] ?? '';
80
+ // Negotiate encoding: Brotli > gzip > deflate.
81
+ let compressor = null;
82
+ let encoding = '';
83
+ if (brEnabled && /\bbr\b/.test(ae)) {
84
+ compressor = zlib.createBrotliCompress({
85
+ params: { [zlib.constants.BROTLI_PARAM_QUALITY]: brotliQuality },
86
+ });
87
+ encoding = 'br';
88
+ }
89
+ else if (/\bgzip\b/.test(ae)) {
90
+ compressor = zlib.createGzip({ level: gzipLevel });
91
+ encoding = 'gzip';
92
+ }
93
+ else if (/\bdeflate\b/.test(ae)) {
94
+ compressor = zlib.createDeflate({ level: gzipLevel });
95
+ encoding = 'deflate';
96
+ }
97
+ if (!compressor)
98
+ return next();
99
+ const comp = compressor;
100
+ const rawRes = res;
101
+ // Capture original write / end before we override them.
102
+ const origWrite = rawRes.write.bind(rawRes);
103
+ const origEnd = rawRes.end.bind(rawRes);
104
+ // Route compressor output back to the raw socket.
105
+ comp.on('data', (chunk) => { origWrite(chunk); });
106
+ comp.on('end', () => { origEnd(); });
107
+ comp.on('error', (e) => {
108
+ console.error('[compress] stream error:', e.message);
109
+ if (!rawRes.writableEnded)
110
+ origEnd();
111
+ });
112
+ // Buffer incoming data so we can decide compress vs bypass at end().
113
+ const pending = [];
114
+ let totalBytes = 0;
115
+ let decided = false; // true once we committed to compress or bypass
116
+ let doCompress = false;
117
+ /**
118
+ * Commit to compression: flush all buffered pending data to the compressor
119
+ * and mark `decided = true, doCompress = true`.
120
+ *
121
+ * @param andEnd - When `true`, also call `comp.end()` to flush and close
122
+ * the compressor after writing pending data.
123
+ */
124
+ const startCompressing = (andEnd) => {
125
+ decided = true;
126
+ doCompress = true;
127
+ res.setHeader('Content-Encoding', encoding);
128
+ res.setHeader('Vary', 'Accept-Encoding');
129
+ res.removeHeader('Content-Length');
130
+ for (const buf of pending)
131
+ comp.write(buf);
132
+ if (andEnd)
133
+ comp.end();
134
+ };
135
+ /**
136
+ * Commit to bypassing compression (total bytes below threshold).
137
+ * Undoes the tentative headers and writes buffered data directly.
138
+ */
139
+ const skipCompression = () => {
140
+ decided = true;
141
+ doCompress = false;
142
+ comp.destroy();
143
+ if (totalBytes > 0)
144
+ res.setHeader('Content-Length', totalBytes);
145
+ for (const buf of pending)
146
+ origWrite(buf);
147
+ };
148
+ // Override res.write.
149
+ res.write = (chunk, encOrCb, _cb) => {
150
+ const enc = typeof encOrCb === 'string' ? encOrCb : 'utf8';
151
+ const buf = toBuffer(chunk, enc);
152
+ if (decided) {
153
+ // Already committed — write directly to the right destination.
154
+ return doCompress ? comp.write(buf) : origWrite(buf);
155
+ }
156
+ pending.push(buf);
157
+ totalBytes += buf.length;
158
+ // Crossed threshold mid-stream: start compression now.
159
+ if (totalBytes >= threshold)
160
+ startCompressing(false);
161
+ return true;
162
+ };
163
+ // Override res.end.
164
+ res.end = (chunk, encOrCb, _cb) => {
165
+ if (typeof chunk === 'function')
166
+ chunk = undefined;
167
+ if (typeof encOrCb === 'function')
168
+ encOrCb = undefined;
169
+ if (chunk != null) {
170
+ const enc = typeof encOrCb === 'string' ? encOrCb : 'utf8';
171
+ const buf = toBuffer(chunk, enc);
172
+ if (decided) {
173
+ if (doCompress)
174
+ comp.write(buf);
175
+ else
176
+ origWrite(buf);
177
+ }
178
+ else {
179
+ pending.push(buf);
180
+ totalBytes += buf.length;
181
+ }
182
+ }
183
+ if (!decided) {
184
+ if (totalBytes >= threshold)
185
+ startCompressing(true);
186
+ else {
187
+ skipCompression();
188
+ origEnd();
189
+ }
190
+ }
191
+ else if (doCompress) {
192
+ comp.end();
193
+ }
194
+ else {
195
+ origEnd();
196
+ }
197
+ return rawRes;
198
+ };
199
+ next();
200
+ };
201
+ }
202
+ /**
203
+ * Request ID middleware.
204
+ *
205
+ * Attaches a unique identifier to every request as `req.id` and echoes it
206
+ * back in the response header (default: `X-Request-ID`). The ID is taken
207
+ * from the incoming header when `allowFromHeader` is `true` (the default);
208
+ * otherwise a new UUID is generated with `crypto.randomUUID()`.
209
+ *
210
+ * Use `req.id` in log statements and error responses to correlate distributed
211
+ * traces back to a single originating request.
212
+ *
213
+ * @param opts - Optional configuration.
214
+ * @returns An Express-compatible middleware function.
215
+ *
216
+ * @example
217
+ * ```ts
218
+ * app.use(requestId());
219
+ * app.use(logger()); // logger can now include req.id in output
220
+ * app.get('/health', (req, res) => res.json({ id: req.id, status: 'ok' }));
221
+ * ```
222
+ */
223
+ function requestId(opts) {
224
+ const header = (opts?.header ?? 'x-request-id').toLowerCase();
225
+ const allowFromHeader = opts?.allowFromHeader !== false;
226
+ const generator = opts?.generator ?? (() => crypto.randomUUID());
227
+ return (req, res, next) => {
228
+ const incoming = req.headers[header];
229
+ const id = (allowFromHeader && incoming) ? incoming : generator();
230
+ req.id = id;
231
+ res.setHeader(header, id);
232
+ next();
233
+ };
234
+ }
235
+ /**
236
+ * In-memory sliding-window rate limiting middleware.
237
+ *
238
+ * Uses a `Map<key, timestamp[]>` to track request timestamps per client.
239
+ * On each request the list is pruned to the current window, then checked
240
+ * against `max`. No external dependencies are required.
241
+ *
242
+ * **Caveats:**
243
+ * - State is held in memory and is lost on process restart.
244
+ * - Not suitable for multi-process deployments without a shared store.
245
+ *
246
+ * @param opts - Rate-limit configuration. `windowMs` and `max` are required.
247
+ * @returns An Express-compatible middleware function.
248
+ *
249
+ * @example
250
+ * ```ts
251
+ * // Max 100 requests per minute per IP:
252
+ * app.use(rateLimit({ windowMs: 60_000, max: 100 }));
253
+ *
254
+ * // Stricter limit on a specific route:
255
+ * app.post('/auth/login', rateLimit({ windowMs: 60_000, max: 5 }), loginHandler);
256
+ * ```
257
+ */
258
+ function rateLimit(opts) {
259
+ const windowMs = opts.windowMs;
260
+ const max = opts.max;
261
+ const keyBy = opts.keyBy ?? ((req) => req.ip ?? '');
262
+ const message = opts.message ?? 'Too Many Requests';
263
+ const statusCode = opts.statusCode ?? 429;
264
+ const sendHeaders = opts.headers !== false;
265
+ // Map<clientKey, requestTimestamps[]>
266
+ const store = new Map();
267
+ return (req, res, next) => {
268
+ const key = keyBy(req);
269
+ const now = Date.now();
270
+ const windowStart = now - windowMs;
271
+ // Prune expired timestamps for this key.
272
+ const timestamps = (store.get(key) ?? []).filter((t) => t > windowStart);
273
+ timestamps.push(now);
274
+ store.set(key, timestamps);
275
+ const count = timestamps.length;
276
+ const remaining = Math.max(0, max - count);
277
+ // Reset = when the oldest request in the current window will fall out.
278
+ const resetAt = timestamps.length > 0
279
+ ? Math.ceil((timestamps[0] + windowMs) / 1000)
280
+ : Math.ceil((now + windowMs) / 1000);
281
+ if (sendHeaders) {
282
+ res.setHeader('X-RateLimit-Limit', String(max));
283
+ res.setHeader('X-RateLimit-Remaining', String(remaining));
284
+ res.setHeader('X-RateLimit-Reset', String(resetAt));
285
+ }
286
+ if (count > max) {
287
+ res.setHeader('Retry-After', String(Math.ceil(windowMs / 1000)));
288
+ res.statusCode = statusCode;
289
+ res.end(message);
290
+ return;
291
+ }
292
+ next();
293
+ };
294
+ }
295
+ /**
296
+ * Response caching header middleware.
297
+ *
298
+ * Sets `Cache-Control`, and optionally `Expires` and `Vary` response headers
299
+ * based on the supplied options. All directives are optional — only the
300
+ * ones you specify are included in the header value.
301
+ *
302
+ * Mount at the router level for a global default, or on individual routes to
303
+ * apply per-route caching policies.
304
+ *
305
+ * @param opts - Cache policy options.
306
+ * @returns An Express-compatible middleware function.
307
+ *
308
+ * @example
309
+ * ```ts
310
+ * // Global: 5-minute browser cache, CDN-agnostic
311
+ * app.use(cacheControl({ maxAge: 300, public: true }));
312
+ *
313
+ * // Per-route: content-addressed asset, cache forever
314
+ * app.get('/static/app.:hash.js', cacheControl({ maxAge: 31_536_000, immutable: true }), serveStatic('public'));
315
+ *
316
+ * // No caching at all
317
+ * app.use('/api', cacheControl({ noStore: true }));
318
+ * ```
319
+ */
320
+ function cacheControl(opts = {}) {
321
+ // Pre-compute the Cache-Control value — it is the same for every response.
322
+ const directives = [];
323
+ if (opts.private)
324
+ directives.push('private');
325
+ if (opts.public)
326
+ directives.push('public');
327
+ if (opts.noStore)
328
+ directives.push('no-store');
329
+ if (opts.noCache)
330
+ directives.push('no-cache');
331
+ if (opts.mustRevalidate)
332
+ directives.push('must-revalidate');
333
+ if (opts.immutable)
334
+ directives.push('immutable');
335
+ if (opts.maxAge != null)
336
+ directives.push(`max-age=${opts.maxAge}`);
337
+ if (opts.sMaxAge != null)
338
+ directives.push(`s-maxage=${opts.sMaxAge}`);
339
+ const cacheControlValue = directives.join(', ');
340
+ const varyValue = Array.isArray(opts.vary)
341
+ ? opts.vary.join(', ')
342
+ : (opts.vary ?? null);
343
+ return (_req, res, next) => {
344
+ if (cacheControlValue)
345
+ res.setHeader('Cache-Control', cacheControlValue);
346
+ if (opts.maxAge != null) {
347
+ const expires = new Date(Date.now() + opts.maxAge * 1000);
348
+ res.setHeader('Expires', expires.toUTCString());
349
+ }
350
+ if (varyValue)
351
+ res.setHeader('Vary', varyValue);
352
+ next();
353
+ };
354
+ }
355
+ /** HTTP methods that do not mutate server state and require no CSRF check. */
356
+ const SAFE_CSRF_METHODS = new Set(['GET', 'HEAD', 'OPTIONS', 'TRACE']);
357
+ /**
358
+ * CSRF protection middleware (double-submit cookie pattern).
359
+ *
360
+ * On every request the middleware:
361
+ * 1. Reads (or generates) a random 256-bit hex token stored in a cookie.
362
+ * 2. Attaches `req.csrfToken()` so handlers can embed the token in forms /
363
+ * single-page applications.
364
+ * 3. For state-mutating requests (POST / PUT / PATCH / DELETE) it validates
365
+ * that the `X-CSRF-Token` header (or `_csrf` body field) matches the
366
+ * cookie value, responding **403** on mismatch.
367
+ *
368
+ * The cookie is **not** `HttpOnly` so that browser JavaScript can read the
369
+ * value and include it in subsequent AJAX request headers.
370
+ *
371
+ * @param opts - Optional configuration.
372
+ * @returns An Express-compatible middleware function.
373
+ *
374
+ * @example
375
+ * ```ts
376
+ * app.use(csrf());
377
+ * app.get('/form', (req, res) =>
378
+ * res.send(`<input type="hidden" name="_csrf" value="${req.csrfToken!()}">`));
379
+ * app.post('/submit', (req, res) => res.send('ok')); // validated automatically
380
+ * ```
381
+ */
382
+ function csrf(opts) {
383
+ const cookieName = opts?.cookieName ?? '_csrf';
384
+ const headerName = (opts?.headerName ?? 'x-csrf-token').toLowerCase();
385
+ const fieldName = opts?.fieldName ?? '_csrf';
386
+ const secure = opts?.secure ?? false;
387
+ const sameSite = opts?.sameSite ?? 'Strict';
388
+ return (req, res, next) => {
389
+ // Generate or reuse existing token from the incoming cookie.
390
+ const existing = req.cookies?.[cookieName];
391
+ const token = (typeof existing === 'string' && existing.length > 0)
392
+ ? existing
393
+ : crypto.randomBytes(32).toString('hex');
394
+ // Refresh the cookie when we generated a new token.
395
+ if (!existing) {
396
+ let cookieStr = `${cookieName}=${token}; Path=/; SameSite=${sameSite}`;
397
+ if (secure)
398
+ cookieStr += '; Secure';
399
+ // Append without clobbering other Set-Cookie headers.
400
+ const prev = res.getHeader('Set-Cookie');
401
+ if (prev == null)
402
+ res.setHeader('Set-Cookie', cookieStr);
403
+ else if (Array.isArray(prev))
404
+ res.setHeader('Set-Cookie', [...prev, cookieStr]);
405
+ else
406
+ res.setHeader('Set-Cookie', [prev, cookieStr]);
407
+ }
408
+ // Expose helper so handlers can embed the token in responses.
409
+ req.csrfToken = () => token;
410
+ // Safe methods skip validation entirely.
411
+ if (SAFE_CSRF_METHODS.has(req.method ?? ''))
412
+ return next();
413
+ // Validate: prefer header, fall back to parsed body field.
414
+ const submitted = req.headers[headerName] ??
415
+ req.body?.[fieldName] ??
416
+ '';
417
+ if (!submitted || submitted !== token) {
418
+ res.statusCode = 403;
419
+ res.end('Forbidden: invalid CSRF token');
420
+ return;
421
+ }
422
+ next();
423
+ };
424
+ }
425
+ /**
426
+ * Security-hardening response headers middleware.
427
+ *
428
+ * Sets a sensible baseline of HTTP response headers that reduce the attack
429
+ * surface for common web vulnerabilities (clickjacking, MIME sniffing, XSS,
430
+ * etc.). Every header can be individually disabled or overridden.
431
+ *
432
+ * Mount once at the top of the router so all responses are covered:
433
+ *
434
+ * ```ts
435
+ * app.use(securityHeaders());
436
+ * ```
437
+ *
438
+ * **Headers set by default:**
439
+ *
440
+ * | Header | Default value |
441
+ * |---------------------------|--------------------------------------------|
442
+ * | Strict-Transport-Security | max-age=15552000; includeSubDomains |
443
+ * | X-Frame-Options | SAMEORIGIN |
444
+ * | X-Content-Type-Options | nosniff |
445
+ * | Referrer-Policy | strict-origin-when-cross-origin |
446
+ * | Permissions-Policy | geolocation=(), microphone=(), camera=() |
447
+ * | X-XSS-Protection | 0 |
448
+ *
449
+ * @param opts - Per-header overrides. Omit to use all defaults.
450
+ * @returns An Express-compatible middleware function.
451
+ *
452
+ * @example
453
+ * ```ts
454
+ * // Disable HSTS on a plain-HTTP development server:
455
+ * app.use(securityHeaders({ hsts: false }));
456
+ *
457
+ * // Deny all framing (not just same-origin):
458
+ * app.use(securityHeaders({ frameOptions: 'DENY' }));
459
+ *
460
+ * // Custom Permissions-Policy:
461
+ * app.use(securityHeaders({
462
+ * permissionsPolicy: 'geolocation=(), payment=(self)',
463
+ * }));
464
+ * ```
465
+ */
466
+ function securityHeaders(opts) {
467
+ // Pre-compute all header values once at middleware-creation time.
468
+ const headers = [];
469
+ // Strict-Transport-Security
470
+ const hsts = opts?.hsts;
471
+ if (hsts !== false) {
472
+ const h = typeof hsts === 'object' ? hsts : {};
473
+ const maxAge = h.maxAge ?? 15_552_000;
474
+ const subdomain = h.includeSubDomains !== false;
475
+ let value = `max-age=${maxAge}`;
476
+ if (subdomain)
477
+ value += '; includeSubDomains';
478
+ if (h.preload)
479
+ value += '; preload';
480
+ headers.push(['Strict-Transport-Security', value]);
481
+ }
482
+ // X-Frame-Options
483
+ const fo = opts?.frameOptions;
484
+ if (fo !== false) {
485
+ headers.push(['X-Frame-Options', fo ?? 'SAMEORIGIN']);
486
+ }
487
+ // X-Content-Type-Options
488
+ if (opts?.contentTypeOptions !== false) {
489
+ headers.push(['X-Content-Type-Options', 'nosniff']);
490
+ }
491
+ // Referrer-Policy
492
+ const rp = opts?.referrerPolicy;
493
+ if (rp !== false) {
494
+ headers.push(['Referrer-Policy', typeof rp === 'string' ? rp : 'strict-origin-when-cross-origin']);
495
+ }
496
+ // Permissions-Policy
497
+ const pp = opts?.permissionsPolicy;
498
+ if (pp !== false) {
499
+ headers.push(['Permissions-Policy', typeof pp === 'string' ? pp : 'geolocation=(), microphone=(), camera=()']);
500
+ }
501
+ // X-XSS-Protection
502
+ const xxp = opts?.xssProtection;
503
+ if (xxp !== false) {
504
+ headers.push(['X-XSS-Protection', typeof xxp === 'string' ? xxp : '0']);
505
+ }
506
+ return (_req, res, next) => {
507
+ for (const [name, value] of headers)
508
+ res.setHeader(name, value);
509
+ next();
510
+ };
511
+ }
@@ -0,0 +1 @@
1
+ { "application/andrew-inset": ["ez"], "application/applixware": ["aw"], "application/atom+xml": ["atom"], "application/atomcat+xml": ["atomcat"], "application/atomsvc+xml": ["atomsvc"], "application/bdoc": ["bdoc"], "application/ccxml+xml": ["ccxml"], "application/cdmi-capability": ["cdmia"], "application/cdmi-container": ["cdmic"], "application/cdmi-domain": ["cdmid"], "application/cdmi-object": ["cdmio"], "application/cdmi-queue": ["cdmiq"], "application/cu-seeme": ["cu"], "application/dash+xml": ["mpd"], "application/davmount+xml": ["davmount"], "application/docbook+xml": ["dbk"], "application/dssc+der": ["dssc"], "application/dssc+xml": ["xdssc"], "application/ecmascript": ["ecma"], "application/emma+xml": ["emma"], "application/epub+zip": ["epub"], "application/exi": ["exi"], "application/font-tdpfr": ["pfr"], "application/font-woff": [], "application/font-woff2": [], "application/geo+json": ["geojson"], "application/gml+xml": ["gml"], "application/gpx+xml": ["gpx"], "application/gxf": ["gxf"], "application/gzip": ["gz"], "application/hyperstudio": ["stk"], "application/inkml+xml": ["ink", "inkml"], "application/ipfix": ["ipfix"], "application/java-archive": ["jar", "war", "ear"], "application/java-serialized-object": ["ser"], "application/java-vm": ["class"], "application/javascript": ["js", "mjs"], "application/json": ["json", "map"], "application/json5": ["json5"], "application/jsonml+json": ["jsonml"], "application/ld+json": ["jsonld"], "application/lost+xml": ["lostxml"], "application/mac-binhex40": ["hqx"], "application/mac-compactpro": ["cpt"], "application/mads+xml": ["mads"], "application/manifest+json": ["webmanifest"], "application/marc": ["mrc"], "application/marcxml+xml": ["mrcx"], "application/mathematica": ["ma", "nb", "mb"], "application/mathml+xml": ["mathml"], "application/mbox": ["mbox"], "application/mediaservercontrol+xml": ["mscml"], "application/metalink+xml": ["metalink"], "application/metalink4+xml": ["meta4"], "application/mets+xml": ["mets"], "application/mods+xml": ["mods"], "application/mp21": ["m21", "mp21"], "application/mp4": ["mp4s", "m4p"], "application/msword": ["doc", "dot"], "application/mxf": ["mxf"], "application/octet-stream": ["bin", "dms", "lrf", "mar", "so", "dist", "distz", "pkg", "bpk", "dump", "elc", "deploy", "exe", "dll", "deb", "dmg", "iso", "img", "msi", "msp", "msm", "buffer"], "application/oda": ["oda"], "application/oebps-package+xml": ["opf"], "application/ogg": ["ogx"], "application/omdoc+xml": ["omdoc"], "application/onenote": ["onetoc", "onetoc2", "onetmp", "onepkg"], "application/oxps": ["oxps"], "application/patch-ops-error+xml": ["xer"], "application/pdf": ["pdf"], "application/pgp-encrypted": ["pgp"], "application/pgp-signature": ["asc", "sig"], "application/pics-rules": ["prf"], "application/pkcs10": ["p10"], "application/pkcs7-mime": ["p7m", "p7c"], "application/pkcs7-signature": ["p7s"], "application/pkcs8": ["p8"], "application/pkix-attr-cert": ["ac"], "application/pkix-cert": ["cer"], "application/pkix-crl": ["crl"], "application/pkix-pkipath": ["pkipath"], "application/pkixcmp": ["pki"], "application/pls+xml": ["pls"], "application/postscript": ["ai", "eps", "ps"], "application/prs.cww": ["cww"], "application/pskc+xml": ["pskcxml"], "application/raml+yaml": ["raml"], "application/rdf+xml": ["rdf"], "application/reginfo+xml": ["rif"], "application/relax-ng-compact-syntax": ["rnc"], "application/resource-lists+xml": ["rl"], "application/resource-lists-diff+xml": ["rld"], "application/rls-services+xml": ["rs"], "application/rpki-ghostbusters": ["gbr"], "application/rpki-manifest": ["mft"], "application/rpki-roa": ["roa"], "application/rsd+xml": ["rsd"], "application/rss+xml": ["rss"], "application/rtf": ["rtf"], "application/sbml+xml": ["sbml"], "application/scvp-cv-request": ["scq"], "application/scvp-cv-response": ["scs"], "application/scvp-vp-request": ["spq"], "application/scvp-vp-response": ["spp"], "application/sdp": ["sdp"], "application/set-payment-initiation": ["setpay"], "application/set-registration-initiation": ["setreg"], "application/shf+xml": ["shf"], "application/smil+xml": ["smi", "smil"], "application/sparql-query": ["rq"], "application/sparql-results+xml": ["srx"], "application/srgs": ["gram"], "application/srgs+xml": ["grxml"], "application/sru+xml": ["sru"], "application/ssdl+xml": ["ssdl"], "application/ssml+xml": ["ssml"], "application/tei+xml": ["tei", "teicorpus"], "application/thraud+xml": ["tfi"], "application/timestamped-data": ["tsd"], "application/vnd.3gpp.pic-bw-large": ["plb"], "application/vnd.3gpp.pic-bw-small": ["psb"], "application/vnd.3gpp.pic-bw-var": ["pvb"], "application/vnd.3gpp2.tcap": ["tcap"], "application/vnd.3m.post-it-notes": ["pwn"], "application/vnd.accpac.simply.aso": ["aso"], "application/vnd.accpac.simply.imp": ["imp"], "application/vnd.acucobol": ["acu"], "application/vnd.acucorp": ["atc", "acutc"], "application/vnd.adobe.air-application-installer-package+zip": ["air"], "application/vnd.adobe.formscentral.fcdt": ["fcdt"], "application/vnd.adobe.fxp": ["fxp", "fxpl"], "application/vnd.adobe.xdp+xml": ["xdp"], "application/vnd.adobe.xfdf": ["xfdf"], "application/vnd.ahead.space": ["ahead"], "application/vnd.airzip.filesecure.azf": ["azf"], "application/vnd.airzip.filesecure.azs": ["azs"], "application/vnd.amazon.ebook": ["azw"], "application/vnd.americandynamics.acc": ["acc"], "application/vnd.amiga.ami": ["ami"], "application/vnd.android.package-archive": ["apk"], "application/vnd.anser-web-certificate-issue-initiation": ["cii"], "application/vnd.anser-web-funds-transfer-initiation": ["fti"], "application/vnd.antix.game-component": ["atx"], "application/vnd.apple.installer+xml": ["mpkg"], "application/vnd.apple.mpegurl": ["m3u8"], "application/vnd.apple.pkpass": ["pkpass"], "application/vnd.aristanetworks.swi": ["swi"], "application/vnd.astraea-software.iota": ["iota"], "application/vnd.audiograph": ["aep"], "application/vnd.blueice.multipass": ["mpm"], "application/vnd.bmi": ["bmi"], "application/vnd.businessobjects": ["rep"], "application/vnd.chemdraw+xml": ["cdxml"], "application/vnd.chipnuts.karaoke-mmd": ["mmd"], "application/vnd.cinderella": ["cdy"], "application/vnd.claymore": ["cla"], "application/vnd.cloanto.rp9": ["rp9"], "application/vnd.clonk.c4group": ["c4g", "c4d", "c4f", "c4p", "c4u"], "application/vnd.cluetrust.cartomobile-config": ["c11amc"], "application/vnd.cluetrust.cartomobile-config-pkg": ["c11amz"], "application/vnd.commonspace": ["csp"], "application/vnd.contact.cmsg": ["cdbcmsg"], "application/vnd.cosmocaller": ["cmc"], "application/vnd.crick.clicker": ["clkx"], "application/vnd.crick.clicker.keyboard": ["clkk"], "application/vnd.crick.clicker.palette": ["clkp"], "application/vnd.crick.clicker.template": ["clkt"], "application/vnd.crick.clicker.wordbank": ["clkw"], "application/vnd.criticaltools.wbs+xml": ["wbs"], "application/vnd.ctc-posml": ["pml"], "application/vnd.cups-ppd": ["ppd"], "application/vnd.curl.car": ["car"], "application/vnd.curl.pcurl": ["pcurl"], "application/vnd.dart": ["dart"], "application/vnd.data-vision.rdz": ["rdz"], "application/vnd.dece.data": ["uvf", "uvvf", "uvd", "uvvd"], "application/vnd.dece.ttml+xml": ["uvt", "uvvt"], "application/vnd.dece.unspecified": ["uvx", "uvvx"], "application/vnd.dece.zip": ["uvz", "uvvz"], "application/vnd.denovo.fcselayout-link": ["fe_launch"], "application/vnd.dna": ["dna"], "application/vnd.dolby.mlp": ["mlp"], "application/vnd.dpgraph": ["dpg"], "application/vnd.dreamfactory": ["dfac"], "application/vnd.ds-keypoint": ["kpxx"], "application/vnd.dvb.ait": ["ait"], "application/vnd.dvb.service": ["svc"], "application/vnd.dynageo": ["geo"], "application/vnd.ecowin.chart": ["mag"], "application/vnd.enliven": ["nml"], "application/vnd.epson.esf": ["esf"], "application/vnd.epson.msf": ["msf"], "application/vnd.epson.quickanime": ["qam"], "application/vnd.epson.salt": ["slt"], "application/vnd.epson.ssf": ["ssf"], "application/vnd.eszigno3+xml": ["es3", "et3"], "application/vnd.ezpix-album": ["ez2"], "application/vnd.ezpix-package": ["ez3"], "application/vnd.fdf": ["fdf"], "application/vnd.fdsn.mseed": ["mseed"], "application/vnd.fdsn.seed": ["seed", "dataless"], "application/vnd.flographit": ["gph"], "application/vnd.fluxtime.clip": ["ftc"], "application/vnd.framemaker": ["fm", "frame", "maker", "book"], "application/vnd.frogans.fnc": ["fnc"], "application/vnd.frogans.ltf": ["ltf"], "application/vnd.fsc.weblaunch": ["fsc"], "application/vnd.fujitsu.oasys": ["oas"], "application/vnd.fujitsu.oasys2": ["oa2"], "application/vnd.fujitsu.oasys3": ["oa3"], "application/vnd.fujitsu.oasysgp": ["fg5"], "application/vnd.fujitsu.oasysprs": ["bh2"], "application/vnd.fujixerox.ddd": ["ddd"], "application/vnd.fujixerox.docuworks": ["xdw"], "application/vnd.fujixerox.docuworks.binder": ["xbd"], "application/vnd.fuzzysheet": ["fzs"], "application/vnd.genomatix.tuxedo": ["txd"], "application/vnd.geogebra.file": ["ggb"], "application/vnd.geogebra.tool": ["ggt"], "application/vnd.geometry-explorer": ["gex", "gre"], "application/vnd.geonext": ["gxt"], "application/vnd.geoplan": ["g2w"], "application/vnd.geospace": ["g3w"], "application/vnd.gmx": ["gmx"], "application/vnd.google-apps.document": ["gdoc"], "application/vnd.google-apps.presentation": ["gslides"], "application/vnd.google-apps.spreadsheet": ["gsheet"], "application/vnd.google-earth.kml+xml": ["kml"], "application/vnd.google-earth.kmz": ["kmz"], "application/vnd.grafeq": ["gqf", "gqs"], "application/vnd.groove-account": ["gac"], "application/vnd.groove-help": ["ghf"], "application/vnd.groove-identity-message": ["gim"], "application/vnd.groove-injector": ["grv"], "application/vnd.groove-tool-message": ["gtm"], "application/vnd.groove-tool-template": ["tpl"], "application/vnd.groove-vcard": ["vcg"], "application/vnd.hal+xml": ["hal"], "application/vnd.handheld-entertainment+xml": ["zmm"], "application/vnd.hbci": ["hbci"], "application/vnd.hhe.lesson-player": ["les"], "application/vnd.hp-hpgl": ["hpgl"], "application/vnd.hp-hpid": ["hpid"], "application/vnd.hp-hps": ["hps"], "application/vnd.hp-jlyt": ["jlt"], "application/vnd.hp-pcl": ["pcl"], "application/vnd.hp-pclxl": ["pclxl"], "application/vnd.hydrostatix.sof-data": ["sfd-hdstx"], "application/vnd.ibm.minipay": ["mpy"], "application/vnd.ibm.modcap": ["afp", "listafp", "list3820"], "application/vnd.ibm.rights-management": ["irm"], "application/vnd.ibm.secure-container": ["sc"], "application/vnd.iccprofile": ["icc", "icm"], "application/vnd.igloader": ["igl"], "application/vnd.immervision-ivp": ["ivp"], "application/vnd.immervision-ivu": ["ivu"], "application/vnd.insors.igm": ["igm"], "application/vnd.intercon.formnet": ["xpw", "xpx"], "application/vnd.intergeo": ["i2g"], "application/vnd.intu.qbo": ["qbo"], "application/vnd.intu.qfx": ["qfx"], "application/vnd.ipunplugged.rcprofile": ["rcprofile"], "application/vnd.irepository.package+xml": ["irp"], "application/vnd.is-xpr": ["xpr"], "application/vnd.isac.fcs": ["fcs"], "application/vnd.jam": ["jam"], "application/vnd.jcp.javame.midlet-rms": ["rms"], "application/vnd.jisp": ["jisp"], "application/vnd.joost.joda-archive": ["joda"], "application/vnd.kahootz": ["ktz", "ktr"], "application/vnd.kde.karbon": ["karbon"], "application/vnd.kde.kchart": ["chrt"], "application/vnd.kde.kformula": ["kfo"], "application/vnd.kde.kivio": ["flw"], "application/vnd.kde.kontour": ["kon"], "application/vnd.kde.kpresenter": ["kpr", "kpt"], "application/vnd.kde.kspread": ["ksp"], "application/vnd.kde.kword": ["kwd", "kwt"], "application/vnd.kenameaapp": ["htke"], "application/vnd.kidspiration": ["kia"], "application/vnd.kinar": ["kne", "knp"], "application/vnd.koan": ["skp", "skd", "skt", "skm"], "application/vnd.kodak-descriptor": ["sse"], "application/vnd.las.las+xml": ["lasxml"], "application/vnd.llamagraphics.life-balance.desktop": ["lbd"], "application/vnd.llamagraphics.life-balance.exchange+xml": ["lbe"], "application/vnd.lotus-1-2-3": ["123"], "application/vnd.lotus-approach": ["apr"], "application/vnd.lotus-freelance": ["pre"], "application/vnd.lotus-notes": ["nsf"], "application/vnd.lotus-organizer": ["org"], "application/vnd.lotus-screencam": ["scm"], "application/vnd.lotus-wordpro": ["lwp"], "application/vnd.macports.portpkg": ["portpkg"], "application/vnd.mcd": ["mcd"], "application/vnd.medcalcdata": ["mc1"], "application/vnd.mediastation.cdkey": ["cdkey"], "application/vnd.mfer": ["mwf"], "application/vnd.mfmp": ["mfm"], "application/vnd.micrografx.flo": ["flo"], "application/vnd.micrografx.igx": ["igx"], "application/vnd.mif": ["mif"], "application/vnd.mobius.daf": ["daf"], "application/vnd.mobius.dis": ["dis"], "application/vnd.mobius.mbk": ["mbk"], "application/vnd.mobius.mqy": ["mqy"], "application/vnd.mobius.msl": ["msl"], "application/vnd.mobius.plc": ["plc"], "application/vnd.mobius.txf": ["txf"], "application/vnd.mophun.application": ["mpn"], "application/vnd.mophun.certificate": ["mpc"], "application/vnd.mozilla.xul+xml": ["xul"], "application/vnd.ms-artgalry": ["cil"], "application/vnd.ms-cab-compressed": ["cab"], "application/vnd.ms-excel": ["xls", "xlm", "xla", "xlc", "xlt", "xlw"], "application/vnd.ms-excel.addin.macroenabled.12": ["xlam"], "application/vnd.ms-excel.sheet.binary.macroenabled.12": ["xlsb"], "application/vnd.ms-excel.sheet.macroenabled.12": ["xlsm"], "application/vnd.ms-excel.template.macroenabled.12": ["xltm"], "application/vnd.ms-fontobject": ["eot"], "application/vnd.ms-htmlhelp": ["chm"], "application/vnd.ms-ims": ["ims"], "application/vnd.ms-lrm": ["lrm"], "application/vnd.ms-officetheme": ["thmx"], "application/vnd.ms-outlook": ["msg"], "application/vnd.ms-pki.seccat": ["cat"], "application/vnd.ms-pki.stl": ["stl"], "application/vnd.ms-powerpoint": ["ppt", "pps", "pot"], "application/vnd.ms-powerpoint.addin.macroenabled.12": ["ppam"], "application/vnd.ms-powerpoint.presentation.macroenabled.12": ["pptm"], "application/vnd.ms-powerpoint.slide.macroenabled.12": ["sldm"], "application/vnd.ms-powerpoint.slideshow.macroenabled.12": ["ppsm"], "application/vnd.ms-powerpoint.template.macroenabled.12": ["potm"], "application/vnd.ms-project": ["mpp", "mpt"], "application/vnd.ms-word.document.macroenabled.12": ["docm"], "application/vnd.ms-word.template.macroenabled.12": ["dotm"], "application/vnd.ms-works": ["wps", "wks", "wcm", "wdb"], "application/vnd.ms-wpl": ["wpl"], "application/vnd.ms-xpsdocument": ["xps"], "application/vnd.mseq": ["mseq"], "application/vnd.musician": ["mus"], "application/vnd.muvee.style": ["msty"], "application/vnd.mynfc": ["taglet"], "application/vnd.neurolanguage.nlu": ["nlu"], "application/vnd.nitf": ["ntf", "nitf"], "application/vnd.noblenet-directory": ["nnd"], "application/vnd.noblenet-sealer": ["nns"], "application/vnd.noblenet-web": ["nnw"], "application/vnd.nokia.n-gage.data": ["ngdat"], "application/vnd.nokia.n-gage.symbian.install": ["n-gage"], "application/vnd.nokia.radio-preset": ["rpst"], "application/vnd.nokia.radio-presets": ["rpss"], "application/vnd.novadigm.edm": ["edm"], "application/vnd.novadigm.edx": ["edx"], "application/vnd.novadigm.ext": ["ext"], "application/vnd.oasis.opendocument.chart": ["odc"], "application/vnd.oasis.opendocument.chart-template": ["otc"], "application/vnd.oasis.opendocument.database": ["odb"], "application/vnd.oasis.opendocument.formula": ["odf"], "application/vnd.oasis.opendocument.formula-template": ["odft"], "application/vnd.oasis.opendocument.graphics": ["odg"], "application/vnd.oasis.opendocument.graphics-template": ["otg"], "application/vnd.oasis.opendocument.image": ["odi"], "application/vnd.oasis.opendocument.image-template": ["oti"], "application/vnd.oasis.opendocument.presentation": ["odp"], "application/vnd.oasis.opendocument.presentation-template": ["otp"], "application/vnd.oasis.opendocument.spreadsheet": ["ods"], "application/vnd.oasis.opendocument.spreadsheet-template": ["ots"], "application/vnd.oasis.opendocument.text": ["odt"], "application/vnd.oasis.opendocument.text-master": ["odm"], "application/vnd.oasis.opendocument.text-template": ["ott"], "application/vnd.oasis.opendocument.text-web": ["oth"], "application/vnd.olpc-sugar": ["xo"], "application/vnd.oma.dd2+xml": ["dd2"], "application/vnd.openofficeorg.extension": ["oxt"], "application/vnd.openxmlformats-officedocument.presentationml.presentation": ["pptx"], "application/vnd.openxmlformats-officedocument.presentationml.slide": ["sldx"], "application/vnd.openxmlformats-officedocument.presentationml.slideshow": ["ppsx"], "application/vnd.openxmlformats-officedocument.presentationml.template": ["potx"], "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": ["xlsx"], "application/vnd.openxmlformats-officedocument.spreadsheetml.template": ["xltx"], "application/vnd.openxmlformats-officedocument.wordprocessingml.document": ["docx"], "application/vnd.openxmlformats-officedocument.wordprocessingml.template": ["dotx"], "application/vnd.osgeo.mapguide.package": ["mgp"], "application/vnd.osgi.dp": ["dp"], "application/vnd.osgi.subsystem": ["esa"], "application/vnd.palm": ["pdb", "pqa", "oprc"], "application/vnd.pawaafile": ["paw"], "application/vnd.pg.format": ["str"], "application/vnd.pg.osasli": ["ei6"], "application/vnd.picsel": ["efif"], "application/vnd.pmi.widget": ["wg"], "application/vnd.pocketlearn": ["plf"], "application/vnd.powerbuilder6": ["pbd"], "application/vnd.previewsystems.box": ["box"], "application/vnd.proteus.magazine": ["mgz"], "application/vnd.publishare-delta-tree": ["qps"], "application/vnd.pvi.ptid1": ["ptid"], "application/vnd.quark.quarkxpress": ["qxd", "qxt", "qwd", "qwt", "qxl", "qxb"], "application/vnd.realvnc.bed": ["bed"], "application/vnd.recordare.musicxml": ["mxl"], "application/vnd.recordare.musicxml+xml": ["musicxml"], "application/vnd.rig.cryptonote": ["cryptonote"], "application/vnd.rim.cod": ["cod"], "application/vnd.rn-realmedia": ["rm"], "application/vnd.rn-realmedia-vbr": ["rmvb"], "application/vnd.route66.link66+xml": ["link66"], "application/vnd.sailingtracker.track": ["st"], "application/vnd.seemail": ["see"], "application/vnd.sema": ["sema"], "application/vnd.semd": ["semd"], "application/vnd.semf": ["semf"], "application/vnd.shana.informed.formdata": ["ifm"], "application/vnd.shana.informed.formtemplate": ["itp"], "application/vnd.shana.informed.interchange": ["iif"], "application/vnd.shana.informed.package": ["ipk"], "application/vnd.simtech-mindmapper": ["twd", "twds"], "application/vnd.smaf": ["mmf"], "application/vnd.smart.teacher": ["teacher"], "application/vnd.solent.sdkm+xml": ["sdkm", "sdkd"], "application/vnd.spotfire.dxp": ["dxp"], "application/vnd.spotfire.sfs": ["sfs"], "application/vnd.stardivision.calc": ["sdc"], "application/vnd.stardivision.draw": ["sda"], "application/vnd.stardivision.impress": ["sdd"], "application/vnd.stardivision.math": ["smf"], "application/vnd.stardivision.writer": ["sdw", "vor"], "application/vnd.stardivision.writer-global": ["sgl"], "application/vnd.stepmania.package": ["smzip"], "application/vnd.stepmania.stepchart": ["sm"], "application/vnd.sun.wadl+xml": ["wadl"], "application/vnd.sun.xml.calc": ["sxc"], "application/vnd.sun.xml.calc.template": ["stc"], "application/vnd.sun.xml.draw": ["sxd"], "application/vnd.sun.xml.draw.template": ["std"], "application/vnd.sun.xml.impress": ["sxi"], "application/vnd.sun.xml.impress.template": ["sti"], "application/vnd.sun.xml.math": ["sxm"], "application/vnd.sun.xml.writer": ["sxw"], "application/vnd.sun.xml.writer.global": ["sxg"], "application/vnd.sun.xml.writer.template": ["stw"], "application/vnd.sus-calendar": ["sus", "susp"], "application/vnd.svd": ["svd"], "application/vnd.symbian.install": ["sis", "sisx"], "application/vnd.syncml+xml": ["xsm"], "application/vnd.syncml.dm+wbxml": ["bdm"], "application/vnd.syncml.dm+xml": ["xdm"], "application/vnd.tao.intent-module-archive": ["tao"], "application/vnd.tcpdump.pcap": ["pcap", "cap", "dmp"], "application/vnd.tmobile-livetv": ["tmo"], "application/vnd.trid.tpt": ["tpt"], "application/vnd.triscape.mxs": ["mxs"], "application/vnd.trueapp": ["tra"], "application/vnd.ufdl": ["ufd", "ufdl"], "application/vnd.uiq.theme": ["utz"], "application/vnd.umajin": ["umj"], "application/vnd.unity": ["unityweb"], "application/vnd.uoml+xml": ["uoml"], "application/vnd.vcx": ["vcx"], "application/vnd.visio": ["vsd", "vst", "vss", "vsw"], "application/vnd.visionary": ["vis"], "application/vnd.vsf": ["vsf"], "application/vnd.wap.wbxml": ["wbxml"], "application/vnd.wap.wmlc": ["wmlc"], "application/vnd.wap.wmlscriptc": ["wmlsc"], "application/vnd.webturbo": ["wtb"], "application/vnd.wolfram.player": ["nbp"], "application/vnd.wordperfect": ["wpd"], "application/vnd.wqd": ["wqd"], "application/vnd.wt.stf": ["stf"], "application/vnd.xara": ["xar"], "application/vnd.xfdl": ["xfdl"], "application/vnd.yamaha.hv-dic": ["hvd"], "application/vnd.yamaha.hv-script": ["hvs"], "application/vnd.yamaha.hv-voice": ["hvp"], "application/vnd.yamaha.openscoreformat": ["osf"], "application/vnd.yamaha.openscoreformat.osfpvg+xml": ["osfpvg"], "application/vnd.yamaha.smaf-audio": ["saf"], "application/vnd.yamaha.smaf-phrase": ["spf"], "application/vnd.yellowriver-custom-menu": ["cmp"], "application/vnd.zul": ["zir", "zirz"], "application/vnd.zzazz.deck+xml": ["zaz"], "application/voicexml+xml": ["vxml"], "application/wasm": ["wasm"], "application/widget": ["wgt"], "application/winhlp": ["hlp"], "application/wsdl+xml": ["wsdl"], "application/wspolicy+xml": ["wspolicy"], "application/x-7z-compressed": ["7z"], "application/x-abiword": ["abw"], "application/x-ace-compressed": ["ace"], "application/x-apple-diskimage": [], "application/x-arj": ["arj"], "application/x-authorware-bin": ["aab", "x32", "u32", "vox"], "application/x-authorware-map": ["aam"], "application/x-authorware-seg": ["aas"], "application/x-bcpio": ["bcpio"], "application/x-bdoc": [], "application/x-bittorrent": ["torrent"], "application/x-blorb": ["blb", "blorb"], "application/x-bzip": ["bz"], "application/x-bzip2": ["bz2", "boz"], "application/x-cbr": ["cbr", "cba", "cbt", "cbz", "cb7"], "application/x-cdlink": ["vcd"], "application/x-cfs-compressed": ["cfs"], "application/x-chat": ["chat"], "application/x-chess-pgn": ["pgn"], "application/x-chrome-extension": ["crx"], "application/x-cocoa": ["cco"], "application/x-conference": ["nsc"], "application/x-cpio": ["cpio"], "application/x-csh": ["csh"], "application/x-debian-package": ["udeb"], "application/x-dgc-compressed": ["dgc"], "application/x-director": ["dir", "dcr", "dxr", "cst", "cct", "cxt", "w3d", "fgd", "swa"], "application/x-doom": ["wad"], "application/x-dtbncx+xml": ["ncx"], "application/x-dtbook+xml": ["dtb"], "application/x-dtbresource+xml": ["res"], "application/x-dvi": ["dvi"], "application/x-envoy": ["evy"], "application/x-eva": ["eva"], "application/x-font-bdf": ["bdf"], "application/x-font-ghostscript": ["gsf"], "application/x-font-linux-psf": ["psf"], "application/x-font-pcf": ["pcf"], "application/x-font-snf": ["snf"], "application/x-font-type1": ["pfa", "pfb", "pfm", "afm"], "application/x-freearc": ["arc"], "application/x-futuresplash": ["spl"], "application/x-gca-compressed": ["gca"], "application/x-glulx": ["ulx"], "application/x-gnumeric": ["gnumeric"], "application/x-gramps-xml": ["gramps"], "application/x-gtar": ["gtar"], "application/x-hdf": ["hdf"], "application/x-httpd-php": ["php"], "application/x-install-instructions": ["install"], "application/x-iso9660-image": [], "application/x-java-archive-diff": ["jardiff"], "application/x-java-jnlp-file": ["jnlp"], "application/x-latex": ["latex"], "application/x-lua-bytecode": ["luac"], "application/x-lzh-compressed": ["lzh", "lha"], "application/x-makeself": ["run"], "application/x-mie": ["mie"], "application/x-mobipocket-ebook": ["prc", "mobi"], "application/x-ms-application": ["application"], "application/x-ms-shortcut": ["lnk"], "application/x-ms-wmd": ["wmd"], "application/x-ms-wmz": ["wmz"], "application/x-ms-xbap": ["xbap"], "application/x-msaccess": ["mdb"], "application/x-msbinder": ["obd"], "application/x-mscardfile": ["crd"], "application/x-msclip": ["clp"], "application/x-msdos-program": [], "application/x-msdownload": ["com", "bat"], "application/x-msmediaview": ["mvb", "m13", "m14"], "application/x-msmetafile": ["wmf", "emf", "emz"], "application/x-msmoney": ["mny"], "application/x-mspublisher": ["pub"], "application/x-msschedule": ["scd"], "application/x-msterminal": ["trm"], "application/x-mswrite": ["wri"], "application/x-netcdf": ["nc", "cdf"], "application/x-ns-proxy-autoconfig": ["pac"], "application/x-nzb": ["nzb"], "application/x-perl": ["pl", "pm"], "application/x-pilot": [], "application/x-pkcs12": ["p12", "pfx"], "application/x-pkcs7-certificates": ["p7b", "spc"], "application/x-pkcs7-certreqresp": ["p7r"], "application/x-rar-compressed": ["rar"], "application/x-redhat-package-manager": ["rpm"], "application/x-research-info-systems": ["ris"], "application/x-sea": ["sea"], "application/x-sh": ["sh"], "application/x-shar": ["shar"], "application/x-shockwave-flash": ["swf"], "application/x-silverlight-app": ["xap"], "application/x-sql": ["sql"], "application/x-stuffit": ["sit"], "application/x-stuffitx": ["sitx"], "application/x-subrip": ["srt"], "application/x-sv4cpio": ["sv4cpio"], "application/x-sv4crc": ["sv4crc"], "application/x-t3vm-image": ["t3"], "application/x-tads": ["gam"], "application/x-tar": ["tar"], "application/x-tcl": ["tcl", "tk"], "application/x-tex": ["tex"], "application/x-tex-tfm": ["tfm"], "application/x-texinfo": ["texinfo", "texi"], "application/x-tgif": ["obj"], "application/x-ustar": ["ustar"], "application/x-virtualbox-hdd": ["hdd"], "application/x-virtualbox-ova": ["ova"], "application/x-virtualbox-ovf": ["ovf"], "application/x-virtualbox-vbox": ["vbox"], "application/x-virtualbox-vbox-extpack": ["vbox-extpack"], "application/x-virtualbox-vdi": ["vdi"], "application/x-virtualbox-vhd": ["vhd"], "application/x-virtualbox-vmdk": ["vmdk"], "application/x-wais-source": ["src"], "application/x-web-app-manifest+json": ["webapp"], "application/x-x509-ca-cert": ["der", "crt", "pem"], "application/x-xfig": ["fig"], "application/x-xliff+xml": ["xlf"], "application/x-xpinstall": ["xpi"], "application/x-xz": ["xz"], "application/x-zmachine": ["z1", "z2", "z3", "z4", "z5", "z6", "z7", "z8"], "application/xaml+xml": ["xaml"], "application/xcap-diff+xml": ["xdf"], "application/xenc+xml": ["xenc"], "application/xhtml+xml": ["xhtml", "xht"], "application/xml": ["xml", "xsl", "xsd", "rng"], "application/xml-dtd": ["dtd"], "application/xop+xml": ["xop"], "application/xproc+xml": ["xpl"], "application/xslt+xml": ["xslt"], "application/xspf+xml": ["xspf"], "application/xv+xml": ["mxml", "xhvml", "xvml", "xvm"], "application/yang": ["yang"], "application/yin+xml": ["yin"], "application/zip": ["zip"], "audio/3gpp": [], "audio/adpcm": ["adp"], "audio/basic": ["au", "snd"], "audio/midi": ["mid", "midi", "kar", "rmi"], "audio/mp3": [], "audio/mp4": ["m4a", "mp4a"], "audio/mpeg": ["mpga", "mp2", "mp2a", "mp3", "m2a", "m3a"], "audio/ogg": ["oga", "ogg", "spx"], "audio/s3m": ["s3m"], "audio/silk": ["sil"], "audio/vnd.dece.audio": ["uva", "uvva"], "audio/vnd.digital-winds": ["eol"], "audio/vnd.dra": ["dra"], "audio/vnd.dts": ["dts"], "audio/vnd.dts.hd": ["dtshd"], "audio/vnd.lucent.voice": ["lvp"], "audio/vnd.ms-playready.media.pya": ["pya"], "audio/vnd.nuera.ecelp4800": ["ecelp4800"], "audio/vnd.nuera.ecelp7470": ["ecelp7470"], "audio/vnd.nuera.ecelp9600": ["ecelp9600"], "audio/vnd.rip": ["rip"], "audio/wav": ["wav"], "audio/wave": [], "audio/webm": ["weba"], "audio/x-aac": ["aac"], "audio/x-aiff": ["aif", "aiff", "aifc"], "audio/x-caf": ["caf"], "audio/x-flac": ["flac"], "audio/x-m4a": [], "audio/x-matroska": ["mka"], "audio/x-mpegurl": ["m3u"], "audio/x-ms-wax": ["wax"], "audio/x-ms-wma": ["wma"], "audio/x-pn-realaudio": ["ram", "ra"], "audio/x-pn-realaudio-plugin": ["rmp"], "audio/x-realaudio": [], "audio/x-wav": [], "audio/xm": ["xm"], "chemical/x-cdx": ["cdx"], "chemical/x-cif": ["cif"], "chemical/x-cmdf": ["cmdf"], "chemical/x-cml": ["cml"], "chemical/x-csml": ["csml"], "chemical/x-xyz": ["xyz"], "font/collection": ["ttc"], "font/otf": ["otf"], "font/ttf": ["ttf"], "font/woff": ["woff"], "font/woff2": ["woff2"], "image/apng": ["apng"], "image/bmp": ["bmp"], "image/cgm": ["cgm"], "image/g3fax": ["g3"], "image/gif": ["gif"], "image/ief": ["ief"], "image/jp2": ["jp2", "jpg2"], "image/jpeg": ["jpeg", "jpg", "jpe"], "image/jpm": ["jpm"], "image/jpx": ["jpx", "jpf"], "image/ktx": ["ktx"], "image/png": ["png"], "image/prs.btif": ["btif"], "image/sgi": ["sgi"], "image/svg+xml": ["svg", "svgz"], "image/tiff": ["tiff", "tif"], "image/vnd.adobe.photoshop": ["psd"], "image/vnd.dece.graphic": ["uvi", "uvvi", "uvg", "uvvg"], "image/vnd.djvu": ["djvu", "djv"], "image/vnd.dvb.subtitle": [], "image/vnd.dwg": ["dwg"], "image/vnd.dxf": ["dxf"], "image/vnd.fastbidsheet": ["fbs"], "image/vnd.fpx": ["fpx"], "image/vnd.fst": ["fst"], "image/vnd.fujixerox.edmics-mmr": ["mmr"], "image/vnd.fujixerox.edmics-rlc": ["rlc"], "image/vnd.ms-modi": ["mdi"], "image/vnd.ms-photo": ["wdp"], "image/vnd.net-fpx": ["npx"], "image/vnd.wap.wbmp": ["wbmp"], "image/vnd.xiff": ["xif"], "image/webp": ["webp"], "image/x-3ds": ["3ds"], "image/x-cmu-raster": ["ras"], "image/x-cmx": ["cmx"], "image/x-freehand": ["fh", "fhc", "fh4", "fh5", "fh7"], "image/x-icon": ["ico"], "image/x-jng": ["jng"], "image/x-mrsid-image": ["sid"], "image/x-ms-bmp": [], "image/x-pcx": ["pcx"], "image/x-pict": ["pic", "pct"], "image/x-portable-anymap": ["pnm"], "image/x-portable-bitmap": ["pbm"], "image/x-portable-graymap": ["pgm"], "image/x-portable-pixmap": ["ppm"], "image/x-rgb": ["rgb"], "image/x-tga": ["tga"], "image/x-xbitmap": ["xbm"], "image/x-xpixmap": ["xpm"], "image/x-xwindowdump": ["xwd"], "message/rfc822": ["eml", "mime"], "model/gltf+json": ["gltf"], "model/gltf-binary": ["glb"], "model/iges": ["igs", "iges"], "model/mesh": ["msh", "mesh", "silo"], "model/vnd.collada+xml": ["dae"], "model/vnd.dwf": ["dwf"], "model/vnd.gdl": ["gdl"], "model/vnd.gtw": ["gtw"], "model/vnd.mts": ["mts"], "model/vnd.vtu": ["vtu"], "model/vrml": ["wrl", "vrml"], "model/x3d+binary": ["x3db", "x3dbz"], "model/x3d+vrml": ["x3dv", "x3dvz"], "model/x3d+xml": ["x3d", "x3dz"], "text/cache-manifest": ["appcache", "manifest"], "text/calendar": ["ics", "ifb"], "text/coffeescript": ["coffee", "litcoffee"], "text/css": ["css"], "text/csv": ["csv"], "text/hjson": ["hjson"], "text/html": ["html", "htm", "shtml"], "text/jade": ["jade"], "text/jsx": ["jsx"], "text/less": ["less"], "text/markdown": ["markdown", "md"], "text/mathml": ["mml"], "text/n3": ["n3"], "text/plain": ["txt", "text", "conf", "def", "list", "log", "in", "ini"], "text/prs.lines.tag": ["dsc"], "text/richtext": ["rtx"], "text/rtf": [], "text/sgml": ["sgml", "sgm"], "text/slim": ["slim", "slm"], "text/stylus": ["stylus", "styl"], "text/tab-separated-values": ["tsv"], "text/troff": ["t", "tr", "roff", "man", "me", "ms"], "text/turtle": ["ttl"], "text/uri-list": ["uri", "uris", "urls"], "text/vcard": ["vcard"], "text/vnd.curl": ["curl"], "text/vnd.curl.dcurl": ["dcurl"], "text/vnd.curl.mcurl": ["mcurl"], "text/vnd.curl.scurl": ["scurl"], "text/vnd.dvb.subtitle": ["sub"], "text/vnd.fly": ["fly"], "text/vnd.fmi.flexstor": ["flx"], "text/vnd.graphviz": ["gv"], "text/vnd.in3d.3dml": ["3dml"], "text/vnd.in3d.spot": ["spot"], "text/vnd.sun.j2me.app-descriptor": ["jad"], "text/vnd.wap.wml": ["wml"], "text/vnd.wap.wmlscript": ["wmls"], "text/vtt": ["vtt"], "text/x-asm": ["s", "asm"], "text/x-c": ["c", "cc", "cxx", "cpp", "h", "hh", "dic"], "text/x-component": ["htc"], "text/x-fortran": ["f", "for", "f77", "f90"], "text/x-handlebars-template": ["hbs"], "text/x-java-source": ["java"], "text/x-lua": ["lua"], "text/x-markdown": ["mkd"], "text/x-nfo": ["nfo"], "text/x-opml": ["opml"], "text/x-org": [], "text/x-pascal": ["p", "pas"], "text/x-processing": ["pde"], "text/x-sass": ["sass"], "text/x-scss": ["scss"], "text/x-setext": ["etx"], "text/x-sfv": ["sfv"], "text/x-suse-ymp": ["ymp"], "text/x-uuencode": ["uu"], "text/x-vcalendar": ["vcs"], "text/x-vcard": ["vcf"], "text/xml": [], "text/yaml": ["yaml", "yml"], "video/3gpp": ["3gp", "3gpp"], "video/3gpp2": ["3g2"], "video/h261": ["h261"], "video/h263": ["h263"], "video/h264": ["h264"], "video/jpeg": ["jpgv"], "video/jpm": ["jpgm"], "video/mj2": ["mj2", "mjp2"], "video/mp2t": ["ts"], "video/mp4": ["mp4", "mp4v", "mpg4"], "video/mpeg": ["mpeg", "mpg", "mpe", "m1v", "m2v"], "video/ogg": ["ogv"], "video/quicktime": ["qt", "mov"], "video/vnd.dece.hd": ["uvh", "uvvh"], "video/vnd.dece.mobile": ["uvm", "uvvm"], "video/vnd.dece.pd": ["uvp", "uvvp"], "video/vnd.dece.sd": ["uvs", "uvvs"], "video/vnd.dece.video": ["uvv", "uvvv"], "video/vnd.dvb.file": ["dvb"], "video/vnd.fvt": ["fvt"], "video/vnd.mpegurl": ["mxu", "m4u"], "video/vnd.ms-playready.media.pyv": ["pyv"], "video/vnd.uvvu.mp4": ["uvu", "uvvu"], "video/vnd.vivo": ["viv"], "video/webm": ["webm"], "video/x-f4v": ["f4v"], "video/x-fli": ["fli"], "video/x-flv": ["flv"], "video/x-m4v": ["m4v"], "video/x-matroska": ["mkv", "mk3d", "mks"], "video/x-mng": ["mng"], "video/x-ms-asf": ["asf", "asx"], "video/x-ms-vob": ["vob"], "video/x-ms-wm": ["wm"], "video/x-ms-wmv": ["wmv"], "video/x-ms-wmx": ["wmx"], "video/x-ms-wvx": ["wvx"], "video/x-msvideo": ["avi"], "video/x-sgi-movie": ["movie"], "video/x-smv": ["smv"], "x-conference/x-cooltalk": ["ice"] }