test_hcsi_reader.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <inttypes.h>
4#include <stdlib.h>
5#include <string.h>
6#include <stdio.h>
7#include <sys/queue.h>
8
9#include "lsquic.h"
10#include "lsquic_int_types.h"
11#include "lsquic_varint.h"
12#include "lsquic_hq.h"
13#include "lsquic_hcsi_reader.h"
14#include "lsquic_hash.h"
15#include "lsquic_conn.h"
16
17struct test
18{
19    int             lineno;
20
21    enum {
22        TEST_NO_FLAGS           = 0,
23        TEST_NUL_OUT_LEST_FULL  = 1 << 0,
24    }               flags;
25
26    unsigned char   input[0x100];
27    size_t          input_sz;
28
29    int             retval;
30    char            output[0x1000];
31};
32
33
34static const struct test tests[] =
35{
36    {
37        __LINE__,
38        TEST_NO_FLAGS,
39        {
40            0x03,
41            0x04,
42            0x80, 0x12, 0x34, 0x45,
43        },
44        6,
45        0,
46        "on_cancel_push: 1193029\n",
47    },
48
49    {
50        __LINE__,
51        TEST_NO_FLAGS,
52        {
53            HQFT_MAX_PUSH_ID,
54            0x02,
55            0x41, 0x23,
56        },
57        4,
58        0,
59        "on_max_push_id: 291\n",
60    },
61
62    {
63        __LINE__,
64        TEST_NO_FLAGS,
65        {
66            HQFT_SETTINGS,
67            0x00,
68        },
69        2,
70        0,
71        "have SETTINGS frame\n",
72    },
73
74    {   /* Frame contents do not match frame length */
75        __LINE__,
76        TEST_NO_FLAGS,
77        {
78            HQFT_MAX_PUSH_ID,
79            0x03,
80            0x41, 0x23,
81        },
82        4,
83        -1,
84        "",
85    },
86
87    {
88        __LINE__,
89        TEST_NO_FLAGS,
90        {
91            HQFT_SETTINGS,
92            13,
93            0x52, 0x34,
94            0xC0, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
95            0x52, 0x35,
96            0x00,
97        },
98        15,
99        0,
100        "on_setting: 0x1234=0x12233445566778\n"
101        "on_setting: 0x1235=0x0\n"
102        "have SETTINGS frame\n"
103        ,
104    },
105
106    {
107        __LINE__,
108        TEST_NO_FLAGS,
109        {
110            0x80, 0x0F, 0x07, 0x00, /* HQFT_PRIORITY_UPDATE_STREAM */
111            7,
112            0x52, 0x34,
113            0x41, 0x42, 0x43, 0x44, 0x45,   /* ABCDE */
114            HQFT_MAX_PUSH_ID,
115            0x02,
116            0x41, 0x23,
117        },
118        16,
119        0,
120        "on_priority_update: stream=0x1234, [ABCDE]\n"
121        "on_max_push_id: 291\n"
122        ,
123    },
124
125    {
126        __LINE__,
127        TEST_NO_FLAGS,
128        {
129            0x80, 0x0F, 0x07, 0x01, /* HQFT_PRIORITY_UPDATE_PUSH */
130            6,
131            0x08,
132            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
133        },
134        11,
135        0,
136        "on_priority_update: push=0x8, [PQRST]\n"
137        ,
138    },
139
140    {
141        __LINE__,
142        TEST_NUL_OUT_LEST_FULL,
143        {
144            0x80, 0x0F, 0x07, 0x01, /* HQFT_PRIORITY_UPDATE_PUSH */
145            21,
146            0x08,
147            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
148            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
149            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
150            0x50, 0x51, 0x52, 0x53, 0x54,   /* PQRST */
151        },
152        26,
153        0,
154        "on_priority_update: push=0x8, [PQRSTPQRSTPQRSTPQRST]\n"
155        ,
156    },
157
158};
159
160
161static void
162on_cancel_push (void *ctx, uint64_t push_id)
163{
164    fprintf(ctx, "%s: %"PRIu64"\n", __func__, push_id);
165}
166
167static void
168on_max_push_id (void *ctx, uint64_t push_id)
169{
170    fprintf(ctx, "%s: %"PRIu64"\n", __func__, push_id);
171}
172
173static void
174on_settings_frame (void *ctx)
175{
176    fprintf(ctx, "have SETTINGS frame\n");
177}
178
179static void
180on_setting (void *ctx, uint64_t setting_id, uint64_t value)
181{
182    fprintf(ctx, "%s: 0x%"PRIX64"=0x%"PRIX64"\n", __func__, setting_id, value);
183}
184
185static void
186on_goaway (void *ctx, uint64_t stream_id)
187{
188    fprintf(ctx, "%s: %"PRIu64"\n", __func__, stream_id);
189}
190
191static void
192on_unexpected_frame (void *ctx, uint64_t frame_type)
193{
194    fprintf(ctx, "%s: %"PRIu64"\n", __func__, frame_type);
195}
196
197static void
198on_priority_update (void *ctx, enum hq_frame_type frame_type,
199                            /* PFV: Priority Field Value */
200                            uint64_t id, const char *pfv, size_t pfv_sz)
201{
202    const char *type;
203
204    switch (frame_type)
205    {
206    case HQFT_PRIORITY_UPDATE_STREAM:  type = "stream"; break;
207    case HQFT_PRIORITY_UPDATE_PUSH:    type = "push"; break;
208    default:                    assert(0); return;
209    }
210
211    fprintf(ctx, "%s: %s=0x%"PRIX64", [%.*s]\n", __func__, type, id,
212                                                        (int) pfv_sz, pfv);
213}
214
215static const struct hcsi_callbacks callbacks =
216{
217    .on_cancel_push         = on_cancel_push,
218    .on_max_push_id         = on_max_push_id,
219    .on_settings_frame      = on_settings_frame,
220    .on_setting             = on_setting,
221    .on_goaway              = on_goaway,
222    .on_unexpected_frame    = on_unexpected_frame,
223    .on_priority_update     = on_priority_update,
224};
225
226
227static void
228abort_error (struct lsquic_conn *conn, int is_app, unsigned error_code,
229                                                    const char *format, ...)
230{
231}
232
233
234static const struct conn_iface conn_iface = {
235    .ci_abort_error     = abort_error,
236};
237
238
239static void
240run_test (const struct test *test)
241{
242    struct hcsi_reader reader;
243    size_t read_sz, out_sz, toread;
244    FILE *out_f;
245    char *output;
246    const unsigned char *p;
247    int s;
248    struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 0);
249    lconn.cn_if = &conn_iface;
250
251    for (read_sz = 1; read_sz <= test->input_sz; ++read_sz)
252    {
253        out_f = open_memstream(&output, &out_sz);
254        lsquic_hcsi_reader_init(&reader, &lconn, &callbacks, out_f);
255
256        p = test->input;
257        do
258        {
259            toread = test->input + test->input_sz - p;
260            if (toread > read_sz)
261                toread = read_sz;
262            s = lsquic_hcsi_reader_feed(&reader, p, toread);
263            if (s != 0)
264                break;
265            p += toread;
266        }
267        while (p < test->input + test->input_sz);
268
269        assert(s == test->retval);
270
271        fclose(out_f);
272        if (test->retval == 0 && read_sz < test->input_sz
273                                    && (test->flags & TEST_NUL_OUT_LEST_FULL))
274            assert(0 == strcmp(output, ""));
275        else
276            assert(0 == strcmp(test->output, output));
277        free(output);
278    }
279}
280
281int
282main (void)
283{
284    const struct test *test;
285    struct test coalesced_test;
286
287    for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test)
288        run_test(test);
289
290    memset(&coalesced_test, 0, sizeof(coalesced_test));
291    for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test)
292        if (test->retval == 0 && !(test->flags & TEST_NUL_OUT_LEST_FULL))
293        {
294            memcpy(coalesced_test.input + coalesced_test.input_sz,
295                    test->input, test->input_sz);
296            coalesced_test.input_sz += test->input_sz;
297            strcat(coalesced_test.output, test->output);
298        }
299    run_test(&coalesced_test);
300
301    return 0;
302}
303