143a63c18SDmitri Tikhonov/*
243a63c18SDmitri Tikhonov * Test QPACK.
343a63c18SDmitri Tikhonov */
443a63c18SDmitri Tikhonov
543a63c18SDmitri Tikhonov#include <assert.h>
6147b1758SDmitri Tikhonov#include <ctype.h>
743a63c18SDmitri Tikhonov#include <stdint.h>
843a63c18SDmitri Tikhonov#include <stdio.h>
943a63c18SDmitri Tikhonov#include <stdlib.h>
1043a63c18SDmitri Tikhonov#include <string.h>
1143a63c18SDmitri Tikhonov
1243a63c18SDmitri Tikhonov#include "lsqpack.h"
13b43d0c9bSDmitri Tikhonov#include "lsqpack-test.h"
1460620859SDmitri Tikhonov#include "lsxpack_header.h"
1543a63c18SDmitri Tikhonov
1643a63c18SDmitri Tikhonov#define ENC_BUF_SZ 200
1743a63c18SDmitri Tikhonov#define HEADER_BUF_SZ 200
1843a63c18SDmitri Tikhonov#define PREFIX_BUF_SZ 10
1943a63c18SDmitri Tikhonov
2043a63c18SDmitri Tikhonovstatic const struct qpack_header_block_test
2143a63c18SDmitri Tikhonov{
2243a63c18SDmitri Tikhonov    /* Identification: */
2343a63c18SDmitri Tikhonov    int             qhbt_lineno;
2443a63c18SDmitri Tikhonov
2543a63c18SDmitri Tikhonov    /* Input: */
266b87e695SDmitri Tikhonov    unsigned        qhbt_table_size;
276b87e695SDmitri Tikhonov    unsigned        qhbt_max_risked_streams;
2843a63c18SDmitri Tikhonov    unsigned        qhbt_n_headers;
2943a63c18SDmitri Tikhonov    struct {
3043a63c18SDmitri Tikhonov        const char *name, *value;
31051fed2dSDmitri Tikhonov        enum lsqpack_enc_flags flags;
3243a63c18SDmitri Tikhonov    }               qhbt_headers[10];
3343a63c18SDmitri Tikhonov
3443a63c18SDmitri Tikhonov    /* Output: */
3543a63c18SDmitri Tikhonov    size_t          qhbt_enc_sz;
3643a63c18SDmitri Tikhonov    unsigned char   qhbt_enc_buf[ENC_BUF_SZ];
3743a63c18SDmitri Tikhonov
3843a63c18SDmitri Tikhonov    size_t          qhbt_prefix_sz;
3943a63c18SDmitri Tikhonov    unsigned char   qhbt_prefix_buf[PREFIX_BUF_SZ];
4043a63c18SDmitri Tikhonov
4143a63c18SDmitri Tikhonov    size_t          qhbt_header_sz;
4243a63c18SDmitri Tikhonov    unsigned char   qhbt_header_buf[HEADER_BUF_SZ];
4343a63c18SDmitri Tikhonov} header_block_tests[] =
4443a63c18SDmitri Tikhonov{
45051fed2dSDmitri Tikhonov
4643a63c18SDmitri Tikhonov    {
4743a63c18SDmitri Tikhonov        .qhbt_lineno        = __LINE__,
486db915e7SDmitri Tikhonov        .qhbt_table_size    = 0x1000,
496db915e7SDmitri Tikhonov        .qhbt_max_risked_streams = 100,
5043a63c18SDmitri Tikhonov        .qhbt_n_headers     = 1,
5143a63c18SDmitri Tikhonov        .qhbt_headers       = {
52051fed2dSDmitri Tikhonov            { ":method", "GET", 0, },
5343a63c18SDmitri Tikhonov        },
5443a63c18SDmitri Tikhonov        .qhbt_enc_sz        = 0,
5543a63c18SDmitri Tikhonov        .qhbt_prefix_sz     = 2,
5643a63c18SDmitri Tikhonov        .qhbt_prefix_buf    = "\x00\x00",
5743a63c18SDmitri Tikhonov        .qhbt_header_sz     = 1,
5843a63c18SDmitri Tikhonov        .qhbt_header_buf    = {
59c0da112cSDmitri Tikhonov            0x80 | 0x40 | 17,
6043a63c18SDmitri Tikhonov        },
6143a63c18SDmitri Tikhonov    },
62051fed2dSDmitri Tikhonov
63051fed2dSDmitri Tikhonov    {
64051fed2dSDmitri Tikhonov        .qhbt_lineno        = __LINE__,
656db915e7SDmitri Tikhonov        .qhbt_table_size    = 0x1000,
666db915e7SDmitri Tikhonov        .qhbt_max_risked_streams = 100,
67051fed2dSDmitri Tikhonov        .qhbt_n_headers     = 1,
68051fed2dSDmitri Tikhonov        .qhbt_headers       = {
6977647c9cSDmitri Tikhonov            { ":method", "method", LQEF_NEVER_INDEX, },
70051fed2dSDmitri Tikhonov        },
71051fed2dSDmitri Tikhonov        .qhbt_enc_sz        = 0,
72051fed2dSDmitri Tikhonov        .qhbt_prefix_sz     = 2,
73051fed2dSDmitri Tikhonov        .qhbt_prefix_buf    = "\x00\x00",
74c0da112cSDmitri Tikhonov        .qhbt_header_sz     = 8,
75051fed2dSDmitri Tikhonov        .qhbt_header_buf    = {
76c0da112cSDmitri Tikhonov            0x40 | 0x20 | 0x10 | 0x0F, 0x00,
77051fed2dSDmitri Tikhonov            0x80 /* Huffman */ | 5 /* length */,
7895bacc9fSDmitri Tikhonov            0xa4, 0xa9, 0x9c, 0xf2, 0x7f,
79051fed2dSDmitri Tikhonov        },
80051fed2dSDmitri Tikhonov    },
81051fed2dSDmitri Tikhonov
826b87e695SDmitri Tikhonov    {
836b87e695SDmitri Tikhonov        .qhbt_lineno        = __LINE__,
846db915e7SDmitri Tikhonov        .qhbt_table_size    = 0x1000,
856b87e695SDmitri Tikhonov        .qhbt_max_risked_streams = 0,
866b87e695SDmitri Tikhonov        .qhbt_n_headers     = 1,
876b87e695SDmitri Tikhonov        .qhbt_headers       = {
886b87e695SDmitri Tikhonov            { ":method", "method", 0, },
896b87e695SDmitri Tikhonov        },
9095bacc9fSDmitri Tikhonov        .qhbt_enc_sz        = 7,
916b87e695SDmitri Tikhonov        .qhbt_enc_buf       = {
92c0da112cSDmitri Tikhonov            0x80 | 0x40 /* static */ | 15 /* name index */,
936b87e695SDmitri Tikhonov            0x80 /* Huffman */ | 5 /* length */,
9495bacc9fSDmitri Tikhonov            0xa4, 0xa9, 0x9c, 0xf2, 0x7f,
956b87e695SDmitri Tikhonov        },
966b87e695SDmitri Tikhonov        .qhbt_prefix_sz     = 2,
976b87e695SDmitri Tikhonov        .qhbt_prefix_buf    = "\x00\x00",
98c0da112cSDmitri Tikhonov        .qhbt_header_sz     = 8,
996b87e695SDmitri Tikhonov        .qhbt_header_buf    = {
100c0da112cSDmitri Tikhonov            0x40 | 0x10 /* Static */ | 15, 0x00,
1016b87e695SDmitri Tikhonov            0x80 /* Huffman */ | 5 /* length */,
10295bacc9fSDmitri Tikhonov            0xa4, 0xa9, 0x9c, 0xf2, 0x7f,
10395bacc9fSDmitri Tikhonov        },
10495bacc9fSDmitri Tikhonov    },
10595bacc9fSDmitri Tikhonov
10695bacc9fSDmitri Tikhonov    {
10795bacc9fSDmitri Tikhonov        .qhbt_lineno        = __LINE__,
1086db915e7SDmitri Tikhonov        .qhbt_table_size    = 0x1000,
1096db915e7SDmitri Tikhonov        .qhbt_max_risked_streams = 0x1000,
11095bacc9fSDmitri Tikhonov        .qhbt_n_headers     = 1,
11195bacc9fSDmitri Tikhonov        .qhbt_headers       = {
11295bacc9fSDmitri Tikhonov            { ":method", "method", 0, },
11395bacc9fSDmitri Tikhonov        },
11495bacc9fSDmitri Tikhonov        .qhbt_enc_sz        = 7,
11595bacc9fSDmitri Tikhonov        .qhbt_enc_buf       = {
116c0da112cSDmitri Tikhonov            0x80 | 0x40 /* static */ | 15 /* name index */,
11795bacc9fSDmitri Tikhonov            0x80 /* Huffman */ | 5 /* length */,
11895bacc9fSDmitri Tikhonov            0xa4, 0xa9, 0x9c, 0xf2, 0x7f,
11995bacc9fSDmitri Tikhonov        },
12095bacc9fSDmitri Tikhonov        .qhbt_prefix_sz     = 2,
121205a2804SDmitri Tikhonov        .qhbt_prefix_buf    = { 0x02, 0x80, },
12295bacc9fSDmitri Tikhonov        .qhbt_header_sz     = 1,
12395bacc9fSDmitri Tikhonov        .qhbt_header_buf    = {
124c9e9d2cdSDmitri Tikhonov            0x10 | 0 /* Relative dynamic ID */,
1256b87e695SDmitri Tikhonov        },
1266b87e695SDmitri Tikhonov    },
1276b87e695SDmitri Tikhonov
1286ac74e8cSDmitri Tikhonov    {
1296ac74e8cSDmitri Tikhonov        .qhbt_lineno        = __LINE__,
1306db915e7SDmitri Tikhonov        .qhbt_table_size    = 0x1000,
1316db915e7SDmitri Tikhonov        .qhbt_max_risked_streams = 0x1000,
1326ac74e8cSDmitri Tikhonov        .qhbt_n_headers     = 1,
1336ac74e8cSDmitri Tikhonov        .qhbt_headers       = {
13477647c9cSDmitri Tikhonov            { "dude", "where is my car?", LQEF_NEVER_INDEX, },
1356ac74e8cSDmitri Tikhonov        },
1366ac74e8cSDmitri Tikhonov        .qhbt_enc_sz        = 0,
1376ac74e8cSDmitri Tikhonov        .qhbt_prefix_sz     = 2,
1386ac74e8cSDmitri Tikhonov        .qhbt_prefix_buf    = "\x00\x00",
1396ac74e8cSDmitri Tikhonov        .qhbt_header_sz     = 17,
1406ac74e8cSDmitri Tikhonov        .qhbt_header_buf    = {
14146a42218SDmitri Tikhonov            0x20 | 0x10 /* No index */ | 0x08 | 3,
14246a42218SDmitri Tikhonov            0x92, 0xd9, 0x0b,
14346a42218SDmitri Tikhonov            0x80 | 0xC,
14446a42218SDmitri Tikhonov            0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa,
14546a42218SDmitri Tikhonov            0x50, 0x83, 0xb3, 0xfc,
14646a42218SDmitri Tikhonov        },
14746a42218SDmitri Tikhonov    },
14846a42218SDmitri Tikhonov
14946a42218SDmitri Tikhonov    {
15046a42218SDmitri Tikhonov        .qhbt_lineno        = __LINE__,
1516db915e7SDmitri Tikhonov        .qhbt_table_size    = 0x1000,
15246a42218SDmitri Tikhonov        .qhbt_max_risked_streams = 0,
1539413d779SDmitri Tikhonov        .qhbt_n_headers     = 3,
15446a42218SDmitri Tikhonov        .qhbt_headers       = {
15546a42218SDmitri Tikhonov            { "dude", "where is my car?", 0, },
15618555864SDmitri Tikhonov            { ":method", "GET", 0, },
1579413d779SDmitri Tikhonov            /* The "aaa..." string triggers header_out_grow_buf() */
1589413d779SDmitri Tikhonov            { "aaaaaaaaaaaaaaaaaaaaaaaaaa",
1599413d779SDmitri Tikhonov                "aaaaaaaaaaaaaaaaaaaaaaaaaa", 0, },
16046a42218SDmitri Tikhonov        },
1619413d779SDmitri Tikhonov        .qhbt_enc_sz        = 53,
16246a42218SDmitri Tikhonov        .qhbt_enc_buf       = {
16346a42218SDmitri Tikhonov            0x40 | 0x20 | 3,
16446a42218SDmitri Tikhonov            0x92, 0xd9, 0x0b,
16546a42218SDmitri Tikhonov            0x80 | 0xC,
16646a42218SDmitri Tikhonov            0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa,
16746a42218SDmitri Tikhonov            0x50, 0x83, 0xb3, 0xfc,
1689413d779SDmitri Tikhonov            0x40 /* Without name reference */ | 0x20 /* Huffman */ | 17 /* Length */,
1699413d779SDmitri Tikhonov            0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x31, 0x8c,
1709413d779SDmitri Tikhonov            0x63, 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xff,
1719413d779SDmitri Tikhonov            0x80 /* Huffman */ | 17 /* length */,
1729413d779SDmitri Tikhonov            0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x31, 0x8c,
1739413d779SDmitri Tikhonov            0x63, 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xff,
17446a42218SDmitri Tikhonov        },
17546a42218SDmitri Tikhonov        .qhbt_prefix_sz     = 2,
17646a42218SDmitri Tikhonov        .qhbt_prefix_buf    = "\x00\x00",
1779413d779SDmitri Tikhonov        .qhbt_header_sz     = 55,
17846a42218SDmitri Tikhonov        .qhbt_header_buf    = {
17946a42218SDmitri Tikhonov            0x20 | 0x08 | 3,
1806ac74e8cSDmitri Tikhonov            0x92, 0xd9, 0x0b,
1816ac74e8cSDmitri Tikhonov            0x80 | 0xC,
1826ac74e8cSDmitri Tikhonov            0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa,
1836ac74e8cSDmitri Tikhonov            0x50, 0x83, 0xb3, 0xfc,
18418555864SDmitri Tikhonov            0x80 | 0x40 | 17,
1859413d779SDmitri Tikhonov            0x20 /* Without name reference */ | 0x08 /* Huffman */ | 7 , 0x0A /* Length */,
1869413d779SDmitri Tikhonov            0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x31, 0x8c,
1879413d779SDmitri Tikhonov            0x63, 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xff,
1889413d779SDmitri Tikhonov            0x80 /* Huffman */ | 17 /* length */,
1899413d779SDmitri Tikhonov            0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x31, 0x8c,
1909413d779SDmitri Tikhonov            0x63, 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xff,
1916ac74e8cSDmitri Tikhonov        },
1926ac74e8cSDmitri Tikhonov    },
1936ac74e8cSDmitri Tikhonov
1948e76c09eSDmitri Tikhonov    {
1958e76c09eSDmitri Tikhonov        .qhbt_lineno        = __LINE__,
1966db915e7SDmitri Tikhonov        .qhbt_table_size    = 0x1000,
1978e76c09eSDmitri Tikhonov        .qhbt_max_risked_streams = 1,
1988e76c09eSDmitri Tikhonov        .qhbt_n_headers     = 1,
1998e76c09eSDmitri Tikhonov        .qhbt_headers       = {
2008e76c09eSDmitri Tikhonov            { "dude", "where is my car?", 0, },
2018e76c09eSDmitri Tikhonov        },
2028e76c09eSDmitri Tikhonov        .qhbt_enc_sz        = 17,
2038e76c09eSDmitri Tikhonov        .qhbt_enc_buf       = {
2048e76c09eSDmitri Tikhonov            0x40 | 0x20 | 3,
2058e76c09eSDmitri Tikhonov            0x92, 0xd9, 0x0b,
2068e76c09eSDmitri Tikhonov            0x80 | 0xC,
2078e76c09eSDmitri Tikhonov            0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa,
2088e76c09eSDmitri Tikhonov            0x50, 0x83, 0xb3, 0xfc,
2098e76c09eSDmitri Tikhonov        },
2108e76c09eSDmitri Tikhonov        .qhbt_prefix_sz     = 2,
211205a2804SDmitri Tikhonov        .qhbt_prefix_buf    = { 0x02, 0x80, },
2128e76c09eSDmitri Tikhonov        .qhbt_header_sz     = 1,
2138e76c09eSDmitri Tikhonov        .qhbt_header_buf    = {
214c9e9d2cdSDmitri Tikhonov            0x10 | 0 /* Relative dynamic ID */,
2158e76c09eSDmitri Tikhonov        },
2168e76c09eSDmitri Tikhonov    },
2178e76c09eSDmitri Tikhonov
21843a63c18SDmitri Tikhonov};
21943a63c18SDmitri Tikhonov
22043a63c18SDmitri Tikhonov
2219e982dfdSDmitri Tikhonovstruct header_buf
2229e982dfdSDmitri Tikhonov{
2239e982dfdSDmitri Tikhonov    unsigned    off;
2249e982dfdSDmitri Tikhonov    char        buf[UINT16_MAX];
2259e982dfdSDmitri Tikhonov};
2269e982dfdSDmitri Tikhonov
2279e982dfdSDmitri Tikhonov
2289e982dfdSDmitri Tikhonovint
2299e982dfdSDmitri Tikhonovheader_set_ptr (struct lsxpack_header *hdr, struct header_buf *header_buf,
2309e982dfdSDmitri Tikhonov                const char *name, size_t name_len,
2319e982dfdSDmitri Tikhonov                const char *val, size_t val_len)
2329e982dfdSDmitri Tikhonov{
2339e982dfdSDmitri Tikhonov    if (header_buf->off + name_len + val_len <= sizeof(header_buf->buf))
2349e982dfdSDmitri Tikhonov    {
2359e982dfdSDmitri Tikhonov        memcpy(header_buf->buf + header_buf->off, name, name_len);
2369e982dfdSDmitri Tikhonov        memcpy(header_buf->buf + header_buf->off + name_len, val, val_len);
2379e982dfdSDmitri Tikhonov        lsxpack_header_set_offset2(hdr, header_buf->buf + header_buf->off,
2389e982dfdSDmitri Tikhonov                                            0, name_len, name_len, val_len);
2399e982dfdSDmitri Tikhonov        header_buf->off += name_len + val_len;
2409e982dfdSDmitri Tikhonov        return 0;
2419e982dfdSDmitri Tikhonov    }
2429e982dfdSDmitri Tikhonov    else
2439e982dfdSDmitri Tikhonov        return -1;
2449e982dfdSDmitri Tikhonov}
2459e982dfdSDmitri Tikhonov
24643a63c18SDmitri Tikhonovstatic void
24743a63c18SDmitri Tikhonovrun_header_test (const struct qpack_header_block_test *test)
24843a63c18SDmitri Tikhonov{
24943a63c18SDmitri Tikhonov    unsigned char header_buf[HEADER_BUF_SZ], enc_buf[ENC_BUF_SZ],
25043a63c18SDmitri Tikhonov        prefix_buf[PREFIX_BUF_SZ];
25195bacc9fSDmitri Tikhonov    unsigned header_off, enc_off;
252b43d0c9bSDmitri Tikhonov    size_t header_sz, enc_sz, dec_sz;
25343a63c18SDmitri Tikhonov    struct lsqpack_enc enc;
25443a63c18SDmitri Tikhonov    unsigned i;
25543a63c18SDmitri Tikhonov    size_t nw;
25643a63c18SDmitri Tikhonov    int s;
25743a63c18SDmitri Tikhonov    enum lsqpack_enc_status enc_st;
25825170ed8SStephen Petrides    float ratio;
259a122a7bdSDmitri Tikhonov    unsigned char dec_buf[LSQPACK_LONGEST_SDTC];
26060620859SDmitri Tikhonov    struct lsxpack_header xhdr;
2619e982dfdSDmitri Tikhonov    struct header_buf hbuf;
26243a63c18SDmitri Tikhonov
263b43d0c9bSDmitri Tikhonov    dec_sz = sizeof(dec_buf);
2646686ad13SDmitri Tikhonov    s = lsqpack_enc_init(&enc, stderr, test->qhbt_table_size,
2656686ad13SDmitri Tikhonov                test->qhbt_table_size, test->qhbt_max_risked_streams,
266b43d0c9bSDmitri Tikhonov                LSQPACK_ENC_OPT_IX_AGGR, dec_buf, &dec_sz);
26743a63c18SDmitri Tikhonov    assert(s == 0);
26843a63c18SDmitri Tikhonov
26943a63c18SDmitri Tikhonov    s = lsqpack_enc_start_header(&enc, 0, 0);
27043a63c18SDmitri Tikhonov    assert(s == 0);
27143a63c18SDmitri Tikhonov
27243a63c18SDmitri Tikhonov    header_off = 0, enc_off = 0;
27343a63c18SDmitri Tikhonov    for (i = 0; i < test->qhbt_n_headers; ++i)
27443a63c18SDmitri Tikhonov    {
27588967572SDmitri Tikhonov        /* Increase buffers one by one to exercise error conditions */
27688967572SDmitri Tikhonov        enc_sz = 0;
27788967572SDmitri Tikhonov        header_sz = 0;
27888967572SDmitri Tikhonov        while (1)
27988967572SDmitri Tikhonov        {
2809e982dfdSDmitri Tikhonov            hbuf.off = 0;
2819e982dfdSDmitri Tikhonov            s = header_set_ptr(&xhdr, &hbuf,
28288967572SDmitri Tikhonov                    test->qhbt_headers[i].name,
28388967572SDmitri Tikhonov                    strlen(test->qhbt_headers[i].name),
28488967572SDmitri Tikhonov                    test->qhbt_headers[i].value,
28560620859SDmitri Tikhonov                    strlen(test->qhbt_headers[i].value));
2869e982dfdSDmitri Tikhonov            assert(s == 0);
28760620859SDmitri Tikhonov            enc_st = lsqpack_enc_encode(&enc,
28860620859SDmitri Tikhonov                    enc_buf + enc_off, &enc_sz,
28960620859SDmitri Tikhonov                    header_buf + header_off, &header_sz,
29060620859SDmitri Tikhonov                    &xhdr,
29188967572SDmitri Tikhonov                    test->qhbt_headers[i].flags);
29288967572SDmitri Tikhonov            switch (enc_st)
29388967572SDmitri Tikhonov            {
29488967572SDmitri Tikhonov            case LQES_NOBUF_ENC:
29588967572SDmitri Tikhonov                if (enc_sz < sizeof(enc_buf) - enc_off)
29688967572SDmitri Tikhonov                    ++enc_sz;
29788967572SDmitri Tikhonov                else
29888967572SDmitri Tikhonov                    assert(0);
29988967572SDmitri Tikhonov                break;
30088967572SDmitri Tikhonov            case LQES_NOBUF_HEAD:
30188967572SDmitri Tikhonov                if (header_sz < sizeof(header_buf) - header_off)
30288967572SDmitri Tikhonov                    ++header_sz;
30388967572SDmitri Tikhonov                else
30488967572SDmitri Tikhonov                    assert(0);
30588967572SDmitri Tikhonov                break;
30688967572SDmitri Tikhonov            default:
30788967572SDmitri Tikhonov                assert(enc_st == LQES_OK);
30888967572SDmitri Tikhonov                goto end_encode_one_header;
30988967572SDmitri Tikhonov            }
31088967572SDmitri Tikhonov        }
31188967572SDmitri Tikhonov  end_encode_one_header:
31243a63c18SDmitri Tikhonov        enc_off += enc_sz;
31343a63c18SDmitri Tikhonov        header_off += header_sz;
31443a63c18SDmitri Tikhonov    }
31543a63c18SDmitri Tikhonov
3163ce33568SDmitri Tikhonov    nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), NULL);
31743a63c18SDmitri Tikhonov    assert(nw == test->qhbt_prefix_sz);
31843a63c18SDmitri Tikhonov    assert(0 == memcmp(test->qhbt_prefix_buf, prefix_buf, nw));
31995bacc9fSDmitri Tikhonov    assert(enc_off == test->qhbt_enc_sz);
32095bacc9fSDmitri Tikhonov    assert(0 == memcmp(test->qhbt_enc_buf, enc_buf, enc_off));
32195bacc9fSDmitri Tikhonov    assert(header_off == test->qhbt_header_sz);
32295bacc9fSDmitri Tikhonov    assert(0 == memcmp(test->qhbt_header_buf, header_buf, header_off));
32325170ed8SStephen Petrides    assert(lsqpack_enc_ratio(&enc) > 0.0);
32443a63c18SDmitri Tikhonov
32543a63c18SDmitri Tikhonov    lsqpack_enc_cleanup(&enc);
32643a63c18SDmitri Tikhonov}
32743a63c18SDmitri Tikhonov
32818555864SDmitri Tikhonov
32918555864SDmitri Tikhonovstruct dhte /* decoded header test ext */
33018555864SDmitri Tikhonov{
33118555864SDmitri Tikhonov    struct lsxpack_header       xhdr;
33218555864SDmitri Tikhonov    size_t                      buf_off;
33318555864SDmitri Tikhonov    char                        buf[0x1000];
33418555864SDmitri Tikhonov};
33518555864SDmitri Tikhonov
33618555864SDmitri Tikhonov
33718555864SDmitri Tikhonovstatic void
33818555864SDmitri Tikhonovdht_unblocked (void *hblock_ctx_p)
33918555864SDmitri Tikhonov{
34018555864SDmitri Tikhonov    assert(0);  /* Not expecting this to be called */
34118555864SDmitri Tikhonov}
34218555864SDmitri Tikhonov
34318555864SDmitri Tikhonov
34418555864SDmitri Tikhonovstatic struct lsxpack_header *
34518555864SDmitri Tikhonovdht_prepare_decode (void *hblock_ctx_p, struct lsxpack_header *xhdr, size_t space)
34618555864SDmitri Tikhonov{
34718555864SDmitri Tikhonov    struct dhte *const dhte = hblock_ctx_p;
34818555864SDmitri Tikhonov    size_t avail;
34918555864SDmitri Tikhonov
35018555864SDmitri Tikhonov    if (space > LSXPACK_MAX_STRLEN)
35118555864SDmitri Tikhonov        return NULL;
35218555864SDmitri Tikhonov
35318555864SDmitri Tikhonov    if (xhdr)
35418555864SDmitri Tikhonov    {
35518555864SDmitri Tikhonov        assert(xhdr == &dhte->xhdr);
35618555864SDmitri Tikhonov        assert(xhdr->val_len < space);
35718555864SDmitri Tikhonov        avail = sizeof(dhte->buf) - xhdr->name_offset - 1 /* NUL */;
35818555864SDmitri Tikhonov        if (avail < space)
35918555864SDmitri Tikhonov            return NULL;
36018555864SDmitri Tikhonov        xhdr->val_len = space;
36118555864SDmitri Tikhonov    }
36218555864SDmitri Tikhonov    else
36318555864SDmitri Tikhonov    {
36418555864SDmitri Tikhonov        avail = sizeof(dhte->buf) - dhte->buf_off - 1 /* NUL */;
36518555864SDmitri Tikhonov        if (avail < space)
36618555864SDmitri Tikhonov            return NULL;
36718555864SDmitri Tikhonov        lsxpack_header_prepare_decode(&dhte->xhdr, dhte->buf, dhte->buf_off,
36818555864SDmitri Tikhonov                                                                        space);
36918555864SDmitri Tikhonov    }
37018555864SDmitri Tikhonov
37118555864SDmitri Tikhonov    return &dhte->xhdr;
37218555864SDmitri Tikhonov}
37318555864SDmitri Tikhonov
37418555864SDmitri Tikhonov
37518555864SDmitri Tikhonovstatic int
37618555864SDmitri Tikhonovdht_process_header (void *hblock_ctx_p, struct lsxpack_header *xhdr)
37718555864SDmitri Tikhonov{
37818555864SDmitri Tikhonov    struct dhte *const dhte = hblock_ctx_p;
37918555864SDmitri Tikhonov
38018555864SDmitri Tikhonov    assert(xhdr == &dhte->xhdr);
38118555864SDmitri Tikhonov    dhte->buf_off += lsxpack_header_get_dec_size(xhdr);
38218555864SDmitri Tikhonov
38318555864SDmitri Tikhonov    return 0;
38418555864SDmitri Tikhonov}
38518555864SDmitri Tikhonov
38618555864SDmitri Tikhonov
38718555864SDmitri Tikhonovstatic void
38818555864SDmitri Tikhonovrun_decoded_headers_test_ext (const struct qpack_header_block_test *test,
38918555864SDmitri Tikhonov                const enum lsqpack_dec_opts opts, const size_t name_offset)
39018555864SDmitri Tikhonov{
39118555864SDmitri Tikhonov    struct lsqpack_dec dec;
39218555864SDmitri Tikhonov    char exp_hbuf[0x1000];  /* Large enough to hold all headers */
39318555864SDmitri Tikhonov    struct dhte dhte;
39418555864SDmitri Tikhonov    size_t sz;
39518555864SDmitri Tikhonov    unsigned i;
39618555864SDmitri Tikhonov    int s;
39718555864SDmitri Tikhonov    enum lsqpack_read_header_status rhs;
39818555864SDmitri Tikhonov    const unsigned char *buf;
39918555864SDmitri Tikhonov    unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK];
40018555864SDmitri Tikhonov    size_t dec_sz;
40118555864SDmitri Tikhonov    const struct lsqpack_dec_hset_if dht_if = {
40218555864SDmitri Tikhonov        .dhi_unblocked      = dht_unblocked,
40318555864SDmitri Tikhonov        .dhi_prepare_decode = dht_prepare_decode,
40418555864SDmitri Tikhonov        .dhi_process_header = dht_process_header,
40518555864SDmitri Tikhonov    };
40618555864SDmitri Tikhonov
40718555864SDmitri Tikhonov    /* Construct expected headers buffer: */
40818555864SDmitri Tikhonov    sz = 0;
40918555864SDmitri Tikhonov    exp_hbuf[0] = '\0';
41018555864SDmitri Tikhonov    for (i = 0; i < test->qhbt_n_headers; ++i)
41118555864SDmitri Tikhonov    {
41218555864SDmitri Tikhonov        strcpy(exp_hbuf + sz, test->qhbt_headers[i].name);
41318555864SDmitri Tikhonov        sz += strlen(test->qhbt_headers[i].name);
41418555864SDmitri Tikhonov        if (opts & LSQPACK_DEC_OPT_HTTP1X)
41518555864SDmitri Tikhonov        {
41618555864SDmitri Tikhonov            strcpy(exp_hbuf + sz, ": ");
41718555864SDmitri Tikhonov            sz += 2;
41818555864SDmitri Tikhonov        }
41918555864SDmitri Tikhonov        strcpy(exp_hbuf + sz, test->qhbt_headers[i].value);
42018555864SDmitri Tikhonov        sz += strlen(test->qhbt_headers[i].value);
42118555864SDmitri Tikhonov        if (opts & LSQPACK_DEC_OPT_HTTP1X)
42218555864SDmitri Tikhonov        {
42318555864SDmitri Tikhonov            strcpy(exp_hbuf + sz, "\r\n");
42418555864SDmitri Tikhonov            sz += 2;
42518555864SDmitri Tikhonov        }
42618555864SDmitri Tikhonov    }
42718555864SDmitri Tikhonov    assert(sz < sizeof(exp_hbuf));  /* Self-check */
42818555864SDmitri Tikhonov
42918555864SDmitri Tikhonov    /* Decode headers into dhte buffer */
43018555864SDmitri Tikhonov    dhte.buf_off = name_offset;
43118555864SDmitri Tikhonov    lsqpack_dec_init(&dec, NULL, test->qhbt_table_size,
43218555864SDmitri Tikhonov                                test->qhbt_max_risked_streams, &dht_if, opts);
43318555864SDmitri Tikhonov    if (test->qhbt_enc_sz)
43418555864SDmitri Tikhonov    {
43518555864SDmitri Tikhonov        s = lsqpack_dec_enc_in(&dec, test->qhbt_enc_buf, test->qhbt_enc_sz);
43618555864SDmitri Tikhonov        assert(s == 0);
43718555864SDmitri Tikhonov    }
43818555864SDmitri Tikhonov    assert(test->qhbt_header_sz);   /* Self-check */
43918555864SDmitri Tikhonov    buf = test->qhbt_prefix_buf;
44018555864SDmitri Tikhonov    dec_sz = sizeof(dec_buf);
44118555864SDmitri Tikhonov    rhs = lsqpack_dec_header_in(&dec, &dhte, 0,
44218555864SDmitri Tikhonov                test->qhbt_prefix_sz + test->qhbt_header_sz,
44318555864SDmitri Tikhonov                &buf, test->qhbt_prefix_sz,
44418555864SDmitri Tikhonov                dec_buf, &dec_sz);
44518555864SDmitri Tikhonov    assert(rhs == LQRHS_NEED);
44618555864SDmitri Tikhonov    assert(buf == test->qhbt_prefix_buf + test->qhbt_prefix_sz);
44718555864SDmitri Tikhonov    buf = test->qhbt_header_buf;
44818555864SDmitri Tikhonov    dec_sz = sizeof(dec_buf);
44918555864SDmitri Tikhonov    rhs = lsqpack_dec_header_read(&dec, &dhte,
45018555864SDmitri Tikhonov                &buf, test->qhbt_header_sz,
45118555864SDmitri Tikhonov                dec_buf, &dec_sz);
45218555864SDmitri Tikhonov    assert(rhs == LQRHS_DONE);
45318555864SDmitri Tikhonov    assert(buf == test->qhbt_header_buf + test->qhbt_header_sz);
45418555864SDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
45518555864SDmitri Tikhonov
45618555864SDmitri Tikhonov    /* Now compare the buffers */
45718555864SDmitri Tikhonov    dhte.buf[dhte.buf_off] = '\0';
45818555864SDmitri Tikhonov    s = strcmp(dhte.buf + name_offset, exp_hbuf);
45918555864SDmitri Tikhonov    assert(s == 0);
46018555864SDmitri Tikhonov}
46118555864SDmitri Tikhonov
46218555864SDmitri Tikhonov
46318555864SDmitri Tikhonovstatic void
46418555864SDmitri Tikhonovrun_decoded_headers_test (const struct qpack_header_block_test *test)
46518555864SDmitri Tikhonov{
46618555864SDmitri Tikhonov    const enum lsqpack_dec_opts opts[] = { 0, LSQPACK_DEC_OPT_HTTP1X, };
46718555864SDmitri Tikhonov    const size_t offs[] = { 0, 1, 20, };
46818555864SDmitri Tikhonov    unsigned i, j;
46918555864SDmitri Tikhonov
47018555864SDmitri Tikhonov    for (i = 0; i < sizeof(opts) / sizeof(opts[0]); ++i)
47118555864SDmitri Tikhonov        for (j = 0; j < sizeof(offs) / sizeof(offs[0]); ++j)
47218555864SDmitri Tikhonov            run_decoded_headers_test_ext(test, opts[i], offs[j]);
47318555864SDmitri Tikhonov}
47418555864SDmitri Tikhonov
47518555864SDmitri Tikhonov
476d4822b2bSDaan De Meyerstatic void
477d4822b2bSDaan De Meyerrun_header_cancellation_test(const struct qpack_header_block_test *test) {
478d4822b2bSDaan De Meyer    unsigned char header_buf[HEADER_BUF_SZ];
479d4822b2bSDaan De Meyer    size_t header_sz, enc_sz;
480d4822b2bSDaan De Meyer    struct lsqpack_enc enc;
481d4822b2bSDaan De Meyer    int s;
482d4822b2bSDaan De Meyer    enum lsqpack_enc_status enc_st;
48360620859SDmitri Tikhonov    struct lsxpack_header xhdr;
4849e982dfdSDmitri Tikhonov    struct header_buf hbuf;
485d4822b2bSDaan De Meyer
486d4822b2bSDaan De Meyer    s = lsqpack_enc_init(&enc, stderr, 0, 0, test->qhbt_max_risked_streams,
487d4822b2bSDaan De Meyer                         LSQPACK_ENC_OPT_IX_AGGR, NULL, NULL);
488d4822b2bSDaan De Meyer    assert(s == 0);
489d4822b2bSDaan De Meyer
490d4822b2bSDaan De Meyer    s = lsqpack_enc_start_header(&enc, 0, 0);
491d4822b2bSDaan De Meyer    assert(s == 0);
492d4822b2bSDaan De Meyer
493d4822b2bSDaan De Meyer    header_sz = HEADER_BUF_SZ;
494d4822b2bSDaan De Meyer    enc_sz = 0;
495d4822b2bSDaan De Meyer
4969e982dfdSDmitri Tikhonov    hbuf.off = 0;
4979e982dfdSDmitri Tikhonov    header_set_ptr(&xhdr, &hbuf,
49860620859SDmitri Tikhonov            test->qhbt_headers[0].name,
49960620859SDmitri Tikhonov            strlen(test->qhbt_headers[0].name),
50060620859SDmitri Tikhonov            test->qhbt_headers[0].value,
50160620859SDmitri Tikhonov            strlen(test->qhbt_headers[0].value));
502d4822b2bSDaan De Meyer    enc_st = lsqpack_enc_encode(&enc,
503d4822b2bSDaan De Meyer                    NULL, &enc_sz,
504d4822b2bSDaan De Meyer                    header_buf, &header_sz,
50560620859SDmitri Tikhonov                    &xhdr,
506d4822b2bSDaan De Meyer                    0);
507d4822b2bSDaan De Meyer    assert(enc_st == LQES_OK);
508d4822b2bSDaan De Meyer
509d4822b2bSDaan De Meyer    s = lsqpack_enc_cancel_header(&enc);
510d4822b2bSDaan De Meyer    assert(s == 0);
511d4822b2bSDaan De Meyer
512d4822b2bSDaan De Meyer    /* Check that we can start again after cancelling. */
513d4822b2bSDaan De Meyer    s = lsqpack_enc_start_header(&enc, 0, 0);
514d4822b2bSDaan De Meyer    assert(s == 0);
515d4822b2bSDaan De Meyer
516d4822b2bSDaan De Meyer    lsqpack_enc_cleanup(&enc);
517d4822b2bSDaan De Meyer}
518d4822b2bSDaan De Meyer
51943a63c18SDmitri Tikhonov
520b43d0c9bSDmitri Tikhonovstatic void
521b43d0c9bSDmitri Tikhonovtest_enc_init (void)
522b43d0c9bSDmitri Tikhonov{
523b43d0c9bSDmitri Tikhonov    struct lsqpack_enc enc;
524b43d0c9bSDmitri Tikhonov    size_t dec_sz;
525b43d0c9bSDmitri Tikhonov    int s;
526b43d0c9bSDmitri Tikhonov    unsigned i;
527b43d0c9bSDmitri Tikhonov    const unsigned char *p;
528b43d0c9bSDmitri Tikhonov    uint64_t val;
529b43d0c9bSDmitri Tikhonov    struct lsqpack_dec_int_state state;
530a122a7bdSDmitri Tikhonov    unsigned char dec_buf[LSQPACK_LONGEST_SDTC];
531b43d0c9bSDmitri Tikhonov
532b43d0c9bSDmitri Tikhonov    const struct {
533b43d0c9bSDmitri Tikhonov        unsigned    peer_max_size;  /* Value provided by peer */
534b43d0c9bSDmitri Tikhonov        unsigned    our_max_size;   /* Value to use */
535b43d0c9bSDmitri Tikhonov        int         expected_tsu;   /* Expecting TSU instruction? */
536b43d0c9bSDmitri Tikhonov    } tests[] = {
537b43d0c9bSDmitri Tikhonov        {   0x1000,     0x1000,     1,  },
538b43d0c9bSDmitri Tikhonov        {   0x1000,     1,          1,  },
539b43d0c9bSDmitri Tikhonov        {    0x100,     0x100,      1,  },
540b43d0c9bSDmitri Tikhonov        {   0x1000,     0,          0,  },
541b43d0c9bSDmitri Tikhonov    };
542b43d0c9bSDmitri Tikhonov
543b43d0c9bSDmitri Tikhonov    for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i)
544b43d0c9bSDmitri Tikhonov    {
545b43d0c9bSDmitri Tikhonov        dec_sz = sizeof(dec_buf);
546b43d0c9bSDmitri Tikhonov        s = lsqpack_enc_init(&enc, stderr, tests[i].peer_max_size,
547b43d0c9bSDmitri Tikhonov                        tests[i].our_max_size, 0, 0, dec_buf, &dec_sz);
548b43d0c9bSDmitri Tikhonov        assert(s == 0);
549b43d0c9bSDmitri Tikhonov        if (tests[i].expected_tsu)
550b43d0c9bSDmitri Tikhonov        {
551b43d0c9bSDmitri Tikhonov            assert(dec_sz > 0);
552b43d0c9bSDmitri Tikhonov            assert((dec_buf[0] & 0xE0) == 0x20);
553b43d0c9bSDmitri Tikhonov            p = dec_buf;
554d3cc03d7SDmitri Tikhonov            state.resume = 0;
555b43d0c9bSDmitri Tikhonov            s = lsqpack_dec_int(&p, p + dec_sz, 5, &val, &state);
556b43d0c9bSDmitri Tikhonov            assert(s == 0);
557b43d0c9bSDmitri Tikhonov            assert(val == tests[i].our_max_size);
558b43d0c9bSDmitri Tikhonov        }
559b43d0c9bSDmitri Tikhonov        else
560b43d0c9bSDmitri Tikhonov            assert(dec_sz == 0);
561b43d0c9bSDmitri Tikhonov        lsqpack_enc_cleanup(&enc);
562b43d0c9bSDmitri Tikhonov    }
563b43d0c9bSDmitri Tikhonov}
564b43d0c9bSDmitri Tikhonov
565b43d0c9bSDmitri Tikhonov
56602c4e282SDmitri Tikhonov/* Test that push promise header does not use the dynamic table, nor does
56702c4e282SDmitri Tikhonov * it update history.
56802c4e282SDmitri Tikhonov */
56902c4e282SDmitri Tikhonovstatic void
57002c4e282SDmitri Tikhonovtest_push_promise (void)
57102c4e282SDmitri Tikhonov{
57202c4e282SDmitri Tikhonov    struct lsqpack_enc enc;
57302c4e282SDmitri Tikhonov    ssize_t nw;
57402c4e282SDmitri Tikhonov    enum lsqpack_enc_status enc_st;
57502c4e282SDmitri Tikhonov    int s;
57602c4e282SDmitri Tikhonov    unsigned i;
57702c4e282SDmitri Tikhonov    const unsigned char *p;
57802c4e282SDmitri Tikhonov    uint64_t val;
57902c4e282SDmitri Tikhonov    struct lsqpack_dec_int_state state;
580a122a7bdSDmitri Tikhonov    unsigned char dec_buf[LSQPACK_LONGEST_SDTC];
58102c4e282SDmitri Tikhonov    unsigned char header_buf[HEADER_BUF_SZ], enc_buf[ENC_BUF_SZ],
58202c4e282SDmitri Tikhonov        prefix_buf[PREFIX_BUF_SZ];
58302c4e282SDmitri Tikhonov    size_t header_sz, enc_sz, dec_sz;
5843ce33568SDmitri Tikhonov    enum lsqpack_enc_header_flags hflags;
58560620859SDmitri Tikhonov    struct lsxpack_header xhdr;
5869e982dfdSDmitri Tikhonov    struct header_buf hbuf;
58702c4e282SDmitri Tikhonov
588c8a0661fSDmitri Tikhonov    dec_sz = sizeof(dec_buf);
58902c4e282SDmitri Tikhonov    s = lsqpack_enc_init(&enc, stderr, 0x1000, 0x1000, 100, 0, dec_buf, &dec_sz);
59002c4e282SDmitri Tikhonov    assert(0 == s);
59102c4e282SDmitri Tikhonov
59202c4e282SDmitri Tikhonov    (void) dec_sz;  /* We don't care for this test */
59302c4e282SDmitri Tikhonov
59402c4e282SDmitri Tikhonov    s = lsqpack_enc_start_header(&enc, 0, 0);
59502c4e282SDmitri Tikhonov    assert(0 == s);
59602c4e282SDmitri Tikhonov    enc_sz = sizeof(enc_buf);
59702c4e282SDmitri Tikhonov    header_sz = sizeof(header_buf);
5989e982dfdSDmitri Tikhonov    hbuf.off = 0;
5999e982dfdSDmitri Tikhonov    header_set_ptr(&xhdr, &hbuf, ":method", 7, "dude!", 5);
60002c4e282SDmitri Tikhonov    enc_st = lsqpack_enc_encode(&enc,
60102c4e282SDmitri Tikhonov            enc_buf, &enc_sz, header_buf, &header_sz,
60260620859SDmitri Tikhonov            &xhdr, 0);
60302c4e282SDmitri Tikhonov    assert(LQES_OK == enc_st);
60402c4e282SDmitri Tikhonov    enc_sz = sizeof(enc_buf);
60502c4e282SDmitri Tikhonov    header_sz = sizeof(header_buf);
6069e982dfdSDmitri Tikhonov    header_set_ptr(&xhdr, &hbuf, ":method", 7, "dude!", 5);
60702c4e282SDmitri Tikhonov    enc_st = lsqpack_enc_encode(&enc,
60802c4e282SDmitri Tikhonov            enc_buf, &enc_sz, header_buf, &header_sz,
60960620859SDmitri Tikhonov            &xhdr, 0);
61002c4e282SDmitri Tikhonov    assert(LQES_OK == enc_st);
6113ce33568SDmitri Tikhonov    nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), &hflags);
61202c4e282SDmitri Tikhonov    assert(2 == nw);
61302c4e282SDmitri Tikhonov    assert(!(prefix_buf[0] == 0 && prefix_buf[1] == 0)); /* Dynamic table used */
6143ce33568SDmitri Tikhonov    assert(hflags & LSQECH_REF_NEW_ENTRIES);
6153ce33568SDmitri Tikhonov    assert(hflags & LSQECH_REF_AT_RISK);
61602c4e282SDmitri Tikhonov
61702c4e282SDmitri Tikhonov    s = lsqpack_enc_start_header(&enc, 0, 0);
61802c4e282SDmitri Tikhonov    assert(0 == s);
61902c4e282SDmitri Tikhonov    enc_sz = sizeof(enc_buf);
62002c4e282SDmitri Tikhonov    header_sz = sizeof(header_buf);
6219e982dfdSDmitri Tikhonov    header_set_ptr(&xhdr, &hbuf, ":method", 7, "dude!", 5);
62202c4e282SDmitri Tikhonov    enc_st = lsqpack_enc_encode(&enc,
62302c4e282SDmitri Tikhonov            enc_buf, &enc_sz, header_buf, &header_sz,
62460620859SDmitri Tikhonov            &xhdr, LQEF_NO_HIST_UPD|LQEF_NO_DYN);
62502c4e282SDmitri Tikhonov    assert(LQES_OK == enc_st);
62602c4e282SDmitri Tikhonov    enc_sz = sizeof(enc_buf);
62702c4e282SDmitri Tikhonov    header_sz = sizeof(header_buf);
6289e982dfdSDmitri Tikhonov    header_set_ptr(&xhdr, &hbuf, ":method", 7, "where is my car?", 16);
62902c4e282SDmitri Tikhonov    enc_st = lsqpack_enc_encode(&enc,
63002c4e282SDmitri Tikhonov            enc_buf, &enc_sz, header_buf, &header_sz,
63160620859SDmitri Tikhonov            &xhdr, LQEF_NO_HIST_UPD|LQEF_NO_DYN);
6323ce33568SDmitri Tikhonov    nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), &hflags);
63302c4e282SDmitri Tikhonov    assert(2 == nw);
63402c4e282SDmitri Tikhonov    assert(prefix_buf[0] == 0 && prefix_buf[1] == 0); /* Dynamic table not used */
6353ce33568SDmitri Tikhonov    assert(!(hflags & LSQECH_REF_NEW_ENTRIES));
63602c4e282SDmitri Tikhonov
63702c4e282SDmitri Tikhonov    /* Last check that history was not updated: */
63802c4e282SDmitri Tikhonov    s = lsqpack_enc_start_header(&enc, 4, 0);
63902c4e282SDmitri Tikhonov    assert(0 == s);
64002c4e282SDmitri Tikhonov    enc_sz = sizeof(enc_buf);
64102c4e282SDmitri Tikhonov    header_sz = sizeof(header_buf);
6429e982dfdSDmitri Tikhonov    header_set_ptr(&xhdr, &hbuf, ":method", 7, "where is my car?", 16);
64302c4e282SDmitri Tikhonov    enc_st = lsqpack_enc_encode(&enc,
64402c4e282SDmitri Tikhonov            enc_buf, &enc_sz, header_buf, &header_sz,
64560620859SDmitri Tikhonov            &xhdr, 0);
64602c4e282SDmitri Tikhonov    assert(enc_sz == 0);
64702c4e282SDmitri Tikhonov    assert(LQES_OK == enc_st);
6483ce33568SDmitri Tikhonov    nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), &hflags);
64902c4e282SDmitri Tikhonov    assert(2 == nw);
65002c4e282SDmitri Tikhonov    assert(prefix_buf[0] == 0 && prefix_buf[1] == 0); /* Dynamic table not used */
6513ce33568SDmitri Tikhonov    assert(!(hflags & LSQECH_REF_AT_RISK));
65202c4e282SDmitri Tikhonov
65302c4e282SDmitri Tikhonov    lsqpack_enc_cleanup(&enc);
65402c4e282SDmitri Tikhonov}
65502c4e282SDmitri Tikhonov
65602c4e282SDmitri Tikhonov
65760620859SDmitri Tikhonovstruct hblock_ctx
65860620859SDmitri Tikhonov{
65960620859SDmitri Tikhonov    unsigned                n_headers;
66060620859SDmitri Tikhonov    int                     finished;
66160620859SDmitri Tikhonov    struct lsxpack_header   xhdr;
66260620859SDmitri Tikhonov    char                    buf[0x10000];
66360620859SDmitri Tikhonov};
66460620859SDmitri Tikhonov
66560620859SDmitri Tikhonov
66660620859SDmitri Tikhonovstatic void
66760620859SDmitri Tikhonovunblocked (void *hblock_ctx_p)
66860620859SDmitri Tikhonov{
66960620859SDmitri Tikhonov    assert(0);  /* Not expecting this to be called */
67060620859SDmitri Tikhonov}
67160620859SDmitri Tikhonov
67260620859SDmitri Tikhonov
67360620859SDmitri Tikhonovstatic struct lsxpack_header *
67460620859SDmitri Tikhonovprepare_decode (void *hblock_ctx_p, struct lsxpack_header *xhdr, size_t space)
67560620859SDmitri Tikhonov{
67660620859SDmitri Tikhonov    struct hblock_ctx *const hctx = hblock_ctx_p;
67760620859SDmitri Tikhonov
67860620859SDmitri Tikhonov    if (space > LSXPACK_MAX_STRLEN)
67960620859SDmitri Tikhonov        return NULL;
68060620859SDmitri Tikhonov
68160620859SDmitri Tikhonov    if (xhdr)
68260620859SDmitri Tikhonov        return NULL;
68360620859SDmitri Tikhonov
68460620859SDmitri Tikhonov    lsxpack_header_prepare_decode(&hctx->xhdr, hctx->buf, 0, sizeof(hctx->buf));
68560620859SDmitri Tikhonov    return &hctx->xhdr;
68660620859SDmitri Tikhonov}
68760620859SDmitri Tikhonov
68860620859SDmitri Tikhonov
68960620859SDmitri Tikhonovstatic int
69060620859SDmitri Tikhonovprocess_header (void *hblock_ctx_p, struct lsxpack_header *xhdr)
69160620859SDmitri Tikhonov{
69260620859SDmitri Tikhonov    struct hblock_ctx *const hctx = hblock_ctx_p;
69360620859SDmitri Tikhonov
69460620859SDmitri Tikhonov    if (xhdr)
69560620859SDmitri Tikhonov        ++hctx->n_headers;
69660620859SDmitri Tikhonov    else
69760620859SDmitri Tikhonov        hctx->finished = 1;
69860620859SDmitri Tikhonov    return 0;
69960620859SDmitri Tikhonov}
70060620859SDmitri Tikhonov
70160620859SDmitri Tikhonov
70260620859SDmitri Tikhonovstatic const struct lsqpack_dec_hset_if hset_if = {
70360620859SDmitri Tikhonov    .dhi_unblocked      = unblocked,
70460620859SDmitri Tikhonov    .dhi_prepare_decode = prepare_decode,
70560620859SDmitri Tikhonov    .dhi_process_header = process_header,
70660620859SDmitri Tikhonov};
70760620859SDmitri Tikhonov
70860620859SDmitri Tikhonov
70981059658SDmitri Tikhonovstatic void
71081059658SDmitri Tikhonovtest_discard_header (int err)
71181059658SDmitri Tikhonov{
71281059658SDmitri Tikhonov    struct lsqpack_dec dec;
71381059658SDmitri Tikhonov    enum lsqpack_read_header_status rhs;
71481059658SDmitri Tikhonov    const unsigned char *buf;
71581059658SDmitri Tikhonov    unsigned char header_block[] = "\x00\x00\xC0\x80";
71660620859SDmitri Tikhonov    struct hblock_ctx hctx = { .n_headers = 0, };
71781059658SDmitri Tikhonov
71860620859SDmitri Tikhonov    lsqpack_dec_init(&dec, NULL, 0, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
71981059658SDmitri Tikhonov
72081059658SDmitri Tikhonov    buf = header_block;
72160620859SDmitri Tikhonov    rhs = lsqpack_dec_header_in(&dec, &hctx, 0, 10,
72260620859SDmitri Tikhonov                                    &buf, 3 + !!err, NULL, NULL);
72381059658SDmitri Tikhonov    if (err)
72481059658SDmitri Tikhonov    {
72560620859SDmitri Tikhonov        assert(hctx.n_headers == 1);
72660620859SDmitri Tikhonov        assert(hctx.finished == 0);
72781059658SDmitri Tikhonov        assert(LQRHS_ERROR == rhs);
72881059658SDmitri Tikhonov    }
72981059658SDmitri Tikhonov    else
73081059658SDmitri Tikhonov    {
73160620859SDmitri Tikhonov        assert(hctx.n_headers == 1);
73260620859SDmitri Tikhonov        assert(hctx.finished == 0);
73381059658SDmitri Tikhonov        assert(3 == buf - header_block);
73481059658SDmitri Tikhonov        assert(LQRHS_NEED == rhs);
73581059658SDmitri Tikhonov        lsqpack_dec_cleanup(&dec);
73681059658SDmitri Tikhonov    }
73781059658SDmitri Tikhonov}
73881059658SDmitri Tikhonov
73981059658SDmitri Tikhonov
740d6183c77SDmitri Tikhonovstatic void
741d6183c77SDmitri Tikhonovtest_static_bounds_header_block (void)
742d6183c77SDmitri Tikhonov{
743d6183c77SDmitri Tikhonov    struct lsqpack_dec dec;
744d6183c77SDmitri Tikhonov    enum lsqpack_read_header_status rhs;
745d6183c77SDmitri Tikhonov    const unsigned char *buf;
746d6183c77SDmitri Tikhonov    /* Static table index 1000 */
747d6183c77SDmitri Tikhonov    unsigned char header_block[] = "\x00\x00\xFF\xA9\x07";
74860620859SDmitri Tikhonov    struct hblock_ctx hctx = { .n_headers = 0, };
749d6183c77SDmitri Tikhonov
75060620859SDmitri Tikhonov    lsqpack_dec_init(&dec, stderr, 0, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
751d6183c77SDmitri Tikhonov    buf = header_block;
75260620859SDmitri Tikhonov    rhs = lsqpack_dec_header_in(&dec, &hctx, 0, 10,
75360620859SDmitri Tikhonov                                    &buf, 5, NULL, NULL);
75460620859SDmitri Tikhonov    assert(hctx.n_headers == 0);
755d6183c77SDmitri Tikhonov    assert(LQRHS_ERROR == rhs);
756d6183c77SDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
757d6183c77SDmitri Tikhonov}
758d6183c77SDmitri Tikhonov
759d6183c77SDmitri Tikhonov
760d6183c77SDmitri Tikhonovstatic void
761d6183c77SDmitri Tikhonovtest_static_bounds_enc_stream (void)
762d6183c77SDmitri Tikhonov{
763d6183c77SDmitri Tikhonov    struct lsqpack_dec dec;
764d6183c77SDmitri Tikhonov    int r;
765d6183c77SDmitri Tikhonov    /* Static table index 1000 */
766d6183c77SDmitri Tikhonov    unsigned char enc_stream[] = "\xFF\xA9\x07\x04" "dude";
767d6183c77SDmitri Tikhonov
76860620859SDmitri Tikhonov    lsqpack_dec_init(&dec, NULL, 0, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
769d6183c77SDmitri Tikhonov    r = lsqpack_dec_enc_in(&dec, enc_stream, 8);
770d6183c77SDmitri Tikhonov    assert(r == -1);
771d6183c77SDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
772d6183c77SDmitri Tikhonov}
773d6183c77SDmitri Tikhonov
774d6183c77SDmitri Tikhonov
77573b010d6SDmitri Tikhonovstatic void
77673b010d6SDmitri Tikhonovtest_wonr_name_too_large_huffman (void)
77773b010d6SDmitri Tikhonov{
77873b010d6SDmitri Tikhonov    struct lsqpack_dec dec;
77973b010d6SDmitri Tikhonov    int r;
78073b010d6SDmitri Tikhonov    /* Partial Insert Without Name Reference with Huffman-encoded name
78173b010d6SDmitri Tikhonov     * string that is larger than 4 x capacity (0x4001)
78273b010d6SDmitri Tikhonov     */
78373b010d6SDmitri Tikhonov    unsigned char enc_stream[] = "\x7F\xE2\x7F";
78473b010d6SDmitri Tikhonov
78560620859SDmitri Tikhonov    lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
78673b010d6SDmitri Tikhonov    r = lsqpack_dec_enc_in(&dec, enc_stream, 3);
78773b010d6SDmitri Tikhonov    assert(r == -1);
78873b010d6SDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
78973b010d6SDmitri Tikhonov}
79073b010d6SDmitri Tikhonov
79173b010d6SDmitri Tikhonov
79273b010d6SDmitri Tikhonovstatic void
79373b010d6SDmitri Tikhonovtest_wonr_name_too_large_plain (void)
79473b010d6SDmitri Tikhonov{
79573b010d6SDmitri Tikhonov    struct lsqpack_dec dec;
79673b010d6SDmitri Tikhonov    int r;
79773b010d6SDmitri Tikhonov    /* Partial Insert Without Name Reference with plain-encoded name
79873b010d6SDmitri Tikhonov     * string that is larger than capacity (0x1001)
79973b010d6SDmitri Tikhonov     */
80073b010d6SDmitri Tikhonov    unsigned char enc_stream[] = "\x5F\xE2\x1F";
80173b010d6SDmitri Tikhonov
80260620859SDmitri Tikhonov    lsqpack_dec_init(&dec, stderr, 0, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
80373b010d6SDmitri Tikhonov    r = lsqpack_dec_enc_in(&dec, enc_stream, 3);
80473b010d6SDmitri Tikhonov    assert(r == -1);
80573b010d6SDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
80673b010d6SDmitri Tikhonov}
80773b010d6SDmitri Tikhonov
80873b010d6SDmitri Tikhonov
80973b010d6SDmitri Tikhonovstatic void
81073b010d6SDmitri Tikhonovtest_wonr_value_too_large_huffman (void)
81173b010d6SDmitri Tikhonov{
81273b010d6SDmitri Tikhonov    struct lsqpack_dec dec;
81373b010d6SDmitri Tikhonov    int r;
81473b010d6SDmitri Tikhonov    /* Partial Insert Without Name Reference with Huffman-encoded value
81573b010d6SDmitri Tikhonov     * string that, together with name, is larger than 4 x capacity (0x3FFF)
81673b010d6SDmitri Tikhonov     */
81773b010d6SDmitri Tikhonov    unsigned char enc_stream[] = "\x42OK\xFF\x80\x7F";
81873b010d6SDmitri Tikhonov
81960620859SDmitri Tikhonov    lsqpack_dec_init(&dec, stderr, 0, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
82073b010d6SDmitri Tikhonov    r = lsqpack_dec_enc_in(&dec, enc_stream, 6);
82173b010d6SDmitri Tikhonov    assert(r == -1);
82273b010d6SDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
82373b010d6SDmitri Tikhonov}
82473b010d6SDmitri Tikhonov
82573b010d6SDmitri Tikhonov
82673b010d6SDmitri Tikhonovstatic void
82773b010d6SDmitri Tikhonovtest_wonr_value_too_large_plain (void)
82873b010d6SDmitri Tikhonov{
82973b010d6SDmitri Tikhonov    struct lsqpack_dec dec;
83073b010d6SDmitri Tikhonov    int r;
83173b010d6SDmitri Tikhonov    /* Partial Insert Without Name Reference with plain-encoded value
83273b010d6SDmitri Tikhonov     * string that, together with name, is larger than capacity (0xFFF)
83373b010d6SDmitri Tikhonov     */
83473b010d6SDmitri Tikhonov    unsigned char enc_stream[] = "\x42OK\x7F\x80\x1F";
83573b010d6SDmitri Tikhonov
83660620859SDmitri Tikhonov    lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
83773b010d6SDmitri Tikhonov    r = lsqpack_dec_enc_in(&dec, enc_stream, 6);
83873b010d6SDmitri Tikhonov    assert(r == -1);
83973b010d6SDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
84073b010d6SDmitri Tikhonov}
84173b010d6SDmitri Tikhonov
84273b010d6SDmitri Tikhonov
84373b010d6SDmitri Tikhonovstatic void
84473b010d6SDmitri Tikhonovtest_winr_value_too_large_huffman (void)
84573b010d6SDmitri Tikhonov{
84673b010d6SDmitri Tikhonov    struct lsqpack_dec dec;
84773b010d6SDmitri Tikhonov    int r;
84873b010d6SDmitri Tikhonov    /* Partial Insert With Name Reference with Huffman-encoded value
84973b010d6SDmitri Tikhonov     * string that, together with name, is larger than 4 x capacity (0x3FE4)
85073b010d6SDmitri Tikhonov     */
85173b010d6SDmitri Tikhonov    /* Refer to static entry 79: access-control-refer-headers (length 28) */
85273b010d6SDmitri Tikhonov    unsigned char enc_stream[] = "\xFF\x10\xFF\xE5\x7E";
85373b010d6SDmitri Tikhonov
85460620859SDmitri Tikhonov    lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
85573b010d6SDmitri Tikhonov    r = lsqpack_dec_enc_in(&dec, enc_stream, 5);
85673b010d6SDmitri Tikhonov    assert(r == -1);
85773b010d6SDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
85873b010d6SDmitri Tikhonov}
85973b010d6SDmitri Tikhonov
86073b010d6SDmitri Tikhonov
86173b010d6SDmitri Tikhonovstatic void
86273b010d6SDmitri Tikhonovtest_winr_value_too_large_plain (void)
86373b010d6SDmitri Tikhonov{
86473b010d6SDmitri Tikhonov    struct lsqpack_dec dec;
86573b010d6SDmitri Tikhonov    int r;
86673b010d6SDmitri Tikhonov    /* Partial Insert With Name Reference with plain-encoded value
86773b010d6SDmitri Tikhonov     * string that, together with name, is larger than capacity (0xFE4)
86873b010d6SDmitri Tikhonov     */
86973b010d6SDmitri Tikhonov    /* Refer to static entry 79: access-control-refer-headers (length 28) */
87073b010d6SDmitri Tikhonov    unsigned char enc_stream[] = "\xFF\x10\x7F\xE5\x1E";
87173b010d6SDmitri Tikhonov
87260620859SDmitri Tikhonov    lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
87373b010d6SDmitri Tikhonov    r = lsqpack_dec_enc_in(&dec, enc_stream, 5);
87473b010d6SDmitri Tikhonov    assert(r == -1);
87573b010d6SDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
87673b010d6SDmitri Tikhonov}
87773b010d6SDmitri Tikhonov
87873b010d6SDmitri Tikhonov
87941eedfafSDmitri Tikhonov/* This is an odd case, but if the first call should provide no input at all,
88041eedfafSDmitri Tikhonov * the decoder should return LQRHS_NEED
88141eedfafSDmitri Tikhonov */
88241eedfafSDmitri Tikhonovstatic void
88341eedfafSDmitri Tikhonovtest_dec_header_zero_in (void)
88441eedfafSDmitri Tikhonov{
88541eedfafSDmitri Tikhonov    struct lsqpack_dec dec;
88641eedfafSDmitri Tikhonov    struct lsqpack_header_list *hlist;
88741eedfafSDmitri Tikhonov    enum lsqpack_read_header_status rhs;
888daec9888SLiteSpeed Tech    const unsigned char *buf = (unsigned char *) "";
88960620859SDmitri Tikhonov    struct hblock_ctx hctx = { .n_headers = 0, };
89041eedfafSDmitri Tikhonov
89160620859SDmitri Tikhonov    lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
89241eedfafSDmitri Tikhonov
89341eedfafSDmitri Tikhonov    rhs = lsqpack_dec_header_in(&dec,
89460620859SDmitri Tikhonov                &hctx /* hblock */,
89541eedfafSDmitri Tikhonov                2 /* Stream ID */,
89641eedfafSDmitri Tikhonov                100 /* How long the thing is */,
89741eedfafSDmitri Tikhonov                &buf,
89841eedfafSDmitri Tikhonov                0 /* How many bytes are available */,
89941eedfafSDmitri Tikhonov                NULL, 0);
90041eedfafSDmitri Tikhonov    assert(LQRHS_NEED == rhs);
90141eedfafSDmitri Tikhonov
90241eedfafSDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
90341eedfafSDmitri Tikhonov}
90441eedfafSDmitri Tikhonov
90541eedfafSDmitri Tikhonov
9068a627c4bSDmitri Tikhonov/* Header that's too should should return LQRHS_ERROR */
9078a627c4bSDmitri Tikhonovstatic void
9088a627c4bSDmitri Tikhonovtest_dec_header_too_short (size_t header_size)
9098a627c4bSDmitri Tikhonov{
9108a627c4bSDmitri Tikhonov    struct lsqpack_dec dec;
9118a627c4bSDmitri Tikhonov    struct lsqpack_header_list *hlist;
9128a627c4bSDmitri Tikhonov    enum lsqpack_read_header_status rhs;
913daec9888SLiteSpeed Tech    const unsigned char *buf = (unsigned char *) "";
91460620859SDmitri Tikhonov    struct hblock_ctx hctx = { .n_headers = 0, };
9158a627c4bSDmitri Tikhonov
91660620859SDmitri Tikhonov    lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X);
9178a627c4bSDmitri Tikhonov
9188a627c4bSDmitri Tikhonov    rhs = lsqpack_dec_header_in(&dec,
91960620859SDmitri Tikhonov                &hctx /* hblock */,
9208a627c4bSDmitri Tikhonov                2 /* Stream ID */,
9218a627c4bSDmitri Tikhonov                header_size,
9228a627c4bSDmitri Tikhonov                &buf,
9238a627c4bSDmitri Tikhonov                0 /* How many bytes are available */,
9248a627c4bSDmitri Tikhonov                NULL, 0);
9258a627c4bSDmitri Tikhonov    assert(LQRHS_ERROR == rhs);
9268a627c4bSDmitri Tikhonov
9278a627c4bSDmitri Tikhonov    lsqpack_dec_cleanup(&dec);
9288a627c4bSDmitri Tikhonov}
9298a627c4bSDmitri Tikhonov
9308a627c4bSDmitri Tikhonov
931147b1758SDmitri Tikhonovstatic void
932147b1758SDmitri Tikhonovtest_enc_risked_streams_test (const char *test)
933147b1758SDmitri Tikhonov{
934147b1758SDmitri Tikhonov    struct lsqpack_enc enc;
935147b1758SDmitri Tikhonov    int s;
936147b1758SDmitri Tikhonov    size_t sz;
937147b1758SDmitri Tikhonov    ssize_t ssz;
938147b1758SDmitri Tikhonov    long arg;
939147b1758SDmitri Tikhonov    enum lsqpack_enc_status es;
940147b1758SDmitri Tikhonov    unsigned n_seqnos = 0;
941147b1758SDmitri Tikhonov    struct {
942147b1758SDmitri Tikhonov        uint64_t stream_id;
943147b1758SDmitri Tikhonov        unsigned seqno;
944147b1758SDmitri Tikhonov    } seqnos[10], *seq_el;
945147b1758SDmitri Tikhonov    unsigned char buf[0x100];
946147b1758SDmitri Tikhonov    unsigned char *end_cmd;
947147b1758SDmitri Tikhonov    int expect_failure;
94860620859SDmitri Tikhonov    struct lsxpack_header xhdr;
9499e982dfdSDmitri Tikhonov    struct header_buf hbuf;
950147b1758SDmitri Tikhonov
951147b1758SDmitri Tikhonov    const struct {
952147b1758SDmitri Tikhonov        const char *name;
953147b1758SDmitri Tikhonov        unsigned    name_len;
954147b1758SDmitri Tikhonov        const char *value;
955147b1758SDmitri Tikhonov        unsigned    value_len;
956147b1758SDmitri Tikhonov    } headers[] = {
957147b1758SDmitri Tikhonov        {   "some", 4, "header", 6, },
958147b1758SDmitri Tikhonov        {   "another", 7, "header", 6, },
959147b1758SDmitri Tikhonov        {   "and yet another", 15, "header, duh", 11, },
960147b1758SDmitri Tikhonov    };
961147b1758SDmitri Tikhonov
962147b1758SDmitri Tikhonov    fprintf(stderr, "BEGIN TEST %s\n", test);
963147b1758SDmitri Tikhonov    lsqpack_enc_preinit(&enc, stderr);
9649e982dfdSDmitri Tikhonov    hbuf.off = 0;
965147b1758SDmitri Tikhonov
966147b1758SDmitri Tikhonov    while (1)
967147b1758SDmitri Tikhonov    {
968147b1758SDmitri Tikhonov        expect_failure = isupper(*test);
969147b1758SDmitri Tikhonov        switch (*test++)
970147b1758SDmitri Tikhonov        {
971147b1758SDmitri Tikhonov        case 'i':
972147b1758SDmitri Tikhonov            arg = strtol(test, (char**)&test, 10);
973147b1758SDmitri Tikhonov            sz = sizeof(buf);
974147b1758SDmitri Tikhonov            s = lsqpack_enc_init(&enc, stderr, 0x1000, 0x1000,
975147b1758SDmitri Tikhonov                                        (unsigned) arg, 0, buf, &sz);
976147b1758SDmitri Tikhonov            assert(s == 0);
977147b1758SDmitri Tikhonov            break;
978147b1758SDmitri Tikhonov        case 'r':
979147b1758SDmitri Tikhonov            arg = strtol(test, (char**)&test, 10);
980147b1758SDmitri Tikhonov            assert((unsigned) arg == enc.qpe_cur_streams_at_risk);
981147b1758SDmitri Tikhonov            break;
982147b1758SDmitri Tikhonov        case 's':   /* Start header */
983147b1758SDmitri Tikhonov            arg = strtol(test, (char**)&test, 10);
984147b1758SDmitri Tikhonov            for (seq_el = seqnos; seq_el < seqnos + n_seqnos; ++seq_el)
985147b1758SDmitri Tikhonov                if (seq_el->stream_id == arg)
986147b1758SDmitri Tikhonov                    break;
987147b1758SDmitri Tikhonov            assert(seq_el < seqnos + sizeof(seqnos) / sizeof(seqnos[0]));
988147b1758SDmitri Tikhonov            if (seq_el == seqnos + n_seqnos)
989147b1758SDmitri Tikhonov            {
990147b1758SDmitri Tikhonov                ++n_seqnos;
991147b1758SDmitri Tikhonov                seq_el->stream_id = arg;
992147b1758SDmitri Tikhonov                seq_el->seqno = 0;
993147b1758SDmitri Tikhonov            }
994147b1758SDmitri Tikhonov            s = lsqpack_enc_start_header(&enc, arg, seq_el->seqno++);
995147b1758SDmitri Tikhonov            assert(s == 0);
996147b1758SDmitri Tikhonov            break;
997147b1758SDmitri Tikhonov        case 'c':   /* En*C*ode */
998147b1758SDmitri Tikhonov            arg = strtol(test, (char**)&test, 10);
999147b1758SDmitri Tikhonov            sz = sizeof(buf);
1000147b1758SDmitri Tikhonov            /* We ignore the output */
10019e982dfdSDmitri Tikhonov            header_set_ptr(&xhdr, &hbuf,
1002147b1758SDmitri Tikhonov                        headers[arg].name, headers[arg].name_len,
100360620859SDmitri Tikhonov                        headers[arg].value, headers[arg].value_len);
100460620859SDmitri Tikhonov            es = lsqpack_enc_encode(&enc, buf, &sz, buf, &sz, &xhdr, 0);
1005147b1758SDmitri Tikhonov            assert(LQES_OK == es);
1006147b1758SDmitri Tikhonov            break;
1007147b1758SDmitri Tikhonov        case 'e':   /* End header */
1008147b1758SDmitri Tikhonov            ssz = lsqpack_enc_end_header(&enc, buf, sizeof(buf), NULL);
1009147b1758SDmitri Tikhonov            assert(ssz > 0);
1010147b1758SDmitri Tikhonov            break;
1011147b1758SDmitri Tikhonov        case 'a':   /* ACK header */
1012147b1758SDmitri Tikhonov        case 'A':
1013147b1758SDmitri Tikhonov            arg = strtol(test, (char**)&test, 10);
1014147b1758SDmitri Tikhonov            buf[0] = 0x80;
1015147b1758SDmitri Tikhonov            end_cmd = lsqpack_enc_int(buf, buf + sizeof(buf), arg, 7);
1016147b1758SDmitri Tikhonov            s = lsqpack_enc_decoder_in(&enc, buf, end_cmd - buf);
1017147b1758SDmitri Tikhonov            if (expect_failure)
1018147b1758SDmitri Tikhonov                assert(s < 0);
1019147b1758SDmitri Tikhonov            else
1020147b1758SDmitri Tikhonov                assert(s == 0);
1021147b1758SDmitri Tikhonov            break;
1022147b1758SDmitri Tikhonov        case 'L':   /* Cancel header */
1023147b1758SDmitri Tikhonov        case 'l':
1024147b1758SDmitri Tikhonov            arg = strtol(test, (char**)&test, 10);
1025147b1758SDmitri Tikhonov            buf[0] = 0x40;
1026147b1758SDmitri Tikhonov            end_cmd = lsqpack_enc_int(buf, buf + sizeof(buf), arg, 6);
1027147b1758SDmitri Tikhonov            s = lsqpack_enc_decoder_in(&enc, buf, end_cmd - buf);
1028147b1758SDmitri Tikhonov            if (expect_failure)
1029147b1758SDmitri Tikhonov                assert(s < 0);
1030147b1758SDmitri Tikhonov            else
1031147b1758SDmitri Tikhonov                assert(s == 0);
1032147b1758SDmitri Tikhonov            break;
1033147b1758SDmitri Tikhonov        case 'N':   /* Insert Count Increment */
1034147b1758SDmitri Tikhonov        case 'n':
1035147b1758SDmitri Tikhonov            arg = strtol(test, (char**)&test, 10);
1036147b1758SDmitri Tikhonov            buf[0] = 0x00;
1037147b1758SDmitri Tikhonov            end_cmd = lsqpack_enc_int(buf, buf + sizeof(buf), arg, 6);
1038147b1758SDmitri Tikhonov            s = lsqpack_enc_decoder_in(&enc, buf, end_cmd - buf);
1039147b1758SDmitri Tikhonov            if (expect_failure)
1040147b1758SDmitri Tikhonov                assert(s < 0);
1041147b1758SDmitri Tikhonov            else
1042147b1758SDmitri Tikhonov                assert(s == 0);
1043147b1758SDmitri Tikhonov            break;
1044147b1758SDmitri Tikhonov            break;
1045147b1758SDmitri Tikhonov        case '\0':
1046147b1758SDmitri Tikhonov            goto end;
1047147b1758SDmitri Tikhonov        default:
1048147b1758SDmitri Tikhonov            assert("unknown action");
1049147b1758SDmitri Tikhonov            goto end;
1050147b1758SDmitri Tikhonov        }
1051147b1758SDmitri Tikhonov    }
1052147b1758SDmitri Tikhonov
1053147b1758SDmitri Tikhonov  end:
1054147b1758SDmitri Tikhonov    lsqpack_enc_cleanup(&enc);
1055147b1758SDmitri Tikhonov}
1056147b1758SDmitri Tikhonov
1057147b1758SDmitri Tikhonov
1058147b1758SDmitri Tikhonovstatic void
1059147b1758SDmitri Tikhonovtest_enc_risked_streams (void)
1060147b1758SDmitri Tikhonov{
1061147b1758SDmitri Tikhonov    const char **test;
1062147b1758SDmitri Tikhonov    const char *tests[] =
1063147b1758SDmitri Tikhonov    {
1064147b1758SDmitri Tikhonov        "i0r0s1c0er0",
1065147b1758SDmitri Tikhonov        "i1r0s1c0er0s2c0er1A1r1a2r0",
1066147b1758SDmitri Tikhonov        "i1r0s1c0er0s2c0er1s2c0c1er1a2r0a2r0",
1067147b1758SDmitri Tikhonov
1068147b1758SDmitri Tikhonov        "i1r0s1c0c1er0"
1069147b1758SDmitri Tikhonov        "s2c0er1"
1070147b1758SDmitri Tikhonov        "s2c0c1er1"
1071147b1758SDmitri Tikhonov        "a2r1"      /* Ack first seqno, # of risked streams still 1 */
1072147b1758SDmitri Tikhonov        "a2r0",
1073147b1758SDmitri Tikhonov
1074147b1758SDmitri Tikhonov        "i1r0s1c0c1er0"
1075147b1758SDmitri Tikhonov        "s2c0er1"
1076147b1758SDmitri Tikhonov        "s2c0c1er1"
1077147b1758SDmitri Tikhonov        "l2r0"      /* Cancel */
1078147b1758SDmitri Tikhonov        ,
1079147b1758SDmitri Tikhonov
1080147b1758SDmitri Tikhonov        "i1r0s1c0c1er0"
1081147b1758SDmitri Tikhonov        "s2c0er1"
1082147b1758SDmitri Tikhonov        "s2c0c1er1"
1083147b1758SDmitri Tikhonov        "N3"
1084147b1758SDmitri Tikhonov        "n1r1"
1085147b1758SDmitri Tikhonov        "n1r0"
1086147b1758SDmitri Tikhonov        ,
1087147b1758SDmitri Tikhonov
1088147b1758SDmitri Tikhonov        NULL,
1089147b1758SDmitri Tikhonov    };
1090147b1758SDmitri Tikhonov
1091147b1758SDmitri Tikhonov    for (test = tests; *test; ++test)
1092147b1758SDmitri Tikhonov        test_enc_risked_streams_test(*test);
1093147b1758SDmitri Tikhonov}
1094147b1758SDmitri Tikhonov
1095147b1758SDmitri Tikhonov
109643a63c18SDmitri Tikhonovint
109743a63c18SDmitri Tikhonovmain (void)
109843a63c18SDmitri Tikhonov{
109943a63c18SDmitri Tikhonov    unsigned i;
110043a63c18SDmitri Tikhonov
110143a63c18SDmitri Tikhonov    for (i = 0; i < sizeof(header_block_tests)
110243a63c18SDmitri Tikhonov                                / sizeof(header_block_tests[0]); ++i)
110318555864SDmitri Tikhonov    {
110443a63c18SDmitri Tikhonov        run_header_test(&header_block_tests[i]);
110518555864SDmitri Tikhonov        run_decoded_headers_test(&header_block_tests[i]);
110618555864SDmitri Tikhonov    }
110743a63c18SDmitri Tikhonov
1108d4822b2bSDaan De Meyer    run_header_cancellation_test(&header_block_tests[0]);
1109b43d0c9bSDmitri Tikhonov    test_enc_init();
111002c4e282SDmitri Tikhonov    test_push_promise();
111181059658SDmitri Tikhonov    test_discard_header(0);
111281059658SDmitri Tikhonov    test_discard_header(1);
1113d6183c77SDmitri Tikhonov    test_static_bounds_header_block();
1114d6183c77SDmitri Tikhonov    test_static_bounds_enc_stream();
111573b010d6SDmitri Tikhonov    test_wonr_name_too_large_huffman();
111673b010d6SDmitri Tikhonov    test_wonr_name_too_large_plain();
111773b010d6SDmitri Tikhonov    test_wonr_value_too_large_huffman();
111873b010d6SDmitri Tikhonov    test_wonr_value_too_large_plain();
111973b010d6SDmitri Tikhonov    test_winr_value_too_large_huffman();
112073b010d6SDmitri Tikhonov    test_winr_value_too_large_plain();
112141eedfafSDmitri Tikhonov    test_dec_header_zero_in();
11228a627c4bSDmitri Tikhonov    test_dec_header_too_short(0);
11238a627c4bSDmitri Tikhonov    test_dec_header_too_short(1);
1124147b1758SDmitri Tikhonov    test_enc_risked_streams();
1125d4822b2bSDaan De Meyer
112643a63c18SDmitri Tikhonov    return 0;
112743a63c18SDmitri Tikhonov}
1128