1 /** 2 * Inflater 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.inflater; 13 14 import libhttp2.types; 15 import libhttp2.buffers; 16 import libhttp2.huffman; 17 import std.algorithm : min; 18 19 struct Inflater 20 { 21 HDTable ctx; 22 23 /// header buffer 24 Buffers hfbufs; 25 26 /// Stores current state of huffman decoding 27 Decoder huff_decoder; 28 29 /// Pointer to the entry which is used current header emission, for reference counting purposes. 30 HDEntry ent_keep; 31 32 /// The number of bytes to read 33 size_t left; 34 35 /// The index in indexed repr or indexed name 36 size_t index; 37 38 /// The length of new name encoded in literal. For huffman encoded string, this is the length after it is decoded. 39 size_t newnamelen; 40 41 /// The maximum header table size the inflater supports. This is the same value transmitted in SettingsID.HEADER_TABLE_SIZE 42 size_t settings_hd_table_bufsize_max = HD_DEFAULT_MAX_BUFFER_SIZE; 43 44 /// The number of next shift to decode integer 45 size_t shift; 46 47 OpCode opcode = OpCode.NONE; 48 49 InflateState state = InflateState.OPCODE; 50 51 /// true if string is huffman encoded 52 bool huffman_encoded; 53 54 /// true if deflater requires that current entry is indexed 55 bool index_required; 56 57 /// true if deflater requires that current entry must not be indexed 58 bool no_index; 59 60 this(bool initialize) { 61 ctx = Mem.alloc!HDTable(); 62 scope(failure) Mem.free(ctx); 63 hfbufs = Mem.alloc!Buffers(MAX_HF_LEN / 8, 8, 1, 0); 64 } 65 66 void free() { 67 if (ent_keep && ent_keep.refcnt == 0) Mem.free(ent_keep); 68 ent_keep = null; 69 Mem.free(ctx); 70 hfbufs.free(); 71 Mem.free(hfbufs); 72 } 73 74 /** 75 * Changes header table size in the |Inflater|. This may trigger 76 * eviction in the dynamic table. 77 * 78 * The |settings_hd_table_bufsize_max| should be the value transmitted 79 * in SettingsID.HEADER_TABLE_SIZE. 80 */ 81 void changeTableSize(size_t _settings_hd_table_bufsize_max) 82 { 83 settings_hd_table_bufsize_max = _settings_hd_table_bufsize_max; 84 ctx.hd_table_bufsize_max = _settings_hd_table_bufsize_max; 85 ctx.shrink(); 86 } 87 88 /** 89 * Inflates name/value block stored in |input| with length |input.length|. 90 * This function performs decompression. For each successful emission of 91 * header field, $(D InflateFlag.EMIT) is set in |inflate_flags| and a header field 92 * is assigned to |hf_out| and the function returns. The caller must not free 93 * the members of |hf_out|. 94 * 95 * The |hf_out| may include pointers to the memory region in the |input|. 96 * The caller must retain the |input| while the |hf_out| is used. 97 * 98 * The application should call this function repeatedly until the 99 * `(*inflate_flags) & InflateFlag.FINAL` is true and 100 * return value is non-negative. This means the all input values are 101 * processed successfully. Then the application must call 102 * `endHeaders()` to prepare for the next header 103 * block input. 104 * 105 * The caller can feed complete compressed header block. It also can 106 * feed it in several chunks. The caller must set |is_final| to 107 * true if the given input is the last block of the compressed 108 * header. 109 * 110 * This function returns the number of bytes processed if it succeeds, 111 * or one of the following negative error codes: 112 * 113 * $(D ErrorCode.HEADER_COMP) 114 * Inflation process has failed. 115 * $(D ErrorCode.BUFFER_ERROR) 116 * The heder field name or value is too large. 117 * 118 * Example follows:: 119 * 120 * void inflateHeaderBlock(ref Inflater hd_inflater, ubyte[] input, bool final) 121 * { 122 * size_t rv; 123 * 124 * for(;;) { 125 * HeaderField nv; 126 * InflateFlag inflate_flags; 127 * 128 * rv = hd_inflater.inflate(hf, inflate_flags, input, final); 129 * 130 * if(rv < 0) { 131 * fprintf(stderr, "inflate failed with error code %d", rv); 132 * return; 133 * } 134 * 135 * input = input[rv .. $]; 136 * 137 * if(inflate_flags & InflateFlag.EMIT) { 138 * writeln(hf.name, " => ", hf.value); 139 * } 140 * 141 * if(inflate_flags & InflateFlag.FINAL) { 142 * hd_inflater.endHeaders(); 143 * break; 144 * } 145 * if((inflate_flags & InflateFlag.EMIT) == 0 && input.length == 0) { 146 * break; 147 * } 148 * } 149 * } 150 * 151 */ 152 int inflate()(ref HeaderField hf_out, auto ref InflateFlag inflate_flags, ubyte[] input, bool is_final) 153 { 154 ErrorCode rv; 155 ubyte* pos = input.ptr; 156 ubyte* first = input.ptr; 157 ubyte* last = input.ptr + input.length; 158 bool rfin; // read finished 159 if (ctx.bad) return ErrorCode.HEADER_COMP; 160 scope(failure) ctx.bad = 1; 161 162 LOGF("inflatehd: start state=%s pos=%s last=%s", state, pos, last); 163 if (state == InflateState.READ_VALUE && pos is last) 164 assert(false); 165 if (ent_keep && ent_keep.refcnt == 0) Mem.free(ent_keep); 166 ent_keep = null; 167 inflate_flags = InflateFlag.NONE; 168 169 for (; pos < last;) { 170 final switch (state) { 171 case InflateState.OPCODE: 172 if ((*pos & 0xe0) == 0x20) { 173 LOGF("inflatehd: header table size change"); 174 opcode = OpCode.INDEXED; 175 state = InflateState.READ_TABLE_SIZE; 176 } else if (*pos & 0x80) { 177 LOGF("inflatehd: indexed repr"); 178 opcode = OpCode.INDEXED; 179 state = InflateState.READ_INDEX; 180 } else { 181 if (*pos == 0x40 || *pos == 0 || *pos == 0x10) { 182 LOGF("inflatehd: literal header repr - new name"); 183 opcode = OpCode.NEWNAME; 184 state = InflateState.NEWNAME_CHECK_NAMELEN; 185 } else { 186 LOGF("inflatehd: literal header repr - indexed name"); 187 opcode = OpCode.INDNAME; 188 state = InflateState.READ_INDEX; 189 } 190 index_required = (*pos & 0x40) != 0; 191 no_index = (*pos & 0xf0) == 0x10; 192 LOGF("inflatehd: indexing required=%d, no_index=%d", index_required, no_index); 193 194 if (opcode == OpCode.NEWNAME) 195 ++pos; 196 } 197 left = 0; 198 shift = 0; 199 break; 200 case InflateState.READ_TABLE_SIZE: 201 rfin = false; 202 int len = readLength(rfin, pos, last, 5, settings_hd_table_bufsize_max); 203 if (len < 0) { 204 rv = cast(ErrorCode) len; 205 goto fail; 206 } 207 pos += len; 208 209 if (!rfin) 210 goto almost_ok; 211 212 LOGF("inflatehd: table_size=%d", left); 213 ctx.hd_table_bufsize_max = left; 214 ctx.shrink(); 215 state = InflateState.OPCODE; 216 break; 217 case InflateState.READ_INDEX: { 218 size_t prefixlen; 219 220 if (opcode == OpCode.INDEXED) 221 prefixlen = 7; 222 else if (index_required) 223 prefixlen = 6; 224 else 225 prefixlen = 4; 226 227 rfin = false; 228 size_t maxlen = ctx.hd_table.length + static_table.length; 229 int len = readLength(rfin, pos, last, prefixlen, maxlen); 230 231 if (len < 0) { 232 rv = cast(ErrorCode) len; 233 goto fail; 234 } 235 pos += len; 236 237 if (!rfin) 238 goto almost_ok; 239 240 if (left == 0) { 241 rv = ErrorCode.HEADER_COMP; 242 goto fail; 243 } 244 245 LOGF("inflatehd: index=%d", left); 246 if (opcode == OpCode.INDEXED) { 247 index = left; 248 --index; 249 250 hf_out = commitIndexed(); 251 252 if (hf_out == HeaderField.init) 253 goto fail; 254 255 state = InflateState.OPCODE; 256 /* If rv == 1, no header was emitted */ 257 if (rv == 0) { 258 inflate_flags |= InflateFlag.EMIT; 259 return cast(int)(pos - first); 260 } 261 } else { 262 index = left; 263 --index; 264 265 state = InflateState.CHECK_VALUELEN; 266 } 267 break; 268 } 269 case InflateState.NEWNAME_CHECK_NAMELEN: 270 setHuffmanEncoded(pos); 271 state = InflateState.NEWNAME_READ_NAMELEN; 272 left = 0; 273 shift = 0; 274 LOGF("inflatehd: huffman encoded=%d", huffman_encoded != 0); 275 goto case InflateState.NEWNAME_READ_NAMELEN; 276 case InflateState.NEWNAME_READ_NAMELEN: 277 rfin = false; 278 int len = readLength(rfin, pos, last, 7, MAX_HF_LEN); 279 280 if (len < 0) { 281 rv = cast(ErrorCode) len; 282 goto fail; 283 } 284 pos += len; 285 if (!rfin) { 286 LOGF("inflatehd: integer not fully decoded. current=%d", left); 287 goto almost_ok; 288 } 289 290 if (huffman_encoded) { 291 huff_decoder = Decoder.init; 292 state = InflateState.NEWNAME_READ_NAMEHUFF; 293 } else 294 state = InflateState.NEWNAME_READ_NAME; 295 break; 296 case InflateState.NEWNAME_READ_NAMEHUFF: 297 int len = readHuffman(hfbufs, pos, last); 298 299 if (len < 0) { 300 rv = cast(ErrorCode) len; 301 goto fail; 302 } 303 pos += len; 304 305 LOGF("inflatehd: %d bytes read in NEWNAME_READ_NAMEHUFF", len); 306 307 if (left) { 308 LOGF("inflatehd: still %d bytes to go", left); 309 goto almost_ok; 310 } 311 312 newnamelen = hfbufs.length; 313 314 state = InflateState.CHECK_VALUELEN; 315 316 break; 317 case InflateState.NEWNAME_READ_NAME: 318 int len = read(hfbufs, pos, last); 319 320 if (len < 0) { 321 rv = cast(ErrorCode) len; 322 goto fail; 323 } 324 pos += len; 325 326 LOGF("inflatehd: %d bytes read in NEWNAME_READ_NAME", len); 327 if (left) { 328 LOGF("inflatehd: still %d bytes to go", left); 329 330 goto almost_ok; 331 } 332 333 newnamelen = hfbufs.length; 334 335 state = InflateState.CHECK_VALUELEN; 336 337 break; 338 case InflateState.CHECK_VALUELEN: 339 setHuffmanEncoded(pos); 340 state = InflateState.READ_VALUELEN; 341 left = 0; 342 shift = 0; 343 LOGF("inflatehd: huffman encoded=%d", huffman_encoded != 0); 344 345 goto case InflateState.READ_VALUELEN; 346 case InflateState.READ_VALUELEN: 347 rfin = false; 348 int len = readLength(rfin, pos, last, 7, MAX_HF_LEN); 349 if (len < 0) { 350 rv = cast(ErrorCode) len; 351 goto fail; 352 } 353 pos += len; 354 355 if (!rfin) 356 goto almost_ok; 357 358 LOGF("inflatehd: valuelen=%d", left); 359 if (left == 0) { 360 if (opcode == OpCode.NEWNAME) 361 hf_out = commitNewName(); 362 else 363 hf_out = commitIndexedName(); 364 365 if (hf_out == HeaderField.init) 366 goto fail; 367 368 state = InflateState.OPCODE; 369 inflate_flags |= InflateFlag.EMIT; 370 return cast(int)(pos - first); 371 } 372 373 if (huffman_encoded) { 374 huff_decoder = Decoder.init; 375 376 state = InflateState.READ_VALUEHUFF; 377 } else { 378 state = InflateState.READ_VALUE; 379 } 380 break; 381 case InflateState.READ_VALUEHUFF: 382 int len = readHuffman(hfbufs, pos, last); 383 384 if (len < 0) { 385 rv = cast(ErrorCode) len; 386 goto fail; 387 } 388 pos += len; 389 390 LOGF("inflatehd: %d bytes read in READ_VALUEHUFF", len); 391 392 if (left) { 393 LOGF("inflatehd: still %d bytes to go", left); 394 goto almost_ok; 395 } 396 397 if (opcode == OpCode.NEWNAME) 398 hf_out = commitNewName(); 399 else 400 hf_out = commitIndexedName(); 401 if (hf_out == HeaderField.init) { 402 goto fail; 403 } 404 state = InflateState.OPCODE; 405 inflate_flags |= InflateFlag.EMIT; 406 407 return cast(int)(pos - first); 408 409 case InflateState.READ_VALUE: 410 int len = read(hfbufs, pos, last); 411 412 if (len < 0) { 413 rv = cast(ErrorCode) len; 414 LOGF("inflatehd: value read failure %d: %s", rv, toString(cast(ErrorCode)rv)); 415 goto fail; 416 } 417 418 pos += len; 419 420 LOGF("inflatehd: %d bytes read in READ_VALUE", len); 421 422 if (left) { 423 LOGF("inflatehd: still %d bytes to go", left); 424 goto almost_ok; 425 } 426 427 if (opcode == OpCode.NEWNAME) 428 hf_out = commitNewName(); 429 else 430 hf_out = commitIndexedName(); 431 432 if (hf_out == HeaderField.init) 433 goto fail; 434 435 state = InflateState.OPCODE; 436 inflate_flags |= InflateFlag.EMIT; 437 438 return cast(int)(pos - first); 439 } 440 } 441 442 assert(pos is last); 443 444 LOGF("inflatehd: all input bytes were processed"); 445 446 if (is_final) { 447 LOGF("inflatehd: is_final set"); 448 449 if (state != InflateState.OPCODE) { 450 LOGF("inflatehd: unacceptable state=%d", state); 451 rv = ErrorCode.HEADER_COMP; 452 453 goto fail; 454 } 455 inflate_flags |= InflateFlag.FINAL; 456 } 457 return cast(int)(pos - first); 458 459 almost_ok: 460 if (is_final && state != InflateState.OPCODE) { 461 LOGF("inflatehd: input ended prematurely"); 462 rv = ErrorCode.HEADER_COMP; 463 goto fail; 464 } 465 466 return cast(int)(pos - first); 467 468 fail: 469 LOGF("inflatehd: error return %d", rv); 470 ctx.bad = 1; 471 return cast(int)rv; 472 473 } 474 475 /** 476 * Signals the end of decompression for one header block. 477 */ 478 void endHeaders() { 479 if (ent_keep && ent_keep.refcnt == 0) Mem.free(ent_keep); 480 ent_keep = null; 481 } 482 483 void setHuffmanEncoded(in ubyte* input) { 484 huffman_encoded = (*input & (cast(ubyte)(1 << 7))) != 0; 485 } 486 487 /* 488 * Decodes the integer from the range [in, last). The result is 489 * assigned to |left|. If the |left| is 0, then 490 * it performs variable integer decoding from scratch. Otherwise, it 491 * uses the |left| as the initial value and continues to 492 * decode assuming that [in, last) begins with intermediary sequence. 493 * 494 * This function returns the number of bytes read if it succeeds, or 495 * one of the following negative error codes: 496 * 497 * ErrorCode.HEADER_COMP 498 * Integer decoding failed 499 */ 500 int readLength(ref bool is_final, ubyte* input, ubyte* last, size_t prefix, size_t maxlen) 501 { 502 int rv; 503 uint output; 504 505 is_final = false; 506 507 rv = decodeLength(output, shift, is_final, cast(uint)left, shift, input, last, prefix); 508 509 if (rv == -1) { 510 LOGF("inflatehd: integer decoding failed"); 511 return cast(int)ErrorCode.HEADER_COMP; 512 } 513 514 if (output > maxlen) { 515 LOGF("inflatehd: integer exceeded the maximum value %d", maxlen); 516 return cast(int)ErrorCode.HEADER_COMP; 517 } 518 519 left = output; 520 521 LOGF("inflatehd: decoded integer is %u", output); 522 523 return rv; 524 } 525 526 /* 527 * Reads |left| bytes from the range [in, last) and performs 528 * huffman decoding against them and pushes the result into the 529 * |buffer|. 530 * 531 * This function returns the number of bytes read if it succeeds, or 532 * one of the following negative error codes: 533 * 534 * ErrorCode.HEADER_COMP 535 * Huffman decoding failed 536 * ErrorCode.BUFFER_ERROR 537 * Out of buffer space. 538 */ 539 int readHuffman(Buffers bufs, ubyte* input, ubyte* last) { 540 int readlen; 541 bool rfin; 542 543 if (cast(size_t) (last - input) >= left) { 544 last = input + left; 545 rfin = true; 546 } 547 readlen = huff_decoder.decode(bufs, input[0 .. last - input], rfin); 548 549 if (readlen < 0) { 550 LOGF("inflatehd: huffman decoding failed"); 551 return readlen; 552 } 553 left -= cast(size_t)readlen; 554 return readlen; 555 } 556 557 /* 558 * Reads |left| bytes from the range [in, last) and copies 559 * them into the |buffer|. 560 * 561 * This function returns the number of bytes read if it succeeds, or 562 * one of the following negative error codes: 563 * 564 * ErrorCode.HEADER_COMP 565 * Header decompression failed 566 * ErrorCode.BUFFER_ERROR 567 * Out of buffer space. 568 */ 569 int read(Buffers bufs, ubyte* input, ubyte* last) 570 { 571 ErrorCode rv; 572 size_t len = min(cast(size_t)(last - input), left); 573 574 rv = bufs.add(cast(string)input[0 .. len]); 575 576 if (rv != 0) 577 return cast(int) rv; 578 579 left -= len; 580 return cast(int) len; 581 } 582 583 HeaderField removeBufs(bool value_only) { 584 HeaderField hf; 585 size_t buflen; 586 ubyte[] buf; 587 Buffer* pbuf; 588 589 if (index_required || hfbufs.head != hfbufs.cur) { 590 buf = hfbufs.remove(); 591 buflen = buf.length; 592 593 if (value_only) 594 hf.name = null; 595 else if (newnamelen > 0) { 596 hf.name = cast(string)Mem.copy(buf[0 .. newnamelen]); 597 } 598 if (buflen - hf.name.length > 0) { 599 hf.value = cast(string)Mem.copy((buf.ptr + hf.name.length)[0 .. buflen - hf.name.length]); 600 } 601 Mem.free(buf); 602 603 return hf; 604 } 605 606 // If we are not going to store header in header table and name/value are in first chunk, 607 // we just refer them from hf, instead of mallocing another memory. 608 pbuf = &hfbufs.head.buf; 609 610 if (value_only) 611 hf.name = null; 612 else 613 hf.name = cast(string)pbuf.pos[0 .. newnamelen]; 614 615 hf.value = cast(string)(pbuf.pos + hf.name.length)[0 .. pbuf.length - hf.name.length]; 616 617 // Resetting does not change the content of first buffer 618 hfbufs.reset(); 619 620 return hf; 621 } 622 623 package: 624 /* 625 * Finalize literal header representation - new name- reception. If 626 * header is emitted, it is returned 627 */ 628 HeaderField commitNewName() { 629 HeaderField hf = removeBufs(false); 630 HeaderField ret; 631 if (no_index) 632 hf.flag = HeaderFlag.NO_INDEX; 633 else 634 hf.flag = HeaderFlag.NONE; 635 636 if (index_required) { 637 HDEntry new_ent; 638 HDFlags ent_flags; 639 640 ent_flags = HDFlags.NAME_ALLOC | HDFlags.NAME_GIFT | HDFlags.VALUE_ALLOC | HDFlags.VALUE_GIFT; 641 642 new_ent = ctx.add(hf, hf.name.hash(), hf.value.hash(), ent_flags); 643 644 if (new_ent) { 645 ret = emitIndexedHeader(new_ent); 646 647 ent_keep = new_ent; 648 649 return ret; 650 } 651 652 Mem.free(hf.name); 653 Mem.free(hf.value); 654 655 return HeaderField.init; 656 } 657 658 ret = emitLiteralHeader(hf); 659 660 return ret; 661 } 662 663 /// Finalize literal header representation - indexed name reception. If header is emitted, the HeaderField is returned 664 HeaderField commitIndexedName() { 665 HeaderField ret; 666 HDEntry ent_name; 667 668 HeaderField hf = removeBufs(true /* value only */); 669 670 if (no_index) 671 hf.flag = HeaderFlag.NO_INDEX; 672 else 673 hf.flag = HeaderFlag.NONE; 674 675 ent_name = ctx.get(index); 676 hf.name = ent_name.hf.name; 677 678 if (index_required) { 679 HDEntry new_ent; 680 HDFlags ent_flags; 681 bool static_name; 682 683 ent_flags = HDFlags.VALUE_ALLOC | HDFlags.VALUE_GIFT; 684 static_name = index < static_table.length; 685 686 if (!static_name) { 687 ent_flags |= HDFlags.NAME_ALLOC; 688 /* For entry in static table, we must not touch ref, because it is shared by threads */ 689 ++ent_name.refcnt; 690 } 691 new_ent = ctx.add(hf, ent_name.name_hash, hf.value.hash(), ent_flags); 692 693 if (!static_name && --ent_name.refcnt == 0) { 694 Mem.free(ent_name); 695 } 696 697 if (new_ent) { 698 ret = emitIndexedHeader(new_ent); 699 ent_keep = new_ent; 700 return ret; 701 } 702 703 Mem.free(hf.value); 704 705 return ret; 706 } 707 708 ret = emitLiteralHeader(hf); 709 710 return ret; 711 } 712 713 /* 714 * Finalize indexed header representation reception. If header is 715 * emitted, returns it 716 */ 717 HeaderField commitIndexed() { 718 HDEntry ent = ctx.get(index); 719 return emitIndexedHeader(ent); 720 } 721 722 // for debugging 723 HeaderField emitIndexedHeader(ref HDEntry ent) { 724 LOGF("inflatehd: indexed header emission: %s: %s", ent?ent.hf.name:"null", ent?ent.hf.value:"null"); 725 726 return ent?ent.hf : HeaderField.init; 727 } 728 729 HeaderField emitLiteralHeader(ref HeaderField hf) { 730 LOGF("inflatehd: literal header emission: %s: %s", hf.name, hf.value); 731 732 return hf; 733 } 734 735 736 } 737 738