• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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