1 /** 2 * Frame 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.frame; 13 import libhttp2.constants; 14 import libhttp2.types; 15 import libhttp2.stream; 16 import libhttp2.buffers; 17 import libhttp2.huffman; 18 import libhttp2.helpers; 19 import libhttp2.deflater; 20 import std.algorithm : min, max; 21 import std.conv : to; 22 import core.stdc..string : memcpy; 23 24 struct FrameHeader 25 { 26 /// The length after this header 27 uint length; 28 FrameType type; 29 FrameFlags flags; 30 int stream_id; 31 32 ubyte reserved = 0; 33 34 this(uint _length, FrameType _type, FrameFlags _flags, int _stream_id) 35 { 36 length = _length; 37 type = _type; 38 flags = _flags; 39 stream_id = _stream_id; 40 } 41 42 // unpack buf into FrameHeader 43 this(in ubyte* buf) { 44 unpack(buf); 45 } 46 47 void unpack(in ubyte* buf) { 48 length = read!uint(buf) >> 8; 49 type = cast(FrameType) buf[3]; 50 flags = cast(FrameFlags) buf[4]; 51 stream_id = read!uint(&buf[5]) & STREAM_ID_MASK; 52 } 53 54 void unpack(in ubyte[] buf) { 55 length = read!uint(buf) >> 8; 56 type = cast(FrameType)buf[3]; 57 flags = cast(FrameFlags)buf[4]; 58 stream_id = read!uint(buf[5 .. $]) & STREAM_ID_MASK; 59 } 60 61 // pack FrameHeader into buf 62 void pack(ubyte[] buf) { 63 write!uint(buf, cast(uint)(length << 8)); 64 buf[3] = cast(ubyte) type; 65 buf[4] = cast(ubyte) flags; 66 write!uint(buf[5 .. $], cast(uint)stream_id); 67 /* ignore hd.reserved for now */ 68 } 69 70 /* 71 * Call this function after payload was serialized, but not before 72 * changing buf.pos and serializing frame header. 73 * 74 * This function assumes bufs.cur points to the last buf chain of the 75 * frame(s). 76 * 77 * This function serializes frame header for HEADERS/PUSH_PROMISE and 78 * handles their successive CONTINUATION frames. 79 * 80 * We don't process any padding here. 81 */ 82 void packShared(Buffers bufs) 83 { 84 Buffer* buf; 85 Buffers.Chain ci; 86 Buffers.Chain ce; 87 88 buf = &bufs.head.buf; 89 length = buf.length; 90 91 LOGF("send: HEADERS/PUSH_PROMISE, payloadlen=%d", length); 92 93 /* We have multiple frame buffers, which means one or more 94 CONTINUATION frame is involved. Remove END_HEADERS flag from the 95 first frame. */ 96 if (bufs.head != bufs.cur) { 97 flags &= ~cast(int)FrameFlags.END_HEADERS; 98 } 99 100 buf.pos -= FRAME_HDLEN; 101 pack((*buf)[]); 102 103 if (bufs.head != bufs.cur) { 104 /* 2nd and later frames are CONTINUATION frames. */ 105 type = FrameType.CONTINUATION; 106 /* We don't have no flags except for last CONTINUATION */ 107 flags = FrameFlags.NONE; 108 109 ce = bufs.cur; 110 111 for (ci = bufs.head.next; ci != ce; ci = ci.next) { 112 buf = &ci.buf; 113 114 length = buf.length; 115 116 LOGF("send: int CONTINUATION, payloadlen=%d", length); 117 118 buf.pos -= FRAME_HDLEN; 119 pack((*buf)[]); 120 } 121 122 buf = &ci.buf; 123 length = buf.length; 124 /* Set END_HEADERS flag for last CONTINUATION */ 125 flags = FrameFlags.END_HEADERS; 126 127 LOGF("send: last CONTINUATION, payloadlen=%d", length); 128 129 buf.pos -= FRAME_HDLEN; 130 pack((*buf)[]); 131 } 132 } 133 134 135 void addPad(Buffers bufs, int padlen, bool framehd_only) 136 { 137 Buffer* buf; 138 139 if (padlen == 0) { 140 LOGF("send: padlen = 0, nothing to do"); 141 142 return ; 143 } 144 145 /* 146 * We have arranged bufs like this: 147 * 148 * 0 1 2 3 149 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 150 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 151 * | |Frame header | Frame payload... : 152 * +-+-----------------+-------------------------------------------+ 153 * | |Frame header | Frame payload... : 154 * +-+-----------------+-------------------------------------------+ 155 * | |Frame header | Frame payload... : 156 * +-+-----------------+-------------------------------------------+ 157 * 158 * We arranged padding so that it is included in the first frame 159 * completely. For padded frame, we are going to adjust buf.pos of 160 * frame which includes padding and serialize (memmove) frame header 161 * in the correct position. Also extends buf.last to include 162 * padding. 163 */ 164 165 buf = &bufs.head.buf; 166 167 assert(buf.available >= cast(size_t)(padlen - 1)); 168 169 frameSetPad(buf, padlen, framehd_only); 170 171 length += padlen; 172 flags |= FrameFlags.PADDED; 173 174 LOGF("send: final payloadlen=%d, padlen=%d", length, padlen); 175 } 176 177 void free(){} 178 } 179 180 /// The HEADERS frame. It has the following members: 181 struct Headers 182 { 183 FrameHeader hd; 184 185 /// The length of the padding in this frame. This includes PAD_HIGH and PAD_LOW. 186 size_t padlen; 187 188 /// The priority specification 189 PrioritySpec pri_spec; 190 191 /// The header fields. 192 HeaderField[] hfa; 193 194 /// The category of this HEADERS frame. 195 HeadersCategory cat; 196 197 /* 198 * Initializes HEADERS frame |frame| with given values. |frame| takes 199 * ownership of |hfa|, so caller must not free it. If |stream_id| is 200 * not assigned yet, it must be -1. 201 */ 202 this(FrameFlags flags, int stream_id, HeadersCategory _cat, in PrioritySpec _pri_spec, HeaderField[] _hfa) { 203 hd = FrameHeader(0, FrameType.HEADERS, flags, stream_id); 204 padlen = 0; 205 hfa = _hfa; 206 cat = _cat; 207 pri_spec = _pri_spec; 208 } 209 210 void free() { 211 if (hfa) { hfa.free(); } 212 } 213 214 /* 215 * Packs HEADERS frame in wire format and store it in |bufs|. 216 * This function expands |bufs| as necessary to store frame. 217 * 218 * The caller must make sure that bufs.reset() is called before calling this function. 219 * 220 * hd.length is assigned after length is determined during 221 * packing process. CONTINUATION frames are also serialized in this 222 * function. This function does not handle padding. 223 * 224 * This function returns 0 if it succeeds, or returns one of the 225 * following negative error codes: 226 * 227 * ErrorCode.HEADER_COMP 228 * The deflate operation failed. 229 */ 230 ErrorCode pack(Buffers bufs, ref Deflater deflater) 231 { 232 size_t hf_offset; 233 ErrorCode rv; 234 Buffer* buf; 235 236 assert(bufs.head == bufs.cur); 237 238 hf_offset = blockOffset(); 239 240 buf = &bufs.cur.buf; 241 242 buf.pos += hf_offset; 243 buf.last = buf.pos; 244 245 /* This call will adjust buf.last to the correct position */ 246 rv = deflater.deflate(bufs, hfa); 247 if (rv == ErrorCode.BUFFER_ERROR) 248 rv = ErrorCode.HEADER_COMP; 249 250 buf.pos -= hf_offset; 251 252 if (rv != 0) 253 return rv; 254 255 if (hd.flags & FrameFlags.PRIORITY) { 256 pri_spec.pack((*buf)[]); 257 } 258 259 padlen = 0; 260 hd.length = bufs.length; 261 hd.packShared(bufs); 262 263 return ErrorCode.OK; 264 } 265 266 /* 267 * Unpacks HEADERS frame byte sequence into this. This function 268 * only unpacks bytes that come before header field and 269 * after possible Pad Length field. 270 */ 271 void unpack(in ubyte[] payload) { 272 if (hd.flags & FrameFlags.PRIORITY) { 273 pri_spec.unpack(payload); 274 } 275 } 276 277 /* 278 * Returns the offset from the HEADERS frame payload where the 279 * compressed header block starts. The frame payload does not include 280 * frame header. 281 */ 282 size_t blockOffset() { 283 return hd.flags.priorityLength(); 284 } 285 286 } 287 288 289 290 /// The DATA frame. The received data is delivered via http2_on_data_chunk_recv_callback 291 struct Data 292 { 293 FrameHeader hd; 294 /// The length of the padding in this frame. This includes PAD_HIGH and PAD_LOW. 295 int padlen; 296 297 this(FrameFlags flags, int stream_id) { 298 /* At this moment, the length of DATA frame is unknown */ 299 hd = FrameHeader(0, FrameType.DATA, flags, stream_id); 300 padlen = 0; 301 } 302 303 void free() {} 304 305 } 306 307 308 /// The structure to specify stream dependency. 309 struct PrioritySpec 310 { 311 /// The stream ID of the stream to depend on. Specifying 0 makes stream not depend any other stream. 312 int stream_id; 313 int weight = DEFAULT_WEIGHT; 314 bool exclusive; 315 316 this(in ubyte[] data) { 317 unpack(data); 318 } 319 320 /** 321 * Packs the PrioritySpec in |buf|. This function assumes |buf| has 322 * enough space for serialization. 323 */ 324 void pack(ubyte[] buf) { 325 write!uint(buf, stream_id); 326 if (exclusive) 327 buf[0] |= 0x80; 328 buf[4] = cast(ubyte)(weight - 1); 329 } 330 331 /** 332 * Unpacks the priority specification from payload |payload| of length 333 * |payload.length| to |pri_spec|. This function 334 * assumes the |payload| contains whole priority specification. 335 */ 336 void unpack(in ubyte[] payload) { 337 stream_id = read!uint(payload) & STREAM_ID_MASK; 338 exclusive = (payload[0] & 0x80) > 0; 339 weight = payload[4] + 1; 340 } 341 342 /** 343 * Initializes PrioritySpec with the |stream_id| of the stream to depend 344 * on with |weight| and its exclusive flag. If |exclusive| is 345 * true, exclusive flag is set. 346 * 347 * The |weight| must be in [$(D HTTP2_MIN_WEIGHT), $(D HTTP2_MAX_WEIGHT)], inclusive. 348 */ 349 this(int _stream_id, int _weight, bool _exclusive) { 350 stream_id = _stream_id; 351 weight = _weight; 352 exclusive = _exclusive; 353 } 354 355 void adjustWeight() { 356 if (weight < MIN_WEIGHT) { 357 weight = MIN_WEIGHT; 358 } else if (weight > MAX_WEIGHT) { 359 weight = MAX_WEIGHT; 360 } 361 } 362 } 363 364 365 366 /// The PRIORITY frame. It has the following members: 367 struct Priority { 368 FrameHeader hd; 369 PrioritySpec pri_spec; 370 371 this(int stream_id, in PrioritySpec _pri_spec = PrioritySpec.init) 372 { 373 hd = FrameHeader(PRIORITY_SPECLEN, FrameType.PRIORITY, FrameFlags.NONE, stream_id); 374 pri_spec = _pri_spec; 375 } 376 377 void free(){} 378 379 /* 380 * Packs PRIORITY frame |frame| in wire format and store it in 381 * |bufs|. 382 * 383 * The caller must make sure that bufs.reset() is called 384 * before calling this function. 385 */ 386 void pack(Buffers bufs) { 387 Buffer* buf; 388 389 assert(bufs.head == bufs.cur); 390 391 buf = &bufs.head.buf; 392 393 assert(buf.available >= PRIORITY_SPECLEN); 394 395 buf.pos -= FRAME_HDLEN; 396 397 hd.pack((*buf)[]); 398 399 pri_spec.pack(buf.last[0 .. buf.available]); 400 401 buf.last += PRIORITY_SPECLEN; 402 } 403 404 /* 405 * Unpacks PRIORITY wire format into this. 406 */ 407 void unpack(in ubyte[] payload) { 408 pri_spec = PrioritySpec(payload); 409 } 410 411 } 412 413 /// The RST_STREAM frame. It has the following members: 414 struct RstStream { 415 FrameHeader hd; 416 FrameError error_code; 417 418 this(int stream_id, FrameError _error_code) 419 { 420 hd = FrameHeader(4, FrameType.RST_STREAM, FrameFlags.NONE, stream_id); 421 error_code = _error_code; 422 } 423 424 void free(){} 425 426 /* 427 * Packs RST_STREAM frame |frame| in wire frame format and store it in 428 * |bufs|. 429 * 430 * The caller must make sure that bufs.reset() is called 431 * before calling this function. 432 */ 433 void pack(Buffers bufs) 434 { 435 Buffer* buf; 436 437 assert(bufs.head == bufs.cur); 438 439 buf = &bufs.head.buf; 440 441 assert(buf.available >= 4); 442 443 buf.pos -= FRAME_HDLEN; 444 445 hd.pack((*buf)[]); 446 447 write!uint(buf.last, error_code); 448 buf.last += 4; 449 } 450 451 /* 452 * Unpacks RST_STREAM frame byte sequence into |frame|. 453 */ 454 void unpack(in ubyte[] payload) { 455 error_code = cast(FrameError)read!uint(payload); 456 } 457 } 458 459 /// The SETTINGS frame 460 struct Settings { 461 FrameHeader hd; 462 Setting[] iva; 463 464 /* 465 * Initializes SETTINGS frame |frame| with given values. |frame| takes 466 * ownership of |iv|, so caller must not free it. The |flags| are 467 * bitwise-OR of one or more of FrameFlags, the only permissible value is ACK. 468 */ 469 this(FrameFlags flags, Setting[] _iva) { 470 // TODO: Allow only FrameFlags.ACK ? 471 hd = FrameHeader(cast(uint)_iva.length * FRAME_SETTINGS_ENTRY_LENGTH, FrameType.SETTINGS, flags, 0); 472 iva = _iva; 473 } 474 475 void free() { if (iva) Mem.free(iva); } 476 477 478 /* 479 * Packs SETTINGS frame in wire format and store it in |bufs|. 480 * 481 * The caller must make sure that bufs.reset() is called 482 * before calling this function. 483 * 484 * This function returns 0 if it succeeds, or returns one of the 485 * following negative error codes: 486 * 487 * ErrorCode.FRAME_SIZE_ERROR 488 * The length of the frame is too large. 489 */ 490 ErrorCode pack(Buffers bufs) { 491 Buffer* buf; 492 493 assert(bufs.head == bufs.cur); 494 495 buf = &bufs.head.buf; 496 497 if (buf.available < cast(size_t) hd.length) { 498 return ErrorCode.FRAME_SIZE_ERROR; 499 } 500 501 buf.pos -= FRAME_HDLEN; 502 503 hd.pack((*buf)[]); 504 buf.last += pack(buf.last[0 .. buf.available], iva); 505 506 return ErrorCode.OK; 507 } 508 509 510 /* 511 * Makes a copy of |_iva| in |iva|. 512 */ 513 void unpack(Setting[] _iva) 514 { 515 if (iva) free(); 516 517 if (_iva.length == 0) { 518 iva = null; 519 return; 520 } 521 522 iva = _iva.copy(); 523 524 } 525 526 void unpack(in ubyte[] payload) { 527 unpack(iva, payload); 528 } 529 530 /* 531 * Unpacks SETTINGS payload into |iva|. The number of entries are 532 * assigned to the |niv|. This function allocates enough memory 533 * to store the result in |iva|. The caller is responsible to free 534 * |iva| after its use. 535 */ 536 static void unpack(ref Setting[] iva, in ubyte[] payload) { 537 size_t len = payload.length / FRAME_SETTINGS_ENTRY_LENGTH; 538 539 if (len == 0) { 540 iva = null; 541 return; 542 } 543 544 iva = Mem.alloc!(Setting[])(len); 545 546 foreach(i, ref iv; iva) { 547 size_t off = i * FRAME_SETTINGS_ENTRY_LENGTH; 548 iv.unpack(payload[off .. $]); 549 } 550 } 551 552 /* 553 * Packs the |_iva|, which includes |_iva.length| entries, in the |buf|, 554 * assuming the |buf| has at least 8 * |_iva.length| bytes. 555 * 556 * Returns the number of bytes written into the |buf|. 557 */ 558 static int pack(ubyte[] buf, in Setting[] _iva) 559 { 560 foreach (ref iv; _iva) { 561 write!ushort(buf, iv.id); 562 write!uint(buf[2 .. $], iv.value); 563 if (FRAME_SETTINGS_ENTRY_LENGTH < buf.length) 564 buf = buf[FRAME_SETTINGS_ENTRY_LENGTH .. $]; 565 } 566 return cast(int) (FRAME_SETTINGS_ENTRY_LENGTH * _iva.length); 567 } 568 569 } 570 571 /// The PUSH_PROMISE frame. 572 struct PushPromise { 573 FrameHeader hd; 574 575 /// The length of the padding in this frame. This includes PAD_HIGH and PAD_LOW. 576 size_t padlen; 577 578 /// The header fields. 579 HeaderField[] hfa; 580 581 /// The promised stream ID 582 int promised_stream_id; 583 584 /// 0 585 ubyte reserved = 0; 586 587 /* 588 * Initializes PUSH_PROMISE frame with given values. PushPromise 589 * takes ownership of |hfa|, so caller must not free it. 590 */ 591 this(FrameFlags flags, int stream_id, int _promised_stream_id, HeaderField[] _hfa) { 592 hd = FrameHeader(0, FrameType.PUSH_PROMISE, flags, stream_id); 593 hfa = _hfa; 594 promised_stream_id = _promised_stream_id; 595 } 596 597 void free() { if (hfa) hfa.free(); } 598 599 /* 600 * Packs PUSH_PROMISE frame in wire format and store it in 601 * |bufs|. This function expands |bufs| as necessary to store 602 * frame. 603 * 604 * The caller must make sure that bufs.reset() is called 605 * before calling this function. 606 * 607 * frame.hd.length is assigned after length is determined during 608 * packing process. CONTINUATION frames are also serialized in this 609 * function. This function does not handle padding. 610 * 611 * This function returns 0 if it succeeds, or returns one of the 612 * following negative error codes: 613 * 614 * ErrorCode.HEADER_COMP 615 * The deflate operation failed. 616 */ 617 ErrorCode pack(Buffers bufs, ref Deflater deflater) 618 { 619 size_t hf_offset = 4; 620 ErrorCode rv; 621 Buffer* buf; 622 623 assert(bufs.head == bufs.cur); 624 625 buf = &bufs.cur.buf; 626 627 buf.pos += hf_offset; 628 buf.last = buf.pos; 629 630 /* This call will adjust buf.last to the correct position */ 631 rv = deflater.deflate(bufs, hfa); 632 633 if (rv == ErrorCode.BUFFER_ERROR) 634 rv = ErrorCode.HEADER_COMP; 635 636 buf.pos -= hf_offset; 637 638 if (rv != 0) 639 return rv; 640 641 write!uint(buf.pos, promised_stream_id); 642 643 padlen = 0; 644 hd.length = bufs.length; 645 646 hd.packShared(bufs); 647 return ErrorCode.OK; 648 } 649 650 /* 651 * Unpacks PUSH_PROMISE frame byte sequence. This 652 * function only unpacks bytes that come before name/value header 653 * block and after possible Pad Length field. 654 * 655 * TODO: handle END_HEADERS flag is not set 656 */ 657 void unpack(in ubyte[] payload) { 658 promised_stream_id = read!uint(payload) & STREAM_ID_MASK; 659 hfa = null; 660 } 661 } 662 663 /// The PING frame. 664 struct Ping { 665 FrameHeader hd; 666 ubyte[8] opaque_data; 667 668 /* 669 * Initializes PING frame with given values. If the 670 * |opaque_data| is not null, it must point to 8 bytes memory region 671 * of data. The data pointed by |opaque_data| is copied. It can be 672 * null. In this case, 8 bytes null is used. 673 */ 674 this(FrameFlags flags, in ubyte[] _opaque_data) { 675 hd = FrameHeader(8, FrameType.PING, flags, 0); 676 if (opaque_data.length > 0) 677 opaque_data[0 .. min(8, _opaque_data.length)] = _opaque_data[0 .. min(8, _opaque_data.length)]; 678 else 679 opaque_data = null; 680 } 681 682 void free(){} 683 684 /* 685 * Packs PING frame in wire format and store it in |bufs|. 686 * 687 * The caller must make sure that bufs.reset() is called 688 * before calling this function. 689 */ 690 void pack(Buffers bufs) { 691 Buffer* buf; 692 693 assert(bufs.head == bufs.cur); 694 695 buf = &bufs.head.buf; 696 697 assert(buf.available >= 8); 698 699 buf.pos -= FRAME_HDLEN; 700 701 hd.pack((*buf)[]); 702 703 memcpy(buf.last, opaque_data.ptr, opaque_data.sizeof); 704 buf.last += opaque_data.sizeof; 705 706 } 707 708 /* 709 * Unpacks PING wire format into |frame|. 710 */ 711 void unpack(in ubyte[] _opaque_data) 712 { 713 if (opaque_data.length > 0) 714 opaque_data[0 .. min(8, _opaque_data.length)] = _opaque_data[0 .. min(8, _opaque_data.length)]; 715 } 716 } 717 718 /// The GOAWAY frame. 719 struct GoAway { 720 FrameHeader hd; 721 int last_stream_id; 722 FrameError error_code; 723 /// The additional debug data 724 string opaque_data; 725 ubyte reserved = 0; 726 727 /* 728 * Initializes GOAWAY frame with given values. On success, this function takes ownership 729 * of |opaque_data|, so caller must not free it. 730 */ 731 this(int _last_stream_id, FrameError _error_code, string _opaque_data) { 732 hd = FrameHeader(cast(uint)(8 + _opaque_data.length), FrameType.GOAWAY, FrameFlags.NONE, 0); 733 last_stream_id = _last_stream_id; 734 error_code = _error_code; 735 opaque_data = _opaque_data; 736 } 737 738 void free() { if (opaque_data) Mem.free(opaque_data); } 739 740 741 /* 742 * Packs GOAWAY frame in wire format and store it in |bufs|. 743 * This function expands |bufs| as necessary to store frame. 744 * 745 * The caller must make sure that bufs.reset() is called 746 * before calling this function. 747 * 748 * This function returns 0 if it succeeds or one of the following 749 * negative error codes: 750 * 751 * ErrorCode.FRAME_SIZE_ERROR 752 * The length of the frame is too large. 753 */ 754 ErrorCode pack(Buffers bufs) 755 { 756 ErrorCode rv; 757 Buffer* buf; 758 759 assert(bufs.head == bufs.cur); 760 761 buf = &bufs.head.buf; 762 763 buf.pos -= FRAME_HDLEN; 764 765 hd.pack((*buf)[]); 766 767 write!uint(buf.last, last_stream_id); 768 buf.last += 4; 769 770 write!uint(buf.last, error_code); 771 buf.last += 4; 772 773 rv = bufs.add(cast(string)opaque_data); 774 775 if (rv == ErrorCode.BUFFER_ERROR) 776 return ErrorCode.FRAME_SIZE_ERROR; 777 778 return rv; 779 } 780 781 /* 782 * Unpacks GOAWAY wire format. The |payload| of length 783 * |payloadlen| contains first 8 bytes of payload. The 784 * |var_gift_payload| contains the remaining payload and its 785 * buffer is gifted to the function and then 786 * |frame|. The |var_gift_payload| must be freed by GoAway.free(). 787 */ 788 void unpack(in ubyte[] payload, ubyte[] var_gift_payload) 789 { 790 last_stream_id = read!uint(payload) & STREAM_ID_MASK; 791 error_code = cast(FrameError) read!uint(payload[4 .. $]); 792 opaque_data = cast(string)var_gift_payload; 793 } 794 795 /* 796 * Unpacks GOAWAY wire format. This function only exists 797 * for unit test. After allocating buffer for debug data, this 798 * function internally calls http2_frame_unpack_goaway_payload(). 799 */ 800 void unpack(in ubyte[] payload) 801 { 802 ubyte[] var_gift_payload; 803 size_t var_gift_payloadlen; 804 size_t payloadlen = payload.length; 805 806 if (payloadlen > 8) { 807 var_gift_payloadlen = payloadlen - 8; 808 } else { 809 var_gift_payloadlen = 0; 810 } 811 812 if (!var_gift_payloadlen) { 813 var_gift_payload = null; 814 } else { 815 var_gift_payload = Mem.alloc!(ubyte[])(var_gift_payloadlen); 816 memcpy(var_gift_payload.ptr, payload.ptr + 8, var_gift_payloadlen); 817 } 818 819 unpack(payload, var_gift_payload); 820 } 821 822 } 823 824 /// The WINDOW_UPDATE frame. 825 struct WindowUpdate { 826 FrameHeader hd; 827 int window_size_increment; 828 ubyte reserved = 0; 829 830 this(FrameFlags flags, int stream_id, int _window_size_increment) 831 { 832 hd = FrameHeader(4, FrameType.WINDOW_UPDATE, flags, stream_id); 833 window_size_increment = _window_size_increment; 834 } 835 836 void free(){} 837 838 /* 839 * Packs WINDOW_UPDATE frame in wire frame format and store it 840 * in |bufs|. 841 * 842 * The caller must make sure that bufs.reset() is called 843 * before calling this function. 844 */ 845 void pack(Buffers bufs) { 846 Buffer* buf; 847 848 assert(bufs.head == bufs.cur); 849 850 buf = &bufs.head.buf; 851 852 assert(buf.available >= 4); 853 854 buf.pos -= FRAME_HDLEN; 855 856 hd.pack((*buf)[]); 857 858 write!uint(buf.last, window_size_increment); 859 buf.last += 4; 860 } 861 862 /* 863 * Unpacks WINDOW_UPDATE frame byte sequence. 864 */ 865 void unpack(in ubyte[] payload) { 866 window_size_increment = read!uint(payload) & WINDOW_SIZE_INCREMENT_MASK; 867 } 868 869 } 870 871 872 /* 873 * This union includes all frames to pass them to various function 874 * calls as http2_frame type. The CONTINUATION frame is omitted 875 * from here because the library deals with it internally. 876 */ 877 union Frame 878 { 879 FrameHeader hd; 880 Data data; 881 Headers headers; 882 Priority priority; 883 RstStream rst_stream; 884 Settings settings; 885 PushPromise push_promise; 886 Ping ping; 887 GoAway goaway; 888 WindowUpdate window_update; 889 890 /* 891 * Returns the number of padding bytes after payload. The total 892 * padding length is given in the |padlen|. The returned value does 893 * not include the Pad Length field. 894 */ 895 size_t trailPadlen(size_t padlen) 896 { 897 return padlen - ((hd.flags & FrameFlags.PADDED) > 0); 898 } 899 900 void unpack(in ubyte[] input) 901 { 902 const(ubyte)[] payload = input[FRAME_HDLEN .. $]; 903 size_t payloadoff; 904 905 hd.unpack(input); 906 907 with (FrameType) final switch (hd.type) { 908 case HEADERS: 909 payloadoff = cast(size_t) ((hd.flags & FrameFlags.PADDED) > 0); 910 headers.unpack(payload[payloadoff .. $]); 911 break; 912 case PRIORITY: 913 priority.unpack(payload); 914 break; 915 case RST_STREAM: 916 rst_stream.unpack(payload); 917 break; 918 case SETTINGS: 919 settings.unpack(payload); 920 break; 921 case PUSH_PROMISE: 922 push_promise.unpack(payload); 923 break; 924 case PING: 925 ping.unpack(payload); 926 break; 927 case GOAWAY: 928 goaway.unpack(payload); 929 break; 930 case WINDOW_UPDATE: 931 window_update.unpack(payload); 932 break; 933 case DATA: 934 case CONTINUATION: 935 break; 936 937 } 938 } 939 940 void unpack(Buffers bufs) { 941 Buffer *buf; 942 943 /* Assuming we have required data in first buffer. We don't decode 944 header block so, we don't mind its space */ 945 buf = &bufs.head.buf; 946 unpack((*buf)[]); 947 } 948 } 949 950 /// struct used for HEADERS and PUSH_PROMISE frame 951 struct HeadersAuxData { 952 DataProvider data_prd; 953 void *stream_user_data; 954 955 /// error code when request HEADERS is canceled by RST_STREAM while it is in queue. 956 FrameError error_code; 957 958 /// nonzero if request HEADERS is canceled. The error code is stored in |error_code|. 959 bool canceled; 960 961 /// nonzero if this item should be attached to stream object to make it under priority control 962 bool attach_stream; 963 } 964 965 /// struct used for DATA frame 966 struct DataAuxData { 967 /// The data to be sent for this DATA frame. 968 DataProvider data_prd; 969 970 /** 971 * The flags of DATA frame. We use separate flags here and 972 * http2_data frame. The latter contains flags actually sent to 973 * peer. This |flags| may contain END_STREAM and only 974 * when |eof| becomes nonzero, flags in http2_data has 975 * END_STREAM set. 976 */ 977 DataFlags flags; 978 979 /// The flag to indicate whether EOF was reached or not. Initially |eof| is 0. It becomes 1 after all data were read. 980 bool eof; 981 982 /// The flag to indicate that DataFlags.NO_COPY was used. 983 bool no_copy; 984 } 985 986 enum GoAwayAuxFlags { 987 NONE = 0x0, 988 /// indicates that session should be terminated after the transmission of this frame. 989 TERM_ON_SEND = 0x1, 990 /// indicates that this GOAWAY is just a notification for graceful shutdown. 991 /// No http2_session.goaway_flags should be updated on the reaction to this frame. 992 SHUTDOWN_NOTICE = 0x2, 993 } 994 995 /// struct used for GOAWAY frame 996 struct GoAwayAuxData { 997 GoAwayAuxFlags flags; 998 } 999 1000 /// Additional data which cannot be stored in Frame struct 1001 union AuxData { 1002 DataAuxData data; 1003 HeadersAuxData headers; 1004 GoAwayAuxData goaway; 1005 } 1006 1007 class OutboundItem { 1008 enum NOGC = true; 1009 import libhttp2.session : Session; 1010 Frame frame; 1011 AuxData aux_data; 1012 long seq; 1013 1014 /// Reset count of weight. See comment for last_cycle 1015 ulong cycle; 1016 1017 /// The priority used in priority comparion. Larger is served ealier. 1018 int weight = OB_EX_WEIGHT; 1019 1020 /// true if this object is queued. 1021 bool queued; 1022 1023 this() { } 1024 1025 this(Session session) { 1026 seq = session.next_seq++; 1027 } 1028 1029 void free() { 1030 1031 with (FrameType) switch (frame.hd.type) { 1032 case HEADERS: 1033 case CONTINUATION: 1034 frame.headers.free(); 1035 break; 1036 case PRIORITY: 1037 frame.priority.free(); 1038 break; 1039 case RST_STREAM: 1040 frame.rst_stream.free(); 1041 break; 1042 case SETTINGS: 1043 frame.settings.free(); 1044 break; 1045 case PUSH_PROMISE: 1046 frame.push_promise.free(); 1047 break; 1048 case PING: 1049 frame.ping.free(); 1050 break; 1051 case GOAWAY: 1052 frame.goaway.free(); 1053 break; 1054 case WINDOW_UPDATE: 1055 frame.window_update.free(); 1056 break; 1057 default: break; 1058 } 1059 } 1060 1061 } 1062 1063 int bytes_compar(const ubyte* a, size_t alen, const ubyte* b, size_t blen) { 1064 import core.stdc..string : memcmp; 1065 int rv; 1066 1067 if (alen == blen) { 1068 return memcmp(a, b, alen); 1069 } 1070 1071 if (alen < blen) { 1072 rv = memcmp(a, b, alen); 1073 1074 if (rv == 0) { 1075 return -1; 1076 } 1077 1078 return rv; 1079 } 1080 1081 rv = memcmp(a, b, blen); 1082 1083 if (rv == 0) { 1084 return 1; 1085 } 1086 1087 return rv; 1088 } 1089 1090 // true if everything is fine, false otherwise 1091 bool check(in Setting[] iva) 1092 { 1093 foreach (entry; iva) { 1094 with(Setting) switch (entry.id) { 1095 case HEADER_TABLE_SIZE: 1096 if (entry.value > MAX_HEADER_TABLE_SIZE) { 1097 return false; 1098 } 1099 break; 1100 case MAX_CONCURRENT_STREAMS: 1101 break; 1102 case ENABLE_PUSH: 1103 if (entry.value != 0 && entry.value != 1) { 1104 return false; 1105 } 1106 break; 1107 case INITIAL_WINDOW_SIZE: 1108 if (entry.value > cast(uint)MAX_WINDOW_SIZE) { 1109 return false; 1110 } 1111 break; 1112 case MAX_FRAME_SIZE: 1113 if (entry.value < MAX_FRAME_SIZE_MIN || 1114 entry.value > MAX_FRAME_SIZE_MAX) { 1115 return false; 1116 } 1117 break; 1118 case MAX_HEADER_LIST_SIZE: 1119 break; 1120 default: 1121 break; 1122 } 1123 } 1124 return true; 1125 } 1126 1127 void frameSetPad(Buffer* buf, int padlen, bool framehd_only) 1128 { 1129 import core.stdc..string : memmove, memset; 1130 int trail_padlen; 1131 int newlen; 1132 1133 LOGF("send: padlen=%d, shift left 1 bytes", padlen); 1134 1135 memmove(buf.pos - 1, buf.pos, FRAME_HDLEN); 1136 1137 --buf.pos; 1138 1139 buf.pos[4] |= FrameFlags.PADDED; 1140 1141 newlen = (read!uint(buf.pos) >> 8) + padlen; 1142 write!uint(buf.pos, cast(uint)((newlen << 8) + buf.pos[3])); 1143 1144 if (framehd_only) 1145 return; 1146 1147 trail_padlen = padlen - 1; 1148 buf.pos[FRAME_HDLEN] = cast(ubyte) trail_padlen; 1149 1150 /* zero out padding */ 1151 memset(buf.last, 0, trail_padlen); 1152 /* extend buffers trail_padlen bytes, since we ate previous padlen - 1153 trail_padlen byte(s) */ 1154 buf.last += trail_padlen; 1155 } 1156 1157 /** 1158 * Returns the number of priority field depending on the |flags|. If 1159 * |flags| has no priority designation, return 0. 1160 */ 1161 size_t priorityLength(FrameFlags flags) { 1162 if (flags & FrameFlags.PRIORITY) { 1163 return PRIORITY_SPECLEN; 1164 } 1165 1166 return 0; 1167 }