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