4 * Copyright (C) 2014-2019 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-lib-core.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 uint8_t static_hdr_len[62] = {
93 10, 7, 7, 5, 5, 7, 7, 7, 7, 7,
94 7, 7, 7, 7, 14, 15, 15, 13, 6, 27,
95 3, 5, 13, 13, 19, 16, 16, 14, 16, 13,
96 12, 6, 4, 4, 6, 7, 4, 4, 8, 17,
97 13, 8, 19, 13, 4, 8, 12, 18, 19, 5,
98 7, 7, 11, 6, 10, 25, 17, 10, 4, 3,
102 static const unsigned char static_token[] = {
104 WSI_TOKEN_HTTP_COLON_AUTHORITY,
105 WSI_TOKEN_HTTP_COLON_METHOD,
106 WSI_TOKEN_HTTP_COLON_METHOD,
107 WSI_TOKEN_HTTP_COLON_PATH,
108 WSI_TOKEN_HTTP_COLON_PATH,
109 WSI_TOKEN_HTTP_COLON_SCHEME,
110 WSI_TOKEN_HTTP_COLON_SCHEME,
111 WSI_TOKEN_HTTP_COLON_STATUS,
112 WSI_TOKEN_HTTP_COLON_STATUS,
113 WSI_TOKEN_HTTP_COLON_STATUS,
114 WSI_TOKEN_HTTP_COLON_STATUS,
115 WSI_TOKEN_HTTP_COLON_STATUS,
116 WSI_TOKEN_HTTP_COLON_STATUS,
117 WSI_TOKEN_HTTP_COLON_STATUS,
118 WSI_TOKEN_HTTP_ACCEPT_CHARSET,
119 WSI_TOKEN_HTTP_ACCEPT_ENCODING,
120 WSI_TOKEN_HTTP_ACCEPT_LANGUAGE,
121 WSI_TOKEN_HTTP_ACCEPT_RANGES,
122 WSI_TOKEN_HTTP_ACCEPT,
123 WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,
125 WSI_TOKEN_HTTP_ALLOW,
126 WSI_TOKEN_HTTP_AUTHORIZATION,
127 WSI_TOKEN_HTTP_CACHE_CONTROL,
128 WSI_TOKEN_HTTP_CONTENT_DISPOSITION,
129 WSI_TOKEN_HTTP_CONTENT_ENCODING,
130 WSI_TOKEN_HTTP_CONTENT_LANGUAGE,
131 WSI_TOKEN_HTTP_CONTENT_LENGTH,
132 WSI_TOKEN_HTTP_CONTENT_LOCATION,
133 WSI_TOKEN_HTTP_CONTENT_RANGE,
134 WSI_TOKEN_HTTP_CONTENT_TYPE,
135 WSI_TOKEN_HTTP_COOKIE,
138 WSI_TOKEN_HTTP_EXPECT,
139 WSI_TOKEN_HTTP_EXPIRES,
142 WSI_TOKEN_HTTP_IF_MATCH,
143 WSI_TOKEN_HTTP_IF_MODIFIED_SINCE,
144 WSI_TOKEN_HTTP_IF_NONE_MATCH,
145 WSI_TOKEN_HTTP_IF_RANGE,
146 WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE,
147 WSI_TOKEN_HTTP_LAST_MODIFIED,
149 WSI_TOKEN_HTTP_LOCATION,
150 WSI_TOKEN_HTTP_MAX_FORWARDS,
151 WSI_TOKEN_HTTP_PROXY_AUTHENTICATE,
152 WSI_TOKEN_HTTP_PROXY_AUTHORIZATION,
153 WSI_TOKEN_HTTP_RANGE,
154 WSI_TOKEN_HTTP_REFERER,
155 WSI_TOKEN_HTTP_REFRESH,
156 WSI_TOKEN_HTTP_RETRY_AFTER,
157 WSI_TOKEN_HTTP_SERVER,
158 WSI_TOKEN_HTTP_SET_COOKIE,
159 WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY,
160 WSI_TOKEN_HTTP_TRANSFER_ENCODING,
161 WSI_TOKEN_HTTP_USER_AGENT,
164 WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
167 /* some of the entries imply values as well as header names */
169 static const char * const http2_canned[] = {
191 #include "huftable.h"
193 static int huftable_decode(int pos, char c)
197 if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */
198 return lextable[q] | 0x8000;
200 return pos + (lextable[q] << 1);
203 static int lws_frag_start(struct lws *wsi, int hdr_token_idx)
205 struct allocated_headers *ah = wsi->http.ah;
208 lwsl_notice("%s: no ah\n", __func__);
212 ah->hdr_token_idx = -1;
214 lwsl_header("%s: token %d ah->pos = %d, ah->nfrag = %d\n",
215 __func__, hdr_token_idx, ah->pos, ah->nfrag);
217 if (!hdr_token_idx) {
218 lwsl_err("%s: zero hdr_token_idx\n", __func__);
222 if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frag_index)) {
223 lwsl_err("%s: frag index %d too big\n", __func__, ah->nfrag);
227 if ((hdr_token_idx == WSI_TOKEN_HTTP_COLON_AUTHORITY ||
228 hdr_token_idx == WSI_TOKEN_HTTP_COLON_METHOD ||
229 hdr_token_idx == WSI_TOKEN_HTTP_COLON_PATH ||
230 hdr_token_idx == WSI_TOKEN_COLON_PROTOCOL ||
231 hdr_token_idx == WSI_TOKEN_HTTP_COLON_SCHEME) &&
232 ah->frag_index[hdr_token_idx]) {
233 if (!(ah->frags[ah->frag_index[hdr_token_idx]].flags & 1)) {
234 lws_h2_goaway(lws_get_network_wsi(wsi),
235 H2_ERR_PROTOCOL_ERROR,
236 "Duplicated pseudoheader");
244 ah->frags[ah->nfrag].offset = ah->pos;
245 ah->frags[ah->nfrag].len = 0;
246 ah->frags[ah->nfrag].nfrag = 0;
247 ah->frags[ah->nfrag].flags = 2; /* we had reason to set it */
249 ah->hdr_token_idx = hdr_token_idx;
252 * Okay, but we could be, eg, the second or subsequent cookie: header
255 if (ah->frag_index[hdr_token_idx]) {
258 /* find the last fragment for this header... */
259 n = ah->frag_index[hdr_token_idx];
260 while (ah->frags[n].nfrag)
261 n = ah->frags[n].nfrag;
262 /* and point it to continue in our continuation fragment */
263 ah->frags[n].nfrag = ah->nfrag;
265 /* cookie continuations need a separator token of ';' */
266 if (hdr_token_idx == WSI_TOKEN_HTTP_COOKIE) {
267 ah->data[ah->pos++] = ';';
268 ah->frags[ah->nfrag].len++;
271 ah->frag_index[hdr_token_idx] = ah->nfrag;
276 static int lws_frag_append(struct lws *wsi, unsigned char c)
278 struct allocated_headers *ah = wsi->http.ah;
280 ah->data[ah->pos++] = c;
281 ah->frags[ah->nfrag].len++;
283 return (int)ah->pos >= wsi->context->max_http_header_data;
286 static int lws_frag_end(struct lws *wsi)
288 lwsl_header("%s\n", __func__);
289 if (lws_frag_append(wsi, 0))
292 /* don't account for the terminating NUL in the logical length */
293 wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
295 wsi->http.ah->nfrag++;
300 lws_hdr_extant(struct lws *wsi, enum lws_token_indexes h)
302 struct allocated_headers *ah = wsi->http.ah;
308 n = ah->frag_index[h];
312 return !!(ah->frags[n].flags & 2);
315 static void lws_dump_header(struct lws *wsi, int hdr)
318 const unsigned char *p;
321 if (hdr == LWS_HPACK_IGNORE_ENTRY) {
322 lwsl_notice("hdr tok ignored\n");
328 len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);
330 strcpy(s, "(too big to show)");
333 p = lws_token_to_string(hdr);
334 lwsl_header(" hdr tok %d (%s) = '%s' (len %d)\n", hdr,
335 p ? (char *)p : (char *)"null", s, len);
341 * [ 0 .... num_entries - 1]
343 * Starts filling at 0+
345 * #62 is *most recently entered*
347 * Number of entries is not restricted, but aggregated size of the entry
348 * payloads is. Unfortunately the way HPACK does this is specific to an
349 * imagined implementation, and lws implementation is much more efficient
350 * (ignoring unknown headers and using the lws token index for the header
355 * returns 0 if dynamic entry (arg and len are filled)
356 * returns -1 if failure
357 * returns nonzero token index if actually static token
360 lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len,
363 struct hpack_dynamic_table *dyn;
365 if (index == LWS_HPACK_IGNORE_ENTRY)
366 return LWS_HPACK_IGNORE_ENTRY;
368 /* dynamic table only belongs to network wsi */
369 wsi = lws_get_network_wsi(wsi);
373 dyn = &wsi->h2.h2n->hpack_dyn_table;
378 if (index < (int)LWS_ARRAY_SIZE(static_token)) {
379 if (arg && index < (int)LWS_ARRAY_SIZE(http2_canned)) {
380 *arg = http2_canned[index];
381 *len = (int)strlen(http2_canned[index]);
384 *hdr_len = static_hdr_len[index];
386 return static_token[index];
390 lwsl_notice("no dynamic table\n");
394 if (index < (int)LWS_ARRAY_SIZE(static_token) ||
395 index >= (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries) {
396 lwsl_info(" %s: adjusted index %d >= %d\n", __func__, index,
398 lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
399 "index out of range");
403 index -= (int)LWS_ARRAY_SIZE(static_token);
404 index = (dyn->pos - 1 - index) % dyn->num_entries;
406 index += dyn->num_entries;
408 lwsl_header("%s: dyn index %d, tok %d\n", __func__, index,
409 dyn->entries[index].lws_hdr_idx);
412 *arg = dyn->entries[index].value;
413 *len = dyn->entries[index].value_len;
417 *hdr_len = dyn->entries[index].hdr_len;
419 return dyn->entries[index].lws_hdr_idx;
423 lws_h2_dynamic_table_dump(struct lws *wsi)
426 struct lws *nwsi = lws_get_network_wsi(wsi);
427 struct hpack_dynamic_table *dyn;
433 dyn = &nwsi->h2.h2n->hpack_dyn_table;
435 lwsl_header("Dump dyn table for nwsi %p (%d / %d members, pos = %d, "
436 "start index %d, virt used %d / %d)\n", nwsi,
437 dyn->used_entries, dyn->num_entries, dyn->pos,
438 (uint32_t)LWS_ARRAY_SIZE(static_token),
439 dyn->virtual_payload_usage, dyn->virtual_payload_max);
441 for (n = 0; n < dyn->used_entries; n++) {
442 m = (dyn->pos - 1 - n) % dyn->num_entries;
444 m += dyn->num_entries;
445 if (dyn->entries[m].lws_hdr_idx != LWS_HPACK_IGNORE_ENTRY)
446 p = (const char *)lws_token_to_string(
447 dyn->entries[m].lws_hdr_idx);
450 lwsl_header(" %3d: tok %s: (len %d) val '%s'\n",
451 (int)(n + LWS_ARRAY_SIZE(static_token)), p,
452 dyn->entries[m].hdr_len, dyn->entries[m].value ?
453 dyn->entries[m].value : "null");
460 lws_dynamic_free(struct hpack_dynamic_table *dyn, int idx)
462 lwsl_header("freeing %d for reuse\n", idx);
463 dyn->virtual_payload_usage -= dyn->entries[idx].value_len +
464 dyn->entries[idx].hdr_len;
465 lws_free_set_NULL(dyn->entries[idx].value);
466 dyn->entries[idx].value = NULL;
467 dyn->entries[idx].value_len = 0;
468 dyn->entries[idx].hdr_len = 0;
469 dyn->entries[idx].lws_hdr_idx = LWS_HPACK_IGNORE_ENTRY;
474 * There are two address spaces, 1) internal ringbuffer and 2) HPACK indexes.
476 * Internal ringbuffer:
478 * The internal ringbuffer wraps as we keep filling it, dyn->pos points to
479 * the next index to be written.
483 * The last-written entry becomes entry 0, the previously-last-written entry
484 * becomes entry 1 etc.
488 lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
489 int lws_hdr_index, char *arg, int len)
491 struct hpack_dynamic_table *dyn;
494 /* dynamic table only belongs to network wsi */
495 wsi = lws_get_network_wsi(wsi);
498 dyn = &wsi->h2.h2n->hpack_dyn_table;
501 lwsl_err("%s: unsized dyn table\n", __func__);
505 lws_h2_dynamic_table_dump(wsi);
507 new_index = (dyn->pos) % dyn->num_entries;
508 if (dyn->num_entries && dyn->used_entries == dyn->num_entries) {
509 if (dyn->virtual_payload_usage < dyn->virtual_payload_max)
510 lwsl_err("Dropping header content before limit!\n");
511 /* we have to drop the oldest to make space */
512 lws_dynamic_free(dyn, new_index);
516 * evict guys to make room, allowing for some overage. We have to
517 * take care about getting a single huge header, and evicting
521 while (dyn->virtual_payload_usage &&
523 dyn->virtual_payload_usage + hdr_len + len >
524 dyn->virtual_payload_max + 1024) {
525 int n = (dyn->pos - dyn->used_entries) % dyn->num_entries;
527 n += dyn->num_entries;
528 lws_dynamic_free(dyn, n);
531 if (dyn->used_entries < dyn->num_entries)
534 dyn->entries[new_index].value_len = 0;
536 if (lws_hdr_index != LWS_HPACK_IGNORE_ENTRY) {
537 if (dyn->entries[new_index].value)
538 lws_free_set_NULL(dyn->entries[new_index].value);
539 dyn->entries[new_index].value =
540 lws_malloc(len + 1, "hpack dyn");
541 if (!dyn->entries[new_index].value)
544 memcpy(dyn->entries[new_index].value, arg, len);
545 dyn->entries[new_index].value[len] = '\0';
546 dyn->entries[new_index].value_len = len;
548 dyn->entries[new_index].value = NULL;
550 dyn->entries[new_index].lws_hdr_idx = lws_hdr_index;
551 dyn->entries[new_index].hdr_len = hdr_len;
553 dyn->virtual_payload_usage += hdr_len + len;
555 lwsl_info("%s: index %ld: lws_hdr_index 0x%x, hdr len %d, '%s' len %d\n",
556 __func__, (long)LWS_ARRAY_SIZE(static_token),
557 lws_hdr_index, hdr_len, dyn->entries[new_index].value ?
558 dyn->entries[new_index].value : "null", len);
560 dyn->pos = (dyn->pos + 1) % dyn->num_entries;
562 lws_h2_dynamic_table_dump(wsi);
568 lws_hpack_dynamic_size(struct lws *wsi, int size)
570 struct hpack_dynamic_table *dyn;
571 struct hpack_dt_entry *dte;
576 * "size" here is coming from the http/2 SETTING
577 * SETTINGS_HEADER_TABLE_SIZE. This is a (virtual, in our case)
578 * linear buffer containing dynamic header names and values... when it
579 * is full, old entries are evicted.
581 * We encode the header as an lws_hdr_idx, which is all the rest of
582 * lws cares about; if there is no matching header we store an empty
583 * entry in the dyn table as a placeholder.
585 * So to make the two systems work together we keep an accounting of
586 * what we are using to decide when to evict... we must only evict
587 * things when the remote peer's accounting also makes him feel he
588 * should evict something.
591 nwsi = lws_get_network_wsi(wsi);
595 dyn = &nwsi->h2.h2n->hpack_dyn_table;
596 lwsl_info("%s: from %d to %d, lim %d\n", __func__,
597 (int)dyn->num_entries, size,
598 nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
601 size = dyn->num_entries * 8;
602 lws_hpack_destroy_dynamic_header(wsi);
605 if (size > (int)nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]) {
606 lwsl_info("rejecting hpack dyn size %u vs %u\n", size,
607 nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
609 // this seems necessary to work with some browsers
611 if (nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE] == 65536 &&
612 size == 65537) { /* h2spec */
613 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
614 "Asked for header table bigger than we told");
618 size = nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE];
621 dyn->virtual_payload_max = size;
625 if (min > dyn->used_entries)
626 min = dyn->used_entries;
628 if (size == dyn->num_entries)
631 if (dyn->num_entries < min)
632 min = dyn->num_entries;
634 // lwsl_notice("dte requested size %d\n", size);
636 dte = lws_zalloc(sizeof(*dte) * (size + 1), "dynamic table entries");
640 while (dyn->virtual_payload_usage && dyn->used_entries &&
641 dyn->virtual_payload_usage > dyn->virtual_payload_max) {
642 n = (dyn->pos - dyn->used_entries) % dyn->num_entries;
644 n += dyn->num_entries;
645 lws_dynamic_free(dyn, n);
648 if (min > dyn->used_entries)
649 min = dyn->used_entries;
652 for (n = 0; n < min; n++) {
653 m = (dyn->pos - dyn->used_entries + n) %
656 m += dyn->num_entries;
657 dte[n] = dyn->entries[m];
660 lws_free(dyn->entries);
664 dyn->num_entries = size;
665 dyn->used_entries = min;
667 dyn->pos = min % size;
671 lws_h2_dynamic_table_dump(wsi);
676 lwsl_info("%s: failed to resize to %d\n", __func__, size);
682 lws_hpack_destroy_dynamic_header(struct lws *wsi)
684 struct hpack_dynamic_table *dyn;
690 dyn = &wsi->h2.h2n->hpack_dyn_table;
695 for (n = 0; n < dyn->num_entries; n++)
696 if (dyn->entries[n].value)
697 lws_free_set_NULL(dyn->entries[n].value);
699 lws_free_set_NULL(dyn->entries);
703 lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token)
705 const char *arg = NULL;
707 const char *p = NULL;
708 int tok = lws_token_from_index(wsi, idx, &arg, &len, NULL);
710 if (tok == LWS_HPACK_IGNORE_ENTRY) {
711 lwsl_header("%s: lws_token says ignore, returning\n", __func__);
716 lwsl_info("%s: idx %d mapped to tok %d\n", __func__, idx, tok);
724 lwsl_header("%s: dyn: idx %d '%s' tok %d\n", __func__, idx, arg,
727 lwsl_header("writing indexed hdr %d (tok %d '%s')\n", idx, tok,
728 lws_token_to_string(tok));
730 if (tok == LWS_HPACK_IGNORE_ENTRY)
736 if (idx < (int)LWS_ARRAY_SIZE(http2_canned))
737 p = http2_canned[idx];
739 if (lws_frag_start(wsi, tok))
744 if (lws_frag_append(wsi, *p++))
747 if (lws_frag_end(wsi))
750 lws_dump_header(wsi, tok);
755 static uint8_t lws_header_implies_psuedoheader_map[] = {
756 0x07, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00 /* <-64 */,
757 0x0e /* <- 72 */, 0x04 /* <- 80 */, 0, 0, 0, 0
761 lws_hpack_handle_pseudo_rules(struct lws *nwsi, struct lws *wsi, int m)
763 if (m == LWS_HPACK_IGNORE_ENTRY || m == -1)
766 if (wsi->seen_nonpseudoheader &&
767 (lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7)))) {
769 lwsl_info("lws tok %d seems to be a pseudoheader\n", m);
772 * it's not legal to see a
773 * pseudoheader after normal
776 lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
777 "Pseudoheader after normal hdrs");
781 if (!(lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7))))
782 wsi->seen_nonpseudoheader = 1;
787 int lws_hpack_interpret(struct lws *wsi, unsigned char c)
789 struct lws *nwsi = lws_get_network_wsi(wsi);
790 struct lws_h2_netconn *h2n = nwsi->h2.h2n;
791 struct allocated_headers *ah = wsi->http.ah;
800 * HPKT_INDEXED_HDR_7 1xxxxxxx: just "header field"
801 * HPKT_INDEXED_HDR_6_VALUE_INCR 01xxxxxx: NEW indexed hdr + val
802 * HPKT_LITERAL_HDR_VALUE_INCR 01000000: NEW literal hdr + val
803 * HPKT_INDEXED_HDR_4_VALUE 0000xxxx: indexed hdr + val
804 * HPKT_INDEXED_HDR_4_VALUE_NEVER 0001xxxx: NEVER NEW indexed hdr + val
805 * HPKT_LITERAL_HDR_VALUE 00000000: literal hdr + val
806 * HPKT_LITERAL_HDR_VALUE_NEVER 00010000: NEVER NEW literal hdr + val
808 switch (h2n->hpack) {
811 h2n->is_first_header_char = 1;
813 h2n->zero_huff_padding = 0;
814 h2n->last_action_dyntable_resize = 0;
816 h2n->hpack_hdr_len = 0;
817 h2n->unknown_header = 0;
818 ah->parser_state = 255;
820 if (c & 0x80) { /* 1.... indexed header field only */
821 /* just a possibly-extended integer */
822 h2n->hpack_type = HPKT_INDEXED_HDR_7;
823 lwsl_header("HPKT_INDEXED_HDR_7 hdr %d\n", c & 0x7f);
824 lws_h2_dynamic_table_dump(wsi);
826 h2n->hdr_idx = c & 0x7f;
827 if ((c & 0x7f) == 0x7f) {
830 h2n->hpack = HPKS_IDX_EXT;
834 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
839 m = lws_token_from_index(wsi, h2n->hdr_idx,
841 if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
844 lwsl_header("HPKT_INDEXED_HDR_7: hdr %d\n", c & 0x7f);
845 if (lws_hpack_use_idx_hdr(wsi, c & 0x7f, -1)) {
846 lwsl_header("%s: idx hdr wr fail\n", __func__);
849 /* stay at same state */
852 if (c & 0x40) { /* 01.... indexed or literal header incr idx */
854 * [possibly-ext hdr idx (6) | new literal hdr name]
855 * H + possibly-ext value length
859 if (c == 0x40) { /* literal header */
860 lwsl_header(" HPKT_LITERAL_HDR_VALUE_INCR\n");
861 h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
864 h2n->hpack = HPKS_HLEN;
868 h2n->hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
869 lwsl_header(" HPKT_INDEXED_HDR_6_VALUE_INCR (hdr %d)\n",
871 h2n->hdr_idx = c & 0x3f;
872 if ((c & 0x3f) == 0x3f) {
875 h2n->hpack = HPKS_IDX_EXT;
880 h2n->hpack = HPKS_HLEN;
882 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
889 case 0x10: /* literal header never index */
890 case 0: /* literal header without indexing */
892 * follows 0x40 except 4-bit hdr idx
893 * and don't add to index
895 if (c == 0) { /* literal name */
896 h2n->hpack_type = HPKT_LITERAL_HDR_VALUE;
897 lwsl_header(" HPKT_LITERAL_HDR_VALUE\n");
898 h2n->hpack = HPKS_HLEN;
902 if (c == 0x10) { /* literal name NEVER */
903 h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_NEVER;
904 lwsl_header(" HPKT_LITERAL_HDR_VALUE_NEVER\n");
905 h2n->hpack = HPKS_HLEN;
909 lwsl_header("indexed\n");
912 h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE_NEVER;
913 lwsl_header("HPKT_LITERAL_HDR_4_VALUE_NEVER\n");
915 h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE;
916 lwsl_header(" HPKT_INDEXED_HDR_4_VALUE\n");
919 if ((c & 0xf) == 0xf) {
920 h2n->hpack_len = c & 0xf;
923 h2n->hpack = HPKS_IDX_EXT;
926 h2n->hdr_idx = c & 0xf;
928 h2n->hpack = HPKS_HLEN;
932 case 0x30: /* header table size update */
933 /* possibly-extended size value (5) */
934 lwsl_header("HPKT_SIZE_5 %x\n", c &0x1f);
935 h2n->hpack_type = HPKT_SIZE_5;
936 h2n->hpack_len = c & 0x1f;
937 if (h2n->hpack_len == 0x1f) {
940 h2n->hpack = HPKS_IDX_EXT;
943 h2n->last_action_dyntable_resize = 1;
944 if (lws_hpack_dynamic_size(wsi, h2n->hpack_len))
951 h2n->hpack_len = h2n->hpack_len |
952 ((c & 0x7f) << h2n->ext_count);
954 if (c & 0x80) /* extended int not complete yet */
957 /* extended integer done */
958 h2n->hpack_len += h2n->hpack_m;
959 lwsl_header("HPKS_IDX_EXT: hpack_len %d\n", h2n->hpack_len);
961 switch (h2n->hpack_type) {
962 case HPKT_INDEXED_HDR_7:
963 if (lws_hpack_use_idx_hdr(wsi, h2n->hpack_len,
965 lwsl_notice("%s: hd7 use fail\n", __func__);
968 h2n->hpack = HPKS_TYPE;
972 h2n->last_action_dyntable_resize = 1;
973 if (lws_hpack_dynamic_size(wsi, h2n->hpack_len))
975 h2n->hpack = HPKS_TYPE;
979 h2n->hdr_idx = h2n->hpack_len;
981 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
982 "extended header index was 0");
986 h2n->hpack = HPKS_HLEN;
991 case HPKS_HLEN: /* [ H | 7+ ] */
992 h2n->huff = !!(c & 0x80);
994 h2n->hpack_len = c & 0x7f;
996 if (h2n->hpack_len == 0x7f) {
1000 h2n->hpack = HPKS_HLEN_EXT;
1004 h2n->hpack = HPKS_DATA;
1005 if (!h2n->value || !h2n->hdr_idx) {
1006 ah->parser_state = WSI_TOKEN_NAME_PART;
1007 ah->lextable_pos = 0;
1008 h2n->unknown_header = 0;
1012 if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1013 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1014 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) {
1015 n = ah->parser_state;
1022 n = lws_token_from_index(wsi, h2n->hdr_idx, NULL,
1024 lwsl_header(" lws_tok_from_idx(%d) says %d\n",
1028 if (n == LWS_HPACK_IGNORE_ENTRY || n == -1)
1029 h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
1031 switch (h2n->hpack_type) {
1033 * hpack types with literal headers were parsed by the lws
1034 * header SM... on recognition of a known lws header, it does
1035 * the correct lws_frag_start() for us already. Other types
1036 * (ie, indexed header) need us to do it here.
1038 case HPKT_LITERAL_HDR_VALUE_INCR:
1039 case HPKT_LITERAL_HDR_VALUE:
1040 case HPKT_LITERAL_HDR_VALUE_NEVER:
1043 if (n != -1 && n != LWS_HPACK_IGNORE_ENTRY &&
1044 lws_frag_start(wsi, n)) {
1045 lwsl_header("%s: frag start failed\n",
1054 h2n->hpack_len = h2n->hpack_len |
1055 ((c & 0x7f) << h2n->ext_count);
1056 h2n->ext_count += 7;
1057 if (c & 0x80) /* extended integer not complete yet */
1060 h2n->hpack_len += h2n->hpack_m;
1064 //lwsl_header(" 0x%02X huff %d\n", c, h2n->huff);
1067 for (n = 0; n < 8; n++) {
1069 char b = (c >> 7) & 1;
1070 prev = h2n->hpack_pos;
1071 h2n->hpack_pos = huftable_decode(
1074 if (h2n->hpack_pos == 0xffff) {
1075 lwsl_notice("Huffman err\n");
1078 if (!(h2n->hpack_pos & 0x8000)) {
1080 h2n->zero_huff_padding = 1;
1084 c1 = h2n->hpack_pos & 0x7fff;
1087 h2n->zero_huff_padding = 0;
1089 /* EOS |11111111|11111111|11111111|111111 */
1090 if (!c1 && prev == HUFTABLE_0x100_PREV) {
1092 H2_ERR_COMPRESSION_ERROR,
1093 "Huffman EOT seen");
1099 if (h2n->value) { /* value */
1102 h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY) {
1104 if (ah->hdr_token_idx ==
1105 WSI_TOKEN_HTTP_COLON_PATH) {
1107 switch (lws_parse_urldecode(
1113 case LPUR_EXCESSIVE:
1116 H2_ERR_PROTOCOL_ERROR,
1124 if (lws_frag_append(wsi, c1)) {
1126 "%s: frag app fail\n",
1131 //lwsl_header("ignoring %c\n", c1);
1134 * Convert name using existing parser,
1135 * If h2n->unknown_header == 0, result is
1136 * in wsi->parser_state
1137 * using WSI_TOKEN_GET_URI.
1139 * If unknown header h2n->unknown_header
1142 h2n->hpack_hdr_len++;
1143 if (h2n->is_first_header_char) {
1144 h2n->is_first_header_char = 0;
1145 h2n->first_hdr_char = c1;
1147 lwsl_header("parser: %c\n", c1);
1148 /* uppercase header names illegal */
1149 if (c1 >= 'A' && c1 <= 'Z') {
1151 H2_ERR_COMPRESSION_ERROR,
1152 "Uppercase literal hpack hdr");
1156 if (!h2n->unknown_header &&
1157 lws_parse(wsi, &c1, &plen))
1158 h2n->unknown_header = 1;
1164 if (--h2n->hpack_len)
1168 * The header (h2n->value = 0) or the payload (h2n->value = 1)
1172 if (h2n->huff && (h2n->huff_pad > 7 ||
1173 (h2n->zero_huff_padding && h2n->huff_pad))) {
1174 lwsl_info("zero_huff_padding: %d huff_pad: %d\n",
1175 h2n->zero_huff_padding, h2n->huff_pad);
1176 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
1177 "Huffman padding excessive or wrong");
1181 if (!h2n->value && (
1182 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1183 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1184 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER)) {
1185 h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
1186 lwsl_header("wsi->parser_state: %d\n",
1189 if (ah->parser_state == WSI_TOKEN_NAME_PART) {
1190 /* h2 headers come without the colon */
1193 n = lws_parse(wsi, &c1, &plen);
1197 if (ah->parser_state == WSI_TOKEN_NAME_PART ||
1198 #if defined(LWS_WITH_CUSTOM_HEADERS)
1199 ah->parser_state == WSI_TOKEN_UNKNOWN_VALUE_PART ||
1201 ah->parser_state == WSI_TOKEN_SKIPPING) {
1202 h2n->unknown_header = 1;
1203 ah->parser_state = -1;
1204 wsi->seen_nonpseudoheader = 1;
1210 /* we have the header */
1213 h2n->hpack = HPKS_HLEN;
1215 h2n->zero_huff_padding = 0;
1221 * we have got both the header and value
1225 switch (h2n->hpack_type) {
1227 * These are the only two that insert to the dyntable
1229 /* NEW indexed hdr with value */
1230 case HPKT_INDEXED_HDR_6_VALUE_INCR:
1231 /* header length is determined by known index */
1232 m = lws_token_from_index(wsi, h2n->hdr_idx, NULL, NULL,
1233 &h2n->hpack_hdr_len);
1235 /* NEW literal hdr with value */
1236 case HPKT_LITERAL_HDR_VALUE_INCR:
1238 * hdr is a new literal, so length is already in
1239 * h2n->hpack_hdr_len
1241 m = ah->parser_state;
1242 if (h2n->unknown_header ||
1243 ah->parser_state == WSI_TOKEN_NAME_PART ||
1244 ah->parser_state == WSI_TOKEN_SKIPPING) {
1245 if (h2n->first_hdr_char == ':') {
1246 lwsl_info("HPKT_LITERAL_HDR_VALUE_INCR:"
1247 " end state %d unk hdr %d\n",
1249 h2n->unknown_header);
1250 /* unknown pseudoheaders are illegal */
1252 H2_ERR_PROTOCOL_ERROR,
1253 "Unknown pseudoheader");
1256 m = LWS_HPACK_IGNORE_ENTRY;
1260 * mark us as having been set at the time of dynamic
1263 ah->frags[ah->nfrag].flags |= 1;
1265 if (lws_dynamic_token_insert(wsi, h2n->hpack_hdr_len, m,
1266 &ah->data[ah->frags[ah->nfrag].offset],
1267 ah->frags[ah->nfrag].len)) {
1268 lwsl_notice("%s: tok_insert fail\n", __func__);
1277 if (h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY && lws_frag_end(wsi))
1280 if (h2n->hpack_type != HPKT_INDEXED_HDR_6_VALUE_INCR) {
1282 if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1283 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1284 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) {
1285 m = ah->parser_state;
1289 m = lws_token_from_index(wsi, h2n->hdr_idx,
1293 if (m != -1 && m != LWS_HPACK_IGNORE_ENTRY)
1294 lws_dump_header(wsi, m);
1296 if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
1299 h2n->is_first_header_char = 1;
1300 h2n->hpack = HPKS_TYPE;
1310 lws_h2_num_start(int starting_bits, unsigned long num)
1312 unsigned int mask = (1 << starting_bits) - 1;
1321 lws_h2_num(int starting_bits, unsigned long num,
1322 unsigned char **p, unsigned char *end)
1324 unsigned int mask = (1 << starting_bits) - 1;
1332 *((*p)++) = 0x80 | (num & 0x7f);
1334 *((*p)++) = 0x00 | (num & 0x7f);
1343 int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name,
1344 const unsigned char *value, int length,
1345 unsigned char **p, unsigned char *end)
1349 lwsl_header("%s: %p %s:%s\n", __func__, *p, name, value);
1351 len = (int)strlen((char *)name);
1353 if (name[len - 1] == ':')
1356 if (wsi->http2_substream && !strncmp((const char *)name,
1357 "transfer-encoding", len)) {
1358 lwsl_header("rejecting %s\n", name);
1363 if (end - *p < len + length + 8)
1366 *((*p)++) = 0; /* literal hdr, literal name, */
1368 *((*p)++) = 0 | lws_h2_num_start(7, len); /* non-HUF */
1369 if (lws_h2_num(7, len, p, end))
1372 /* upper-case header names are verboten in h2, but OK on h1, so
1373 * they're not illegal per se. Silently convert them for h2... */
1376 *((*p)++) = tolower((int)*name++);
1378 *((*p)++) = 0 | lws_h2_num_start(7, length); /* non-HUF */
1379 if (lws_h2_num(7, length, p, end))
1382 memcpy(*p, value, length);
1388 int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token,
1389 const unsigned char *value, int length,
1390 unsigned char **p, unsigned char *end)
1392 const unsigned char *name;
1394 name = lws_token_to_string(token);
1398 return lws_add_http2_header_by_name(wsi, name, value, length, p, end);
1401 int lws_add_http2_header_status(struct lws *wsi, unsigned int code,
1402 unsigned char **p, unsigned char *end)
1404 unsigned char status[10];
1407 wsi->h2.send_END_STREAM = 0; // !!(code >= 400);
1409 n = sprintf((char *)status, "%u", code);
1410 if (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS,