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