1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | const tokenChars = [
|
16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
18 | 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
|
19 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
|
20 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
21 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
22 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
23 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0
|
24 | ];
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 | function push(dest, name, elem) {
|
37 | if (dest[name] === undefined) dest[name] = [elem];
|
38 | else dest[name].push(elem);
|
39 | }
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | function parse(header) {
|
49 | const offers = Object.create(null);
|
50 |
|
51 | if (header === undefined || header === '') return offers;
|
52 |
|
53 | let params = Object.create(null);
|
54 | let mustUnescape = false;
|
55 | let isEscaping = false;
|
56 | let inQuotes = false;
|
57 | let extensionName;
|
58 | let paramName;
|
59 | let start = -1;
|
60 | let end = -1;
|
61 | let i = 0;
|
62 |
|
63 | for (; i < header.length; i++) {
|
64 | const code = header.charCodeAt(i);
|
65 |
|
66 | if (extensionName === undefined) {
|
67 | if (end === -1 && tokenChars[code] === 1) {
|
68 | if (start === -1) start = i;
|
69 | } else if (code === 0x20 || code === 0x09 ) {
|
70 | if (end === -1 && start !== -1) end = i;
|
71 | } else if (code === 0x3b || code === 0x2c ) {
|
72 | if (start === -1) {
|
73 | throw new SyntaxError(`Unexpected character at index ${i}`);
|
74 | }
|
75 |
|
76 | if (end === -1) end = i;
|
77 | const name = header.slice(start, end);
|
78 | if (code === 0x2c) {
|
79 | push(offers, name, params);
|
80 | params = Object.create(null);
|
81 | } else {
|
82 | extensionName = name;
|
83 | }
|
84 |
|
85 | start = end = -1;
|
86 | } else {
|
87 | throw new SyntaxError(`Unexpected character at index ${i}`);
|
88 | }
|
89 | } else if (paramName === undefined) {
|
90 | if (end === -1 && tokenChars[code] === 1) {
|
91 | if (start === -1) start = i;
|
92 | } else if (code === 0x20 || code === 0x09) {
|
93 | if (end === -1 && start !== -1) end = i;
|
94 | } else if (code === 0x3b || code === 0x2c) {
|
95 | if (start === -1) {
|
96 | throw new SyntaxError(`Unexpected character at index ${i}`);
|
97 | }
|
98 |
|
99 | if (end === -1) end = i;
|
100 | push(params, header.slice(start, end), true);
|
101 | if (code === 0x2c) {
|
102 | push(offers, extensionName, params);
|
103 | params = Object.create(null);
|
104 | extensionName = undefined;
|
105 | }
|
106 |
|
107 | start = end = -1;
|
108 | } else if (code === 0x3d && start !== -1 && end === -1) {
|
109 | paramName = header.slice(start, i);
|
110 | start = end = -1;
|
111 | } else {
|
112 | throw new SyntaxError(`Unexpected character at index ${i}`);
|
113 | }
|
114 | } else {
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
|
120 | if (isEscaping) {
|
121 | if (tokenChars[code] !== 1) {
|
122 | throw new SyntaxError(`Unexpected character at index ${i}`);
|
123 | }
|
124 | if (start === -1) start = i;
|
125 | else if (!mustUnescape) mustUnescape = true;
|
126 | isEscaping = false;
|
127 | } else if (inQuotes) {
|
128 | if (tokenChars[code] === 1) {
|
129 | if (start === -1) start = i;
|
130 | } else if (code === 0x22 && start !== -1) {
|
131 | inQuotes = false;
|
132 | end = i;
|
133 | } else if (code === 0x5c ) {
|
134 | isEscaping = true;
|
135 | } else {
|
136 | throw new SyntaxError(`Unexpected character at index ${i}`);
|
137 | }
|
138 | } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {
|
139 | inQuotes = true;
|
140 | } else if (end === -1 && tokenChars[code] === 1) {
|
141 | if (start === -1) start = i;
|
142 | } else if (start !== -1 && (code === 0x20 || code === 0x09)) {
|
143 | if (end === -1) end = i;
|
144 | } else if (code === 0x3b || code === 0x2c) {
|
145 | if (start === -1) {
|
146 | throw new SyntaxError(`Unexpected character at index ${i}`);
|
147 | }
|
148 |
|
149 | if (end === -1) end = i;
|
150 | let value = header.slice(start, end);
|
151 | if (mustUnescape) {
|
152 | value = value.replace(/\\/g, '');
|
153 | mustUnescape = false;
|
154 | }
|
155 | push(params, paramName, value);
|
156 | if (code === 0x2c) {
|
157 | push(offers, extensionName, params);
|
158 | params = Object.create(null);
|
159 | extensionName = undefined;
|
160 | }
|
161 |
|
162 | paramName = undefined;
|
163 | start = end = -1;
|
164 | } else {
|
165 | throw new SyntaxError(`Unexpected character at index ${i}`);
|
166 | }
|
167 | }
|
168 | }
|
169 |
|
170 | if (start === -1 || inQuotes) {
|
171 | throw new SyntaxError('Unexpected end of input');
|
172 | }
|
173 |
|
174 | if (end === -1) end = i;
|
175 | const token = header.slice(start, end);
|
176 | if (extensionName === undefined) {
|
177 | push(offers, token, params);
|
178 | } else {
|
179 | if (paramName === undefined) {
|
180 | push(params, token, true);
|
181 | } else if (mustUnescape) {
|
182 | push(params, paramName, token.replace(/\\/g, ''));
|
183 | } else {
|
184 | push(params, paramName, token);
|
185 | }
|
186 | push(offers, extensionName, params);
|
187 | }
|
188 |
|
189 | return offers;
|
190 | }
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 | function format(extensions) {
|
200 | return Object.keys(extensions)
|
201 | .map((extension) => {
|
202 | let configurations = extensions[extension];
|
203 | if (!Array.isArray(configurations)) configurations = [configurations];
|
204 | return configurations
|
205 | .map((params) => {
|
206 | return [extension]
|
207 | .concat(
|
208 | Object.keys(params).map((k) => {
|
209 | let values = params[k];
|
210 | if (!Array.isArray(values)) values = [values];
|
211 | return values
|
212 | .map((v) => (v === true ? k : `${k}=${v}`))
|
213 | .join('; ');
|
214 | })
|
215 | )
|
216 | .join('; ');
|
217 | })
|
218 | .join(', ');
|
219 | })
|
220 | .join(', ');
|
221 | }
|
222 |
|
223 | module.exports = { format, parse };
|