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