test_frame_reader.c revision a74702c6
1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
2#include <assert.h>
3#include <errno.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#ifndef WIN32
8#include <unistd.h>
9#else
10#include <getopt.h>
11#endif
12#include <sys/queue.h>
13
14#include "lsquic.h"
15#include "lsquic_frame_common.h"
16#include "lshpack.h"
17#include "lsquic_mm.h"
18#include "lsquic_int_types.h"
19#include "lsquic_conn_flow.h"
20#include "lsquic_sfcw.h"
21#include "lsquic_rtt.h"
22#include "lsquic_hash.h"
23#include "lsquic_conn.h"
24#include "lsquic_varint.h"
25#include "lsquic_hq.h"
26#include "lsquic_stream.h"
27#include "lsquic_conn_public.h"
28#include "lsquic_logger.h"
29#if LSQUIC_CONN_STATS
30#include "lsquic_int_types.h"
31#include "lsquic_conn.h"
32#endif
33
34#include "lsquic_frame_reader.h"
35#include "lsquic_headers.h"
36#include "lsquic_http1x_if.h"
37
38
39struct callback_value   /* What callback returns */
40{
41    enum {
42        CV_HEADERS,
43        CV_SETTINGS,
44        CV_PUSH_PROMISE,
45        CV_PRIORITY,
46        CV_ERROR,
47    }                                   type;
48    unsigned                            stream_off; /* Checked only if not zero */
49    union {
50        struct headers {
51            uint32_t                stream_id;
52            uint32_t                oth_stream_id;
53            unsigned short          weight;
54            signed char             exclusive;
55            unsigned char           flags;
56            unsigned                size;
57            unsigned                off;
58            char                    buf[0x100];
59        }                               headers;
60        struct {
61            uint16_t                    id;
62            uint32_t                    value;
63        }                               setting;
64        void                           *push_promise;
65        struct cv_error {
66            enum frame_reader_error     code;
67            lsquic_stream_id_t          stream_id;
68        }                               error;
69        struct cv_priority {
70            lsquic_stream_id_t          stream_id;
71            int                         exclusive;
72            lsquic_stream_id_t          dep_stream_id;
73            unsigned                    weight;
74        }                               priority;
75    }                                   u;
76};
77
78
79void
80compare_headers (const struct headers *got_h, const struct headers *exp_h)
81{
82    assert(got_h->stream_id == exp_h->stream_id);
83    assert(got_h->oth_stream_id == exp_h->oth_stream_id);
84    assert(got_h->weight == exp_h->weight);
85    assert(got_h->exclusive == exp_h->exclusive);
86    assert(got_h->size == exp_h->size);
87    assert(strlen(got_h->buf) == got_h->size);
88    assert(got_h->off == exp_h->off);
89    assert(got_h->flags == exp_h->flags);
90    assert(0 == memcmp(got_h->buf, exp_h->buf, got_h->size));
91}
92
93
94void
95compare_push_promises (const struct headers *got_h, const struct headers *exp_h)
96{
97    assert(got_h->stream_id == exp_h->stream_id);
98    assert(got_h->oth_stream_id == exp_h->oth_stream_id);
99    assert(got_h->size == exp_h->size);
100    assert(strlen(got_h->buf) == got_h->size);
101    assert(got_h->off == exp_h->off);
102    assert(got_h->flags == exp_h->flags);
103    assert(0 == memcmp(got_h->buf, exp_h->buf, got_h->size));
104}
105
106
107void
108compare_priorities (const struct cv_priority *got_prio,
109                    const struct cv_priority *exp_prio)
110{
111    assert(got_prio->stream_id      == exp_prio->stream_id);
112    assert(got_prio->exclusive      == exp_prio->exclusive);
113    assert(got_prio->dep_stream_id  == exp_prio->dep_stream_id);
114    assert(got_prio->weight         == exp_prio->weight);
115}
116
117
118void
119compare_errors (const struct cv_error *got_err,
120                const struct cv_error *exp_err)
121{
122    assert(got_err->code == exp_err->code);
123    assert(got_err->stream_id == exp_err->stream_id);
124}
125
126
127static void
128compare_cb_vals (const struct callback_value *got,
129                 const struct callback_value *exp)
130{
131    assert(got->type == exp->type);
132    if (exp->stream_off)
133        assert(exp->stream_off == got->stream_off);
134    switch (got->type)
135    {
136    case CV_HEADERS:
137        compare_headers(&got->u.headers, &exp->u.headers);
138        break;
139    case CV_PUSH_PROMISE:
140        compare_push_promises(&got->u.headers, &exp->u.headers);
141        break;
142    case CV_ERROR:
143        compare_errors(&got->u.error, &exp->u.error);
144        break;
145    case CV_PRIORITY:
146        compare_priorities(&got->u.priority, &exp->u.priority);
147        break;
148    case CV_SETTINGS:
149        /* TODO */
150        break;
151    }
152}
153
154
155static struct {
156    size_t          in_sz;
157    size_t          in_off;
158    size_t          in_max_req_sz;
159    size_t          in_max_sz;
160    unsigned char   in_buf[0x1000];
161} input;
162
163
164static struct cb_ctx {
165    unsigned                n_cb_vals;
166    struct callback_value   cb_vals[10];
167} g_cb_ctx;
168
169
170static void
171reset_cb_ctx (struct cb_ctx *cb_ctx)
172{
173    cb_ctx->n_cb_vals = 0;
174    memset(&cb_ctx->cb_vals, 0xA5, sizeof(cb_ctx->cb_vals));
175}
176
177
178static void
179copy_uh_to_headers (const struct uncompressed_headers *uh, struct headers *h)
180{
181    const struct http1x_headers *h1h = uh->uh_hset;
182    h->flags = uh->uh_flags;
183    h->weight = uh->uh_weight;
184    h->stream_id = uh->uh_stream_id;
185    h->exclusive = uh->uh_exclusive;
186    h->oth_stream_id = uh->uh_oth_stream_id;
187    h->size = h1h->h1h_size;
188    h->off = h1h->h1h_off;
189    memcpy(h->buf, h1h->h1h_buf, h->size);
190    h->buf[h->size] = '\0';
191}
192
193
194static void
195on_incoming_headers (void *ctx, struct uncompressed_headers *uh)
196{
197    struct cb_ctx *cb_ctx = ctx;
198    assert(cb_ctx == &g_cb_ctx);
199    unsigned i = cb_ctx->n_cb_vals++;
200    assert(i < sizeof(cb_ctx->cb_vals) / sizeof(cb_ctx->cb_vals[0]));
201    cb_ctx->cb_vals[i].type = CV_HEADERS;
202    cb_ctx->cb_vals[i].stream_off = input.in_off;
203    copy_uh_to_headers(uh, &cb_ctx->cb_vals[i].u.headers);
204    assert(uh->uh_flags & UH_H1H);
205    lsquic_http1x_if->hsi_discard_header_set(uh->uh_hset);
206    free(uh);
207}
208
209
210static void
211on_push_promise (void *ctx, struct uncompressed_headers *uh)
212{
213    struct cb_ctx *cb_ctx = ctx;
214    assert(cb_ctx == &g_cb_ctx);
215    unsigned i = cb_ctx->n_cb_vals++;
216    assert(i < sizeof(cb_ctx->cb_vals) / sizeof(cb_ctx->cb_vals[0]));
217    cb_ctx->cb_vals[i].type = CV_PUSH_PROMISE;
218    cb_ctx->cb_vals[i].stream_off = input.in_off;
219    copy_uh_to_headers(uh, &cb_ctx->cb_vals[i].u.headers);
220    assert(uh->uh_flags & UH_H1H);
221    lsquic_http1x_if->hsi_discard_header_set(uh->uh_hset);
222    free(uh);
223}
224
225
226static void
227on_error (void *ctx, lsquic_stream_id_t stream_id, enum frame_reader_error error)
228{
229    struct cb_ctx *cb_ctx = ctx;
230    assert(cb_ctx == &g_cb_ctx);
231    unsigned i = cb_ctx->n_cb_vals++;
232    assert(i < sizeof(cb_ctx->cb_vals) / sizeof(cb_ctx->cb_vals[0]));
233    cb_ctx->cb_vals[i].type = CV_ERROR;
234    cb_ctx->cb_vals[i].u.error.stream_id = stream_id;
235    cb_ctx->cb_vals[i].u.error.code = error;
236    cb_ctx->cb_vals[i].stream_off = input.in_off;
237}
238
239
240static void
241on_settings (void *ctx, uint16_t id, uint32_t value)
242{
243    struct cb_ctx *cb_ctx = ctx;
244    assert(cb_ctx == &g_cb_ctx);
245    unsigned i = cb_ctx->n_cb_vals++;
246    assert(i < sizeof(cb_ctx->cb_vals) / sizeof(cb_ctx->cb_vals[0]));
247    cb_ctx->cb_vals[i].type = CV_SETTINGS;
248    cb_ctx->cb_vals[i].u.setting.id = id;
249    cb_ctx->cb_vals[i].u.setting.value = value;
250    cb_ctx->cb_vals[i].stream_off = input.in_off;
251}
252
253
254static void
255on_priority (void *ctx, lsquic_stream_id_t stream_id, int exclusive,
256             lsquic_stream_id_t dep_stream_id, unsigned weight)
257{
258    struct cb_ctx *cb_ctx = ctx;
259    assert(cb_ctx == &g_cb_ctx);
260    unsigned i = cb_ctx->n_cb_vals++;
261    assert(i < sizeof(cb_ctx->cb_vals) / sizeof(cb_ctx->cb_vals[0]));
262    cb_ctx->cb_vals[i].type = CV_PRIORITY;
263    cb_ctx->cb_vals[i].u.priority.stream_id     = stream_id;
264    cb_ctx->cb_vals[i].u.priority.exclusive     = exclusive;
265    cb_ctx->cb_vals[i].u.priority.dep_stream_id = dep_stream_id;
266    cb_ctx->cb_vals[i].u.priority.weight        = weight;
267    cb_ctx->cb_vals[i].stream_off = input.in_off;
268}
269
270
271static const struct frame_reader_callbacks frame_callbacks = {
272    .frc_on_headers      = on_incoming_headers,
273    .frc_on_push_promise = on_push_promise,
274    .frc_on_settings     = on_settings,
275    .frc_on_priority     = on_priority,
276    .frc_on_error        = on_error,
277};
278
279
280static ssize_t
281read_from_stream (struct lsquic_stream *stream, void *buf, size_t sz)
282{
283    if (sz > input.in_max_req_sz)
284        input.in_max_req_sz = sz;
285    if (input.in_sz - input.in_off < sz)
286        sz = input.in_sz - input.in_off;
287    if (sz > input.in_max_sz)
288        sz = input.in_max_sz;
289    memcpy(buf, input.in_buf + input.in_off, sz);
290    input.in_off += sz;
291    return sz;
292}
293
294
295struct frame_reader_test {
296    unsigned                        frt_lineno;
297    /* Input */
298    enum frame_reader_flags         frt_fr_flags;
299    unsigned char                   frt_buf[0x100];
300    unsigned short                  frt_bufsz;
301    unsigned                        frt_max_headers_sz;
302    /* Output */
303    unsigned short                  frt_in_off;
304    int                             frt_err;      /* True if expecting error */
305    unsigned                        frt_n_cb_vals;
306    struct callback_value           frt_cb_vals[10];
307};
308
309
310#define HEADERS(str) .buf = (str), .size = sizeof(str) - 1
311
312static const struct frame_reader_test tests[] = {
313    {   .frt_lineno = __LINE__,
314        .frt_fr_flags = 0,
315        .frt_buf    = {
316            /* Length: */       0x00, 0x00, 0x04,
317            /* Type: */         0x01,
318            /* Flags: */        HFHF_END_HEADERS,
319                            0x80|           /* <----- This bit must be ignored */
320            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
321            /* Block fragment: */
322                                0x48, 0x82, 0x64, 0x02,
323        },
324        .frt_bufsz  = 13,
325        .frt_n_cb_vals = 1,
326        .frt_cb_vals = {
327            {
328                .type = CV_HEADERS,
329                .u.headers = {
330                    .stream_id       = 12345,
331                    .oth_stream_id   = 0,
332                    .weight          = 0,
333                    .exclusive       = -1,
334                    .off             = 0,
335                    .flags           = UH_H1H,
336                    HEADERS("HTTP/1.1 302 Found\r\n\r\n"),
337                },
338            },
339        },
340    },
341
342    {   .frt_lineno = __LINE__,
343        .frt_fr_flags = 0,
344        .frt_buf    = {
345            /* Length: */       0x00, 0x00, 0x16,
346            /* Type: */         0x01,
347            /* Flags: */        HFHF_END_HEADERS|HFHF_PADDED,
348            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
349            /* Padding length */0x11,
350            /* Block fragment: */
351                                0x48, 0x82, 0x64, 0x02,
352            /* Padding: */      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
353                                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
354                                0xFF,
355        },
356        .frt_bufsz  = 9 + 1 + 4 + 17,
357        .frt_n_cb_vals = 1,
358        .frt_cb_vals = {
359            {
360                .type = CV_HEADERS,
361                .u.headers = {
362                    .stream_id       = 12345,
363                    .oth_stream_id   = 0,
364                    .weight          = 0,
365                    .exclusive       = -1,
366                    .off             = 0,
367                    .flags           = UH_H1H,
368                    HEADERS("HTTP/1.1 302 Found\r\n\r\n"),
369                },
370            },
371        },
372    },
373
374    {   .frt_lineno = __LINE__,
375        .frt_fr_flags = 0,
376        .frt_buf    = {
377            /* Length: */       0x00, 0x00, 0x1B,
378            /* Type: */         0x01,
379            /* Flags: */        HFHF_END_HEADERS|HFHF_PADDED|HFHF_PRIORITY|
380                                                            HFHF_END_STREAM,
381            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
382            /* Padding length */0x11,
383            /* Exclusive: */    0x80|
384            /* Dep Stream Id: */
385                                0x00, 0x00, 0x12, 0x34,
386            /* Weight: */       0xFF,
387            /* Block fragment: */
388                                0x48, 0x82, 0x64, 0x02,
389            /* Padding: */      0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
390                                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
391                                0xFF,
392            /* Length: */       0x00, 0x00, 0x05,
393            /* Type: */         HTTP_FRAME_PRIORITY,
394            /* Flags: */        0x00,
395            /* Stream Id: */    0x00, 0x00, 0x00, 0x39,
396            /* Dep Stream Id: */0x80, 0x00, 0x00, 0x19,
397            /* Weight: */       0x77,
398        },
399        .frt_bufsz  = 9 + 1 + 5 + 4 + 17
400                    + 9 + 5,
401        .frt_n_cb_vals = 2,
402        .frt_cb_vals = {
403            {
404                .type = CV_HEADERS,
405                .u.headers = {
406                    .stream_id       = 12345,
407                    .oth_stream_id   = 0x1234,
408                    .weight          = 0xFF + 1,
409                    .exclusive       = 1,
410                    .off             = 0,
411                    .flags           = UH_FIN | UH_H1H,
412                    HEADERS("HTTP/1.1 302 Found\r\n\r\n"),
413                },
414            },
415            {
416                .type = CV_PRIORITY,
417                .u.priority = {
418                    .stream_id      = 0x39,
419                    .exclusive      = 1,
420                    .dep_stream_id  = 0x19,
421                    .weight         = 0x77 + 1,
422                },
423            },
424        },
425    },
426
427    {   .frt_lineno = __LINE__,
428        .frt_fr_flags = 0,
429        .frt_buf    = {
430            /* Length: */       0x00, 0x00, 0x09,
431            /* Type: */         0x01,
432            /* Flags: */        HFHF_END_HEADERS|HFHF_PRIORITY,
433            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
434            /* Exclusive: */    0x00|
435            /* Dep Stream Id: */
436                                0x00, 0x00, 0x12, 0x34,
437            /* Weight: */       0x00,
438            /* Block fragment: */
439                                0x48, 0x82, 0x64, 0x02,
440        },
441        .frt_bufsz  = 9 + 5 + 4,
442        .frt_n_cb_vals = 1,
443        .frt_cb_vals = {
444            {
445                .type = CV_HEADERS,
446                .u.headers = {
447                    .stream_id       = 12345,
448                    .oth_stream_id   = 0x1234,
449                    .weight          = 1,
450                    .exclusive       = 0,
451                    .off             = 0,
452                    .flags           = UH_H1H,
453                    HEADERS("HTTP/1.1 302 Found\r\n\r\n"),
454                },
455            },
456        },
457    },
458
459    {   .frt_lineno = __LINE__,
460        .frt_fr_flags = 0,
461        .frt_buf    = {
462            /* Length: */       0x00, 0x00, 0x0E,
463            /* Type: */         0x01,
464            /* Flags: */        HFHF_END_HEADERS|HFHF_PRIORITY,
465            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
466            /* Exclusive: */    0x00|
467            /* Dep Stream Id: */
468                                0x00, 0x00, 0x12, 0x34,
469            /* Weight: */       0x00,
470            /* Block fragment: */
471                                0x48, 0x82, 0x64, 0x02,
472                                0x60, 0x03, 0x61, 0x3d, 0x62,
473        },
474        .frt_bufsz  = 9 + 5 + 4 + 5,
475        .frt_n_cb_vals = 1,
476        .frt_cb_vals = {
477            {
478                .type = CV_HEADERS,
479                .u.headers = {
480                    .stream_id       = 12345,
481                    .oth_stream_id   = 0x1234,
482                    .weight          = 1,
483                    .exclusive       = 0,
484                    .off             = 0,
485                    .flags           = UH_H1H,
486                    HEADERS("HTTP/1.1 302 Found\r\n"
487                               "Cookie: a=b\r\n\r\n"),
488                },
489            },
490        },
491    },
492
493    {   .frt_lineno = __LINE__,
494        .frt_fr_flags = 0,
495        .frt_buf    = {
496            /* Length: */       0x00, 0x00, 0x18,
497            /* Type: */         0x01,
498            /* Flags: */        HFHF_END_HEADERS|HFHF_PRIORITY,
499            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
500            /* Exclusive: */    0x00|
501            /* Dep Stream Id: */
502                                0x00, 0x00, 0x12, 0x34,
503            /* Weight: */       0x00,
504            /* Block fragment: */
505                                0x48, 0x82, 0x64, 0x02,
506                                0x60, 0x03, 0x61, 0x3d, 0x62,
507                                0x60, 0x03, 0x63, 0x3d, 0x64,
508                                0x60, 0x03, 0x65, 0x3d, 0x66,
509        },
510        .frt_bufsz  = 9 + 5 + 4 + 15,
511        .frt_n_cb_vals = 1,
512        .frt_cb_vals = {
513            {
514                .type = CV_HEADERS,
515                .u.headers = {
516                    .stream_id       = 12345,
517                    .oth_stream_id   = 0x1234,
518                    .weight          = 1,
519                    .exclusive       = 0,
520                    .off             = 0,
521                    .flags           = UH_H1H,
522                    HEADERS("HTTP/1.1 302 Found\r\n"
523                               "Cookie: a=b; c=d; e=f\r\n\r\n"),
524                },
525            },
526        },
527    },
528
529    {   .frt_lineno = __LINE__,
530        .frt_fr_flags = FRF_SERVER,
531        .frt_buf    = {
532            /* Length: */       0x00, 0x00, 0x16,
533            /* Type: */         0x01,
534            /* Flags: */        HFHF_END_HEADERS|HFHF_PRIORITY,
535            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
536            /* Exclusive: */    0x00|
537            /* Dep Stream Id: */
538                                0x00, 0x00, 0x12, 0x34,
539            /* Weight: */       0x00,
540            /* Block fragment: */
541                                0x82, 0x84, 0x86, 0x41, 0x8c, 0xf1, 0xe3, 0xc2,
542                                0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4,
543                                0xff,
544            /* Length: */       0x00, 0x00, 0xEE,
545            /* Type: */         HTTP_FRAME_CONTINUATION,
546            /* Flags: */        HFHF_END_HEADERS,
547            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
548            /* Block fragment: */
549                                'W', 'H', 'A', 'T', 'E', 'V', 'E', 'R',
550        },
551        .frt_bufsz  = 9 + 5 + 17
552                    + 9 + 0 + 8,
553        .frt_err = 1,
554        .frt_in_off = 9 + 5 + 17 + 9,
555        .frt_n_cb_vals = 1,
556        .frt_cb_vals = {
557            {
558                .type = CV_HEADERS,
559                .u.headers = {
560                    .stream_id       = 12345,
561                    .oth_stream_id   = 0x1234,
562                    .weight          = 1,
563                    .exclusive       = 0,
564                    .off             = 0,
565                    .flags           = UH_H1H,
566                    HEADERS("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"),
567                },
568            },
569        },
570    },
571
572    {   .frt_lineno = __LINE__,
573        .frt_fr_flags = FRF_SERVER,
574        .frt_buf    = {
575            /* Length: */       0x00, 0x00, 0x16,
576            /* Type: */         0x01,
577            /* Flags: */        HFHF_END_HEADERS|HFHF_PRIORITY,
578            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
579            /* Exclusive: */    0x00|
580            /* Dep Stream Id: */
581                                0x00, 0x00, 0x12, 0x34,
582            /* Weight: */       0x00,
583            /* Block fragment: */
584                                0x82, 0x84, 0x86, 0x41, 0x8c, 0xf1, 0xe3, 0xc2,
585                                0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4,
586                                0xff,
587            /* Length: */       0x00, 0x00, 0xEE,
588            /* Type: */         HTTP_FRAME_CONTINUATION,
589            /* Flags: */        HFHF_END_HEADERS,
590            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
591            /* Block fragment: */
592                                'W', 'H', 'A', 'T', 'E', 'V', 'E', 'R',
593        },
594        .frt_bufsz  = 9 + 5 + 17
595                    + 9 + 0 + 8,
596        .frt_err = 1,
597        .frt_in_off = 9 + 5 + 17 + 9,
598        .frt_n_cb_vals = 1,
599        .frt_cb_vals = {
600            {
601                .type = CV_HEADERS,
602                .u.headers = {
603                    .stream_id       = 12345,
604                    .oth_stream_id   = 0x1234,
605                    .weight          = 1,
606                    .exclusive       = 0,
607                    .off             = 0,
608                    .flags           = UH_H1H,
609                    HEADERS("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"),
610                },
611            },
612        },
613    },
614
615    {   .frt_lineno = __LINE__,
616        .frt_fr_flags = FRF_SERVER,
617        .frt_buf    = {
618            /* Length: */       0x00, 0x00, 0x16,
619            /* Type: */         0x01,
620            /* Flags: */        HFHF_PRIORITY,
621            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
622            /* Exclusive: */    0x00|
623            /* Dep Stream Id: */
624                                0x00, 0x00, 0x12, 0x34,
625            /* Weight: */       0x00,
626            /* Block fragment: */
627                                0x82, 0x84, 0x86, 0x41, 0x8c, 0xf1, 0xe3, 0xc2,
628                                0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4,
629                                0xff,
630            /* Length: */       0x00, 0x00, 0xEE,
631            /* Type: */         HTTP_FRAME_CONTINUATION,
632            /* Flags: */        HFHF_END_HEADERS,
633            /* Stream Id: */    0x00, 0xFF, 0x30, 0x39, /* Stream ID does not match */
634            /* Block fragment: */
635                                'W', 'H', 'A', 'T', 'E', 'V', 'E', 'R',
636        },
637        .frt_bufsz  = 9 + 5 + 17
638                    + 9 + 0 + 8,
639        .frt_err = 1,
640        .frt_in_off = 9 + 5 + 17 + 9,
641        .frt_n_cb_vals = 0,
642    },
643
644    {   .frt_lineno = __LINE__,
645        .frt_fr_flags = FRF_SERVER,
646        .frt_buf    = {
647            /* Length: */       0x00, 0x00, 0xEE,
648            /* Type: */         HTTP_FRAME_CONTINUATION,
649            /* Flags: */        HFHF_END_HEADERS,
650            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
651            /* Block fragment: */
652                                'W', 'H', 'A', 'T', 'E', 'V', 'E', 'R',
653        },
654        .frt_bufsz  = 9 + 0 + 8,
655        .frt_err = 1,
656        .frt_in_off = 9,
657        .frt_n_cb_vals = 0,
658    },
659
660    {   .frt_lineno = __LINE__,
661        .frt_fr_flags = FRF_SERVER,
662        .frt_buf    = {
663            /* Length: */       0x00, 0x00, 0x10,
664            /* Type: */         0x01,
665            /* Flags: */        0x00,   /* Note absence of HFHF_END_HEADERS */
666            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
667            /* Block fragment:
668             *   perl hpack.pl :method GET :path / host www.example.com
669             */
670                                0x82, 0x84, 0x66, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5,
671                                0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff,
672            /* Length: */       0x00, 0x00, 0x08,
673            /* Type: */         0x01,
674            /* Flags: */        HFHF_END_HEADERS,
675            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
676            /* Block fragment: */
677                                'W', 'H', 'A', 'T', 'E', 'V', 'E', 'R',
678        },
679        .frt_bufsz  = 9 + 0 + 16
680                    + 9 + 0 + 8,
681        .frt_in_off = 9 + 16 + 9,
682        .frt_err = 1,
683        .frt_n_cb_vals = 1,
684        .frt_cb_vals = {
685            {
686                .type = CV_ERROR,
687                .u.error = {
688                    .stream_id  = 0x3039,
689                    .code       = FR_ERR_EXPECTED_CONTIN,
690                },
691            },
692        },
693    },
694
695    {   .frt_lineno = __LINE__,
696        .frt_fr_flags = FRF_SERVER,
697        .frt_buf    = {
698            /* Length: */       0x00, 0x00, 0x10,
699            /* Type: */         0x01,
700            /* Flags: */        HFHF_END_HEADERS,
701            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
702            /* Block fragment:
703             *   perl hpack.pl :method GET :path / host www.example.com
704             */
705                                0x82, 0x84, 0x66, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5,
706                                0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff,
707            /* Length: */       0x00, 0x00, 0x1A,
708            /* Type: */         0x01,
709            /* Flags: */        HFHF_END_HEADERS|HFHF_PRIORITY,
710            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
711            /* Exclusive: */    0x00|
712            /* Dep Stream Id: */
713                                0x00, 0x00, 0x12, 0x34,
714            /* Weight: */       0x00,
715            /* Block fragment:
716             *   perl hpack.pl :method GET :path / :scheme http Host www.example.com
717             */
718                                0x82, 0x84, 0x86, 0x40, 0x83, 0xc6, 0x74, 0x27,
719                                0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b,
720                                0xa0, 0xab, 0x90, 0xf4, 0xff,
721            /* Length: */       0x00, 0x00, 0x11,
722            /* Type: */         0x01,
723            /* Flags: */        HFHF_END_HEADERS,
724            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
725            /* Block fragment: */
726                                0x82, 0x84, 0x86, 0x41, 0x8c, 0xf1, 0xe3, 0xc2,
727                                0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4,
728                                0xff,
729        },
730        .frt_bufsz  = 9 + 0 + 16
731                    + 9 + 5 + 21
732                    + 9 + 0 + 17,
733        .frt_n_cb_vals = 3,
734        .frt_cb_vals = {
735            {
736                .type = CV_ERROR,
737                .u.error = {
738                    .stream_id  = 12345,
739                    .code       = FR_ERR_BAD_HEADER,
740                },
741            },
742            {
743                .type = CV_ERROR,
744                .u.error = {
745                    .stream_id  = 12345,
746                    .code       = FR_ERR_BAD_HEADER,
747                },
748            },
749            {
750                .type = CV_HEADERS,
751                .u.headers = {
752                    .stream_id       = 12345,
753                    .oth_stream_id   = 0,
754                    .weight          = 0,
755                    .exclusive       = -1,
756                    .off             = 0,
757                    .flags           = UH_H1H,
758                    HEADERS("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"),
759                },
760            },
761        },
762    },
763
764    {   .frt_lineno = __LINE__,
765        .frt_fr_flags = 0,
766        .frt_buf    = {
767            /* Length: */       0x00, 0x00, 0x15,
768            /* Type: */         HTTP_FRAME_PUSH_PROMISE,
769            /* Flags: */        HFHF_END_HEADERS,
770            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
771            /* Dep stream Id: */0x00, 0x12, 0x34, 0x56,
772            /* Block fragment: */
773                                0x82, 0x84, 0x86, 0x41, 0x8c, 0xf1, 0xe3, 0xc2,
774                                0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4,
775                                0xff,
776        },
777        .frt_bufsz  = 9 + 0 + 0x15,
778        .frt_n_cb_vals = 1,
779        .frt_cb_vals = {
780            {
781                .type = CV_PUSH_PROMISE,
782                .u.headers = {
783                    .stream_id       = 12345,
784                    .oth_stream_id   = 0x123456,
785                    .flags           = UH_PP | UH_H1H,
786                    HEADERS("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"),
787                },
788            },
789        },
790    },
791
792    {   .frt_lineno = __LINE__,
793        .frt_fr_flags = 0,
794        .frt_buf    = {
795            /* Length: */       0x00, 0x00, 0x02,
796            /* Type: */         HTTP_FRAME_HEADERS,
797            /* Flags: */        0x00,
798                            0x80|           /* <----- This bit must be ignored */
799            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
800            /* Block fragment: */
801                                0x48, 0x82,
802            /* Length: */       0x00, 0x00, 0x02,
803            /* Type: */         HTTP_FRAME_CONTINUATION,
804            /* Flags: */        HFHF_END_HEADERS,
805            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
806            /* Block fragment: */
807                                0x64, 0x02,
808        },
809        .frt_bufsz  = 9 + 2 + 9 + 2,
810        .frt_n_cb_vals = 1,
811        .frt_cb_vals = {
812            {
813                .type = CV_HEADERS,
814                .u.headers = {
815                    .stream_id       = 12345,
816                    .oth_stream_id   = 0,
817                    .weight          = 0,
818                    .exclusive       = -1,
819                    .off             = 0,
820                    .flags           = UH_H1H,
821                    HEADERS("HTTP/1.1 302 Found\r\n\r\n"),
822                },
823            },
824        },
825    },
826
827    {   .frt_lineno = __LINE__,
828        .frt_fr_flags = 0,
829        .frt_buf    = {
830            /* Length: */       0x00, 0x00, 0x00,
831            /* Type: */         HTTP_FRAME_SETTINGS,
832            /* Flags: */        0x00,
833            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
834        },
835        .frt_bufsz  = 9,
836        .frt_n_cb_vals = 1,
837        .frt_err = 1,
838        .frt_cb_vals = {
839            {
840                .type = CV_ERROR,
841                .u.error.code = FR_ERR_INVALID_FRAME_SIZE,
842                .u.error.stream_id = 12345,
843            },
844        },
845    },
846
847    {   .frt_lineno = __LINE__,
848        .frt_fr_flags = 0,
849        .frt_buf    = {
850            /* Length: */       0x00, 0x00, 0x07,
851            /* Type: */         HTTP_FRAME_SETTINGS,
852            /* Flags: */        0x00,
853            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
854                                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
855        },
856        .frt_bufsz  = 9 + 7,
857        .frt_n_cb_vals = 1,
858        .frt_err = 1,
859        .frt_in_off = 9,
860        .frt_cb_vals = {
861            {
862                .type = CV_ERROR,
863                .u.error.code = FR_ERR_INVALID_FRAME_SIZE,
864                .u.error.stream_id = 12345,
865            },
866        },
867    },
868
869    {   .frt_lineno = __LINE__,
870        .frt_fr_flags = 0,
871        .frt_buf    = {
872            /* Length: */       0x00, 0x00, 0x06,
873            /* Type: */         HTTP_FRAME_SETTINGS,
874            /* Flags: */        0x00,
875            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
876                                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
877        },
878        .frt_bufsz  = 9 + 6,
879        .frt_n_cb_vals = 1,
880        .frt_err = 1,
881        .frt_in_off = 9,
882        .frt_cb_vals = {
883            {
884                .type = CV_ERROR,
885                .u.error.code = FR_ERR_NONZERO_STREAM_ID,
886                .u.error.stream_id = 12345,
887            },
888        },
889    },
890
891    {   .frt_lineno = __LINE__,
892        .frt_fr_flags = 0,
893        .frt_buf    = {
894            /* Length: */       0x00, 0x00, 0x0C,
895            /* Type: */         HTTP_FRAME_SETTINGS,
896            /* Flags: */        0x00,
897            /* Stream Id: */    0x00, 0x00, 0x00, 0x00,
898                                0x00, SETTINGS_INITIAL_WINDOW_SIZE,
899                                0x01, 0x02, 0x03, 0x04,
900                                0x00, SETTINGS_HEADER_TABLE_SIZE,
901                                0x02, 0x03, 0x04, 0x05,
902        },
903        .frt_bufsz  = 9 + 12,
904        .frt_n_cb_vals = 2,
905        .frt_cb_vals = {
906            {
907                .type = CV_SETTINGS,
908                .u.setting.id    = SETTINGS_INITIAL_WINDOW_SIZE,
909                .u.setting.value = 0x01020304,
910            },
911            {
912                .type = CV_SETTINGS,
913                .u.setting.id    = SETTINGS_HEADER_TABLE_SIZE,
914                .u.setting.value = 0x02030405,
915            },
916        },
917    },
918
919    {   .frt_lineno = __LINE__,
920        .frt_fr_flags = 0,
921        .frt_buf    = {
922            /* Length: */       0x00, 0x00, 0x09,
923            /* Type: */         0x01,
924            /* Flags: */        HFHF_END_HEADERS|HFHF_PRIORITY,
925            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
926            /* Exclusive: */    0x00|
927            /* Dep Stream Id: */
928                                0x00, 0x00, 0x12, 0x34,
929            /* Weight: */       0x00,
930            /* Block fragment: */
931                                0x48, 0x82, 0x64, 0x02,
932            /* Length: */       0x00, 0x00, 0x06,
933            /* Type: */         HTTP_FRAME_SETTINGS,
934            /* Flags: */        0x00,
935            /* Stream Id: */    0x00, 0x00, 0x00, 0x00,
936                                0x00, SETTINGS_INITIAL_WINDOW_SIZE,
937                                0x01, 0x02, 0x03, 0x04,
938        },
939        .frt_bufsz  = 9 + 5 + 4 + 9 + 6,
940        .frt_max_headers_sz = 10,
941        .frt_n_cb_vals = 2,
942        .frt_cb_vals = {
943            {
944                .type = CV_ERROR,
945                .stream_off = 9 + 5 + 4,
946                .u.error.code = FR_ERR_BAD_HEADER,
947                .u.error.stream_id = 12345,
948            },
949            {
950                .type = CV_SETTINGS,
951                .u.setting.id    = SETTINGS_INITIAL_WINDOW_SIZE,
952                .u.setting.value = 0x01020304,
953            },
954        },
955    },
956
957    {   .frt_lineno = __LINE__,
958        .frt_fr_flags = 0,
959        .frt_buf    = {
960            /* Length: */       0x00, 0x00, 0x11,
961            /* Type: */         0x01,
962            /* Flags: */        HFHF_END_HEADERS,
963            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
964            /* Block fragment: */
965                                /* 0x11 bytes of no consequence: they are not
966                                 * parsed.
967                                 */
968                                000, 001, 002, 003, 004, 005, 006, 007,
969                                010, 011, 012, 013, 014, 015, 016, 017,
970                                020,
971            /* Length: */       0x00, 0x00, 0x06,
972            /* Type: */         HTTP_FRAME_SETTINGS,
973            /* Flags: */        0x00,
974            /* Stream Id: */    0x00, 0x00, 0x00, 0x00,
975                                0x00, SETTINGS_INITIAL_WINDOW_SIZE,
976                                0x01, 0x02, 0x03, 0x04,
977        },
978        .frt_bufsz  = 9 + 0 + 0x11 + 9 + 6,
979        .frt_max_headers_sz = 0x10,
980        .frt_n_cb_vals = 2,
981        .frt_cb_vals = {
982            {
983                .type = CV_ERROR,
984                .stream_off = 9,
985                .u.error.code = FR_ERR_BAD_HEADER,
986                .u.error.stream_id = 12345,
987            },
988            {
989                .type = CV_SETTINGS,
990                .u.setting.id    = SETTINGS_INITIAL_WINDOW_SIZE,
991                .u.setting.value = 0x01020304,
992            },
993        },
994    },
995
996    {   .frt_lineno = __LINE__,
997        .frt_fr_flags = 0,
998        .frt_buf    = {
999            /* Length: */       0x00, 0x00, 0x10,
1000            /* Type: */         0x01,
1001            /* Flags: */        0x00,
1002            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
1003            /* Block fragment: */
1004                                /* 0x10 bytes of no consequence: they are not
1005                                 * parsed.
1006                                 */
1007                                000, 001, 002, 003, 004, 005, 006, 007,
1008                                010, 011, 012, 013, 014, 015, 016, 017,
1009            /* Length: */       0x00, 0x00, 0x10,
1010            /* Type: */         HTTP_FRAME_CONTINUATION,
1011            /* Flags: */        0x00,
1012            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
1013            /* Block fragment: */
1014                                000, 001, 002, 003, 004, 005, 006, 007,
1015                                010, 011, 012, 013, 014, 015, 016, 017,
1016            /* Length: */       0x00, 0x00, 0x10,
1017            /* Type: */         HTTP_FRAME_CONTINUATION,
1018            /* Flags: */        HFHF_END_HEADERS,
1019            /* Stream Id: */    0x00, 0x00, 0x30, 0x39,
1020            /* Block fragment: */
1021                                000, 001, 002, 003, 004, 005, 006, 007,
1022                                010, 011, 012, 013, 014, 015, 016, 017,
1023            /* Length: */       0x00, 0x00, 0x06,
1024            /* Type: */         HTTP_FRAME_SETTINGS,
1025            /* Flags: */        0x00,
1026            /* Stream Id: */    0x00, 0x00, 0x00, 0x00,
1027                                0x00, SETTINGS_INITIAL_WINDOW_SIZE,
1028                                0x01, 0x02, 0x03, 0x04,
1029        },
1030        .frt_bufsz  = 9 + 0 + 0x10 + 9 + 0 + 0x10 + 9 + 0 + 0x10 + 9 + 6,
1031        .frt_max_headers_sz = 0x19,
1032        .frt_n_cb_vals = 2,
1033        .frt_cb_vals = {
1034            {
1035                .type = CV_ERROR,
1036                .stream_off = 9 + 0 + 0x10 + 9,
1037                .u.error.code = FR_ERR_BAD_HEADER,
1038                .u.error.stream_id = 12345,
1039            },
1040            {
1041                .type = CV_SETTINGS,
1042                .u.setting.id    = SETTINGS_INITIAL_WINDOW_SIZE,
1043                .u.setting.value = 0x01020304,
1044            },
1045        },
1046    },
1047
1048    {   .frt_lineno = __LINE__,
1049        .frt_fr_flags = 0,
1050        .frt_buf    = {
1051            /* Length: */       0x00, 0x00,
1052                                            0x04,  /* <-- wrong payload size */
1053            /* Type: */         HTTP_FRAME_PRIORITY,
1054            /* Flags: */        0x00,
1055            /* Stream Id: */    0x00, 0x00, 0x00, 0x39,
1056            /* Dep Stream Id: */0x80, 0x00, 0x00, 0x19,
1057            /* Weight: */       0x77,
1058        },
1059        .frt_bufsz  = 9 + 5,
1060        .frt_n_cb_vals = 1,
1061        .frt_err = 1,
1062        .frt_in_off = 9,
1063        .frt_cb_vals = {
1064            {
1065                .type = CV_ERROR,
1066                .stream_off = 9,
1067                .u.error.code = FR_ERR_INVALID_FRAME_SIZE,
1068                .u.error.stream_id = 0x39,
1069            }
1070        },
1071    },
1072
1073    {   .frt_lineno = __LINE__,
1074        .frt_fr_flags = 0,
1075        .frt_buf    = {
1076            /* Length: */       0x00, 0x00, 0x05,
1077            /* Type: */         HTTP_FRAME_PRIORITY,
1078            /* Flags: */        0x00,
1079            /* Stream Id: */    0x00, 0x00, 0x00, 0x00, /* Invalid stream ID */
1080            /* Dep Stream Id: */0x80, 0x00, 0x00, 0x19,
1081            /* Weight: */       0x77,
1082        },
1083        .frt_bufsz  = 9 + 5,
1084        .frt_n_cb_vals = 1,
1085        .frt_err = 1,
1086        .frt_in_off = 9,
1087        .frt_cb_vals = {
1088            {
1089                .type = CV_ERROR,
1090                .stream_off = 9,
1091                .u.error.code = FR_ERR_ZERO_STREAM_ID,
1092                .u.error.stream_id = 0x00,
1093            }
1094        },
1095    },
1096
1097    {
1098        .frt_bufsz  = 0,
1099    },
1100};
1101
1102
1103static struct lsquic_stream *
1104my_get_stream_by_id (struct lsquic_conn *conn, lsquic_stream_id_t stream_id)
1105{
1106    return (void *) my_get_stream_by_id;
1107}
1108
1109
1110static void
1111test_one_frt (const struct frame_reader_test *frt)
1112{
1113    struct lsquic_frame_reader *fr;
1114    unsigned short exp_off;
1115    struct lshpack_dec hdec;
1116    struct lsquic_mm mm;
1117    struct lsquic_conn lconn;
1118    struct lsquic_conn_public conn_pub;
1119    struct lsquic_stream stream;
1120    int s;
1121    struct conn_iface my_conn_if;
1122
1123#if LSQUIC_CONN_STATS
1124    struct conn_stats conn_stats;
1125    memset(&conn_stats, 0, sizeof(conn_stats));
1126#endif
1127
1128    memset(&stream, 0, sizeof(stream));
1129    memset(&lconn, 0, sizeof(lconn));
1130    memset(&conn_pub, 0, sizeof(conn_pub));
1131    memset(&my_conn_if, 0, sizeof(my_conn_if));
1132    my_conn_if.ci_get_stream_by_id = my_get_stream_by_id;
1133    lconn.cn_if = &my_conn_if;
1134    stream.conn_pub = &conn_pub;
1135    conn_pub.lconn = &lconn;
1136
1137  top:
1138    lsquic_mm_init(&mm);
1139    lshpack_dec_init(&hdec);
1140    memset(&input, 0, sizeof(input));
1141    memcpy(input.in_buf, frt->frt_buf, frt->frt_bufsz);
1142    input.in_sz  = frt->frt_bufsz;
1143
1144    do
1145    {
1146        reset_cb_ctx(&g_cb_ctx);
1147        input.in_off = 0;
1148        ++input.in_max_sz;
1149
1150        fr = lsquic_frame_reader_new(frt->frt_fr_flags, frt->frt_max_headers_sz,
1151                &mm, &stream, read_from_stream, &hdec, &frame_callbacks, &g_cb_ctx,
1152#if LSQUIC_CONN_STATS
1153                &conn_stats,
1154#endif
1155                lsquic_http1x_if, NULL);
1156        do
1157        {
1158            s = lsquic_frame_reader_read(fr);
1159            if (s != 0)
1160                break;
1161        }
1162        while (input.in_off < input.in_sz);
1163
1164        assert(frt->frt_err || 0 == s);
1165
1166        if (my_conn_if.ci_get_stream_by_id)
1167        {
1168            assert(g_cb_ctx.n_cb_vals == frt->frt_n_cb_vals);
1169
1170            unsigned i;
1171            for (i = 0; i < g_cb_ctx.n_cb_vals; ++i)
1172                compare_cb_vals(&g_cb_ctx.cb_vals[i], &frt->frt_cb_vals[i]);
1173        }
1174
1175        exp_off = frt->frt_in_off;
1176        if (!exp_off)
1177            exp_off = frt->frt_bufsz;
1178        assert(input.in_off == exp_off);
1179
1180        lsquic_frame_reader_destroy(fr);
1181    }
1182    while (input.in_max_sz < input.in_max_req_sz);
1183    lshpack_dec_cleanup(&hdec);
1184
1185    if (!(frt->frt_fr_flags & FRF_SERVER) && my_conn_if.ci_get_stream_by_id)
1186    {
1187        /* Do it again, but this time test header block skip logic */
1188        my_conn_if.ci_get_stream_by_id = NULL;
1189        goto top;
1190    }
1191
1192    lsquic_mm_cleanup(&mm);
1193}
1194
1195
1196int
1197main (int argc, char **argv)
1198{
1199    int opt;
1200
1201    while (-1 != (opt = getopt(argc, argv, "l:")))
1202    {
1203        switch (opt)
1204        {
1205        case 'l':
1206            lsquic_log_to_fstream(stderr, LLTS_NONE);
1207            lsquic_logger_lopt(optarg);
1208            break;
1209        default:
1210            exit(1);
1211        }
1212    }
1213
1214    const struct frame_reader_test *frt;
1215    for (frt = tests; frt->frt_bufsz > 0; ++frt)
1216        test_one_frt(frt);
1217    return 0;
1218}
1219