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