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 }