test_send_headers.c revision 9a690580
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
146
147static const struct conn_iface our_conn_if =
148{
149    .ci_can_write_ack = unit_test_doesnt_write_ack,
150    .ci_get_path      = get_network_path,
151};
152
153
154static struct http1x_ctor_ctx ctor_ctx = { .is_server = 0, };
155
156
157static void
158init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window,
159        unsigned initial_stream_window, enum stream_ctor_flags addl_ctor_flags)
160{
161    int s;
162    memset(tobjs, 0, sizeof(*tobjs));
163    LSCONN_INITIALIZE(&tobjs->lconn);
164    tobjs->lconn.cn_pf = select_pf_by_ver(LSQVER_ID25);
165    tobjs->lconn.cn_version = LSQVER_ID25;
166    tobjs->lconn.cn_esf_c = &lsquic_enc_session_common_ietf_v1;
167    network_path.np_pack_size = IQUIC_MAX_IPv4_PACKET_SZ;
168    tobjs->lconn.cn_if = &our_conn_if;
169    lsquic_mm_init(&tobjs->eng_pub.enp_mm);
170    TAILQ_INIT(&tobjs->conn_pub.sending_streams);
171    TAILQ_INIT(&tobjs->conn_pub.read_streams);
172    TAILQ_INIT(&tobjs->conn_pub.write_streams);
173    TAILQ_INIT(&tobjs->conn_pub.service_streams);
174    lsquic_cfcw_init(&tobjs->conn_pub.cfcw, &tobjs->conn_pub,
175                                                    initial_conn_window);
176    lsquic_conn_cap_init(&tobjs->conn_pub.conn_cap, initial_conn_window);
177    lsquic_alarmset_init(&tobjs->alset, 0);
178    tobjs->conn_pub.mm = &tobjs->eng_pub.enp_mm;
179    tobjs->conn_pub.lconn = &tobjs->lconn;
180    tobjs->conn_pub.enpub = &tobjs->eng_pub;
181    tobjs->conn_pub.send_ctl = &tobjs->send_ctl;
182    tobjs->conn_pub.packet_out_malo =
183                        lsquic_malo_create(sizeof(struct lsquic_packet_out));
184    tobjs->conn_pub.path = &network_path;
185    tobjs->initial_stream_window = initial_stream_window;
186    lsquic_send_ctl_init(&tobjs->send_ctl, &tobjs->alset, &tobjs->eng_pub,
187        &tobjs->ver_neg, &tobjs->conn_pub, 0);
188    tobjs->stream_if = &stream_if;
189    tobjs->stream_if_ctx = NULL;
190    tobjs->ctor_flags = SCF_CALL_ON_NEW|SCF_DI_AUTOSWITCH|SCF_HTTP
191                      |addl_ctor_flags;
192    if ((1 << tobjs->lconn.cn_version) & LSQUIC_IETF_VERSIONS)
193    {
194        lsquic_qeh_init(&tobjs->qeh, &tobjs->lconn);
195        s = lsquic_qeh_settings(&tobjs->qeh, 0, 0, 0, 0);
196        assert(0 == s);
197        tobjs->conn_pub.u.ietf.qeh = &tobjs->qeh;
198        tobjs->conn_pub.enpub->enp_hsi_if  = lsquic_http1x_if;
199        tobjs->conn_pub.enpub->enp_hsi_ctx = &ctor_ctx;
200        s = lsquic_qdh_init(&tobjs->qdh, &tobjs->lconn, 0,
201                                    tobjs->conn_pub.enpub, 0, 0);
202        tobjs->conn_pub.u.ietf.qdh = &tobjs->qdh;
203        assert(0 == s);
204    }
205}
206
207
208static void
209deinit_test_objs (struct test_objs *tobjs)
210{
211    assert(!lsquic_malo_first(tobjs->eng_pub.enp_mm.malo.stream_frame));
212    lsquic_send_ctl_cleanup(&tobjs->send_ctl);
213    lsquic_malo_destroy(tobjs->conn_pub.packet_out_malo);
214    lsquic_mm_cleanup(&tobjs->eng_pub.enp_mm);
215    if ((1 << tobjs->lconn.cn_version) & LSQUIC_IETF_VERSIONS)
216    {
217        lsquic_qeh_cleanup(&tobjs->qeh);
218        lsquic_qdh_cleanup(&tobjs->qdh);
219    }
220}
221
222
223static struct lsquic_stream *
224new_stream (struct test_objs *tobjs, unsigned stream_id, uint64_t send_off)
225{
226    return lsquic_stream_new(stream_id, &tobjs->conn_pub, tobjs->stream_if,
227        tobjs->stream_if_ctx, tobjs->initial_stream_window, send_off,
228        tobjs->ctor_flags);
229}
230
231static struct test_vals {
232    /* What lsquic_qeh_write_headers() returns or sets */
233    enum qwh_status     status;
234    size_t              prefix_sz;
235    size_t              headers_sz;
236    uint64_t            completion_offset;
237} test_vals;
238
239
240enum qwh_status
241lsquic_qeh_write_headers (struct qpack_enc_hdl *qeh,
242    lsquic_stream_id_t stream_id, unsigned seqno,
243    const struct lsquic_http_headers *headers, unsigned char *buf,
244    size_t *prefix_sz, size_t *headers_sz, uint64_t *completion_offset,
245    enum lsqpack_enc_header_flags *hflags)
246{
247    memset(buf - *prefix_sz, 0xC5, *prefix_sz + *headers_sz);
248    *prefix_sz = test_vals.prefix_sz;
249    *headers_sz = test_vals.headers_sz;
250    *completion_offset = test_vals.completion_offset;
251    if (hflags)
252        *hflags = 0;
253    return test_vals.status;
254}
255
256
257static uint64_t s_enc_off;
258
259uint64_t
260lsquic_qeh_enc_off (struct qpack_enc_hdl *qeh)
261{
262    return s_enc_off;
263}
264
265
266static void
267test_flushes_and_closes (void)
268{
269    struct test_objs tobjs;
270    struct lsquic_stream *stream;
271    ssize_t nw;
272    int s;
273    struct uncompressed_headers *uh;
274    void *hset;
275
276    /* For our tests purposes, we treat headers as an opaque object */
277    struct lsquic_http_headers *headers = (void *) 1;
278
279    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
280
281    stream = new_stream(&tobjs, 0, 0x1000);
282    test_vals.status = QWH_FULL;
283    test_vals.prefix_sz = 2;
284    test_vals.headers_sz = 40;
285    test_vals.completion_offset = 0;
286    s = lsquic_stream_send_headers(stream, headers, 0);
287    assert(0 == s);
288    assert(stream->sm_n_buffered == test_vals.prefix_sz + test_vals.headers_sz);
289    assert(0 == stream->sm_hblock_sz);
290    lsquic_stream_destroy(stream);
291
292    stream = new_stream(&tobjs, 4, 0x1000);
293    test_vals.status = QWH_PARTIAL;
294    test_vals.prefix_sz = 2;
295    test_vals.headers_sz = 40;
296    test_vals.completion_offset = 10;
297    s = lsquic_stream_send_headers(stream, headers, 0);
298    assert(0 == s);
299    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
300    assert(0 == stream->sm_n_buffered);
301    nw = lsquic_stream_write(stream, "hello", 5);
302    assert(0 == nw);
303    s = lsquic_stream_flush(stream);
304    assert(s == 0);
305    lsquic_stream_destroy(stream);
306
307    /* Mock server side stream cycle */
308    stream = new_stream(&tobjs, 8, 0x1000);
309    uh = calloc(1, sizeof(*uh));
310    *uh = (struct uncompressed_headers) {
311        .uh_stream_id   = stream->id,
312        .uh_weight      = 127,
313        .uh_hset        = (void *) 12345,
314    };
315    s = lsquic_stream_uh_in(stream, uh);
316    assert(s == 0);
317    hset = lsquic_stream_get_hset(stream);
318    assert(hset == (void *) 12345);
319    s = lsquic_stream_shutdown(stream, 0);
320    assert(0 == s);
321    test_vals.status = QWH_PARTIAL;
322    test_vals.prefix_sz = 2;
323    test_vals.headers_sz = 40;
324    test_vals.completion_offset = 10;
325    assert(!(stream->sm_qflags & SMQF_WANT_WRITE)); /* Begin with them off */
326    s = lsquic_stream_send_headers(stream, headers, 0);
327    assert(0 == s);
328    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
329    assert(0 == stream->sm_n_buffered);
330    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
331    nw = lsquic_stream_write(stream, "hello", 5);
332    assert(0 == nw);
333    s = lsquic_stream_flush(stream);
334    assert(s == 0);
335    s = lsquic_stream_close(stream);
336    assert(s == 0);
337    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
338    assert(0 == stream->sm_n_buffered);
339    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Still set */
340    s_enc_off = 10;   /* Encoder is done writing */
341    lsquic_stream_dispatch_write_events(stream);
342    assert(stream->sm_qflags & SMQF_CALL_ONCLOSE);
343    lsquic_stream_acked(stream, QUIC_FRAME_STREAM);
344    lsquic_stream_call_on_close(stream);
345    assert(stream->sm_qflags & SMQF_FREE_STREAM);
346    lsquic_stream_destroy(stream);
347
348    deinit_test_objs(&tobjs);
349}
350
351
352static void
353test_headers_wantwrite_restoration (const int want_write)
354{
355    struct test_objs tobjs;
356    struct lsquic_stream *stream;
357    ssize_t nw;
358    int s;
359    struct uncompressed_headers *uh;
360    void *hset;
361
362    s_call_wantwrite_in_ctor = 1;
363    s_wantwrite_arg = want_write;
364
365    /* For our tests purposes, we treat headers as an opaque object */
366    struct lsquic_http_headers *headers = (void *) 1;
367
368    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
369
370    /* Mock server side stream cycle */
371
372    stream = new_stream(&tobjs, 4 * __LINE__, 0x1000);
373    uh = calloc(1, sizeof(*uh));
374    *uh = (struct uncompressed_headers) {
375        .uh_stream_id   = stream->id,
376        .uh_weight      = 127,
377        .uh_hset        = (void *) 12345,
378    };
379    s = lsquic_stream_uh_in(stream, uh);
380    assert(s == 0);
381    hset = lsquic_stream_get_hset(stream);
382    assert(hset == (void *) 12345);
383    s = lsquic_stream_shutdown(stream, 0);
384    assert(0 == s);
385    test_vals.status = QWH_PARTIAL;
386    test_vals.prefix_sz = 2;
387    test_vals.headers_sz = 40;
388    test_vals.completion_offset = 10;
389    assert(want_write == !!(stream->sm_qflags & SMQF_WANT_WRITE));
390    s = lsquic_stream_send_headers(stream, headers, 0);
391    assert(0 == s);
392    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
393    assert(0 == stream->sm_n_buffered);
394    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
395    nw = lsquic_stream_write(stream, "hello", 5);
396    assert(0 == nw);
397    s = lsquic_stream_flush(stream);
398    assert(s == 0);
399    s = lsquic_stream_close(stream);
400    assert(s == 0);
401    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
402    assert(0 == stream->sm_n_buffered);
403    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Still set */
404    s_enc_off = 10;   /* Encoder is done writing */
405    lsquic_stream_dispatch_write_events(stream);
406    assert(stream->sm_qflags & SMQF_CALL_ONCLOSE);
407    lsquic_stream_acked(stream, QUIC_FRAME_STREAM);
408    lsquic_stream_call_on_close(stream);
409    assert(stream->sm_qflags & SMQF_FREE_STREAM);
410    lsquic_stream_destroy(stream);
411
412    stream = new_stream(&tobjs, 4 * __LINE__, 0x1000);
413    uh = calloc(1, sizeof(*uh));
414    *uh = (struct uncompressed_headers) {
415        .uh_stream_id   = stream->id,
416        .uh_weight      = 127,
417        .uh_hset        = (void *) 12345,
418    };
419    s = lsquic_stream_uh_in(stream, uh);
420    assert(s == 0);
421    hset = lsquic_stream_get_hset(stream);
422    assert(hset == (void *) 12345);
423    s = lsquic_stream_shutdown(stream, 0);
424    assert(0 == s);
425    test_vals.status = QWH_PARTIAL;
426    test_vals.prefix_sz = 2;
427    test_vals.headers_sz = 40;
428    test_vals.completion_offset = 10;
429    assert(want_write == !!(stream->sm_qflags & SMQF_WANT_WRITE));
430    s = lsquic_stream_send_headers(stream, headers, 0);
431    assert(0 == s);
432    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
433    assert(0 == stream->sm_n_buffered);
434    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
435    s_enc_off = 10;   /* Encoder is done writing */
436    lsquic_stream_dispatch_write_events(stream);
437    assert(0 == stream->sm_hblock_sz);  /* Wrote header */
438    assert(want_write == s_onwrite_called);
439    lsquic_stream_destroy(stream);
440
441    deinit_test_objs(&tobjs);
442    s_call_wantwrite_in_ctor = 0;
443    s_wantwrite_arg = 0;
444    s_onwrite_called = 0;
445}
446
447
448static void
449test_pp_wantwrite_restoration (const int want_write)
450{
451    struct test_objs tobjs;
452    struct lsquic_stream *stream;
453    int s;
454    struct uncompressed_headers *uh;
455    struct push_promise *promise;
456    void *hset;
457
458    s_call_wantwrite_in_ctor = 1;
459    s_wantwrite_arg = want_write;
460
461    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
462
463    /* Mock server side stream cycle */
464
465    stream = new_stream(&tobjs, 4 * __LINE__, 10);
466    uh = calloc(1, sizeof(*uh));
467    *uh = (struct uncompressed_headers) {
468        .uh_stream_id   = stream->id,
469        .uh_weight      = 127,
470        .uh_hset        = (void *) 12345,
471    };
472    s = lsquic_stream_uh_in(stream, uh);
473    assert(s == 0);
474    hset = lsquic_stream_get_hset(stream);
475    assert(hset == (void *) 12345);
476    s = lsquic_stream_shutdown(stream, 0);
477    assert(0 == s);
478    promise = calloc(1, sizeof(*promise) + 20);
479    promise->pp_id = 0;
480    promise->pp_content_len = 20;
481    assert(want_write == !!(stream->sm_qflags & SMQF_WANT_WRITE));
482    s = lsquic_stream_push_promise(stream, promise);
483    assert(s == 0);
484    assert((stream->stream_flags & (STREAM_NOPUSH|STREAM_PUSHING))
485                                        == (STREAM_NOPUSH|STREAM_PUSHING));
486    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
487    /* Dispatch: there should be no progress made */
488    lsquic_stream_dispatch_write_events(stream);
489    assert((stream->stream_flags & (STREAM_NOPUSH|STREAM_PUSHING))
490                                        == (STREAM_NOPUSH|STREAM_PUSHING));
491    assert(stream->sm_qflags & SMQF_WANT_WRITE);
492    assert(SLIST_FIRST(&stream->sm_promises)->pp_write_state != PPWS_DONE);
493    /* Now update window and dispatch again */
494    lsquic_stream_window_update(stream, 100);
495    lsquic_stream_dispatch_write_events(stream);
496    assert((stream->stream_flags & (STREAM_NOPUSH|STREAM_PUSHING))
497                                        == (STREAM_NOPUSH|STREAM_PUSHING));
498    assert(SLIST_FIRST(&stream->sm_promises)->pp_write_state == PPWS_DONE); /* Done! */
499    assert(want_write == s_onwrite_called); /* Restored: and on_write called */
500
501    lsquic_stream_destroy(stream);
502    deinit_test_objs(&tobjs);
503    s_call_wantwrite_in_ctor = 0;
504    s_wantwrite_arg = 0;
505    s_onwrite_called = 0;
506}
507
508
509/* Create a new stream frame.  Each stream frame has a real packet_in to
510 * back it up, just like in real code.  The contents of the packet do
511 * not matter.
512 */
513static stream_frame_t *
514new_frame_in_ext (struct test_objs *tobjs, size_t off, size_t sz, int fin,
515                                                            const void *data)
516{
517    lsquic_packet_in_t *packet_in;
518    stream_frame_t *frame;
519
520    assert(sz <= 1370);
521
522    packet_in = lsquic_mm_get_packet_in(&tobjs->eng_pub.enp_mm);
523    if (data)
524        packet_in->pi_data = (void *) data;
525    else
526    {
527        packet_in->pi_data = lsquic_mm_get_packet_in_buf(&tobjs->eng_pub.enp_mm, 1370);
528        packet_in->pi_flags |= PI_OWN_DATA;
529        memset(packet_in->pi_data, 'A', sz);
530    }
531    /* This is not how stream frame looks in the packet: we have no
532     * header.  In our test case it does not matter, as we only care
533     * about stream frame.
534     */
535    packet_in->pi_data_sz = sz;
536    packet_in->pi_refcnt = 1;
537
538    frame = lsquic_malo_get(tobjs->eng_pub.enp_mm.malo.stream_frame);
539    memset(frame, 0, sizeof(*frame));
540    frame->packet_in = packet_in;
541    frame->data_frame.df_offset = off;
542    frame->data_frame.df_size = sz;
543    frame->data_frame.df_data = &packet_in->pi_data[0];
544    frame->data_frame.df_fin  = fin;
545
546    return frame;
547}
548
549
550static stream_frame_t *
551new_frame_in (struct test_objs *tobjs, size_t off, size_t sz, int fin)
552{
553    return new_frame_in_ext(tobjs, off, sz, fin, NULL);
554}
555
556
557/* Test that reading from stream returns -1/EWOULDBLOCK if no headers are
558 * available.
559 */
560static void
561test_read_headers (int ietf, int use_hset)
562{
563    struct test_objs tobjs;
564    struct lsquic_stream *stream;
565    struct stream_frame *frame;
566    ssize_t nr;
567    int s;
568    void *hset;
569    unsigned char buf[1];
570
571    init_test_objs(&tobjs, 0x1000, 0x1000, ietf ? SCF_IETF : 0);
572
573    stream = new_stream(&tobjs, 0, 0x1000);
574    frame = new_frame_in(&tobjs, 0, 35, 1);
575    s = lsquic_stream_frame_in(stream, frame);
576    assert(s == 0);
577
578    if (use_hset)
579    {
580        hset = lsquic_stream_get_hset(stream);
581        assert(NULL == hset);
582    }
583    else
584    {
585        nr = lsquic_stream_read(stream, buf, sizeof(buf));
586        assert(-1 == nr);
587        /* In GQUIC mode, the error is that the headers are no available yet.
588         * In IETF mode, the error is that we hit EOF unexpectedly -- as headers
589         * are sent on the same stream in HEADERS frame.
590         */
591        if (!ietf)
592            assert(EWOULDBLOCK == errno);
593    }
594
595    lsquic_stream_destroy(stream);
596
597    deinit_test_objs(&tobjs);
598}
599
600
601static void
602test_read_headers_http1x (void)
603{
604    struct test_objs tobjs;
605    struct lsquic_stream *stream;
606    struct stream_frame *frame;
607    int s;
608    const unsigned char headers_frame[5] = {
609        0x01,   /* Headers frame */
610        0x03,   /* Frame length */
611        0x00,
612        0x00,
613        0xC0 | 25   /* :status 200 */,
614    };
615    ssize_t nr;
616    unsigned char buf[0x100];
617
618    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
619
620    stream = new_stream(&tobjs, 0, 0x1000);
621    frame = new_frame_in(&tobjs, 0, sizeof(headers_frame), 1);
622    memcpy((unsigned char *) frame->data_frame.df_data, headers_frame,
623                                                    sizeof(headers_frame));
624    s = lsquic_stream_frame_in(stream, frame);
625    assert(s == 0);
626
627    assert(stream->stream_flags & STREAM_FIN_REACHED);
628    s = lsquic_stream_readable(stream);
629
630    nr = lsquic_stream_read(stream, buf, sizeof(buf));
631    assert(nr > 0);
632    assert(nr == 19);
633    assert(0 == memcmp(buf, "HTTP/1.1 200 OK\r\n\r\n", nr));
634
635    lsquic_stream_destroy(stream);
636
637    deinit_test_objs(&tobjs);
638}
639
640
641int
642main (int argc, char **argv)
643{
644    int opt;
645
646    lsquic_global_init(LSQUIC_GLOBAL_SERVER);
647
648    while (-1 != (opt = getopt(argc, argv, "l:")))
649    {
650        switch (opt)
651        {
652        case 'l':
653            lsquic_log_to_fstream(stderr, 0);
654            lsquic_logger_lopt(optarg);
655            break;
656        default:
657            exit(1);
658        }
659    }
660
661    test_flushes_and_closes();
662    test_headers_wantwrite_restoration(0);
663    test_headers_wantwrite_restoration(1);
664    test_pp_wantwrite_restoration(0);
665    test_pp_wantwrite_restoration(1);
666    test_read_headers(0, 0);
667    test_read_headers(0, 1);
668    test_read_headers(1, 0);
669    test_read_headers(1, 1);
670    test_read_headers_http1x();
671
672    return 0;
673}
674