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