test_frame_reader.c revision a74702c6
1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 2#include <assert.h> 3#include <errno.h> 4#include <stdio.h> 5#include <stdlib.h> 6#include <string.h> 7#ifndef WIN32 8#include <unistd.h> 9#else 10#include <getopt.h> 11#endif 12#include <sys/queue.h> 13 14#include "lsquic.h" 15#include "lsquic_frame_common.h" 16#include "lshpack.h" 17#include "lsquic_mm.h" 18#include "lsquic_int_types.h" 19#include "lsquic_conn_flow.h" 20#include "lsquic_sfcw.h" 21#include "lsquic_rtt.h" 22#include "lsquic_hash.h" 23#include "lsquic_conn.h" 24#include "lsquic_varint.h" 25#include "lsquic_hq.h" 26#include "lsquic_stream.h" 27#include "lsquic_conn_public.h" 28#include "lsquic_logger.h" 29#if LSQUIC_CONN_STATS 30#include "lsquic_int_types.h" 31#include "lsquic_conn.h" 32#endif 33 34#include "lsquic_frame_reader.h" 35#include "lsquic_headers.h" 36#include "lsquic_http1x_if.h" 37 38 39struct callback_value /* What callback returns */ 40{ 41 enum { 42 CV_HEADERS, 43 CV_SETTINGS, 44 CV_PUSH_PROMISE, 45 CV_PRIORITY, 46 CV_ERROR, 47 } type; 48 unsigned stream_off; /* Checked only if not zero */ 49 union { 50 struct headers { 51 uint32_t stream_id; 52 uint32_t oth_stream_id; 53 unsigned short weight; 54 signed char exclusive; 55 unsigned char flags; 56 unsigned size; 57 unsigned off; 58 char buf[0x100]; 59 } headers; 60 struct { 61 uint16_t id; 62 uint32_t value; 63 } setting; 64 void *push_promise; 65 struct cv_error { 66 enum frame_reader_error code; 67 lsquic_stream_id_t stream_id; 68 } error; 69 struct cv_priority { 70 lsquic_stream_id_t stream_id; 71 int exclusive; 72 lsquic_stream_id_t dep_stream_id; 73 unsigned weight; 74 } priority; 75 } u; 76}; 77 78 79void 80compare_headers (const struct headers *got_h, const struct headers *exp_h) 81{ 82 assert(got_h->stream_id == exp_h->stream_id); 83 assert(got_h->oth_stream_id == exp_h->oth_stream_id); 84 assert(got_h->weight == exp_h->weight); 85 assert(got_h->exclusive == exp_h->exclusive); 86 assert(got_h->size == exp_h->size); 87 assert(strlen(got_h->buf) == got_h->size); 88 assert(got_h->off == exp_h->off); 89 assert(got_h->flags == exp_h->flags); 90 assert(0 == memcmp(got_h->buf, exp_h->buf, got_h->size)); 91} 92 93 94void 95compare_push_promises (const struct headers *got_h, const struct headers *exp_h) 96{ 97 assert(got_h->stream_id == exp_h->stream_id); 98 assert(got_h->oth_stream_id == exp_h->oth_stream_id); 99 assert(got_h->size == exp_h->size); 100 assert(strlen(got_h->buf) == got_h->size); 101 assert(got_h->off == exp_h->off); 102 assert(got_h->flags == exp_h->flags); 103 assert(0 == memcmp(got_h->buf, exp_h->buf, got_h->size)); 104} 105 106 107void 108compare_priorities (const struct cv_priority *got_prio, 109 const struct cv_priority *exp_prio) 110{ 111 assert(got_prio->stream_id == exp_prio->stream_id); 112 assert(got_prio->exclusive == exp_prio->exclusive); 113 assert(got_prio->dep_stream_id == exp_prio->dep_stream_id); 114 assert(got_prio->weight == exp_prio->weight); 115} 116 117 118void 119compare_errors (const struct cv_error *got_err, 120 const struct cv_error *exp_err) 121{ 122 assert(got_err->code == exp_err->code); 123 assert(got_err->stream_id == exp_err->stream_id); 124} 125 126 127static void 128compare_cb_vals (const struct callback_value *got, 129 const struct callback_value *exp) 130{ 131 assert(got->type == exp->type); 132 if (exp->stream_off) 133 assert(exp->stream_off == got->stream_off); 134 switch (got->type) 135 { 136 case CV_HEADERS: 137 compare_headers(&got->u.headers, &exp->u.headers); 138 break; 139 case CV_PUSH_PROMISE: 140 compare_push_promises(&got->u.headers, &exp->u.headers); 141 break; 142 case CV_ERROR: 143 compare_errors(&got->u.error, &exp->u.error); 144 break; 145 case CV_PRIORITY: 146 compare_priorities(&got->u.priority, &exp->u.priority); 147 break; 148 case CV_SETTINGS: 149 /* TODO */ 150 break; 151 } 152} 153 154 155static struct { 156 size_t in_sz; 157 size_t in_off; 158 size_t in_max_req_sz; 159 size_t in_max_sz; 160 unsigned char in_buf[0x1000]; 161} input; 162 163 164static struct cb_ctx { 165 unsigned n_cb_vals; 166 struct callback_value cb_vals[10]; 167} g_cb_ctx; 168 169 170static void 171reset_cb_ctx (struct cb_ctx *cb_ctx) 172{ 173 cb_ctx->n_cb_vals = 0; 174 memset(&cb_ctx->cb_vals, 0xA5, sizeof(cb_ctx->cb_vals)); 175} 176 177 178static void 179copy_uh_to_headers (const struct uncompressed_headers *uh, struct headers *h) 180{ 181 const struct http1x_headers *h1h = uh->uh_hset; 182 h->flags = uh->uh_flags; 183 h->weight = uh->uh_weight; 184 h->stream_id = uh->uh_stream_id; 185 h->exclusive = uh->uh_exclusive; 186 h->oth_stream_id = uh->uh_oth_stream_id; 187 h->size = h1h->h1h_size; 188 h->off = h1h->h1h_off; 189 memcpy(h->buf, h1h->h1h_buf, h->size); 190 h->buf[h->size] = '\0'; 191} 192 193 194static void 195on_incoming_headers (void *ctx, struct uncompressed_headers *uh) 196{ 197 struct cb_ctx *cb_ctx = ctx; 198 assert(cb_ctx == &g_cb_ctx); 199 unsigned i = cb_ctx->n_cb_vals++; 200 assert(i < sizeof(cb_ctx->cb_vals) / sizeof(cb_ctx->cb_vals[0])); 201 cb_ctx->cb_vals[i].type = CV_HEADERS; 202 cb_ctx->cb_vals[i].stream_off = input.in_off; 203 copy_uh_to_headers(uh, &cb_ctx->cb_vals[i].u.headers); 204 assert(uh->uh_flags & UH_H1H); 205 lsquic_http1x_if->hsi_discard_header_set(uh->uh_hset); 206 free(uh); 207} 208 209 210static void 211on_push_promise (void *ctx, struct uncompressed_headers *uh) 212{ 213 struct cb_ctx *cb_ctx = ctx; 214 assert(cb_ctx == &g_cb_ctx); 215 unsigned i = cb_ctx->n_cb_vals++; 216 assert(i < sizeof(cb_ctx->cb_vals) / sizeof(cb_ctx->cb_vals[0])); 217 cb_ctx->cb_vals[i].type = CV_PUSH_PROMISE; 218 cb_ctx->cb_vals[i].stream_off = input.in_off; 219 copy_uh_to_headers(uh, &cb_ctx->cb_vals[i].u.headers); 220 assert(uh->uh_flags & UH_H1H); 221 lsquic_http1x_if->hsi_discard_header_set(uh->uh_hset); 222 free(uh); 223} 224 225 226static void 227on_error (void *ctx, lsquic_stream_id_t stream_id, enum frame_reader_error error) 228{ 229 struct cb_ctx *cb_ctx = ctx; 230 assert(cb_ctx == &g_cb_ctx); 231 unsigned i = cb_ctx->n_cb_vals++; 232 assert(i < sizeof(cb_ctx->cb_vals) / sizeof(cb_ctx->cb_vals[0])); 233 cb_ctx->cb_vals[i].type = CV_ERROR; 234 cb_ctx->cb_vals[i].u.error.stream_id = stream_id; 235 cb_ctx->cb_vals[i].u.error.code = error; 236 cb_ctx->cb_vals[i].stream_off = input.in_off; 237} 238 239 240static void 241on_settings (void *ctx, uint16_t id, uint32_t value) 242{ 243 struct cb_ctx *cb_ctx = ctx; 244 assert(cb_ctx == &g_cb_ctx); 245 unsigned i = cb_ctx->n_cb_vals++; 246 assert(i < sizeof(cb_ctx->cb_vals) / sizeof(cb_ctx->cb_vals[0])); 247 cb_ctx->cb_vals[i].type = CV_SETTINGS; 248 cb_ctx->cb_vals[i].u.setting.id = id; 249 cb_ctx->cb_vals[i].u.setting.value = value; 250 cb_ctx->cb_vals[i].stream_off = input.in_off; 251} 252 253 254static void 255on_priority (void *ctx, lsquic_stream_id_t stream_id, int exclusive, 256 lsquic_stream_id_t dep_stream_id, unsigned weight) 257{ 258 struct cb_ctx *cb_ctx = ctx; 259 assert(cb_ctx == &g_cb_ctx); 260 unsigned i = cb_ctx->n_cb_vals++; 261 assert(i < sizeof(cb_ctx->cb_vals) / sizeof(cb_ctx->cb_vals[0])); 262 cb_ctx->cb_vals[i].type = CV_PRIORITY; 263 cb_ctx->cb_vals[i].u.priority.stream_id = stream_id; 264 cb_ctx->cb_vals[i].u.priority.exclusive = exclusive; 265 cb_ctx->cb_vals[i].u.priority.dep_stream_id = dep_stream_id; 266 cb_ctx->cb_vals[i].u.priority.weight = weight; 267 cb_ctx->cb_vals[i].stream_off = input.in_off; 268} 269 270 271static const struct frame_reader_callbacks frame_callbacks = { 272 .frc_on_headers = on_incoming_headers, 273 .frc_on_push_promise = on_push_promise, 274 .frc_on_settings = on_settings, 275 .frc_on_priority = on_priority, 276 .frc_on_error = on_error, 277}; 278 279 280static ssize_t 281read_from_stream (struct lsquic_stream *stream, void *buf, size_t sz) 282{ 283 if (sz > input.in_max_req_sz) 284 input.in_max_req_sz = sz; 285 if (input.in_sz - input.in_off < sz) 286 sz = input.in_sz - input.in_off; 287 if (sz > input.in_max_sz) 288 sz = input.in_max_sz; 289 memcpy(buf, input.in_buf + input.in_off, sz); 290 input.in_off += sz; 291 return sz; 292} 293 294 295struct frame_reader_test { 296 unsigned frt_lineno; 297 /* Input */ 298 enum frame_reader_flags frt_fr_flags; 299 unsigned char frt_buf[0x100]; 300 unsigned short frt_bufsz; 301 unsigned frt_max_headers_sz; 302 /* Output */ 303 unsigned short frt_in_off; 304 int frt_err; /* True if expecting error */ 305 unsigned frt_n_cb_vals; 306 struct callback_value frt_cb_vals[10]; 307}; 308 309 310#define HEADERS(str) .buf = (str), .size = sizeof(str) - 1 311 312static const struct frame_reader_test tests[] = { 313 { .frt_lineno = __LINE__, 314 .frt_fr_flags = 0, 315 .frt_buf = { 316 /* Length: */ 0x00, 0x00, 0x04, 317 /* Type: */ 0x01, 318 /* Flags: */ HFHF_END_HEADERS, 319 0x80| /* <----- This bit must be ignored */ 320 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 321 /* Block fragment: */ 322 0x48, 0x82, 0x64, 0x02, 323 }, 324 .frt_bufsz = 13, 325 .frt_n_cb_vals = 1, 326 .frt_cb_vals = { 327 { 328 .type = CV_HEADERS, 329 .u.headers = { 330 .stream_id = 12345, 331 .oth_stream_id = 0, 332 .weight = 0, 333 .exclusive = -1, 334 .off = 0, 335 .flags = UH_H1H, 336 HEADERS("HTTP/1.1 302 Found\r\n\r\n"), 337 }, 338 }, 339 }, 340 }, 341 342 { .frt_lineno = __LINE__, 343 .frt_fr_flags = 0, 344 .frt_buf = { 345 /* Length: */ 0x00, 0x00, 0x16, 346 /* Type: */ 0x01, 347 /* Flags: */ HFHF_END_HEADERS|HFHF_PADDED, 348 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 349 /* Padding length */0x11, 350 /* Block fragment: */ 351 0x48, 0x82, 0x64, 0x02, 352 /* Padding: */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 353 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 354 0xFF, 355 }, 356 .frt_bufsz = 9 + 1 + 4 + 17, 357 .frt_n_cb_vals = 1, 358 .frt_cb_vals = { 359 { 360 .type = CV_HEADERS, 361 .u.headers = { 362 .stream_id = 12345, 363 .oth_stream_id = 0, 364 .weight = 0, 365 .exclusive = -1, 366 .off = 0, 367 .flags = UH_H1H, 368 HEADERS("HTTP/1.1 302 Found\r\n\r\n"), 369 }, 370 }, 371 }, 372 }, 373 374 { .frt_lineno = __LINE__, 375 .frt_fr_flags = 0, 376 .frt_buf = { 377 /* Length: */ 0x00, 0x00, 0x1B, 378 /* Type: */ 0x01, 379 /* Flags: */ HFHF_END_HEADERS|HFHF_PADDED|HFHF_PRIORITY| 380 HFHF_END_STREAM, 381 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 382 /* Padding length */0x11, 383 /* Exclusive: */ 0x80| 384 /* Dep Stream Id: */ 385 0x00, 0x00, 0x12, 0x34, 386 /* Weight: */ 0xFF, 387 /* Block fragment: */ 388 0x48, 0x82, 0x64, 0x02, 389 /* Padding: */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 390 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 391 0xFF, 392 /* Length: */ 0x00, 0x00, 0x05, 393 /* Type: */ HTTP_FRAME_PRIORITY, 394 /* Flags: */ 0x00, 395 /* Stream Id: */ 0x00, 0x00, 0x00, 0x39, 396 /* Dep Stream Id: */0x80, 0x00, 0x00, 0x19, 397 /* Weight: */ 0x77, 398 }, 399 .frt_bufsz = 9 + 1 + 5 + 4 + 17 400 + 9 + 5, 401 .frt_n_cb_vals = 2, 402 .frt_cb_vals = { 403 { 404 .type = CV_HEADERS, 405 .u.headers = { 406 .stream_id = 12345, 407 .oth_stream_id = 0x1234, 408 .weight = 0xFF + 1, 409 .exclusive = 1, 410 .off = 0, 411 .flags = UH_FIN | UH_H1H, 412 HEADERS("HTTP/1.1 302 Found\r\n\r\n"), 413 }, 414 }, 415 { 416 .type = CV_PRIORITY, 417 .u.priority = { 418 .stream_id = 0x39, 419 .exclusive = 1, 420 .dep_stream_id = 0x19, 421 .weight = 0x77 + 1, 422 }, 423 }, 424 }, 425 }, 426 427 { .frt_lineno = __LINE__, 428 .frt_fr_flags = 0, 429 .frt_buf = { 430 /* Length: */ 0x00, 0x00, 0x09, 431 /* Type: */ 0x01, 432 /* Flags: */ HFHF_END_HEADERS|HFHF_PRIORITY, 433 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 434 /* Exclusive: */ 0x00| 435 /* Dep Stream Id: */ 436 0x00, 0x00, 0x12, 0x34, 437 /* Weight: */ 0x00, 438 /* Block fragment: */ 439 0x48, 0x82, 0x64, 0x02, 440 }, 441 .frt_bufsz = 9 + 5 + 4, 442 .frt_n_cb_vals = 1, 443 .frt_cb_vals = { 444 { 445 .type = CV_HEADERS, 446 .u.headers = { 447 .stream_id = 12345, 448 .oth_stream_id = 0x1234, 449 .weight = 1, 450 .exclusive = 0, 451 .off = 0, 452 .flags = UH_H1H, 453 HEADERS("HTTP/1.1 302 Found\r\n\r\n"), 454 }, 455 }, 456 }, 457 }, 458 459 { .frt_lineno = __LINE__, 460 .frt_fr_flags = 0, 461 .frt_buf = { 462 /* Length: */ 0x00, 0x00, 0x0E, 463 /* Type: */ 0x01, 464 /* Flags: */ HFHF_END_HEADERS|HFHF_PRIORITY, 465 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 466 /* Exclusive: */ 0x00| 467 /* Dep Stream Id: */ 468 0x00, 0x00, 0x12, 0x34, 469 /* Weight: */ 0x00, 470 /* Block fragment: */ 471 0x48, 0x82, 0x64, 0x02, 472 0x60, 0x03, 0x61, 0x3d, 0x62, 473 }, 474 .frt_bufsz = 9 + 5 + 4 + 5, 475 .frt_n_cb_vals = 1, 476 .frt_cb_vals = { 477 { 478 .type = CV_HEADERS, 479 .u.headers = { 480 .stream_id = 12345, 481 .oth_stream_id = 0x1234, 482 .weight = 1, 483 .exclusive = 0, 484 .off = 0, 485 .flags = UH_H1H, 486 HEADERS("HTTP/1.1 302 Found\r\n" 487 "Cookie: a=b\r\n\r\n"), 488 }, 489 }, 490 }, 491 }, 492 493 { .frt_lineno = __LINE__, 494 .frt_fr_flags = 0, 495 .frt_buf = { 496 /* Length: */ 0x00, 0x00, 0x18, 497 /* Type: */ 0x01, 498 /* Flags: */ HFHF_END_HEADERS|HFHF_PRIORITY, 499 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 500 /* Exclusive: */ 0x00| 501 /* Dep Stream Id: */ 502 0x00, 0x00, 0x12, 0x34, 503 /* Weight: */ 0x00, 504 /* Block fragment: */ 505 0x48, 0x82, 0x64, 0x02, 506 0x60, 0x03, 0x61, 0x3d, 0x62, 507 0x60, 0x03, 0x63, 0x3d, 0x64, 508 0x60, 0x03, 0x65, 0x3d, 0x66, 509 }, 510 .frt_bufsz = 9 + 5 + 4 + 15, 511 .frt_n_cb_vals = 1, 512 .frt_cb_vals = { 513 { 514 .type = CV_HEADERS, 515 .u.headers = { 516 .stream_id = 12345, 517 .oth_stream_id = 0x1234, 518 .weight = 1, 519 .exclusive = 0, 520 .off = 0, 521 .flags = UH_H1H, 522 HEADERS("HTTP/1.1 302 Found\r\n" 523 "Cookie: a=b; c=d; e=f\r\n\r\n"), 524 }, 525 }, 526 }, 527 }, 528 529 { .frt_lineno = __LINE__, 530 .frt_fr_flags = FRF_SERVER, 531 .frt_buf = { 532 /* Length: */ 0x00, 0x00, 0x16, 533 /* Type: */ 0x01, 534 /* Flags: */ HFHF_END_HEADERS|HFHF_PRIORITY, 535 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 536 /* Exclusive: */ 0x00| 537 /* Dep Stream Id: */ 538 0x00, 0x00, 0x12, 0x34, 539 /* Weight: */ 0x00, 540 /* Block fragment: */ 541 0x82, 0x84, 0x86, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 542 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 543 0xff, 544 /* Length: */ 0x00, 0x00, 0xEE, 545 /* Type: */ HTTP_FRAME_CONTINUATION, 546 /* Flags: */ HFHF_END_HEADERS, 547 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 548 /* Block fragment: */ 549 'W', 'H', 'A', 'T', 'E', 'V', 'E', 'R', 550 }, 551 .frt_bufsz = 9 + 5 + 17 552 + 9 + 0 + 8, 553 .frt_err = 1, 554 .frt_in_off = 9 + 5 + 17 + 9, 555 .frt_n_cb_vals = 1, 556 .frt_cb_vals = { 557 { 558 .type = CV_HEADERS, 559 .u.headers = { 560 .stream_id = 12345, 561 .oth_stream_id = 0x1234, 562 .weight = 1, 563 .exclusive = 0, 564 .off = 0, 565 .flags = UH_H1H, 566 HEADERS("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"), 567 }, 568 }, 569 }, 570 }, 571 572 { .frt_lineno = __LINE__, 573 .frt_fr_flags = FRF_SERVER, 574 .frt_buf = { 575 /* Length: */ 0x00, 0x00, 0x16, 576 /* Type: */ 0x01, 577 /* Flags: */ HFHF_END_HEADERS|HFHF_PRIORITY, 578 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 579 /* Exclusive: */ 0x00| 580 /* Dep Stream Id: */ 581 0x00, 0x00, 0x12, 0x34, 582 /* Weight: */ 0x00, 583 /* Block fragment: */ 584 0x82, 0x84, 0x86, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 585 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 586 0xff, 587 /* Length: */ 0x00, 0x00, 0xEE, 588 /* Type: */ HTTP_FRAME_CONTINUATION, 589 /* Flags: */ HFHF_END_HEADERS, 590 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 591 /* Block fragment: */ 592 'W', 'H', 'A', 'T', 'E', 'V', 'E', 'R', 593 }, 594 .frt_bufsz = 9 + 5 + 17 595 + 9 + 0 + 8, 596 .frt_err = 1, 597 .frt_in_off = 9 + 5 + 17 + 9, 598 .frt_n_cb_vals = 1, 599 .frt_cb_vals = { 600 { 601 .type = CV_HEADERS, 602 .u.headers = { 603 .stream_id = 12345, 604 .oth_stream_id = 0x1234, 605 .weight = 1, 606 .exclusive = 0, 607 .off = 0, 608 .flags = UH_H1H, 609 HEADERS("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"), 610 }, 611 }, 612 }, 613 }, 614 615 { .frt_lineno = __LINE__, 616 .frt_fr_flags = FRF_SERVER, 617 .frt_buf = { 618 /* Length: */ 0x00, 0x00, 0x16, 619 /* Type: */ 0x01, 620 /* Flags: */ HFHF_PRIORITY, 621 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 622 /* Exclusive: */ 0x00| 623 /* Dep Stream Id: */ 624 0x00, 0x00, 0x12, 0x34, 625 /* Weight: */ 0x00, 626 /* Block fragment: */ 627 0x82, 0x84, 0x86, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 628 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 629 0xff, 630 /* Length: */ 0x00, 0x00, 0xEE, 631 /* Type: */ HTTP_FRAME_CONTINUATION, 632 /* Flags: */ HFHF_END_HEADERS, 633 /* Stream Id: */ 0x00, 0xFF, 0x30, 0x39, /* Stream ID does not match */ 634 /* Block fragment: */ 635 'W', 'H', 'A', 'T', 'E', 'V', 'E', 'R', 636 }, 637 .frt_bufsz = 9 + 5 + 17 638 + 9 + 0 + 8, 639 .frt_err = 1, 640 .frt_in_off = 9 + 5 + 17 + 9, 641 .frt_n_cb_vals = 0, 642 }, 643 644 { .frt_lineno = __LINE__, 645 .frt_fr_flags = FRF_SERVER, 646 .frt_buf = { 647 /* Length: */ 0x00, 0x00, 0xEE, 648 /* Type: */ HTTP_FRAME_CONTINUATION, 649 /* Flags: */ HFHF_END_HEADERS, 650 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 651 /* Block fragment: */ 652 'W', 'H', 'A', 'T', 'E', 'V', 'E', 'R', 653 }, 654 .frt_bufsz = 9 + 0 + 8, 655 .frt_err = 1, 656 .frt_in_off = 9, 657 .frt_n_cb_vals = 0, 658 }, 659 660 { .frt_lineno = __LINE__, 661 .frt_fr_flags = FRF_SERVER, 662 .frt_buf = { 663 /* Length: */ 0x00, 0x00, 0x10, 664 /* Type: */ 0x01, 665 /* Flags: */ 0x00, /* Note absence of HFHF_END_HEADERS */ 666 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 667 /* Block fragment: 668 * perl hpack.pl :method GET :path / host www.example.com 669 */ 670 0x82, 0x84, 0x66, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 671 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, 672 /* Length: */ 0x00, 0x00, 0x08, 673 /* Type: */ 0x01, 674 /* Flags: */ HFHF_END_HEADERS, 675 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 676 /* Block fragment: */ 677 'W', 'H', 'A', 'T', 'E', 'V', 'E', 'R', 678 }, 679 .frt_bufsz = 9 + 0 + 16 680 + 9 + 0 + 8, 681 .frt_in_off = 9 + 16 + 9, 682 .frt_err = 1, 683 .frt_n_cb_vals = 1, 684 .frt_cb_vals = { 685 { 686 .type = CV_ERROR, 687 .u.error = { 688 .stream_id = 0x3039, 689 .code = FR_ERR_EXPECTED_CONTIN, 690 }, 691 }, 692 }, 693 }, 694 695 { .frt_lineno = __LINE__, 696 .frt_fr_flags = FRF_SERVER, 697 .frt_buf = { 698 /* Length: */ 0x00, 0x00, 0x10, 699 /* Type: */ 0x01, 700 /* Flags: */ HFHF_END_HEADERS, 701 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 702 /* Block fragment: 703 * perl hpack.pl :method GET :path / host www.example.com 704 */ 705 0x82, 0x84, 0x66, 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 706 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 0xff, 707 /* Length: */ 0x00, 0x00, 0x1A, 708 /* Type: */ 0x01, 709 /* Flags: */ HFHF_END_HEADERS|HFHF_PRIORITY, 710 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 711 /* Exclusive: */ 0x00| 712 /* Dep Stream Id: */ 713 0x00, 0x00, 0x12, 0x34, 714 /* Weight: */ 0x00, 715 /* Block fragment: 716 * perl hpack.pl :method GET :path / :scheme http Host www.example.com 717 */ 718 0x82, 0x84, 0x86, 0x40, 0x83, 0xc6, 0x74, 0x27, 719 0x8c, 0xf1, 0xe3, 0xc2, 0xe5, 0xf2, 0x3a, 0x6b, 720 0xa0, 0xab, 0x90, 0xf4, 0xff, 721 /* Length: */ 0x00, 0x00, 0x11, 722 /* Type: */ 0x01, 723 /* Flags: */ HFHF_END_HEADERS, 724 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 725 /* Block fragment: */ 726 0x82, 0x84, 0x86, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 727 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 728 0xff, 729 }, 730 .frt_bufsz = 9 + 0 + 16 731 + 9 + 5 + 21 732 + 9 + 0 + 17, 733 .frt_n_cb_vals = 3, 734 .frt_cb_vals = { 735 { 736 .type = CV_ERROR, 737 .u.error = { 738 .stream_id = 12345, 739 .code = FR_ERR_BAD_HEADER, 740 }, 741 }, 742 { 743 .type = CV_ERROR, 744 .u.error = { 745 .stream_id = 12345, 746 .code = FR_ERR_BAD_HEADER, 747 }, 748 }, 749 { 750 .type = CV_HEADERS, 751 .u.headers = { 752 .stream_id = 12345, 753 .oth_stream_id = 0, 754 .weight = 0, 755 .exclusive = -1, 756 .off = 0, 757 .flags = UH_H1H, 758 HEADERS("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"), 759 }, 760 }, 761 }, 762 }, 763 764 { .frt_lineno = __LINE__, 765 .frt_fr_flags = 0, 766 .frt_buf = { 767 /* Length: */ 0x00, 0x00, 0x15, 768 /* Type: */ HTTP_FRAME_PUSH_PROMISE, 769 /* Flags: */ HFHF_END_HEADERS, 770 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 771 /* Dep stream Id: */0x00, 0x12, 0x34, 0x56, 772 /* Block fragment: */ 773 0x82, 0x84, 0x86, 0x41, 0x8c, 0xf1, 0xe3, 0xc2, 774 0xe5, 0xf2, 0x3a, 0x6b, 0xa0, 0xab, 0x90, 0xf4, 775 0xff, 776 }, 777 .frt_bufsz = 9 + 0 + 0x15, 778 .frt_n_cb_vals = 1, 779 .frt_cb_vals = { 780 { 781 .type = CV_PUSH_PROMISE, 782 .u.headers = { 783 .stream_id = 12345, 784 .oth_stream_id = 0x123456, 785 .flags = UH_PP | UH_H1H, 786 HEADERS("GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n"), 787 }, 788 }, 789 }, 790 }, 791 792 { .frt_lineno = __LINE__, 793 .frt_fr_flags = 0, 794 .frt_buf = { 795 /* Length: */ 0x00, 0x00, 0x02, 796 /* Type: */ HTTP_FRAME_HEADERS, 797 /* Flags: */ 0x00, 798 0x80| /* <----- This bit must be ignored */ 799 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 800 /* Block fragment: */ 801 0x48, 0x82, 802 /* Length: */ 0x00, 0x00, 0x02, 803 /* Type: */ HTTP_FRAME_CONTINUATION, 804 /* Flags: */ HFHF_END_HEADERS, 805 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 806 /* Block fragment: */ 807 0x64, 0x02, 808 }, 809 .frt_bufsz = 9 + 2 + 9 + 2, 810 .frt_n_cb_vals = 1, 811 .frt_cb_vals = { 812 { 813 .type = CV_HEADERS, 814 .u.headers = { 815 .stream_id = 12345, 816 .oth_stream_id = 0, 817 .weight = 0, 818 .exclusive = -1, 819 .off = 0, 820 .flags = UH_H1H, 821 HEADERS("HTTP/1.1 302 Found\r\n\r\n"), 822 }, 823 }, 824 }, 825 }, 826 827 { .frt_lineno = __LINE__, 828 .frt_fr_flags = 0, 829 .frt_buf = { 830 /* Length: */ 0x00, 0x00, 0x00, 831 /* Type: */ HTTP_FRAME_SETTINGS, 832 /* Flags: */ 0x00, 833 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 834 }, 835 .frt_bufsz = 9, 836 .frt_n_cb_vals = 1, 837 .frt_err = 1, 838 .frt_cb_vals = { 839 { 840 .type = CV_ERROR, 841 .u.error.code = FR_ERR_INVALID_FRAME_SIZE, 842 .u.error.stream_id = 12345, 843 }, 844 }, 845 }, 846 847 { .frt_lineno = __LINE__, 848 .frt_fr_flags = 0, 849 .frt_buf = { 850 /* Length: */ 0x00, 0x00, 0x07, 851 /* Type: */ HTTP_FRAME_SETTINGS, 852 /* Flags: */ 0x00, 853 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 854 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 855 }, 856 .frt_bufsz = 9 + 7, 857 .frt_n_cb_vals = 1, 858 .frt_err = 1, 859 .frt_in_off = 9, 860 .frt_cb_vals = { 861 { 862 .type = CV_ERROR, 863 .u.error.code = FR_ERR_INVALID_FRAME_SIZE, 864 .u.error.stream_id = 12345, 865 }, 866 }, 867 }, 868 869 { .frt_lineno = __LINE__, 870 .frt_fr_flags = 0, 871 .frt_buf = { 872 /* Length: */ 0x00, 0x00, 0x06, 873 /* Type: */ HTTP_FRAME_SETTINGS, 874 /* Flags: */ 0x00, 875 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 876 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 877 }, 878 .frt_bufsz = 9 + 6, 879 .frt_n_cb_vals = 1, 880 .frt_err = 1, 881 .frt_in_off = 9, 882 .frt_cb_vals = { 883 { 884 .type = CV_ERROR, 885 .u.error.code = FR_ERR_NONZERO_STREAM_ID, 886 .u.error.stream_id = 12345, 887 }, 888 }, 889 }, 890 891 { .frt_lineno = __LINE__, 892 .frt_fr_flags = 0, 893 .frt_buf = { 894 /* Length: */ 0x00, 0x00, 0x0C, 895 /* Type: */ HTTP_FRAME_SETTINGS, 896 /* Flags: */ 0x00, 897 /* Stream Id: */ 0x00, 0x00, 0x00, 0x00, 898 0x00, SETTINGS_INITIAL_WINDOW_SIZE, 899 0x01, 0x02, 0x03, 0x04, 900 0x00, SETTINGS_HEADER_TABLE_SIZE, 901 0x02, 0x03, 0x04, 0x05, 902 }, 903 .frt_bufsz = 9 + 12, 904 .frt_n_cb_vals = 2, 905 .frt_cb_vals = { 906 { 907 .type = CV_SETTINGS, 908 .u.setting.id = SETTINGS_INITIAL_WINDOW_SIZE, 909 .u.setting.value = 0x01020304, 910 }, 911 { 912 .type = CV_SETTINGS, 913 .u.setting.id = SETTINGS_HEADER_TABLE_SIZE, 914 .u.setting.value = 0x02030405, 915 }, 916 }, 917 }, 918 919 { .frt_lineno = __LINE__, 920 .frt_fr_flags = 0, 921 .frt_buf = { 922 /* Length: */ 0x00, 0x00, 0x09, 923 /* Type: */ 0x01, 924 /* Flags: */ HFHF_END_HEADERS|HFHF_PRIORITY, 925 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 926 /* Exclusive: */ 0x00| 927 /* Dep Stream Id: */ 928 0x00, 0x00, 0x12, 0x34, 929 /* Weight: */ 0x00, 930 /* Block fragment: */ 931 0x48, 0x82, 0x64, 0x02, 932 /* Length: */ 0x00, 0x00, 0x06, 933 /* Type: */ HTTP_FRAME_SETTINGS, 934 /* Flags: */ 0x00, 935 /* Stream Id: */ 0x00, 0x00, 0x00, 0x00, 936 0x00, SETTINGS_INITIAL_WINDOW_SIZE, 937 0x01, 0x02, 0x03, 0x04, 938 }, 939 .frt_bufsz = 9 + 5 + 4 + 9 + 6, 940 .frt_max_headers_sz = 10, 941 .frt_n_cb_vals = 2, 942 .frt_cb_vals = { 943 { 944 .type = CV_ERROR, 945 .stream_off = 9 + 5 + 4, 946 .u.error.code = FR_ERR_BAD_HEADER, 947 .u.error.stream_id = 12345, 948 }, 949 { 950 .type = CV_SETTINGS, 951 .u.setting.id = SETTINGS_INITIAL_WINDOW_SIZE, 952 .u.setting.value = 0x01020304, 953 }, 954 }, 955 }, 956 957 { .frt_lineno = __LINE__, 958 .frt_fr_flags = 0, 959 .frt_buf = { 960 /* Length: */ 0x00, 0x00, 0x11, 961 /* Type: */ 0x01, 962 /* Flags: */ HFHF_END_HEADERS, 963 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 964 /* Block fragment: */ 965 /* 0x11 bytes of no consequence: they are not 966 * parsed. 967 */ 968 000, 001, 002, 003, 004, 005, 006, 007, 969 010, 011, 012, 013, 014, 015, 016, 017, 970 020, 971 /* Length: */ 0x00, 0x00, 0x06, 972 /* Type: */ HTTP_FRAME_SETTINGS, 973 /* Flags: */ 0x00, 974 /* Stream Id: */ 0x00, 0x00, 0x00, 0x00, 975 0x00, SETTINGS_INITIAL_WINDOW_SIZE, 976 0x01, 0x02, 0x03, 0x04, 977 }, 978 .frt_bufsz = 9 + 0 + 0x11 + 9 + 6, 979 .frt_max_headers_sz = 0x10, 980 .frt_n_cb_vals = 2, 981 .frt_cb_vals = { 982 { 983 .type = CV_ERROR, 984 .stream_off = 9, 985 .u.error.code = FR_ERR_BAD_HEADER, 986 .u.error.stream_id = 12345, 987 }, 988 { 989 .type = CV_SETTINGS, 990 .u.setting.id = SETTINGS_INITIAL_WINDOW_SIZE, 991 .u.setting.value = 0x01020304, 992 }, 993 }, 994 }, 995 996 { .frt_lineno = __LINE__, 997 .frt_fr_flags = 0, 998 .frt_buf = { 999 /* Length: */ 0x00, 0x00, 0x10, 1000 /* Type: */ 0x01, 1001 /* Flags: */ 0x00, 1002 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 1003 /* Block fragment: */ 1004 /* 0x10 bytes of no consequence: they are not 1005 * parsed. 1006 */ 1007 000, 001, 002, 003, 004, 005, 006, 007, 1008 010, 011, 012, 013, 014, 015, 016, 017, 1009 /* Length: */ 0x00, 0x00, 0x10, 1010 /* Type: */ HTTP_FRAME_CONTINUATION, 1011 /* Flags: */ 0x00, 1012 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 1013 /* Block fragment: */ 1014 000, 001, 002, 003, 004, 005, 006, 007, 1015 010, 011, 012, 013, 014, 015, 016, 017, 1016 /* Length: */ 0x00, 0x00, 0x10, 1017 /* Type: */ HTTP_FRAME_CONTINUATION, 1018 /* Flags: */ HFHF_END_HEADERS, 1019 /* Stream Id: */ 0x00, 0x00, 0x30, 0x39, 1020 /* Block fragment: */ 1021 000, 001, 002, 003, 004, 005, 006, 007, 1022 010, 011, 012, 013, 014, 015, 016, 017, 1023 /* Length: */ 0x00, 0x00, 0x06, 1024 /* Type: */ HTTP_FRAME_SETTINGS, 1025 /* Flags: */ 0x00, 1026 /* Stream Id: */ 0x00, 0x00, 0x00, 0x00, 1027 0x00, SETTINGS_INITIAL_WINDOW_SIZE, 1028 0x01, 0x02, 0x03, 0x04, 1029 }, 1030 .frt_bufsz = 9 + 0 + 0x10 + 9 + 0 + 0x10 + 9 + 0 + 0x10 + 9 + 6, 1031 .frt_max_headers_sz = 0x19, 1032 .frt_n_cb_vals = 2, 1033 .frt_cb_vals = { 1034 { 1035 .type = CV_ERROR, 1036 .stream_off = 9 + 0 + 0x10 + 9, 1037 .u.error.code = FR_ERR_BAD_HEADER, 1038 .u.error.stream_id = 12345, 1039 }, 1040 { 1041 .type = CV_SETTINGS, 1042 .u.setting.id = SETTINGS_INITIAL_WINDOW_SIZE, 1043 .u.setting.value = 0x01020304, 1044 }, 1045 }, 1046 }, 1047 1048 { .frt_lineno = __LINE__, 1049 .frt_fr_flags = 0, 1050 .frt_buf = { 1051 /* Length: */ 0x00, 0x00, 1052 0x04, /* <-- wrong payload size */ 1053 /* Type: */ HTTP_FRAME_PRIORITY, 1054 /* Flags: */ 0x00, 1055 /* Stream Id: */ 0x00, 0x00, 0x00, 0x39, 1056 /* Dep Stream Id: */0x80, 0x00, 0x00, 0x19, 1057 /* Weight: */ 0x77, 1058 }, 1059 .frt_bufsz = 9 + 5, 1060 .frt_n_cb_vals = 1, 1061 .frt_err = 1, 1062 .frt_in_off = 9, 1063 .frt_cb_vals = { 1064 { 1065 .type = CV_ERROR, 1066 .stream_off = 9, 1067 .u.error.code = FR_ERR_INVALID_FRAME_SIZE, 1068 .u.error.stream_id = 0x39, 1069 } 1070 }, 1071 }, 1072 1073 { .frt_lineno = __LINE__, 1074 .frt_fr_flags = 0, 1075 .frt_buf = { 1076 /* Length: */ 0x00, 0x00, 0x05, 1077 /* Type: */ HTTP_FRAME_PRIORITY, 1078 /* Flags: */ 0x00, 1079 /* Stream Id: */ 0x00, 0x00, 0x00, 0x00, /* Invalid stream ID */ 1080 /* Dep Stream Id: */0x80, 0x00, 0x00, 0x19, 1081 /* Weight: */ 0x77, 1082 }, 1083 .frt_bufsz = 9 + 5, 1084 .frt_n_cb_vals = 1, 1085 .frt_err = 1, 1086 .frt_in_off = 9, 1087 .frt_cb_vals = { 1088 { 1089 .type = CV_ERROR, 1090 .stream_off = 9, 1091 .u.error.code = FR_ERR_ZERO_STREAM_ID, 1092 .u.error.stream_id = 0x00, 1093 } 1094 }, 1095 }, 1096 1097 { 1098 .frt_bufsz = 0, 1099 }, 1100}; 1101 1102 1103static struct lsquic_stream * 1104my_get_stream_by_id (struct lsquic_conn *conn, lsquic_stream_id_t stream_id) 1105{ 1106 return (void *) my_get_stream_by_id; 1107} 1108 1109 1110static void 1111test_one_frt (const struct frame_reader_test *frt) 1112{ 1113 struct lsquic_frame_reader *fr; 1114 unsigned short exp_off; 1115 struct lshpack_dec hdec; 1116 struct lsquic_mm mm; 1117 struct lsquic_conn lconn; 1118 struct lsquic_conn_public conn_pub; 1119 struct lsquic_stream stream; 1120 int s; 1121 struct conn_iface my_conn_if; 1122 1123#if LSQUIC_CONN_STATS 1124 struct conn_stats conn_stats; 1125 memset(&conn_stats, 0, sizeof(conn_stats)); 1126#endif 1127 1128 memset(&stream, 0, sizeof(stream)); 1129 memset(&lconn, 0, sizeof(lconn)); 1130 memset(&conn_pub, 0, sizeof(conn_pub)); 1131 memset(&my_conn_if, 0, sizeof(my_conn_if)); 1132 my_conn_if.ci_get_stream_by_id = my_get_stream_by_id; 1133 lconn.cn_if = &my_conn_if; 1134 stream.conn_pub = &conn_pub; 1135 conn_pub.lconn = &lconn; 1136 1137 top: 1138 lsquic_mm_init(&mm); 1139 lshpack_dec_init(&hdec); 1140 memset(&input, 0, sizeof(input)); 1141 memcpy(input.in_buf, frt->frt_buf, frt->frt_bufsz); 1142 input.in_sz = frt->frt_bufsz; 1143 1144 do 1145 { 1146 reset_cb_ctx(&g_cb_ctx); 1147 input.in_off = 0; 1148 ++input.in_max_sz; 1149 1150 fr = lsquic_frame_reader_new(frt->frt_fr_flags, frt->frt_max_headers_sz, 1151 &mm, &stream, read_from_stream, &hdec, &frame_callbacks, &g_cb_ctx, 1152#if LSQUIC_CONN_STATS 1153 &conn_stats, 1154#endif 1155 lsquic_http1x_if, NULL); 1156 do 1157 { 1158 s = lsquic_frame_reader_read(fr); 1159 if (s != 0) 1160 break; 1161 } 1162 while (input.in_off < input.in_sz); 1163 1164 assert(frt->frt_err || 0 == s); 1165 1166 if (my_conn_if.ci_get_stream_by_id) 1167 { 1168 assert(g_cb_ctx.n_cb_vals == frt->frt_n_cb_vals); 1169 1170 unsigned i; 1171 for (i = 0; i < g_cb_ctx.n_cb_vals; ++i) 1172 compare_cb_vals(&g_cb_ctx.cb_vals[i], &frt->frt_cb_vals[i]); 1173 } 1174 1175 exp_off = frt->frt_in_off; 1176 if (!exp_off) 1177 exp_off = frt->frt_bufsz; 1178 assert(input.in_off == exp_off); 1179 1180 lsquic_frame_reader_destroy(fr); 1181 } 1182 while (input.in_max_sz < input.in_max_req_sz); 1183 lshpack_dec_cleanup(&hdec); 1184 1185 if (!(frt->frt_fr_flags & FRF_SERVER) && my_conn_if.ci_get_stream_by_id) 1186 { 1187 /* Do it again, but this time test header block skip logic */ 1188 my_conn_if.ci_get_stream_by_id = NULL; 1189 goto top; 1190 } 1191 1192 lsquic_mm_cleanup(&mm); 1193} 1194 1195 1196int 1197main (int argc, char **argv) 1198{ 1199 int opt; 1200 1201 while (-1 != (opt = getopt(argc, argv, "l:"))) 1202 { 1203 switch (opt) 1204 { 1205 case 'l': 1206 lsquic_log_to_fstream(stderr, LLTS_NONE); 1207 lsquic_logger_lopt(optarg); 1208 break; 1209 default: 1210 exit(1); 1211 } 1212 } 1213 1214 const struct frame_reader_test *frt; 1215 for (frt = tests; frt->frt_bufsz > 0; ++frt) 1216 test_one_frt(frt); 1217 return 0; 1218} 1219