deno.land / std@0.224.0 / media_types / parse_media_type.ts

parse_media_type.ts
View Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.// This module is browser compatible.
import { consumeMediaParam, decode2331Encoding } from "./_util.ts";
/** * Parses the media type and any optional parameters, per * {@link https://datatracker.ietf.org/doc/html/rfc1521 | RFC 1521}. Media * types are the values in `Content-Type` and `Content-Disposition` headers. On * success the function returns a tuple where the first element is the media * type and the second element is the optional parameters or `undefined` if * there are none. * * The function will throw if the parsed value is invalid. * * The returned media type will be normalized to be lower case, and returned * params keys will be normalized to lower case, but preserves the casing of * the value. * * @example * ```ts * import { parseMediaType } from "https://deno.land/std@$STD_VERSION/media_types/parse_media_type.ts"; * * parseMediaType("application/JSON"); // ["application/json", undefined] * parseMediaType("text/html; charset=UTF-8"); // ["text/html", { charset: "UTF-8" }] * ``` */export function parseMediaType( v: string,): [mediaType: string, params: Record<string, string> | undefined] { const [base] = v.split(";") as [string]; const mediaType = base.toLowerCase().trim();
const params: Record<string, string> = {}; // Map of base parameter name -> parameter name -> value // for parameters containing a '*' character. const continuation = new Map<string, Record<string, string>>();
v = v.slice(base.length); while (v.length) { v = v.trimStart(); if (v.length === 0) { break; } const [key, value, rest] = consumeMediaParam(v); if (!key) { if (rest.trim() === ";") { // ignore trailing semicolons break; } throw new TypeError("Invalid media parameter."); }
let pmap = params; const [baseName, rest2] = key.split("*"); if (baseName && rest2 !== undefined) { if (!continuation.has(baseName)) { continuation.set(baseName, {}); } pmap = continuation.get(baseName)!; } if (key in pmap) { throw new TypeError("Duplicate key parsed."); } pmap[key] = value; v = rest; }
// Stitch together any continuations or things with stars // (i.e. RFC 2231 things with stars: "foo*0" or "foo*") let str = ""; for (const [key, pieceMap] of continuation) { const singlePartKey = `${key}*`; const v = pieceMap[singlePartKey]; if (v) { const decv = decode2331Encoding(v); if (decv) { params[key] = decv; } continue; }
str = ""; let valid = false; for (let n = 0;; n++) { const simplePart = `${key}*${n}`; let v = pieceMap[simplePart]; if (v) { valid = true; str += v; continue; } const encodedPart = `${simplePart}*`; v = pieceMap[encodedPart]; if (!v) { break; } valid = true; if (n === 0) { const decv = decode2331Encoding(v); if (decv) { str += decv; } } else { const decv = decodeURI(v); str += decv; } } if (valid) { params[key] = str; } }
return Object.keys(params).length ? [mediaType, params] : [mediaType, undefined];}
std

Version Info

Tagged at
6 months ago