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