1 /*****************************************************************************
2 * hpack.c: HPACK Header Compression for HTTP/2
3 *****************************************************************************
4 * Copyright (C) 2015 Rémi Denis-Courmont
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #ifdef DEC_TEST
26 # undef NDEBUG
27 #endif
28
29 #include <assert.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <stdbool.h>
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <string.h>
36
37 #include "hpack.h"
38
39 /** Static Table header names */
40 static const char hpack_names[][28] =
41 {
42 ":authority", ":method", ":method", ":path", ":path", ":scheme", ":scheme",
43 ":status", ":status", ":status", ":status", ":status", ":status",
44 ":status", "accept-charset", "accept-encoding", "accept-language",
45 "accept-ranges", "accept", "access-control-allow-origin", "age", "allow",
46 "authorization", "cache-control", "content-disposition",
47 "content-encoding", "content-language", "content-length",
48 "content-location", "content-range", "content-type", "cookie", "date",
49 "etag", "expect", "expires", "from", "host", "if-match",
50 "if-modified-since", "if-none-match", "if-range", "if-unmodified-since",
51 "last-modified", "link", "location", "max-forwards", "proxy-authenticate",
52 "proxy-authorization", "range", "referer", "refresh", "retry-after",
53 "server", "set-cookie", "strict-transport-security", "transfer-encoding",
54 "user-agent", "vary", "via", "www-authenticate",
55 };
56
57 /** Static Table header values */
58 static const char hpack_values[][14] =
59 {
60 "", "GET", "POST", "/", "/index.html", "http", "https", "200", "204",
61 "206", "304", "400", "404", "500", "", "gzip, deflate"
62 };
63
64 struct hpack_decoder
65 {
66 char **table;
67 size_t entries;
68 size_t size;
69 size_t max_size;
70 };
71
hpack_decode_init(size_t header_table_size)72 struct hpack_decoder *hpack_decode_init(size_t header_table_size)
73 {
74 struct hpack_decoder *dec = malloc(sizeof (*dec));
75 if (dec == NULL)
76 return NULL;
77
78 dec->table = NULL;
79 dec->entries = 0;
80 dec->size = 0;
81 dec->max_size = header_table_size;
82 return dec;
83 }
84
hpack_decode_destroy(struct hpack_decoder * dec)85 void hpack_decode_destroy(struct hpack_decoder *dec)
86 {
87 for (unsigned i = 0; i < dec->entries; i++)
88 free(dec->table[i]);
89 free(dec->table);
90 free(dec);
91 }
92
93 /**
94 * Decodes an HPACK unsigned variable length integer.
95 * @return the value on success, -1 on error (and sets errno).
96 */
hpack_decode_int(unsigned n,const uint8_t ** restrict datap,size_t * restrict lengthp)97 static int_fast32_t hpack_decode_int(unsigned n,
98 const uint8_t **restrict datap,
99 size_t *restrict lengthp)
100 {
101 const uint8_t *p = *datap;
102 size_t length = *lengthp;
103
104 assert(n >= 1 && n <= 8);
105 assert(length >= 1);
106
107 unsigned mask = (1 << n) - 1;
108 uint_fast32_t i = *(p++) & mask;
109 length--;
110
111 if (i == mask)
112 {
113 unsigned shift = 0;
114 uint8_t b;
115
116 do
117 {
118 if (length-- < 1)
119 {
120 errno = EINVAL;
121 return -1;
122 }
123
124 if (shift >= 28)
125 {
126 errno = ERANGE;
127 return -1;
128 }
129
130 b = *(p++);
131 i += (b & 0x7F) << shift;
132 shift += 7;
133 }
134 while (b & 0x80);
135 }
136
137 *datap = p;
138 *lengthp = length;
139 return i;
140 }
141
142 /**
143 * Decodes a raw string literal.
144 */
hpack_decode_str_raw(const uint8_t * data,size_t length)145 static char *hpack_decode_str_raw(const uint8_t *data, size_t length)
146 {
147 char *s = malloc(length + 1);
148 if (s != NULL)
149 {
150 memcpy(s, data, length);
151 s[length] = '\0';
152 }
153 return s;
154 }
155
hpack_decode_byte_huffman(const uint8_t * restrict end,int * restrict bit_offset)156 static int hpack_decode_byte_huffman(const uint8_t *restrict end,
157 int *restrict bit_offset)
158 {
159 static const unsigned char tab[256] = {
160 /* 5 bits */
161 48, 49, 50, 97, 99, 101, 105, 111, 115, 116,
162 /* 6 bits */
163 32, 37, 45, 46, 47, 51, 52, 53, 54, 55, 56, 57, 61, 65,
164 95, 98, 100, 102, 103, 104, 108, 109, 110, 112, 114, 117,
165 /* 7 bits */
166 58, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
167 79, 80, 81, 82, 83, 84, 85, 86, 87, 89, 106, 107, 113, 118,
168 119, 120, 121, 122,
169 /* 8 bits */
170 38, 42, 44, 59, 88, 90,
171 /* 10 bits */
172 33, 34, 40, 41, 63,
173 /* 11 bits */
174 39, 43, 124,
175 /* 12 bits */
176 35, 62,
177 /* 13 bits */
178 0, 36, 64, 91, 93, 126,
179 /* 14 bits */
180 94, 125,
181 /* 15 bits */
182 60, 96, 123,
183 /* 19 bits */
184 92, 195, 208,
185 /* 20 bits */
186 128, 130, 131, 162, 184, 194, 224, 226,
187 /* 21 bits */
188 153, 161, 167, 172, 176, 177, 179, 209, 216, 217, 227, 229, 230,
189 /* 22 bits */
190 129, 132, 133, 134, 136, 146, 154, 156, 160, 163, 164, 169, 170, 173,
191 178, 181, 185, 186, 187, 189, 190, 196, 198, 228, 232, 233,
192 /* 23 bits */
193 1, 135, 137, 138, 139, 140, 141, 143, 147, 149, 150, 151, 152, 155,
194 157, 158, 165, 166, 168, 174, 175, 180, 182, 183, 188, 191, 197, 231,
195 239,
196 /* 24 bits */
197 9, 142, 144, 145, 148, 159, 171, 206, 215, 225, 236, 237,
198 /* 25 bits */
199 199, 207, 234, 235,
200 /* 26 bits */
201 192, 193, 200, 201, 202, 205, 210, 213, 218, 219, 238, 240, 242, 243,
202 255,
203 /* 27 bits */
204 203, 204, 211, 212, 214, 221, 222, 223, 241, 244, 245, 246, 247, 248,
205 250, 251, 252, 253, 254,
206 /* 28 bits */
207 2, 3, 4, 5, 6, 7, 8, 11, 12, 14, 15, 16, 17, 18,
208 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 220,
209 249,
210 /* 30 bits */
211 10, 13, 22,
212 };
213 static const unsigned char values[30] = {
214 0, 0, 0, 0, 10, 26, 32, 6, 0, 5, 3, 2, 6, 2, 3,
215 0, 0, 0, 3, 8, 13, 26, 29, 12, 4, 15, 19, 29, 0, 3
216 };
217 const unsigned char *p = tab;
218 uint_fast32_t code = 0, offset = 0;
219 unsigned shift = -*bit_offset;
220
221 for (unsigned i = 0; i < 30; i++)
222 {
223 code <<= 1;
224
225 /* Read one bit */
226 if (*bit_offset)
227 {
228 shift = (shift - 1) & 7;
229 code |= (end[*bit_offset >> 3] >> shift) & 1;
230 (*bit_offset)++;
231 }
232 else
233 code |= 1; /* EOS is all ones */
234
235 assert(code >= offset);
236 if ((code - offset) < values[i])
237 return p[code - offset];
238 p += values[i];
239 offset = (offset + values[i]) * 2;
240 }
241
242 assert(p - tab == 256);
243
244 if (code == 0x3fffffff)
245 return 256; /* EOS */
246
247 errno = EINVAL;
248 return -1;
249 }
250
251 /**
252 * Decodes an Huffman-encoded string literal.
253 */
hpack_decode_str_huffman(const uint8_t * data,size_t length)254 static char *hpack_decode_str_huffman(const uint8_t *data, size_t length)
255 {
256 unsigned char *str = malloc(length * 2 + 1);
257 if (str == NULL)
258 return NULL;
259
260 size_t len = 0;
261 int bit_offset = -8 * length;
262 data += length;
263
264 for (;;)
265 {
266 int c = hpack_decode_byte_huffman(data, &bit_offset);
267 if (c < 0)
268 {
269 errno = EINVAL;
270 goto error;
271 }
272
273 /* NOTE: EOS (256) is converted to nul terminator */
274 str[len++] = c;
275
276 if (c == 256)
277 break;
278 }
279
280 return (char *)str;
281
282 error:
283 free(str);
284 return NULL;
285 }
286
287 /**
288 * Decodes a string literal.
289 * @return a heap-allocated nul-terminated string success,
290 * NULL on error (and sets errno).
291 */
hpack_decode_str(const uint8_t ** restrict datap,size_t * restrict lengthp)292 static char *hpack_decode_str(const uint8_t **restrict datap,
293 size_t *restrict lengthp)
294 {
295 if (*lengthp < 1)
296 {
297 errno = EINVAL;
298 return NULL;
299 }
300
301 bool huffman = ((*datap)[0] & 0x80) != 0;
302 int_fast32_t len = hpack_decode_int(7, datap, lengthp);
303 if (len < 0)
304 return NULL;
305
306 if ((size_t)len > *lengthp)
307 {
308 errno = EINVAL;
309 return NULL;
310 }
311
312 if (len > 65535) /* Stick to a sane limit */
313 {
314 errno = ERANGE;
315 return NULL;
316 }
317
318 const uint8_t *buf = *datap;
319
320 *datap += len;
321 *lengthp -= len;
322
323 return (huffman ? hpack_decode_str_huffman : hpack_decode_str_raw)
324 (buf, len);
325 }
326
hpack_lookup_name(const struct hpack_decoder * dec,uint_fast32_t idx)327 static char *hpack_lookup_name(const struct hpack_decoder *dec,
328 uint_fast32_t idx)
329 {
330 if (idx == 0)
331 {
332 errno = EINVAL;
333 return NULL;
334 }
335
336 idx--;
337 if (idx < sizeof (hpack_names) / sizeof (hpack_names[0]))
338 return strdup(hpack_names[idx]);
339
340 idx -= sizeof (hpack_names) / sizeof (hpack_names[0]);
341 if (idx < dec->entries)
342 {
343 const char *entry = dec->table[dec->entries - (idx + 1)];
344 return strdup(entry);
345 }
346
347 errno = EINVAL;
348 return NULL;
349 }
350
hpack_lookup_value(const struct hpack_decoder * dec,uint_fast32_t idx)351 static char *hpack_lookup_value(const struct hpack_decoder *dec,
352 uint_fast32_t idx)
353 {
354 if (idx == 0)
355 {
356 errno = EINVAL;
357 return NULL;
358 }
359
360 idx--;
361 if (idx < sizeof (hpack_values) / sizeof (hpack_values[0]))
362 return strdup(hpack_values[idx]);
363 if (idx < sizeof (hpack_names) / sizeof (hpack_names[0]))
364 return strdup("");
365
366 idx -= sizeof (hpack_names) / sizeof (hpack_names[0]);
367 if (idx < dec->entries)
368 {
369 const char *entry = dec->table[dec->entries - (idx + 1)];
370 return strdup(entry + strlen(entry) + 1);
371 }
372
373 errno = EINVAL;
374 return NULL;
375 }
376
hpack_decode_evict(struct hpack_decoder * dec)377 static void hpack_decode_evict(struct hpack_decoder *dec)
378 {
379 /* Eviction: count how many entries to evict */
380 size_t evicted = 0;
381 while (dec->size > dec->max_size)
382 {
383 assert(evicted < dec->entries);
384
385 size_t namelen = strlen(dec->table[evicted]);
386 size_t valuelen = strlen(dec->table[evicted] + namelen + 1);
387
388 assert(dec->size >= 32 + namelen + valuelen);
389 dec->size -= 32 + namelen + valuelen;
390 evicted++;
391 }
392
393 /* Eviction: remove oldest entries */
394 if (evicted > 0)
395 {
396 for (size_t i = 0; i < evicted; i++)
397 free(dec->table[i]);
398
399 dec->entries -= evicted;
400 memmove(dec->table, dec->table + evicted,
401 sizeof (dec->table[0]) * dec->entries);
402 }
403 }
404
hpack_append_hdr(struct hpack_decoder * dec,const char * name,const char * value)405 static int hpack_append_hdr(struct hpack_decoder *dec,
406 const char *name, const char *value)
407 {
408 size_t namelen = strlen(name), valuelen = strlen(value);
409 char *entry = malloc(namelen + valuelen + 2);
410 if (entry == NULL)
411 return -1;
412 memcpy(entry, name, namelen + 1);
413 memcpy(entry + namelen + 1, value, valuelen + 1);
414
415 char **newtab = realloc(dec->table,
416 sizeof (dec->table[0]) * (dec->entries + 1));
417 if (newtab == NULL)
418 {
419 free(entry);
420 return -1;
421 }
422
423 dec->table = newtab;
424 dec->table[dec->entries] = entry;
425 dec->entries++;
426 dec->size += 32 + namelen + valuelen;
427
428 hpack_decode_evict(dec);
429 return 0;
430 }
431
hpack_decode_hdr_indexed(struct hpack_decoder * dec,const uint8_t ** restrict datap,size_t * restrict lengthp,char ** restrict namep,char ** restrict valuep)432 static int hpack_decode_hdr_indexed(struct hpack_decoder *dec,
433 const uint8_t **restrict datap,
434 size_t *restrict lengthp,
435 char **restrict namep,
436 char **restrict valuep)
437 {
438 int_fast32_t idx = hpack_decode_int(7, datap, lengthp);
439 if (idx < 0)
440 return -1;
441
442 char *name = hpack_lookup_name(dec, idx);
443 if (name == NULL)
444 return -1;
445
446 char *value = hpack_lookup_value(dec, idx);
447 if (value == NULL)
448 {
449 free(name);
450 return -1;
451 }
452
453 *namep = name;
454 *valuep = value;
455 return 0;
456 }
457
hpack_decode_hdr_index(struct hpack_decoder * dec,const uint8_t ** restrict datap,size_t * restrict lengthp,char ** restrict namep,char ** restrict valuep)458 static int hpack_decode_hdr_index(struct hpack_decoder *dec,
459 const uint8_t **restrict datap,
460 size_t *restrict lengthp,
461 char **restrict namep,
462 char **restrict valuep)
463 {
464 int_fast32_t idx = hpack_decode_int(6, datap, lengthp);
465 if (idx < 0)
466 return -1;
467
468 char *name;
469
470 if (idx != 0)
471 name = hpack_lookup_name(dec, idx);
472 else
473 name = hpack_decode_str(datap, lengthp);
474 if (name == NULL)
475 return -1;
476
477 char *value = hpack_decode_str(datap, lengthp);
478 if (value == NULL)
479 {
480 free(name);
481 return -1;
482 }
483
484 if (hpack_append_hdr(dec, name, value))
485 {
486 free(value);
487 free(name);
488 return -1;
489 }
490
491 *namep = name;
492 *valuep = value;
493 return 0;
494 }
495
hpack_decode_hdr_noindex(struct hpack_decoder * dec,const uint8_t ** restrict datap,size_t * restrict lengthp,char ** restrict namep,char ** restrict valuep)496 static int hpack_decode_hdr_noindex(struct hpack_decoder *dec,
497 const uint8_t **restrict datap,
498 size_t *restrict lengthp,
499 char **restrict namep,
500 char **restrict valuep)
501 {
502 int_fast32_t idx = hpack_decode_int(4, datap, lengthp);
503 if (idx < 0)
504 return -1;
505
506 char *name;
507
508 if (idx != 0)
509 name = hpack_lookup_name(dec, idx);
510 else
511 name = hpack_decode_str(datap, lengthp);
512 if (name == NULL)
513 return -1;
514
515 char *value = hpack_decode_str(datap, lengthp);
516 if (value == NULL)
517 {
518 free(name);
519 return -1;
520 }
521
522 *namep = name;
523 *valuep = value;
524 return 0;
525 }
526
hpack_decode_tbl_update(struct hpack_decoder * dec,const uint8_t ** restrict datap,size_t * restrict lengthp,char ** restrict name,char ** restrict value)527 static int hpack_decode_tbl_update(struct hpack_decoder *dec,
528 const uint8_t **restrict datap,
529 size_t *restrict lengthp,
530 char **restrict name,
531 char **restrict value)
532 {
533 int_fast32_t max = hpack_decode_int(5, datap, lengthp);
534 if (max < 0)
535 return -1;
536
537 if ((size_t)max > dec->max_size)
538 { /* Increasing the maximum is not permitted per the specification */
539 errno = EINVAL;
540 return -1;
541 }
542
543 *value = *name = NULL;
544 dec->max_size = max;
545 hpack_decode_evict(dec);
546 return 0;
547 }
548
hpack_decode_hdr(struct hpack_decoder * dec,const uint8_t ** restrict datap,size_t * restrict lengthp,char ** restrict namep,char ** restrict valuep)549 static int hpack_decode_hdr(struct hpack_decoder *dec,
550 const uint8_t **restrict datap,
551 size_t *restrict lengthp,
552 char **restrict namep,
553 char **restrict valuep)
554 {
555 int (*cb)(struct hpack_decoder *, const uint8_t **, size_t *,
556 char **, char **);
557
558 assert(*lengthp >= 1);
559
560 uint8_t b = **datap;
561
562 if (b & 0x80)
563 cb = hpack_decode_hdr_indexed;
564 else if (b & 0x40)
565 cb = hpack_decode_hdr_index;
566 else if (b & 0x20)
567 cb = hpack_decode_tbl_update;
568 else
569 /* NOTE: never indexed and not indexed are treated identically */
570 cb = hpack_decode_hdr_noindex;
571
572 return cb(dec, datap, lengthp, namep, valuep);
573 }
574
hpack_decode(struct hpack_decoder * dec,const uint8_t * data,size_t length,char * headers[][2],unsigned max)575 int hpack_decode(struct hpack_decoder *dec, const uint8_t *data,
576 size_t length, char *headers[][2], unsigned max)
577 {
578 unsigned count = 0;
579
580 while (length > 0)
581 {
582 char *name, *value;
583 int val = hpack_decode_hdr(dec, &data, &length, &name, &value);
584 if (val < 0)
585 goto error;
586
587 assert((name == NULL) == (value == NULL));
588 if (name == NULL)
589 continue;
590
591 if (count < max)
592 {
593 headers[count][0] = name;
594 headers[count][1] = value;
595 }
596 else
597 {
598 free(value);
599 free(name);
600 }
601 count++;
602 }
603 return count;
604
605 error:
606 while (count > 0)
607 {
608 count--;
609 free(headers[count][1]);
610 free(headers[count][0]);
611 }
612 return -1;
613 }
614
615 /*** Test cases ***/
616 #ifdef DEC_TEST
617 # include <stdarg.h>
618 # include <stdio.h>
619
test_integer(unsigned n,const uint8_t * buf,size_t len,int_fast32_t value)620 static void test_integer(unsigned n, const uint8_t *buf, size_t len,
621 int_fast32_t value)
622 {
623 printf("%s(%u, %zu byte(s))...\n", __func__, n, len);
624
625 /* Check too short buffers */
626 for (size_t i = 1; i < len; i++)
627 {
628 const uint8_t *cutbuf = buf;
629 size_t cutlen = i;
630 assert(hpack_decode_int(n, &cutbuf, &cutlen) == -1);
631 }
632
633 /* Check succesful decoding */
634 const uint8_t *end = buf + len;
635 int_fast32_t v = hpack_decode_int(n, &buf, &len);
636
637 assert(v == value);
638 assert(buf == end);
639 assert(len == 0);
640 }
641
test_integers(void)642 static void test_integers(void)
643 {
644 /* Decoding 10 using a 5-bits prefix */
645 for (unsigned i = 0; i < 8; i++)
646 {
647 uint8_t data[1] = { (i << 5) | 0xA };
648 test_integer(5, data, 1, 10);
649 }
650
651 /* Decoding 1337 using a 5-bits prefix */
652 for (unsigned i = 0; i < 8; i++)
653 {
654 uint8_t data[3] = { (i << 5) | 0x1F, 0x9A, 0x0A };
655 test_integer(5, data, 3, 1337);
656 }
657
658 /* Decoding 42 using a 8-bits prefix */
659 uint8_t data[1] = { 42 };
660 test_integer(8, data, 1, 42);
661 }
662
test_header(const char * str,size_t len,const char * name,const char * value)663 static void test_header(const char *str, size_t len,
664 const char *name, const char *value)
665 {
666 printf("%s(%zu bytes, \"%s\", \"%s\")...\n", __func__, len, name, value);
667
668 struct hpack_decoder *dec = hpack_decode_init(4096);
669 assert(dec != NULL);
670
671 const uint8_t *buf = (const uint8_t *)str;
672 char *n, *v;
673
674 /* Check too short buffers */
675 for (size_t i = 1; i < len; i++)
676 {
677 const uint8_t *cutbuf = buf;
678 size_t cutlen = i;
679
680 assert(hpack_decode_hdr(dec, &cutbuf, &cutlen, &n, &v) == -1);
681 }
682
683 /* Check succesful decoding */
684 int ret = hpack_decode_hdr(dec, &buf, &len, &n, &v);
685 assert(ret == 0);
686 assert(!strcmp(name, n));
687 assert(!strcmp(value, v));
688 free(v);
689 free(n);
690
691 hpack_decode_destroy(dec);
692 }
693
test_headers(void)694 static void test_headers(void)
695 {
696 test_header("@\x0a""custom-key""\x0d""custom-header", 26,
697 "custom-key", "custom-header");
698 test_header("\x04\x0c""/sample/path", 14, ":path", "/sample/path");
699 test_header("\x10\x08""password""\x06""secret", 17, "password", "secret");
700 test_header("\x82", 1, ":method", "GET");
701 }
702
test_block(struct hpack_decoder * dec,const char * req,size_t len,...)703 static void test_block(struct hpack_decoder *dec, const char *req, size_t len,
704 ...)
705 {
706 printf("%s(%zu bytes)...\n", __func__, len);
707
708 va_list ap;
709
710 const uint8_t *buf = (const uint8_t *)req;
711 char *headers[16][2];
712 int count = hpack_decode(dec, buf, len, headers, 16);
713
714 printf(" %d headers:\n", count);
715 assert(count >= 0);
716
717 va_start(ap, len);
718 for (int i = 0; i < count; i++)
719 {
720 const char *name = va_arg(ap, const char *);
721 const char *value = va_arg(ap, const char *);
722
723 printf(" %s: %s\n", headers[i][0], headers[i][1]);
724 assert(!strcmp(name, headers[i][0]));
725 assert(!strcmp(value, headers[i][1]));
726 free(headers[i][1]);
727 free(headers[i][0]);
728 }
729 assert(va_arg(ap, const char *) == NULL);
730 }
731
test_reqs(void)732 static void test_reqs(void)
733 {
734 struct hpack_decoder *dec = hpack_decode_init(4096);
735 assert(dec != NULL);
736
737 test_block(dec, NULL, 0, NULL);
738 test_block(dec, "\x82\x86\x84\x41\x0f""www.example.com", 20,
739 ":method", "GET", ":scheme", "http", ":path", "/",
740 ":authority", "www.example.com", NULL);
741 test_block(dec, "\x82\x86\x84\xbe\x58\x08""no-cache", 14,
742 ":method", "GET", ":scheme", "http", ":path", "/",
743 ":authority", "www.example.com", "cache-control", "no-cache",
744 NULL);
745 test_block(dec,
746 "\x82\x87\x85\xbf\x40\x0a""custom-key""\x0c""custom-value", 29,
747 ":method", "GET", ":scheme", "https", ":path", "/index.html",
748 ":authority", "www.example.com", "custom-key", "custom-value",
749 NULL);
750
751 hpack_decode_destroy(dec);
752 }
753
test_reqs_huffman(void)754 static void test_reqs_huffman(void)
755 {
756 struct hpack_decoder *dec = hpack_decode_init(4096);
757 assert(dec != NULL);
758
759 test_block(dec, "\x82\x86\x84\x41\x8c\xf1\xe3\xc2\xe5\xf2\x3a\x6b\xa0\xab"
760 "\x90\xf4\xff", 17,
761 ":method", "GET", ":scheme", "http", ":path", "/",
762 ":authority", "www.example.com", NULL);
763 test_block(dec, "\x82\x86\x84\xbe\x58\x86\xa8\xeb\x10\x64\x9c\xbf", 12,
764 ":method", "GET", ":scheme", "http", ":path", "/",
765 ":authority", "www.example.com", "cache-control", "no-cache",
766 NULL);
767 test_block(dec, "\x82\x87\x85\xbf\x40\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f"
768 "\x89\x25\xa8\x49\xe9\x5b\xb8\xe8\xb4\xbf", 24,
769 ":method", "GET", ":scheme", "https", ":path", "/index.html",
770 ":authority", "www.example.com", "custom-key", "custom-value",
771 NULL);
772
773 hpack_decode_destroy(dec);
774 }
775
test_resps(void)776 static void test_resps(void)
777 {
778 struct hpack_decoder *dec = hpack_decode_init(256);
779 assert(dec != NULL);
780
781 test_block(dec, "\x48\x03""302""\x58\x07""private"
782 "\x61\x1d""Mon, 21 Oct 2013 20:13:21 GMT"
783 "\x6e\x17""https://www.example.com", 70,
784 ":status", "302", "cache-control", "private",
785 "date", "Mon, 21 Oct 2013 20:13:21 GMT",
786 "location", "https://www.example.com", NULL);
787 test_block(dec, "\x48\x03""307""\xc1\xc0\xbf", 8,
788 ":status", "307", "cache-control", "private",
789 "date", "Mon, 21 Oct 2013 20:13:21 GMT",
790 "location", "https://www.example.com", NULL);
791 test_block(dec, "\x88\xc1\x61\x1d""Mon, 21 Oct 2013 20:13:22 GMT"
792 "\xc0\x5a\x04""gzip""\x77\x38""foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU;"
793 " max-age=3600; version=1", 98,
794 ":status", "200", "cache-control", "private",
795 "date", "Mon, 21 Oct 2013 20:13:22 GMT",
796 "location", "https://www.example.com",
797 "content-encoding", "gzip",
798 "set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; "
799 "max-age=3600; version=1",
800 NULL);
801
802 hpack_decode_destroy(dec);
803 }
804
test_resps_huffman(void)805 static void test_resps_huffman(void)
806 {
807 struct hpack_decoder *dec = hpack_decode_init(256);
808 assert(dec != NULL);
809
810 test_block(dec, "\x48\x82\x64\x02\x58\x85\xae\xc3\x77\x1a\x4b\x61\x96\xd0"
811 "\x7a\xbe\x94\x10\x54\xd4\x44\xa8\x20\x05\x95\x04\x0b\x81\x66"
812 "\xe0\x82\xa6\x2d\x1b\xff\x6e\x91\x9d\x29\xad\x17\x18\x63\xc7"
813 "\x8f\x0b\x97\xc8\xe9\xae\x82\xae\x43\xd3", 54,
814 ":status", "302", "cache-control", "private",
815 "date", "Mon, 21 Oct 2013 20:13:21 GMT",
816 "location", "https://www.example.com", NULL);
817 test_block(dec, "\x48\x83\x64\x0e\xff\xc1\xc0\xbf", 8,
818 ":status", "307", "cache-control", "private",
819 "date", "Mon, 21 Oct 2013 20:13:21 GMT",
820 "location", "https://www.example.com", NULL);
821 test_block(dec, "\x88\xc1\x61\x96\xd0\x7a\xbe\x94\x10\x54\xd4\x44\xa8\x20"
822 "\x05\x95\x04\x0b\x81\x66\xe0\x84\xa6\x2d\x1b\xff\xc0\x5a\x83"
823 "\x9b\xd9\xab\x77\xad\x94\xe7\x82\x1d\xd7\xf2\xe6\xc7\xb3\x35"
824 "\xdf\xdf\xcd\x5b\x39\x60\xd5\xaf\x27\x08\x7f\x36\x72\xc1\xab"
825 "\x27\x0f\xb5\x29\x1f\x95\x87\x31\x60\x65\xc0\x03\xed\x4e\xe5"
826 "\xb1\x06\x3d\x50\x07", 79,
827 ":status", "200", "cache-control", "private",
828 "date", "Mon, 21 Oct 2013 20:13:22 GMT",
829 "location", "https://www.example.com",
830 "content-encoding", "gzip",
831 "set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; "
832 "max-age=3600; version=1",
833 NULL);
834
835 hpack_decode_destroy(dec);
836 }
837
838
main(void)839 int main(void)
840 {
841 test_integers();
842 test_headers();
843 test_reqs();
844 test_reqs_huffman();
845 test_resps();
846 test_resps_huffman();
847 }
848 #endif /* TEST */
849