4 * Copyright (C) 2014 Andy Green <andy@warmcat.com>
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.
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.
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,
22 #include "private-libwebsockets.h"
25 * Official static header table for HPACK
26 * +-------+-----------------------------+---------------+
29 | 3 | :method | POST |
31 | 5 | :path | /index.html |
32 | 6 | :scheme | http |
33 | 7 | :scheme | https |
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 | |
46 | 20 | access-control-allow-origin | |
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 | |
66 | 40 | if-modified-since | |
67 | 41 | if-none-match | |
69 | 43 | if-unmodified-since | |
70 | 44 | last-modified | |
73 | 47 | max-forwards | |
74 | 48 | proxy-authenticate | |
75 | 49 | proxy-authorization | |
79 | 53 | retry-after | |
82 | 56 | strict-transport-security | |
83 | 57 | transfer-encoding | |
87 | 61 | www-authenticate | |
88 +-------+-----------------------------+---------------+
91 static const unsigned char static_token[] = {
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,
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,
127 WSI_TOKEN_HTTP_EXPECT,
128 WSI_TOKEN_HTTP_EXPIRES,
131 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,
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,
153 WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
156 /* some of the entries imply values as well as header names */
158 static const char * const http2_canned[] = {
180 #include "huftable.h"
182 static int huftable_decode(int pos, char c)
186 if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */
187 return lextable[q] | 0x8000;
189 return pos + (lextable[q] << 1);
192 static int lws_hpack_update_table_size(struct lws *wsi, int idx)
194 lwsl_info("hpack set table size %d\n", idx);
198 static int lws_frag_start(struct lws *wsi, int hdr_token_idx)
200 struct allocated_headers * ah = wsi->u.http2.http.ah;
202 if (!hdr_token_idx) {
203 lwsl_err("%s: zero hdr_token_idx\n", __func__);
207 if (ah->nfrag >= ARRAY_SIZE(ah->frag_index)) {
208 lwsl_err("%s: frag index %d too big\n", __func__, ah->nfrag);
212 ah->frags[ah->nfrag].offset = ah->pos;
213 ah->frags[ah->nfrag].len = 0;
214 ah->frags[ah->nfrag].nfrag = 0;
216 ah->frag_index[hdr_token_idx] = ah->nfrag;
221 static int lws_frag_append(struct lws *wsi, unsigned char c)
223 struct allocated_headers * ah = wsi->u.http2.http.ah;
225 ah->data[ah->pos++] = c;
226 ah->frags[ah->nfrag].len++;
228 return ah->pos >= wsi->context->max_http_header_data;
231 static int lws_frag_end(struct lws *wsi)
233 if (lws_frag_append(wsi, 0))
236 wsi->u.http2.http.ah->nfrag++;
240 static void lws_dump_header(struct lws *wsi, int hdr)
243 int len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);
245 lwsl_info(" hdr tok %d (%s) = '%s'\n", hdr, lws_token_to_string(hdr), s);
249 lws_token_from_index(struct lws *wsi, int index, char **arg, int *len)
251 struct hpack_dynamic_table *dyn;
253 /* dynamic table only belongs to network wsi */
255 wsi = lws_http2_get_network_wsi(wsi);
257 dyn = wsi->u.http2.hpack_dyn_table;
259 if (index < ARRAY_SIZE(static_token))
260 return static_token[index];
265 index -= ARRAY_SIZE(static_token);
266 if (index >= dyn->num_entries)
270 *arg = dyn->args + dyn->entries[index].arg_offset;
271 *len = dyn->entries[index].arg_len;
274 return dyn->entries[index].token;
278 lws_hpack_add_dynamic_header(struct lws *wsi, int token, char *arg, int len)
280 struct hpack_dynamic_table *dyn;
283 wsi = lws_http2_get_network_wsi(wsi);
284 dyn = wsi->u.http2.hpack_dyn_table;
287 dyn = lws_zalloc(sizeof(*dyn));
290 wsi->u.http2.hpack_dyn_table = dyn;
292 dyn->args = lws_malloc(1024);
295 dyn->args_length = 1024;
296 dyn->entries = lws_malloc(sizeof(dyn->entries[0]) * 20);
299 dyn->num_entries = 20;
302 if (dyn->next == dyn->num_entries)
305 if (dyn->args_length - dyn->pos < len)
308 dyn->entries[dyn->next].token = token;
309 dyn->entries[dyn->next].arg_offset = dyn->pos;
311 memcpy(dyn->args + dyn->pos, arg, len);
312 dyn->entries[dyn->next].arg_len = len;
314 lwsl_info("%s: added dynamic hdr %d, token %d (%s), len %d\n",
315 __func__, dyn->next, token, lws_token_to_string(token), len);
326 wsi->u.http2.hpack_dyn_table = NULL;
331 static int lws_write_indexed_hdr(struct lws *wsi, int idx)
334 int tok = lws_token_from_index(wsi, idx, NULL, 0);
336 lwsl_info("writing indexed hdr %d (tok %d '%s')\n", idx, tok,
337 lws_token_to_string(tok));
339 if (lws_frag_start(wsi, tok))
342 if (idx < ARRAY_SIZE(http2_canned)) {
343 p = http2_canned[idx];
345 if (lws_frag_append(wsi, *p++))
348 if (lws_frag_end(wsi))
351 lws_dump_header(wsi, tok);
356 int lws_hpack_interpret(struct lws *wsi, unsigned char c)
362 lwsl_debug(" state %d\n", wsi->u.http2.hpack);
364 switch (wsi->u.http2.hpack) {
365 case HPKS_OPT_PADDING:
366 wsi->u.http2.padding = c;
367 lwsl_info("padding %d\n", c);
368 if (wsi->u.http2.flags & LWS_HTTP2_FLAG_PRIORITY) {
369 wsi->u.http2.hpack = HKPS_OPT_E_DEPENDENCY;
370 wsi->u.http2.hpack_m = 4;
372 wsi->u.http2.hpack = HPKS_TYPE;
374 case HKPS_OPT_E_DEPENDENCY:
375 wsi->u.http2.hpack_e_dep <<= 8;
376 wsi->u.http2.hpack_e_dep |= c;
377 if (! --wsi->u.http2.hpack_m) {
378 lwsl_info("hpack_e_dep = 0x%x\n", wsi->u.http2.hpack_e_dep);
379 wsi->u.http2.hpack = HKPS_OPT_WEIGHT;
382 case HKPS_OPT_WEIGHT:
384 wsi->u.http2.hpack = HPKS_TYPE;
389 if (wsi->u.http2.count > (wsi->u.http2.length - wsi->u.http2.padding)) {
390 lwsl_info("padding eat\n");
394 if (c & 0x80) { /* indexed header field only */
395 /* just a possibly-extended integer */
396 wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_7;
397 lwsl_debug("HKPS_TYPE setting header_index %d\n", c & 0x7f);
398 wsi->u.http2.header_index = c & 0x7f;
399 if ((c & 0x7f) == 0x7f) {
400 wsi->u.http2.hpack_len = c & 0x7f;
401 wsi->u.http2.hpack_m = 0;
402 wsi->u.http2.hpack = HPKS_IDX_EXT;
405 lwsl_debug("HKPS_TYPE: %d\n", c & 0x7f);
406 if (lws_write_indexed_hdr(wsi, c & 0x7f))
408 /* stay at same state */
411 if (c & 0x40) { /* literal header incr idx */
413 * [possibly-extended hdr idx (6) | new literal hdr name]
414 * H + possibly-extended value length
417 lwsl_debug("HKPS_TYPE 2 setting header_index %d\n", 0);
418 wsi->u.http2.header_index = 0;
419 if (c == 0x40) { /* literal name */
420 wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
421 wsi->u.http2.value = 0;
422 wsi->u.http2.hpack = HPKS_HLEN;
426 wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
427 if ((c & 0x3f) == 0x3f) {
428 wsi->u.http2.hpack_len = c & 0x3f;
429 wsi->u.http2.hpack_m = 0;
430 wsi->u.http2.hpack = HPKS_IDX_EXT;
433 lwsl_debug("HKPS_TYPE 3 setting header_index %d\n", c & 0x3f);
434 wsi->u.http2.header_index = c & 0x3f;
435 wsi->u.http2.value = 1;
436 wsi->u.http2.hpack = HPKS_HLEN;
440 case 0x10: /* literal header never index */
441 case 0: /* literal header without indexing */
443 * follows 0x40 except 4-bit hdr idx
444 * and don't add to index
446 if (c == 0) { /* literal name */
447 wsi->u.http2.hpack_type = HPKT_LITERAL_HDR_VALUE;
448 wsi->u.http2.hpack = HPKS_HLEN;
449 wsi->u.http2.value = 0;
452 //lwsl_debug("indexed\n");
454 wsi->u.http2.hpack_type = HPKT_INDEXED_HDR_4_VALUE;
455 wsi->u.http2.header_index = 0;
456 if ((c & 0xf) == 0xf) {
457 wsi->u.http2.hpack_len = c & 0xf;
458 wsi->u.http2.hpack_m = 0;
459 wsi->u.http2.hpack = HPKS_IDX_EXT;
462 //lwsl_err("HKPS_TYPE 5 setting header_index %d\n", c & 0xf);
463 wsi->u.http2.header_index = c & 0xf;
464 wsi->u.http2.value = 1;
465 wsi->u.http2.hpack = HPKS_HLEN;
469 case 0x30: /* header table size update */
470 /* possibly-extended size value (5) */
471 wsi->u.http2.hpack_type = HPKT_SIZE_5;
472 if ((c & 0x1f) == 0x1f) {
473 wsi->u.http2.hpack_len = c & 0x1f;
474 wsi->u.http2.hpack_m = 0;
475 wsi->u.http2.hpack = HPKS_IDX_EXT;
478 lws_hpack_update_table_size(wsi, c & 0x1f);
479 /* stay at HPKS_TYPE state */
485 wsi->u.http2.hpack_len += (c & 0x7f) << wsi->u.http2.hpack_m;
486 wsi->u.http2.hpack_m += 7;
488 switch (wsi->u.http2.hpack_type) {
489 case HPKT_INDEXED_HDR_7:
490 //lwsl_err("HKPS_IDX_EXT hdr idx %d\n", wsi->u.http2.hpack_len);
491 if (lws_write_indexed_hdr(wsi, wsi->u.http2.hpack_len))
493 wsi->u.http2.hpack = HPKS_TYPE;
496 // lwsl_err("HKPS_IDX_EXT setting header_index %d\n",
497 // wsi->u.http2.hpack_len);
498 wsi->u.http2.header_index = wsi->u.http2.hpack_len;
499 wsi->u.http2.value = 1;
500 wsi->u.http2.hpack = HPKS_HLEN;
506 case HPKS_HLEN: /* [ H | 7+ ] */
507 wsi->u.http2.huff = !!(c & 0x80);
508 wsi->u.http2.hpack_pos = 0;
509 wsi->u.http2.hpack_len = c & 0x7f;
510 if (wsi->u.http2.hpack_len < 0x7f) {
512 if (wsi->u.http2.value) {
513 if (wsi->u.http2.header_index)
514 if (lws_frag_start(wsi, lws_token_from_index(wsi,
515 wsi->u.http2.header_index,
517 // lwsl_notice("%s: hlen failed\n", __func__);
521 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
522 wsi->u.http2.hpack = HPKS_DATA;
525 wsi->u.http2.hpack_m = 0;
526 wsi->u.http2.hpack = HPKS_HLEN_EXT;
530 wsi->u.http2.hpack_len += (c & 0x7f) <<
531 wsi->u.http2.hpack_m;
532 wsi->u.http2.hpack_m += 7;
539 for (n = 0; n < 8; n++) {
540 if (wsi->u.http2.huff) {
541 prev = wsi->u.http2.hpack_pos;
542 wsi->u.http2.hpack_pos = huftable_decode(
543 wsi->u.http2.hpack_pos,
546 if (wsi->u.http2.hpack_pos == 0xffff)
548 if (!(wsi->u.http2.hpack_pos & 0x8000))
550 c1 = wsi->u.http2.hpack_pos & 0x7fff;
551 wsi->u.http2.hpack_pos = 0;
553 if (!c1 && prev == HUFTABLE_0x100_PREV)
559 if (wsi->u.http2.value) { /* value */
560 if (wsi->u.http2.header_index)
561 if (lws_frag_append(wsi, c1))
564 if (lws_parse(wsi, c1))
569 if (--wsi->u.http2.hpack_len == 0) {
571 switch (wsi->u.http2.hpack_type) {
572 case HPKT_LITERAL_HDR_VALUE_INCR:
573 case HPKT_INDEXED_HDR_6_VALUE_INCR: // !!!
574 if (lws_hpack_add_dynamic_header(wsi,
575 lws_token_from_index(wsi,
576 wsi->u.http2.header_index,
577 NULL, NULL), NULL, 0))
585 if (wsi->u.http2.value) {
586 if (lws_frag_end(wsi))
588 // lwsl_err("data\n");
589 lws_dump_header(wsi, lws_token_from_index(
590 wsi, wsi->u.http2.header_index,
592 if (wsi->u.http2.count + wsi->u.http2.padding ==
594 wsi->u.http2.hpack = HKPS_OPT_DISCARD_PADDING;
596 wsi->u.http2.hpack = HPKS_TYPE;
598 //if (wsi->u.hdr.parser_state < WSI_TOKEN_COUNT)
600 wsi->u.http2.value = 1;
601 wsi->u.http2.hpack = HPKS_HLEN;
605 case HKPS_OPT_DISCARD_PADDING:
606 lwsl_info("eating padding %x\n", c);
607 if (! --wsi->u.http2.padding)
608 wsi->u.http2.hpack = HPKS_TYPE;
615 static int lws_http2_num(int starting_bits, unsigned long num,
616 unsigned char **p, unsigned char *end)
618 int mask = (1 << starting_bits) - 1;
631 *((*p)++) = 0x80 | (num & 0x7f);
640 int lws_add_http2_header_by_name(struct lws *wsi,
641 const unsigned char *name,
642 const unsigned char *value, int length,
643 unsigned char **p, unsigned char *end)
647 lwsl_info("%s: %p %s:%s\n", __func__, *p, name, value);
649 len = strlen((char *)name);
651 if (name[len - 1] == ':')
654 if (end - *p < len + length + 8)
657 *((*p)++) = 0; /* not indexed, literal name */
659 **p = 0; /* non-HUF */
660 if (lws_http2_num(7, len, p, end))
662 memcpy(*p, name, len);
665 *(*p) = 0; /* non-HUF */
666 if (lws_http2_num(7, length, p, end))
669 memcpy(*p, value, length);
675 int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token,
676 const unsigned char *value, int length,
677 unsigned char **p, unsigned char *end)
679 const unsigned char *name;
681 name = lws_token_to_string(token);
685 return lws_add_http2_header_by_name(wsi, name, value, length, p, end);
688 int lws_add_http2_header_status(struct lws *wsi,
689 unsigned int code, unsigned char **p,
692 unsigned char status[10];
695 wsi->u.http2.send_END_STREAM = !!(code >= 400);
697 n = sprintf((char *)status, "%u", code);
698 if (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS,