blob: 88aa29186f68f4dd808f3f0dbc2f70def286514d [file] [log] [blame]
Andy Greenecc2e722014-10-09 16:57:47 +08001/*
Andy Green2add6342014-10-12 08:38:16 +08002 * lib/hpack.c
3 *
4 * Copyright (C) 2014 Andy Green <andy@warmcat.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22#include "private-libwebsockets.h"
23
24/*
Andy Greenecc2e722014-10-09 16:57:47 +080025 * Official static header table for HPACK
26 * +-------+-----------------------------+---------------+
27 | 1 | :authority | |
28 | 2 | :method | GET |
29 | 3 | :method | POST |
30 | 4 | :path | / |
31 | 5 | :path | /index.html |
32 | 6 | :scheme | http |
33 | 7 | :scheme | https |
34 | 8 | :status | 200 |
35 | 9 | :status | 204 |
36 | 10 | :status | 206 |
37 | 11 | :status | 304 |
38 | 12 | :status | 400 |
39 | 13 | :status | 404 |
40 | 14 | :status | 500 |
41 | 15 | accept-charset | |
42 | 16 | accept-encoding | gzip, deflate |
43 | 17 | accept-language | |
44 | 18 | accept-ranges | |
45 | 19 | accept | |
46 | 20 | access-control-allow-origin | |
47 | 21 | age | |
48 | 22 | allow | |
49 | 23 | authorization | |
50 | 24 | cache-control | |
51 | 25 | content-disposition | |
52 | 26 | content-encoding | |
53 | 27 | content-language | |
54 | 28 | content-length | |
55 | 29 | content-location | |
56 | 30 | content-range | |
57 | 31 | content-type | |
58 | 32 | cookie | |
59 | 33 | date | |
60 | 34 | etag | |
61 | 35 | expect | |
62 | 36 | expires | |
63 | 37 | from | |
64 | 38 | host | |
65 | 39 | if-match | |
66 | 40 | if-modified-since | |
67 | 41 | if-none-match | |
68 | 42 | if-range | |
69 | 43 | if-unmodified-since | |
70 | 44 | last-modified | |
71 | 45 | link | |
72 | 46 | location | |
73 | 47 | max-forwards | |
74 | 48 | proxy-authenticate | |
75 | 49 | proxy-authorization | |
76 | 50 | range | |
77 | 51 | referer | |
78 | 52 | refresh | |
79 | 53 | retry-after | |
80 | 54 | server | |
81 | 55 | set-cookie | |
82 | 56 | strict-transport-security | |
83 | 57 | transfer-encoding | |
84 | 58 | user-agent | |
85 | 59 | vary | |
86 | 60 | via | |
87 | 61 | www-authenticate | |
88 +-------+-----------------------------+---------------+
89*/
90
91static const unsigned char static_token[] = {
92 0,
93 WSI_TOKEN_HTTP_COLON_AUTHORITY,
94 WSI_TOKEN_HTTP_COLON_METHOD,
95 WSI_TOKEN_HTTP_COLON_METHOD,
96 WSI_TOKEN_HTTP_COLON_PATH,
97 WSI_TOKEN_HTTP_COLON_PATH,
98 WSI_TOKEN_HTTP_COLON_SCHEME,
99 WSI_TOKEN_HTTP_COLON_SCHEME,
100 WSI_TOKEN_HTTP_COLON_STATUS,
101 WSI_TOKEN_HTTP_COLON_STATUS,
102 WSI_TOKEN_HTTP_COLON_STATUS,
103 WSI_TOKEN_HTTP_COLON_STATUS,
104 WSI_TOKEN_HTTP_COLON_STATUS,
105 WSI_TOKEN_HTTP_COLON_STATUS,
106 WSI_TOKEN_HTTP_COLON_STATUS,
107 WSI_TOKEN_HTTP_ACCEPT_CHARSET,
108 WSI_TOKEN_HTTP_ACCEPT_ENCODING,
109 WSI_TOKEN_HTTP_ACCEPT_LANGUAGE,
110 WSI_TOKEN_HTTP_ACCEPT_RANGES,
111 WSI_TOKEN_HTTP_ACCEPT,
112 WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,
113 WSI_TOKEN_HTTP_AGE,
114 WSI_TOKEN_HTTP_ALLOW,
115 WSI_TOKEN_HTTP_AUTHORIZATION,
116 WSI_TOKEN_HTTP_CACHE_CONTROL,
117 WSI_TOKEN_HTTP_CONTENT_DISPOSITION,
118 WSI_TOKEN_HTTP_CONTENT_ENCODING,
119 WSI_TOKEN_HTTP_CONTENT_LANGUAGE,
120 WSI_TOKEN_HTTP_CONTENT_LENGTH,
121 WSI_TOKEN_HTTP_CONTENT_LOCATION,
122 WSI_TOKEN_HTTP_CONTENT_RANGE,
123 WSI_TOKEN_HTTP_CONTENT_TYPE,
124 WSI_TOKEN_HTTP_COOKIE,
125 WSI_TOKEN_HTTP_DATE,
126 WSI_TOKEN_HTTP_ETAG,
127 WSI_TOKEN_HTTP_EXPECT,
128 WSI_TOKEN_HTTP_EXPIRES,
129 WSI_TOKEN_HTTP_FROM,
Andy Green2add6342014-10-12 08:38:16 +0800130 WSI_TOKEN_HOST,
Andy Greenecc2e722014-10-09 16:57:47 +0800131 WSI_TOKEN_HTTP_IF_MATCH,
132 WSI_TOKEN_HTTP_IF_MODIFIED_SINCE,
133 WSI_TOKEN_HTTP_IF_NONE_MATCH,
134 WSI_TOKEN_HTTP_IF_RANGE,
135 WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE,
136 WSI_TOKEN_HTTP_LAST_MODIFIED,
137 WSI_TOKEN_HTTP_LINK,
138 WSI_TOKEN_HTTP_LOCATION,
139 WSI_TOKEN_HTTP_MAX_FORWARDS,
140 WSI_TOKEN_HTTP_PROXY_AUTHENTICATE,
141 WSI_TOKEN_HTTP_PROXY_AUTHORIZATION,
142 WSI_TOKEN_HTTP_RANGE,
143 WSI_TOKEN_HTTP_REFERER,
144 WSI_TOKEN_HTTP_REFRESH,
145 WSI_TOKEN_HTTP_RETRY_AFTER,
146 WSI_TOKEN_HTTP_SERVER,
147 WSI_TOKEN_HTTP_SET_COOKIE,
148 WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY,
149 WSI_TOKEN_HTTP_TRANSFER_ENCODING,
150 WSI_TOKEN_HTTP_USER_AGENT,
151 WSI_TOKEN_HTTP_VARY,
152 WSI_TOKEN_HTTP_VIA,
153 WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
154};
155
Andy Green2add6342014-10-12 08:38:16 +0800156/* some of the entries imply values as well as header names */
157
Andy Greenecc2e722014-10-09 16:57:47 +0800158static const char * const http2_canned[] = {
159 "",
160 "",
161 "GET",
162 "POST",
163 "/",
164 "/index.html",
165 "http",
166 "https",
167 "200",
168 "204",
169 "206",
Andy Greenecc2e722014-10-09 16:57:47 +0800170 "304",
171 "400",
172 "404",
173 "500",
174 "",
175 "gzip, deflate"
176};
177
Andy Green2add6342014-10-12 08:38:16 +0800178/* see minihuf.c */
179
Andy Greenecc2e722014-10-09 16:57:47 +0800180#include "huftable.h"
181
Andy Green2add6342014-10-12 08:38:16 +0800182static int huftable_decode(int pos, char c)
Andy Greenecc2e722014-10-09 16:57:47 +0800183{
184 int q = pos + !!c;
185
186 if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */
187 return lextable[q] | 0x8000;
188
189 return pos + (lextable[q] << 1);
190}
191
Andy Green4b85c1d2015-12-04 11:08:32 +0800192static int lws_hpack_update_table_size(struct lws *wsi, int idx)
Andy Greenecc2e722014-10-09 16:57:47 +0800193{
Andy Green2add6342014-10-12 08:38:16 +0800194 lwsl_info("hpack set table size %d\n", idx);
195 return 0;
Andy Greenecc2e722014-10-09 16:57:47 +0800196}
197
Andy Green4b85c1d2015-12-04 11:08:32 +0800198static int lws_frag_start(struct lws *wsi, int hdr_token_idx)
Andy Greenecc2e722014-10-09 16:57:47 +0800199{
Andy Green2add6342014-10-12 08:38:16 +0800200 struct allocated_headers * ah = wsi->u.http2.http.ah;
201
202 if (!hdr_token_idx)
203 return 1;
Andy Green40110e82015-12-14 08:52:03 +0800204
Andy Green6b5de702015-12-15 21:15:58 +0800205 if (ah->nfrag >= ARRAY_SIZE(ah->frag_index))
Andy Green2add6342014-10-12 08:38:16 +0800206 return 1;
Andy Green40110e82015-12-14 08:52:03 +0800207
Andy Green6b5de702015-12-15 21:15:58 +0800208 ah->frags[ah->nfrag].offset = ah->pos;
209 ah->frags[ah->nfrag].len = 0;
210 ah->frags[ah->nfrag].nfrag = 0;
Andy Green2add6342014-10-12 08:38:16 +0800211
Andy Green6b5de702015-12-15 21:15:58 +0800212 ah->frag_index[hdr_token_idx] = ah->nfrag;
Andy Green40110e82015-12-14 08:52:03 +0800213
Andy Green2add6342014-10-12 08:38:16 +0800214 return 0;
215}
216
Andy Green4b85c1d2015-12-04 11:08:32 +0800217static int lws_frag_append(struct lws *wsi, unsigned char c)
Andy Green2add6342014-10-12 08:38:16 +0800218{
219 struct allocated_headers * ah = wsi->u.http2.http.ah;
220
221 ah->data[ah->pos++] = c;
Andy Green6b5de702015-12-15 21:15:58 +0800222 ah->frags[ah->nfrag].len++;
Andy Green40110e82015-12-14 08:52:03 +0800223
Andy Green2add6342014-10-12 08:38:16 +0800224 return ah->pos >= sizeof(ah->data);
225}
226
Andy Green4b85c1d2015-12-04 11:08:32 +0800227static int lws_frag_end(struct lws *wsi)
Andy Green2add6342014-10-12 08:38:16 +0800228{
229 if (lws_frag_append(wsi, 0))
230 return 1;
231
Andy Green6b5de702015-12-15 21:15:58 +0800232 wsi->u.http2.http.ah->nfrag++;
Andy Green2add6342014-10-12 08:38:16 +0800233 return 0;
234}
235
Andy Green4b85c1d2015-12-04 11:08:32 +0800236static void lws_dump_header(struct lws *wsi, int hdr)
Andy Green2add6342014-10-12 08:38:16 +0800237{
238 char s[200];
239 int len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);
240 s[len] = '\0';
Andy Green200f3852014-10-18 12:23:05 +0800241 lwsl_info(" hdr tok %d (%s) = '%s'\n", hdr, lws_token_to_string(hdr), s);
Andy Green2add6342014-10-12 08:38:16 +0800242}
243
Andy Green576d3ec2015-12-06 10:05:37 +0800244static int
245lws_token_from_index(struct lws *wsi, int index, char **arg, int *len)
Andy Green2add6342014-10-12 08:38:16 +0800246{
Andy Green200f3852014-10-18 12:23:05 +0800247 struct hpack_dynamic_table *dyn;
Andy Green40110e82015-12-14 08:52:03 +0800248
Andy Green200f3852014-10-18 12:23:05 +0800249 /* dynamic table only belongs to network wsi */
Andy Green40110e82015-12-14 08:52:03 +0800250
Andy Green200f3852014-10-18 12:23:05 +0800251 wsi = lws_http2_get_network_wsi(wsi);
Andy Green40110e82015-12-14 08:52:03 +0800252
Andy Green200f3852014-10-18 12:23:05 +0800253 dyn = wsi->u.http2.hpack_dyn_table;
254
Andy Green2add6342014-10-12 08:38:16 +0800255 if (index < ARRAY_SIZE(static_token))
256 return static_token[index];
Andy Green200f3852014-10-18 12:23:05 +0800257
258 if (!dyn)
259 return 0;
Andy Green40110e82015-12-14 08:52:03 +0800260
Andy Green200f3852014-10-18 12:23:05 +0800261 index -= ARRAY_SIZE(static_token);
262 if (index >= dyn->num_entries)
263 return 0;
Andy Green40110e82015-12-14 08:52:03 +0800264
Andy Green200f3852014-10-18 12:23:05 +0800265 if (arg && len) {
266 *arg = dyn->args + dyn->entries[index].arg_offset;
267 *len = dyn->entries[index].arg_len;
268 }
Andy Green40110e82015-12-14 08:52:03 +0800269
Andy Green200f3852014-10-18 12:23:05 +0800270 return dyn->entries[index].token;
Andy Green2add6342014-10-12 08:38:16 +0800271}
272
Andy Green576d3ec2015-12-06 10:05:37 +0800273static int
274lws_hpack_add_dynamic_header(struct lws *wsi, int token, char *arg, int len)
Andy Green200f3852014-10-18 12:23:05 +0800275{
276 struct hpack_dynamic_table *dyn;
277 int ret = 1;
Andy Green40110e82015-12-14 08:52:03 +0800278
Andy Green200f3852014-10-18 12:23:05 +0800279 wsi = lws_http2_get_network_wsi(wsi);
280 dyn = wsi->u.http2.hpack_dyn_table;
281
282 if (!dyn) {
Alejandro Mery6ff28242014-12-04 23:59:35 +0100283 dyn = lws_zalloc(sizeof(*dyn));
Andy Green200f3852014-10-18 12:23:05 +0800284 if (!dyn)
285 return 1;
Andy Green200f3852014-10-18 12:23:05 +0800286 wsi->u.http2.hpack_dyn_table = dyn;
Andy Green40110e82015-12-14 08:52:03 +0800287
Alejandro Mery6ff28242014-12-04 23:59:35 +0100288 dyn->args = lws_malloc(1024);
Andy Green200f3852014-10-18 12:23:05 +0800289 if (!dyn->args)
290 goto bail1;
291 dyn->args_length = 1024;
Alejandro Mery6ff28242014-12-04 23:59:35 +0100292 dyn->entries = lws_malloc(sizeof(dyn->entries[0]) * 20);
Andy Green200f3852014-10-18 12:23:05 +0800293 if (!dyn->entries)
294 goto bail2;
295 dyn->num_entries = 20;
296 }
Andy Green40110e82015-12-14 08:52:03 +0800297
Andy Green200f3852014-10-18 12:23:05 +0800298 if (dyn->next == dyn->num_entries)
299 return 1;
Andy Green40110e82015-12-14 08:52:03 +0800300
Andy Green200f3852014-10-18 12:23:05 +0800301 if (dyn->args_length - dyn->pos < len)
302 return 1;
Andy Green40110e82015-12-14 08:52:03 +0800303
Andy Green200f3852014-10-18 12:23:05 +0800304 dyn->entries[dyn->next].token = token;
305 dyn->entries[dyn->next].arg_offset = dyn->pos;
306 if (len)
307 memcpy(dyn->args + dyn->pos, arg, len);
308 dyn->entries[dyn->next].arg_len = len;
Andy Green40110e82015-12-14 08:52:03 +0800309
Andy Green576d3ec2015-12-06 10:05:37 +0800310 lwsl_info("%s: added dynamic hdr %d, token %d (%s), len %d\n",
311 __func__, dyn->next, token, lws_token_to_string(token), len);
Andy Green40110e82015-12-14 08:52:03 +0800312
Andy Green200f3852014-10-18 12:23:05 +0800313 dyn->pos += len;
314 dyn->next++;
Andy Green40110e82015-12-14 08:52:03 +0800315
Andy Green200f3852014-10-18 12:23:05 +0800316 return 0;
Alejandro Mery6ff28242014-12-04 23:59:35 +0100317
Andy Green200f3852014-10-18 12:23:05 +0800318bail2:
Alejandro Mery6ff28242014-12-04 23:59:35 +0100319 lws_free(dyn->args);
Andy Green200f3852014-10-18 12:23:05 +0800320bail1:
Alejandro Mery6ff28242014-12-04 23:59:35 +0100321 lws_free(dyn);
Andy Green200f3852014-10-18 12:23:05 +0800322 wsi->u.http2.hpack_dyn_table = NULL;
Alejandro Mery6ff28242014-12-04 23:59:35 +0100323
Andy Green200f3852014-10-18 12:23:05 +0800324 return ret;
325}
326
Andy Green4b85c1d2015-12-04 11:08:32 +0800327static int lws_write_indexed_hdr(struct lws *wsi, int idx)
Andy Green2add6342014-10-12 08:38:16 +0800328{
329 const char *p;
Andy Green200f3852014-10-18 12:23:05 +0800330 int tok = lws_token_from_index(wsi, idx, NULL, 0);
Andy Green2add6342014-10-12 08:38:16 +0800331
Andy Green576d3ec2015-12-06 10:05:37 +0800332 lwsl_info("writing indexed hdr %d (tok %d '%s')\n", idx, tok,
333 lws_token_to_string(tok));
Andy Green2add6342014-10-12 08:38:16 +0800334
335 if (lws_frag_start(wsi, tok))
336 return 1;
337
338 if (idx < ARRAY_SIZE(http2_canned)) {
339 p = http2_canned[idx];
340 while (*p)
341 if (lws_frag_append(wsi, *p++))
342 return 1;
343 }
344 if (lws_frag_end(wsi))
345 return 1;
Andy Green40110e82015-12-14 08:52:03 +0800346
Andy Green2add6342014-10-12 08:38:16 +0800347 lws_dump_header(wsi, tok);
348
349 return 0;
350}
351
Andy Green4b85c1d2015-12-04 11:08:32 +0800352int lws_hpack_interpret(struct lws_context *context,
353 struct lws *wsi, unsigned char c)
Andy Green2add6342014-10-12 08:38:16 +0800354{
355 unsigned int prev;
356 unsigned char c1;
357 int n;
358
Andy Greenecc2e722014-10-09 16:57:47 +0800359 switch (wsi->u.http2.hpack) {
Andy Green200f3852014-10-18 12:23:05 +0800360 case HPKS_OPT_PADDING:
361 wsi->u.http2.padding = c;
362 lwsl_info("padding %d\n", c);
363 if (wsi->u.http2.flags & LWS_HTTP2_FLAG_PRIORITY) {
364 wsi->u.http2.hpack = HKPS_OPT_E_DEPENDENCY;
365 wsi->u.http2.hpack_m = 4;
366 } else
367 wsi->u.http2.hpack = HPKS_TYPE;
368 break;
369 case HKPS_OPT_E_DEPENDENCY:
370 wsi->u.http2.hpack_e_dep <<= 8;
371 wsi->u.http2.hpack_e_dep |= c;
372 if (! --wsi->u.http2.hpack_m) {
373 lwsl_info("hpack_e_dep = 0x%x\n", wsi->u.http2.hpack_e_dep);
374 wsi->u.http2.hpack = HKPS_OPT_WEIGHT;
375 }
376 break;
377 case HKPS_OPT_WEIGHT:
378 /* weight */
379 wsi->u.http2.hpack = HPKS_TYPE;
380 break;
Andy Green40110e82015-12-14 08:52:03 +0800381
Andy Greenecc2e722014-10-09 16:57:47 +0800382 case HPKS_TYPE:
Andy Green40110e82015-12-14 08:52:03 +0800383
Andy Greenbbbf07a2014-10-27 16:46:44 +0800384 if (wsi->u.http2.count > (wsi->u.http2.length - wsi->u.http2.padding)) {
385 lwsl_info("padding eat\n");
386 break;
387 }
Andy Green40110e82015-12-14 08:52:03 +0800388
Andy Greenecc2e722014-10-09 16:57:47 +0800389 if (c & 0x80) { /* indexed header field only */
Andy Green2add6342014-10-12 08:38:16 +0800390 /* just a possibly-extended integer */
391 wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_7;
Andy Greenecc2e722014-10-09 16:57:47 +0800392 wsi->u.http2.header_index = c & 0x7f;
Andy Green2add6342014-10-12 08:38:16 +0800393 if ((c & 0x7f) == 0x7f) {
394 wsi->u.http2.hpack_len = c & 0x7f;
395 wsi->u.http2.hpack_m = 0;
396 wsi->u.http2.hpack = HPKS_IDX_EXT;
397 break;
398 }
Andy Green200f3852014-10-18 12:23:05 +0800399 if (lws_write_indexed_hdr(wsi, c & 0x7f))
Andy Green2add6342014-10-12 08:38:16 +0800400 return 1;
Andy Greenecc2e722014-10-09 16:57:47 +0800401 /* stay at same state */
402 break;
403 }
404 if (c & 0x40) { /* literal header incr idx */
Andy Green2add6342014-10-12 08:38:16 +0800405 /*
406 * [possibly-extended hdr idx (6) | new literal hdr name]
407 * H + possibly-extended value length
408 * literal value
409 */
410 wsi->u.http2.header_index = 0;
Andy Greenecc2e722014-10-09 16:57:47 +0800411 if (c == 0x40) { /* literal name */
Andy Green2add6342014-10-12 08:38:16 +0800412 wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
413 wsi->u.http2.value = 0;
Andy Greenecc2e722014-10-09 16:57:47 +0800414 wsi->u.http2.hpack = HPKS_HLEN;
415 break;
416 }
417 /* indexed name */
Andy Green2add6342014-10-12 08:38:16 +0800418 wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
419 if ((c & 0x3f) == 0x3f) {
420 wsi->u.http2.hpack_len = c & 0x3f;
421 wsi->u.http2.hpack_m = 0;
422 wsi->u.http2.hpack = HPKS_IDX_EXT;
423 break;
424 }
Andy Greenecc2e722014-10-09 16:57:47 +0800425 wsi->u.http2.header_index = c & 0x3f;
Andy Green2add6342014-10-12 08:38:16 +0800426 wsi->u.http2.value = 1;
Andy Greenecc2e722014-10-09 16:57:47 +0800427 wsi->u.http2.hpack = HPKS_HLEN;
428 break;
429 }
430 switch(c & 0xf0) {
Andy Green2add6342014-10-12 08:38:16 +0800431 case 0x10: /* literal header never index */
Andy Greenecc2e722014-10-09 16:57:47 +0800432 case 0: /* literal header without indexing */
Andy Green40110e82015-12-14 08:52:03 +0800433 /*
Andy Green2add6342014-10-12 08:38:16 +0800434 * follows 0x40 except 4-bit hdr idx
435 * and don't add to index
436 */
Andy Greenecc2e722014-10-09 16:57:47 +0800437 if (c == 0) { /* literal name */
Andy Green2add6342014-10-12 08:38:16 +0800438 wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE;
439 wsi->u.http2.hpack = HPKS_HLEN;
440 wsi->u.http2.value = 0;
Andy Greenecc2e722014-10-09 16:57:47 +0800441 break;
442 }
443 /* indexed name */
Andy Green2add6342014-10-12 08:38:16 +0800444 wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_4_VALUE;
445 wsi->u.http2.header_index = 0;
446 if ((c & 0xf) == 0xf) {
447 wsi->u.http2.hpack_len = c & 0xf;
448 wsi->u.http2.hpack_m = 0;
449 wsi->u.http2.hpack = HPKS_IDX_EXT;
Andy Greenecc2e722014-10-09 16:57:47 +0800450 break;
451 }
Andy Greenecc2e722014-10-09 16:57:47 +0800452 wsi->u.http2.header_index = c & 0xf;
Andy Green2add6342014-10-12 08:38:16 +0800453 wsi->u.http2.value = 1;
454 wsi->u.http2.hpack = HPKS_HLEN;
Andy Greenecc2e722014-10-09 16:57:47 +0800455 break;
Andy Green2add6342014-10-12 08:38:16 +0800456
Andy Greenecc2e722014-10-09 16:57:47 +0800457 case 0x20:
458 case 0x30: /* header table size update */
Andy Green2add6342014-10-12 08:38:16 +0800459 /* possibly-extended size value (5) */
460 wsi->u.http2.hpack_type = HPKT_SIZE_5;
461 if ((c & 0x1f) == 0x1f) {
462 wsi->u.http2.hpack_len = c & 0x1f;
463 wsi->u.http2.hpack_m = 0;
464 wsi->u.http2.hpack = HPKS_IDX_EXT;
465 break;
466 }
467 lws_hpack_update_table_size(wsi, c & 0x1f);
468 /* stay at HPKS_TYPE state */
Andy Greenecc2e722014-10-09 16:57:47 +0800469 break;
470 }
Andy Green2add6342014-10-12 08:38:16 +0800471 break;
Andy Green40110e82015-12-14 08:52:03 +0800472
Andy Green2add6342014-10-12 08:38:16 +0800473 case HPKS_IDX_EXT:
474 wsi->u.http2.hpack_len += (c & 0x7f) << wsi->u.http2.hpack_m;
475 wsi->u.http2.hpack_m += 7;
476 if (!(c & 0x80)) {
477 switch (wsi->u.http2.hpack_type) {
478 case HPKT_INDEXED_HDR_7:
Andy Green200f3852014-10-18 12:23:05 +0800479 if (lws_write_indexed_hdr(wsi, wsi->u.http2.hpack_len))
Andy Green2add6342014-10-12 08:38:16 +0800480 return 1;
481 wsi->u.http2.hpack = HPKS_TYPE;
482 break;
483 default:
484 wsi->u.http2.header_index = wsi->u.http2.hpack_len;
485 wsi->u.http2.value = 1;
486 wsi->u.http2.hpack = HPKS_HLEN;
487 break;
488 }
489 }
490 break;
491
492 case HPKS_HLEN: /* [ H | 7+ ] */
Andy Greenecc2e722014-10-09 16:57:47 +0800493 wsi->u.http2.huff = !!(c & 0x80);
Andy Green2add6342014-10-12 08:38:16 +0800494 wsi->u.http2.hpack_pos = 0;
Andy Greenecc2e722014-10-09 16:57:47 +0800495 wsi->u.http2.hpack_len = c & 0x7f;
Andy Green2add6342014-10-12 08:38:16 +0800496 if (wsi->u.http2.hpack_len < 0x7f) {
497pre_data:
498 if (wsi->u.http2.value) {
Andy Green576d3ec2015-12-06 10:05:37 +0800499 if (lws_frag_start(wsi, lws_token_from_index(wsi,
500 wsi->u.http2.header_index,
501 NULL, NULL)))
Andy Green2add6342014-10-12 08:38:16 +0800502 return 1;
503 } else
504 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
505 wsi->u.http2.hpack = HPKS_DATA;
Andy Greenecc2e722014-10-09 16:57:47 +0800506 break;
507 }
508 wsi->u.http2.hpack_m = 0;
Andy Green2add6342014-10-12 08:38:16 +0800509 wsi->u.http2.hpack = HPKS_HLEN_EXT;
Andy Greenecc2e722014-10-09 16:57:47 +0800510 break;
Andy Green40110e82015-12-14 08:52:03 +0800511
Andy Greenecc2e722014-10-09 16:57:47 +0800512 case HPKS_HLEN_EXT:
Andy Green2add6342014-10-12 08:38:16 +0800513 wsi->u.http2.hpack_len += (c & 0x7f) <<
514 wsi->u.http2.hpack_m;
Andy Greenecc2e722014-10-09 16:57:47 +0800515 wsi->u.http2.hpack_m += 7;
516 if (!(c & 0x80))
Andy Green2add6342014-10-12 08:38:16 +0800517 goto pre_data;
518
Andy Greenecc2e722014-10-09 16:57:47 +0800519 break;
520
521 case HPKS_DATA:
Andy Green2add6342014-10-12 08:38:16 +0800522 for (n = 0; n < 8; n++) {
523 if (wsi->u.http2.huff) {
524 prev = wsi->u.http2.hpack_pos;
Andy Green576d3ec2015-12-06 10:05:37 +0800525 wsi->u.http2.hpack_pos = huftable_decode(
Andy Green2add6342014-10-12 08:38:16 +0800526 wsi->u.http2.hpack_pos,
Andy Green576d3ec2015-12-06 10:05:37 +0800527 (c >> 7) & 1);
Andy Green2add6342014-10-12 08:38:16 +0800528 c <<= 1;
529 if (wsi->u.http2.hpack_pos == 0xffff)
530 return 1;
531 if (!(wsi->u.http2.hpack_pos & 0x8000))
532 continue;
533 c1 = wsi->u.http2.hpack_pos & 0x7fff;
534 wsi->u.http2.hpack_pos = 0;
Andy Green40110e82015-12-14 08:52:03 +0800535
Andy Green2add6342014-10-12 08:38:16 +0800536 if (!c1 && prev == HUFTABLE_0x100_PREV)
537 ; /* EOT */
538 } else {
539 n = 8;
540 c1 = c;
541 }
542 if (wsi->u.http2.value) { /* value */
543 if (lws_frag_append(wsi, c1))
544 return 1;
545 } else { /* name */
Andy Green6b5de702015-12-15 21:15:58 +0800546 if (lws_parse(wsi, c1))
Andy Green2add6342014-10-12 08:38:16 +0800547 return 1;
Andy Green40110e82015-12-14 08:52:03 +0800548
Andy Green2add6342014-10-12 08:38:16 +0800549 }
550 }
551 if (--wsi->u.http2.hpack_len == 0) {
Andy Green40110e82015-12-14 08:52:03 +0800552
Andy Green200f3852014-10-18 12:23:05 +0800553 switch (wsi->u.http2.hpack_type) {
554 case HPKT_LITERAL_HDR_VALUE_INCR:
555 case HPKT_INDEXED_HDR_6_VALUE_INCR: // !!!
Andy Green576d3ec2015-12-06 10:05:37 +0800556 if (lws_hpack_add_dynamic_header(wsi,
557 lws_token_from_index(wsi,
558 wsi->u.http2.header_index,
559 NULL, NULL), NULL, 0))
Andy Green200f3852014-10-18 12:23:05 +0800560 return 1;
561 break;
562 default:
563 break;
564 }
Andy Green40110e82015-12-14 08:52:03 +0800565
Andy Green2add6342014-10-12 08:38:16 +0800566 n = 8;
567 if (wsi->u.http2.value) {
568 if (lws_frag_end(wsi))
569 return 1;
Andy Greenecc2e722014-10-09 16:57:47 +0800570
Andy Green576d3ec2015-12-06 10:05:37 +0800571 lws_dump_header(wsi, lws_token_from_index(
572 wsi, wsi->u.http2.header_index,
573 NULL, NULL));
574 if (wsi->u.http2.count + wsi->u.http2.padding ==
575 wsi->u.http2.length)
Andy Green200f3852014-10-18 12:23:05 +0800576 wsi->u.http2.hpack = HKPS_OPT_DISCARD_PADDING;
577 else
578 wsi->u.http2.hpack = HPKS_TYPE;
Andy Green2add6342014-10-12 08:38:16 +0800579 } else { /* name */
580 if (wsi->u.hdr.parser_state < WSI_TOKEN_COUNT)
Andy Green40110e82015-12-14 08:52:03 +0800581
Andy Green2add6342014-10-12 08:38:16 +0800582 wsi->u.http2.value = 1;
583 wsi->u.http2.hpack = HPKS_HLEN;
584 }
585 }
586 break;
Andy Green200f3852014-10-18 12:23:05 +0800587 case HKPS_OPT_DISCARD_PADDING:
588 lwsl_info("eating padding %x\n", c);
589 if (! --wsi->u.http2.padding)
590 wsi->u.http2.hpack = HPKS_TYPE;
591 break;
Andy Greenecc2e722014-10-09 16:57:47 +0800592 }
Andy Green40110e82015-12-14 08:52:03 +0800593
Andy Green2add6342014-10-12 08:38:16 +0800594 return 0;
Andy Greenecc2e722014-10-09 16:57:47 +0800595}
Andy Green917f43a2014-10-12 14:31:47 +0800596
Andy Greendc8a3a82015-12-06 09:15:27 +0800597static int lws_http2_num(int starting_bits, unsigned long num,
598 unsigned char **p, unsigned char *end)
Andy Green917f43a2014-10-12 14:31:47 +0800599{
600 int mask = (1 << starting_bits) - 1;
601
602 if (num < mask) {
603 *((*p)++) |= num;
604 return *p >= end;
605 }
Andy Green40110e82015-12-14 08:52:03 +0800606
Andy Green917f43a2014-10-12 14:31:47 +0800607 *((*p)++) |= mask;
608 if (*p >= end)
609 return 1;
Andy Green40110e82015-12-14 08:52:03 +0800610
Andy Green917f43a2014-10-12 14:31:47 +0800611 num -= mask;
612 while (num >= 128) {
613 *((*p)++) = 0x80 | (num & 0x7f);
614 if (*p >= end)
615 return 1;
616 num >>= 7;
617 }
Andy Green40110e82015-12-14 08:52:03 +0800618
Andy Green917f43a2014-10-12 14:31:47 +0800619 return 0;
620}
621
Andy Green576d3ec2015-12-06 10:05:37 +0800622int lws_add_http2_header_by_name(struct lws_context *context, struct lws *wsi,
Andy Greendc8a3a82015-12-06 09:15:27 +0800623 const unsigned char *name,
Andy Green576d3ec2015-12-06 10:05:37 +0800624 const unsigned char *value, int length,
625 unsigned char **p, unsigned char *end)
Andy Green917f43a2014-10-12 14:31:47 +0800626{
627 int len;
Andy Green40110e82015-12-14 08:52:03 +0800628
Andy Green917f43a2014-10-12 14:31:47 +0800629 lwsl_info("%s: %p %s:%s\n", __func__, *p, name, value);
Andy Green40110e82015-12-14 08:52:03 +0800630
Andy Green917f43a2014-10-12 14:31:47 +0800631 len = strlen((char *)name);
632 if (len)
633 if (name[len - 1] == ':')
634 len--;
635
636 if (end - *p < len + length + 8)
637 return 1;
638
639 *((*p)++) = 0; /* not indexed, literal name */
640
641 **p = 0; /* non-HUF */
642 if (lws_http2_num(7, len, p, end))
643 return 1;
644 memcpy(*p, name, len);
645 *p += len;
646
647 *(*p) = 0; /* non-HUF */
648 if (lws_http2_num(7, length, p, end))
649 return 1;
Andy Green40110e82015-12-14 08:52:03 +0800650
Andy Green917f43a2014-10-12 14:31:47 +0800651 memcpy(*p, value, length);
652 *p += length;
Andy Green40110e82015-12-14 08:52:03 +0800653
Andy Green917f43a2014-10-12 14:31:47 +0800654 return 0;
655}
656
Andy Greendc8a3a82015-12-06 09:15:27 +0800657int lws_add_http2_header_by_token(struct lws_context *context, struct lws *wsi,
Andy Green576d3ec2015-12-06 10:05:37 +0800658 enum lws_token_indexes token,
659 const unsigned char *value, int length,
660 unsigned char **p, unsigned char *end)
Andy Green917f43a2014-10-12 14:31:47 +0800661{
662 const unsigned char *name;
663
664 name = lws_token_to_string(token);
665 if (!name)
666 return 1;
Andy Green40110e82015-12-14 08:52:03 +0800667
Andy Greendc8a3a82015-12-06 09:15:27 +0800668 return lws_add_http2_header_by_name(context, wsi, name, value,
669 length, p, end);
Andy Green917f43a2014-10-12 14:31:47 +0800670}
671
Andy Greendc8a3a82015-12-06 09:15:27 +0800672int lws_add_http2_header_status(struct lws_context *context, struct lws *wsi,
673 unsigned int code, unsigned char **p,
674 unsigned char *end)
Andy Green917f43a2014-10-12 14:31:47 +0800675{
676 unsigned char status[10];
677 int n;
Andy Green40110e82015-12-14 08:52:03 +0800678
Andy Green1cea5812014-10-19 07:36:20 +0800679 wsi->u.http2.send_END_STREAM = !!(code >= 400);
Andy Green40110e82015-12-14 08:52:03 +0800680
Andy Green917f43a2014-10-12 14:31:47 +0800681 n = sprintf((char *)status, "%u", code);
Andy Greendc8a3a82015-12-06 09:15:27 +0800682 if (lws_add_http2_header_by_token(context, wsi,
683 WSI_TOKEN_HTTP_COLON_STATUS, status,
684 n, p, end))
Andy Green917f43a2014-10-12 14:31:47 +0800685 return 1;
686
687 return 0;
Alejandro Mery6ff28242014-12-04 23:59:35 +0100688}