1 module yu.tools.http1xparser.default_; 2 3 enum HTTPType : ubyte 4 { 5 REQUEST, 6 RESPONSE, 7 BOTH 8 } 9 10 enum HTTPMethod : ushort 11 { 12 DELETE = 0, 13 GET = 1, 14 HEAD = 2, 15 POST = 3, 16 PUT = 4, 17 /* pathological */ 18 CONNECT = 5, 19 OPTIONS = 6, 20 TRACE = 7, 21 /* WebDAV */ 22 COPY = 8, 23 LOCK = 9, 24 MKCOL = 10, 25 MOVE = 11, 26 PROPFIND = 12, 27 PROPPATCH = 13, 28 SEARCH = 14, 29 UNLOCK = 15, 30 BIND = 16, 31 REBIND = 17, 32 UNBIND = 18, 33 ACL = 19, 34 /* subversion */ 35 REPORT = 20, 36 MKACTIVITY = 21, 37 CHECKOUT = 22, 38 MERGE = 23, 39 /* upnp */ 40 MSEARCH = 24, 41 NOTIFY = 25, 42 SUBSCRIBE = 26, 43 UNSUBSCRIBE = 27, 44 /* RFC-5789 */ 45 PATCH = 28, 46 PURGE = 29, 47 /* CalDAV */ 48 MKCALENDAR = 30, 49 /* RFC-2068, section 19.6.1.2 */ 50 LINK = 31, 51 UNLINK = 32, 52 INVAILD = 33 53 } 54 55 enum HTTPParserErrno : ushort 56 { 57 /* No error */ 58 HPE_OK = 0, //"success") \ 59 60 /* Callback-related errors */ 61 HPE_CB_MessageBegin = 1, //"the on_message_begin callback failed") \ 62 HPE_CB_Url = 2, // "the on_url callback failed") \ 63 HPE_CB_HeaderField = 3, //"the on_header_field callback failed") \ 64 HPE_CB_HeaderValue = 4, //"the on_header_value callback failed") \ 65 HPE_CB_HeadersComplete = 5, //"the on_headers_complete callback failed") \ 66 HPE_CB_Body = 6, //"the on_body callback failed") \ 67 HPE_CB_MessageComplete = 7, // "the on_message_complete callback failed") \ 68 HPE_CB_Status = 8, // "the on_status callback failed") \ 69 HPE_CB_ChunkHeader = 9, //"the on_chunk_header callback failed") \ 70 HPE_CB_ChunkComplete = 10, //"the on_chunk_complete callback failed") \ 71 72 /* Parsing-related errors */ 73 HPE_INVALID_EOF_STATE = 11, // "stream ended at an unexpected time") \ 74 HPE_HEADER_OVERFLOW = 12, // "too many header bytes seen; overflow detected") \ 75 HPE_CLOSED_CONNECTION = 13, // "data received after completed connection: close message") \ 76 HPE_INVALID_VERSION = 14, // "invalid HTTP version") \ 77 HPE_INVALID_STATUS = 15, //"invalid HTTP status code") \ 78 HPE_INVALID_METHOD = 16, //"invalid HTTP method") \ 79 HPE_INVALID_URL = 17, //"invalid URL") \ 80 HPE_INVALID_HOST = 18, //"invalid host") \ 81 HPE_INVALID_PORT = 19, //"invalid port") \ 82 HPE_INVALID_PATH = 20, //"invalid path") \ 83 HPE_INVALID_QUERY_STRING = 21, //"invalid query string") \ 84 HPE_INVALID_FRAGMENT = 22, // "invalid fragment") \ 85 HPE_LF_EXPECTED = 23, //"LF character expected") \ 86 HPE_INVALID_HEADER_TOKEN = 24, //"invalid character in header") \ 87 HPE_INVALID_CONTENT_LENGTH = 25, // "invalid character in content-length header") \ 88 HPE_UNEXPECTED_CONTENT_LENGTH = 26, // "unexpected content-length header") \ 89 HPE_INVALID_CHUNK_SIZE = 27, // "invalid character in chunk size header") \ 90 HPE_INVALID_CONSTANT = 28, // "invalid constant string") \ 91 HPE_INVALID_INTERNAL_STATE = 29, //"encountered unexpected internal state")\ 92 HPE_STRICT = 30, // "strict mode assertion failed") \ 93 HPE_PAUSED = 31, //"parser is paused") \ 94 HPE_UNKNOWN = 32 //"an unknown error occurred") 95 } 96 97 enum CR = '\r'; 98 enum LF = '\n'; 99 100 enum ubyte[] PROXY_CONNECTION = cast(ubyte[]) "proxy-connection"; 101 enum ubyte[] CONNECTION = cast(ubyte[]) "connection"; 102 enum ubyte[] CONTENT_LENGTH = cast(ubyte[]) "content-length"; 103 enum ubyte[] TRANSFER_ENCODING = cast(ubyte[]) "transfer-encoding"; 104 enum ubyte[] UPGRADE = cast(ubyte[]) "upgrade"; 105 enum ubyte[] CHUNKED = cast(ubyte[]) "chunked"; 106 enum ubyte[] KEEP_ALIVE = cast(ubyte[]) "keep-alive"; 107 enum ubyte[] CLOSE = cast(ubyte[]) "close"; 108 109 enum ULLONG_MAX = ulong.max; 110 111 enum string[34] method_strings = [ 112 "DELETE", "GET", "HEAD", "POST", "PUT", /* pathological */ 113 "CONNECT", "OPTIONS", "TRACE", 114 /* WebDAV */ 115 "COPY", "LOCK", "MKCOL", "MOVE", "PROPFIND", "PROPPATCH", "SEARCH", 116 "UNLOCK", "BIND", "REBIND", "UNBIND", "ACL", /* subversion */ 117 "REPORT", "MKACTIVITY", 118 "CHECKOUT", "MERGE", /* upnp */ 119 "MSEARCH", "NOTIFY", "SUBSCRIBE", "UNSUBSCRIBE", /* RFC-5789 */ 120 "PATCH", "PURGE", /* CalDAV */ 121 "MKCALENDAR", /* RFC-2068, section 19.6.1.2 */ 122 "LINK", "UNLINK", /* 无效的 */ 123 "INVAILD" 124 ]; 125 126 enum HTTPMethod[string] method_id = buildMethodID(); 127 128 129 enum string[33] error_string = [ 130 "success" //ok 131 /* Callback-related errors */ 132 , "the on_message_begin callback failed" //CB_message_begin 133 , 134 "the on_url callback failed" //CB_url 135 , "the on_header_field callback failed" //CB_header_field 136 , 137 "the on_header_value callback failed" //CB_header_value 138 , "the on_headers_complete callback failed" //CB_headers_complete 139 , "the on_body callback failed" //CB_body 140 , 141 "the on_message_complete callback failed" //CB_message_complete 142 , "the on_status callback failed" //CB_status 143 , "the on_chunk_header callback failed" //CB_chunk_header 144 , 145 "the on_chunk_complete callback failed" //CB_chunk_complete 146 /* Parsing-related errors */ 147 , "stream ended at an unexpected time" //INVALID_EOF_STATE 148 , 149 "too many header bytes seen; overflow detected" //HEADER_OVERFLOW 150 , "data received after completed connection: close message" //CLOSED_CONNECTION 151 , 152 "invalid HTTP version" //INVALID_VERSION 153 , "invalid HTTP status code" //INVALID_STATUS 154 , "invalid HTTP method" //INVALID_METHOD 155 , "invalid URL" //INVALID_URL 156 , 157 "invalid host" //INVALID_HOST 158 , "invalid port" // INVALID_PORT 159 , "invalid query string" //INVALID_QUERY_STRING 160 , "invalid fragment" //INVALID_FRAGMENT 161 , 162 "LF character expected" //LF_EXPECTED 163 , "invalid character in header" //INVALID_HEADER_TOKEN 164 , 165 "invalid character in content-length header" //INVALID_CONTENT_LENGTH 166 , "unexpected content-length header" // UNEXPECTED_CONTENT_LENGTH 167 , 168 "invalid character in chunk size header" //INVALID_CHUNK_SIZE 169 , "invalid constant string" //INVALID_CONSTANT 170 , "encountered unexpected internal state" //INVALID_INTERNAL_STATE 171 , 172 "strict mode assertion failed" // STRICT 173 , "parser is paused" //PAUSED 174 , "an unknown error occurred" //UNKNOWN 175 ]; 176 177 @safe class Http1xParserExcetion : Exception { 178 this(HTTPParserErrno error, string file = __FILE__, size_t line = __LINE__, 179 Throwable next = null) @nogc @safe pure nothrow 180 { 181 _parserError = error; 182 super(error_string[error], file, line, next); 183 } 184 185 HTTPParserErrno parserError(){return _parserError;} 186 private: 187 HTTPParserErrno _parserError = HTTPParserErrno.HPE_OK; 188 } 189 190 191 @safe class Http1xParserStopExcetion : Exception { 192 this(HTTPParserErrno error, ulong size,string file = __FILE__, size_t line = __LINE__, 193 Throwable next = null) @nogc @safe pure nothrow 194 { 195 _parserError = error; 196 super(error_string[error], file, line, next); 197 _size = size; 198 } 199 200 HTTPParserErrno parserError(){return _parserError;} 201 ulong handleSize(){return _size;} 202 private: 203 HTTPParserErrno _parserError = HTTPParserErrno.HPE_OK; 204 ulong _size; 205 } 206 207 enum HTTPParserFlags 208 { 209 F_CHUNKED = 1 << 0, 210 F_CONNECTION_KEEP_ALIVE = 1 << 1, 211 F_CONNECTION_CLOSE = 1 << 2, 212 F_CONNECTION_UPGRADE = 1 << 3, 213 F_TRAILING = 1 << 4, 214 F_UPGRADE = 1 << 5, 215 F_SKIPBODY = 1 << 6, 216 F_CONTENTLENGTH = 1 << 7, 217 F_ZERO = 0 218 } 219 220 enum HTTPParserURLFields 221 { 222 UF_SCHEMA = 0, 223 UF_HOST = 1, 224 UF_PORT = 2, 225 UF_PATH = 3, 226 UF_QUERY = 4, 227 UF_FRAGMENT = 5, 228 UF_USERINFO = 6, 229 UF_MAX = 7 230 } 231 232 enum char[256] tokens = [ /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 233 0, 0, 0, 0, 0, 0, 0, 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 234 0, 0, 0, 0, 0, 0, 0, 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 235 0, 0, 0, 0, 0, 0, 0, 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 236 0, 0, 0, 0, 0, 0, 0, 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ 237 0, '!', 0, '#', '$', '%', '&', '\'', /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 238 0, 0, '*', '+', 0, '-', '.', 0, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ 239 '0', 240 '1', '2', '3', '4', '5', '6', '7', /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ 241 '8', '9', 0, 0, 0, 0, 0, 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 242 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 243 'h', 'i', 244 'j', 'k', 'l', 'm', 'n', 'o', /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 245 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 246 'x', 247 'y', 'z', 0, 0, 0, '^', '_', /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ 248 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 249 'h', 250 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 251 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 252 /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 253 'x', 'y', 'z', 0, '|', 0, '~', 0]; 254 255 enum byte[256] unhex = [-1, -1, -1, -1, -1, -1, -1, 256 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 257 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 258 -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, 259 -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, 260 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 261 -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 262 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]; 263 264 version (HTTP_PARSER_STRICT) 265 { 266 pragma(inline,true) 267 ubyte T(ubyte v) 268 { 269 return 0; 270 } 271 } 272 else 273 { 274 pragma(inline,true) 275 ubyte T(ubyte v) 276 { 277 return v; 278 } 279 } 280 281 282 enum ubyte[32] normal_url_char = [ /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 283 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 284 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 285 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 286 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ 287 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 288 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ 289 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ 290 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 291 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 292 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 293 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 294 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ 295 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 296 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 297 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 298 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,]; 299 300 301 enum HTTPParserState 302 { 303 s_dead = 1 /* important that this is > 0 */ 304 305 , 306 s_start_req_or_res, 307 s_res_or_resp_H, 308 s_start_res, 309 s_res_H, 310 s_res_HT, 311 s_res_HTT, 312 s_res_HTTP, 313 s_res_first_http_major, 314 s_res_http_major, 315 s_res_first_http_minor, 316 s_res_http_minor, 317 s_res_first_status_code, 318 s_res_status_code, 319 s_res_status_start, 320 s_res_status, 321 s_res_line_almost_done, 322 s_start_req, 323 s_req_method, 324 s_req_spaces_before_url, 325 s_req_schema, 326 s_req_schema_slash, 327 s_req_schema_slash_slash, 328 s_req_server_start, 329 s_req_server, 330 s_req_server_with_at, 331 s_req_path, 332 s_req_query_string_start, 333 s_req_query_string, 334 s_req_fragment_start, 335 s_req_fragment, 336 s_req_http_start, 337 s_req_http_H, 338 s_req_http_HT, 339 s_req_http_HTT, 340 s_req_http_HTTP, 341 s_req_first_http_major, 342 s_req_http_major, 343 s_req_first_http_minor, 344 s_req_http_minor, 345 s_req_line_almost_done, 346 s_header_field_start, 347 s_header_field, 348 s_header_value_discard_ws, 349 s_header_value_discard_ws_almost_done, 350 s_header_value_discard_lws, 351 s_header_value_start, 352 s_header_value, 353 s_header_value_lws, 354 s_header_almost_done, 355 s_chunk_size_start, 356 s_chunk_size, 357 s_chunk_parameters, 358 s_chunk_size_almost_done, 359 s_headers_almost_done, 360 s_headers_done /* Important: 's_headers_done' must be the last 'header' state. All 361 * states beyond this must be 'body' states. It is used for overflow 362 * checking. See the PARSING_HEADER() macro. 363 */ 364 365 , 366 s_chunk_data, 367 s_chunk_data_almost_done, 368 s_chunk_data_done, 369 s_body_identity, 370 s_body_identity_eof, 371 s_message_done 372 } 373 374 enum HTTPParserHeaderstates 375 { 376 h_general = 0, 377 h_C, 378 h_CO, 379 h_CON, 380 h_matching_connection, 381 h_matching_proxy_connection, 382 h_matching_content_length, 383 h_matching_transfer_encoding, 384 h_matching_upgrade, 385 h_connection, 386 h_content_length, 387 h_transfer_encoding, 388 h_upgrade, 389 h_matching_transfer_encoding_chunked, 390 h_matching_connection_token_start, 391 h_matching_connection_keep_alive, 392 h_matching_connection_close, 393 h_matching_connection_upgrade, 394 h_matching_connection_token, 395 h_transfer_encoding_chunked, 396 h_connection_keep_alive, 397 h_connection_close, 398 h_connection_upgrade 399 } 400 401 enum http_parser_url_fields 402 { UF_SCHEMA = 0 403 , UF_HOST = 1 404 , UF_PORT = 2 405 , UF_PATH = 3 406 , UF_QUERY = 4 407 , UF_FRAGMENT = 5 408 , UF_USERINFO = 6 409 , UF_MAX = 7 410 }; 411 412 413 enum HTTPParserHostState 414 { 415 s_http_host_dead = 1, 416 s_http_userinfo_start, 417 s_http_userinfo, 418 s_http_host_start, 419 s_http_host_v6_start, 420 s_http_host, 421 s_http_host_v6, 422 s_http_host_v6_end, 423 s_http_host_v6_zone_start, 424 s_http_host_v6_zone, 425 s_http_host_port_start, 426 s_http_host_port 427 } 428 429 HTTPMethod[string] buildMethodID() 430 { 431 HTTPMethod[string] rv; 432 foreach(i, str; method_strings){ 433 rv[str] = cast(HTTPMethod)i; 434 } 435 return rv; 436 }