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