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