@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.
Files changed (83) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +208 -0
  3. package/esm/deps/deno.land/std@0.180.0/http/_negotiation/common.js +40 -0
  4. package/esm/deps/deno.land/std@0.180.0/http/_negotiation/encoding.js +121 -0
  5. package/esm/deps/deno.land/std@0.180.0/http/_negotiation/language.js +110 -0
  6. package/esm/deps/deno.land/std@0.180.0/http/_negotiation/media_type.js +174 -0
  7. package/esm/deps/deno.land/std@0.180.0/http/negotiation.js +36 -0
  8. package/esm/deps/deno.land/std@0.180.0/media_types/_db.js +33 -0
  9. package/esm/deps/deno.land/std@0.180.0/media_types/_util.js +122 -0
  10. package/esm/deps/deno.land/std@0.180.0/media_types/content_type.js +54 -0
  11. package/esm/deps/deno.land/std@0.180.0/media_types/extension.js +25 -0
  12. package/esm/deps/deno.land/std@0.180.0/media_types/extensions_by_type.js +30 -0
  13. package/esm/deps/deno.land/std@0.180.0/media_types/format_media_type.js +60 -0
  14. package/esm/deps/deno.land/std@0.180.0/media_types/get_charset.js +36 -0
  15. package/esm/deps/deno.land/std@0.180.0/media_types/mod.js +22 -0
  16. package/esm/deps/deno.land/std@0.180.0/media_types/parse_media_type.js +121 -0
  17. package/esm/deps/deno.land/std@0.180.0/media_types/type_by_extension.js +23 -0
  18. package/esm/deps/deno.land/std@0.180.0/media_types/vendor/mime-db.v1.52.0.js +8555 -0
  19. package/esm/deps/deno.land/x/vary@1.0.0/mod.js +108 -0
  20. package/esm/deps.js +8 -0
  21. package/esm/encoders/deflate.js +11 -0
  22. package/esm/encoders/gzip.js +11 -0
  23. package/esm/encoders/utils.js +7 -0
  24. package/esm/middleware.js +55 -0
  25. package/esm/mod.js +3 -0
  26. package/esm/package.json +3 -0
  27. package/esm/transform.js +23 -0
  28. package/esm/types.js +3 -0
  29. package/esm/utils.js +19 -0
  30. package/package.json +55 -0
  31. package/script/deps/deno.land/std@0.180.0/http/_negotiation/common.js +45 -0
  32. package/script/deps/deno.land/std@0.180.0/http/_negotiation/encoding.js +125 -0
  33. package/script/deps/deno.land/std@0.180.0/http/_negotiation/language.js +114 -0
  34. package/script/deps/deno.land/std@0.180.0/http/_negotiation/media_type.js +178 -0
  35. package/script/deps/deno.land/std@0.180.0/http/negotiation.js +42 -0
  36. package/script/deps/deno.land/std@0.180.0/media_types/_db.js +39 -0
  37. package/script/deps/deno.land/std@0.180.0/media_types/_util.js +132 -0
  38. package/script/deps/deno.land/std@0.180.0/media_types/content_type.js +58 -0
  39. package/script/deps/deno.land/std@0.180.0/media_types/extension.js +29 -0
  40. package/script/deps/deno.land/std@0.180.0/media_types/extensions_by_type.js +34 -0
  41. package/script/deps/deno.land/std@0.180.0/media_types/format_media_type.js +64 -0
  42. package/script/deps/deno.land/std@0.180.0/media_types/get_charset.js +40 -0
  43. package/script/deps/deno.land/std@0.180.0/media_types/mod.js +38 -0
  44. package/script/deps/deno.land/std@0.180.0/media_types/parse_media_type.js +125 -0
  45. package/script/deps/deno.land/std@0.180.0/media_types/type_by_extension.js +27 -0
  46. package/script/deps/deno.land/std@0.180.0/media_types/vendor/mime-db.v1.52.0.js +8557 -0
  47. package/script/deps/deno.land/x/vary@1.0.0/mod.js +113 -0
  48. package/script/deps.js +22 -0
  49. package/script/encoders/deflate.js +14 -0
  50. package/script/encoders/gzip.js +14 -0
  51. package/script/encoders/utils.js +10 -0
  52. package/script/middleware.js +61 -0
  53. package/script/mod.js +7 -0
  54. package/script/package.json +3 -0
  55. package/script/transform.js +27 -0
  56. package/script/types.js +4 -0
  57. package/script/utils.js +24 -0
  58. package/types/deps/deno.land/std@0.180.0/http/_negotiation/common.d.ts +37 -0
  59. package/types/deps/deno.land/std@0.180.0/http/_negotiation/encoding.d.ts +33 -0
  60. package/types/deps/deno.land/std@0.180.0/http/_negotiation/language.d.ts +30 -0
  61. package/types/deps/deno.land/std@0.180.0/http/_negotiation/media_type.d.ts +30 -0
  62. package/types/deps/deno.land/std@0.180.0/http/negotiation.d.ts +126 -0
  63. package/types/deps/deno.land/std@0.180.0/media_types/_db.d.ts +5 -0
  64. package/types/deps/deno.land/std@0.180.0/media_types/_util.d.ts +21 -0
  65. package/types/deps/deno.land/std@0.180.0/media_types/content_type.d.ts +38 -0
  66. package/types/deps/deno.land/std@0.180.0/media_types/extension.d.ts +17 -0
  67. package/types/deps/deno.land/std@0.180.0/media_types/extensions_by_type.d.ts +20 -0
  68. package/types/deps/deno.land/std@0.180.0/media_types/format_media_type.d.ts +16 -0
  69. package/types/deps/deno.land/std@0.180.0/media_types/get_charset.d.ts +15 -0
  70. package/types/deps/deno.land/std@0.180.0/media_types/mod.d.ts +20 -0
  71. package/types/deps/deno.land/std@0.180.0/media_types/parse_media_type.d.ts +37 -0
  72. package/types/deps/deno.land/std@0.180.0/media_types/type_by_extension.d.ts +17 -0
  73. package/types/deps/deno.land/std@0.180.0/media_types/vendor/mime-db.v1.52.0.d.ts +8518 -0
  74. package/types/deps/deno.land/x/vary@1.0.0/mod.d.ts +23 -0
  75. package/types/deps.d.ts +7 -0
  76. package/types/encoders/deflate.d.ts +3 -0
  77. package/types/encoders/gzip.d.ts +3 -0
  78. package/types/encoders/utils.d.ts +4 -0
  79. package/types/middleware.d.ts +28 -0
  80. package/types/mod.d.ts +2 -0
  81. package/types/transform.d.ts +3 -0
  82. package/types/types.d.ts +15 -0
  83. package/types/utils.d.ts +2 -0
