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 }