1 /**
2  * Types
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.types;
13 
14 import libhttp2.constants;
15 import libhttp2.helpers;
16 import std.conv : to;
17 import memutils.refcounted;
18 import memutils.utils;
19 import std.datetime;
20 alias Mem = ThreadMem;
21 void LOGF(ARGS...)(lazy ARGS args) {
22 	import std.stdio: writefln;
23 	import std.stdio : File;
24 	static if (DEBUG) {
25 		File f = File();
26 		f.open("runtime.log", "a+");
27 		try f.write(Clock.currTime().to!string); catch {}
28 		try f.write(" "); catch {}
29 		try f.writefln(args); catch {}
30 	}
31 }
32 
33 void logDebug(ARGS...)(lazy ARGS args) {
34 	import std.stdio: writeln;
35 	import std.stdio : File;
36 	static if (DEBUG) {
37 		File f = File();
38 		f.open("runtime.log", "a+");
39 		try f.write(Clock.currTime().to!string); catch {}
40 		try f.write(" "); catch {}
41 		try f.writefln(args); catch {}
42 	}
43 }
44 
45 /// Return values used in this library.  The code range is [-999, -500], inclusive.
46 enum ErrorCode : int {
47     OK = 0,
48 
49 	ERROR = -1,
50 	CREDENTIAL_PENDING = -101,
51 	IGN_HEADER_BLOCK = -103,
52 
53 	/*
54      * Invalid HTTP header field was received but it can be treated as
55      * if it was not received because of compatibility reasons.
56     */
57 	IGN_HTTP_HEADER = -105,
58 
59 	IGN_PAYLOAD = -104,
60 	/// Invalid argument passed.
61     INVALID_ARGUMENT = -501,
62 
63 	/// Out of buffer space.
64 	BUFFER_ERROR = -502,
65 
66 	/// The specified protocol version is not supported.
67 	UNSUPPORTED_VERSION = -503,
68 
69 	/// Used as a return value from http2_send_callback and http2_recv_callback
70 	/// to indicate that the operation would block.
71 	WOULDBLOCK = -504,
72 
73 	/// General protocol error
74 	PROTO = -505,
75 
76 	/// The frame is invalid.
77 	INVALID_FRAME = -506,
78 
79 	/// The peer performed a shutdown on the connection.
80 	EOF = -507,
81 
82 	/// Used as a return value from DataProvider to indicate that data
83     /// transfer is postponed.  See DataProvider for details.
84 	DEFERRED = -508,
85 
86 	/// Stream ID has reached the maximum value.  Therefore no stream ID is available.
87 	STREAM_ID_NOT_AVAILABLE = -509,
88 
89 	/// The stream is already closed; or the stream ID is invalid.
90 	STREAM_CLOSED = -510,
91 
92 	/// RST_STREAM has been added to the outbound queue.  The stream is in closing state.
93 	STREAM_CLOSING = -511,
94 
95 	/// The transmission is not allowed for this stream (e.g., a frame with END_STREAM flag set has already sent).
96 	STREAM_SHUT_WR = -512,
97 
98 	/// The stream ID is invalid.
99 	INVALID_STREAM_ID = -513,
100 
101 	/// The state of the stream is not valid (e.g., DATA cannot be sent to the stream if response HEADERS has not been sent).
102 	INVALID_STREAM_STATE = -514,
103 	/// Another DATA frame has already been deferred.
104 	/// 
105 	DEFERRED_DATA_EXIST = -515,
106 
107 	/// Starting new stream is not allowed (e.g., GOAWAY has been sent and/or received).
108 	START_STREAM_NOT_ALLOWED = -516,
109 	/**
110    * GOAWAY has already been sent.
111    */
112 	GOAWAY_ALREADY_SENT = -517,
113 
114 	/**
115    * The received frame contains the invalid header block (e.g., There
116    * are duplicate header names; or the header names are not encoded
117    * in US-ASCII character set and not lower cased; or the header name
118    * is zero-length string; or the header value contains multiple
119    * in-sequence NUL bytes).
120    */
121 	INVALID_HEADER_BLOCK = -518,
122 
123 	/// Indicates that the context is not suitable to perform the requested operation.
124 	INVALID_STATE = -519,
125 
126 	/// The user callback function failed due to the temporal error.
127 	TEMPORAL_CALLBACK_FAILURE = -521,
128 
129 	/// The length of the frame is invalid, either too large or too small.
130 	FRAME_SIZE_ERROR = -522,
131 
132 	/// Header block inflate/deflate error.
133 	HEADER_COMP = -523,
134 
135 	/// Flow control error
136 	FLOW_CONTROL = -524,
137 
138 	/// Insufficient buffer size given to function.
139 	INSUFF_BUFSIZE = -525,
140 
141 	/// Callback was paused by the application
142 	PAUSE = -526,
143 
144 	/// There are too many in-flight SETTING frame and no more transmission of SETTINGS is allowed.
145 	TOO_MANY_INFLIGHT_SETTINGS = -527,
146 
147 	/// The server push is disabled.
148 	PUSH_DISABLED = -528,
149 
150 	/// DATA frame for a given stream has been already submitted and has not been fully processed yet.
151 	DATA_EXIST = -529,
152 
153 	/// The current session is closing due to a connection error or http2_session_terminate_session() is called.
154 	SESSION_CLOSING = -530,
155 
156 	/// Invalid HTTP header field was received and stream is going to be closed.
157 	HTTP_HEADER = -531,
158 
159 	/**
160     * The errors < FATAL mean that the library is under unexpected condition and processing was terminated (e.g.,
161     * out of memory).  If application receives this error code, it must stop using that $(D Session) object and only allowed
162     * operation for that object is deallocate it using http2_session_del().
163     */
164 	FATAL = -900,
165 
166 	/// Out of memory.  This is a fatal error.
167 	NOMEM = -901,
168 
169 	/// The user callback function failed.  This is a fatal error.
170 	CALLBACK_FAILURE = -902,
171 
172 	/// Invalid connection preface was received and further processing is not possible.
173 	BAD_PREFACE = -903
174 }
175 
176 /*
177  * Returns string describing the |error_code|.  The |error_code| must be one of the $(D ErrorCode).
178  */
179 string toString(ErrorCode error_code) {
180 	with(ErrorCode) switch (error_code) {
181 		case OK:
182 			return "Success";
183 		case ERROR:
184 			return "Unknown error";
185 		case INVALID_ARGUMENT:
186 			return "Invalid argument";
187 		case BUFFER_ERROR:
188 			return "Out of buffer space";
189 		case UNSUPPORTED_VERSION:
190 			return "Unsupported SPDY version";
191 		case WOULDBLOCK:
192 			return "Operation would block";
193 		case PROTO:
194 			return "Protocol error";
195 		case INVALID_FRAME:
196 			return "Invalid frame octets";
197 		case EOF:
198 			return "EOF";
199 		case DEFERRED:
200 			return "Data transfer deferred";
201 		case STREAM_ID_NOT_AVAILABLE:
202 			return "No more Stream ID available";
203 		case STREAM_CLOSED:
204 			return "Stream was already closed or invalid";
205 		case STREAM_CLOSING:
206 			return "Stream is closing";
207 		case STREAM_SHUT_WR:
208 			return "The transmission is not allowed for this stream";
209 		case INVALID_STREAM_ID:
210 			return "Stream ID is invalid";
211 		case INVALID_STREAM_STATE:
212 			return "Invalid stream state";
213 		case DEFERRED_DATA_EXIST:
214 			return "Another DATA frame has already been deferred";
215 		case SESSION_CLOSING:
216 			return "The current session is closing";
217 		case START_STREAM_NOT_ALLOWED:
218 			return "request HEADERS is not allowed";
219 		case GOAWAY_ALREADY_SENT:
220 			return "GOAWAY has already been sent";
221 		case INVALID_HEADER_BLOCK:
222 			return "Invalid header block";
223 		case INVALID_STATE:
224 			return "Invalid state";
225 		case TEMPORAL_CALLBACK_FAILURE:
226 			return "The user callback function failed due to the temporal error";
227 		case FRAME_SIZE_ERROR:
228 			return "The length of the frame is invalid";
229 		case HEADER_COMP:
230 			return "Header compression/decompression error";
231 		case FLOW_CONTROL:
232 			return "Flow control error";
233 		case INSUFF_BUFSIZE:
234 			return "Insufficient buffer size given to function";
235 		case PAUSE:
236 			return "Callback was paused by the application";
237 		case TOO_MANY_INFLIGHT_SETTINGS:
238 			return "Too many inflight SETTINGS";
239 		case PUSH_DISABLED:
240 			return "Server push is disabled by peer";
241 		case DATA_EXIST:
242 			return "DATA frame already exists";
243 		case NOMEM:
244 			return "Out of memory";
245 		case CALLBACK_FAILURE:
246 			return "The user callback function failed";
247 		case BAD_PREFACE:
248 			return "Received bad connection preface";
249 		default: return error_code.to!string;
250 	}
251 }
252 
253 /// The flag for a header field.
254 enum HeaderFlag : ubyte 
255 {
256 	/// No flag set.
257 	NONE = 0,
258 
259 	/**
260     * Indicates that this header field must not be indexed ("Literal
261     * Header Field never Indexed" representation must be used in HPACK
262     * encoding).  Other implementation calls this bit as "sensitive".
263     */
264 	NO_INDEX = 0x01
265 }
266 
267 /// The header field, which mainly used to represent HTTP headers.
268 struct HeaderField 
269 {
270 	enum NOGC = true;
271 	immutable(char)[] name;
272 	immutable(char)[] value;
273 
274 	HeaderFlag flag = HeaderFlag.NONE;
275 
276 	bool opEquals()(auto ref HeaderField other) const {
277 		return name == other.name && value == other.value;
278 	}
279 
280 	void free() {
281 		if (name.length > 0)
282 			Mem.free(name);
283 		if (value.length > 0)
284 			Mem.free(value);
285 		name = null;
286 		value = null;
287 	}
288 
289 	/**
290 	* Returns true if HTTP header field name |name| of length |len| is
291 	* valid according to http://tools.ietf.org/html/rfc7230#section-3.2
292 	*
293 	* Because this is a header field name in HTTP2, the upper cased alphabet
294 	* is treated as error.
295 	*/
296 	bool validateName() {
297 		immutable(char)* pos = name.ptr;
298 		size_t len = name.length;
299 		if (len == 0)
300 			return false;
301 
302 		if (*pos == ':') {
303 			if (name.length == 1)
304 				return false;
305 			++pos;
306 			--len;
307 		}
308 
309 		for (const immutable(char)* last = pos + len; pos != last; ++pos) {
310 			if (!VALID_HD_NAME_CHARS[*pos]) {
311 				return false;
312 			}
313 		}
314 		return true;
315 	}
316 
317 	/*
318 	 * Returns true if HTTP header field value |value| of length |len|
319 	 * is valid according to http://tools.ietf.org/html/rfc7230#section-3.2
320 	 */
321 	bool validateValue() {
322 		immutable(char)* pos = value.ptr;
323 		size_t len = value.length;
324 
325 		for (const immutable(char)* last = pos + len; pos != last; ++pos) {
326 			if (!VALID_HD_VALUE_CHARS[*pos]) {
327 				return false;
328 			}
329 		}
330 		return true;
331 	}
332 
333 	import libhttp2.stream : Stream;
334 	/// Validate a request header
335 	bool validateRequestHeader(Stream stream, bool trailer) {
336 		int token;
337 		
338 		if (name[0] == ':') 
339 			if (trailer || (stream.httpFlags & HTTPFlags.PSEUDO_HEADER_DISALLOWED)) 
340 				return false;
341 		
342 		token = parseToken(name);
343 		
344 		with(Token) switch (token) {
345 			case _AUTHORITY:
346 				if (!validatePseudoHeader(stream, HTTPFlags._AUTHORITY)) 
347 					return false;
348 
349 				break;
350 			case _METHOD:
351 				if (!validatePseudoHeader(stream, HTTPFlags._METHOD)) 
352 					return false;
353 				
354 				switch (value.length)
355 				{
356 					case 4:
357 
358 						if (value == "HEAD") {
359 							stream.httpFlags = cast(HTTPFlags)(stream.httpFlags | HTTPFlags.METH_HEAD);
360 						} 
361 						break;
362 					case 7:
363 						switch (value[6])
364 						{
365 							case 'T':
366 								if (value == "CONNECT") {
367 									if (stream.id % 2 == 0) {
368 										/* we won't allow CONNECT for push */
369 										return false;
370 									}
371 									stream.httpFlags = cast(HTTPFlags)(stream.httpFlags | HTTPFlags.METH_CONNECT);
372 									if (stream.httpFlags & (HTTPFlags._PATH | HTTPFlags._SCHEME)) 
373 										return false;
374 								}
375 								break;
376 
377 							case 'S':
378 								if (value == "OPTIONS") {
379 									stream.httpFlags = cast(HTTPFlags)(stream.httpFlags | HTTPFlags.METH_OPTIONS);
380 								}
381 								break;
382 							default:
383 								break;
384 						}
385 						break;
386 					default:
387 						break;
388 				}
389 				break;
390 			case _PATH:
391 				if (stream.httpFlags & HTTPFlags.METH_CONNECT) {
392 					return false;
393 				}
394 				if (!validatePseudoHeader(stream, HTTPFlags._PATH)) {
395 					return false;
396 				}
397 				if (value[0] == '/') {
398 					stream.httpFlags = cast(HTTPFlags)(stream.httpFlags | HTTPFlags.PATH_REGULAR);
399 				} else if (value.length == 1 && value[0] == '*') {
400 					stream.httpFlags = cast(HTTPFlags)(stream.httpFlags | HTTPFlags.PATH_ASTERISK);
401 				}
402 				break;
403 			case _SCHEME:
404 				if (stream.httpFlags & HTTPFlags.METH_CONNECT) {
405 					return false;
406 				}
407 				if (!validatePseudoHeader(stream, HTTPFlags._SCHEME)) {
408 					return false;
409 				}
410 				if ((value.length == 4 && memieq("http".ptr, value.ptr, 4)) ||
411 					(value.length == 5 && memieq("https".ptr, value.ptr, 5))) {
412 					stream.httpFlags = cast(HTTPFlags)(stream.httpFlags | HTTPFlags.SCHEME_HTTP);
413 				}
414 				break;
415 			case HOST:
416 				if (!validatePseudoHeader(stream, HTTPFlags.HOST)) {
417 					return false;
418 				}
419 				break;
420 			case CONTENT_LENGTH: {
421 				if (stream.contentLength != -1) 
422 					return false;
423 				import std.conv : parse;
424 				stream.contentLength = parse!long(value);
425 				if (stream.contentLength == -1) 
426 					return false;
427 				break;
428 			}
429 				/* disallowed header fields */
430 /* Ignore because this can cause issues with reverse proxies
431  * case CONNECTION:
432 			case KEEP_ALIVE:
433 			case PROXY_CONNECTION:
434 			case TRANSFER_ENCODING:
435 			case UPGRADE:
436 				return false;*/
437 			case TE:
438 				import std..string : icmp;
439 				if (icmp(value, "trailers") != 0)
440 					return false;
441 				break;
442 			default:
443 				if (name[0] == ':')
444 					return false;
445 		}
446 		if (name[0] != ':')
447 			stream.httpFlags = cast(HTTPFlags)(stream.httpFlags | HTTPFlags.PSEUDO_HEADER_DISALLOWED);		
448 		
449 		return true;
450 	}
451 
452 	bool validateResponseHeader(Stream stream, int trailer) 
453 	{
454 		import std.conv : parse;
455 		int token;
456 		
457 		if (name[0] == ':') {
458 			if (trailer || (stream.httpFlags & HTTPFlags.PSEUDO_HEADER_DISALLOWED)) {
459 				return false;
460 			}
461 		}
462 		
463 		token = parseToken(name);
464 		
465 		with(Token) switch (token) {
466 			case _STATUS: {
467 				if (!validatePseudoHeader(stream, HTTPFlags._STATUS)) {
468 					return false;
469 				}
470 				if (value.length != 3) {
471 					return false;
472 				}
473 				stream.statusCode = cast(short)parse!uint(value);
474 				if (stream.statusCode == -1)
475 					return false;
476 				break;
477 			}
478 			case CONTENT_LENGTH: {
479 				if (stream.contentLength != -1) {
480 					return false;
481 				}
482 				stream.contentLength = parse!long(value);
483 				if (stream.contentLength == -1) {
484 					return false;
485 				}
486 				break;
487 			}
488 				/* disallowed header fields */
489 			case CONNECTION:
490 			case KEEP_ALIVE:
491 			case PROXY_CONNECTION:
492 			case TRANSFER_ENCODING:
493 			case UPGRADE:
494 				return false;
495 			case TE:
496 				import std..string : icmp;
497 				if (icmp("trailers", value) != 0) {
498 					return false;
499 				}
500 				break;
501 			default:
502 				if (name[0] == ':') {
503 					return false;
504 				}
505 		}
506 		
507 		if (name[0] != ':') {
508 			stream.httpFlags = cast(HTTPFlags)(stream.httpFlags | HTTPFlags.PSEUDO_HEADER_DISALLOWED);
509 		}
510 		
511 		return true;
512 	}
513 private:	
514 	bool validatePseudoHeader(Stream stream, HTTPFlags flag) {
515 		if (stream.httpFlags & flag) {
516 			return false;
517 		}
518 		if (lws(value)) {
519 			return false;
520 		}
521 		stream.httpFlags = cast(HTTPFlags)(stream.httpFlags | flag);
522 		return true;
523 	}
524 
525 	bool lws(in string s) {
526 		size_t i;
527 		for (i = 0; i < s.length; ++i)
528 			if (s.ptr[i] != ' ' && s.ptr[i] != '\t')
529 				return false;
530 		return true;
531 	}
532 }
533 
534 
535 /// The frame types in HTTP/2 specification.
536 enum FrameType : ubyte
537 {
538 	DATA = 0,
539 	HEADERS = 0x01,
540     PRIORITY = 0x02,
541 	RST_STREAM = 0x03,
542 	SETTINGS = 0x04,
543 	PUSH_PROMISE = 0x05,
544     PING = 0x06,
545 	GOAWAY = 0x07,
546 	WINDOW_UPDATE = 0x08,
547 	CONTINUATION = 0x09
548 }
549 
550 /// The flags for HTTP/2 frames.  This enum defines all flags for all frames.
551 enum FrameFlags : ubyte 
552 {
553 	NONE = 0,
554 	END_STREAM = 0x01,
555 	END_HEADERS = 0x04,
556 	ACK = 0x01,
557 	PADDED = 0x08,
558 	PRIORITY = 0x20
559 }
560 
561 
562 /// The status codes for the RST_STREAM and GOAWAY frames.
563 enum FrameError : uint
564 {
565 	NO_ERROR = 0x00,
566 	PROTOCOL_ERROR = 0x01,
567 	INTERNAL_ERROR = 0x02,
568 	FLOW_CONTROL_ERROR = 0x03,
569 	TIMEOUT = 0x04,
570 	STREAM_CLOSED = 0x05,
571 	FRAME_SIZE_ERROR = 0x06,
572 	REFUSED_STREAM = 0x07,
573 	CANCEL = 0x08,
574 	COMPRESSION_ERROR = 0x09,
575 	CONNECT_ERROR = 0x0a,
576 	ENHANCE_YOUR_CALM = 0x0b,
577 	INADEQUATE_SECURITY = 0x0c,
578 	HTTP_1_1_REQUIRED = 0x0d
579 }
580 
581 /**
582  * Callback function invoked when the library wants to read data from
583  * the source.  The read data is sent in the stream |stream_id|.
584  * The implementation of this function must read at most |length|
585  * bytes of data from |source| (or possibly other places) and store
586  * them in |buf| and return number of data stored in |buf|.  If EOF is
587  * reached, set $(D DataFlags.EOF)
588  *
589  * Sometime it is desirable to avoid copying data into |buf| and let
590  * application to send data directly.  To achieve this, set
591  * `DataFlags.NO_COPY` to |data_flags| (and possibly
592  * other flags, just like when we do copy), and return the number of
593  * bytes to send without copying data into |buf|.  The library, seeing
594  * `DataFlags.NO_COPY`, will invoke `Connector.writeData`.  
595  * The application must send complete DATA frame in that callback.
596  *
597  * If the application wants to postpone DATA frames (e.g.,
598  * asynchronous I/O, or reading data blocks for long time), it is
599  * achieved by setting $(D pause) without reading
600  * any data in this invocation.  The library removes DATA frame from
601  * the outgoing queue temporarily.  To move back deferred DATA frame
602  * to outgoing queue, call `resumeData()`.  
603  * 
604  * In case of error, there are 2 choices.
605  * Setting $(D rst_stream=true) will close the stream by issuing RST_STREAM with 
606  * $(D FrameError.INTERNAL_ERROR).  If a different error code is desirable, 
607  * use `http2_submit_rst_stream()`  with a desired error code and then
608  * set $(D rst_stream) to true. 
609  * 
610  * Returning false will signal $(D Error.CALLBACK_FAILURE), aborting the entire session.
611  */
612 alias DataProvider = int delegate(ubyte[] buf, ref DataFlags data_flags);
613 
614 /// The flags used to set in |data_flags| output parameter in DataSource.read_callback
615 enum DataFlags : ubyte
616 {
617 	/// No flag set.
618 	NONE = 0,
619 
620 	/// Indicates EOF was sensed.
621 	EOF = 0x01,
622 	/// Indicates that END_STREAM flag must not be set 
623 	/// even if EOF is set. Usually this flag is used to send
624 	/// trailer header fields with `submitRequest()` or `submitResponse()`
625 	/// Note: unused at the moment
626 	NO_END_STREAM = 0x02,
627 	/// Indicates that application will send complete DATA frame
628 	/// in `Connector.writeData`
629 	NO_COPY = 0x04
630 }
631 
632 /**
633  * The category of HEADERS, which indicates the role of the frame.  In
634  * HTTP/2 spec, request, response, push response and other arbitrary
635  * headers (e.g., trailers) are all called just HEADERS.  To give the
636  * application the role of incoming HEADERS frame, we define several
637  * categories.
638  */
639 enum HeadersCategory : ubyte
640 {
641 	/// The HEADERS frame is opening new stream, which is analogous to SYN_STREAM in SPDY.
642 	REQUEST = 0,
643 
644 	/// The HEADERS frame is the first response headers, which is analogous to SYN_REPLY in SPDY.
645 	RESPONSE = 1,
646 
647 	/// The HEADERS frame is the first headers sent against reserved stream.
648 	PUSH_RESPONSE = 2,
649 
650 	/**
651     * The HEADERS frame which does not apply for the above categories,
652     * which is analogous to HEADERS in SPDY.  If non-final response
653     * (e.g., status 1xx) is used, final response HEADERS frame will be
654     * categorized here.
655     */
656 	HEADERS = 3
657 }
658 
659 
660 /// nghttp2_stream_state
661 /**
662  * If local peer is stream initiator:
663  * OPENING : upon sending request HEADERS
664  * OPENED : upon receiving response HEADERS
665  * CLOSING : upon queuing RST_STREAM
666  *
667  * If remote peer is stream initiator:
668  * OPENING : upon receiving request HEADERS
669  * OPENED : upon sending response HEADERS
670  * CLOSING : upon queuing RST_STREAM
671  */
672 enum StreamState : ubyte {
673 	/// Initial state
674 	INITIAL,
675 	
676 	/// For stream initiator: request HEADERS has been sent, but response HEADERS has not been received yet. 
677 	/// For receiver: request HEADERS has been received, but it does not send response HEADERS yet. 
678 	OPENING,
679 	
680 	/// For stream initiator: response HEADERS is received. For receiver: response HEADERS is sent.
681 	OPENED,
682 	
683 	/// RST_STREAM is received, but somehow we need to keep stream in memory.
684 	CLOSING,
685 	
686 	/// PUSH_PROMISE is received or sent
687 	RESERVED,
688 	
689 	/// Stream is created in this state if it is used as anchor in dependency tree.
690 	IDLE
691 }
692 
693 enum ShutdownFlag {
694 	NONE = 0,
695 	
696 	/// Indicates further receptions will be disallowed.
697 	RD = 0x01,
698 	
699 	/// Indicates further transmissions will be disallowed.
700 	WR = 0x02,
701 	
702 	/// Indicates both further receptions and transmissions will be disallowed.
703 	RDWR = RD | WR
704 }
705 
706 enum StreamFlags : ubyte {
707 	NONE = 0,
708 	
709 	/// Indicates that this stream is pushed stream and not opened yet.
710 	PUSH = 0x01,
711 	
712 	/// Indicates that this stream was closed
713 	CLOSED = 0x02,
714 	
715 	/// Indicates the item is deferred due to flow control.
716 	DEFERRED_FLOW_CONTROL = 0x04,
717 	
718 	/// Indicates the item is deferred by user callback
719 	DEFERRED_USER = 0x08,
720 	
721 	/// bitwise OR of DEFERRED_FLOW_CONTROL and DEFERRED_USER. */
722 	DEFERRED_ALL = 0x0c    
723 }
724 
725 /// HTTP related flags to enforce HTTP semantics
726 enum HTTPFlags {
727 	NONE = 0,
728 	
729 	/// header field seen so far 
730 	_AUTHORITY = 1,
731 	_PATH = 1 << 1,
732 	_METHOD = 1 << 2,
733 	_SCHEME = 1 << 3,
734 	
735 	/// host is not pseudo header, but we require either host or :authority 
736 	HOST = 1 << 4,
737 	_STATUS = 1 << 5,
738 	
739 	/// required header fields for HTTP request except for CONNECT method.
740 	REQ_HEADERS = _METHOD | _PATH | _SCHEME,
741 	PSEUDO_HEADER_DISALLOWED = 1 << 6,
742 	
743 	/* HTTP method flags */
744 	METH_CONNECT = 1 << 7,
745 	METH_HEAD = 1 << 8,
746 	METH_OPTIONS = 1 << 9,
747 	METH_ALL = METH_CONNECT | METH_HEAD | METH_OPTIONS,
748 	/* :path category */
749 	/* path starts with "/" */
750 	PATH_REGULAR = 1 << 10,
751 	/* path "*" */
752 	PATH_ASTERISK = 1 << 11,
753 	/* scheme */
754 	/* "http" or "https" scheme */
755 	SCHEME_HTTP = 1 << 12,
756 
757 	/* set if final response is expected */
758 	EXPECT_FINAL_RESPONSE = 1 << 13,
759 }
760 
761 enum StreamDPRI {
762 	NONE = 0,
763 	NO_ITEM = 0x01,
764 	TOP = 0x02,
765 	REST = 0x04
766 }
767 
768 /// HTTP Tokens
769 enum Token : int {
770 	ERROR = -1,
771 	_AUTHORITY = 0,
772 	_METHOD,
773 	_PATH,
774 	_SCHEME,
775 	_STATUS,
776 	CONNECTION,
777 	CONTENT_LENGTH,
778 	HOST,
779 	KEEP_ALIVE,
780 	PROXY_CONNECTION,
781 	TE,
782 	TRANSFER_ENCODING,
783 	UPGRADE,
784 	MAXIDX,
785 }
786 
787 struct Setting {
788 	alias SettingCode = ushort;
789 	/// Notes: If we add SETTINGS, update the capacity of HTTP2_INBOUND_NUM_IV as well
790 	enum : SettingCode {
791 		HEADER_TABLE_SIZE = 0x01,
792 		ENABLE_PUSH = 0x02,
793 		MAX_CONCURRENT_STREAMS = 0x03,
794 		INITIAL_WINDOW_SIZE = 0x04,
795 		MAX_FRAME_SIZE = 0x05,
796 		MAX_HEADER_LIST_SIZE = 0x06
797 	}
798 	
799 	/// The SETTINGS ID.
800 	SettingCode id;
801 	uint value;
802 
803 	void unpack(in ubyte[] payload) {
804 		id = read!ushort(payload);
805 		value = read!uint(payload[2 .. $]);
806 	}
807 }
808 
809 alias SettingsID = Setting.SettingCode;
810