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 } else
268 ah->frag_index[hdr_token_idx] = ah->nfrag;
269
270 return 0;
271 }
272
lws_frag_append(struct lws * wsi,unsigned char c)273 static int lws_frag_append(struct lws *wsi, unsigned char c)
274 {
275 struct allocated_headers *ah = wsi->http.ah;
276
277 ah->data[ah->pos++] = (char)c;
278 ah->frags[ah->nfrag].len++;
279
280 return (unsigned int)ah->pos >= wsi->a.context->max_http_header_data;
281 }
282
lws_frag_end(struct lws * wsi)283 static int lws_frag_end(struct lws *wsi)
284 {
285 lwsl_header("%s\n", __func__);
286 if (lws_frag_append(wsi, 0))
287 return 1;
288
289 /* don't account for the terminating NUL in the logical length */
290 wsi->http.ah->frags[wsi->http.ah->nfrag].len--;
291
292 wsi->http.ah->nfrag++;
293 return 0;
294 }
295
296 int
lws_hdr_extant(struct lws * wsi,enum lws_token_indexes h)297 lws_hdr_extant(struct lws *wsi, enum lws_token_indexes h)
298 {
299 struct allocated_headers *ah = wsi->http.ah;
300 int n;
301
302 if (!ah)
303 return 0;
304
305 n = ah->frag_index[h];
306 if (!n)
307 return 0;
308
309 return !!(ah->frags[n].flags & 2);
310 }
311
lws_dump_header(struct lws * wsi,int hdr)312 static void lws_dump_header(struct lws *wsi, int hdr)
313 {
314 char s[200];
315 const unsigned char *p;
316 int len;
317
318 if (hdr == LWS_HPACK_IGNORE_ENTRY) {
319 lwsl_notice("hdr tok ignored\n");
320 return;
321 }
322
323 (void)p;
324
325 len = lws_hdr_copy(wsi, s, sizeof(s) - 1, (enum lws_token_indexes)hdr);
326 if (len < 0)
327 strcpy(s, "(too big to show)");
328 else
329 s[len] = '\0';
330 #if defined(_DEBUG)
331 p = lws_token_to_string((enum lws_token_indexes)hdr);
332 lwsl_header(" hdr tok %d (%s) = '%s' (len %d)\n", hdr,
333 p ? (char *)p : (char *)"null", s, len);
334 #endif
335 }
336
337 /*
338 * dynamic table
339 *
340 * [ 0 .... num_entries - 1]
341 *
342 * Starts filling at 0+
343 *
344 * #62 is *most recently entered*
345 *
346 * Number of entries is not restricted, but aggregated size of the entry
347 * payloads is. Unfortunately the way HPACK does this is specific to an
348 * imagined implementation, and lws implementation is much more efficient
349 * (ignoring unknown headers and using the lws token index for the header
350 * name part).
351 */
352
353 /*
354 * returns 0 if dynamic entry (arg and len are filled)
355 * returns -1 if failure
356 * returns nonzero token index if actually static token
357 */
358 static int
lws_token_from_index(struct lws * wsi,int index,const char ** arg,int * len,uint32_t * hdr_len)359 lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len,
360 uint32_t *hdr_len)
361 {
362 struct hpack_dynamic_table *dyn;
363
364 if (index == LWS_HPACK_IGNORE_ENTRY)
365 return LWS_HPACK_IGNORE_ENTRY;
366
367 /* dynamic table only belongs to network wsi */
368 wsi = lws_get_network_wsi(wsi);
369 if (!wsi->h2.h2n)
370 return -1;
371
372 dyn = &wsi->h2.h2n->hpack_dyn_table;
373
374 if (index < 0)
375 return -1;
376
377 if (index < (int)LWS_ARRAY_SIZE(static_token)) {
378 if (arg && index < (int)LWS_ARRAY_SIZE(http2_canned)) {
379 *arg = http2_canned[index];
380 *len = (int)strlen(http2_canned[index]);
381 }
382 if (hdr_len)
383 *hdr_len = static_hdr_len[index];
384
385 return static_token[index];
386 }
387
388 if (!dyn) {
389 lwsl_notice("no dynamic table\n");
390 return -1;
391 }
392
393 if (index >= (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries) {
394 lwsl_info(" %s: adjusted index %d >= %d\n", __func__, index,
395 (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries);
396 lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR,
397 "index out of range");
398 return -1;
399 }
400
401 index -= (int)LWS_ARRAY_SIZE(static_token);
402 index = lws_safe_modulo(dyn->pos - 1 - index, dyn->num_entries);
403 if (index < 0)
404 index += dyn->num_entries;
405
406 lwsl_header("%s: dyn index %d, tok %d\n", __func__, index,
407 dyn->entries[index].lws_hdr_idx);
408
409 if (arg && len) {
410 *arg = dyn->entries[index].value;
411 *len = dyn->entries[index].value_len;
412 }
413
414 if (hdr_len)
415 *hdr_len = dyn->entries[index].hdr_len;
416
417 return dyn->entries[index].lws_hdr_idx;
418 }
419
420 static int
lws_h2_dynamic_table_dump(struct lws * wsi)421 lws_h2_dynamic_table_dump(struct lws *wsi)
422 {
423 #if 0
424 struct lws *nwsi = lws_get_network_wsi(wsi);
425 struct hpack_dynamic_table *dyn;
426 int n, m;
427 const char *p;
428
429 if (!nwsi->h2.h2n)
430 return 1;
431 dyn = &nwsi->h2.h2n->hpack_dyn_table;
432
433 lwsl_header("Dump dyn table for nwsi %s (%d / %d members, pos = %d, "
434 "start index %d, virt used %d / %d)\n", lws_wsi_tag(nwsi),
435 dyn->used_entries, dyn->num_entries, dyn->pos,
436 (uint32_t)LWS_ARRAY_SIZE(static_token),
437 dyn->virtual_payload_usage, dyn->virtual_payload_max);
438
439 for (n = 0; n < dyn->used_entries; n++) {
440 m = lws_safe_modulo(dyn->pos - 1 - n, dyn->num_entries);
441 if (m < 0)
442 m += dyn->num_entries;
443 if (dyn->entries[m].lws_hdr_idx != LWS_HPACK_IGNORE_ENTRY)
444 p = (const char *)lws_token_to_string(
445 dyn->entries[m].lws_hdr_idx);
446 else
447 p = "(ignored)";
448 lwsl_header(" %3d: tok %s: (len %d) val '%s'\n",
449 (int)(n + LWS_ARRAY_SIZE(static_token)), p,
450 dyn->entries[m].hdr_len, dyn->entries[m].value ?
451 dyn->entries[m].value : "null");
452 }
453 #endif
454 return 0;
455 }
456
457 static void
lws_dynamic_free(struct hpack_dynamic_table * dyn,int idx)458 lws_dynamic_free(struct hpack_dynamic_table *dyn, int idx)
459 {
460 lwsl_header("freeing %d for reuse\n", idx);
461 dyn->virtual_payload_usage = (uint32_t)((unsigned int)dyn->virtual_payload_usage - (unsigned int)(dyn->entries[idx].value_len +
462 dyn->entries[idx].hdr_len));
463 lws_free_set_NULL(dyn->entries[idx].value);
464 dyn->entries[idx].value = NULL;
465 dyn->entries[idx].value_len = 0;
466 dyn->entries[idx].hdr_len = 0;
467 dyn->entries[idx].lws_hdr_idx = LWS_HPACK_IGNORE_ENTRY;
468 dyn->used_entries--;
469 }
470
471 /*
472 * There are two address spaces, 1) internal ringbuffer and 2) HPACK indexes.
473 *
474 * Internal ringbuffer:
475 *
476 * The internal ringbuffer wraps as we keep filling it, dyn->pos points to
477 * the next index to be written.
478 *
479 * HPACK indexes:
480 *
481 * The last-written entry becomes entry 0, the previously-last-written entry
482 * becomes entry 1 etc.
483 */
484
485 static int
lws_dynamic_token_insert(struct lws * wsi,int hdr_len,int lws_hdr_index,char * arg,size_t len)486 lws_dynamic_token_insert(struct lws *wsi, int hdr_len,
487 int lws_hdr_index, char *arg, size_t len)
488 {
489 struct hpack_dynamic_table *dyn;
490 int new_index;
491
492 /* dynamic table only belongs to network wsi */
493 wsi = lws_get_network_wsi(wsi);
494 if (!wsi->h2.h2n)
495 return 1;
496 dyn = &wsi->h2.h2n->hpack_dyn_table;
497
498 if (!dyn->entries) {
499 lwsl_err("%s: unsized dyn table\n", __func__);
500
501 return 1;
502 }
503 lws_h2_dynamic_table_dump(wsi);
504
505 new_index = lws_safe_modulo(dyn->pos, dyn->num_entries);
506 if (dyn->num_entries && dyn->used_entries == dyn->num_entries) {
507 if (dyn->virtual_payload_usage < dyn->virtual_payload_max)
508 lwsl_err("Dropping header content before limit!\n");
509 /* we have to drop the oldest to make space */
510 lws_dynamic_free(dyn, new_index);
511 }
512
513 /*
514 * evict guys to make room, allowing for some overage. We have to
515 * take care about getting a single huge header, and evicting
516 * everything
517 */
518
519 while (dyn->virtual_payload_usage &&
520 dyn->used_entries &&
521 dyn->virtual_payload_usage + (unsigned int)hdr_len + len >
522 dyn->virtual_payload_max + 1024) {
523 int n = lws_safe_modulo(dyn->pos - dyn->used_entries,
524 dyn->num_entries);
525 if (n < 0)
526 n += dyn->num_entries;
527 lws_dynamic_free(dyn, n);
528 }
529
530 if (dyn->used_entries < dyn->num_entries)
531 dyn->used_entries++;
532
533 dyn->entries[new_index].value_len = 0;
534
535 if (lws_hdr_index != LWS_HPACK_IGNORE_ENTRY) {
536 if (dyn->entries[new_index].value)
537 lws_free_set_NULL(dyn->entries[new_index].value);
538 dyn->entries[new_index].value =
539 lws_malloc(len + 1, "hpack dyn");
540 if (!dyn->entries[new_index].value)
541 return 1;
542
543 memcpy(dyn->entries[new_index].value, arg, len);
544 dyn->entries[new_index].value[len] = '\0';
545 dyn->entries[new_index].value_len = (uint16_t)len;
546 } else
547 dyn->entries[new_index].value = NULL;
548
549 dyn->entries[new_index].lws_hdr_idx = (uint16_t)lws_hdr_index;
550 dyn->entries[new_index].hdr_len = (uint16_t)hdr_len;
551
552 dyn->virtual_payload_usage = (uint32_t)(dyn->virtual_payload_usage +
553 (unsigned int)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", (int)len);
559
560 dyn->pos = (uint16_t)lws_safe_modulo(dyn->pos + 1, dyn->num_entries);
561
562 lws_h2_dynamic_table_dump(wsi);
563
564 return 0;
565 }
566
567 int
lws_hpack_dynamic_size(struct lws * wsi,int size)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 %u\n", __func__,
597 (int)dyn->num_entries, size,
598 (unsigned int)nwsi->a.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->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]) {
606 lwsl_info("rejecting hpack dyn size %u vs %u\n", size,
607 (unsigned int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE]);
608
609 // this seems necessary to work with some browsers
610
611 if (nwsi->a.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 = (int)nwsi->a.vhost->h2.set.s[H2SET_HEADER_TABLE_SIZE];
619 }
620
621 dyn->virtual_payload_max = (uint32_t)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) * (unsigned int)(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 = lws_safe_modulo(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 = (uint16_t)size;
665 dyn->used_entries = (uint16_t)min;
666 if (size)
667 dyn->pos = (uint16_t)lws_safe_modulo(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
lws_hpack_destroy_dynamic_header(struct lws * wsi)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
lws_hpack_use_idx_hdr(struct lws * wsi,int idx,int known_token)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((enum lws_token_indexes)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, (unsigned char)*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 #if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
756 static uint8_t lws_header_implies_psuedoheader_map[] = {
757 0x03,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
758 };
759 #endif
760 #if !defined(LWS_HTTP_HEADERS_ALL) && defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
761 static uint8_t lws_header_implies_psuedoheader_map[] = {
762 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
763 };
764 #endif
765 #if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
766 static uint8_t lws_header_implies_psuedoheader_map[] = {
767 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
768 };
769 #endif
770 #if !defined(LWS_HTTP_HEADERS_ALL) && defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && !defined(LWS_ROLE_H2)
771 static uint8_t lws_header_implies_psuedoheader_map[] = {
772 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
773 };
774 #endif
775 #if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2)
776 static uint8_t lws_header_implies_psuedoheader_map[] = {
777 0x03,0x00,0x80,0x0f,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
778 };
779 #endif
780 #if !defined(LWS_HTTP_HEADERS_ALL) && defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && !defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2)
781 static uint8_t lws_header_implies_psuedoheader_map[] = {
782 0x07,0x00,0x00,0x3e,0x00,0x00,0x00,0x80,0x03,0x09,0x00,0x00,0x00,0x00,0x00,0x00,
783 };
784 #endif
785 #if !defined(LWS_HTTP_HEADERS_ALL) && !defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2)
786 static uint8_t lws_header_implies_psuedoheader_map[] = {
787 0x03,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x00,0x00,
788 };
789 #endif
790 #if defined(LWS_HTTP_HEADERS_ALL) || ( defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) && defined(LWS_ROLE_WS) && defined(LWS_ROLE_H2))
791 static uint8_t lws_header_implies_psuedoheader_map[] = {
792 0x07,0x00,0x00,0x00,0xf8,0x00,0x00,0x00,0x00,0x0e,0x24,0x00,0x00,0x00,0x00,0x00,
793 };
794 #endif
795
796
797 static int
lws_hpack_handle_pseudo_rules(struct lws * nwsi,struct lws * wsi,int m)798 lws_hpack_handle_pseudo_rules(struct lws *nwsi, struct lws *wsi, int m)
799 {
800 if (m == LWS_HPACK_IGNORE_ENTRY || m == -1)
801 return 0;
802
803 if (wsi->seen_nonpseudoheader &&
804 (lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7)))) {
805
806 lwsl_info("lws tok %d seems to be a pseudoheader\n", m);
807
808 /*
809 * it's not legal to see a
810 * pseudoheader after normal
811 * headers
812 */
813 lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR,
814 "Pseudoheader after normal hdrs");
815 return 1;
816 }
817
818 if (!(lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7))))
819 wsi->seen_nonpseudoheader = 1;
820
821 return 0;
822 }
823
lws_hpack_interpret(struct lws * wsi,unsigned char c)824 int lws_hpack_interpret(struct lws *wsi, unsigned char c)
825 {
826 struct lws *nwsi = lws_get_network_wsi(wsi);
827 struct lws_h2_netconn *h2n = nwsi->h2.h2n;
828 struct allocated_headers *ah = wsi->http.ah;
829 unsigned int prev;
830 unsigned char c1;
831 int n, m, plen;
832
833 if (!h2n)
834 return -1;
835
836 /*
837 * HPKT_INDEXED_HDR_7 1xxxxxxx: just "header field"
838 * HPKT_INDEXED_HDR_6_VALUE_INCR 01xxxxxx: NEW indexed hdr + val
839 * HPKT_LITERAL_HDR_VALUE_INCR 01000000: NEW literal hdr + val
840 * HPKT_INDEXED_HDR_4_VALUE 0000xxxx: indexed hdr + val
841 * HPKT_INDEXED_HDR_4_VALUE_NEVER 0001xxxx: NEVER NEW indexed hdr + val
842 * HPKT_LITERAL_HDR_VALUE 00000000: literal hdr + val
843 * HPKT_LITERAL_HDR_VALUE_NEVER 00010000: NEVER NEW literal hdr + val
844 */
845 switch (h2n->hpack) {
846
847 case HPKS_TYPE:
848 h2n->is_first_header_char = 1;
849 h2n->huff_pad = 0;
850 h2n->zero_huff_padding = 0;
851 h2n->last_action_dyntable_resize = 0;
852 h2n->ext_count = 0;
853 h2n->hpack_hdr_len = 0;
854 h2n->unknown_header = 0;
855 ah->parser_state = 255;
856
857 if (c & 0x80) { /* 1.... indexed header field only */
858 /* just a possibly-extended integer */
859 h2n->hpack_type = HPKT_INDEXED_HDR_7;
860 lwsl_header("HPKT_INDEXED_HDR_7 hdr %d\n", c & 0x7f);
861 lws_h2_dynamic_table_dump(wsi);
862
863 h2n->hdr_idx = c & 0x7f;
864 if ((c & 0x7f) == 0x7f) {
865 h2n->hpack_len = 0;
866 h2n->hpack_m = 0x7f;
867 h2n->hpack = HPKS_IDX_EXT;
868 break;
869 }
870 if (!h2n->hdr_idx) {
871 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
872 "hdr index 0 seen");
873 return 1;
874 }
875
876 m = lws_token_from_index(wsi, (int)h2n->hdr_idx,
877 NULL, NULL, NULL);
878 if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
879 return 1;
880
881 lwsl_header("HPKT_INDEXED_HDR_7: hdr %d\n", c & 0x7f);
882 if (lws_hpack_use_idx_hdr(wsi, c & 0x7f, -1)) {
883 lwsl_header("%s: idx hdr wr fail\n", __func__);
884 return 1;
885 }
886 /* stay at same state */
887 break;
888 }
889 if (c & 0x40) { /* 01.... indexed or literal header incr idx */
890 /*
891 * [possibly-ext hdr idx (6) | new literal hdr name]
892 * H + possibly-ext value length
893 * literal value
894 */
895 h2n->hdr_idx = 0;
896 if (c == 0x40) { /* literal header */
897 lwsl_header(" HPKT_LITERAL_HDR_VALUE_INCR\n");
898 h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_INCR;
899 h2n->value = 0;
900 h2n->hpack_len = 0;
901 h2n->hpack = HPKS_HLEN;
902 break;
903 }
904 /* indexed header */
905 h2n->hpack_type = HPKT_INDEXED_HDR_6_VALUE_INCR;
906 lwsl_header(" HPKT_INDEXED_HDR_6_VALUE_INCR (hdr %d)\n",
907 c & 0x3f);
908 h2n->hdr_idx = c & 0x3f;
909 if ((c & 0x3f) == 0x3f) {
910 h2n->hpack_m = 0x3f;
911 h2n->hpack_len = 0;
912 h2n->hpack = HPKS_IDX_EXT;
913 break;
914 }
915
916 h2n->value = 1;
917 h2n->hpack = HPKS_HLEN;
918 if (!h2n->hdr_idx) {
919 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
920 "hdr index 0 seen");
921 return 1;
922 }
923 break;
924 }
925 switch(c & 0xf0) {
926 case 0x10: /* literal header never index */
927 case 0: /* literal header without indexing */
928 /*
929 * follows 0x40 except 4-bit hdr idx
930 * and don't add to index
931 */
932 if (c == 0) { /* literal name */
933 h2n->hpack_type = HPKT_LITERAL_HDR_VALUE;
934 lwsl_header(" HPKT_LITERAL_HDR_VALUE\n");
935 h2n->hpack = HPKS_HLEN;
936 h2n->value = 0;
937 break;
938 }
939 if (c == 0x10) { /* literal name NEVER */
940 h2n->hpack_type = HPKT_LITERAL_HDR_VALUE_NEVER;
941 lwsl_header(" HPKT_LITERAL_HDR_VALUE_NEVER\n");
942 h2n->hpack = HPKS_HLEN;
943 h2n->value = 0;
944 break;
945 }
946 lwsl_header("indexed\n");
947 /* indexed name */
948 if (c & 0x10) {
949 h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE_NEVER;
950 lwsl_header("HPKT_LITERAL_HDR_4_VALUE_NEVER\n");
951 } else {
952 h2n->hpack_type = HPKT_INDEXED_HDR_4_VALUE;
953 lwsl_header(" HPKT_INDEXED_HDR_4_VALUE\n");
954 }
955 h2n->hdr_idx = 0;
956 if ((c & 0xf) == 0xf) {
957 h2n->hpack_len = c & 0xf;
958 h2n->hpack_m = 0xf;
959 h2n->hpack_len = 0;
960 h2n->hpack = HPKS_IDX_EXT;
961 break;
962 }
963 h2n->hdr_idx = c & 0xf;
964 h2n->value = 1;
965 h2n->hpack = HPKS_HLEN;
966 break;
967
968 case 0x20:
969 case 0x30: /* header table size update */
970 /* possibly-extended size value (5) */
971 lwsl_header("HPKT_SIZE_5 %x\n", c &0x1f);
972 h2n->hpack_type = HPKT_SIZE_5;
973 h2n->hpack_len = c & 0x1f;
974 if (h2n->hpack_len == 0x1f) {
975 h2n->hpack_m = 0x1f;
976 h2n->hpack_len = 0;
977 h2n->hpack = HPKS_IDX_EXT;
978 break;
979 }
980 h2n->last_action_dyntable_resize = 1;
981 if (lws_hpack_dynamic_size(wsi, (int)h2n->hpack_len))
982 return 1;
983 break;
984 }
985 break;
986
987 case HPKS_IDX_EXT:
988 h2n->hpack_len = (uint32_t)((unsigned int)h2n->hpack_len |
989 (unsigned int)((c & 0x7f) << h2n->ext_count));
990 h2n->ext_count = (uint8_t)(h2n->ext_count + 7);
991 if (c & 0x80) /* extended int not complete yet */
992 break;
993
994 /* extended integer done */
995 h2n->hpack_len += h2n->hpack_m;
996 lwsl_header("HPKS_IDX_EXT: hpack_len %u\n", (unsigned int)h2n->hpack_len);
997
998 switch (h2n->hpack_type) {
999 case HPKT_INDEXED_HDR_7:
1000 if (lws_hpack_use_idx_hdr(wsi, (int)h2n->hpack_len,
1001 (int)h2n->hdr_idx)) {
1002 lwsl_notice("%s: hd7 use fail\n", __func__);
1003 return 1;
1004 }
1005 h2n->hpack = HPKS_TYPE;
1006 break;
1007
1008 case HPKT_SIZE_5:
1009 h2n->last_action_dyntable_resize = 1;
1010 if (lws_hpack_dynamic_size(wsi, (int)h2n->hpack_len))
1011 return 1;
1012 h2n->hpack = HPKS_TYPE;
1013 break;
1014
1015 default:
1016 h2n->hdr_idx = h2n->hpack_len;
1017 if (!h2n->hdr_idx) {
1018 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
1019 "extended header index was 0");
1020 return 1;
1021 }
1022 h2n->value = 1;
1023 h2n->hpack = HPKS_HLEN;
1024 break;
1025 }
1026 break;
1027
1028 case HPKS_HLEN: /* [ H | 7+ ] */
1029 h2n->huff = !!(c & 0x80);
1030 h2n->hpack_pos = 0;
1031 h2n->hpack_len = c & 0x7f;
1032
1033 if (h2n->hpack_len == 0x7f) {
1034 h2n->hpack_m = 0x7f;
1035 h2n->hpack_len = 0;
1036 h2n->ext_count = 0;
1037 h2n->hpack = HPKS_HLEN_EXT;
1038 break;
1039 }
1040
1041 if (h2n->value && !h2n->hpack_len) {
1042 lwsl_debug("%s: zero-length header data\n", __func__);
1043 h2n->hpack = HPKS_TYPE;
1044 goto fin;
1045 }
1046
1047 pre_data:
1048 h2n->hpack = HPKS_DATA;
1049 if (!h2n->value || !h2n->hdr_idx) {
1050 ah->parser_state = WSI_TOKEN_NAME_PART;
1051 ah->lextable_pos = 0;
1052 h2n->unknown_header = 0;
1053 break;
1054 }
1055
1056 if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1057 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1058 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) {
1059 n = ah->parser_state;
1060 if (n == 255) {
1061 n = -1;
1062 h2n->hdr_idx = (uint32_t)-1;
1063 } else
1064 h2n->hdr_idx = 1;
1065 } else {
1066 n = lws_token_from_index(wsi, (int)h2n->hdr_idx, NULL,
1067 NULL, NULL);
1068 lwsl_header(" lws_tok_from_idx(%u) says %d\n",
1069 (unsigned int)h2n->hdr_idx, n);
1070 }
1071
1072 if (n == LWS_HPACK_IGNORE_ENTRY || n == -1)
1073 h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
1074
1075 switch (h2n->hpack_type) {
1076 /*
1077 * hpack types with literal headers were parsed by the lws
1078 * header SM... on recognition of a known lws header, it does
1079 * the correct lws_frag_start() for us already. Other types
1080 * (ie, indexed header) need us to do it here.
1081 */
1082 case HPKT_LITERAL_HDR_VALUE_INCR:
1083 case HPKT_LITERAL_HDR_VALUE:
1084 case HPKT_LITERAL_HDR_VALUE_NEVER:
1085 break;
1086 default:
1087 if (n != -1 && n != LWS_HPACK_IGNORE_ENTRY &&
1088 lws_frag_start(wsi, n)) {
1089 lwsl_header("%s: frag start failed\n",
1090 __func__);
1091 return 1;
1092 }
1093 break;
1094 }
1095 break;
1096
1097 case HPKS_HLEN_EXT:
1098 h2n->hpack_len = (uint32_t)((unsigned int)h2n->hpack_len |
1099 (unsigned int)((c & 0x7f) << h2n->ext_count));
1100 h2n->ext_count = (uint8_t)(h2n->ext_count + 7);
1101 if (c & 0x80) /* extended integer not complete yet */
1102 break;
1103
1104 h2n->hpack_len += h2n->hpack_m;
1105 goto pre_data;
1106
1107 case HPKS_DATA:
1108 //lwsl_header(" 0x%02X huff %d\n", c, h2n->huff);
1109 c1 = c;
1110
1111 for (n = 0; n < 8; n++) {
1112 if (h2n->huff) {
1113 char b = (c >> 7) & 1;
1114 prev = h2n->hpack_pos;
1115 h2n->hpack_pos = (uint16_t)huftable_decode(
1116 (int)h2n->hpack_pos, b);
1117 c = (unsigned char)(c << 1);
1118 if (h2n->hpack_pos == 0xffff) {
1119 lwsl_notice("Huffman err\n");
1120 return 1;
1121 }
1122 if (!(h2n->hpack_pos & 0x8000)) {
1123 if (!b)
1124 h2n->zero_huff_padding = 1;
1125 h2n->huff_pad++;
1126 continue;
1127 }
1128 c1 = (uint8_t)(h2n->hpack_pos & 0x7fff);
1129 h2n->hpack_pos = 0;
1130 h2n->huff_pad = 0;
1131 h2n->zero_huff_padding = 0;
1132
1133 /* EOS |11111111|11111111|11111111|111111 */
1134 if (!c1 && prev == HUFTABLE_0x100_PREV) {
1135 lws_h2_goaway(nwsi,
1136 H2_ERR_COMPRESSION_ERROR,
1137 "Huffman EOT seen");
1138 return 1;
1139 }
1140 } else
1141 n = 8;
1142
1143 if (h2n->value) { /* value */
1144
1145 if (h2n->hdr_idx &&
1146 h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY) {
1147
1148 if (ah->hdr_token_idx ==
1149 WSI_TOKEN_HTTP_COLON_PATH) {
1150
1151 switch (lws_parse_urldecode(
1152 wsi, &c1)) {
1153 case LPUR_CONTINUE:
1154 break;
1155 case LPUR_SWALLOW:
1156 goto swallow;
1157 case LPUR_EXCESSIVE:
1158 case LPUR_FORBID:
1159 lws_h2_goaway(nwsi,
1160 H2_ERR_PROTOCOL_ERROR,
1161 "Evil URI");
1162 return 1;
1163
1164 default:
1165 return -1;
1166 }
1167 }
1168 if (lws_frag_append(wsi, c1)) {
1169 lwsl_notice(
1170 "%s: frag app fail\n",
1171 __func__);
1172 return 1;
1173 }
1174 } //else
1175 //lwsl_header("ignoring %c\n", c1);
1176 } else {
1177 /*
1178 * Convert name using existing parser,
1179 * If h2n->unknown_header == 0, result is
1180 * in wsi->parser_state
1181 * using WSI_TOKEN_GET_URI.
1182 *
1183 * If unknown header h2n->unknown_header
1184 * will be set.
1185 */
1186 h2n->hpack_hdr_len++;
1187 if (h2n->is_first_header_char) {
1188 h2n->is_first_header_char = 0;
1189 h2n->first_hdr_char = (char)c1;
1190 }
1191 lwsl_header("parser: %c\n", c1);
1192 /* uppercase header names illegal */
1193 if (c1 >= 'A' && c1 <= 'Z') {
1194 lws_h2_goaway(nwsi,
1195 H2_ERR_COMPRESSION_ERROR,
1196 "Uppercase literal hpack hdr");
1197 return 1;
1198 }
1199 plen = 1;
1200 if (!h2n->unknown_header &&
1201 lws_parse(wsi, &c1, &plen))
1202 h2n->unknown_header = 1;
1203 }
1204 swallow:
1205 (void)n;
1206 } // for n
1207
1208 if (--h2n->hpack_len)
1209 break;
1210
1211 /*
1212 * The header (h2n->value = 0) or the payload (h2n->value = 1)
1213 * is complete.
1214 */
1215
1216 if (h2n->huff && (h2n->huff_pad > 7 ||
1217 (h2n->zero_huff_padding && h2n->huff_pad))) {
1218 lwsl_info("zero_huff_padding: %d huff_pad: %d\n",
1219 h2n->zero_huff_padding, h2n->huff_pad);
1220 lws_h2_goaway(nwsi, H2_ERR_COMPRESSION_ERROR,
1221 "Huffman padding excessive or wrong");
1222 return 1;
1223 }
1224 fin:
1225 if (!h2n->value && (
1226 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1227 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1228 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER)) {
1229 h2n->hdr_idx = LWS_HPACK_IGNORE_ENTRY;
1230 lwsl_header("wsi->parser_state: %d\n",
1231 ah->parser_state);
1232
1233 if (ah->parser_state == WSI_TOKEN_NAME_PART) {
1234 /* h2 headers come without the colon */
1235 c1 = ':';
1236 plen = 1;
1237 n = lws_parse(wsi, &c1, &plen);
1238 (void)n;
1239 }
1240
1241 if (ah->parser_state == WSI_TOKEN_NAME_PART ||
1242 #if defined(LWS_WITH_CUSTOM_HEADERS)
1243 ah->parser_state == WSI_TOKEN_UNKNOWN_VALUE_PART ||
1244 #endif
1245 ah->parser_state == WSI_TOKEN_SKIPPING) {
1246 h2n->unknown_header = 1;
1247 ah->parser_state = 0xff;
1248 wsi->seen_nonpseudoheader = 1;
1249 }
1250 }
1251
1252 /* we have the header */
1253 if (!h2n->value) {
1254 h2n->value = 1;
1255 h2n->hpack = HPKS_HLEN;
1256 h2n->huff_pad = 0;
1257 h2n->zero_huff_padding = 0;
1258 h2n->ext_count = 0;
1259 break;
1260 }
1261
1262 /*
1263 * we have got both the header and value
1264 */
1265
1266 m = -1;
1267 switch (h2n->hpack_type) {
1268 /*
1269 * These are the only two that insert to the dyntable
1270 */
1271 /* NEW indexed hdr with value */
1272 case HPKT_INDEXED_HDR_6_VALUE_INCR:
1273 /* header length is determined by known index */
1274 m = lws_token_from_index(wsi, (int)h2n->hdr_idx, NULL, NULL,
1275 &h2n->hpack_hdr_len);
1276 if (m < 0)
1277 /*
1278 * The peer may only send known 6-bit indexes,
1279 * there's still the possibility it sends an unset
1280 * dynamic index that we can't succeed to look up
1281 */
1282 return 1;
1283 goto add_it;
1284 /* NEW literal hdr with value */
1285 case HPKT_LITERAL_HDR_VALUE_INCR:
1286 /*
1287 * hdr is a new literal, so length is already in
1288 * h2n->hpack_hdr_len
1289 */
1290 m = ah->parser_state;
1291 if (h2n->unknown_header ||
1292 ah->parser_state == WSI_TOKEN_NAME_PART ||
1293 ah->parser_state == WSI_TOKEN_SKIPPING) {
1294 if (h2n->first_hdr_char == ':') {
1295 lwsl_info("HPKT_LITERAL_HDR_VALUE_INCR:"
1296 " end state %d unk hdr %d\n",
1297 ah->parser_state,
1298 h2n->unknown_header);
1299 /* unknown pseudoheaders are illegal */
1300 lws_h2_goaway(nwsi,
1301 H2_ERR_PROTOCOL_ERROR,
1302 "Unknown pseudoheader");
1303 return 1;
1304 }
1305 m = LWS_HPACK_IGNORE_ENTRY;
1306 }
1307 add_it:
1308 /*
1309 * mark us as having been set at the time of dynamic
1310 * token insertion.
1311 */
1312 ah->frags[ah->nfrag].flags |= 1;
1313
1314 if (lws_dynamic_token_insert(wsi, (int)h2n->hpack_hdr_len, m,
1315 &ah->data[ah->frags[ah->nfrag].offset],
1316 ah->frags[ah->nfrag].len)) {
1317 lwsl_notice("%s: tok_insert fail\n", __func__);
1318 return 1;
1319 }
1320 break;
1321
1322 default:
1323 break;
1324 }
1325
1326 if (h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY && lws_frag_end(wsi))
1327 return 1;
1328
1329 if (h2n->hpack_type != HPKT_INDEXED_HDR_6_VALUE_INCR) {
1330
1331 if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE ||
1332 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR ||
1333 h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) {
1334 m = ah->parser_state;
1335 if (m == 255)
1336 m = -1;
1337 } else
1338 m = lws_token_from_index(wsi, (int)h2n->hdr_idx,
1339 NULL, NULL, NULL);
1340 }
1341
1342 if (m != -1 && m != LWS_HPACK_IGNORE_ENTRY)
1343 lws_dump_header(wsi, m);
1344
1345 if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
1346 return 1;
1347
1348 h2n->is_first_header_char = 1;
1349 h2n->hpack = HPKS_TYPE;
1350 break;
1351 }
1352
1353 return 0;
1354 }
1355
1356
1357
1358 static unsigned int
lws_h2_num_start(int starting_bits,unsigned long num)1359 lws_h2_num_start(int starting_bits, unsigned long num)
1360 {
1361 unsigned int mask = (unsigned int)((1 << starting_bits) - 1);
1362
1363 if (num < mask)
1364 return (unsigned int)num;
1365
1366 return mask;
1367 }
1368
1369 static int
lws_h2_num(int starting_bits,unsigned long num,unsigned char ** p,unsigned char * end)1370 lws_h2_num(int starting_bits, unsigned long num,
1371 unsigned char **p, unsigned char *end)
1372 {
1373 unsigned int mask = (unsigned int)((1 << starting_bits) - 1);
1374
1375 if (num < mask)
1376 return 0;
1377
1378 num -= mask;
1379 do {
1380 if (num > 127)
1381 *((*p)++) = (uint8_t)(0x80 | (num & 0x7f));
1382 else
1383 *((*p)++) = (uint8_t)(0x00 | (num & 0x7f));
1384 if (*p >= end)
1385 return 1;
1386 num >>= 7;
1387 } while (num);
1388
1389 return 0;
1390 }
1391
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)1392 int lws_add_http2_header_by_name(struct lws *wsi, const unsigned char *name,
1393 const unsigned char *value, int length,
1394 unsigned char **p, unsigned char *end)
1395 {
1396 int len;
1397
1398 #if defined(_DEBUG)
1399 /* value does not have to be NUL-terminated... %.*s not available on
1400 * all platforms */
1401 if (value) {
1402 lws_strnncpy((char *)*p, (const char *)value, length,
1403 lws_ptr_diff(end, (*p)));
1404
1405 lwsl_header("%s: %p %s:%s (len %d)\n", __func__, *p, name,
1406 (const char *)*p, length);
1407 } else {
1408 lwsl_err("%s: %p dummy copy %s (len %d)\n", __func__, *p, name, length);
1409 }
1410 #endif
1411
1412 len = (int)strlen((char *)name);
1413 if (len)
1414 if (name[len - 1] == ':')
1415 len--;
1416
1417 if (wsi->mux_substream && !strncmp((const char *)name,
1418 "transfer-encoding", (unsigned int)len)) {
1419 lwsl_header("rejecting %s\n", name);
1420
1421 return 0;
1422 }
1423
1424 if (end - *p < len + length + 8)
1425 return 1;
1426
1427 *((*p)++) = 0; /* literal hdr, literal name, */
1428
1429 *((*p)++) = (uint8_t)(0 | (uint8_t)lws_h2_num_start(7, (unsigned long)len)); /* non-HUF */
1430 if (lws_h2_num(7, (unsigned long)len, p, end))
1431 return 1;
1432
1433 /* upper-case header names are verboten in h2, but OK on h1, so
1434 * they're not illegal per se. Silently convert them for h2... */
1435
1436 while(len--)
1437 *((*p)++) = (uint8_t)tolower((int)*name++);
1438
1439 *((*p)++) = (uint8_t)(0 | (uint8_t)lws_h2_num_start(7, (unsigned long)length)); /* non-HUF */
1440 if (lws_h2_num(7, (unsigned long)length, p, end))
1441 return 1;
1442
1443 if (value)
1444 memcpy(*p, value, (unsigned int)length);
1445 *p += length;
1446
1447 return 0;
1448 }
1449
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)1450 int lws_add_http2_header_by_token(struct lws *wsi, enum lws_token_indexes token,
1451 const unsigned char *value, int length,
1452 unsigned char **p, unsigned char *end)
1453 {
1454 const unsigned char *name;
1455
1456 name = lws_token_to_string(token);
1457 if (!name)
1458 return 1;
1459
1460 return lws_add_http2_header_by_name(wsi, name, value, length, p, end);
1461 }
1462
lws_add_http2_header_status(struct lws * wsi,unsigned int code,unsigned char ** p,unsigned char * end)1463 int lws_add_http2_header_status(struct lws *wsi, unsigned int code,
1464 unsigned char **p, unsigned char *end)
1465 {
1466 unsigned char status[10];
1467 int n;
1468
1469 wsi->h2.send_END_STREAM = 0; // !!(code >= 400);
1470
1471 n = sprintf((char *)status, "%u", code);
1472 if (lws_add_http2_header_by_token(wsi, WSI_TOKEN_HTTP_COLON_STATUS,
1473 status, n, p, end))
1474
1475 return 1;
1476
1477 return 0;
1478 }
1479