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