1 /*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include "private-lib-core.h"
26
27 /*
28 * Official static header table for HPACK
29 * +-------+-----------------------------+---------------+
30 | 1 | :authority | |
31 | 2 | :method | GET |
32 | 3 | :method | POST |
33 | 4 | :path | / |
34 | 5 | :path | /index.html |
35 | 6 | :scheme | http |
36 | 7 | :scheme | https |
37 | 8 | :status | 200 |
38 | 9 | :status | 204 |
39 | 10 | :status | 206 |
40 | 11 | :status | 304 |
41 | 12 | :status | 400 |
42 | 13 | :status | 404 |
43 | 14 | :status | 500 |
44 | 15 | accept-charset | |
45 | 16 | accept-encoding | gzip, deflate |
46 | 17 | accept-language | |
47 | 18 | accept-ranges | |
48 | 19 | accept | |
49 | 20 | access-control-allow-origin | |
50 | 21 | age | |
51 | 22 | allow | |
52 | 23 | authorization | |
53 | 24 | cache-control | |
54 | 25 | content-disposition | |
55 | 26 | content-encoding | |
56 | 27 | content-language | |
57 | 28 | content-length | |
58 | 29 | content-location | |
59 | 30 | content-range | |
60 | 31 | content-type | |
61 | 32 | cookie | |
62 | 33 | date | |
63 | 34 | etag | |
64 | 35 | expect | |
65 | 36 | expires | |
66 | 37 | from | |
67 | 38 | host | |
68 | 39 | if-match | |
69 | 40 | if-modified-since | |
70 | 41 | if-none-match | |
71 | 42 | if-range | |
72 | 43 | if-unmodified-since | |
73 | 44 | last-modified | |
74 | 45 | link | |
75 | 46 | location | |
76 | 47 | max-forwards | |
77 | 48 | proxy-authenticate | |
78 | 49 | proxy-authorization | |
79 | 50 | range | |
80 | 51 | referer | |
81 | 52 | refresh | |
82 | 53 | retry-after | |
83 | 54 | server | |
84 | 55 | set-cookie | |
85 | 56 | strict-transport-security | |
86 | 57 | transfer-encoding | |
87 | 58 | user-agent | |
88 | 59 | vary | |
89 | 60 | via | |
90 | 61 | www-authenticate | |
91 +-------+-----------------------------+---------------+
92 */
93
94 static const uint8_t static_hdr_len[62] = {
95 0, /* starts at 1 */
96 10, 7, 7, 5, 5, 7, 7, 7, 7, 7,
97 7, 7, 7, 7, 14, 15, 15, 13, 6, 27,
98 3, 5, 13, 13, 19, 16, 16, 14, 16, 13,
99 12, 6, 4, 4, 6, 7, 4, 4, 8, 17,
100 13, 8, 19, 13, 4, 8, 12, 18, 19, 5,
101 7, 7, 11, 6, 10, 25, 17, 10, 4, 3,
102 16
103 };
104
105 static const unsigned char static_token[] = {
106 0,
107 WSI_TOKEN_HTTP_COLON_AUTHORITY,
108 WSI_TOKEN_HTTP_COLON_METHOD,
109 WSI_TOKEN_HTTP_COLON_METHOD,
110 WSI_TOKEN_HTTP_COLON_PATH,
111 WSI_TOKEN_HTTP_COLON_PATH,
112 WSI_TOKEN_HTTP_COLON_SCHEME,
113 WSI_TOKEN_HTTP_COLON_SCHEME,
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_COLON_STATUS,
119 WSI_TOKEN_HTTP_COLON_STATUS,
120 WSI_TOKEN_HTTP_COLON_STATUS,
121 WSI_TOKEN_HTTP_ACCEPT_CHARSET,
122 WSI_TOKEN_HTTP_ACCEPT_ENCODING,
123 WSI_TOKEN_HTTP_ACCEPT_LANGUAGE,
124 WSI_TOKEN_HTTP_ACCEPT_RANGES,
125 WSI_TOKEN_HTTP_ACCEPT,
126 WSI_TOKEN_HTTP_ACCESS_CONTROL_ALLOW_ORIGIN,
127 WSI_TOKEN_HTTP_AGE,
128 WSI_TOKEN_HTTP_ALLOW,
129 WSI_TOKEN_HTTP_AUTHORIZATION,
130 WSI_TOKEN_HTTP_CACHE_CONTROL,
131 WSI_TOKEN_HTTP_CONTENT_DISPOSITION,
132 WSI_TOKEN_HTTP_CONTENT_ENCODING,
133 WSI_TOKEN_HTTP_CONTENT_LANGUAGE,
134 WSI_TOKEN_HTTP_CONTENT_LENGTH,
135 WSI_TOKEN_HTTP_CONTENT_LOCATION,
136 WSI_TOKEN_HTTP_CONTENT_RANGE,
137 WSI_TOKEN_HTTP_CONTENT_TYPE,
138 WSI_TOKEN_HTTP_COOKIE,
139 WSI_TOKEN_HTTP_DATE,
140 WSI_TOKEN_HTTP_ETAG,
141 WSI_TOKEN_HTTP_EXPECT,
142 WSI_TOKEN_HTTP_EXPIRES,
143 WSI_TOKEN_HTTP_FROM,
144 WSI_TOKEN_HOST,
145 WSI_TOKEN_HTTP_IF_MATCH,
146 WSI_TOKEN_HTTP_IF_MODIFIED_SINCE,
147 WSI_TOKEN_HTTP_IF_NONE_MATCH,
148 WSI_TOKEN_HTTP_IF_RANGE,
149 WSI_TOKEN_HTTP_IF_UNMODIFIED_SINCE,
150 WSI_TOKEN_HTTP_LAST_MODIFIED,
151 WSI_TOKEN_HTTP_LINK,
152 WSI_TOKEN_HTTP_LOCATION,
153 WSI_TOKEN_HTTP_MAX_FORWARDS,
154 WSI_TOKEN_HTTP_PROXY_AUTHENTICATE,
155 WSI_TOKEN_HTTP_PROXY_AUTHORIZATION,
156 WSI_TOKEN_HTTP_RANGE,
157 WSI_TOKEN_HTTP_REFERER,
158 WSI_TOKEN_HTTP_REFRESH,
159 WSI_TOKEN_HTTP_RETRY_AFTER,
160 WSI_TOKEN_HTTP_SERVER,
161 WSI_TOKEN_HTTP_SET_COOKIE,
162 WSI_TOKEN_HTTP_STRICT_TRANSPORT_SECURITY,
163 WSI_TOKEN_HTTP_TRANSFER_ENCODING,
164 WSI_TOKEN_HTTP_USER_AGENT,
165 WSI_TOKEN_HTTP_VARY,
166 WSI_TOKEN_HTTP_VIA,
167 WSI_TOKEN_HTTP_WWW_AUTHENTICATE,
168 };
169
170 /* some of the entries imply values as well as header names */
171
172 static const char * const http2_canned[] = {
173 "",
174 "",
175 "GET",
176 "POST",
177 "/",
178 "/index.html",
179 "http",
180 "https",
181 "200",
182 "204",
183 "206",
184 "304",
185 "400",
186 "404",
187 "500",
188 "",
189 "gzip, deflate"
190 };
191
192 /* see minihuf.c */
193
194 #include "huftable.h"
195
huftable_decode(int pos,char c)196 static int huftable_decode(int pos, char c)
197 {
198 int q = pos + !!c;
199
200 if (lextable_terms[q >> 3] & (1 << (q & 7))) /* terminal */
201 return lextable[q] | 0x8000;
202
203 return pos + (lextable[q] << 1);
204 }
205
lws_frag_start(struct lws * wsi,int hdr_token_idx)206 static int lws_frag_start(struct lws *wsi, int hdr_token_idx)
207 {
208 struct allocated_headers *ah = wsi->http.ah;
209
210 if (!ah) {
211 lwsl_notice("%s: no ah\n", __func__);
212 return 1;
213 }
214
215 ah->hdr_token_idx = -1;
216
217 lwsl_header("%s: token %d ah->pos = %d, ah->nfrag = %d\n",
218 __func__, hdr_token_idx, ah->pos, ah->nfrag);
219
220 if (!hdr_token_idx) {
221 lwsl_err("%s: zero hdr_token_idx\n", __func__);
222 return 1;
223 }
224
225 if (ah->nfrag >= LWS_ARRAY_SIZE(ah->frag_index)) {
226 lwsl_err("%s: frag index %d too big\n", __func__, ah->nfrag);
227 return 1;
228 }
229
230 if ((hdr_token_idx == WSI_TOKEN_HTTP_COLON_AUTHORITY ||
231 hdr_token_idx == WSI_TOKEN_HTTP_COLON_METHOD ||
232 hdr_token_idx == WSI_TOKEN_HTTP_COLON_PATH ||
233 hdr_token_idx == WSI_TOKEN_COLON_PROTOCOL ||
234 hdr_token_idx == WSI_TOKEN_HTTP_COLON_SCHEME) &&
235 ah->frag_index[hdr_token_idx]) {
236 if (!(ah->frags[ah->frag_index[hdr_token_idx]].flags & 1)) {
237 lws_h2_goaway(lws_get_network_wsi(wsi),
238 H2_ERR_PROTOCOL_ERROR,
239 "Duplicated pseudoheader");
240 return 1;
241 }
242 }
243
244 if (ah->nfrag == 0)
245 ah->nfrag = 1;
246
247 ah->frags[ah->nfrag].offset = ah->pos;
248 ah->frags[ah->nfrag].len = 0;
249 ah->frags[ah->nfrag].nfrag = 0;
250 ah->frags[ah->nfrag].flags = 2; /* we had reason to set it */
251
252 ah->hdr_token_idx = hdr_token_idx;
253
254 /*
255 * Okay, but we could be, eg, the second or subsequent cookie: header
256 */
257
258 if (ah->frag_index[hdr_token_idx]) {
259 int n;
260
261 /* find the last fragment for this header... */
262 n = ah->frag_index[hdr_token_idx];
263 while (ah->frags[n].nfrag)
264 n = ah->frags[n].nfrag;
265 /* and point it to continue in our continuation fragment */
266 ah->frags[n].nfrag = ah->nfrag;
267
268 /* cookie continuations need a separator token of ';' */
269 if (hdr_token_idx == WSI_TOKEN_HTTP_COOKIE) {
270 ah->data[ah->pos++] = ';';
271 ah->frags[ah->nfrag].len++;
272 }
273 } else
274 ah->frag_index[hdr_token_idx] = ah->nfrag;
275
276 return 0;
277 }
278
lws_frag_append(struct lws * wsi,unsigned char c)279 static int lws_frag_append(struct lws *wsi, unsigned char c)
280 {
281 struct allocated_headers *ah = wsi->http.ah;
282
283 ah->data[ah->pos++] = c;
284 ah->frags[ah->nfrag].len++;
285
286 return (int)ah->pos >= wsi->context->max_http_header_data;
287 }
288
lws_frag_end(struct lws * wsi)289 static int lws_frag_end(struct lws *wsi)
290 {
291 lwsl_header("%s\n", __func__);
292 if (lws_frag_append(wsi, 0))
293 return 1;
294
295 /* don't account for the terminating NUL in the logical length */
296 wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
297
298 wsi->http.ah->nfrag++;
299 return 0;
300 }
301
302 int
lws_hdr_extant(struct lws * wsi,enum lws_token_indexes h)303 lws_hdr_extant(struct lws *wsi, enum lws_token_indexes h)
304 {
305 struct allocated_headers *ah = wsi->http.ah;
306 int n;
307
308 if (!ah)
309 return 0;
310
311 n = ah->frag_index[h];
312 if (!n)
313 return 0;
314
315 return !!(ah->frags[n].flags & 2);
316 }
317
lws_dump_header(struct lws * wsi,int hdr)318 static void lws_dump_header(struct lws *wsi, int hdr)
319 {
320 char s[200];
321 const unsigned char *p;
322 int len;
323
324 if (hdr == LWS_HPACK_IGNORE_ENTRY) {
325 lwsl_notice("hdr tok ignored\n");
326 return;
327 }
328
329 (void)p;
330
331 len = lws_hdr_copy(wsi, s, sizeof(s) - 1, hdr);
332 if (len < 0)
333 strcpy(s, "(too big to show)");
334 else
335 s[len] = '\0';
336 p = lws_token_to_string(hdr);
337 lwsl_header(" hdr tok %d (%s) = '%s' (len %d)\n", hdr,
338 p ? (char *)p : (char *)"null", s, len);
339 }
340
341 /*
342 * dynamic table
343 *
344 * [ 0 .... num_entries - 1]
345 *
346 * Starts filling at 0+
347 *
348 * #62 is *most recently entered*
349 *
350 * Number of entries is not restricted, but aggregated size of the entry
351 * payloads is. Unfortunately the way HPACK does this is specific to an
352 * imagined implementation, and lws implementation is much more efficient
353 * (ignoring unknown headers and using the lws token index for the header
354 * name part).
355 */
356
357 /*
358 * returns 0 if dynamic entry (arg and len are filled)
359 * returns -1 if failure
360 * returns nonzero token index if actually static token
361 */
362 static int
lws_token_from_index(struct lws * wsi,int index,const char ** arg,int * len,uint32_t * hdr_len)363 lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len,
364 uint32_t *hdr_len)
365 {
366 struct hpack_dynamic_table *dyn;
367
368 if (index == LWS_HPACK_IGNORE_ENTRY)
369 return LWS_HPACK_IGNORE_ENTRY;
370
371 /* dynamic table only belongs to network wsi */
372 wsi = lws_get_network_wsi(wsi);
373 if (!wsi->h2.h2n)
374 return -1;
375
376 dyn = &wsi->h2.h2n->hpack_dyn_table;
377
378 if (index < 0)
379 return -1;
380
381 if (index < (int)LWS_ARRAY_SIZE(static_token)) {
382 if (arg && index < (int)LWS_ARRAY_SIZE(http2_canned)) {
383 *arg = http2_canned[index];
384 *len = (int)strlen(http2_canned[index]);
385 }
386 if (hdr_len)
387 *hdr_len = static_hdr_len[index];
388
389 return static_token[index];
390 }
391
392 if (!dyn) {
393 lwsl_notice("no dynamic table\n");
394 return -1;
395 }
396
397 if (index >= (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries) {
398 lwsl_info(" %s: adjusted index %d >= %d\n", __func__, index,
399 (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries);
400 lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
401 "index out of range");
402 return -1;
403 }
404
405 index -= (int)LWS_ARRAY_SIZE(static_token);
406 index = (dyn->pos - 1 - index) % dyn->num_entries;
407 if (index < 0)
408 index += dyn->num_entries;
409
410 lwsl_header("%s: dyn index %d, tok %d\n", __func__, index,
411 dyn->entries[index].lws_hdr_idx);
412
413 if (arg && len) {
414 *arg = dyn->entries[index].value;
415 *len = dyn->entries[index].value_len;
416 }
417
418 if (hdr_len)
419 *hdr_len = dyn->entries[index].hdr_len;
420
421 return dyn->entries[index].lws_hdr_idx;
422 }
423
424 static int
lws_h2_dynamic_table_dump(struct lws * wsi)425 lws_h2_dynamic_table_dump(struct lws *wsi)
426 {
427 #if 0
428 struct lws *nwsi = lws_get_network_wsi(wsi);
429 struct hpack_dynamic_table *dyn;
430 int n, m;
431 const char *p;
432
433 if (!nwsi->h2.h2n)
434 return 1;
435 dyn = &nwsi->h2.h2n->hpack_dyn_table;
436
437 lwsl_header("Dump dyn table for nwsi %p (%d / %d members, pos = %d, "
438 "start index %d, virt used %d / %d)\n", nwsi,
439 dyn->used_entries, dyn->num_entries, dyn->pos,
440 (uint32_t)LWS_ARRAY_SIZE(static_token),
441 dyn->virtual_payload_usage, dyn->virtual_payload_max);
442
443 for (n = 0; n < dyn->used_entries; n++) {
444 m = (dyn->pos - 1 - n) % dyn->num_entries;
445 if (m < 0)
446 m += dyn->num_entries;
447 if (dyn->entries[m].lws_hdr_idx != LWS_HPACK_IGNORE_ENTRY)
448 p = (const char *)lws_token_to_string(
449 dyn->entries[m].lws_hdr_idx);
450 else
451 p = "(ignored)";
452 lwsl_header(" %3d: tok %s: (len %d) val '%s'\n",
453 (int)(n + LWS_ARRAY_SIZE(static_token)), p,
454 dyn->entries[m].hdr_len, dyn->entries[m].value ?
455 dyn->entries[m].value : "null");
456 }
457 #endif
458 return 0;
459 }
460
461 static void
lws_dynamic_free(struct hpack_dynamic_table * dyn,int idx)462 lws_dynamic_free(struct hpack_dynamic_table *dyn, int idx)
463 {
464 lwsl_header("freeing %d for reuse\n", idx);
465 dyn->virtual_payload_usage -= dyn->entries[idx].value_len +
466 dyn->entries[idx].hdr_len;
467 lws_free_set_NULL(dyn->entries[idx].value);
468 dyn->entries[idx].value = NULL;
469 dyn->entries[idx].value_len = 0;
470 dyn->entries[idx].hdr_len = 0;
471 dyn->entries[idx].lws_hdr_idx = LWS_HPACK_IGNORE_ENTRY;
472 dyn->used_entries--;
473 }
474
475 /*
476 * There are two address spaces, 1) internal ringbuffer and 2) HPACK indexes.
477 *
478 * Internal ringbuffer:
479 *
480 * The internal ringbuffer wraps as we keep filling it, dyn->pos points to
481 * the next index to be written.
482 *
483 * HPACK indexes:
484 *
485 * The last-written entry becomes entry 0, the previously-last-written entry
486 * becomes entry 1 etc.
487 */
488
489 static int
lws_dynamic_token_insert(struct lws * wsi,int hdr_len,int lws_hdr_index,char * arg,int len)490 lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
491 int lws_hdr_index, char *arg, int len)
492 {
493 struct hpack_dynamic_table *dyn;
494 int new_index;
495
496 /* dynamic table only belongs to network wsi */
497 wsi = lws_get_network_wsi(wsi);
498 if (!wsi->h2.h2n)
499 return 1;
500 dyn = &wsi->h2.h2n->hpack_dyn_table;
501
502 if (!dyn->entries) {
503 lwsl_err("%s: unsized dyn table\n", __func__);
504
505 return 1;
506 }
507 lws_h2_dynamic_table_dump(wsi);
508
509 new_index = (dyn->pos) % dyn->num_entries;
510 if (dyn->num_entries && dyn->used_entries == dyn->num_entries) {
511 if (dyn->virtual_payload_usage < dyn->virtual_payload_max)
512 lwsl_err("Dropping header content before limit!\n");
513 /* we have to drop the oldest to make space */
514 lws_dynamic_free(dyn, new_index);
515 }
516
517 /*
518 * evict guys to make room, allowing for some overage. We have to
519 * take care about getting a single huge header, and evicting
520 * everything
521 */
522
523 while (dyn->virtual_payload_usage &&
524 dyn->used_entries &&
525 dyn->virtual_payload_usage + hdr_len + len >
526 dyn->virtual_payload_max + 1024) {
527 int n = (dyn->pos - dyn->used_entries) % dyn->num_entries;
528 if (n < 0)
529 n += dyn->num_entries;
530 lws_dynamic_free(dyn, n);
531 }
532
533 if (dyn->used_entries < dyn->num_entries)
534 dyn->used_entries++;
535
536 dyn->entries[new_index].value_len = 0;
537
538 if (lws_hdr_index != LWS_HPACK_IGNORE_ENTRY) {
539 if (dyn->entries[new_index].value)
540 lws_free_set_NULL(dyn->entries[new_index].value);
541 dyn->entries[new_index].value =
542 lws_malloc(len + 1, "hpack dyn");
543 if (!dyn->entries[new_index].value)
544 return 1;
545
546 memcpy(dyn->entries[new_index].value, arg, len);
547 dyn->entries[new_index].value[len] = '\0';
548 dyn->entries[new_index].value_len = len;
549 } else
550 dyn->entries[new_index].value = NULL;
551
552 dyn->entries[new_index].lws_hdr_idx = lws_hdr_index;
553 dyn->entries[new_index].hdr_len = hdr_len;
554
555 dyn->virtual_payload_usage += hdr_len + len;
556
557 lwsl_info("%s: index %ld: lws_hdr_index 0x%x, hdr len %d, '%s' len %d\n",
558 __func__, (long)LWS_ARRAY_SIZE(static_token),
559 lws_hdr_index, hdr_len, dyn->entries[new_index].value ?
560 dyn->entries[new_index].value : "null", len);
561
562 dyn->pos = (dyn->pos + 1) % dyn->num_entries;
563
564 lws_h2_dynamic_table_dump(wsi);
565
566 return 0;
567 }
568
569 int
lws_hpack_dynamic_size(struct lws * wsi,int size)570 lws_hpack_dynamic_size(struct lws *wsi, int size)
571 {
572 struct hpack_dynamic_table *dyn;
573 struct hpack_dt_entry *dte;
574 struct lws *nwsi;
575 int min, n = 0, m;
576
577 /*
578 * "size" here is coming from the http/2 SETTING
579 * SETTINGS_HEADER_TABLE_SIZE. This is a (virtual, in our case)
580 * linear buffer containing dynamic header names and values... when it
581 * is full, old entries are evicted.
582 *
583 * We encode the header as an lws_hdr_idx, which is all the rest of
584 * lws cares about; if there is no matching header we store an empty
585 * entry in the dyn table as a placeholder.
586 *
587 * So to make the two systems work together we keep an accounting of
588 * what we are using to decide when to evict... we must only evict
589 * things when the remote peer's accounting also makes him feel he
590 * should evict something.
591 */
592
593 nwsi = lws_get_network_wsi(wsi);
594 if (!nwsi->h2.h2n)
595 goto bail;
596
597 dyn = &nwsi->h2.h2n->hpack_dyn_table;
598 lwsl_info("%s: from %d to %d, lim %u\n", __func__,
599 (int)dyn->num_entries, size,
600 (unsigned int)nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
601
602 if (!size) {
603 size = dyn->num_entries * 8;
604 lws_hpack_destroy_dynamic_header(wsi);
605 }
606
607 if (size > (int)nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]) {
608 lwsl_info("rejecting hpack dyn size %u vs %u\n", size,
609 (unsigned int)nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
610
611 // this seems necessary to work with some browsers
612
613 if (nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE] == 65536 &&
614 size == 65537) { /* h2spec */
615 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
616 "Asked for header table bigger than we told");
617 goto bail;
618 }
619
620 size = nwsi->vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE];
621 }
622
623 dyn->virtual_payload_max = size;
624
625 size = size / 8;
626 min = size;
627 if (min > dyn->used_entries)
628 min = dyn->used_entries;
629
630 if (size == dyn->num_entries)
631 return 0;
632
633 if (dyn->num_entries < min)
634 min = dyn->num_entries;
635
636 // lwsl_notice("dte requested size %d\n", size);
637
638 dte = lws_zalloc(sizeof(*dte) * (size + 1), "dynamic table entries");
639 if (!dte)
640 goto bail;
641
642 while (dyn->virtual_payload_usage && dyn->used_entries &&
643 dyn->virtual_payload_usage > dyn->virtual_payload_max) {
644 n = (dyn->pos - dyn->used_entries) % dyn->num_entries;
645 if (n < 0)
646 n += dyn->num_entries;
647 lws_dynamic_free(dyn, n);
648 }
649
650 if (min > dyn->used_entries)
651 min = dyn->used_entries;
652
653 if (dyn->entries) {
654 for (n = 0; n < min; n++) {
655 m = (dyn->pos - dyn->used_entries + n) %
656 dyn->num_entries;
657 if (m < 0)
658 m += dyn->num_entries;
659 dte[n] = dyn->entries[m];
660 }
661
662 lws_free(dyn->entries);
663 }
664
665 dyn->entries = dte;
666 dyn->num_entries = size;
667 dyn->used_entries = min;
668 if (size)
669 dyn->pos = min % size;
670 else
671 dyn->pos = 0;
672
673 lws_h2_dynamic_table_dump(wsi);
674
675 return 0;
676
677 bail:
678 lwsl_info("%s: failed to resize to %d\n", __func__, size);
679
680 return 1;
681 }
682
683 void
lws_hpack_destroy_dynamic_header(struct lws * wsi)684 lws_hpack_destroy_dynamic_header(struct lws *wsi)
685 {
686 struct hpack_dynamic_table *dyn;
687 int n;
688
689 if (!wsi->h2.h2n)
690 return;
691
692 dyn = &wsi->h2.h2n->hpack_dyn_table;
693
694 if (!dyn->entries)
695 return;
696
697 for (n = 0; n < dyn->num_entries; n++)
698 if (dyn->entries[n].value)
699 lws_free_set_NULL(dyn->entries[n].value);
700
701 lws_free_set_NULL(dyn->entries);
702 }
703
704 static int
lws_hpack_use_idx_hdr(struct lws * wsi,int idx,int known_token)705 lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token)
706 {
707 const char *arg = NULL;
708 int len = 0;
709 const char *p = NULL;
710 int tok = lws_token_from_index(wsi, idx, &arg, &len, NULL);
711
712 if (tok == LWS_HPACK_IGNORE_ENTRY) {
713 lwsl_header("%s: lws_token says ignore, returning\n", __func__);
714 return 0;
715 }
716
717 if (tok == -1) {
718 lwsl_info("%s: idx %d mapped to tok %d\n", __func__, idx, tok);
719 return 1;
720 }
721
722 if (arg) {
723 /* dynamic result */
724 if (known_token > 0)
725 tok = known_token;
726 lwsl_header("%s: dyn: idx %d '%s' tok %d\n", __func__, idx, arg,
727 tok);
728 } else
729 lwsl_header("writing indexed hdr %d (tok %d '%s')\n", idx, tok,
730 lws_token_to_string(tok));
731
732 if (tok == LWS_HPACK_IGNORE_ENTRY)
733 return 0;
734
735 if (arg)
736 p = arg;
737
738 if (idx < (int)LWS_ARRAY_SIZE(http2_canned))
739 p = http2_canned[idx];
740
741 if (lws_frag_start(wsi, tok))
742 return 1;
743
744 if (p)
745 while (*p && len--)
746 if (lws_frag_append(wsi, *p++))
747 return 1;
748
749 if (lws_frag_end(wsi))
750 return 1;
751
752 lws_dump_header(wsi, tok);
753
754 return 0;
755 }
756
757 #if !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
758 static uint8_t lws_header_implies_psuedoheader_map[] = {
759 0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
760 };
761 #endif
762 #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
763 static uint8_t lws_header_implies_psuedoheader_map[] = {
764 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
765 };
766 #endif
767 #if !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
768 static uint8_t lws_header_implies_psuedoheader_map[] = {
769 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
770 };
771 #endif
772 #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
773 static uint8_t lws_header_implies_psuedoheader_map[] = {
774 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
775 };
776 #endif
777 #if !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2)
778 static uint8_t lws_header_implies_psuedoheader_map[] = {
779 0x03,0x00,0x80,0x0f,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
780 };
781 #endif
782 #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2)
783 static uint8_t lws_header_implies_psuedoheader_map[] = {
784 0x07,0x00,0x00,0x3e,0x00,0x00,0x00,0x80,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
785 };
786 #endif
787 #if !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2)
788 static uint8_t lws_header_implies_psuedoheader_map[] = {
789 0x03,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
790 };
791 #endif
792 #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2)
793 static uint8_t lws_header_implies_psuedoheader_map[] = {
794 0x07,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x0e,0x04,0x00,0x00,0x00,0x00,0x00,
795 };
796 #endif
797
798 static int
lws_hpack_handle_pseudo_rules(struct lws * nwsi,struct lws * wsi,int m)799 lws_hpack_handle_pseudo_rules(struct lws *nwsi, struct lws *wsi, int m)
800 {
801 if (m == LWS_HPACK_IGNORE_ENTRY || m == -1)
802 return 0;
803
804 if (wsi->seen_nonpseudoheader &&
805 (lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7)))) {
806
807 lwsl_info("lws tok %d seems to be a pseudoheader\n", m);
808
809 /*
810 * it's not legal to see a
811 * pseudoheader after normal
812 * headers
813 */
814 lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
815 "Pseudoheader after normal hdrs");
816 return 1;
817 }
818
819 if (!(lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7))))
820 wsi->seen_nonpseudoheader = 1;
821
822 return 0;
823 }
824
lws_hpack_interpret(struct lws * wsi,unsigned char c)825 int lws_hpack_interpret(struct lws *wsi, unsigned char c)
826 {
827 struct lws *nwsi = lws_get_network_wsi(wsi);
828 struct lws_h2_netconn *h2n = nwsi->h2.h2n;
829 struct allocated_headers *ah = wsi->http.ah;
830 unsigned int prev;
831 unsigned char c1;
832 int n, m, plen;
833
834 if (!h2n)
835 return -1;
836
837 /*
838 * HPKT_INDEXED_HDR_7 1xxxxxxx: just "header field"
839 * HPKT_INDEXED_HDR_6_VALUE_INCR 01xxxxxx: NEW indexed hdr + val
840 * HPKT_LITERAL_HDR_VALUE_INCR 01000000: NEW literal hdr + val
841 * HPKT_INDEXED_HDR_4_VALUE 0000xxxx: indexed hdr + val
842 * HPKT_INDEXED_HDR_4_VALUE_NEVER 0001xxxx: NEVER NEW indexed hdr + val
843 * HPKT_LITERAL_HDR_VALUE 00000000: literal hdr + val
844 * HPKT_LITERAL_HDR_VALUE_NEVER 00010000: NEVER NEW literal hdr + val
845 */
846 switch (h2n->hpack) {
847
848 case HPKS_TYPE:
849 h2n->is_first_header_char = 1;
850 h2n->huff_pad = 0;
851 h2n->zero_huff_padding = 0;
852 h2n->last_action_dyntable_resize = 0;
853 h2n->ext_count = 0;
854 h2n->hpack_hdr_len = 0;
855 h2n->unknown_header = 0;
856 ah->parser_state = 255;
857
858 if (c & 0x80) { /* 1.... indexed header field only */
859 /* just a possibly-extended integer */
860 h2n->hpack_type = HPKT_INDEXED_HDR_7;
861 lwsl_header("HPKT_INDEXED_HDR_7 hdr %d\n", c & 0x7f);
862 lws_h2_dynamic_table_dump(wsi);
863
864 h2n->hdr_idx = c & 0x7f;
865 if ((c & 0x7f) == 0x7f) {
866 h2n->hpack_len = 0;
867 h2n->hpack_m = 0x7f;
868 h2n->hpack = HPKS_IDX_EXT;
869 break;
870 }
871 if (!h2n->hdr_idx) {
872 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
873 "hdr index 0 seen");
874 return 1;
875 }
876
877 m = lws_token_from_index(wsi, h2n->hdr_idx,
878 NULL, NULL, NULL);
879 if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
880 return 1;
881
882 lwsl_header("HPKT_INDEXED_HDR_7: hdr %d\n", c & 0x7f);
883 if (lws_hpack_use_idx_hdr(wsi, c & 0x7f, -1)) {
884 lwsl_header("%s: idx hdr wr fail\n", __func__);
885 return 1;
886 }
887 /* stay at same state */
888 break;
889 }
890 if (c & 0x40) { /* 01.... indexed or literal header incr idx */
891 /*
892 * [possibly-ext hdr idx (6) | new literal hdr name]
893 * H + possibly-ext value length
894 * literal value
895 */
896 h2n->hdr_idx = 0;
897 if (c == 0x40) { /* literal header */
898 lwsl_header(" HPKT_LITERAL_HDR_VALUE_INCR\n");
899 h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
900 h2n->value = 0;
901 h2n->hpack_len = 0;
902 h2n->hpack = HPKS_HLEN;
903 break;
904 }
905 /* indexed header */
906 h2n->hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
907 lwsl_header(" HPKT_INDEXED_HDR_6_VALUE_INCR (hdr %d)\n",
908 c & 0x3f);
909 h2n->hdr_idx = c & 0x3f;
910 if ((c & 0x3f) == 0x3f) {
911 h2n->hpack_m = 0x3f;
912 h2n->hpack_len = 0;
913 h2n->hpack = HPKS_IDX_EXT;
914 break;
915 }
916
917 h2n->value = 1;
918 h2n->hpack = HPKS_HLEN;
919 if (!h2n->hdr_idx) {
920 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
921 "hdr index 0 seen");
922 return 1;
923 }
924 break;
925 }
926 switch(c & 0xf0) {
927 case 0x10: /* literal header never index */
928 case 0: /* literal header without indexing */
929 /*
930 * follows 0x40 except 4-bit hdr idx
931 * and don't add to index
932 */
933 if (c == 0) { /* literal name */
934 h2n->hpack_type = HPKT_LITERAL_HDR_VALUE;
935 lwsl_header(" HPKT_LITERAL_HDR_VALUE\n");
936 h2n->hpack = HPKS_HLEN;
937 h2n->value = 0;
938 break;
939 }
940 if (c == 0x10) { /* literal name NEVER */
941 h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_NEVER;
942 lwsl_header(" HPKT_LITERAL_HDR_VALUE_NEVER\n");
943 h2n->hpack = HPKS_HLEN;
944 h2n->value = 0;
945 break;
946 }
947 lwsl_header("indexed\n");
948 /* indexed name */
949 if (c & 0x10) {
950 h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE_NEVER;
951 lwsl_header("HPKT_LITERAL_HDR_4_VALUE_NEVER\n");
952 } else {
953 h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE;
954 lwsl_header(" HPKT_INDEXED_HDR_4_VALUE\n");
955 }
956 h2n->hdr_idx = 0;
957 if ((c & 0xf) == 0xf) {
958 h2n->hpack_len = c & 0xf;
959 h2n->hpack_m = 0xf;
960 h2n->hpack_len = 0;
961 h2n->hpack = HPKS_IDX_EXT;
962 break;
963 }
964 h2n->hdr_idx = c & 0xf;
965 h2n->value = 1;
966 h2n->hpack = HPKS_HLEN;
967 break;
968
969 case 0x20:
970 case 0x30: /* header table size update */
971 /* possibly-extended size value (5) */
972 lwsl_header("HPKT_SIZE_5 %x\n", c &0x1f);
973 h2n->hpack_type = HPKT_SIZE_5;
974 h2n->hpack_len = c & 0x1f;
975 if (h2n->hpack_len == 0x1f) {
976 h2n->hpack_m = 0x1f;
977 h2n->hpack_len = 0;
978 h2n->hpack = HPKS_IDX_EXT;
979 break;
980 }
981 h2n->last_action_dyntable_resize = 1;
982 if (lws_hpack_dynamic_size(wsi, h2n->hpack_len))
983 return 1;
984 break;
985 }
986 break;
987
988 case HPKS_IDX_EXT:
989 h2n->hpack_len = h2n->hpack_len |
990 ((c & 0x7f) << h2n->ext_count);
991 h2n->ext_count += 7;
992 if (c & 0x80) /* extended int not complete yet */
993 break;
994
995 /* extended integer done */
996 h2n->hpack_len += h2n->hpack_m;
997 lwsl_header("HPKS_IDX_EXT: hpack_len %u\n", (unsigned int)h2n->hpack_len);
998
999 switch (h2n->hpack_type) {
1000 case HPKT_INDEXED_HDR_7:
1001 if (lws_hpack_use_idx_hdr(wsi, h2n->hpack_len,
1002 h2n->hdr_idx)) {
1003 lwsl_notice("%s: hd7 use fail\n", __func__);
1004 return 1;
1005 }
1006 h2n->hpack = HPKS_TYPE;
1007 break;
1008
1009 case HPKT_SIZE_5:
1010 h2n->last_action_dyntable_resize = 1;
1011 if (lws_hpack_dynamic_size(wsi, h2n->hpack_len))
1012 return 1;
1013 h2n->hpack = HPKS_TYPE;
1014 break;
1015
1016 default:
1017 h2n->hdr_idx = h2n->hpack_len;
1018 if (!h2n->hdr_idx) {
1019 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
1020 "extended header index was 0");
1021 return 1;
1022 }
1023 h2n->value = 1;
1024 h2n->hpack = HPKS_HLEN;
1025 break;
1026 }
1027 break;
1028
1029 case HPKS_HLEN: /* [ H | 7+ ] */
1030 h2n->huff = !!(c & 0x80);
1031 h2n->hpack_pos = 0;
1032 h2n->hpack_len = c & 0x7f;
1033
1034 if (h2n->hpack_len == 0x7f) {
1035 h2n->hpack_m = 0x7f;
1036 h2n->hpack_len = 0;
1037 h2n->ext_count = 0;
1038 h2n->hpack = HPKS_HLEN_EXT;
1039 break;
1040 }
1041
1042 if (h2n->value && !h2n->hpack_len) {
1043 lwsl_debug("%s: zero-length header data\n", __func__);
1044 h2n->hpack = HPKS_TYPE;
1045 goto fin;
1046 }
1047
1048 pre_data:
1049 h2n->hpack = HPKS_DATA;
1050 if (!h2n->value || !h2n->hdr_idx) {
1051 ah->parser_state = WSI_TOKEN_NAME_PART;
1052 ah->lextable_pos = 0;
1053 h2n->unknown_header = 0;
1054 break;
1055 }
1056
1057 if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1058 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1059 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) {
1060 n = ah->parser_state;
1061 if (n == 255) {
1062 n = -1;
1063 h2n->hdr_idx = -1;
1064 } else
1065 h2n->hdr_idx = 1;
1066 } else {
1067 n = lws_token_from_index(wsi, h2n->hdr_idx, NULL,
1068 NULL, NULL);
1069 lwsl_header(" lws_tok_from_idx(%u) says %d\n",
1070 (unsigned int)h2n->hdr_idx, n);
1071 }
1072
1073 if (n == LWS_HPACK_IGNORE_ENTRY || n == -1)
1074 h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
1075
1076 switch (h2n->hpack_type) {
1077 /*
1078 * hpack types with literal headers were parsed by the lws
1079 * header SM... on recognition of a known lws header, it does
1080 * the correct lws_frag_start() for us already. Other types
1081 * (ie, indexed header) need us to do it here.
1082 */
1083 case HPKT_LITERAL_HDR_VALUE_INCR:
1084 case HPKT_LITERAL_HDR_VALUE:
1085 case HPKT_LITERAL_HDR_VALUE_NEVER:
1086 break;
1087 default:
1088 if (n != -1 && n != LWS_HPACK_IGNORE_ENTRY &&
1089 lws_frag_start(wsi, n)) {
1090 lwsl_header("%s: frag start failed\n",
1091 __func__);
1092 return 1;
1093 }
1094 break;
1095 }
1096 break;
1097
1098 case HPKS_HLEN_EXT:
1099 h2n->hpack_len = h2n->hpack_len |
1100 ((c & 0x7f) << h2n->ext_count);
1101 h2n->ext_count += 7;
1102 if (c & 0x80) /* extended integer not complete yet */
1103 break;
1104
1105 h2n->hpack_len += h2n->hpack_m;
1106 goto pre_data;
1107
1108 case HPKS_DATA:
1109 //lwsl_header(" 0x%02X huff %d\n", c, h2n->huff);
1110 c1 = c;
1111
1112 for (n = 0; n < 8; n++) {
1113 if (h2n->huff) {
1114 char b = (c >> 7) & 1;
1115 prev = h2n->hpack_pos;
1116 h2n->hpack_pos = huftable_decode(
1117 h2n->hpack_pos, b);
1118 c <<= 1;
1119 if (h2n->hpack_pos == 0xffff) {
1120 lwsl_notice("Huffman err\n");
1121 return 1;
1122 }
1123 if (!(h2n->hpack_pos & 0x8000)) {
1124 if (!b)
1125 h2n->zero_huff_padding = 1;
1126 h2n->huff_pad++;
1127 continue;
1128 }
1129 c1 = h2n->hpack_pos & 0x7fff;
1130 h2n->hpack_pos = 0;
1131 h2n->huff_pad = 0;
1132 h2n->zero_huff_padding = 0;
1133
1134 /* EOS |11111111|11111111|11111111|111111 */
1135 if (!c1 && prev == HUFTABLE_0x100_PREV) {
1136 lws_h2_goaway(nwsi,
1137 H2_ERR_COMPRESSION_ERROR,
1138 "Huffman EOT seen");
1139 return 1;
1140 }
1141 } else
1142 n = 8;
1143
1144 if (h2n->value) { /* value */
1145
1146 if (h2n->hdr_idx &&
1147 h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY) {
1148
1149 if (ah->hdr_token_idx ==
1150 WSI_TOKEN_HTTP_COLON_PATH) {
1151
1152 switch (lws_parse_urldecode(
1153 wsi, &c1)) {
1154 case LPUR_CONTINUE:
1155 break;
1156 case LPUR_SWALLOW:
1157 goto swallow;
1158 case LPUR_EXCESSIVE:
1159 case LPUR_FORBID:
1160 lws_h2_goaway(nwsi,
1161 H2_ERR_PROTOCOL_ERROR,
1162 "Evil URI");
1163 return 1;
1164
1165 default:
1166 return -1;
1167 }
1168 }
1169 if (lws_frag_append(wsi, c1)) {
1170 lwsl_notice(
1171 "%s: frag app fail\n",
1172 __func__);
1173 return 1;
1174 }
1175 } //else
1176 //lwsl_header("ignoring %c\n", c1);
1177 } else {
1178 /*
1179 * Convert name using existing parser,
1180 * If h2n->unknown_header == 0, result is
1181 * in wsi->parser_state
1182 * using WSI_TOKEN_GET_URI.
1183 *
1184 * If unknown header h2n->unknown_header
1185 * will be set.
1186 */
1187 h2n->hpack_hdr_len++;
1188 if (h2n->is_first_header_char) {
1189 h2n->is_first_header_char = 0;
1190 h2n->first_hdr_char = c1;
1191 }
1192 lwsl_header("parser: %c\n", c1);
1193 /* uppercase header names illegal */
1194 if (c1 >= 'A' && c1 <= 'Z') {
1195 lws_h2_goaway(nwsi,
1196 H2_ERR_COMPRESSION_ERROR,
1197 "Uppercase literal hpack hdr");
1198 return 1;
1199 }
1200 plen = 1;
1201 if (!h2n->unknown_header &&
1202 lws_parse(wsi, &c1, &plen))
1203 h2n->unknown_header = 1;
1204 }
1205 swallow:
1206 (void)n;
1207 } // for n
1208
1209 if (--h2n->hpack_len)
1210 break;
1211
1212 /*
1213 * The header (h2n->value = 0) or the payload (h2n->value = 1)
1214 * is complete.
1215 */
1216
1217 if (h2n->huff && (h2n->huff_pad > 7 ||
1218 (h2n->zero_huff_padding && h2n->huff_pad))) {
1219 lwsl_info("zero_huff_padding: %d huff_pad: %d\n",
1220 h2n->zero_huff_padding, h2n->huff_pad);
1221 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
1222 "Huffman padding excessive or wrong");
1223 return 1;
1224 }
1225 fin:
1226 if (!h2n->value && (
1227 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1228 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1229 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER)) {
1230 h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
1231 lwsl_header("wsi->parser_state: %d\n",
1232 ah->parser_state);
1233
1234 if (ah->parser_state == WSI_TOKEN_NAME_PART) {
1235 /* h2 headers come without the colon */
1236 c1 = ':';
1237 plen = 1;
1238 n = lws_parse(wsi, &c1, &plen);
1239 (void)n;
1240 }
1241
1242 if (ah->parser_state == WSI_TOKEN_NAME_PART ||
1243 #if defined(LWS_WITH_CUSTOM_HEADERS)
1244 ah->parser_state == WSI_TOKEN_UNKNOWN_VALUE_PART ||
1245 #endif
1246 ah->parser_state == WSI_TOKEN_SKIPPING) {
1247 h2n->unknown_header = 1;
1248 ah->parser_state = -1;
1249 wsi->seen_nonpseudoheader = 1;
1250 }
1251 }
1252
1253 n = 8;
1254
1255 /* we have the header */
1256 if (!h2n->value) {
1257 h2n->value = 1;
1258 h2n->hpack = HPKS_HLEN;
1259 h2n->huff_pad = 0;
1260 h2n->zero_huff_padding = 0;
1261 h2n->ext_count = 0;
1262 break;
1263 }
1264
1265 /*
1266 * we have got both the header and value
1267 */
1268
1269 m = -1;
1270 switch (h2n->hpack_type) {
1271 /*
1272 * These are the only two that insert to the dyntable
1273 */
1274 /* NEW indexed hdr with value */
1275 case HPKT_INDEXED_HDR_6_VALUE_INCR:
1276 /* header length is determined by known index */
1277 m = lws_token_from_index(wsi, h2n->hdr_idx, NULL, NULL,
1278 &h2n->hpack_hdr_len);
1279 goto add_it;
1280 /* NEW literal hdr with value */
1281 case HPKT_LITERAL_HDR_VALUE_INCR:
1282 /*
1283 * hdr is a new literal, so length is already in
1284 * h2n->hpack_hdr_len
1285 */
1286 m = ah->parser_state;
1287 if (h2n->unknown_header ||
1288 ah->parser_state == WSI_TOKEN_NAME_PART ||
1289 ah->parser_state == WSI_TOKEN_SKIPPING) {
1290 if (h2n->first_hdr_char == ':') {
1291 lwsl_info("HPKT_LITERAL_HDR_VALUE_INCR:"
1292 " end state %d unk hdr %d\n",
1293 ah->parser_state,
1294 h2n->unknown_header);
1295 /* unknown pseudoheaders are illegal */
1296 lws_h2_goaway(nwsi,
1297 H2_ERR_PROTOCOL_ERROR,
1298 "Unknown pseudoheader");
1299 return 1;
1300 }
1301 m = LWS_HPACK_IGNORE_ENTRY;
1302 }
1303 add_it:
1304 /*
1305 * mark us as having been set at the time of dynamic
1306 * token insertion.
1307 */
1308 ah->frags[ah->nfrag].flags |= 1;
1309
1310 if (lws_dynamic_token_insert(wsi, h2n->hpack_hdr_len, m,
1311 &ah->data[ah->frags[ah->nfrag].offset],
1312 ah->frags[ah->nfrag].len)) {
1313 lwsl_notice("%s: tok_insert fail\n", __func__);
1314 return 1;
1315 }
1316 break;
1317
1318 default:
1319 break;
1320 }
1321
1322 if (h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY && lws_frag_end(wsi))
1323 return 1;
1324
1325 if (h2n->hpack_type != HPKT_INDEXED_HDR_6_VALUE_INCR) {
1326
1327 if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1328 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1329 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) {
1330 m = ah->parser_state;
1331 if (m == 255)
1332 m = -1;
1333 } else
1334 m = lws_token_from_index(wsi, h2n->hdr_idx,
1335 NULL, NULL, NULL);
1336 }
1337
1338 if (m != -1 && m != LWS_HPACK_IGNORE_ENTRY)
1339 lws_dump_header(wsi, m);
1340
1341 if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
1342 return 1;
1343
1344 h2n->is_first_header_char = 1;
1345 h2n->hpack = HPKS_TYPE;
1346 break;
1347 }
1348
1349 return 0;
1350 }
1351
1352
1353
1354 static int
lws_h2_num_start(int starting_bits,unsigned long num)1355 lws_h2_num_start(int starting_bits, unsigned long num)
1356 {
1357 unsigned int mask = (1 << starting_bits) - 1;
1358
1359 if (num < mask)
1360 return (int)num;
1361
1362 return mask;
1363 }
1364
1365 static int
lws_h2_num(int starting_bits,unsigned long num,unsigned char ** p,unsigned char * end)1366 lws_h2_num(int starting_bits, unsigned long num,
1367 unsigned char **p, unsigned char *end)
1368 {
1369 unsigned int mask = (1 << starting_bits) - 1;
1370
1371 if (num < mask)
1372 return 0;
1373
1374 num -= mask;
1375 do {
1376 if (num > 127)
1377 *((*p)++) = 0x80 | (num & 0x7f);
1378 else
1379 *((*p)++) = 0x00 | (num & 0x7f);
1380 if (*p >= end)
1381 return 1;
1382 num >>= 7;
1383 } while (num);
1384
1385 return 0;
1386 }
1387
lws_add_http2_header_by_name(struct lws * wsi,const unsigned char * name,const unsigned char * value,int length,unsigned char ** p,unsigned char * end)1388 int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name,
1389 const unsigned char *value, int length,
1390 unsigned char **p, unsigned char *end)
1391 {
1392 int len;
1393
1394 lwsl_header("%s: %p %s:%s (len %d)\n", __func__, *p, name, value,
1395 length);
1396
1397 len = (int)strlen((char *)name);
1398 if (len)
1399 if (name[len - 1] == ':')
1400 len--;
1401
1402 if (wsi->mux_substream && !strncmp((const char *)name,
1403 "transfer-encoding", len)) {
1404 lwsl_header("rejecting %s\n", name);
1405
1406 return 0;
1407 }
1408
1409 if (end - *p < len + length + 8)
1410 return 1;
1411
1412 *((*p)++) = 0; /* literal hdr, literal name, */
1413
1414 *((*p)++) = 0 | lws_h2_num_start(7, len); /* non-HUF */
1415 if (lws_h2_num(7, len, p, end))
1416 return 1;
1417
1418 /* upper-case header names are verboten in h2, but OK on h1, so
1419 * they're not illegal per se. Silently convert them for h2... */
1420
1421 while(len--)
1422 *((*p)++) = tolower((int)*name++);
1423
1424 *((*p)++) = 0 | lws_h2_num_start(7, length); /* non-HUF */
1425 if (lws_h2_num(7, length, p, end))
1426 return 1;
1427
1428 memcpy(*p, value, length);
1429 *p += length;
1430
1431 return 0;
1432 }
1433
lws_add_http2_header_by_token(struct lws * wsi,enum lws_token_indexes token,const unsigned char * value,int length,unsigned char ** p,unsigned char * end)1434 int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token,
1435 const unsigned char *value, int length,
1436 unsigned char **p, unsigned char *end)
1437 {
1438 const unsigned char *name;
1439
1440 name = lws_token_to_string(token);
1441 if (!name)
1442 return 1;
1443
1444 return lws_add_http2_header_by_name(wsi, name, value, length, p, end);
1445 }
1446
lws_add_http2_header_status(struct lws * wsi,unsigned int code,unsigned char ** p,unsigned char * end)1447 int lws_add_http2_header_status(struct lws *wsi, unsigned int code,
1448 unsigned char **p, unsigned char *end)
1449 {
1450 unsigned char status[10];
1451 int n;
1452
1453 wsi->h2.send_END_STREAM = 0; // !!(code >= 400);
1454
1455 n = sprintf((char *)status, "%u", code);
1456 if (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS,
1457 status, n, p, end))
1458
1459 return 1;
1460
1461 return 0;
1462 }
1463