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