1/* 2 * Test QPACK. 3 */ 4 5#include <assert.h> 6#include <ctype.h> 7#include <stdint.h> 8#include <stdio.h> 9#include <stdlib.h> 10#include <string.h> 11 12#include "lsqpack.h" 13#include "lsqpack-test.h" 14#include "lsxpack_header.h" 15 16#define ENC_BUF_SZ 200 17#define HEADER_BUF_SZ 200 18#define PREFIX_BUF_SZ 10 19 20static const struct qpack_header_block_test 21{ 22 /* Identification: */ 23 int qhbt_lineno; 24 25 /* Input: */ 26 unsigned qhbt_table_size; 27 unsigned qhbt_max_risked_streams; 28 unsigned qhbt_n_headers; 29 struct { 30 const char *name, *value; 31 enum lsqpack_enc_flags flags; 32 } qhbt_headers[10]; 33 34 /* Output: */ 35 size_t qhbt_enc_sz; 36 unsigned char qhbt_enc_buf[ENC_BUF_SZ]; 37 38 size_t qhbt_prefix_sz; 39 unsigned char qhbt_prefix_buf[PREFIX_BUF_SZ]; 40 41 size_t qhbt_header_sz; 42 unsigned char qhbt_header_buf[HEADER_BUF_SZ]; 43} header_block_tests[] = 44{ 45 46 { 47 .qhbt_lineno = __LINE__, 48 .qhbt_table_size = 0x1000, 49 .qhbt_max_risked_streams = 100, 50 .qhbt_n_headers = 1, 51 .qhbt_headers = { 52 { ":method", "GET", 0, }, 53 }, 54 .qhbt_enc_sz = 0, 55 .qhbt_prefix_sz = 2, 56 .qhbt_prefix_buf = "\x00\x00", 57 .qhbt_header_sz = 1, 58 .qhbt_header_buf = { 59 0x80 | 0x40 | 17, 60 }, 61 }, 62 63 { 64 .qhbt_lineno = __LINE__, 65 .qhbt_table_size = 0x1000, 66 .qhbt_max_risked_streams = 100, 67 .qhbt_n_headers = 1, 68 .qhbt_headers = { 69 { ":method", "method", LQEF_NEVER_INDEX, }, 70 }, 71 .qhbt_enc_sz = 0, 72 .qhbt_prefix_sz = 2, 73 .qhbt_prefix_buf = "\x00\x00", 74 .qhbt_header_sz = 8, 75 .qhbt_header_buf = { 76 0x40 | 0x20 | 0x10 | 0x0F, 0x00, 77 0x80 /* Huffman */ | 5 /* length */, 78 0xa4, 0xa9, 0x9c, 0xf2, 0x7f, 79 }, 80 }, 81 82 { 83 .qhbt_lineno = __LINE__, 84 .qhbt_table_size = 0x1000, 85 .qhbt_max_risked_streams = 0, 86 .qhbt_n_headers = 1, 87 .qhbt_headers = { 88 { ":method", "method", 0, }, 89 }, 90 .qhbt_enc_sz = 7, 91 .qhbt_enc_buf = { 92 0x80 | 0x40 /* static */ | 15 /* name index */, 93 0x80 /* Huffman */ | 5 /* length */, 94 0xa4, 0xa9, 0x9c, 0xf2, 0x7f, 95 }, 96 .qhbt_prefix_sz = 2, 97 .qhbt_prefix_buf = "\x00\x00", 98 .qhbt_header_sz = 8, 99 .qhbt_header_buf = { 100 0x40 | 0x10 /* Static */ | 15, 0x00, 101 0x80 /* Huffman */ | 5 /* length */, 102 0xa4, 0xa9, 0x9c, 0xf2, 0x7f, 103 }, 104 }, 105 106 { 107 .qhbt_lineno = __LINE__, 108 .qhbt_table_size = 0x1000, 109 .qhbt_max_risked_streams = 0x1000, 110 .qhbt_n_headers = 1, 111 .qhbt_headers = { 112 { ":method", "method", 0, }, 113 }, 114 .qhbt_enc_sz = 7, 115 .qhbt_enc_buf = { 116 0x80 | 0x40 /* static */ | 15 /* name index */, 117 0x80 /* Huffman */ | 5 /* length */, 118 0xa4, 0xa9, 0x9c, 0xf2, 0x7f, 119 }, 120 .qhbt_prefix_sz = 2, 121 .qhbt_prefix_buf = { 0x02, 0x80, }, 122 .qhbt_header_sz = 1, 123 .qhbt_header_buf = { 124 0x10 | 0 /* Relative dynamic ID */, 125 }, 126 }, 127 128 { 129 .qhbt_lineno = __LINE__, 130 .qhbt_table_size = 0x1000, 131 .qhbt_max_risked_streams = 0x1000, 132 .qhbt_n_headers = 1, 133 .qhbt_headers = { 134 { "dude", "where is my car?", LQEF_NEVER_INDEX, }, 135 }, 136 .qhbt_enc_sz = 0, 137 .qhbt_prefix_sz = 2, 138 .qhbt_prefix_buf = "\x00\x00", 139 .qhbt_header_sz = 17, 140 .qhbt_header_buf = { 141 0x20 | 0x10 /* No index */ | 0x08 | 3, 142 0x92, 0xd9, 0x0b, 143 0x80 | 0xC, 144 0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa, 145 0x50, 0x83, 0xb3, 0xfc, 146 }, 147 }, 148 149 { 150 .qhbt_lineno = __LINE__, 151 .qhbt_table_size = 0x1000, 152 .qhbt_max_risked_streams = 0, 153 .qhbt_n_headers = 3, 154 .qhbt_headers = { 155 { "dude", "where is my car?", 0, }, 156 { ":method", "GET", 0, }, 157 /* The "aaa..." string triggers header_out_grow_buf() */ 158 { "aaaaaaaaaaaaaaaaaaaaaaaaaa", 159 "aaaaaaaaaaaaaaaaaaaaaaaaaa", 0, }, 160 }, 161 .qhbt_enc_sz = 53, 162 .qhbt_enc_buf = { 163 0x40 | 0x20 | 3, 164 0x92, 0xd9, 0x0b, 165 0x80 | 0xC, 166 0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa, 167 0x50, 0x83, 0xb3, 0xfc, 168 0x40 /* Without name reference */ | 0x20 /* Huffman */ | 17 /* Length */, 169 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x31, 0x8c, 170 0x63, 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xff, 171 0x80 /* Huffman */ | 17 /* length */, 172 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x31, 0x8c, 173 0x63, 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xff, 174 }, 175 .qhbt_prefix_sz = 2, 176 .qhbt_prefix_buf = "\x00\x00", 177 .qhbt_header_sz = 55, 178 .qhbt_header_buf = { 179 0x20 | 0x08 | 3, 180 0x92, 0xd9, 0x0b, 181 0x80 | 0xC, 182 0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa, 183 0x50, 0x83, 0xb3, 0xfc, 184 0x80 | 0x40 | 17, 185 0x20 /* Without name reference */ | 0x08 /* Huffman */ | 7 , 0x0A /* Length */, 186 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x31, 0x8c, 187 0x63, 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xff, 188 0x80 /* Huffman */ | 17 /* length */, 189 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xc6, 0x31, 0x8c, 190 0x63, 0x18, 0xc6, 0x31, 0x8c, 0x63, 0x18, 0xff, 191 }, 192 }, 193 194 { 195 .qhbt_lineno = __LINE__, 196 .qhbt_table_size = 0x1000, 197 .qhbt_max_risked_streams = 1, 198 .qhbt_n_headers = 1, 199 .qhbt_headers = { 200 { "dude", "where is my car?", 0, }, 201 }, 202 .qhbt_enc_sz = 17, 203 .qhbt_enc_buf = { 204 0x40 | 0x20 | 3, 205 0x92, 0xd9, 0x0b, 206 0x80 | 0xC, 207 0xf1, 0x39, 0x6c, 0x2a, 0x86, 0x42, 0x94, 0xfa, 208 0x50, 0x83, 0xb3, 0xfc, 209 }, 210 .qhbt_prefix_sz = 2, 211 .qhbt_prefix_buf = { 0x02, 0x80, }, 212 .qhbt_header_sz = 1, 213 .qhbt_header_buf = { 214 0x10 | 0 /* Relative dynamic ID */, 215 }, 216 }, 217 218}; 219 220 221struct header_buf 222{ 223 unsigned off; 224 char buf[UINT16_MAX]; 225}; 226 227 228int 229header_set_ptr (struct lsxpack_header *hdr, struct header_buf *header_buf, 230 const char *name, size_t name_len, 231 const char *val, size_t val_len) 232{ 233 if (header_buf->off + name_len + val_len <= sizeof(header_buf->buf)) 234 { 235 memcpy(header_buf->buf + header_buf->off, name, name_len); 236 memcpy(header_buf->buf + header_buf->off + name_len, val, val_len); 237 lsxpack_header_set_offset2(hdr, header_buf->buf + header_buf->off, 238 0, name_len, name_len, val_len); 239 header_buf->off += name_len + val_len; 240 return 0; 241 } 242 else 243 return -1; 244} 245 246static void 247run_header_test (const struct qpack_header_block_test *test) 248{ 249 unsigned char header_buf[HEADER_BUF_SZ], enc_buf[ENC_BUF_SZ], 250 prefix_buf[PREFIX_BUF_SZ]; 251 unsigned header_off, enc_off; 252 size_t header_sz, enc_sz, dec_sz; 253 struct lsqpack_enc enc; 254 unsigned i; 255 size_t nw; 256 int s; 257 enum lsqpack_enc_status enc_st; 258 float ratio; 259 unsigned char dec_buf[LSQPACK_LONGEST_SDTC]; 260 struct lsxpack_header xhdr; 261 struct header_buf hbuf; 262 263 dec_sz = sizeof(dec_buf); 264 s = lsqpack_enc_init(&enc, stderr, test->qhbt_table_size, 265 test->qhbt_table_size, test->qhbt_max_risked_streams, 266 LSQPACK_ENC_OPT_IX_AGGR, dec_buf, &dec_sz); 267 assert(s == 0); 268 269 s = lsqpack_enc_start_header(&enc, 0, 0); 270 assert(s == 0); 271 272 header_off = 0, enc_off = 0; 273 for (i = 0; i < test->qhbt_n_headers; ++i) 274 { 275 /* Increase buffers one by one to exercise error conditions */ 276 enc_sz = 0; 277 header_sz = 0; 278 while (1) 279 { 280 hbuf.off = 0; 281 s = header_set_ptr(&xhdr, &hbuf, 282 test->qhbt_headers[i].name, 283 strlen(test->qhbt_headers[i].name), 284 test->qhbt_headers[i].value, 285 strlen(test->qhbt_headers[i].value)); 286 assert(s == 0); 287 enc_st = lsqpack_enc_encode(&enc, 288 enc_buf + enc_off, &enc_sz, 289 header_buf + header_off, &header_sz, 290 &xhdr, 291 test->qhbt_headers[i].flags); 292 switch (enc_st) 293 { 294 case LQES_NOBUF_ENC: 295 if (enc_sz < sizeof(enc_buf) - enc_off) 296 ++enc_sz; 297 else 298 assert(0); 299 break; 300 case LQES_NOBUF_HEAD: 301 if (header_sz < sizeof(header_buf) - header_off) 302 ++header_sz; 303 else 304 assert(0); 305 break; 306 default: 307 assert(enc_st == LQES_OK); 308 goto end_encode_one_header; 309 } 310 } 311 end_encode_one_header: 312 enc_off += enc_sz; 313 header_off += header_sz; 314 } 315 316 nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), NULL); 317 assert(nw == test->qhbt_prefix_sz); 318 assert(0 == memcmp(test->qhbt_prefix_buf, prefix_buf, nw)); 319 assert(enc_off == test->qhbt_enc_sz); 320 assert(0 == memcmp(test->qhbt_enc_buf, enc_buf, enc_off)); 321 assert(header_off == test->qhbt_header_sz); 322 assert(0 == memcmp(test->qhbt_header_buf, header_buf, header_off)); 323 assert(lsqpack_enc_ratio(&enc) > 0.0); 324 325 lsqpack_enc_cleanup(&enc); 326} 327 328 329struct dhte /* decoded header test ext */ 330{ 331 struct lsxpack_header xhdr; 332 size_t buf_off; 333 char buf[0x1000]; 334}; 335 336 337static void 338dht_unblocked (void *hblock_ctx_p) 339{ 340 assert(0); /* Not expecting this to be called */ 341} 342 343 344static struct lsxpack_header * 345dht_prepare_decode (void *hblock_ctx_p, struct lsxpack_header *xhdr, size_t space) 346{ 347 struct dhte *const dhte = hblock_ctx_p; 348 size_t avail; 349 350 if (space > LSXPACK_MAX_STRLEN) 351 return NULL; 352 353 if (xhdr) 354 { 355 assert(xhdr == &dhte->xhdr); 356 assert(xhdr->val_len < space); 357 avail = sizeof(dhte->buf) - xhdr->name_offset - 1 /* NUL */; 358 if (avail < space) 359 return NULL; 360 xhdr->val_len = space; 361 } 362 else 363 { 364 avail = sizeof(dhte->buf) - dhte->buf_off - 1 /* NUL */; 365 if (avail < space) 366 return NULL; 367 lsxpack_header_prepare_decode(&dhte->xhdr, dhte->buf, dhte->buf_off, 368 space); 369 } 370 371 return &dhte->xhdr; 372} 373 374 375static int 376dht_process_header (void *hblock_ctx_p, struct lsxpack_header *xhdr) 377{ 378 struct dhte *const dhte = hblock_ctx_p; 379 380 assert(xhdr == &dhte->xhdr); 381 dhte->buf_off += lsxpack_header_get_dec_size(xhdr); 382 383 return 0; 384} 385 386 387static void 388run_decoded_headers_test_ext (const struct qpack_header_block_test *test, 389 const enum lsqpack_dec_opts opts, const size_t name_offset) 390{ 391 struct lsqpack_dec dec; 392 char exp_hbuf[0x1000]; /* Large enough to hold all headers */ 393 struct dhte dhte; 394 size_t sz; 395 unsigned i; 396 int s; 397 enum lsqpack_read_header_status rhs; 398 const unsigned char *buf; 399 unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 400 size_t dec_sz; 401 const struct lsqpack_dec_hset_if dht_if = { 402 .dhi_unblocked = dht_unblocked, 403 .dhi_prepare_decode = dht_prepare_decode, 404 .dhi_process_header = dht_process_header, 405 }; 406 407 /* Construct expected headers buffer: */ 408 sz = 0; 409 exp_hbuf[0] = '\0'; 410 for (i = 0; i < test->qhbt_n_headers; ++i) 411 { 412 strcpy(exp_hbuf + sz, test->qhbt_headers[i].name); 413 sz += strlen(test->qhbt_headers[i].name); 414 if (opts & LSQPACK_DEC_OPT_HTTP1X) 415 { 416 strcpy(exp_hbuf + sz, ": "); 417 sz += 2; 418 } 419 strcpy(exp_hbuf + sz, test->qhbt_headers[i].value); 420 sz += strlen(test->qhbt_headers[i].value); 421 if (opts & LSQPACK_DEC_OPT_HTTP1X) 422 { 423 strcpy(exp_hbuf + sz, "\r\n"); 424 sz += 2; 425 } 426 } 427 assert(sz < sizeof(exp_hbuf)); /* Self-check */ 428 429 /* Decode headers into dhte buffer */ 430 dhte.buf_off = name_offset; 431 lsqpack_dec_init(&dec, NULL, test->qhbt_table_size, 432 test->qhbt_max_risked_streams, &dht_if, opts); 433 if (test->qhbt_enc_sz) 434 { 435 s = lsqpack_dec_enc_in(&dec, test->qhbt_enc_buf, test->qhbt_enc_sz); 436 assert(s == 0); 437 } 438 assert(test->qhbt_header_sz); /* Self-check */ 439 buf = test->qhbt_prefix_buf; 440 dec_sz = sizeof(dec_buf); 441 rhs = lsqpack_dec_header_in(&dec, &dhte, 0, 442 test->qhbt_prefix_sz + test->qhbt_header_sz, 443 &buf, test->qhbt_prefix_sz, 444 dec_buf, &dec_sz); 445 assert(rhs == LQRHS_NEED); 446 assert(buf == test->qhbt_prefix_buf + test->qhbt_prefix_sz); 447 buf = test->qhbt_header_buf; 448 dec_sz = sizeof(dec_buf); 449 rhs = lsqpack_dec_header_read(&dec, &dhte, 450 &buf, test->qhbt_header_sz, 451 dec_buf, &dec_sz); 452 assert(rhs == LQRHS_DONE); 453 assert(buf == test->qhbt_header_buf + test->qhbt_header_sz); 454 lsqpack_dec_cleanup(&dec); 455 456 /* Now compare the buffers */ 457 dhte.buf[dhte.buf_off] = '\0'; 458 s = strcmp(dhte.buf + name_offset, exp_hbuf); 459 assert(s == 0); 460} 461 462 463static void 464run_decoded_headers_test (const struct qpack_header_block_test *test) 465{ 466 const enum lsqpack_dec_opts opts[] = { 0, LSQPACK_DEC_OPT_HTTP1X, }; 467 const size_t offs[] = { 0, 1, 20, }; 468 unsigned i, j; 469 470 for (i = 0; i < sizeof(opts) / sizeof(opts[0]); ++i) 471 for (j = 0; j < sizeof(offs) / sizeof(offs[0]); ++j) 472 run_decoded_headers_test_ext(test, opts[i], offs[j]); 473} 474 475 476static void 477run_header_cancellation_test(const struct qpack_header_block_test *test) { 478 unsigned char header_buf[HEADER_BUF_SZ]; 479 size_t header_sz, enc_sz; 480 struct lsqpack_enc enc; 481 int s; 482 enum lsqpack_enc_status enc_st; 483 struct lsxpack_header xhdr; 484 struct header_buf hbuf; 485 486 s = lsqpack_enc_init(&enc, stderr, 0, 0, test->qhbt_max_risked_streams, 487 LSQPACK_ENC_OPT_IX_AGGR, NULL, NULL); 488 assert(s == 0); 489 490 s = lsqpack_enc_start_header(&enc, 0, 0); 491 assert(s == 0); 492 493 header_sz = HEADER_BUF_SZ; 494 enc_sz = 0; 495 496 hbuf.off = 0; 497 header_set_ptr(&xhdr, &hbuf, 498 test->qhbt_headers[0].name, 499 strlen(test->qhbt_headers[0].name), 500 test->qhbt_headers[0].value, 501 strlen(test->qhbt_headers[0].value)); 502 enc_st = lsqpack_enc_encode(&enc, 503 NULL, &enc_sz, 504 header_buf, &header_sz, 505 &xhdr, 506 0); 507 assert(enc_st == LQES_OK); 508 509 s = lsqpack_enc_cancel_header(&enc); 510 assert(s == 0); 511 512 /* Check that we can start again after cancelling. */ 513 s = lsqpack_enc_start_header(&enc, 0, 0); 514 assert(s == 0); 515 516 lsqpack_enc_cleanup(&enc); 517} 518 519 520static void 521test_enc_init (void) 522{ 523 struct lsqpack_enc enc; 524 size_t dec_sz; 525 int s; 526 unsigned i; 527 const unsigned char *p; 528 uint64_t val; 529 struct lsqpack_dec_int_state state; 530 unsigned char dec_buf[LSQPACK_LONGEST_SDTC]; 531 532 const struct { 533 unsigned peer_max_size; /* Value provided by peer */ 534 unsigned our_max_size; /* Value to use */ 535 int expected_tsu; /* Expecting TSU instruction? */ 536 } tests[] = { 537 { 0x1000, 0x1000, 1, }, 538 { 0x1000, 1, 1, }, 539 { 0x100, 0x100, 1, }, 540 { 0x1000, 0, 0, }, 541 }; 542 543 for (i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) 544 { 545 dec_sz = sizeof(dec_buf); 546 s = lsqpack_enc_init(&enc, stderr, tests[i].peer_max_size, 547 tests[i].our_max_size, 0, 0, dec_buf, &dec_sz); 548 assert(s == 0); 549 if (tests[i].expected_tsu) 550 { 551 assert(dec_sz > 0); 552 assert((dec_buf[0] & 0xE0) == 0x20); 553 p = dec_buf; 554 state.resume = 0; 555 s = lsqpack_dec_int(&p, p + dec_sz, 5, &val, &state); 556 assert(s == 0); 557 assert(val == tests[i].our_max_size); 558 } 559 else 560 assert(dec_sz == 0); 561 lsqpack_enc_cleanup(&enc); 562 } 563} 564 565 566/* Test that push promise header does not use the dynamic table, nor does 567 * it update history. 568 */ 569static void 570test_push_promise (void) 571{ 572 struct lsqpack_enc enc; 573 ssize_t nw; 574 enum lsqpack_enc_status enc_st; 575 int s; 576 unsigned i; 577 const unsigned char *p; 578 uint64_t val; 579 struct lsqpack_dec_int_state state; 580 unsigned char dec_buf[LSQPACK_LONGEST_SDTC]; 581 unsigned char header_buf[HEADER_BUF_SZ], enc_buf[ENC_BUF_SZ], 582 prefix_buf[PREFIX_BUF_SZ]; 583 size_t header_sz, enc_sz, dec_sz; 584 enum lsqpack_enc_header_flags hflags; 585 struct lsxpack_header xhdr; 586 struct header_buf hbuf; 587 588 dec_sz = sizeof(dec_buf); 589 s = lsqpack_enc_init(&enc, stderr, 0x1000, 0x1000, 100, 0, dec_buf, &dec_sz); 590 assert(0 == s); 591 592 (void) dec_sz; /* We don't care for this test */ 593 594 s = lsqpack_enc_start_header(&enc, 0, 0); 595 assert(0 == s); 596 enc_sz = sizeof(enc_buf); 597 header_sz = sizeof(header_buf); 598 hbuf.off = 0; 599 header_set_ptr(&xhdr, &hbuf, ":method", 7, "dude!", 5); 600 enc_st = lsqpack_enc_encode(&enc, 601 enc_buf, &enc_sz, header_buf, &header_sz, 602 &xhdr, 0); 603 assert(LQES_OK == enc_st); 604 enc_sz = sizeof(enc_buf); 605 header_sz = sizeof(header_buf); 606 header_set_ptr(&xhdr, &hbuf, ":method", 7, "dude!", 5); 607 enc_st = lsqpack_enc_encode(&enc, 608 enc_buf, &enc_sz, header_buf, &header_sz, 609 &xhdr, 0); 610 assert(LQES_OK == enc_st); 611 nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), &hflags); 612 assert(2 == nw); 613 assert(!(prefix_buf[0] == 0 && prefix_buf[1] == 0)); /* Dynamic table used */ 614 assert(hflags & LSQECH_REF_NEW_ENTRIES); 615 assert(hflags & LSQECH_REF_AT_RISK); 616 617 s = lsqpack_enc_start_header(&enc, 0, 0); 618 assert(0 == s); 619 enc_sz = sizeof(enc_buf); 620 header_sz = sizeof(header_buf); 621 header_set_ptr(&xhdr, &hbuf, ":method", 7, "dude!", 5); 622 enc_st = lsqpack_enc_encode(&enc, 623 enc_buf, &enc_sz, header_buf, &header_sz, 624 &xhdr, LQEF_NO_HIST_UPD|LQEF_NO_DYN); 625 assert(LQES_OK == enc_st); 626 enc_sz = sizeof(enc_buf); 627 header_sz = sizeof(header_buf); 628 header_set_ptr(&xhdr, &hbuf, ":method", 7, "where is my car?", 16); 629 enc_st = lsqpack_enc_encode(&enc, 630 enc_buf, &enc_sz, header_buf, &header_sz, 631 &xhdr, LQEF_NO_HIST_UPD|LQEF_NO_DYN); 632 nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), &hflags); 633 assert(2 == nw); 634 assert(prefix_buf[0] == 0 && prefix_buf[1] == 0); /* Dynamic table not used */ 635 assert(!(hflags & LSQECH_REF_NEW_ENTRIES)); 636 637 /* Last check that history was not updated: */ 638 s = lsqpack_enc_start_header(&enc, 4, 0); 639 assert(0 == s); 640 enc_sz = sizeof(enc_buf); 641 header_sz = sizeof(header_buf); 642 header_set_ptr(&xhdr, &hbuf, ":method", 7, "where is my car?", 16); 643 enc_st = lsqpack_enc_encode(&enc, 644 enc_buf, &enc_sz, header_buf, &header_sz, 645 &xhdr, 0); 646 assert(enc_sz == 0); 647 assert(LQES_OK == enc_st); 648 nw = lsqpack_enc_end_header(&enc, prefix_buf, sizeof(prefix_buf), &hflags); 649 assert(2 == nw); 650 assert(prefix_buf[0] == 0 && prefix_buf[1] == 0); /* Dynamic table not used */ 651 assert(!(hflags & LSQECH_REF_AT_RISK)); 652 653 lsqpack_enc_cleanup(&enc); 654} 655 656 657struct hblock_ctx 658{ 659 unsigned n_headers; 660 int finished; 661 struct lsxpack_header xhdr; 662 char buf[0x10000]; 663}; 664 665 666static void 667unblocked (void *hblock_ctx_p) 668{ 669 assert(0); /* Not expecting this to be called */ 670} 671 672 673static struct lsxpack_header * 674prepare_decode (void *hblock_ctx_p, struct lsxpack_header *xhdr, size_t space) 675{ 676 struct hblock_ctx *const hctx = hblock_ctx_p; 677 678 if (space > LSXPACK_MAX_STRLEN) 679 return NULL; 680 681 if (xhdr) 682 return NULL; 683 684 lsxpack_header_prepare_decode(&hctx->xhdr, hctx->buf, 0, sizeof(hctx->buf)); 685 return &hctx->xhdr; 686} 687 688 689static int 690process_header (void *hblock_ctx_p, struct lsxpack_header *xhdr) 691{ 692 struct hblock_ctx *const hctx = hblock_ctx_p; 693 694 if (xhdr) 695 ++hctx->n_headers; 696 else 697 hctx->finished = 1; 698 return 0; 699} 700 701 702static const struct lsqpack_dec_hset_if hset_if = { 703 .dhi_unblocked = unblocked, 704 .dhi_prepare_decode = prepare_decode, 705 .dhi_process_header = process_header, 706}; 707 708 709static void 710test_discard_header (int err) 711{ 712 struct lsqpack_dec dec; 713 enum lsqpack_read_header_status rhs; 714 const unsigned char *buf; 715 unsigned char header_block[] = "\x00\x00\xC0\x80"; 716 struct hblock_ctx hctx = { .n_headers = 0, }; 717 718 lsqpack_dec_init(&dec, NULL, 0, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 719 720 buf = header_block; 721 rhs = lsqpack_dec_header_in(&dec, &hctx, 0, 10, 722 &buf, 3 + !!err, NULL, NULL); 723 if (err) 724 { 725 assert(hctx.n_headers == 1); 726 assert(hctx.finished == 0); 727 assert(LQRHS_ERROR == rhs); 728 } 729 else 730 { 731 assert(hctx.n_headers == 1); 732 assert(hctx.finished == 0); 733 assert(3 == buf - header_block); 734 assert(LQRHS_NEED == rhs); 735 lsqpack_dec_cleanup(&dec); 736 } 737} 738 739 740static void 741test_static_bounds_header_block (void) 742{ 743 struct lsqpack_dec dec; 744 enum lsqpack_read_header_status rhs; 745 const unsigned char *buf; 746 /* Static table index 1000 */ 747 unsigned char header_block[] = "\x00\x00\xFF\xA9\x07"; 748 struct hblock_ctx hctx = { .n_headers = 0, }; 749 750 lsqpack_dec_init(&dec, stderr, 0, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 751 buf = header_block; 752 rhs = lsqpack_dec_header_in(&dec, &hctx, 0, 10, 753 &buf, 5, NULL, NULL); 754 assert(hctx.n_headers == 0); 755 assert(LQRHS_ERROR == rhs); 756 lsqpack_dec_cleanup(&dec); 757} 758 759 760static void 761test_static_bounds_enc_stream (void) 762{ 763 struct lsqpack_dec dec; 764 int r; 765 /* Static table index 1000 */ 766 unsigned char enc_stream[] = "\xFF\xA9\x07\x04" "dude"; 767 768 lsqpack_dec_init(&dec, NULL, 0, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 769 r = lsqpack_dec_enc_in(&dec, enc_stream, 8); 770 assert(r == -1); 771 lsqpack_dec_cleanup(&dec); 772} 773 774 775static void 776test_wonr_name_too_large_huffman (void) 777{ 778 struct lsqpack_dec dec; 779 int r; 780 /* Partial Insert Without Name Reference with Huffman-encoded name 781 * string that is larger than 4 x capacity (0x4001) 782 */ 783 unsigned char enc_stream[] = "\x7F\xE2\x7F"; 784 785 lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 786 r = lsqpack_dec_enc_in(&dec, enc_stream, 3); 787 assert(r == -1); 788 lsqpack_dec_cleanup(&dec); 789} 790 791 792static void 793test_wonr_name_too_large_plain (void) 794{ 795 struct lsqpack_dec dec; 796 int r; 797 /* Partial Insert Without Name Reference with plain-encoded name 798 * string that is larger than capacity (0x1001) 799 */ 800 unsigned char enc_stream[] = "\x5F\xE2\x1F"; 801 802 lsqpack_dec_init(&dec, stderr, 0, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 803 r = lsqpack_dec_enc_in(&dec, enc_stream, 3); 804 assert(r == -1); 805 lsqpack_dec_cleanup(&dec); 806} 807 808 809static void 810test_wonr_value_too_large_huffman (void) 811{ 812 struct lsqpack_dec dec; 813 int r; 814 /* Partial Insert Without Name Reference with Huffman-encoded value 815 * string that, together with name, is larger than 4 x capacity (0x3FFF) 816 */ 817 unsigned char enc_stream[] = "\x42OK\xFF\x80\x7F"; 818 819 lsqpack_dec_init(&dec, stderr, 0, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 820 r = lsqpack_dec_enc_in(&dec, enc_stream, 6); 821 assert(r == -1); 822 lsqpack_dec_cleanup(&dec); 823} 824 825 826static void 827test_wonr_value_too_large_plain (void) 828{ 829 struct lsqpack_dec dec; 830 int r; 831 /* Partial Insert Without Name Reference with plain-encoded value 832 * string that, together with name, is larger than capacity (0xFFF) 833 */ 834 unsigned char enc_stream[] = "\x42OK\x7F\x80\x1F"; 835 836 lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 837 r = lsqpack_dec_enc_in(&dec, enc_stream, 6); 838 assert(r == -1); 839 lsqpack_dec_cleanup(&dec); 840} 841 842 843static void 844test_winr_value_too_large_huffman (void) 845{ 846 struct lsqpack_dec dec; 847 int r; 848 /* Partial Insert With Name Reference with Huffman-encoded value 849 * string that, together with name, is larger than 4 x capacity (0x3FE4) 850 */ 851 /* Refer to static entry 79: access-control-refer-headers (length 28) */ 852 unsigned char enc_stream[] = "\xFF\x10\xFF\xE5\x7E"; 853 854 lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 855 r = lsqpack_dec_enc_in(&dec, enc_stream, 5); 856 assert(r == -1); 857 lsqpack_dec_cleanup(&dec); 858} 859 860 861static void 862test_winr_value_too_large_plain (void) 863{ 864 struct lsqpack_dec dec; 865 int r; 866 /* Partial Insert With Name Reference with plain-encoded value 867 * string that, together with name, is larger than capacity (0xFE4) 868 */ 869 /* Refer to static entry 79: access-control-refer-headers (length 28) */ 870 unsigned char enc_stream[] = "\xFF\x10\x7F\xE5\x1E"; 871 872 lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 873 r = lsqpack_dec_enc_in(&dec, enc_stream, 5); 874 assert(r == -1); 875 lsqpack_dec_cleanup(&dec); 876} 877 878 879/* This is an odd case, but if the first call should provide no input at all, 880 * the decoder should return LQRHS_NEED 881 */ 882static void 883test_dec_header_zero_in (void) 884{ 885 struct lsqpack_dec dec; 886 struct lsqpack_header_list *hlist; 887 enum lsqpack_read_header_status rhs; 888 const unsigned char *buf = (unsigned char *) ""; 889 struct hblock_ctx hctx = { .n_headers = 0, }; 890 891 lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 892 893 rhs = lsqpack_dec_header_in(&dec, 894 &hctx /* hblock */, 895 2 /* Stream ID */, 896 100 /* How long the thing is */, 897 &buf, 898 0 /* How many bytes are available */, 899 NULL, 0); 900 assert(LQRHS_NEED == rhs); 901 902 lsqpack_dec_cleanup(&dec); 903} 904 905 906/* Header that's too should should return LQRHS_ERROR */ 907static void 908test_dec_header_too_short (size_t header_size) 909{ 910 struct lsqpack_dec dec; 911 struct lsqpack_header_list *hlist; 912 enum lsqpack_read_header_status rhs; 913 const unsigned char *buf = (unsigned char *) ""; 914 struct hblock_ctx hctx = { .n_headers = 0, }; 915 916 lsqpack_dec_init(&dec, stderr, 0x1000, 0, &hset_if, LSQPACK_DEC_OPT_HTTP1X); 917 918 rhs = lsqpack_dec_header_in(&dec, 919 &hctx /* hblock */, 920 2 /* Stream ID */, 921 header_size, 922 &buf, 923 0 /* How many bytes are available */, 924 NULL, 0); 925 assert(LQRHS_ERROR == rhs); 926 927 lsqpack_dec_cleanup(&dec); 928} 929 930 931static void 932test_enc_risked_streams_test (const char *test) 933{ 934 struct lsqpack_enc enc; 935 int s; 936 size_t sz; 937 ssize_t ssz; 938 long arg; 939 enum lsqpack_enc_status es; 940 unsigned n_seqnos = 0; 941 struct { 942 uint64_t stream_id; 943 unsigned seqno; 944 } seqnos[10], *seq_el; 945 unsigned char buf[0x100]; 946 unsigned char *end_cmd; 947 int expect_failure; 948 struct lsxpack_header xhdr; 949 struct header_buf hbuf; 950 951 const struct { 952 const char *name; 953 unsigned name_len; 954 const char *value; 955 unsigned value_len; 956 } headers[] = { 957 { "some", 4, "header", 6, }, 958 { "another", 7, "header", 6, }, 959 { "and yet another", 15, "header, duh", 11, }, 960 }; 961 962 fprintf(stderr, "BEGIN TEST %s\n", test); 963 lsqpack_enc_preinit(&enc, stderr); 964 hbuf.off = 0; 965 966 while (1) 967 { 968 expect_failure = isupper(*test); 969 switch (*test++) 970 { 971 case 'i': 972 arg = strtol(test, (char**)&test, 10); 973 sz = sizeof(buf); 974 s = lsqpack_enc_init(&enc, stderr, 0x1000, 0x1000, 975 (unsigned) arg, 0, buf, &sz); 976 assert(s == 0); 977 break; 978 case 'r': 979 arg = strtol(test, (char**)&test, 10); 980 assert((unsigned) arg == enc.qpe_cur_streams_at_risk); 981 break; 982 case 's': /* Start header */ 983 arg = strtol(test, (char**)&test, 10); 984 for (seq_el = seqnos; seq_el < seqnos + n_seqnos; ++seq_el) 985 if (seq_el->stream_id == arg) 986 break; 987 assert(seq_el < seqnos + sizeof(seqnos) / sizeof(seqnos[0])); 988 if (seq_el == seqnos + n_seqnos) 989 { 990 ++n_seqnos; 991 seq_el->stream_id = arg; 992 seq_el->seqno = 0; 993 } 994 s = lsqpack_enc_start_header(&enc, arg, seq_el->seqno++); 995 assert(s == 0); 996 break; 997 case 'c': /* En*C*ode */ 998 arg = strtol(test, (char**)&test, 10); 999 sz = sizeof(buf); 1000 /* We ignore the output */ 1001 header_set_ptr(&xhdr, &hbuf, 1002 headers[arg].name, headers[arg].name_len, 1003 headers[arg].value, headers[arg].value_len); 1004 es = lsqpack_enc_encode(&enc, buf, &sz, buf, &sz, &xhdr, 0); 1005 assert(LQES_OK == es); 1006 break; 1007 case 'e': /* End header */ 1008 ssz = lsqpack_enc_end_header(&enc, buf, sizeof(buf), NULL); 1009 assert(ssz > 0); 1010 break; 1011 case 'a': /* ACK header */ 1012 case 'A': 1013 arg = strtol(test, (char**)&test, 10); 1014 buf[0] = 0x80; 1015 end_cmd = lsqpack_enc_int(buf, buf + sizeof(buf), arg, 7); 1016 s = lsqpack_enc_decoder_in(&enc, buf, end_cmd - buf); 1017 if (expect_failure) 1018 assert(s < 0); 1019 else 1020 assert(s == 0); 1021 break; 1022 case 'L': /* Cancel header */ 1023 case 'l': 1024 arg = strtol(test, (char**)&test, 10); 1025 buf[0] = 0x40; 1026 end_cmd = lsqpack_enc_int(buf, buf + sizeof(buf), arg, 6); 1027 s = lsqpack_enc_decoder_in(&enc, buf, end_cmd - buf); 1028 if (expect_failure) 1029 assert(s < 0); 1030 else 1031 assert(s == 0); 1032 break; 1033 case 'N': /* Insert Count Increment */ 1034 case 'n': 1035 arg = strtol(test, (char**)&test, 10); 1036 buf[0] = 0x00; 1037 end_cmd = lsqpack_enc_int(buf, buf + sizeof(buf), arg, 6); 1038 s = lsqpack_enc_decoder_in(&enc, buf, end_cmd - buf); 1039 if (expect_failure) 1040 assert(s < 0); 1041 else 1042 assert(s == 0); 1043 break; 1044 break; 1045 case '\0': 1046 goto end; 1047 default: 1048 assert("unknown action"); 1049 goto end; 1050 } 1051 } 1052 1053 end: 1054 lsqpack_enc_cleanup(&enc); 1055} 1056 1057 1058static void 1059test_enc_risked_streams (void) 1060{ 1061 const char **test; 1062 const char *tests[] = 1063 { 1064 "i0r0s1c0er0", 1065 "i1r0s1c0er0s2c0er1A1r1a2r0", 1066 "i1r0s1c0er0s2c0er1s2c0c1er1a2r0a2r0", 1067 1068 "i1r0s1c0c1er0" 1069 "s2c0er1" 1070 "s2c0c1er1" 1071 "a2r1" /* Ack first seqno, # of risked streams still 1 */ 1072 "a2r0", 1073 1074 "i1r0s1c0c1er0" 1075 "s2c0er1" 1076 "s2c0c1er1" 1077 "l2r0" /* Cancel */ 1078 , 1079 1080 "i1r0s1c0c1er0" 1081 "s2c0er1" 1082 "s2c0c1er1" 1083 "N3" 1084 "n1r1" 1085 "n1r0" 1086 , 1087 1088 NULL, 1089 }; 1090 1091 for (test = tests; *test; ++test) 1092 test_enc_risked_streams_test(*test); 1093} 1094 1095 1096int 1097main (void) 1098{ 1099 unsigned i; 1100 1101 for (i = 0; i < sizeof(header_block_tests) 1102 / sizeof(header_block_tests[0]); ++i) 1103 { 1104 run_header_test(&header_block_tests[i]); 1105 run_decoded_headers_test(&header_block_tests[i]); 1106 } 1107 1108 run_header_cancellation_test(&header_block_tests[0]); 1109 test_enc_init(); 1110 test_push_promise(); 1111 test_discard_header(0); 1112 test_discard_header(1); 1113 test_static_bounds_header_block(); 1114 test_static_bounds_enc_stream(); 1115 test_wonr_name_too_large_huffman(); 1116 test_wonr_name_too_large_plain(); 1117 test_wonr_value_too_large_huffman(); 1118 test_wonr_value_too_large_plain(); 1119 test_winr_value_too_large_huffman(); 1120 test_winr_value_too_large_plain(); 1121 test_dec_header_zero_in(); 1122 test_dec_header_too_short(0); 1123 test_dec_header_too_short(1); 1124 test_enc_risked_streams(); 1125 1126 return 0; 1127} 1128