test_send_headers.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 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