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