@@ -0,0 +1,108 @@
1
+ /*!
2
+ * Based on https://github.com/jshttp/vary/blob/master/index.js
3
+ * Copyright(c) 2014-2017 Douglas Christopher Wilson
4
+ * Copyright(c) 2020 Henry Zhuang
5
+ * MIT Licensed
6
+ */
7
+ /**
8
+ * RegExp to match field-name in RFC 7230 sec 3.2
9
+ *
10
+ * field-name = token
11
+ * token = 1*tchar
12
+ * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
13
+ * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
14
+ * / DIGIT / ALPHA
15
+ * ; any VCHAR, except delimiters
16
+ */
17
+ const FIELD_NAME_REGEXP = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
18
+ /**
19
+ * Append a field to a vary header.
20
+ *
21
+ * @param {String} header
22
+ * @param {String|Array} field
23
+ * @return {String}
24
+ * @public
25
+ */
26
+ export function append(header, field) {
27
+ // if (typeof header !== 'string') {
28
+ // throw new TypeError('header argument is required')
29
+ // }
30
+ // if (!field) {
31
+ // throw new TypeError('field argument is required')
32
+ // }
33
+ // existing, unspecified vary
34
+ if (header === "*") {
35
+ return header;
36
+ }
37
+ // get fields array
38
+ const fields = !Array.isArray(field) ? parse(String(field)) : field;
39
+ // assert on invalid field names
40
+ for (let j = 0; j < fields.length; j++) {
41
+ if (!FIELD_NAME_REGEXP.test(fields[j])) {
42
+ throw new TypeError(`field argument contains an invalid header name \`${fields[j]}\``);
43
+ }
44
+ }
45
+ // enumerate current values
46
+ let val = header;
47
+ const vals = parse(header.toLowerCase());
48
+ // unspecified vary
49
+ if (fields.indexOf("*") !== -1 || vals.indexOf("*") !== -1) {
50
+ return "*";
51
+ }
52
+ for (let i = 0; i < fields.length; i++) {
53
+ const fld = fields[i].toLowerCase();
54
+ // append value (case-preserving)
55
+ if (vals.indexOf(fld) === -1) {
56
+ vals.push(fld);
57
+ val = val ? val + ", " + fields[i] : fields[i];
58
+ }
59
+ }
60
+ return val;
61
+ }
62
+ /**
63
+ * Parse a vary header into an array.
64
+ *
65
+ * @param {String} header
66
+ * @return {Array}
67
+ * @private
68
+ */
69
+ function parse(header) {
70
+ let end = 0;
71
+ const list = [];
72
+ let start = 0;
73
+ // gather tokens
74
+ for (let i = 0, len = header.length; i < len; i++) {
75
+ switch (header.charCodeAt(i)) {
76
+ case 0x20: /* */
77
+ if (start === end) {
78
+ start = end = i + 1;
79
+ }
80
+ break;
81
+ case 0x2c: /* , */
82
+ list.push(header.substring(start, end));
83
+ start = end = i + 1;
84
+ break;
85
+ default:
86
+ end = i + 1;
87
+ break;
88
+ }
89
+ }
90
+ // final token
91
+ list.push(header.substring(start, end));
92
+ return list;
93
+ }
94
+ /**
95
+ * Mark that a request is varied on a header field.
96
+ *
97
+ * @param {Headers} header
98
+ * @param {String|Array} field
99
+ * @public
100
+ */
101
+ export function vary(header, field) {
102
+ // get existing header
103
+ let val = header.get("vary") || "";
104
+ // set new header
105
+ if ((val = append(val, field))) {
106
+ header.set("vary", val);
107
+ }
108
+ }
package/esm/deps.js ADDED
@@ -0,0 +1,8 @@
1
+ // Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ export { CachingHeader, ContentNegotiationHeader, RepresentationHeader, } from "@httpland/http-utils";
4
+ export { acceptsEncodings } from "./deps/deno.land/std@0.180.0/http/negotiation.js";
5
+ export { parseMediaType } from "./deps/deno.land/std@0.180.0/media_types/mod.js";
6
+ export { isNull } from "isxx";
7
+ export { default as compressible } from "compressible";
8
+ export { vary } from "./deps/deno.land/x/vary@1.0.0/mod.js";
@@ -0,0 +1,11 @@
1
+ // Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ import { Format } from "./utils.js";
4
+ function encodeDeflate(stream) {
5
+ return stream.pipeThrough(new CompressionStream(Format.Deflate));
6
+ }
7
+ /** Encoder for `deflate` */
8
+ export const Deflate = {
9
+ encoding: Format.Deflate,
10
+ encode: encodeDeflate,
11
+ };
@@ -0,0 +1,11 @@
1
+ // Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ import { Format } from "./utils.js";
4
+ function encodeGzip(stream) {
5
+ return stream.pipeThrough(new CompressionStream(Format.Gzip));
6
+ }
7
+ /** Encoder for `gzip` */
8
+ export const Gzip = {
9
+ encoding: Format.Gzip,
10
+ encode: encodeGzip,
11
+ };
@@ -0,0 +1,7 @@
1
+ // Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ export var Format;
4
+ (function (Format) {
5
+ Format["Gzip"] = "gzip";
6
+ Format["Deflate"] = "deflate";
7
+ })(Format || (Format = {}));
@@ -0,0 +1,55 @@
1
+ // Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ import { acceptsEncodings, ContentNegotiationHeader, vary, } from "./deps.js";
4
+ import { withContentEncoding } from "./transform.js";
5
+ import { Gzip } from "./encoders/gzip.js";
6
+ import { Deflate } from "./encoders/deflate.js";
7
+ const DefaultEncoders = [Gzip, Deflate];
8
+ /** Create HTTP content compression middleware.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { compression } from "https://deno.land/x/compression_middleware@$VERSION/mod.ts";
13
+ * import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
14
+ *
15
+ * const middleware = compression();
16
+ * const request = new Request("test:", {
17
+ * headers: {
18
+ * "accept-encoding": "deflate;q=0.5, gzip;q=1.0, deflate-raw;q=0.3",
19
+ * },
20
+ * });
21
+ *
22
+ * const response = await middleware(
23
+ * request,
24
+ * () => new Response("<body>"),
25
+ * );
26
+ *
27
+ * assertEquals(await response.text(), "<gzip:body>");
28
+ * assertEquals(response.headers.get("content-encoding"), "gzip");
29
+ * ```
30
+ */
31
+ export function compression(encoders) {
32
+ const encodingMap = {
33
+ ...fromEncoders(DefaultEncoders),
34
+ ...Array.isArray(encoders) ? fromEncoders(encoders) : encoders,
35
+ };
36
+ const encodings = Object.keys(encodingMap);
37
+ return async (request, next) => {
38
+ const encoding = acceptsEncodings(request, ...encodings, IDENTITY);
39
+ const response = await next(request);
40
+ vary(response.headers, ContentNegotiationHeader.AcceptEncoding);
41
+ if (!encoding || encoding === IDENTITY)
42
+ return response;
43
+ const encode = encodingMap[encoding];
44
+ if (!encode)
45
+ return response;
46
+ return withContentEncoding(response, { encode, encoding });
47
+ };
48
+ }
49
+ export function flat(encoder) {
50
+ return [encoder.encoding, encoder.encode];
51
+ }
52
+ export function fromEncoders(encoders) {
53
+ return Object.fromEntries(encoders.map(flat));
54
+ }
55
+ const IDENTITY = "identity";
package/esm/mod.js ADDED
@@ -0,0 +1,3 @@
1
+ // Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ export { compression } from "./middleware.js";
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,23 @@
1
+ // Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ import { CachingHeader, compressible, isNull, parseMediaType, RepresentationHeader, } from "./deps.js";
4
+ import { isNoTransform, reCalcContentLength } from "./utils.js";
5
+ /** Response with `Content-Encoding` header. */
6
+ export async function withContentEncoding(response, context) {
7
+ const contentType = response.headers.get(RepresentationHeader.ContentType);
8
+ const cacheControl = response.headers.get(CachingHeader.CacheControl);
9
+ if (isNull(contentType) ||
10
+ response.headers.has(RepresentationHeader.ContentEncoding) ||
11
+ !response.body ||
12
+ response.bodyUsed ||
13
+ (!isNull(cacheControl) && isNoTransform(cacheControl)))
14
+ return response;
15
+ const [mediaType] = parseMediaType(contentType);
16
+ const isCompressible = compressible(mediaType);
17
+ if (!isCompressible)
18
+ return response;
19
+ const bodyInit = await context.encode(response.body);
20
+ const newResponse = await reCalcContentLength(new Response(bodyInit, response));
21
+ newResponse.headers.set(RepresentationHeader.ContentEncoding, context.encoding);
22
+ return newResponse;
23
+ }
package/esm/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ export {};
package/esm/utils.js ADDED
@@ -0,0 +1,19 @@
1
+ // Copyright 2023-latest the httpland authors. All rights reserved. MIT license.
2
+ // This module is browser compatible.
3
+ import { RepresentationHeader } from "./deps.js";
4
+ const ReNoTransform = /(?:^|,)\s*?no-transform\s*?(?:,|$)/;
5
+ export function isNoTransform(input) {
6
+ return ReNoTransform.test(input);
7
+ }
8
+ export async function reCalcContentLength(response) {
9
+ if (response.bodyUsed ||
10
+ !response.headers.has(RepresentationHeader.ContentLength))
11
+ return response;
12
+ const length = await response
13
+ .clone()
14
+ .arrayBuffer()
15
+ .then((buffer) => buffer.byteLength)
16
+ .then(String);
17
+ response.headers.set(RepresentationHeader.ContentLength, length);
18
+ return response;
19
+ }
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "module": "./esm/mod.js",
3
+ "main": "./script/mod.js",
4
+ "types": "./types/mod.d.ts",
5
+ "name": "@httpland/compression-middleware",
6
+ "version": "1.0.0-beta.1",
7
+ "description": "HTTP compression middleware",
8
+ "keywords": [
9
+ "http",
10
+ "middleware",
11
+ "header",
12
+ "compression",
13
+ "compress",
14
+ "gzip",
15
+ "deflate",
16
+ "encoding",
17
+ "encoder",
18
+ "fetch-api"
19
+ ],
20
+ "engines": {
21
+ "node": "^18.x"
22
+ },
23
+ "license": "MIT",
24
+ "homepage": "https://github.com/httpland/compression-middleware",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/httpland/compression-middleware.git"
28
+ },
29
+ "bugs": {
30
+ "url": "https://github.com/httpland/compression-middleware/issues"
31
+ },
32
+ "sideEffects": false,
33
+ "type": "module",
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "exports": {
38
+ ".": {
39
+ "import": {
40
+ "types": "./types/mod.d.ts",
41
+ "default": "./esm/mod.js"
42
+ },
43
+ "require": {
44
+ "types": "./types/mod.d.ts",
45
+ "default": "./script/mod.js"
46
+ }
47
+ }
48
+ },
49
+ "dependencies": {
50
+ "@httpland/http-middleware": "1.0.0",
51
+ "@httpland/http-utils": "1.0.0-beta.13",
52
+ "compressible": "2.0.18",
53
+ "isxx": "1.0.0-beta.24"
54
+ }
55
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
3
+ /*!
4
+ * Adapted directly from negotiator at https://github.com/jshttp/negotiator/
5
+ * which is licensed as follows:
6
+ *
7
+ * (The MIT License)
8
+ *
9
+ * Copyright (c) 2012-2014 Federico Romero
10
+ * Copyright (c) 2012-2014 Isaac Z. Schlueter
11
+ * Copyright (c) 2014-2015 Douglas Christopher Wilson
12
+ *
13
+ * Permission is hereby granted, free of charge, to any person obtaining
14
+ * a copy of this software and associated documentation files (the
15
+ * 'Software'), to deal in the Software without restriction, including
16
+ * without limitation the rights to use, copy, modify, merge, publish,
17
+ * distribute, sublicense, and/or sell copies of the Software, and to
18
+ * permit persons to whom the Software is furnished to do so, subject to
19
+ * the following conditions:
20
+ *
21
+ * The above copyright notice and this permission notice shall be
22
+ * included in all copies or substantial portions of the Software.
23
+ *
24
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
25
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.isQuality = exports.compareSpecs = void 0;
34
+ function compareSpecs(a, b) {
35
+ return (b.q - a.q ||
36
+ (b.s ?? 0) - (a.s ?? 0) ||
37
+ (a.o ?? 0) - (b.o ?? 0) ||
38
+ a.i - b.i ||
39
+ 0);
40
+ }
41
+ exports.compareSpecs = compareSpecs;
42
+ function isQuality(spec) {
43
+ return spec.q > 0;
44
+ }
45
+ exports.isQuality = isQuality;
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
3
+ /*!
4
+ * Adapted directly from negotiator at https://github.com/jshttp/negotiator/
5
+ * which is licensed as follows:
6
+ *
7
+ * (The MIT License)
8
+ *
9
+ * Copyright (c) 2012-2014 Federico Romero
10
+ * Copyright (c) 2012-2014 Isaac Z. Schlueter
11
+ * Copyright (c) 2014-2015 Douglas Christopher Wilson
12
+ *
13
+ * Permission is hereby granted, free of charge, to any person obtaining
14
+ * a copy of this software and associated documentation files (the
15
+ * 'Software'), to deal in the Software without restriction, including
16
+ * without limitation the rights to use, copy, modify, merge, publish,
17
+ * distribute, sublicense, and/or sell copies of the Software, and to
18
+ * permit persons to whom the Software is furnished to do so, subject to
19
+ * the following conditions:
20
+ *
21
+ * The above copyright notice and this permission notice shall be
22
+ * included in all copies or substantial portions of the Software.
23
+ *
24
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
25
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.preferredEncodings = void 0;
34
+ const common_js_1 = require("./common.js");
35
+ const simpleEncodingRegExp = /^\s*([^\s;]+)\s*(?:;(.*))?$/;
36
+ function parseEncoding(str, i) {
37
+ const match = simpleEncodingRegExp.exec(str);
38
+ if (!match) {
39
+ return undefined;
40
+ }
41
+ const encoding = match[1];
42
+ let q = 1;
43
+ if (match[2]) {
44
+ const params = match[2].split(";");
45
+ for (const param of params) {
46
+ const p = param.trim().split("=");
47
+ if (p[0] === "q") {
48
+ q = parseFloat(p[1]);
49
+ break;
50
+ }
51
+ }
52
+ }
53
+ return { encoding, q, i };
54
+ }
55
+ function specify(encoding, spec, i = -1) {
56
+ if (!spec.encoding) {
57
+ return;
58
+ }
59
+ let s = 0;
60
+ if (spec.encoding.toLocaleLowerCase() === encoding.toLocaleLowerCase()) {
61
+ s = 1;
62
+ }
63
+ else if (spec.encoding !== "*") {
64
+ return;
65
+ }
66
+ return {
67
+ i,
68
+ o: spec.i,
69
+ q: spec.q,
70
+ s,
71
+ };
72
+ }
73
+ function parseAcceptEncoding(accept) {
74
+ const accepts = accept.split(",");
75
+ const parsedAccepts = [];
76
+ let hasIdentity = false;
77
+ let minQuality = 1;
78
+ for (let i = 0; i < accepts.length; i++) {
79
+ const encoding = parseEncoding(accepts[i].trim(), i);
80
+ if (encoding) {
81
+ parsedAccepts.push(encoding);
82
+ hasIdentity = hasIdentity || !!specify("identity", encoding);
83
+ minQuality = Math.min(minQuality, encoding.q || 1);
84
+ }
85
+ }
86
+ if (!hasIdentity) {
87
+ parsedAccepts.push({
88
+ encoding: "identity",
89
+ q: minQuality,
90
+ i: accepts.length - 1,
91
+ });
92
+ }
93
+ return parsedAccepts;
94
+ }
95
+ function getEncodingPriority(encoding, accepted, index) {
96
+ let priority = { o: -1, q: 0, s: 0, i: 0 };
97
+ for (const s of accepted) {
98
+ const spec = specify(encoding, s, index);
99
+ if (spec &&
100
+ (priority.s - spec.s || priority.q - spec.q ||
101
+ priority.o - spec.o) <
102
+ 0) {
103
+ priority = spec;
104
+ }
105
+ }
106
+ return priority;
107
+ }
108
+ /** Given an `Accept-Encoding` string, parse out the encoding returning a
109
+ * negotiated encoding based on the `provided` encodings otherwise just a
110
+ * prioritized array of encodings. */
111
+ function preferredEncodings(accept, provided) {
112
+ const accepts = parseAcceptEncoding(accept);
113
+ if (!provided) {
114
+ return accepts
115
+ .filter(common_js_1.isQuality)
116
+ .sort(common_js_1.compareSpecs)
117
+ .map((spec) => spec.encoding);
118
+ }
119
+ const priorities = provided.map((type, index) => getEncodingPriority(type, accepts, index));
120
+ return priorities
121
+ .filter(common_js_1.isQuality)
122
+ .sort(common_js_1.compareSpecs)
123
+ .map((priority) => provided[priorities.indexOf(priority)]);
124
+ }
125
+ exports.preferredEncodings = preferredEncodings;
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
3
+ /*!
4
+ * Adapted directly from negotiator at https://github.com/jshttp/negotiator/
5
+ * which is licensed as follows:
6
+ *
7
+ * (The MIT License)
8
+ *
9
+ * Copyright (c) 2012-2014 Federico Romero
10
+ * Copyright (c) 2012-2014 Isaac Z. Schlueter
11
+ * Copyright (c) 2014-2015 Douglas Christopher Wilson
12
+ *
13
+ * Permission is hereby granted, free of charge, to any person obtaining
14
+ * a copy of this software and associated documentation files (the
15
+ * 'Software'), to deal in the Software without restriction, including
16
+ * without limitation the rights to use, copy, modify, merge, publish,
17
+ * distribute, sublicense, and/or sell copies of the Software, and to
18
+ * permit persons to whom the Software is furnished to do so, subject to
19
+ * the following conditions:
20
+ *
21
+ * The above copyright notice and this permission notice shall be
22
+ * included in all copies or substantial portions of the Software.
23
+ *
24
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
25
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
28
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.preferredLanguages = void 0;
34
+ const common_js_1 = require("./common.js");
35
+ const SIMPLE_LANGUAGE_REGEXP = /^\s*([^\s\-;]+)(?:-([^\s;]+))?\s*(?:;(.*))?$/;
36
+ function parseLanguage(str, i) {
37
+ const match = SIMPLE_LANGUAGE_REGEXP.exec(str);
38
+ if (!match) {
39
+ return undefined;
40
+ }
41
+ const [, prefix, suffix] = match;
42
+ const full = suffix ? `${prefix}-${suffix}` : prefix;
43
+ let q = 1;
44
+ if (match[3]) {
45
+ const params = match[3].split(";");
46
+ for (const param of params) {
47
+ const [key, value] = param.trim().split("=");
48
+ if (key === "q") {
49
+ q = parseFloat(value);
50
+ break;
51
+ }
52
+ }
53
+ }
54
+ return { prefix, suffix, full, q, i };
55
+ }
56
+ function parseAcceptLanguage(accept) {
57
+ const accepts = accept.split(",");
58
+ const result = [];
59
+ for (let i = 0; i < accepts.length; i++) {
60
+ const language = parseLanguage(accepts[i].trim(), i);
61
+ if (language) {
62
+ result.push(language);
63
+ }
64
+ }
65
+ return result;
66
+ }
67
+ function specify(language, spec, i) {
68
+ const p = parseLanguage(language, i);
69
+ if (!p) {
70
+ return undefined;
71
+ }
72
+ let s = 0;
73
+ if (spec.full.toLowerCase() === p.full.toLowerCase()) {
74
+ s |= 4;
75
+ }
76
+ else if (spec.prefix.toLowerCase() === p.prefix.toLowerCase()) {
77
+ s |= 2;
78
+ }
79
+ else if (spec.full.toLowerCase() === p.prefix.toLowerCase()) {
80
+ s |= 1;
81
+ }
82
+ else if (spec.full !== "*") {
83
+ return;
84
+ }
85
+ return { i, o: spec.i, q: spec.q, s };
86
+ }
87
+ function getLanguagePriority(language, accepted, index) {
88
+ let priority = { i: -1, o: -1, q: 0, s: 0 };
89
+ for (const accepts of accepted) {
90
+ const spec = specify(language, accepts, index);
91
+ if (spec &&
92
+ ((priority.s ?? 0) - (spec.s ?? 0) || priority.q - spec.q ||
93
+ (priority.o ?? 0) - (spec.o ?? 0)) < 0) {
94
+ priority = spec;
95
+ }
96
+ }
97
+ return priority;
98
+ }
99
+ function preferredLanguages(accept = "*", provided) {
100
+ const accepts = parseAcceptLanguage(accept);
101
+ if (!provided) {
102
+ return accepts
103
+ .filter(common_js_1.isQuality)
104
+ .sort(common_js_1.compareSpecs)
105
+ .map((spec) => spec.full);
106
+ }
107
+ const priorities = provided
108
+ .map((type, index) => getLanguagePriority(type, accepts, index));
109
+ return priorities
110
+ .filter(common_js_1.isQuality)
111
+ .sort(common_js_1.compareSpecs)
112
+ .map((priority) => provided[priorities.indexOf(priority)]);
113
+ }
114
+ exports.preferredLanguages = preferredLanguages;