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