@httpland/compression-middleware 1.0.0-beta.1
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +20 -0
- package/README.md +208 -0
- package/esm/deps/deno.land/std@0.180.0/http/_negotiation/common.js +40 -0
- package/esm/deps/deno.land/std@0.180.0/http/_negotiation/encoding.js +121 -0
- package/esm/deps/deno.land/std@0.180.0/http/_negotiation/language.js +110 -0
- package/esm/deps/deno.land/std@0.180.0/http/_negotiation/media_type.js +174 -0
- package/esm/deps/deno.land/std@0.180.0/http/negotiation.js +36 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/_db.js +33 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/_util.js +122 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/content_type.js +54 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/extension.js +25 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/extensions_by_type.js +30 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/format_media_type.js +60 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/get_charset.js +36 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/mod.js +22 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/parse_media_type.js +121 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/type_by_extension.js +23 -0
- package/esm/deps/deno.land/std@0.180.0/media_types/vendor/mime-db.v1.52.0.js +8555 -0
- package/esm/deps/deno.land/x/vary@1.0.0/mod.js +108 -0
- package/esm/deps.js +8 -0
- package/esm/encoders/deflate.js +11 -0
- package/esm/encoders/gzip.js +11 -0
- package/esm/encoders/utils.js +7 -0
- package/esm/middleware.js +55 -0
- package/esm/mod.js +3 -0
- package/esm/package.json +3 -0
- package/esm/transform.js +23 -0
- package/esm/types.js +3 -0
- package/esm/utils.js +19 -0
- package/package.json +55 -0
- package/script/deps/deno.land/std@0.180.0/http/_negotiation/common.js +45 -0
- package/script/deps/deno.land/std@0.180.0/http/_negotiation/encoding.js +125 -0
- package/script/deps/deno.land/std@0.180.0/http/_negotiation/language.js +114 -0
- package/script/deps/deno.land/std@0.180.0/http/_negotiation/media_type.js +178 -0
- package/script/deps/deno.land/std@0.180.0/http/negotiation.js +42 -0
- package/script/deps/deno.land/std@0.180.0/media_types/_db.js +39 -0
- package/script/deps/deno.land/std@0.180.0/media_types/_util.js +132 -0
- package/script/deps/deno.land/std@0.180.0/media_types/content_type.js +58 -0
- package/script/deps/deno.land/std@0.180.0/media_types/extension.js +29 -0
- package/script/deps/deno.land/std@0.180.0/media_types/extensions_by_type.js +34 -0
- package/script/deps/deno.land/std@0.180.0/media_types/format_media_type.js +64 -0
- package/script/deps/deno.land/std@0.180.0/media_types/get_charset.js +40 -0
- package/script/deps/deno.land/std@0.180.0/media_types/mod.js +38 -0
- package/script/deps/deno.land/std@0.180.0/media_types/parse_media_type.js +125 -0
- package/script/deps/deno.land/std@0.180.0/media_types/type_by_extension.js +27 -0
- package/script/deps/deno.land/std@0.180.0/media_types/vendor/mime-db.v1.52.0.js +8557 -0
- package/script/deps/deno.land/x/vary@1.0.0/mod.js +113 -0
- package/script/deps.js +22 -0
- package/script/encoders/deflate.js +14 -0
- package/script/encoders/gzip.js +14 -0
- package/script/encoders/utils.js +10 -0
- package/script/middleware.js +61 -0
- package/script/mod.js +7 -0
- package/script/package.json +3 -0
- package/script/transform.js +27 -0
- package/script/types.js +4 -0
- package/script/utils.js +24 -0
- package/types/deps/deno.land/std@0.180.0/http/_negotiation/common.d.ts +37 -0
- package/types/deps/deno.land/std@0.180.0/http/_negotiation/encoding.d.ts +33 -0
- package/types/deps/deno.land/std@0.180.0/http/_negotiation/language.d.ts +30 -0
- package/types/deps/deno.land/std@0.180.0/http/_negotiation/media_type.d.ts +30 -0
- package/types/deps/deno.land/std@0.180.0/http/negotiation.d.ts +126 -0
- package/types/deps/deno.land/std@0.180.0/media_types/_db.d.ts +5 -0
- package/types/deps/deno.land/std@0.180.0/media_types/_util.d.ts +21 -0
- package/types/deps/deno.land/std@0.180.0/media_types/content_type.d.ts +38 -0
- package/types/deps/deno.land/std@0.180.0/media_types/extension.d.ts +17 -0
- package/types/deps/deno.land/std@0.180.0/media_types/extensions_by_type.d.ts +20 -0
- package/types/deps/deno.land/std@0.180.0/media_types/format_media_type.d.ts +16 -0
- package/types/deps/deno.land/std@0.180.0/media_types/get_charset.d.ts +15 -0
- package/types/deps/deno.land/std@0.180.0/media_types/mod.d.ts +20 -0
- package/types/deps/deno.land/std@0.180.0/media_types/parse_media_type.d.ts +37 -0
- package/types/deps/deno.land/std@0.180.0/media_types/type_by_extension.d.ts +17 -0
- package/types/deps/deno.land/std@0.180.0/media_types/vendor/mime-db.v1.52.0.d.ts +8518 -0
- package/types/deps/deno.land/x/vary@1.0.0/mod.d.ts +23 -0
- package/types/deps.d.ts +7 -0
- package/types/encoders/deflate.d.ts +3 -0
- package/types/encoders/gzip.d.ts +3 -0
- package/types/encoders/utils.d.ts +4 -0
- package/types/middleware.d.ts +28 -0
- package/types/mod.d.ts +2 -0
- package/types/transform.d.ts +3 -0
- package/types/types.d.ts +15 -0
- package/types/utils.d.ts +2 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
/**
|
3
|
+
* Contains the functions {@linkcode accepts}, {@linkcode acceptsEncodings}, and
|
4
|
+
* {@linkcode acceptsLanguages} to provide content negotiation capabilities.
|
5
|
+
*
|
6
|
+
* @module
|
7
|
+
*/
|
8
|
+
import { preferredEncodings } from "./_negotiation/encoding.js";
|
9
|
+
import { preferredLanguages } from "./_negotiation/language.js";
|
10
|
+
import { preferredMediaTypes } from "./_negotiation/media_type.js";
|
11
|
+
export function accepts(request, ...types) {
|
12
|
+
const accept = request.headers.get("accept");
|
13
|
+
return types.length
|
14
|
+
? accept ? preferredMediaTypes(accept, types)[0] : types[0]
|
15
|
+
: accept
|
16
|
+
? preferredMediaTypes(accept)
|
17
|
+
: ["*/*"];
|
18
|
+
}
|
19
|
+
export function acceptsEncodings(request, ...encodings) {
|
20
|
+
const acceptEncoding = request.headers.get("accept-encoding");
|
21
|
+
return encodings.length
|
22
|
+
? acceptEncoding
|
23
|
+
? preferredEncodings(acceptEncoding, encodings)[0]
|
24
|
+
: encodings[0]
|
25
|
+
: acceptEncoding
|
26
|
+
? preferredEncodings(acceptEncoding)
|
27
|
+
: ["*"];
|
28
|
+
}
|
29
|
+
export function acceptsLanguages(request, ...langs) {
|
30
|
+
const acceptLanguage = request.headers.get("accept-language");
|
31
|
+
return langs.length
|
32
|
+
? acceptLanguage ? preferredLanguages(acceptLanguage, langs)[0] : langs[0]
|
33
|
+
: acceptLanguage
|
34
|
+
? preferredLanguages(acceptLanguage)
|
35
|
+
: ["*"];
|
36
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
import db from "./vendor/mime-db.v1.52.0.js";
|
3
|
+
import { extensions } from "./_util.js";
|
4
|
+
/** A map of the media type for a given extension */
|
5
|
+
export const types = new Map();
|
6
|
+
/** Internal function to populate the maps based on the Mime DB. */
|
7
|
+
(function populateMaps() {
|
8
|
+
const preference = ["nginx", "apache", undefined, "iana"];
|
9
|
+
for (const type of Object.keys(db)) {
|
10
|
+
const mime = db[type];
|
11
|
+
const exts = mime.extensions;
|
12
|
+
if (!exts || !exts.length) {
|
13
|
+
continue;
|
14
|
+
}
|
15
|
+
// @ts-ignore work around denoland/dnt#148
|
16
|
+
extensions.set(type, exts);
|
17
|
+
for (const ext of exts) {
|
18
|
+
const current = types.get(ext);
|
19
|
+
if (current) {
|
20
|
+
const from = preference.indexOf(db[current].source);
|
21
|
+
const to = preference.indexOf(mime.source);
|
22
|
+
if (current !== "application/octet-stream" &&
|
23
|
+
(from > to ||
|
24
|
+
// @ts-ignore work around denoland/dnt#148
|
25
|
+
(from === to && current.startsWith("application/")))) {
|
26
|
+
continue;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
types.set(ext, type);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
})();
|
33
|
+
export { db };
|
@@ -0,0 +1,122 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
/** A map of extensions for a given media type. */
|
3
|
+
export const extensions = new Map();
|
4
|
+
export function consumeToken(v) {
|
5
|
+
const notPos = indexOf(v, isNotTokenChar);
|
6
|
+
if (notPos == -1) {
|
7
|
+
return [v, ""];
|
8
|
+
}
|
9
|
+
if (notPos == 0) {
|
10
|
+
return ["", v];
|
11
|
+
}
|
12
|
+
return [v.slice(0, notPos), v.slice(notPos)];
|
13
|
+
}
|
14
|
+
export function consumeValue(v) {
|
15
|
+
if (!v) {
|
16
|
+
return ["", v];
|
17
|
+
}
|
18
|
+
if (v[0] !== `"`) {
|
19
|
+
return consumeToken(v);
|
20
|
+
}
|
21
|
+
let value = "";
|
22
|
+
for (let i = 1; i < v.length; i++) {
|
23
|
+
const r = v[i];
|
24
|
+
if (r === `"`) {
|
25
|
+
return [value, v.slice(i + 1)];
|
26
|
+
}
|
27
|
+
if (r === "\\" && i + 1 < v.length && isTSpecial(v[i + 1])) {
|
28
|
+
value += v[i + 1];
|
29
|
+
i++;
|
30
|
+
continue;
|
31
|
+
}
|
32
|
+
if (r === "\r" || r === "\n") {
|
33
|
+
return ["", v];
|
34
|
+
}
|
35
|
+
value += v[i];
|
36
|
+
}
|
37
|
+
return ["", v];
|
38
|
+
}
|
39
|
+
export function consumeMediaParam(v) {
|
40
|
+
let rest = v.trimStart();
|
41
|
+
if (!rest.startsWith(";")) {
|
42
|
+
return ["", "", v];
|
43
|
+
}
|
44
|
+
rest = rest.slice(1);
|
45
|
+
rest = rest.trimStart();
|
46
|
+
let param;
|
47
|
+
[param, rest] = consumeToken(rest);
|
48
|
+
param = param.toLowerCase();
|
49
|
+
if (!param) {
|
50
|
+
return ["", "", v];
|
51
|
+
}
|
52
|
+
rest = rest.slice(1);
|
53
|
+
rest = rest.trimStart();
|
54
|
+
const [value, rest2] = consumeValue(rest);
|
55
|
+
if (value == "" && rest2 === rest) {
|
56
|
+
return ["", "", v];
|
57
|
+
}
|
58
|
+
rest = rest2;
|
59
|
+
return [param, value, rest];
|
60
|
+
}
|
61
|
+
export function decode2331Encoding(v) {
|
62
|
+
const sv = v.split(`'`, 3);
|
63
|
+
if (sv.length !== 3) {
|
64
|
+
return undefined;
|
65
|
+
}
|
66
|
+
const charset = sv[0].toLowerCase();
|
67
|
+
if (!charset) {
|
68
|
+
return undefined;
|
69
|
+
}
|
70
|
+
if (charset != "us-ascii" && charset != "utf-8") {
|
71
|
+
return undefined;
|
72
|
+
}
|
73
|
+
const encv = decodeURI(sv[2]);
|
74
|
+
if (!encv) {
|
75
|
+
return undefined;
|
76
|
+
}
|
77
|
+
return encv;
|
78
|
+
}
|
79
|
+
function indexOf(s, fn) {
|
80
|
+
let i = -1;
|
81
|
+
for (const v of s) {
|
82
|
+
i++;
|
83
|
+
if (fn(v)) {
|
84
|
+
return i;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
return -1;
|
88
|
+
}
|
89
|
+
export function isIterator(obj) {
|
90
|
+
if (obj == null) {
|
91
|
+
return false;
|
92
|
+
}
|
93
|
+
// deno-lint-ignore no-explicit-any
|
94
|
+
return typeof obj[Symbol.iterator] === "function";
|
95
|
+
}
|
96
|
+
export function isToken(s) {
|
97
|
+
if (!s) {
|
98
|
+
return false;
|
99
|
+
}
|
100
|
+
return indexOf(s, isNotTokenChar) < 0;
|
101
|
+
}
|
102
|
+
function isNotTokenChar(r) {
|
103
|
+
return !isTokenChar(r);
|
104
|
+
}
|
105
|
+
function isTokenChar(r) {
|
106
|
+
const code = r.charCodeAt(0);
|
107
|
+
return code > 0x20 && code < 0x7f && !isTSpecial(r);
|
108
|
+
}
|
109
|
+
function isTSpecial(r) {
|
110
|
+
return `()<>@,;:\\"/[]?=`.includes(r[0]);
|
111
|
+
}
|
112
|
+
const CHAR_CODE_SPACE = " ".charCodeAt(0);
|
113
|
+
const CHAR_CODE_TILDE = "~".charCodeAt(0);
|
114
|
+
export function needsEncoding(s) {
|
115
|
+
for (const b of s) {
|
116
|
+
const charCode = b.charCodeAt(0);
|
117
|
+
if ((charCode < CHAR_CODE_SPACE || charCode > CHAR_CODE_TILDE) && b !== "\t") {
|
118
|
+
return true;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
return false;
|
122
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
import { parseMediaType } from "./parse_media_type.js";
|
3
|
+
import { typeByExtension } from "./type_by_extension.js";
|
4
|
+
import { getCharset } from "./get_charset.js";
|
5
|
+
import { formatMediaType } from "./format_media_type.js";
|
6
|
+
/**
|
7
|
+
* Given an extension or media type, return a full `Content-Type` or
|
8
|
+
* `Content-Disposition` header value.
|
9
|
+
*
|
10
|
+
* The function will treat the `extensionOrType` as a media type when it
|
11
|
+
* contains a `/`, otherwise it will process it as an extension, with or without
|
12
|
+
* the leading `.`.
|
13
|
+
*
|
14
|
+
* Returns `undefined` if unable to resolve the media type.
|
15
|
+
*
|
16
|
+
* > Note: a side effect of `deno/x/media_types` was that you could pass a file
|
17
|
+
* > name (e.g. `file.json`) and it would return the content type. This behavior
|
18
|
+
* > is intentionally not supported here. If you want to get an extension for a
|
19
|
+
* > file name, use `extname()` from `std/path/mod.ts` to determine the
|
20
|
+
* > extension and pass it here.
|
21
|
+
*
|
22
|
+
* @example
|
23
|
+
* ```ts
|
24
|
+
* import { contentType } from "https://deno.land/std@$STD_VERSION/media_types/content_type.ts";
|
25
|
+
*
|
26
|
+
* contentType(".json"); // `application/json; charset=UTF-8`
|
27
|
+
* contentType("text/html"); // `text/html; charset=UTF-8`
|
28
|
+
* contentType("text/html; charset=UTF-8"); // `text/html; charset=UTF-8`
|
29
|
+
* contentType("txt"); // `text/plain; charset=UTF-8`
|
30
|
+
* contentType("foo"); // undefined
|
31
|
+
* contentType("file.json"); // undefined
|
32
|
+
* ```
|
33
|
+
*/
|
34
|
+
export function contentType(extensionOrType) {
|
35
|
+
try {
|
36
|
+
const [mediaType, params = {}] = extensionOrType.includes("/")
|
37
|
+
? parseMediaType(extensionOrType)
|
38
|
+
: [typeByExtension(extensionOrType), undefined];
|
39
|
+
if (!mediaType) {
|
40
|
+
return undefined;
|
41
|
+
}
|
42
|
+
if (!("charset" in params)) {
|
43
|
+
const charset = getCharset(mediaType);
|
44
|
+
if (charset) {
|
45
|
+
params.charset = charset;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
return formatMediaType(mediaType, params);
|
49
|
+
}
|
50
|
+
catch {
|
51
|
+
// just swallow returning undefined
|
52
|
+
}
|
53
|
+
return undefined;
|
54
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
import { extensionsByType } from "./extensions_by_type.js";
|
3
|
+
/**
|
4
|
+
* For a given media type, return the most relevant extension, or `undefined`
|
5
|
+
* if no extension can be found.
|
6
|
+
*
|
7
|
+
* Extensions are returned without a leading `.`.
|
8
|
+
*
|
9
|
+
* @example
|
10
|
+
* ```ts
|
11
|
+
* import { extension } from "https://deno.land/std@$STD_VERSION/media_types/extension.ts";
|
12
|
+
*
|
13
|
+
* extension("text/plain"); // `txt`
|
14
|
+
* extension("application/json"); // `json`
|
15
|
+
* extension("text/html; charset=UTF-8"); // `html`
|
16
|
+
* extension("application/foo"); // undefined
|
17
|
+
* ```
|
18
|
+
*/
|
19
|
+
export function extension(type) {
|
20
|
+
const exts = extensionsByType(type);
|
21
|
+
if (exts) {
|
22
|
+
return exts[0];
|
23
|
+
}
|
24
|
+
return undefined;
|
25
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
import { parseMediaType } from "./parse_media_type.js";
|
3
|
+
import { extensions } from "./_util.js";
|
4
|
+
export { extensions };
|
5
|
+
/**
|
6
|
+
* Returns the extensions known to be associated with the media type `type`.
|
7
|
+
* The returned extensions will each begin with a leading dot, as in `.html`.
|
8
|
+
*
|
9
|
+
* When `type` has no associated extensions, the function returns `undefined`.
|
10
|
+
*
|
11
|
+
* Extensions are returned without a leading `.`.
|
12
|
+
*
|
13
|
+
* @example
|
14
|
+
* ```ts
|
15
|
+
* import { extensionsByType } from "https://deno.land/std@$STD_VERSION/media_types/extensions_by_type.ts";
|
16
|
+
*
|
17
|
+
* extensionsByType("application/json"); // ["json", "map"]
|
18
|
+
* extensionsByType("text/html; charset=UTF-8"); // ["html", "htm", "shtml"]
|
19
|
+
* extensionsByType("application/foo"); // undefined
|
20
|
+
* ```
|
21
|
+
*/
|
22
|
+
export function extensionsByType(type) {
|
23
|
+
try {
|
24
|
+
const [mediaType] = parseMediaType(type);
|
25
|
+
return extensions.get(mediaType);
|
26
|
+
}
|
27
|
+
catch {
|
28
|
+
// just swallow errors, returning undefined
|
29
|
+
}
|
30
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
import { isIterator, isToken, needsEncoding } from "./_util.js";
|
3
|
+
/** Serializes the media type and the optional parameters as a media type
|
4
|
+
* conforming to RFC 2045 and RFC 2616.
|
5
|
+
*
|
6
|
+
* The type and parameter names are written in lower-case.
|
7
|
+
*
|
8
|
+
* When any of the arguments results in a standard violation then the return
|
9
|
+
* value will be an empty string (`""`).
|
10
|
+
*
|
11
|
+
* @example
|
12
|
+
* ```ts
|
13
|
+
* import { formatMediaType } from "https://deno.land/std@$STD_VERSION/media_types/format_media_type.ts";
|
14
|
+
*
|
15
|
+
* formatMediaType("text/plain", { charset: "UTF-8" }); // `text/plain; charset=UTF-8`
|
16
|
+
* ```
|
17
|
+
*/
|
18
|
+
export function formatMediaType(type, param) {
|
19
|
+
let b = "";
|
20
|
+
const [major, sub] = type.split("/");
|
21
|
+
if (!sub) {
|
22
|
+
if (!isToken(type)) {
|
23
|
+
return "";
|
24
|
+
}
|
25
|
+
b += type.toLowerCase();
|
26
|
+
}
|
27
|
+
else {
|
28
|
+
if (!isToken(major) || !isToken(sub)) {
|
29
|
+
return "";
|
30
|
+
}
|
31
|
+
b += `${major.toLowerCase()}/${sub.toLowerCase()}`;
|
32
|
+
}
|
33
|
+
if (param) {
|
34
|
+
param = isIterator(param) ? Object.fromEntries(param) : param;
|
35
|
+
const attrs = Object.keys(param);
|
36
|
+
attrs.sort();
|
37
|
+
for (const attribute of attrs) {
|
38
|
+
if (!isToken(attribute)) {
|
39
|
+
return "";
|
40
|
+
}
|
41
|
+
const value = param[attribute];
|
42
|
+
b += `; ${attribute.toLowerCase()}`;
|
43
|
+
const needEnc = needsEncoding(value);
|
44
|
+
if (needEnc) {
|
45
|
+
b += "*";
|
46
|
+
}
|
47
|
+
b += "=";
|
48
|
+
if (needEnc) {
|
49
|
+
b += `utf-8''${encodeURIComponent(value)}`;
|
50
|
+
continue;
|
51
|
+
}
|
52
|
+
if (isToken(value)) {
|
53
|
+
b += value;
|
54
|
+
continue;
|
55
|
+
}
|
56
|
+
b += `"${value.replace(/["\\]/gi, (m) => `\\${m}`)}"`;
|
57
|
+
}
|
58
|
+
}
|
59
|
+
return b;
|
60
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
import { parseMediaType } from "./parse_media_type.js";
|
3
|
+
import { db } from "./_db.js";
|
4
|
+
/**
|
5
|
+
* Given a media type or header value, identify the encoding charset. If the
|
6
|
+
* charset cannot be determined, the function returns `undefined`.
|
7
|
+
*
|
8
|
+
* @example
|
9
|
+
* ```ts
|
10
|
+
* import { getCharset } from "https://deno.land/std@$STD_VERSION/media_types/get_charset.ts";
|
11
|
+
*
|
12
|
+
* getCharset("text/plain"); // `UTF-8`
|
13
|
+
* getCharset("application/foo"); // undefined
|
14
|
+
* getCharset("application/news-checkgroups"); // `US-ASCII`
|
15
|
+
* getCharset("application/news-checkgroups; charset=UTF-8"); // `UTF-8`
|
16
|
+
* ```
|
17
|
+
*/
|
18
|
+
export function getCharset(type) {
|
19
|
+
try {
|
20
|
+
const [mediaType, params] = parseMediaType(type);
|
21
|
+
if (params && params["charset"]) {
|
22
|
+
return params["charset"];
|
23
|
+
}
|
24
|
+
const entry = db[mediaType];
|
25
|
+
if (entry && entry.charset) {
|
26
|
+
return entry.charset;
|
27
|
+
}
|
28
|
+
if (mediaType.startsWith("text/")) {
|
29
|
+
return "UTF-8";
|
30
|
+
}
|
31
|
+
}
|
32
|
+
catch {
|
33
|
+
// just swallow errors, returning undefined
|
34
|
+
}
|
35
|
+
return undefined;
|
36
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
// This module is browser compatible.
|
3
|
+
/** Utility functions for media types (MIME types).
|
4
|
+
*
|
5
|
+
* This API is inspired by the GoLang [`mime`](https://pkg.go.dev/mime) package
|
6
|
+
* and [jshttp/mime-types](https://github.com/jshttp/mime-types), and is
|
7
|
+
* designed to integrate and improve the APIs from
|
8
|
+
* [deno.land/x/media_types](https://deno.land/x/media_types).
|
9
|
+
*
|
10
|
+
* The `vendor` folder contains copy of the
|
11
|
+
* [jshttp/mime-db](https://github.com/jshttp/mime-types) `db.json` file along
|
12
|
+
* with its license.
|
13
|
+
*
|
14
|
+
* @module
|
15
|
+
*/
|
16
|
+
export * from "./content_type.js";
|
17
|
+
export * from "./extension.js";
|
18
|
+
export * from "./extensions_by_type.js";
|
19
|
+
export * from "./format_media_type.js";
|
20
|
+
export * from "./get_charset.js";
|
21
|
+
export * from "./parse_media_type.js";
|
22
|
+
export * from "./type_by_extension.js";
|
@@ -0,0 +1,121 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
import { consumeMediaParam, decode2331Encoding } from "./_util.js";
|
3
|
+
/**
|
4
|
+
* Parses the media type and any optional parameters, per
|
5
|
+
* [RFC 1521](https://datatracker.ietf.org/doc/html/rfc1521). Media types are
|
6
|
+
* the values in `Content-Type` and `Content-Disposition` headers. On success
|
7
|
+
* the function returns a tuple where the first element is the media type and
|
8
|
+
* the second element is the optional parameters or `undefined` if there are
|
9
|
+
* none.
|
10
|
+
*
|
11
|
+
* The function will throw if the parsed value is invalid.
|
12
|
+
*
|
13
|
+
* The returned media type will be normalized to be lower case, and returned
|
14
|
+
* params keys will be normalized to lower case, but preserves the casing of
|
15
|
+
* the value.
|
16
|
+
*
|
17
|
+
* @example
|
18
|
+
* ```ts
|
19
|
+
* import { parseMediaType } from "https://deno.land/std@$STD_VERSION/media_types/parse_media_type.ts";
|
20
|
+
* import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";
|
21
|
+
*
|
22
|
+
* assertEquals(
|
23
|
+
* parseMediaType("application/JSON"),
|
24
|
+
* [
|
25
|
+
* "application/json",
|
26
|
+
* undefined
|
27
|
+
* ]
|
28
|
+
* );
|
29
|
+
*
|
30
|
+
* assertEquals(
|
31
|
+
* parseMediaType("text/html; charset=UTF-8"),
|
32
|
+
* [
|
33
|
+
* "application/json",
|
34
|
+
* { charset: "UTF-8" },
|
35
|
+
* ]
|
36
|
+
* );
|
37
|
+
* ```
|
38
|
+
*/
|
39
|
+
export function parseMediaType(v) {
|
40
|
+
const [base] = v.split(";");
|
41
|
+
const mediaType = base.toLowerCase().trim();
|
42
|
+
const params = {};
|
43
|
+
// Map of base parameter name -> parameter name -> value
|
44
|
+
// for parameters containing a '*' character.
|
45
|
+
const continuation = new Map();
|
46
|
+
v = v.slice(base.length);
|
47
|
+
while (v.length) {
|
48
|
+
v = v.trimStart();
|
49
|
+
if (v.length === 0) {
|
50
|
+
break;
|
51
|
+
}
|
52
|
+
const [key, value, rest] = consumeMediaParam(v);
|
53
|
+
if (!key) {
|
54
|
+
if (rest.trim() === ";") {
|
55
|
+
// ignore trailing semicolons
|
56
|
+
break;
|
57
|
+
}
|
58
|
+
throw new TypeError("Invalid media parameter.");
|
59
|
+
}
|
60
|
+
let pmap = params;
|
61
|
+
const [baseName, rest2] = key.split("*");
|
62
|
+
if (baseName && rest2 != null) {
|
63
|
+
if (!continuation.has(baseName)) {
|
64
|
+
continuation.set(baseName, {});
|
65
|
+
}
|
66
|
+
pmap = continuation.get(baseName);
|
67
|
+
}
|
68
|
+
if (key in pmap) {
|
69
|
+
throw new TypeError("Duplicate key parsed.");
|
70
|
+
}
|
71
|
+
pmap[key] = value;
|
72
|
+
v = rest;
|
73
|
+
}
|
74
|
+
// Stitch together any continuations or things with stars
|
75
|
+
// (i.e. RFC 2231 things with stars: "foo*0" or "foo*")
|
76
|
+
let str = "";
|
77
|
+
for (const [key, pieceMap] of continuation) {
|
78
|
+
const singlePartKey = `${key}*`;
|
79
|
+
const v = pieceMap[singlePartKey];
|
80
|
+
if (v) {
|
81
|
+
const decv = decode2331Encoding(v);
|
82
|
+
if (decv) {
|
83
|
+
params[key] = decv;
|
84
|
+
}
|
85
|
+
continue;
|
86
|
+
}
|
87
|
+
str = "";
|
88
|
+
let valid = false;
|
89
|
+
for (let n = 0;; n++) {
|
90
|
+
const simplePart = `${key}*${n}`;
|
91
|
+
let v = pieceMap[simplePart];
|
92
|
+
if (v) {
|
93
|
+
valid = true;
|
94
|
+
str += v;
|
95
|
+
continue;
|
96
|
+
}
|
97
|
+
const encodedPart = `${simplePart}*`;
|
98
|
+
v = pieceMap[encodedPart];
|
99
|
+
if (!v) {
|
100
|
+
break;
|
101
|
+
}
|
102
|
+
valid = true;
|
103
|
+
if (n === 0) {
|
104
|
+
const decv = decode2331Encoding(v);
|
105
|
+
if (decv) {
|
106
|
+
str += decv;
|
107
|
+
}
|
108
|
+
}
|
109
|
+
else {
|
110
|
+
const decv = decodeURI(v);
|
111
|
+
str += decv;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
if (valid) {
|
115
|
+
params[key] = str;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
return Object.keys(params).length
|
119
|
+
? [mediaType, params]
|
120
|
+
: [mediaType, undefined];
|
121
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
2
|
+
import { types } from "./_db.js";
|
3
|
+
/**
|
4
|
+
* Returns the media type associated with the file extension. Values are
|
5
|
+
* normalized to lower case and matched irrespective of a leading `.`.
|
6
|
+
*
|
7
|
+
* When `extension` has no associated type, the function returns `undefined`.
|
8
|
+
*
|
9
|
+
* @example
|
10
|
+
* ```ts
|
11
|
+
* import { typeByExtension } from "https://deno.land/std@$STD_VERSION/media_types/type_by_extension.ts";
|
12
|
+
*
|
13
|
+
* typeByExtension("js"); // `application/json`
|
14
|
+
* typeByExtension(".HTML"); // `text/html`
|
15
|
+
* typeByExtension("foo"); // undefined
|
16
|
+
* typeByExtension("file.json"); // undefined
|
17
|
+
* ```
|
18
|
+
*/
|
19
|
+
export function typeByExtension(extension) {
|
20
|
+
extension = extension.startsWith(".") ? extension.slice(1) : extension;
|
21
|
+
// @ts-ignore workaround around denoland/dnt#148
|
22
|
+
return types.get(extension.toLowerCase());
|
23
|
+
}
|