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