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 }