test_send_headers.c revision 8ae5ecb4
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * test_send_headers.c -- Test what happens when lsquic_stream_send_headers()
4 * is called.
5 */
6
7#include <assert.h>
8#include <errno.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/queue.h>
13#include <sys/types.h>
14#include <fcntl.h>
15#include <limits.h>
16#ifndef WIN32
17#include <unistd.h>
18#else
19#include <getopt.h>
20#endif
21
22#include "lsquic.h"
23
24#include "lsquic_packet_common.h"
25#include "lsquic_packet_ietf.h"
26#include "lsquic_alarmset.h"
27#include "lsquic_packet_in.h"
28#include "lsquic_conn_flow.h"
29#include "lsquic_rtt.h"
30#include "lsquic_sfcw.h"
31#include "lsquic_varint.h"
32#include "lsquic_hq.h"
33#include "lsquic_hash.h"
34#include "lsquic_stream.h"
35#include "lsquic_types.h"
36#include "lsquic_malo.h"
37#include "lsquic_mm.h"
38#include "lsquic_conn_public.h"
39#include "lsquic_logger.h"
40#include "lsquic_parse.h"
41#include "lsquic_conn.h"
42#include "lsquic_engine_public.h"
43#include "lsquic_cubic.h"
44#include "lsquic_pacer.h"
45#include "lsquic_senhist.h"
46#include "lsquic_bw_sampler.h"
47#include "lsquic_minmax.h"
48#include "lsquic_bbr.h"
49#include "lsquic_send_ctl.h"
50#include "lsquic_ver_neg.h"
51#include "lsquic_packet_out.h"
52#include "lsquic_enc_sess.h"
53#include "lsqpack.h"
54#include "lsquic_frab_list.h"
55#include "lsquic_http1x_if.h"
56#include "lsquic_qdec_hdl.h"
57#include "lsquic_qenc_hdl.h"
58#include "lsquic_varint.h"
59#include "lsquic_hq.h"
60#include "lsquic_data_in_if.h"
61#include "lsquic_headers.h"
62#include "lsquic_push_promise.h"
63
64static int s_call_wantwrite_in_ctor;
65static int s_wantwrite_arg;
66static int s_onwrite_called;
67
68static lsquic_stream_ctx_t *
69on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
70{
71    if (s_call_wantwrite_in_ctor)
72        lsquic_stream_wantwrite(stream, s_wantwrite_arg);
73    return NULL;
74}
75
76
77static void
78on_close (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
79{
80}
81
82
83static void
84on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *h)
85{
86    s_onwrite_called = 1;
87    lsquic_stream_wantwrite(stream, 0);
88}
89
90
91const struct lsquic_stream_if stream_if = {
92    .on_new_stream          = on_new_stream,
93    .on_write               = on_write,
94    .on_close               = on_close,
95};
96
97
98enum buf_packet_type
99lsquic_send_ctl_determine_bpt (struct lsquic_send_ctl *ctl,
100                                        const struct lsquic_stream *stream)
101{
102    return BPT_HIGHEST_PRIO;
103}
104
105
106/* This function is only here to avoid crash in the test: */
107void
108lsquic_engine_add_conn_to_tickable (struct lsquic_engine_public *enpub,
109                                    lsquic_conn_t *conn)
110{
111}
112
113
114struct test_objs {
115    struct lsquic_engine_public eng_pub;
116    struct lsquic_conn        lconn;
117    struct lsquic_conn_public conn_pub;
118    struct lsquic_send_ctl    send_ctl;
119    struct lsquic_alarmset    alset;
120    void                     *stream_if_ctx;
121    struct ver_neg            ver_neg;
122    const struct lsquic_stream_if *
123                              stream_if;
124    unsigned                  initial_stream_window;
125    enum stream_ctor_flags    ctor_flags;
126    struct qpack_enc_hdl      qeh;
127    struct qpack_dec_hdl      qdh;
128};
129
130
131static int
132unit_test_doesnt_write_ack (struct lsquic_conn *lconn)
133{
134    return 0;
135}
136
137
138static struct network_path network_path;
139
140static struct network_path *
141get_network_path (struct lsquic_conn *lconn, const struct sockaddr *sa)
142{
143    return &network_path;
144}
145
146static void
147abort_error (struct lsquic_conn *lconn, int is_app,
148                                unsigned error_code, const char *fmt, ...)
149{
150}
151
152static const struct conn_iface our_conn_if =
153{
154    .ci_can_write_ack = unit_test_doesnt_write_ack,
155    .ci_get_path      = get_network_path,
156    .ci_abort_error   = abort_error,
157};
158
159
160static struct http1x_ctor_ctx ctor_ctx = { .is_server = 0, };
161
162
163static void
164init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window,
165        unsigned initial_stream_window, enum stream_ctor_flags addl_ctor_flags)
166{
167    int s;
168    memset(tobjs, 0, sizeof(*tobjs));
169    LSCONN_INITIALIZE(&tobjs->lconn);
170    tobjs->lconn.cn_pf = select_pf_by_ver(LSQVER_ID27);
171    tobjs->lconn.cn_version = LSQVER_ID27;
172    tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_ietf_v1;
173    network_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ;
174    tobjs->lconn.cn_if = &our_conn_if;
175    lsquic_mm_init(&tobjs->eng_pub.enp_mm);
176    TAILQ_INIT(&tobjs->conn_pub.sending_streams);
177    TAILQ_INIT(&tobjs->conn_pub.read_streams);
178    TAILQ_INIT(&tobjs->conn_pub.write_streams);
179    TAILQ_INIT(&tobjs->conn_pub.service_streams);
180    lsquic_cfcw_init(&tobjs->conn_pub.cfcw, &tobjs->conn_pub,
181                                                    initial_conn_window);
182    lsquic_conn_cap_init(&tobjs->conn_pub.conn_cap, initial_conn_window);
183    lsquic_alarmset_init(&tobjs->alset, 0);
184    tobjs->conn_pub.mm = &tobjs->eng_pub.enp_mm;
185    tobjs->conn_pub.lconn = &tobjs->lconn;
186    tobjs->conn_pub.enpub = &tobjs->eng_pub;
187    tobjs->conn_pub.send_ctl = &tobjs->send_ctl;
188    tobjs->conn_pub.packet_out_malo =
189                        lsquic_malo_create(sizeof(struct lsquic_packet_out));
190    tobjs->conn_pub.path = &network_path;
191    tobjs->initial_stream_window = initial_stream_window;
192    lsquic_send_ctl_init(&tobjs->send_ctl, &tobjs->alset, &tobjs->eng_pub,
193        &tobjs->ver_neg, &tobjs->conn_pub, 0);
194    tobjs->stream_if = &stream_if;
195    tobjs->stream_if_ctx = NULL;
196    tobjs->ctor_flags = SCF_CALL_ON_NEW|SCF_DI_AUTOSWITCH|SCF_HTTP
197                      |addl_ctor_flags;
198    if ((1 << tobjs->lconn.cn_version) & LSQUIC_IETF_VERSIONS)
199    {
200        lsquic_qeh_init(&tobjs->qeh, &tobjs->lconn);
201        s = lsquic_qeh_settings(&tobjs->qeh, 0, 0, 0, 0);
202        assert(0 == s);
203        tobjs->conn_pub.u.ietf.qeh = &tobjs->qeh;
204        tobjs->conn_pub.enpub->enp_hsi_if  = lsquic_http1x_if;
205        tobjs->conn_pub.enpub->enp_hsi_ctx = &ctor_ctx;
206        s = lsquic_qdh_init(&tobjs->qdh, &tobjs->lconn, 0,
207                                    tobjs->conn_pub.enpub, 0, 0);
208        tobjs->conn_pub.u.ietf.qdh = &tobjs->qdh;
209        assert(0 == s);
210    }
211}
212
213
214static void
215deinit_test_objs (struct test_objs *tobjs)
216{
217    assert(!lsquic_malo_first(tobjs->eng_pub.enp_mm.malo.stream_frame));
218    lsquic_send_ctl_cleanup(&tobjs->send_ctl);
219    lsquic_malo_destroy(tobjs->conn_pub.packet_out_malo);
220    lsquic_mm_cleanup(&tobjs->eng_pub.enp_mm);
221    if ((1 << tobjs->lconn.cn_version) & LSQUIC_IETF_VERSIONS)
222    {
223        lsquic_qeh_cleanup(&tobjs->qeh);
224        lsquic_qdh_cleanup(&tobjs->qdh);
225    }
226}
227
228
229static struct lsquic_stream *
230new_stream (struct test_objs *tobjs, unsigned stream_id, uint64_t send_off)
231{
232    return lsquic_stream_new(stream_id, &tobjs->conn_pub, tobjs->stream_if,
233        tobjs->stream_if_ctx, tobjs->initial_stream_window, send_off,
234        tobjs->ctor_flags);
235}
236
237static struct test_vals {
238    /* What lsquic_qeh_write_headers() returns or sets */
239    enum qwh_status     status;
240    size_t              prefix_sz;
241    size_t              headers_sz;
242    uint64_t            completion_offset;
243} test_vals;
244
245
246enum qwh_status
247lsquic_qeh_write_headers (struct qpack_enc_hdl *qeh,
248    lsquic_stream_id_t stream_id, unsigned seqno,
249    const struct lsquic_http_headers *headers, unsigned char *buf,
250    size_t *prefix_sz, size_t *headers_sz, uint64_t *completion_offset,
251    enum lsqpack_enc_header_flags *hflags)
252{
253    memset(buf - *prefix_sz, 0xC5, *prefix_sz + *headers_sz);
254    *prefix_sz = test_vals.prefix_sz;
255    *headers_sz = test_vals.headers_sz;
256    *completion_offset = test_vals.completion_offset;
257    if (hflags)
258        *hflags = 0;
259    return test_vals.status;
260}
261
262
263static uint64_t s_enc_off;
264
265uint64_t
266lsquic_qeh_enc_off (struct qpack_enc_hdl *qeh)
267{
268    return s_enc_off;
269}
270
271
272static void
273test_flushes_and_closes (void)
274{
275    struct test_objs tobjs;
276    struct lsquic_stream *stream;
277    ssize_t nw;
278    int s;
279    struct uncompressed_headers *uh;
280    void *hset;
281
282    /* For our tests purposes, we treat headers as an opaque object */
283    struct lsquic_http_headers *headers = (void *) 1;
284
285    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
286
287    stream = new_stream(&tobjs, 0, 0x1000);
288    test_vals.status = QWH_FULL;
289    test_vals.prefix_sz = 2;
290    test_vals.headers_sz = 40;
291    test_vals.completion_offset = 0;
292    s = lsquic_stream_send_headers(stream, headers, 0);
293    assert(0 == s);
294    assert(stream->sm_n_buffered == test_vals.prefix_sz + test_vals.headers_sz);
295    assert(0 == stream->sm_hblock_sz);
296    lsquic_stream_destroy(stream);
297
298    stream = new_stream(&tobjs, 4, 0x1000);
299    test_vals.status = QWH_PARTIAL;
300    test_vals.prefix_sz = 2;
301    test_vals.headers_sz = 40;
302    test_vals.completion_offset = 10;
303    s = lsquic_stream_send_headers(stream, headers, 0);
304    assert(0 == s);
305    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
306    assert(0 == stream->sm_n_buffered);
307    nw = lsquic_stream_write(stream, "hello", 5);
308    assert(0 == nw);
309    s = lsquic_stream_flush(stream);
310    assert(s == 0);
311    lsquic_stream_destroy(stream);
312
313    /* Mock server side stream cycle */
314    stream = new_stream(&tobjs, 8, 0x1000);
315    uh = calloc(1, sizeof(*uh));
316    *uh = (struct uncompressed_headers) {
317        .uh_stream_id   = stream->id,
318        .uh_weight      = 127,
319        .uh_hset        = (void *) 12345,
320    };
321    s = lsquic_stream_uh_in(stream, uh);
322    assert(s == 0);
323    hset = lsquic_stream_get_hset(stream);
324    assert(hset == (void *) 12345);
325    s = lsquic_stream_shutdown(stream, 0);
326    assert(0 == s);
327    test_vals.status = QWH_PARTIAL;
328    test_vals.prefix_sz = 2;
329    test_vals.headers_sz = 40;
330    test_vals.completion_offset = 10;
331    assert(!(stream->sm_qflags & SMQF_WANT_WRITE)); /* Begin with them off */
332    s = lsquic_stream_send_headers(stream, headers, 0);
333    assert(0 == s);
334    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
335    assert(0 == stream->sm_n_buffered);
336    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
337    nw = lsquic_stream_write(stream, "hello", 5);
338    assert(0 == nw);
339    s = lsquic_stream_flush(stream);
340    assert(s == 0);
341    s = lsquic_stream_close(stream);
342    assert(s == 0);
343    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
344    assert(0 == stream->sm_n_buffered);
345    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Still set */
346    s_enc_off = 10;   /* Encoder is done writing */
347    lsquic_stream_dispatch_write_events(stream);
348    assert(stream->sm_qflags & SMQF_CALL_ONCLOSE);
349    lsquic_stream_acked(stream, QUIC_FRAME_STREAM);
350    lsquic_stream_call_on_close(stream);
351    assert(stream->sm_qflags & SMQF_FREE_STREAM);
352    lsquic_stream_destroy(stream);
353
354    deinit_test_objs(&tobjs);
355}
356
357
358static void
359test_headers_wantwrite_restoration (const int want_write)
360{
361    struct test_objs tobjs;
362    struct lsquic_stream *stream;
363    ssize_t nw;
364    int s;
365    struct uncompressed_headers *uh;
366    void *hset;
367
368    s_call_wantwrite_in_ctor = 1;
369    s_wantwrite_arg = want_write;
370
371    /* For our tests purposes, we treat headers as an opaque object */
372    struct lsquic_http_headers *headers = (void *) 1;
373
374    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
375
376    /* Mock server side stream cycle */
377
378    stream = new_stream(&tobjs, 4 * __LINE__, 0x1000);
379    uh = calloc(1, sizeof(*uh));
380    *uh = (struct uncompressed_headers) {
381        .uh_stream_id   = stream->id,
382        .uh_weight      = 127,
383        .uh_hset        = (void *) 12345,
384    };
385    s = lsquic_stream_uh_in(stream, uh);
386    assert(s == 0);
387    hset = lsquic_stream_get_hset(stream);
388    assert(hset == (void *) 12345);
389    s = lsquic_stream_shutdown(stream, 0);
390    assert(0 == s);
391    test_vals.status = QWH_PARTIAL;
392    test_vals.prefix_sz = 2;
393    test_vals.headers_sz = 40;
394    test_vals.completion_offset = 10;
395    assert(want_write == !!(stream->sm_qflags & SMQF_WANT_WRITE));
396    s = lsquic_stream_send_headers(stream, headers, 0);
397    assert(0 == s);
398    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
399    assert(0 == stream->sm_n_buffered);
400    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
401    nw = lsquic_stream_write(stream, "hello", 5);
402    assert(0 == nw);
403    s = lsquic_stream_flush(stream);
404    assert(s == 0);
405    s = lsquic_stream_close(stream);
406    assert(s == 0);
407    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
408    assert(0 == stream->sm_n_buffered);
409    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Still set */
410    s_enc_off = 10;   /* Encoder is done writing */
411    lsquic_stream_dispatch_write_events(stream);
412    assert(stream->sm_qflags & SMQF_CALL_ONCLOSE);
413    lsquic_stream_acked(stream, QUIC_FRAME_STREAM);
414    lsquic_stream_call_on_close(stream);
415    assert(stream->sm_qflags & SMQF_FREE_STREAM);
416    lsquic_stream_destroy(stream);
417
418    stream = new_stream(&tobjs, 4 * __LINE__, 0x1000);
419    uh = calloc(1, sizeof(*uh));
420    *uh = (struct uncompressed_headers) {
421        .uh_stream_id   = stream->id,
422        .uh_weight      = 127,
423        .uh_hset        = (void *) 12345,
424    };
425    s = lsquic_stream_uh_in(stream, uh);
426    assert(s == 0);
427    hset = lsquic_stream_get_hset(stream);
428    assert(hset == (void *) 12345);
429    s = lsquic_stream_shutdown(stream, 0);
430    assert(0 == s);
431    test_vals.status = QWH_PARTIAL;
432    test_vals.prefix_sz = 2;
433    test_vals.headers_sz = 40;
434    test_vals.completion_offset = 10;
435    assert(want_write == !!(stream->sm_qflags & SMQF_WANT_WRITE));
436    s = lsquic_stream_send_headers(stream, headers, 0);
437    assert(0 == s);
438    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
439    assert(0 == stream->sm_n_buffered);
440    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
441    s_enc_off = 10;   /* Encoder is done writing */
442    lsquic_stream_dispatch_write_events(stream);
443    assert(0 == stream->sm_hblock_sz);  /* Wrote header */
444    assert(want_write == s_onwrite_called);
445    lsquic_stream_destroy(stream);
446
447    deinit_test_objs(&tobjs);
448    s_call_wantwrite_in_ctor = 0;
449    s_wantwrite_arg = 0;
450    s_onwrite_called = 0;
451}
452
453
454static void
455test_pp_wantwrite_restoration (const int want_write)
456{
457    struct test_objs tobjs;
458    struct lsquic_stream *stream;
459    int s;
460    struct uncompressed_headers *uh;
461    struct push_promise *promise;
462    void *hset;
463
464    s_call_wantwrite_in_ctor = 1;
465    s_wantwrite_arg = want_write;
466
467    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
468
469    /* Mock server side stream cycle */
470
471    stream = new_stream(&tobjs, 4 * __LINE__, 10);
472    uh = calloc(1, sizeof(*uh));
473    *uh = (struct uncompressed_headers) {
474        .uh_stream_id   = stream->id,
475        .uh_weight      = 127,
476        .uh_hset        = (void *) 12345,
477    };
478    s = lsquic_stream_uh_in(stream, uh);
479    assert(s == 0);
480    hset = lsquic_stream_get_hset(stream);
481    assert(hset == (void *) 12345);
482    s = lsquic_stream_shutdown(stream, 0);
483    assert(0 == s);
484    promise = calloc(1, sizeof(*promise) + 20);
485    promise->pp_id = 0;
486    promise->pp_content_len = 20;
487    assert(want_write == !!(stream->sm_qflags & SMQF_WANT_WRITE));
488    s = lsquic_stream_push_promise(stream, promise);
489    assert(s == 0);
490    assert((stream->stream_flags & (STREAM_NOPUSH|STREAM_PUSHING))
491                                        == (STREAM_NOPUSH|STREAM_PUSHING));
492    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
493    /* Dispatch: there should be no progress made */
494    lsquic_stream_dispatch_write_events(stream);
495    assert((stream->stream_flags & (STREAM_NOPUSH|STREAM_PUSHING))
496                                        == (STREAM_NOPUSH|STREAM_PUSHING));
497    assert(stream->sm_qflags & SMQF_WANT_WRITE);
498    assert(SLIST_FIRST(&stream->sm_promises)->pp_write_state != PPWS_DONE);
499    /* Now update window and dispatch again */
500    lsquic_stream_window_update(stream, 100);
501    lsquic_stream_dispatch_write_events(stream);
502    assert((stream->stream_flags & (STREAM_NOPUSH|STREAM_PUSHING))
503                                        == (STREAM_NOPUSH|STREAM_PUSHING));
504    assert(SLIST_FIRST(&stream->sm_promises)->pp_write_state == PPWS_DONE); /* Done! */
505    assert(want_write == s_onwrite_called); /* Restored: and on_write called */
506
507    lsquic_stream_destroy(stream);
508    deinit_test_objs(&tobjs);
509    s_call_wantwrite_in_ctor = 0;
510    s_wantwrite_arg = 0;
511    s_onwrite_called = 0;
512}
513
514
515/* Create a new stream frame.  Each stream frame has a real packet_in to
516 * back it up, just like in real code.  The contents of the packet do
517 * not matter.
518 */
519static stream_frame_t *
520new_frame_in_ext (struct test_objs *tobjs, size_t off, size_t sz, int fin,
521                                                            const void *data)
522{
523    lsquic_packet_in_t *packet_in;
524    stream_frame_t *frame;
525
526    assert(sz <= 1370);
527
528    packet_in = lsquic_mm_get_packet_in(&tobjs->eng_pub.enp_mm);
529    if (data)
530        packet_in->pi_data = (void *) data;
531    else
532    {
533        packet_in->pi_data = lsquic_mm_get_packet_in_buf(&tobjs->eng_pub.enp_mm, 1370);
534        packet_in->pi_flags |= PI_OWN_DATA;
535        memset(packet_in->pi_data, 'A', sz);
536    }
537    /* This is not how stream frame looks in the packet: we have no
538     * header.  In our test case it does not matter, as we only care
539     * about stream frame.
540     */
541    packet_in->pi_data_sz = sz;
542    packet_in->pi_refcnt = 1;
543
544    frame = lsquic_malo_get(tobjs->eng_pub.enp_mm.malo.stream_frame);
545    memset(frame, 0, sizeof(*frame));
546    frame->packet_in = packet_in;
547    frame->data_frame.df_offset = off;
548    frame->data_frame.df_size = sz;
549    frame->data_frame.df_data = &packet_in->pi_data[0];
550    frame->data_frame.df_fin  = fin;
551
552    return frame;
553}
554
555
556static stream_frame_t *
557new_frame_in (struct test_objs *tobjs, size_t off, size_t sz, int fin)
558{
559    return new_frame_in_ext(tobjs, off, sz, fin, NULL);
560}
561
562
563/* Test that reading from stream returns -1/EWOULDBLOCK if no headers are
564 * available.
565 */
566static void
567test_read_headers (int ietf, int use_hset)
568{
569    struct test_objs tobjs;
570    struct lsquic_stream *stream;
571    struct stream_frame *frame;
572    ssize_t nr;
573    int s;
574    void *hset;
575    unsigned char buf[1];
576
577    init_test_objs(&tobjs, 0x1000, 0x1000, ietf ? SCF_IETF : 0);
578
579    stream = new_stream(&tobjs, 0, 0x1000);
580    frame = new_frame_in(&tobjs, 0, 35, 1);
581    s = lsquic_stream_frame_in(stream, frame);
582    assert(s == 0);
583
584    if (use_hset)
585    {
586        hset = lsquic_stream_get_hset(stream);
587        assert(NULL == hset);
588    }
589    else
590    {
591        nr = lsquic_stream_read(stream, buf, sizeof(buf));
592        assert(-1 == nr);
593        /* In GQUIC mode, the error is that the headers are no available yet.
594         * In IETF mode, the error is that we hit EOF unexpectedly -- as headers
595         * are sent on the same stream in HEADERS frame.
596         */
597        if (!ietf)
598            assert(EWOULDBLOCK == errno);
599    }
600
601    lsquic_stream_destroy(stream);
602
603    deinit_test_objs(&tobjs);
604}
605
606
607static void
608test_read_headers_http1x (void)
609{
610    struct test_objs tobjs;
611    struct lsquic_stream *stream;
612    struct stream_frame *frame;
613    int s;
614    const unsigned char headers_frame[5] = {
615        0x01,   /* Headers frame */
616        0x03,   /* Frame length */
617        0x00,
618        0x00,
619        0xC0 | 25   /* :status 200 */,
620    };
621    ssize_t nr;
622    unsigned char buf[0x100];
623
624    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
625
626    stream = new_stream(&tobjs, 0, 0x1000);
627    frame = new_frame_in(&tobjs, 0, sizeof(headers_frame), 1);
628    memcpy((unsigned char *) frame->data_frame.df_data, headers_frame,
629                                                    sizeof(headers_frame));
630    s = lsquic_stream_frame_in(stream, frame);
631    assert(s == 0);
632
633    assert(stream->stream_flags & STREAM_FIN_REACHED);
634    s = lsquic_stream_readable(stream);
635
636    nr = lsquic_stream_read(stream, buf, sizeof(buf));
637    assert(nr > 0);
638    assert(nr == 19);
639    assert(0 == memcmp(buf, "HTTP/1.1 200 OK\r\n\r\n", nr));
640
641    lsquic_stream_destroy(stream);
642
643    deinit_test_objs(&tobjs);
644}
645
646
647int
648main (int argc, char **argv)
649{
650    int opt;
651
652    lsquic_global_init(LSQUIC_GLOBAL_SERVER);
653
654    while (-1 != (opt = getopt(argc, argv, "l:")))
655    {
656        switch (opt)
657        {
658        case 'l':
659            lsquic_log_to_fstream(stderr, 0);
660            lsquic_logger_lopt(optarg);
661            break;
662        default:
663            exit(1);
664        }
665    }
666
667    test_flushes_and_closes();
668    test_headers_wantwrite_restoration(0);
669    test_headers_wantwrite_restoration(1);
670    test_pp_wantwrite_restoration(0);
671    test_pp_wantwrite_restoration(1);
672    test_read_headers(0, 0);
673    test_read_headers(0, 1);
674    test_read_headers(1, 0);
675    test_read_headers(1, 1);
676    test_read_headers_http1x();
677
678    return 0;
679}
680