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