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