private.h: rename to contain dir
[platform/upstream/libwebsockets.git] / lib / roles / h2 / hpack.c
1 /*
2  * lib/hpack.c
3  *
4  * Copyright (C) 2014-2019 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-lib-core.h"
23
24 /*
25  * 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
91 static const uint8_t static_hdr_len[62] = {
92                 0, /* starts at 1 */
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,
99                 16
100 };
101
102 static const unsigned char static_token[] = {
103         0,
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,
124         WSI_TOKEN_HTTP_AGE,
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,
136         WSI_TOKEN_HTTP_DATE,
137         WSI_TOKEN_HTTP_ETAG,
138         WSI_TOKEN_HTTP_EXPECT,
139         WSI_TOKEN_HTTP_EXPIRES,
140         WSI_TOKEN_HTTP_FROM,
141         WSI_TOKEN_HOST,
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,
148         WSI_TOKEN_HTTP_LINK,
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,
162         WSI_TOKEN_HTTP_VARY,
163         WSI_TOKEN_HTTP_VIA,
164         WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
165 };
166
167 /* some of the entries imply values as well as header names */
168
169 static const char * const http2_canned[] = {
170         "",
171         "",
172         "GET",
173         "POST",
174         "/",
175         "/index.html",
176         "http",
177         "https",
178         "200",
179         "204",
180         "206",
181         "304",
182         "400",
183         "404",
184         "500",
185         "",
186         "gzip, deflate"
187 };
188
189 /* see minihuf.c */
190
191 #include "huftable.h"
192
193 static int huftable_decode(int pos, char c)
194 {
195         int q = pos + !!c;
196
197         if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */
198                 return lextable[q] | 0x8000;
199
200         return pos + (lextable[q] << 1);
201 }
202
203 static int lws_frag_start(struct lws *wsi, int hdr_token_idx)
204 {
205         struct allocated_headers *ah = wsi->http.ah;
206
207         if (!ah) {
208                 lwsl_notice("%s: no ah\n", __func__);
209                 return 1;
210         }
211
212         ah->hdr_token_idx = -1;
213
214         lwsl_header("%s: token %d ah->pos = %d, ah->nfrag = %d\n",
215                    __func__, hdr_token_idx, ah->pos, ah->nfrag);
216
217         if (!hdr_token_idx) {
218                 lwsl_err("%s: zero hdr_token_idx\n", __func__);
219                 return 1;
220         }
221
222         if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frag_index)) {
223                 lwsl_err("%s: frag index %d too big\n", __func__, ah->nfrag);
224                 return 1;
225         }
226
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");
237                         return 1;
238                 }
239         }
240
241         if (ah->nfrag == 0)
242                 ah->nfrag = 1;
243
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 */
248
249         ah->hdr_token_idx = hdr_token_idx;
250
251         /*
252          * Okay, but we could be, eg, the second or subsequent cookie: header
253          */
254
255         if (ah->frag_index[hdr_token_idx]) {
256                 int n;
257
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;
264
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++;
269                 }
270         } else
271                 ah->frag_index[hdr_token_idx] = ah->nfrag;
272
273         return 0;
274 }
275
276 static int lws_frag_append(struct lws *wsi, unsigned char c)
277 {
278         struct allocated_headers *ah = wsi->http.ah;
279
280         ah->data[ah->pos++] = c;
281         ah->frags[ah->nfrag].len++;
282
283         return (int)ah->pos >= wsi->context->max_http_header_data;
284 }
285
286 static int lws_frag_end(struct lws *wsi)
287 {
288         lwsl_header("%s\n", __func__);
289         if (lws_frag_append(wsi, 0))
290                 return 1;
291
292         /* don't account for the terminating NUL in the logical length */
293         wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
294
295         wsi->http.ah->nfrag++;
296         return 0;
297 }
298
299 int
300 lws_hdr_extant(struct lws *wsi, enum lws_token_indexes h)
301 {
302         struct allocated_headers *ah = wsi->http.ah;
303         int n;
304
305         if (!ah)
306                 return 0;
307
308         n = ah->frag_index[h];
309         if (!n)
310                 return 0;
311
312         return !!(ah->frags[n].flags & 2);
313 }
314
315 static void lws_dump_header(struct lws *wsi, int hdr)
316 {
317         char s[200];
318         const unsigned char *p;
319         int len;
320
321         if (hdr == LWS_HPACK_IGNORE_ENTRY) {
322                 lwsl_notice("hdr tok ignored\n");
323                 return;
324         }
325
326         (void)p;
327
328         len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);
329         if (len < 0)
330                 strcpy(s, "(too big to show)");
331         else
332                 s[len] = '\0';
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);
336 }
337
338 /*
339  * dynamic table
340  *
341  *  [ 0 ....   num_entries - 1]
342  *
343  *  Starts filling at 0+
344  *
345  *  #62 is *most recently entered*
346  *
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
351  *  name part).
352  */
353
354 /*
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
358  */
359 static int
360 lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len,
361                      uint32_t *hdr_len)
362 {
363         struct hpack_dynamic_table *dyn;
364
365         if (index == LWS_HPACK_IGNORE_ENTRY)
366                 return LWS_HPACK_IGNORE_ENTRY;
367
368         /* dynamic table only belongs to network wsi */
369         wsi = lws_get_network_wsi(wsi);
370         if (!wsi->h2.h2n)
371                 return -1;
372
373         dyn = &wsi->h2.h2n->hpack_dyn_table;
374
375         if (index < 0)
376                 return -1;
377
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]);
382                 }
383                 if (hdr_len)
384                         *hdr_len = static_hdr_len[index];
385
386                 return static_token[index];
387         }
388
389         if (!dyn) {
390                 lwsl_notice("no dynamic table\n");
391                 return -1;
392         }
393
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,
397                             dyn->used_entries);
398                 lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
399                               "index out of range");
400                 return -1;
401         }
402
403         index -= (int)LWS_ARRAY_SIZE(static_token);
404         index = (dyn->pos - 1 - index) % dyn->num_entries;
405         if (index < 0)
406                 index += dyn->num_entries;
407
408         lwsl_header("%s: dyn index %d, tok %d\n", __func__, index,
409                     dyn->entries[index].lws_hdr_idx);
410
411         if (arg && len) {
412                 *arg = dyn->entries[index].value;
413                 *len = dyn->entries[index].value_len;
414         }
415
416         if (hdr_len)
417                 *hdr_len = dyn->entries[index].hdr_len;
418
419         return dyn->entries[index].lws_hdr_idx;
420 }
421
422 static int
423 lws_h2_dynamic_table_dump(struct lws *wsi)
424 {
425 #if 0
426         struct lws *nwsi = lws_get_network_wsi(wsi);
427         struct hpack_dynamic_table *dyn;
428         int n, m;
429         const char *p;
430
431         if (!nwsi->h2.h2n)
432                 return 1;
433         dyn = &nwsi->h2.h2n->hpack_dyn_table;
434
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);
440
441         for (n = 0; n < dyn->used_entries; n++) {
442                 m = (dyn->pos - 1 - n) % dyn->num_entries;
443                 if (m < 0)
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);
448                 else
449                         p = "(ignored)";
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");
454         }
455 #endif
456         return 0;
457 }
458
459 static void
460 lws_dynamic_free(struct hpack_dynamic_table *dyn, int idx)
461 {
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;
470         dyn->used_entries--;
471 }
472
473 /*
474  * There are two address spaces, 1) internal ringbuffer and 2) HPACK indexes.
475  *
476  * Internal ringbuffer:
477  *
478  * The internal ringbuffer wraps as we keep filling it, dyn->pos points to
479  * the next index to be written.
480  *
481  * HPACK indexes:
482  *
483  * The last-written entry becomes entry 0, the previously-last-written entry
484  * becomes entry 1 etc.
485  */
486
487 static int
488 lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
489                          int lws_hdr_index, char *arg, int len)
490 {
491         struct hpack_dynamic_table *dyn;
492         int new_index;
493
494         /* dynamic table only belongs to network wsi */
495         wsi = lws_get_network_wsi(wsi);
496         if (!wsi->h2.h2n)
497                 return 1;
498         dyn = &wsi->h2.h2n->hpack_dyn_table;
499
500         if (!dyn->entries) {
501                 lwsl_err("%s: unsized dyn table\n", __func__);
502
503                 return 1;
504         }
505         lws_h2_dynamic_table_dump(wsi);
506
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);
513         }
514
515         /*
516          * evict guys to make room, allowing for some overage.  We have to
517          * take care about getting a single huge header, and evicting
518          * everything
519          */
520
521         while (dyn->virtual_payload_usage &&
522                dyn->used_entries &&
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;
526                 if (n < 0)
527                         n += dyn->num_entries;
528                 lws_dynamic_free(dyn, n);
529         }
530
531         if (dyn->used_entries < dyn->num_entries)
532                 dyn->used_entries++;
533
534         dyn->entries[new_index].value_len = 0;
535
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)
542                         return 1;
543
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;
547         } else
548                 dyn->entries[new_index].value = NULL;
549
550         dyn->entries[new_index].lws_hdr_idx = lws_hdr_index;
551         dyn->entries[new_index].hdr_len = hdr_len;
552
553         dyn->virtual_payload_usage += hdr_len + len;
554
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);
559
560         dyn->pos = (dyn->pos + 1) % dyn->num_entries;
561
562         lws_h2_dynamic_table_dump(wsi);
563
564         return 0;
565 }
566
567 int
568 lws_hpack_dynamic_size(struct lws *wsi, int size)
569 {
570         struct hpack_dynamic_table *dyn;
571         struct hpack_dt_entry *dte;
572         struct lws *nwsi;
573         int min, n = 0, m;
574
575         /*
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.
580          *
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.
584          *
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.
589          */
590
591         nwsi = lws_get_network_wsi(wsi);
592         if (!nwsi->h2.h2n)
593                 goto bail;
594
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]);
599
600         if (!size) {
601                 size = dyn->num_entries * 8;
602                 lws_hpack_destroy_dynamic_header(wsi);
603         }
604
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]);
608
609                 // this seems necessary to work with some browsers
610
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");
615                         goto bail;
616                 }
617
618                 size = nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE];
619         }
620
621         dyn->virtual_payload_max = size;
622
623         size = size / 8;
624         min = size;
625         if (min > dyn->used_entries)
626                 min = dyn->used_entries;
627
628         if (size == dyn->num_entries)
629                 return 0;
630
631         if (dyn->num_entries < min)
632                 min = dyn->num_entries;
633
634         // lwsl_notice("dte requested size %d\n", size);
635
636         dte = lws_zalloc(sizeof(*dte) * (size + 1), "dynamic table entries");
637         if (!dte)
638                 goto bail;
639
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;
643                 if (n < 0)
644                         n += dyn->num_entries;
645                 lws_dynamic_free(dyn, n);
646         }
647
648         if (min > dyn->used_entries)
649                 min = dyn->used_entries;
650
651         if (dyn->entries) {
652                 for (n = 0; n < min; n++) {
653                         m = (dyn->pos - dyn->used_entries + n) %
654                                                 dyn->num_entries;
655                         if (m < 0)
656                                 m += dyn->num_entries;
657                         dte[n] = dyn->entries[m];
658                 }
659
660                 lws_free(dyn->entries);
661         }
662
663         dyn->entries = dte;
664         dyn->num_entries = size;
665         dyn->used_entries = min;
666         if (size)
667                 dyn->pos = min % size;
668         else
669                 dyn->pos = 0;
670
671         lws_h2_dynamic_table_dump(wsi);
672
673         return 0;
674
675 bail:
676         lwsl_info("%s: failed to resize to %d\n", __func__, size);
677
678         return 1;
679 }
680
681 void
682 lws_hpack_destroy_dynamic_header(struct lws *wsi)
683 {
684         struct hpack_dynamic_table *dyn;
685         int n;
686
687         if (!wsi->h2.h2n)
688                 return;
689
690         dyn = &wsi->h2.h2n->hpack_dyn_table;
691
692         if (!dyn->entries)
693                 return;
694
695         for (n = 0; n < dyn->num_entries; n++)
696                 if (dyn->entries[n].value)
697                         lws_free_set_NULL(dyn->entries[n].value);
698
699         lws_free_set_NULL(dyn->entries);
700 }
701
702 static int
703 lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token)
704 {
705         const char *arg = NULL;
706         int len = 0;
707         const char *p = NULL;
708         int tok = lws_token_from_index(wsi, idx, &arg, &len, NULL);
709
710         if (tok == LWS_HPACK_IGNORE_ENTRY) {
711                 lwsl_header("%s: lws_token says ignore, returning\n", __func__);
712                 return 0;
713         }
714
715         if (tok == -1) {
716                 lwsl_info("%s: idx %d mapped to tok %d\n", __func__, idx, tok);
717                 return 1;
718         }
719
720         if (arg) {
721                 /* dynamic result */
722                 if (known_token > 0)
723                         tok = known_token;
724                 lwsl_header("%s: dyn: idx %d '%s' tok %d\n", __func__, idx, arg,
725                            tok);
726         } else
727                 lwsl_header("writing indexed hdr %d (tok %d '%s')\n", idx, tok,
728                                 lws_token_to_string(tok));
729
730         if (tok == LWS_HPACK_IGNORE_ENTRY)
731                 return 0;
732
733         if (arg)
734                 p = arg;
735
736         if (idx < (int)LWS_ARRAY_SIZE(http2_canned))
737                 p = http2_canned[idx];
738
739         if (lws_frag_start(wsi, tok))
740                 return 1;
741
742         if (p)
743                 while (*p && len--)
744                         if (lws_frag_append(wsi, *p++))
745                                 return 1;
746
747         if (lws_frag_end(wsi))
748                 return 1;
749
750         lws_dump_header(wsi, tok);
751
752         return 0;
753 }
754
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
758 };
759
760 static int
761 lws_hpack_handle_pseudo_rules(struct lws *nwsi, struct lws *wsi, int m)
762 {
763         if (m == LWS_HPACK_IGNORE_ENTRY || m == -1)
764                 return 0;
765
766         if (wsi->seen_nonpseudoheader &&
767             (lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7)))) {
768
769                 lwsl_info("lws tok %d seems to be a pseudoheader\n", m);
770
771                 /*
772                  * it's not legal to see a
773                  * pseudoheader after normal
774                  * headers
775                  */
776                 lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
777                         "Pseudoheader after normal hdrs");
778                 return 1;
779         }
780
781         if (!(lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7))))
782                 wsi->seen_nonpseudoheader = 1;
783
784         return 0;
785 }
786
787 int lws_hpack_interpret(struct lws *wsi, unsigned char c)
788 {
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;
792         unsigned int prev;
793         unsigned char c1;
794         int n, m, plen;
795
796         if (!h2n)
797                 return -1;
798
799         /*
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
807          */
808         switch (h2n->hpack) {
809
810         case HPKS_TYPE:
811                 h2n->is_first_header_char = 1;
812                 h2n->huff_pad = 0;
813                 h2n->zero_huff_padding = 0;
814                 h2n->last_action_dyntable_resize = 0;
815                 h2n->ext_count = 0;
816                 h2n->hpack_hdr_len = 0;
817                 h2n->unknown_header = 0;
818                 ah->parser_state = 255;
819
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);
825
826                         h2n->hdr_idx = c & 0x7f;
827                         if ((c & 0x7f) == 0x7f) {
828                                 h2n->hpack_len = 0;
829                                 h2n->hpack_m = 0x7f;
830                                 h2n->hpack = HPKS_IDX_EXT;
831                                 break;
832                         }
833                         if (!h2n->hdr_idx) {
834                                 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
835                                               "hdr index 0 seen");
836                                         return 1;
837                         }
838
839                         m = lws_token_from_index(wsi, h2n->hdr_idx,
840                                                  NULL, NULL, NULL);
841                         if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
842                                 return 1;
843
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__);
847                                 return 1;
848                         }
849                         /* stay at same state */
850                         break;
851                 }
852                 if (c & 0x40) { /* 01.... indexed or literal header incr idx */
853                         /*
854                          * [possibly-ext hdr idx (6) | new literal hdr name]
855                          * H + possibly-ext value length
856                          * literal value
857                          */
858                         h2n->hdr_idx = 0;
859                         if (c == 0x40) { /* literal header */
860                                 lwsl_header("   HPKT_LITERAL_HDR_VALUE_INCR\n");
861                                 h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
862                                 h2n->value = 0;
863                                 h2n->hpack_len = 0;
864                                 h2n->hpack = HPKS_HLEN;
865                                 break;
866                         }
867                         /* indexed header */
868                         h2n->hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
869                         lwsl_header(" HPKT_INDEXED_HDR_6_VALUE_INCR (hdr %d)\n",
870                                    c & 0x3f);
871                         h2n->hdr_idx = c & 0x3f;
872                         if ((c & 0x3f) == 0x3f) {
873                                 h2n->hpack_m = 0x3f;
874                                 h2n->hpack_len = 0;
875                                 h2n->hpack = HPKS_IDX_EXT;
876                                 break;
877                         }
878
879                         h2n->value = 1;
880                         h2n->hpack = HPKS_HLEN;
881                         if (!h2n->hdr_idx) {
882                                 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
883                                               "hdr index 0 seen");
884                                         return 1;
885                         }
886                         break;
887                 }
888                 switch(c & 0xf0) {
889                 case 0x10: /* literal header never index */
890                 case 0:    /* literal header without indexing */
891                         /*
892                          * follows 0x40 except 4-bit hdr idx
893                          * and don't add to index
894                          */
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;
899                                 h2n->value = 0;
900                                 break;
901                         }
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;
906                                 h2n->value = 0;
907                                 break;
908                         }
909                         lwsl_header("indexed\n");
910                         /* indexed name */
911                         if (c & 0x10) {
912                                 h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE_NEVER;
913                                 lwsl_header("HPKT_LITERAL_HDR_4_VALUE_NEVER\n");
914                         } else {
915                                 h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE;
916                                 lwsl_header("   HPKT_INDEXED_HDR_4_VALUE\n");
917                         }
918                         h2n->hdr_idx = 0;
919                         if ((c & 0xf) == 0xf) {
920                                 h2n->hpack_len = c & 0xf;
921                                 h2n->hpack_m = 0xf;
922                                 h2n->hpack_len = 0;
923                                 h2n->hpack = HPKS_IDX_EXT;
924                                 break;
925                         }
926                         h2n->hdr_idx = c & 0xf;
927                         h2n->value = 1;
928                         h2n->hpack = HPKS_HLEN;
929                         break;
930
931                 case 0x20:
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) {
938                                 h2n->hpack_m = 0x1f;
939                                 h2n->hpack_len = 0;
940                                 h2n->hpack = HPKS_IDX_EXT;
941                                 break;
942                         }
943                         h2n->last_action_dyntable_resize = 1;
944                         if (lws_hpack_dynamic_size(wsi, h2n->hpack_len))
945                                 return 1;
946                         break;
947                 }
948                 break;
949
950         case HPKS_IDX_EXT:
951                 h2n->hpack_len = h2n->hpack_len |
952                                  ((c & 0x7f) << h2n->ext_count);
953                 h2n->ext_count += 7;
954                 if (c & 0x80) /* extended int not complete yet */
955                         break;
956
957                 /* extended integer done */
958                 h2n->hpack_len += h2n->hpack_m;
959                 lwsl_header("HPKS_IDX_EXT: hpack_len %d\n", h2n->hpack_len);
960
961                 switch (h2n->hpack_type) {
962                 case HPKT_INDEXED_HDR_7:
963                         if (lws_hpack_use_idx_hdr(wsi, h2n->hpack_len,
964                                                   h2n->hdr_idx)) {
965                                 lwsl_notice("%s: hd7 use fail\n", __func__);
966                                 return 1;
967                         }
968                         h2n->hpack = HPKS_TYPE;
969                         break;
970
971                 case HPKT_SIZE_5:
972                         h2n->last_action_dyntable_resize = 1;
973                         if (lws_hpack_dynamic_size(wsi, h2n->hpack_len))
974                                 return 1;
975                         h2n->hpack = HPKS_TYPE;
976                         break;
977
978                 default:
979                         h2n->hdr_idx = h2n->hpack_len;
980                         if (!h2n->hdr_idx) {
981                                 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
982                                               "extended header index was 0");
983                                 return 1;
984                         }
985                         h2n->value = 1;
986                         h2n->hpack = HPKS_HLEN;
987                         break;
988                 }
989                 break;
990
991         case HPKS_HLEN: /* [ H | 7+ ] */
992                 h2n->huff = !!(c & 0x80);
993                 h2n->hpack_pos = 0;
994                 h2n->hpack_len = c & 0x7f;
995
996                 if (h2n->hpack_len == 0x7f) {
997                         h2n->hpack_m = 0x7f;
998                         h2n->hpack_len = 0;
999                         h2n->ext_count = 0;
1000                         h2n->hpack = HPKS_HLEN_EXT;
1001                         break;
1002                 }
1003 pre_data:
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;
1009                         break;
1010                 }
1011
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;
1016                         if (n == 255) {
1017                                 n = -1;
1018                                 h2n->hdr_idx = -1;
1019                         } else
1020                                 h2n->hdr_idx = 1;
1021                 } else {
1022                         n = lws_token_from_index(wsi, h2n->hdr_idx, NULL,
1023                                                  NULL, NULL);
1024                         lwsl_header("  lws_tok_from_idx(%d) says %d\n",
1025                                    h2n->hdr_idx, n);
1026                 }
1027
1028                 if (n == LWS_HPACK_IGNORE_ENTRY || n == -1)
1029                         h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
1030
1031                 switch (h2n->hpack_type) {
1032                 /*
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.
1037                  */
1038                 case HPKT_LITERAL_HDR_VALUE_INCR:
1039                 case HPKT_LITERAL_HDR_VALUE:
1040                 case HPKT_LITERAL_HDR_VALUE_NEVER:
1041                         break;
1042                 default:
1043                         if (n != -1 && n != LWS_HPACK_IGNORE_ENTRY &&
1044                             lws_frag_start(wsi, n)) {
1045                                 lwsl_header("%s: frag start failed\n",
1046                                             __func__);
1047                                 return 1;
1048                         }
1049                         break;
1050                 }
1051                 break;
1052
1053         case HPKS_HLEN_EXT:
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 */
1058                         break;
1059
1060                 h2n->hpack_len += h2n->hpack_m;
1061                 goto pre_data;
1062
1063         case HPKS_DATA:
1064                 //lwsl_header(" 0x%02X huff %d\n", c, h2n->huff);
1065                         c1 = c;
1066
1067                 for (n = 0; n < 8; n++) {
1068                         if (h2n->huff) {
1069                                 char b = (c >> 7) & 1;
1070                                 prev = h2n->hpack_pos;
1071                                 h2n->hpack_pos = huftable_decode(
1072                                                 h2n->hpack_pos, b);
1073                                 c <<= 1;
1074                                 if (h2n->hpack_pos == 0xffff) {
1075                                         lwsl_notice("Huffman err\n");
1076                                         return 1;
1077                                 }
1078                                 if (!(h2n->hpack_pos & 0x8000)) {
1079                                         if (!b)
1080                                                 h2n->zero_huff_padding = 1;
1081                                         h2n->huff_pad++;
1082                                         continue;
1083                                 }
1084                                 c1 = h2n->hpack_pos & 0x7fff;
1085                                 h2n->hpack_pos = 0;
1086                                 h2n->huff_pad = 0;
1087                                 h2n->zero_huff_padding = 0;
1088
1089                                 /* EOS |11111111|11111111|11111111|111111 */
1090                                 if (!c1 && prev == HUFTABLE_0x100_PREV) {
1091                                         lws_h2_goaway(nwsi,
1092                                                 H2_ERR_COMPRESSION_ERROR,
1093                                                 "Huffman EOT seen");
1094                                         return 1;
1095                                 }
1096                         } else
1097                                 n = 8;
1098
1099                         if (h2n->value) { /* value */
1100
1101                                 if (h2n->hdr_idx &&
1102                                     h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY) {
1103
1104                                         if (ah->hdr_token_idx ==
1105                                             WSI_TOKEN_HTTP_COLON_PATH) {
1106
1107                                                 switch (lws_parse_urldecode(
1108                                                                     wsi, &c1)) {
1109                                                 case LPUR_CONTINUE:
1110                                                         break;
1111                                                 case LPUR_SWALLOW:
1112                                                         goto swallow;
1113                                                 case LPUR_EXCESSIVE:
1114                                                 case LPUR_FORBID:
1115                                                         lws_h2_goaway(nwsi,
1116                                                           H2_ERR_PROTOCOL_ERROR,
1117                                                           "Evil URI");
1118                                                         return 1;
1119
1120                                                 default:
1121                                                         return -1;
1122                                                 }
1123                                         }
1124                                         if (lws_frag_append(wsi, c1)) {
1125                                                 lwsl_notice(
1126                                                         "%s: frag app fail\n",
1127                                                             __func__);
1128                                                 return 1;
1129                                         }
1130                                 } //else
1131                                         //lwsl_header("ignoring %c\n", c1);
1132                         } else {
1133                                 /*
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.
1138                                  *
1139                                  * If unknown header h2n->unknown_header
1140                                  * will be set.
1141                                  */
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;
1146                                 }
1147                                 lwsl_header("parser: %c\n", c1);
1148                                 /* uppercase header names illegal */
1149                                 if (c1 >= 'A' && c1 <= 'Z') {
1150                                         lws_h2_goaway(nwsi,
1151                                                 H2_ERR_COMPRESSION_ERROR,
1152                                                 "Uppercase literal hpack hdr");
1153                                         return 1;
1154                                 }
1155                                 plen = 1;
1156                                 if (!h2n->unknown_header &&
1157                                     lws_parse(wsi, &c1, &plen))
1158                                         h2n->unknown_header = 1;
1159                         }
1160 swallow:
1161                         (void)n;
1162                 } // for n
1163
1164                 if (--h2n->hpack_len)
1165                         break;
1166
1167                 /*
1168                  * The header (h2n->value = 0) or the payload (h2n->value = 1)
1169                  * is complete.
1170                  */
1171
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");
1178                         return 1;
1179                 }
1180
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",
1187                                         ah->parser_state);
1188
1189                         if (ah->parser_state == WSI_TOKEN_NAME_PART) {
1190                                 /* h2 headers come without the colon */
1191                                 c1 = ':';
1192                                 plen = 1;
1193                                 n = lws_parse(wsi, &c1, &plen);
1194                                 (void)n;
1195                         }
1196
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 ||
1200 #endif
1201                             ah->parser_state == WSI_TOKEN_SKIPPING) {
1202                                 h2n->unknown_header = 1;
1203                                 ah->parser_state = -1;
1204                                 wsi->seen_nonpseudoheader = 1;
1205                         }
1206                 }
1207
1208                 n = 8;
1209
1210                 /* we have the header */
1211                 if (!h2n->value) {
1212                         h2n->value = 1;
1213                         h2n->hpack = HPKS_HLEN;
1214                         h2n->huff_pad = 0;
1215                         h2n->zero_huff_padding = 0;
1216                         h2n->ext_count = 0;
1217                         break;
1218                 }
1219
1220                 /*
1221                  * we have got both the header and value
1222                  */
1223
1224                 m = -1;
1225                 switch (h2n->hpack_type) {
1226                 /*
1227                  * These are the only two that insert to the dyntable
1228                  */
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);
1234                         goto add_it;
1235                 /* NEW literal hdr with value */
1236                 case HPKT_LITERAL_HDR_VALUE_INCR:
1237                         /*
1238                          * hdr is a new literal, so length is already in
1239                          * h2n->hpack_hdr_len
1240                          */
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",
1248                                                   ah->parser_state,
1249                                                 h2n->unknown_header);
1250                                         /* unknown pseudoheaders are illegal */
1251                                         lws_h2_goaway(nwsi,
1252                                                       H2_ERR_PROTOCOL_ERROR,
1253                                                       "Unknown pseudoheader");
1254                                         return 1;
1255                                 }
1256                                 m = LWS_HPACK_IGNORE_ENTRY;
1257                         }
1258 add_it:
1259                         /*
1260                          * mark us as having been set at the time of dynamic
1261                          * token insertion.
1262                          */
1263                         ah->frags[ah->nfrag].flags |= 1;
1264
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__);
1269                                 return 1;
1270                         }
1271                         break;
1272
1273                 default:
1274                         break;
1275                 }
1276
1277                 if (h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY && lws_frag_end(wsi))
1278                         return 1;
1279
1280                 if (h2n->hpack_type != HPKT_INDEXED_HDR_6_VALUE_INCR) {
1281
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;
1286                                 if (m == 255)
1287                                         m = -1;
1288                         } else
1289                                 m = lws_token_from_index(wsi, h2n->hdr_idx,
1290                                                          NULL, NULL, NULL);
1291                 }
1292
1293                 if (m != -1 && m != LWS_HPACK_IGNORE_ENTRY)
1294                         lws_dump_header(wsi, m);
1295
1296                 if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
1297                         return 1;
1298
1299                 h2n->is_first_header_char = 1;
1300                 h2n->hpack = HPKS_TYPE;
1301                 break;
1302         }
1303
1304         return 0;
1305 }
1306
1307
1308
1309 static int
1310 lws_h2_num_start(int starting_bits, unsigned long num)
1311 {
1312         unsigned int mask = (1 << starting_bits) - 1;
1313
1314         if (num < mask)
1315                 return (int)num;
1316
1317         return mask;
1318 }
1319
1320 static int
1321 lws_h2_num(int starting_bits, unsigned long num,
1322                          unsigned char **p, unsigned char *end)
1323 {
1324         unsigned int mask = (1 << starting_bits) - 1;
1325
1326         if (num < mask)
1327                 return 0;
1328
1329         num -= mask;
1330         do {
1331                 if (num > 127)
1332                         *((*p)++) = 0x80 | (num & 0x7f);
1333                 else
1334                         *((*p)++) = 0x00 | (num & 0x7f);
1335                 if (*p >= end)
1336                         return 1;
1337                 num >>= 7;
1338         } while (num);
1339
1340         return 0;
1341 }
1342
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)
1346 {
1347         int len;
1348
1349         lwsl_header("%s: %p  %s:%s\n", __func__, *p, name, value);
1350
1351         len = (int)strlen((char *)name);
1352         if (len)
1353                 if (name[len - 1] == ':')
1354                         len--;
1355
1356         if (wsi->http2_substream && !strncmp((const char *)name,
1357                                              "transfer-encoding", len)) {
1358                 lwsl_header("rejecting %s\n", name);
1359
1360                 return 0;
1361         }
1362
1363         if (end - *p < len + length + 8)
1364                 return 1;
1365
1366         *((*p)++) = 0; /* literal hdr, literal name,  */
1367
1368         *((*p)++) = 0 | lws_h2_num_start(7, len); /* non-HUF */
1369         if (lws_h2_num(7, len, p, end))
1370                 return 1;
1371
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... */
1374
1375         while(len--)
1376                 *((*p)++) = tolower((int)*name++);
1377
1378         *((*p)++) = 0 | lws_h2_num_start(7, length); /* non-HUF */
1379         if (lws_h2_num(7, length, p, end))
1380                 return 1;
1381
1382         memcpy(*p, value, length);
1383         *p += length;
1384
1385         return 0;
1386 }
1387
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)
1391 {
1392         const unsigned char *name;
1393
1394         name = lws_token_to_string(token);
1395         if (!name)
1396                 return 1;
1397
1398         return lws_add_http2_header_by_name(wsi, name, value, length, p, end);
1399 }
1400
1401 int lws_add_http2_header_status(struct lws *wsi, unsigned int code,
1402                                 unsigned char **p, unsigned char *end)
1403 {
1404         unsigned char status[10];
1405         int n;
1406
1407         wsi->h2.send_END_STREAM = 0; // !!(code >= 400);
1408
1409         n = sprintf((char *)status, "%u", code);
1410         if (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS,
1411                                           status, n, p, end))
1412
1413                 return 1;
1414
1415         return 0;
1416 }