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