test_send_headers.c revision 2f2f4363
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    /* OK, we did not read FIN, expect these flags: */
344    assert((stream->sm_qflags & (SMQF_SEND_STOP_SENDING|SMQF_WAIT_FIN_OFF)) == (SMQF_SEND_STOP_SENDING|SMQF_WAIT_FIN_OFF));
345    lsquic_stream_ss_frame_sent(stream);
346    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
347    assert(0 == stream->sm_n_buffered);
348    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Still set */
349    s_enc_off = 10;   /* Encoder is done writing */
350    lsquic_stream_dispatch_write_events(stream);
351    assert(stream->sm_qflags & SMQF_CALL_ONCLOSE);
352    lsquic_stream_acked(stream, QUIC_FRAME_STREAM);
353    lsquic_stream_call_on_close(stream);
354    assert(!(stream->sm_qflags & SMQF_FREE_STREAM));    /* Not yet */
355    lsquic_stream_rst_in(stream, 0, 0);
356    assert(!(stream->sm_qflags & (SMQF_SEND_STOP_SENDING|SMQF_WAIT_FIN_OFF)));
357    assert(stream->sm_qflags & SMQF_FREE_STREAM);
358    lsquic_stream_destroy(stream);
359
360    deinit_test_objs(&tobjs);
361}
362
363
364static void
365test_headers_wantwrite_restoration (const int want_write)
366{
367    struct test_objs tobjs;
368    struct lsquic_stream *stream;
369    ssize_t nw;
370    int s;
371    struct uncompressed_headers *uh;
372    void *hset;
373
374    s_call_wantwrite_in_ctor = 1;
375    s_wantwrite_arg = want_write;
376
377    /* For our tests purposes, we treat headers as an opaque object */
378    struct lsquic_http_headers *headers = (void *) 1;
379
380    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
381
382    /* Mock server side stream cycle */
383
384    stream = new_stream(&tobjs, 4 * __LINE__, 0x1000);
385    uh = calloc(1, sizeof(*uh));
386    *uh = (struct uncompressed_headers) {
387        .uh_stream_id   = stream->id,
388        .uh_weight      = 127,
389        .uh_hset        = (void *) 12345,
390    };
391    s = lsquic_stream_uh_in(stream, uh);
392    assert(s == 0);
393    hset = lsquic_stream_get_hset(stream);
394    assert(hset == (void *) 12345);
395    stream->stream_flags |= STREAM_FIN_RECVD;   /* Pretend we received FIN */
396    s = lsquic_stream_shutdown(stream, 0);
397    assert(0 == s);
398    test_vals.status = QWH_PARTIAL;
399    test_vals.prefix_sz = 2;
400    test_vals.headers_sz = 40;
401    test_vals.completion_offset = 10;
402    assert(want_write == !!(stream->sm_qflags & SMQF_WANT_WRITE));
403    s = lsquic_stream_send_headers(stream, headers, 0);
404    assert(0 == s);
405    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
406    assert(0 == stream->sm_n_buffered);
407    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
408    nw = lsquic_stream_write(stream, "hello", 5);
409    assert(0 == nw);
410    s = lsquic_stream_flush(stream);
411    assert(s == 0);
412    s = lsquic_stream_close(stream);
413    assert(s == 0);
414    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
415    assert(0 == stream->sm_n_buffered);
416    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Still set */
417    s_enc_off = 10;   /* Encoder is done writing */
418    lsquic_stream_dispatch_write_events(stream);
419    assert(stream->sm_qflags & SMQF_CALL_ONCLOSE);
420    lsquic_stream_acked(stream, QUIC_FRAME_STREAM);
421    lsquic_stream_call_on_close(stream);
422    assert(stream->sm_qflags & SMQF_FREE_STREAM);
423    lsquic_stream_destroy(stream);
424
425    stream = new_stream(&tobjs, 4 * __LINE__, 0x1000);
426    uh = calloc(1, sizeof(*uh));
427    *uh = (struct uncompressed_headers) {
428        .uh_stream_id   = stream->id,
429        .uh_weight      = 127,
430        .uh_hset        = (void *) 12345,
431    };
432    s = lsquic_stream_uh_in(stream, uh);
433    assert(s == 0);
434    hset = lsquic_stream_get_hset(stream);
435    assert(hset == (void *) 12345);
436    s = lsquic_stream_shutdown(stream, 0);
437    assert(0 == s);
438    test_vals.status = QWH_PARTIAL;
439    test_vals.prefix_sz = 2;
440    test_vals.headers_sz = 40;
441    test_vals.completion_offset = 10;
442    assert(want_write == !!(stream->sm_qflags & SMQF_WANT_WRITE));
443    s = lsquic_stream_send_headers(stream, headers, 0);
444    assert(0 == s);
445    assert(stream->sm_hblock_sz == test_vals.prefix_sz + test_vals.headers_sz);
446    assert(0 == stream->sm_n_buffered);
447    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
448    s_enc_off = 10;   /* Encoder is done writing */
449    lsquic_stream_dispatch_write_events(stream);
450    assert(0 == stream->sm_hblock_sz);  /* Wrote header */
451    assert(want_write == s_onwrite_called);
452    lsquic_stream_destroy(stream);
453
454    deinit_test_objs(&tobjs);
455    s_call_wantwrite_in_ctor = 0;
456    s_wantwrite_arg = 0;
457    s_onwrite_called = 0;
458}
459
460
461static void
462test_pp_wantwrite_restoration (const int want_write)
463{
464    struct test_objs tobjs;
465    struct lsquic_stream *stream;
466    int s;
467    struct uncompressed_headers *uh;
468    struct push_promise *promise;
469    void *hset;
470
471    s_call_wantwrite_in_ctor = 1;
472    s_wantwrite_arg = want_write;
473
474    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
475
476    /* Mock server side stream cycle */
477
478    stream = new_stream(&tobjs, 4 * __LINE__, 10);
479    uh = calloc(1, sizeof(*uh));
480    *uh = (struct uncompressed_headers) {
481        .uh_stream_id   = stream->id,
482        .uh_weight      = 127,
483        .uh_hset        = (void *) 12345,
484    };
485    s = lsquic_stream_uh_in(stream, uh);
486    assert(s == 0);
487    hset = lsquic_stream_get_hset(stream);
488    assert(hset == (void *) 12345);
489    s = lsquic_stream_shutdown(stream, 0);
490    assert(0 == s);
491    promise = calloc(1, sizeof(*promise) + 20);
492    promise->pp_id = 0;
493    promise->pp_content_len = 20;
494    assert(want_write == !!(stream->sm_qflags & SMQF_WANT_WRITE));
495    s = lsquic_stream_push_promise(stream, promise);
496    assert(s == 0);
497    assert((stream->stream_flags & (STREAM_NOPUSH|STREAM_PUSHING))
498                                        == (STREAM_NOPUSH|STREAM_PUSHING));
499    assert(stream->sm_qflags & SMQF_WANT_WRITE);    /* Want write is now set */
500    /* Dispatch: there should be no progress made */
501    lsquic_stream_dispatch_write_events(stream);
502    assert((stream->stream_flags & (STREAM_NOPUSH|STREAM_PUSHING))
503                                        == (STREAM_NOPUSH|STREAM_PUSHING));
504    assert(stream->sm_qflags & SMQF_WANT_WRITE);
505    assert(SLIST_FIRST(&stream->sm_promises)->pp_write_state != PPWS_DONE);
506    /* Now update window and dispatch again */
507    lsquic_stream_window_update(stream, 100);
508    lsquic_stream_dispatch_write_events(stream);
509    assert((stream->stream_flags & (STREAM_NOPUSH|STREAM_PUSHING))
510                                        == (STREAM_NOPUSH|STREAM_PUSHING));
511    assert(SLIST_FIRST(&stream->sm_promises)->pp_write_state == PPWS_DONE); /* Done! */
512    assert(want_write == s_onwrite_called); /* Restored: and on_write called */
513
514    lsquic_stream_destroy(stream);
515    deinit_test_objs(&tobjs);
516    s_call_wantwrite_in_ctor = 0;
517    s_wantwrite_arg = 0;
518    s_onwrite_called = 0;
519}
520
521
522/* Create a new stream frame.  Each stream frame has a real packet_in to
523 * back it up, just like in real code.  The contents of the packet do
524 * not matter.
525 */
526static stream_frame_t *
527new_frame_in_ext (struct test_objs *tobjs, size_t off, size_t sz, int fin,
528                                                            const void *data)
529{
530    lsquic_packet_in_t *packet_in;
531    stream_frame_t *frame;
532
533    assert(sz <= 1370);
534
535    packet_in = lsquic_mm_get_packet_in(&tobjs->eng_pub.enp_mm);
536    if (data)
537        packet_in->pi_data = (void *) data;
538    else
539    {
540        packet_in->pi_data = lsquic_mm_get_packet_in_buf(&tobjs->eng_pub.enp_mm, 1370);
541        packet_in->pi_flags |= PI_OWN_DATA;
542        memset(packet_in->pi_data, 'A', sz);
543    }
544    /* This is not how stream frame looks in the packet: we have no
545     * header.  In our test case it does not matter, as we only care
546     * about stream frame.
547     */
548    packet_in->pi_data_sz = sz;
549    packet_in->pi_refcnt = 1;
550
551    frame = lsquic_malo_get(tobjs->eng_pub.enp_mm.malo.stream_frame);
552    memset(frame, 0, sizeof(*frame));
553    frame->packet_in = packet_in;
554    frame->data_frame.df_offset = off;
555    frame->data_frame.df_size = sz;
556    frame->data_frame.df_data = &packet_in->pi_data[0];
557    frame->data_frame.df_fin  = fin;
558
559    return frame;
560}
561
562
563static stream_frame_t *
564new_frame_in (struct test_objs *tobjs, size_t off, size_t sz, int fin)
565{
566    return new_frame_in_ext(tobjs, off, sz, fin, NULL);
567}
568
569
570/* Test that reading from stream returns -1/EWOULDBLOCK if no headers are
571 * available.
572 */
573static void
574test_read_headers (int ietf, int use_hset)
575{
576    struct test_objs tobjs;
577    struct lsquic_stream *stream;
578    struct stream_frame *frame;
579    ssize_t nr;
580    int s;
581    void *hset;
582    unsigned char buf[1];
583
584    init_test_objs(&tobjs, 0x1000, 0x1000, ietf ? SCF_IETF : 0);
585
586    stream = new_stream(&tobjs, 0, 0x1000);
587    frame = new_frame_in(&tobjs, 0, 35, 1);
588    s = lsquic_stream_frame_in(stream, frame);
589    assert(s == 0);
590
591    if (use_hset)
592    {
593        hset = lsquic_stream_get_hset(stream);
594        assert(NULL == hset);
595    }
596    else
597    {
598        nr = lsquic_stream_read(stream, buf, sizeof(buf));
599        assert(-1 == nr);
600        /* In GQUIC mode, the error is that the headers are no available yet.
601         * In IETF mode, the error is that we hit EOF unexpectedly -- as headers
602         * are sent on the same stream in HEADERS frame.
603         */
604        if (!ietf)
605            assert(EWOULDBLOCK == errno);
606    }
607
608    lsquic_stream_destroy(stream);
609
610    deinit_test_objs(&tobjs);
611}
612
613
614static void
615test_read_headers_http1x (void)
616{
617    struct test_objs tobjs;
618    struct lsquic_stream *stream;
619    struct stream_frame *frame;
620    int s;
621    const unsigned char headers_frame[5] = {
622        0x01,   /* Headers frame */
623        0x03,   /* Frame length */
624        0x00,
625        0x00,
626        0xC0 | 25   /* :status 200 */,
627    };
628    ssize_t nr;
629    unsigned char buf[0x100];
630
631    init_test_objs(&tobjs, 0x1000, 0x1000, SCF_IETF);
632
633    stream = new_stream(&tobjs, 0, 0x1000);
634    frame = new_frame_in(&tobjs, 0, sizeof(headers_frame), 1);
635    memcpy((unsigned char *) frame->data_frame.df_data, headers_frame,
636                                                    sizeof(headers_frame));
637    s = lsquic_stream_frame_in(stream, frame);
638    assert(s == 0);
639
640    assert(stream->stream_flags & STREAM_FIN_REACHED);
641    s = lsquic_stream_readable(stream);
642
643    nr = lsquic_stream_read(stream, buf, sizeof(buf));
644    assert(nr > 0);
645    assert(nr == 19);
646    assert(0 == memcmp(buf, "HTTP/1.1 200 OK\r\n\r\n", nr));
647
648    lsquic_stream_destroy(stream);
649
650    deinit_test_objs(&tobjs);
651}
652
653
654int
655main (int argc, char **argv)
656{
657    int opt;
658
659    lsquic_global_init(LSQUIC_GLOBAL_SERVER);
660
661    while (-1 != (opt = getopt(argc, argv, "l:")))
662    {
663        switch (opt)
664        {
665        case 'l':
666            lsquic_log_to_fstream(stderr, 0);
667            lsquic_logger_lopt(optarg);
668            break;
669        default:
670            exit(1);
671        }
672    }
673
674    test_flushes_and_closes();
675    test_headers_wantwrite_restoration(0);
676    test_headers_wantwrite_restoration(1);
677    test_pp_wantwrite_restoration(0);
678    test_pp_wantwrite_restoration(1);
679    test_read_headers(0, 0);
680    test_read_headers(0, 1);
681    test_read_headers(1, 0);
682    test_read_headers(1, 1);
683    test_read_headers_http1x();
684
685    return 0;
686}
687