1 /** 2 * Huffman Tests 3 * 4 * Copyright: 5 * (C) 2012-2015 Tatsuhiro Tsujikawa 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Distributed under the terms of the MIT license with an additional section 1.2 of the curl/libcurl project. 10 * Consult the provided LICENSE.md file for details 11 */ 12 module libhttp2.huffman_tests; 13 14 import libhttp2.constants; 15 static if (TEST_ALL): 16 17 import libhttp2.buffers; 18 import libhttp2.huffman; 19 import libhttp2.deflater; 20 import libhttp2.inflater; 21 import libhttp2.types; 22 import libhttp2.frame; 23 import libhttp2.helpers; 24 import libhttp2.tests; 25 import std.c.string : memcmp, memset; 26 27 void test_hd_deflate() { 28 Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE); 29 Inflater inflater = Inflater(true); 30 HeaderField[] hfa1 = [HeaderField(":path", "/my-example/index.html"), HeaderField(":scheme", "https"), HeaderField("hello", "world")]; 31 HeaderField[] hfa2 = [HeaderField(":path", "/script.js"), HeaderField(":scheme", "https")]; 32 HeaderField[] hfa3 = [HeaderField("cookie", "k1=v1"), HeaderField("cookie", "k2=v2"), HeaderField("via", "proxy")]; 33 HeaderField[] hfa4 = [HeaderField(":path", "/style.css"), HeaderField("cookie", "k1=v1"), HeaderField("cookie", "k1=v1")]; 34 HeaderField[] hfa5 = [HeaderField(":path", "/style.css"), HeaderField("x-nghttp2", "")]; 35 Buffers bufs = framePackBuffers(); 36 size_t blocklen; 37 HeaderFields output; 38 ErrorCode rv; 39 40 rv = deflater.deflate(bufs, hfa1); 41 blocklen = bufs.length; 42 assert(0 == rv); 43 assert(blocklen > 0); 44 assert(blocklen == output.inflate(inflater, bufs, 0)); 45 46 assert(3 == output.length); 47 assert(hfa1.equals(output[0 .. 3])); 48 49 output.reset(); 50 bufs.reset(); 51 52 /* Second headers */ 53 rv = deflater.deflate(bufs, hfa2); 54 blocklen = bufs.length; 55 56 assert(0 == rv); 57 assert(blocklen > 0); 58 assert(blocklen == output.inflate(inflater, bufs, 0)); 59 60 assert(2 == output.length); 61 assert(hfa2.equals(output[0 .. 2])); 62 63 output.reset(); 64 bufs.reset(); 65 66 /* Third headers, including same header field name, but value is not 67 the same. */ 68 rv = deflater.deflate(bufs, hfa3); 69 blocklen = bufs.length; 70 71 assert(0 == rv); 72 assert(blocklen > 0); 73 assert(blocklen == output.inflate(inflater, bufs, 0)); 74 75 assert(3 == output.length); 76 assert(hfa3.equals(output[0 .. 3])); 77 78 output.reset(); 79 bufs.reset(); 80 81 /* Fourth headers, including duplicate header fields. */ 82 rv = deflater.deflate(bufs, hfa4); 83 blocklen = bufs.length; 84 85 assert(0 == rv); 86 assert(blocklen > 0); 87 assert(blocklen == output.inflate(inflater, bufs, 0)); 88 89 assert(3 == output.length); 90 assert(hfa4.equals(output[0 .. 3])); 91 92 output.reset(); 93 bufs.reset(); 94 95 /* Fifth headers includes empty value */ 96 rv = deflater.deflate(bufs, hfa5); 97 blocklen = bufs.length; 98 99 assert(0 == rv); 100 assert(blocklen > 0); 101 assert(blocklen == output.inflate(inflater, bufs, 0)); 102 103 assert(2 == output.length); 104 assert(hfa5.equals(output[0 .. 2])); 105 106 output.reset(); 107 bufs.reset(); 108 109 /* Cleanup */ 110 bufs.free(); 111 inflater.free(); 112 deflater.free(); 113 } 114 115 void test_hd_deflate_same_indexed_repr() { 116 Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE); 117 Inflater inflater = Inflater(true); 118 HeaderField[] hfa1 = [HeaderField("cookie", "alpha"), HeaderField("cookie", "alpha")]; 119 HeaderField[] hfa2 = [HeaderField("cookie", "alpha"), HeaderField("cookie", "alpha"), HeaderField("cookie", "alpha")]; 120 Buffers bufs = framePackBuffers(); 121 size_t blocklen; 122 HeaderFields output; 123 ErrorCode rv; 124 125 /* Encode 2 same headers. Emit 1 literal reprs and 1 index repr. */ 126 rv = deflater.deflate(bufs, hfa1); 127 blocklen = bufs.length; 128 129 assert(0 == rv); 130 assert(blocklen > 0); 131 assert(blocklen == output.inflate(inflater, bufs, 0)); 132 133 assert(2 == output.length); 134 assert(hfa1.equals(output[])); 135 136 output.reset(); 137 bufs.reset(); 138 139 /* Encode 3 same headers. This time, emits 3 index reprs. */ 140 rv = deflater.deflate(bufs, hfa2); 141 blocklen = bufs.length; 142 143 assert(0 == rv); 144 assert(blocklen == 3); 145 assert(blocklen == output.inflate(inflater, bufs, 0)); 146 147 assert(3 == output.length); 148 assert(hfa2.equals(output[0 .. 3])); 149 150 output.reset(); 151 bufs.reset(); 152 153 /* Cleanup */ 154 bufs.free(); 155 inflater.free(); 156 deflater.free(); 157 } 158 159 void test_hd_inflate_indexed() { 160 Inflater inflater = Inflater(true); 161 Buffers bufs = framePackBuffers(); 162 size_t blocklen; 163 HeaderField hf = HeaderField(":path", "/"); 164 HeaderFields output; 165 166 bufs.add((1 << 7) | 4); 167 168 blocklen = bufs.length; 169 170 assert(1 == blocklen); 171 assert(blocklen == output.inflate(inflater, bufs, 0)); 172 173 assert(1 == output.length); 174 175 assert(hf == output.hfa_raw[0]); 176 177 output.reset(); 178 bufs.reset(); 179 180 /* index = 0 is error */ 181 bufs.add(1 << 7); 182 183 blocklen = bufs.length; 184 185 assert(1 == blocklen); 186 assert(ErrorCode.HEADER_COMP == output.inflate(inflater, bufs, 0)); 187 188 bufs.free(); 189 inflater.free(); 190 } 191 192 void test_hd_inflate_indname_noinc() { 193 Inflater inflater = Inflater(true); 194 Buffers bufs = framePackBuffers(); 195 size_t blocklen; 196 HeaderField[] hfa = [ 197 /* Huffman */ 198 HeaderField("user-agent", "nghttp2"), 199 /* Expecting no huffman */ 200 HeaderField("user-agent", "x") 201 ]; 202 size_t i; 203 HeaderFields output; 204 205 foreach (ref hf; hfa) { 206 assert(0 == bufs.emitIndexedNameBlock(57, hf, false)); 207 blocklen = bufs.length; 208 209 assert(blocklen > 0); 210 assert(blocklen == output.inflate(inflater, bufs, 0)); 211 assert(1 == output.length); 212 assert(hf == output.hfa_raw[0]); 213 assert(0 == inflater.ctx.hd_table.length); 214 215 output.reset(); 216 bufs.reset(); 217 } 218 219 bufs.free(); 220 inflater.free(); 221 } 222 223 void test_hd_inflate_indname_inc() { 224 Inflater inflater = Inflater(true); 225 Buffers bufs = framePackBuffers(); 226 size_t blocklen; 227 HeaderField hf = HeaderField("user-agent", "nghttp2"); 228 HeaderFields output; 229 assert(0 == bufs.emitIndexedNameBlock(57, hf, 1)); 230 blocklen = bufs.length; 231 232 assert(blocklen > 0); 233 assert(blocklen == output.inflate(inflater, bufs, 0)); 234 assert(1 == output.length); 235 assert(hf == output.hfa_raw[0]); 236 assert(1 == inflater.ctx.hd_table.length); 237 assert(hf == inflater.ctx.get(static_table.length + inflater.ctx.hd_table.length - 1).hf); 238 239 output.reset(); 240 bufs.free(); 241 inflater.free(); 242 } 243 244 void test_hd_inflate_indname_inc_eviction() { 245 Inflater inflater = Inflater(true); 246 Buffers bufs = framePackBuffers(); 247 size_t blocklen; 248 ubyte[1024] value; 249 memset(value.ptr, '0', value.length); 250 HeaderFields output; 251 HeaderField hf; 252 253 hf.value = cast(string)value; 254 hf.flag = HeaderFlag.NONE; 255 256 assert(0 == bufs.emitIndexedNameBlock(14, hf, true)); 257 assert(0 == bufs.emitIndexedNameBlock(15, hf, true)); 258 assert(0 == bufs.emitIndexedNameBlock(16, hf, true)); 259 assert(0 == bufs.emitIndexedNameBlock(17, hf, true)); 260 261 blocklen = bufs.length; 262 263 assert(blocklen > 0); 264 265 assert(blocklen == output.inflate(inflater, bufs, 0)); 266 267 assert(4 == output.length); 268 assert(14 == output.hfa_raw[0].name.length); 269 assert("accept-charset" == output.hfa_raw[0].name); 270 assert(value.length == output.hfa_raw[0].value.length); 271 272 output.reset(); 273 bufs.reset(); 274 275 assert(3 == inflater.ctx.hd_table.length); 276 277 bufs.free(); 278 inflater.free(); 279 } 280 281 void test_hd_inflate_newname_noinc() { 282 Inflater inflater = Inflater(true); 283 Buffers bufs = framePackBuffers(); 284 size_t blocklen; 285 HeaderField[] hfa = [/* Expecting huffman for both */ 286 HeaderField("my-long-content-length", "nghttp2"), 287 /* Expecting no huffman for both */ 288 HeaderField("x", "y"), 289 /* Huffman for key only */ 290 HeaderField("my-long-content-length", "y"), 291 /* Huffman for value only */ 292 HeaderField("x", "nghttp2")]; 293 size_t i; 294 HeaderFields output; 295 296 foreach (ref hf; hfa) { 297 assert(0 == bufs.emitNewNameBlock(hf, false)); 298 299 blocklen = bufs.length; 300 301 assert(blocklen > 0); 302 assert(blocklen == output.inflate(inflater, bufs, 0)); 303 304 assert(1 == output.length); 305 assert(hf == output.hfa_raw[0]); 306 assert(0 == inflater.ctx.hd_table.length); 307 308 output.reset(); 309 bufs.reset(); 310 } 311 312 bufs.free(); 313 inflater.free(); 314 } 315 316 void test_hd_inflate_newname_inc() { 317 Inflater inflater = Inflater(true); 318 Buffers bufs = framePackBuffers(); 319 size_t blocklen; 320 HeaderField hf = HeaderField("x-rel", "nghttp2"); 321 HeaderFields output; 322 323 assert(0 == bufs.emitNewNameBlock(hf, true)); 324 325 blocklen = bufs.length; 326 327 assert(blocklen > 0); 328 assert(blocklen == output.inflate(inflater, bufs, 0)); 329 330 assert(1 == output.length); 331 assert(hf == output.hfa_raw[0]); 332 assert(1 == inflater.ctx.hd_table.length); 333 assert(hf == inflater.ctx.get(static_table.length + inflater.ctx.hd_table.length - 1).hf); 334 335 output.reset(); 336 bufs.free(); 337 inflater.free(); 338 } 339 340 void test_hd_inflate_clearall_inc() { 341 Inflater inflater = Inflater(true); 342 Buffers bufs = largeBuffers(8192); 343 size_t blocklen; 344 HeaderField hf; 345 ubyte[4060] value; 346 memset(value.ptr, '0', value.length); 347 HeaderFields output; 348 349 /* Total 4097 bytes space required to hold this entry */ 350 hf.name = "alpha"; 351 hf.value = cast(string)value; 352 hf.flag = HeaderFlag.NONE; 353 354 assert(0 == bufs.emitNewNameBlock(hf, true)); 355 356 blocklen = bufs.length; 357 358 assert(blocklen > 0); 359 assert(blocklen == output.inflate(inflater, bufs, 0)); 360 361 assert(1 == output.length); 362 assert(hf == output.hfa_raw[0]); 363 assert(0 == inflater.ctx.hd_table.length); 364 365 output.reset(); 366 367 /* Do it again */ 368 assert(blocklen == output.inflate(inflater, bufs, 0)); 369 370 assert(1 == output.length); 371 assert(hf == output.hfa_raw[0]); 372 assert(0 == inflater.ctx.hd_table.length); 373 374 output.reset(); 375 bufs.reset(); 376 377 /* This time, 4096 bytes space required, which is just fits in the header table */ 378 hf.value = hf.value[0 .. 4059]; 379 assert(0 == bufs.emitNewNameBlock(hf, true)); 380 381 blocklen = bufs.length; 382 383 assert(blocklen > 0); 384 assert(blocklen == output.inflate(inflater, bufs, 0)); 385 386 assert(1 == output.length); 387 assert(hf == output.hfa_raw[0]); 388 assert(1 == inflater.ctx.hd_table.length); 389 390 output.reset(); 391 bufs.reset(); 392 393 bufs.free(); 394 inflater.free(); 395 } 396 397 void test_hd_inflate_zero_length_huffman() { 398 Inflater inflater = Inflater(true); 399 Buffers bufs = framePackBuffers(); 400 /* Literal header without indexing - new name */ 401 ubyte[] data = [0x40, 0x01, 0x78 /* 'x' */, 0x80]; 402 HeaderFields output; 403 404 bufs.add(cast(string)data); 405 406 /* /\* Literal header without indexing - new name *\/ */ 407 /* ptr[0] = 0x40; */ 408 /* ptr[1] = 1; */ 409 /* ptr[2] = 'x'; */ 410 /* ptr[3] = 0x80; */ 411 412 413 assert(4 == output.inflate(inflater, bufs, 0)); 414 415 assert(1 == output.length); 416 assert(1 == output.hfa_raw[0].name.length); 417 assert('x' == output.hfa_raw[0].name[0]); 418 assert(null == output.hfa_raw[0].value); 419 assert(0 == output.hfa_raw[0].value.length); 420 421 output.reset(); 422 bufs.free(); 423 inflater.free(); 424 } 425 426 void test_hd_ringbuf_reserve() { 427 Deflater deflater; 428 Inflater inflater = Inflater(true); 429 HeaderField hf; 430 Buffers bufs = framePackBuffers(); 431 HeaderFields output; 432 int i; 433 size_t rv; 434 size_t blocklen; 435 436 hf.flag = HeaderFlag.NONE; 437 hf.name = "a"; 438 char[] value = Mem.alloc!(char[])(4); 439 memset(value.ptr, 0, value.length); 440 hf.value = cast(string) value; 441 deflater = Deflater(8000); 442 443 444 inflater.changeTableSize(8000); 445 deflater.changeTableSize(8000); 446 447 for (i = 0; i < 150; ++i) { 448 memcpy(value.ptr, &i, i.sizeof); 449 rv = deflater.deflate(bufs, hf); 450 blocklen = bufs.length; 451 452 assert(0 == rv); 453 assert(blocklen > 0); 454 455 assert(blocklen == output.inflate(inflater, bufs, 0)); 456 457 assert(1 == output.length); 458 assert(hf == output.hfa_raw[0]); 459 460 output.reset(); 461 bufs.reset(); 462 } 463 464 bufs.free(); 465 inflater.free(); 466 deflater.free(); 467 468 Mem.free(hf.value); 469 } 470 471 void test_hd_change_table_size() { 472 Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE); 473 Inflater inflater = Inflater(true); 474 HeaderField[] hfa = [HeaderField("alpha", "bravo"), HeaderField("charlie", "delta")]; 475 HeaderField[] hfa2 = [HeaderField(":path", "/")]; 476 Buffers bufs = framePackBuffers(); 477 size_t rv; 478 HeaderFields output; 479 size_t blocklen; 480 481 /* inflater changes notifies 8000 max header table size */ 482 inflater.changeTableSize(8000); 483 deflater.changeTableSize(8000); 484 485 assert(4096 == deflater.ctx.hd_table_bufsize_max); 486 487 assert(8000 == inflater.ctx.hd_table_bufsize_max); 488 assert(8000 == inflater.settings_hd_table_bufsize_max); 489 490 /* This will emit encoding context update with header table size 4096 */ 491 rv = deflater.deflate(bufs, hfa[0 .. 2]); 492 blocklen = bufs.length; 493 494 assert(0 == rv); 495 assert(blocklen > 0); 496 assert(2 == deflater.ctx.hd_table.length); 497 assert(4096 == deflater.ctx.hd_table_bufsize_max); 498 499 assert(blocklen == output.inflate(inflater, bufs, 0)); 500 assert(2 == inflater.ctx.hd_table.length); 501 assert(4096 == inflater.ctx.hd_table_bufsize_max); 502 assert(8000 == inflater.settings_hd_table_bufsize_max); 503 504 output.reset(); 505 bufs.reset(); 506 507 /* inflater changes header table size to 1024 */ 508 inflater.changeTableSize(1024); 509 deflater.changeTableSize(1024); 510 511 assert(1024 == deflater.ctx.hd_table_bufsize_max); 512 513 assert(1024 == inflater.ctx.hd_table_bufsize_max); 514 assert(1024 == inflater.settings_hd_table_bufsize_max); 515 516 rv = deflater.deflate(bufs, hfa[0 .. 2]); 517 blocklen = bufs.length; 518 519 assert(0 == rv); 520 assert(blocklen > 0); 521 assert(2 == deflater.ctx.hd_table.length); 522 assert(1024 == deflater.ctx.hd_table_bufsize_max); 523 524 assert(blocklen == output.inflate(inflater, bufs, 0)); 525 assert(2 == inflater.ctx.hd_table.length); 526 assert(1024 == inflater.ctx.hd_table_bufsize_max); 527 assert(1024 == inflater.settings_hd_table_bufsize_max); 528 529 output.reset(); 530 bufs.reset(); 531 532 /* inflater changes header table size to 0 */ 533 inflater.changeTableSize(0); 534 deflater.changeTableSize(0); 535 536 assert(0 == deflater.ctx.hd_table.length); 537 assert(0 == deflater.ctx.hd_table_bufsize_max); 538 539 assert(0 == inflater.ctx.hd_table.length); 540 assert(0 == inflater.ctx.hd_table_bufsize_max); 541 assert(0 == inflater.settings_hd_table_bufsize_max); 542 543 rv = deflater.deflate(bufs, hfa[0 .. 2]); 544 blocklen = bufs.length; 545 546 assert(0 == rv); 547 assert(blocklen > 0); 548 assert(0 == deflater.ctx.hd_table.length); 549 assert(0 == deflater.ctx.hd_table_bufsize_max); 550 551 assert(blocklen == output.inflate(inflater, bufs, 0)); 552 assert(0 == inflater.ctx.hd_table.length); 553 assert(0 == inflater.ctx.hd_table_bufsize_max); 554 assert(0 == inflater.settings_hd_table_bufsize_max); 555 556 output.reset(); 557 bufs.reset(); 558 559 bufs.free(); 560 inflater.free(); 561 deflater.free(); 562 563 /* Check table buffer is expanded */ 564 bufs = framePackBuffers(); 565 566 deflater = Deflater(8192); 567 inflater = Inflater(true); 568 569 /* First inflater changes header table size to 8000 */ 570 inflater.changeTableSize(8000); 571 deflater.changeTableSize(8000); 572 573 assert(8000 == deflater.ctx.hd_table_bufsize_max); 574 575 assert(8000 == inflater.ctx.hd_table_bufsize_max); 576 assert(8000 == inflater.settings_hd_table_bufsize_max); 577 578 rv = deflater.deflate(bufs, hfa[0 .. 2]); 579 blocklen = bufs.length; 580 581 assert(0 == rv); 582 assert(blocklen > 0); 583 assert(2 == deflater.ctx.hd_table.length); 584 assert(8000 == deflater.ctx.hd_table_bufsize_max); 585 586 assert(blocklen == output.inflate(inflater, bufs, 0)); 587 assert(2 == inflater.ctx.hd_table.length); 588 assert(8000 == inflater.ctx.hd_table_bufsize_max); 589 assert(8000 == inflater.settings_hd_table_bufsize_max); 590 591 output.reset(); 592 bufs.reset(); 593 594 inflater.changeTableSize(16383); 595 deflater.changeTableSize(16383); 596 597 assert(8192 == deflater.ctx.hd_table_bufsize_max); 598 599 assert(16383 == inflater.ctx.hd_table_bufsize_max); 600 assert(16383 == inflater.settings_hd_table_bufsize_max); 601 602 rv = deflater.deflate(bufs, hfa[0 .. 2]); 603 blocklen = bufs.length; 604 605 assert(0 == rv); 606 assert(blocklen > 0); 607 assert(2 == deflater.ctx.hd_table.length); 608 assert(8192 == deflater.ctx.hd_table_bufsize_max); 609 610 assert(blocklen == output.inflate(inflater, bufs, 0)); 611 assert(2 == inflater.ctx.hd_table.length); 612 assert(8192 == inflater.ctx.hd_table_bufsize_max); 613 assert(16383 == inflater.settings_hd_table_bufsize_max); 614 615 output.reset(); 616 bufs.reset(); 617 618 /* Lastly, check the error condition */ 619 620 rv = bufs.emitTableSize(25600); 621 assert(rv == 0); 622 assert(ErrorCode.HEADER_COMP == output.inflate(inflater, bufs, 0)); 623 624 output.reset(); 625 bufs.reset(); 626 627 inflater.free(); 628 deflater.free(); 629 630 /* Check that encoder can handle the case where its allowable buffer 631 size is less than default size, 4096 */ 632 deflater = Deflater(1024); 633 inflater = Inflater(true); 634 635 assert(1024 == deflater.ctx.hd_table_bufsize_max); 636 637 /* This emits context update with buffer size 1024 */ 638 rv = deflater.deflate(bufs, hfa[0 .. 2]); 639 blocklen = bufs.length; 640 641 assert(0 == rv); 642 assert(blocklen > 0); 643 assert(2 == deflater.ctx.hd_table.length); 644 assert(1024 == deflater.ctx.hd_table_bufsize_max); 645 646 assert(blocklen == output.inflate(inflater, bufs, 0)); 647 assert(2 == inflater.ctx.hd_table.length); 648 assert(1024 == inflater.ctx.hd_table_bufsize_max); 649 assert(4096 == inflater.settings_hd_table_bufsize_max); 650 651 output.reset(); 652 bufs.reset(); 653 654 inflater.free(); 655 deflater.free(); 656 657 /* Check that table size uint.max can be received */ 658 deflater = Deflater(uint.max); 659 inflater = Inflater(true); 660 661 inflater.changeTableSize(uint.max); 662 deflater.changeTableSize(uint.max); 663 664 rv = deflater.deflate(bufs, hfa[0 .. 2]); 665 blocklen = bufs.length; 666 667 assert(0 == rv); 668 assert(uint.max == deflater.ctx.hd_table_bufsize_max); 669 670 assert(blocklen == output.inflate(inflater, bufs, 0)); 671 assert(uint.max == inflater.ctx.hd_table_bufsize_max); 672 assert(uint.max == inflater.settings_hd_table_bufsize_max); 673 674 output.reset(); 675 bufs.reset(); 676 677 inflater.free(); 678 deflater.free(); 679 680 /* Check that context update emitted twice 681 */ 682 deflater = Deflater(4096); 683 inflater = Inflater(true); 684 685 inflater.changeTableSize(0); 686 inflater.changeTableSize(3000); 687 deflater.changeTableSize(0); 688 deflater.changeTableSize(3000); 689 690 assert(0 == deflater.min_hd_table_bufsize_max); 691 assert(3000 == deflater.ctx.hd_table_bufsize_max); 692 693 rv = deflater.deflate(bufs, hfa2[0 .. 1]); 694 blocklen = bufs.length; 695 696 assert(0 == rv); 697 assert(3 < blocklen); 698 assert(3000 == deflater.ctx.hd_table_bufsize_max); 699 assert(uint.max == deflater.min_hd_table_bufsize_max); 700 701 assert(blocklen == output.inflate(inflater, bufs, 0)); 702 assert(3000 == inflater.ctx.hd_table_bufsize_max); 703 assert(3000 == inflater.settings_hd_table_bufsize_max); 704 705 output.reset(); 706 707 inflater.free(); 708 deflater.free(); 709 710 bufs.free(); 711 } 712 713 void check_deflate_inflate(ref Deflater deflater, ref Inflater inflater, HeaderField[] hfa) 714 { 715 Buffers bufs = framePackBuffers(); 716 size_t blocklen; 717 HeaderFields output; 718 ErrorCode rv; 719 720 rv = deflater.deflate(bufs, hfa); 721 blocklen = bufs.length; 722 723 assert(0 == rv); 724 assert(blocklen >= 0); 725 assert(blocklen == output.inflate(inflater, bufs, 0)); 726 assert(hfa.length == output.length); 727 assert(hfa.equals(output[])); 728 output.reset(); 729 bufs.free(); 730 } 731 732 void test_hd_deflate_inflate() { 733 Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE); 734 Inflater inflater = Inflater(true); 735 HeaderField[] hfa1 = [ 736 HeaderField(":status", "200 OK"), 737 HeaderField("access-control-allow-origin", "*"), 738 HeaderField("cache-control", "private, max-age=0, must-revalidate"), 739 HeaderField("content-length", "76073"), 740 HeaderField("content-type", "text/html"), 741 HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"), 742 HeaderField("expires", "Sat, 27 Jul 2013 06:22:12 GMT"), 743 HeaderField("server", "Apache"), 744 HeaderField("vary", "foobar"), 745 HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"), 746 HeaderField("x-cache", "MISS from alphabravo"), 747 HeaderField("x-cache-action", "MISS"), 748 HeaderField("x-cache-age", "0"), 749 HeaderField("x-cache-lookup", "MISS from alphabravo:3128"), 750 HeaderField("x-lb-nocache", "true") 751 ]; 752 HeaderField[] hfa2 = [ 753 HeaderField(":status", "304 Not Modified"), 754 HeaderField("age", "0"), 755 HeaderField("cache-control", "max-age=56682045"), 756 HeaderField("content-type", "text/css"), 757 HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"), 758 HeaderField("expires", "Thu, 14 May 2015 07:22:57 GMT"), 759 HeaderField("last-modified", "Tue, 14 May 2013 07:22:15 GMT"), 760 HeaderField("vary", "Accept-Encoding"), 761 HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"), 762 HeaderField("x-cache", "HIT from alphabravo"), 763 HeaderField("x-cache-lookup", "HIT from alphabravo:3128")]; 764 765 HeaderField[] hfa3 = [ 766 HeaderField(":status", "304 Not Modified"), 767 HeaderField("age", "0"), 768 HeaderField("cache-control", "max-age=56682072"), 769 HeaderField("content-type", "text/css"), 770 HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"), 771 HeaderField("expires", "Thu, 14 May 2015 07:23:24 GMT"), 772 HeaderField("last-modified", "Tue, 14 May 2013 07:22:13 GMT"), 773 HeaderField("vary", "Accept-Encoding"), 774 HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"), 775 HeaderField("x-cache", "HIT from alphabravo"), 776 HeaderField("x-cache-lookup", "HIT from alphabravo:3128") 777 ]; 778 779 HeaderField[] hfa4 = [ 780 HeaderField(":status", "304 Not Modified"), 781 HeaderField("age", "0"), 782 HeaderField("cache-control", "max-age=56682022"), 783 HeaderField("content-type", "text/css"), 784 HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"), 785 HeaderField("expires", "Thu, 14 May 2015 07:22:34 GMT"), 786 HeaderField("last-modified", "Tue, 14 May 2013 07:22:14 GMT"), 787 HeaderField("vary", "Accept-Encoding"), 788 HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"), 789 HeaderField("x-cache", "HIT from alphabravo"), 790 HeaderField("x-cache-lookup", "HIT from alphabravo:3128") 791 ]; 792 HeaderField[] hfa5 = [ 793 HeaderField(":status", "304 Not Modified"), 794 HeaderField("age", "0"), 795 HeaderField("cache-control", "max-age=4461139"), 796 HeaderField("content-type", "application/x-javascript"), 797 HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"), 798 HeaderField("expires", "Mon, 16 Sep 2013 21:34:31 GMT"), 799 HeaderField("last-modified", "Thu, 05 May 2011 09:15:59 GMT"), 800 HeaderField("vary", "Accept-Encoding"), 801 HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"), 802 HeaderField("x-cache", "HIT from alphabravo"), 803 HeaderField("x-cache-lookup", "HIT from alphabravo:3128") 804 ]; 805 806 HeaderField[] hfa6 = [ 807 HeaderField(":status", "304 Not Modified"), 808 HeaderField("age", "0"), 809 HeaderField("cache-control", "max-age=18645951"), 810 HeaderField("content-type", "application/x-javascript"), 811 HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"), 812 HeaderField("expires", "Fri, 28 Feb 2014 01:48:03 GMT"), 813 HeaderField("last-modified", "Tue, 12 Jul 2011 16:02:59 GMT"), 814 HeaderField("vary", "Accept-Encoding"), 815 HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"), 816 HeaderField("x-cache", "HIT from alphabravo"), 817 HeaderField("x-cache-lookup", "HIT from alphabravo:3128"), 818 ]; 819 HeaderField[] hfa7 = [ 820 HeaderField(":status", "304 Not Modified"), 821 HeaderField("age", "0"), 822 HeaderField("cache-control", "max-age=31536000"), 823 HeaderField("content-type", "application/javascript"), 824 HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"), 825 HeaderField("etag", "\"6807-4dc5b54e0dcc0\""), 826 HeaderField("expires", "Wed, 21 May 2014 08:32:17 GMT"), 827 HeaderField("last-modified", "Fri, 10 May 2013 11:18:51 GMT"), 828 HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"), 829 HeaderField("x-cache", "HIT from alphabravo"), 830 HeaderField("x-cache-lookup", "HIT from alphabravo:3128") 831 ]; 832 HeaderField[] hfa8 = [ 833 HeaderField(":status", "304 Not Modified"), 834 HeaderField("age", "0"), 835 HeaderField("cache-control", "max-age=31536000"), 836 HeaderField("content-type", "application/javascript"), 837 HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"), 838 HeaderField("etag", "\"41c6-4de7d28585b00\""), 839 HeaderField("expires", "Thu, 12 Jun 2014 10:00:58 GMT"), 840 HeaderField("last-modified", "Thu, 06 Jun 2013 14:30:36 GMT"), 841 HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"), 842 HeaderField("x-cache", "HIT from alphabravo"), 843 HeaderField("x-cache-lookup", "HIT from alphabravo:3128") 844 ]; 845 846 HeaderField[] hfa9 = [ 847 HeaderField(":status", "304 Not Modified"), 848 HeaderField("age", "0"), 849 HeaderField("cache-control", "max-age=31536000"), 850 HeaderField("content-type", "application/javascript"), 851 HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"), 852 HeaderField("etag", "\"19d6e-4dc5b35a541c0\""), 853 HeaderField("expires", "Wed, 21 May 2014 08:32:18 GMT"), 854 HeaderField("last-modified", "Fri, 10 May 2013 11:10:07 GMT"), 855 HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"), 856 HeaderField("x-cache", "HIT from alphabravo"), 857 HeaderField("x-cache-lookup", "HIT from alphabravo:3128") 858 ]; 859 HeaderField[] hfa10 = [ 860 HeaderField(":status", "304 Not Modified"), 861 HeaderField("age", "0"), 862 HeaderField("cache-control", "max-age=56682045"), 863 HeaderField("content-type", "text/css"), 864 HeaderField("date", "Sat, 27 Jul 2013 06:22:12 GMT"), 865 HeaderField("expires", "Thu, 14 May 2015 07:22:57 GMT"), 866 HeaderField("last-modified", "Tue, 14 May 2013 07:21:53 GMT"), 867 HeaderField("vary", "Accept-Encoding"), 868 HeaderField("via", "1.1 alphabravo (squid/3.x.x), 1.1 nghttpx"), 869 HeaderField("x-cache", "HIT from alphabravo"), 870 HeaderField("x-cache-lookup", "HIT from alphabravo:3128") 871 ]; 872 873 check_deflate_inflate(deflater, inflater, hfa1); 874 check_deflate_inflate(deflater, inflater, hfa2); 875 check_deflate_inflate(deflater, inflater, hfa3); 876 check_deflate_inflate(deflater, inflater, hfa4); 877 check_deflate_inflate(deflater, inflater, hfa5); 878 check_deflate_inflate(deflater, inflater, hfa6); 879 check_deflate_inflate(deflater, inflater, hfa7); 880 check_deflate_inflate(deflater, inflater, hfa8); 881 check_deflate_inflate(deflater, inflater, hfa9); 882 check_deflate_inflate(deflater, inflater, hfa10); 883 884 inflater.free(); 885 deflater.free(); 886 } 887 888 void test_hd_no_index() { 889 Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE); 890 Inflater inflater = Inflater(true); 891 Buffers bufs = framePackBuffers(); 892 size_t blocklen; 893 HeaderField[] hfa = [ 894 HeaderField(":method", "GET"), HeaderField(":method", "POST"), 895 HeaderField(":path", "/foo"), HeaderField("version", "HTTP/1.1"), 896 HeaderField(":method", "GET") 897 ]; 898 size_t i; 899 HeaderFields output; 900 ErrorCode rv; 901 902 /* 1st :method: GET can be indexable, last one is not */ 903 foreach (ref hf; hfa[1 .. $]) { 904 hf.flag = HeaderFlag.NO_INDEX; 905 } 906 907 rv = deflater.deflate(bufs, hfa); 908 blocklen = bufs.length; 909 910 assert(0 == rv); 911 assert(blocklen > 0); 912 assert(blocklen == output.inflate(inflater, bufs, 0)); 913 914 assert(hfa.length == output.length); 915 assert(hfa.equals(output[])); 916 917 assert(output.hfa_raw[0].flag == HeaderFlag.NONE); 918 919 foreach (ref hf; output[][1 .. $]) 920 assert(hf.flag == HeaderFlag.NO_INDEX); 921 922 output.reset(); 923 924 bufs.free(); 925 inflater.free(); 926 deflater.free(); 927 } 928 929 void test_hd_deflate_bound() { 930 Deflater deflater = Deflater(DEFAULT_MAX_DEFLATE_BUFFER_SIZE); 931 HeaderField[] hfa = [HeaderField(":method", "GET"), HeaderField("alpha", "bravo")]; 932 Buffers bufs = framePackBuffers(); 933 size_t bound, bound2; 934 935 bound = deflater.upperBound(hfa); 936 937 assert(12 + 6 * 2 * 2 + hfa[0].name.length + hfa[0].value.length + hfa[1].name.length + hfa[1].value.length == bound); 938 939 deflater.deflate(bufs, hfa); 940 941 assert(bound > cast(size_t)bufs.length); 942 943 bound2 = deflater.upperBound(hfa); 944 945 assert(bound == bound2); 946 947 bufs.free(); 948 deflater.free(); 949 } 950 951 void test_hd_public_api() { 952 Deflater deflater = Deflater(4096); 953 Inflater inflater = Inflater(true); 954 HeaderField[] hfa = [HeaderField("alpha", "bravo"), HeaderField("charlie", "delta")]; 955 ubyte[4096] buf; 956 size_t buflen; 957 size_t blocklen; 958 Buffers bufs = framePackBuffers(); 959 960 buflen = deflater.upperBound(hfa); 961 962 blocklen = deflater.deflate(buf[0 .. buflen], hfa); 963 964 assert(blocklen > 0); 965 bufs.free(); 966 bufs = new Buffers(buf[0 .. blocklen]); 967 bufs.head.buf.last += blocklen; 968 HeaderFields dummy; 969 assert(blocklen == dummy.inflate(inflater, bufs, 0)); 970 dummy.reset(); 971 bufs.free(); 972 973 inflater.free(); 974 deflater.free(); 975 976 /* See ErrorCode.INSUFF_BUFSIZE */ 977 deflater = Deflater(4096); 978 979 blocklen = deflater.deflate(buf[0 .. blocklen - 1], hfa); 980 981 assert(ErrorCode.INSUFF_BUFSIZE == blocklen); 982 deflater.free(); 983 } 984 985 private size_t encodeLength(ubyte *buf, ulong n, size_t prefix) { 986 size_t k = (1 << prefix) - 1; 987 size_t len; 988 *buf &= ~(cast(ubyte)k); 989 if (n >= k) { 990 *buf++ |= cast(ubyte) k; 991 n -= k; 992 ++len; 993 } else { 994 *buf++ |= cast(ubyte) n; 995 return 1; 996 } 997 do { 998 ++len; 999 if (n >= 128) { 1000 *buf++ = cast(ubyte)((1 << 7) | ((cast(ubyte)n) & 0x7f)); 1001 n >>= 7; 1002 } else { 1003 *buf++ = cast(ubyte)n; 1004 break; 1005 } 1006 } while (n); 1007 return len; 1008 } 1009 1010 void test_hd_decode_length() { 1011 uint output; 1012 size_t shift; 1013 bool is_final; 1014 ubyte[16] buf; 1015 ubyte* bufp; 1016 size_t len; 1017 size_t rv; 1018 size_t i; 1019 1020 len = encodeLength(buf.ptr, uint.max, 7); 1021 1022 rv = output.decodeLength(shift, is_final, 0, 0, buf.ptr, buf.ptr + cast(size_t)len, 7); 1023 1024 assert(cast(int)len == rv, len.to!string ~ " != " ~ rv.to!string); 1025 assert(false != is_final); 1026 assert(uint.max == output); 1027 1028 /* Make sure that we can decode integer if we feed 1 byte at a time */ 1029 output = 0; 1030 shift = 0; 1031 is_final = false; 1032 bufp = buf.ptr; 1033 1034 for (i = 0; i < len; ++i, ++bufp) { 1035 rv = output.decodeLength(shift, is_final, output, shift, bufp, bufp + 1, 7); 1036 assert(rv == 1); 1037 1038 if (is_final) { 1039 break; 1040 } 1041 } 1042 1043 assert(i == len - 1); 1044 assert(0 != is_final); 1045 assert(uint.max == output); 1046 1047 /* Check overflow case */ 1048 memset(buf.ptr, 0, buf.length); 1049 len = encodeLength(buf.ptr, 1L << 32, 7); 1050 1051 rv = output.decodeLength(shift, is_final, 0, 0, buf.ptr, buf.ptr + len, 7); 1052 1053 assert(-1 == rv); 1054 } 1055 1056 void test_hd_huff_encode() { 1057 ErrorCode rv; 1058 size_t len; 1059 Buffers bufs, outbufs; 1060 Decoder ctx; 1061 const ubyte[] t1 = [22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]; 1062 1063 bufs = framePackBuffers(); 1064 outbufs = framePackBuffers(); 1065 1066 rv = bufs.encodeHuffman(cast(string)t1); 1067 1068 assert(rv == 0); 1069 1070 len = ctx.decode(outbufs, bufs.cur.buf[], true); 1071 1072 assert(bufs.length == len); 1073 assert(cast(size_t)t1.length == outbufs.length); 1074 1075 assert(t1[0 .. $] == outbufs.cur.buf.pos[0 .. t1.length]); 1076 1077 bufs.free(); 1078 outbufs.free(); 1079 } 1080 1081 unittest { 1082 import memutils.allocators; 1083 enum Debugger = 0x02; 1084 assert(0 == getAllocator!Debugger().bytesAllocated()); 1085 test_hd_deflate(); 1086 test_hd_deflate_same_indexed_repr(); 1087 test_hd_inflate_indexed(); 1088 test_hd_inflate_indname_noinc(); 1089 test_hd_inflate_indname_inc(); 1090 test_hd_inflate_indname_inc_eviction(); 1091 test_hd_inflate_newname_noinc(); 1092 test_hd_inflate_newname_inc(); 1093 test_hd_inflate_clearall_inc(); 1094 test_hd_inflate_zero_length_huffman(); 1095 test_hd_ringbuf_reserve(); 1096 test_hd_change_table_size(); 1097 test_hd_deflate_inflate(); 1098 test_hd_no_index(); 1099 test_hd_deflate_bound(); 1100 test_hd_public_api(); 1101 test_hd_decode_length(); 1102 test_hd_huff_encode(); 1103 assert(0 == getAllocator!Debugger().bytesAllocated()); 1104 }