@httpland/compression-middleware 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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
|
+
}
|