1 module yu.tools.http1xparser.parser;
2 
3 import yu.tools.http1xparser.default_;
4 import yu.tools.http1xparser.url;
5 
6 /** ubyte[] 为传过去字段里的位置引用,没有数据拷贝,自己使用的时候注意拷贝数据, 
7  bool 此段数据是否完结,可能只是数据的一部分。
8  */
9 
10 alias CallBackData = void delegate(ref HTTP1xParser, ubyte[], bool);
11 alias CallBackNotify = void delegate(ref HTTP1xParser);
12 
13 @trusted struct HTTP1xParser
14 {
15     @disable this(this);
16 
17     this(HTTPType ty, uint maxHeaderSize = 4096) nothrow
18     {
19         rest(ty, maxHeaderSize);
20     }
21 
22     pragma(inline, true) @property type() nothrow
23     {
24         return _type;
25     }
26 
27     pragma(inline, true) @property isUpgrade() nothrow
28     {
29         return _upgrade;
30     }
31 
32     pragma(inline, true) @property contentLength() nothrow
33     {
34         return _contentLength;
35     }
36 
37     pragma(inline, true) @property isChunked() nothrow
38     {
39         return (_flags & HTTPParserFlags.F_CHUNKED) == 0 ? false : true;
40     }
41 
42     pragma(inline, true) @property method() nothrow
43     {
44         return _method;
45     }
46 
47     pragma(inline, true) @property methodString() nothrow
48     {
49         return method_strings[_method];
50     }
51 
52      //版本号首位
53     pragma(inline, true) @property major() nothrow
54     {
55         return _httpMajor;
56     }
57 
58     //版本号末尾
59     pragma(inline, true) @property minor() nothrow
60     {
61         return _httpMinor;
62     }
63 
64     pragma(inline, true)  @property statusCode()nothrow {return _statusCode;}
65 
66     pragma(inline, true) @property handleIng() nothrow
67     {
68         return _isHandle;
69     }
70 
71     pragma(inline, true)  //will throw Http1xParserStopExcetion
72     @property stopNow() nothrow
73     {
74         _isHandle = false;
75     }
76 
77     pragma(inline, true) @property skipBody() nothrow
78     {
79         return _skipBody;
80     }
81 
82     pragma(inline) @property skipBody(bool skip) nothrow
83     {
84         return _skipBody = skip;
85     }
86 
87     pragma(inline, true) @property keepalive() nothrow
88     {
89         return _keepAlive;
90     }
91 
92     /** 回调函数指定 */
93     pragma(inline, true) @property onMessageBegin(CallBackNotify cback) nothrow
94     {
95         _onMessageBegin = cback;
96     }
97 
98     pragma(inline, true) @property onMessageComplete(CallBackNotify cback) nothrow
99     {
100         _onMessageComplete = cback;
101     }
102 
103     pragma(inline, true) @property onHeaderComplete(CallBackNotify cback) nothrow
104     {
105         _onHeadersComplete = cback;
106     }
107 
108     pragma(inline, true) @property onChunkHeader(CallBackNotify cback) nothrow
109     {
110         _onChunkHeader = cback;
111     }
112 
113     pragma(inline, true) @property onChunkComplete(CallBackNotify cback) nothrow
114     {
115         _onChunkComplete = cback;
116     }
117 
118     pragma(inline, true) @property onUrl(CallBackData cback) nothrow
119     {
120         _onUrl = cback;
121     }
122 
123     pragma(inline, true) @property onStatus(CallBackData cback) nothrow
124     {
125         _onStatus = cback;
126     }
127 
128     pragma(inline, true) @property onHeaderField(CallBackData cback) nothrow
129     { 
130         _onHeaderField = cback;
131     }
132 
133     pragma(inline, true) @property onHeaderValue(CallBackData cback) nothrow
134     {
135         _onHeaderValue = cback;
136     }
137 
138     pragma(inline, true) @property onBody(CallBackData cback) nothrow
139     {
140         _onBody = cback;
141     }
142 
143     void rest(HTTPType ty, uint maxHeaderSize = 4096) nothrow
144     {
145         type = ty;
146         _maxHeaderSize = maxHeaderSize;
147         _state = (type == HTTPType.REQUEST ? HTTPParserState.s_start_req : (type == HTTPType.RESPONSE
148                 ? HTTPParserState.s_start_res : HTTPParserState.s_start_req_or_res));
149         _httpErrno = HTTPParserErrno.HPE_OK;
150         _flags = HTTPParserFlags.F_ZERO;
151         _isHandle = false;
152         _skipBody = false;
153         _keepAlive = 0x00;
154     }
155 
156 public:
157 
158     pragma(inline, true) bool bodyIsFinal() nothrow
159     {
160         return _state == HTTPParserState.s_message_done;
161     }
162 
163     ulong httpParserExecute(ubyte[] data) 
164     {
165         _isHandle = true;
166         scope (exit)
167             _isHandle = false;
168         ubyte c, ch;
169         byte unhexVal;
170         size_t mHeaderFieldMark = size_t.max;
171         size_t mHeaderValueMark = size_t.max;
172         size_t mUrlMark = size_t.max;
173         size_t mBodyMark = size_t.max;
174         size_t mStatusMark = size_t.max;
175         size_t maxP = cast(long) data.length;
176         size_t p = 0;
177         if (_httpErrno != HTTPParserErrno.HPE_OK)
178             return 0;
179         if (data.length == 0)
180         {
181             switch (_state) with (HTTPParserState)
182             {
183             case s_body_identity_eof:
184                 /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
185                     * we got paused.
186                     */
187                 mixin(CALLBACK_NOTIFY_NOADVANCE("MessageComplete"));
188                 return 0;
189 
190             case s_dead:
191             case s_start_req_or_res:
192             case s_start_res:
193             case s_start_req:
194                 return 0;
195 
196             default:
197                 _httpErrno = HTTPParserErrno.HPE_INVALID_EOF_STATE;
198                 return 1;
199             }
200         }
201 
202         if (_state == HTTPParserState.s_header_field)
203             mHeaderFieldMark = 0;
204         if (_state == HTTPParserState.s_header_value)
205             mHeaderValueMark = 0;
206         switch (_state) with (HTTPParserState)
207         {
208         case s_req_path:
209         case s_req_schema:
210         case s_req_schema_slash:
211         case s_req_schema_slash_slash:
212         case s_req_server_start:
213         case s_req_server:
214         case s_req_server_with_at:
215         case s_req_query_string_start:
216         case s_req_query_string:
217         case s_req_fragment_start:
218         case s_req_fragment:
219             mUrlMark = 0;
220             break;
221         case s_res_status:
222             mStatusMark = 0;
223             break;
224         default:
225             break;
226         }
227         for (; p < maxP; ++p)
228             with (HTTPParserErrno)
229             {
230                 ch = data[p];
231                 if (_state <= HTTPParserState.s_headers_done)
232                 {
233                     _nread += 1;
234                     if (_nread > _maxHeaderSize)
235                         throw new Http1xParserExcetion(HPE_HEADER_OVERFLOW);
236                 }
237                 while (true)
238                 {
239                     switch (_state) with (HTTPParserState)
240                     {
241                     case s_dead:
242                         /* this _state is used after a 'Connection: close' message
243 					 * the parser will error out if it reads another message
244 					 */
245                         if (ch == CR || ch == LF)
246                             break;
247                         else
248                             throw new Http1xParserExcetion(HPE_CLOSED_CONNECTION);
249                     case s_start_req_or_res:
250                         {
251                             if (ch == CR || ch == LF)
252                                 break;
253                             _flags = HTTPParserFlags.F_ZERO;
254                             _contentLength = ulong.max;
255 
256                             if (ch == 'H')
257                             {
258                                 _state = s_res_or_resp_H;
259                                 mixin(CALLBACK_NOTIFY("MessageBegin")); // 开始处理
260                             }
261                             else
262                             {
263                                 type = HTTPType.REQUEST;
264                                 _state = s_start_req;
265                                 continue;
266                             }
267                             break;
268                         }
269                     case s_res_or_resp_H:
270                         if (ch == 'T')
271                         {
272                             type = HTTPType.RESPONSE;
273                             _state = s_res_HT;
274                         }
275                         else
276                         {
277                             if (ch != 'E')
278                                 throw new Http1xParserExcetion(HPE_INVALID_CONSTANT);
279 
280                             type = HTTPType.REQUEST;
281                             _method = HTTPMethod.HEAD;
282                             _index = 2;
283                             _state = s_req_method;
284                         }
285                         break;
286 
287                     case s_start_res:
288                         {
289                             _flags = HTTPParserFlags.F_ZERO;
290                             _contentLength = ulong.max;
291                             switch (ch)
292                             {
293                             case 'H':
294                                 _state = s_res_H;
295                                 break;
296 
297                             case CR:
298                             case LF:
299                                 break;
300 
301                             default:
302                                 throw new Http1xParserExcetion(HPE_INVALID_CONSTANT);
303                             }
304                             mixin(CALLBACK_NOTIFY("MessageBegin"));
305                         }
306                         break;
307                     case s_res_H:
308                         STRICT_CHECK(ch != 'T');
309                         _state = s_res_HT;
310                         break;
311 
312                     case s_res_HT:
313                         STRICT_CHECK(ch != 'T');
314                         _state = s_res_HTT;
315                         break;
316 
317                     case s_res_HTT:
318                         STRICT_CHECK(ch != 'P');
319                         _state = s_res_HTTP;
320                         break;
321 
322                     case s_res_HTTP:
323                         STRICT_CHECK(ch != '/');
324                         _state = s_res_first_http_major;
325                         break;
326 
327                     case s_res_first_http_major:
328                         if (ch < '0' || ch > '9')
329                             throw new Http1xParserExcetion(HPE_INVALID_VERSION);
330 
331                         _httpMajor = cast(ushort)(ch - '0');
332                         _state = HTTPParserState.s_res_http_major;
333                         break;
334 
335                         /* major HTTP version or dot */
336                     case s_res_http_major:
337                         {
338                             if (ch == '.')
339                             {
340                                 _state = s_res_first_http_minor;
341                                 break;
342                             }
343                             if (!mixin(IS_NUM("ch")))
344                                 throw new Http1xParserExcetion(HPE_INVALID_VERSION);
345 
346                             _httpMajor *= 10;
347                             _httpMajor += ch - '0';
348 
349                             if (_httpMajor > 999)
350                                 throw new Http1xParserExcetion(HPE_INVALID_VERSION);
351                         }
352                         break;
353 
354                         /* first digit of minor HTTP version */
355                     case s_res_first_http_minor:
356                         if (!mixin(IS_NUM("ch")))
357                             throw new Http1xParserExcetion(HPE_INVALID_VERSION);
358 
359                         _httpMinor = cast(ushort)(ch - '0');
360                         _state = s_res_http_minor;
361                         break;
362 
363                         /* minor HTTP version or end of request line */
364                     case s_res_http_minor:
365                         {
366                             if (ch == ' ')
367                             {
368                                 _state = s_res_first_status_code;
369                                 break;
370                             }
371 
372                             if (!mixin(IS_NUM("ch")))
373                                 throw new Http1xParserExcetion(HPE_INVALID_VERSION);
374                             _httpMinor *= 10;
375                             _httpMinor += ch - '0';
376 
377                             if (_httpMinor > 999)
378                                 throw new Http1xParserExcetion(HPE_INVALID_VERSION);
379                         }
380                         break;
381 
382                     case s_res_first_status_code:
383                         {
384                             if (!mixin(IS_NUM("ch")))
385                             {
386                                 if (ch == ' ')
387                                     break;
388                                 throw new Http1xParserExcetion(HPE_INVALID_STATUS);
389                             }
390                             _statusCode = ch - '0';
391                             _state = s_res_status_code;
392                         }
393                         break;
394 
395                     case s_res_status_code:
396                         {
397                             if (!mixin(IS_NUM("ch")))
398                             {
399                                 switch (ch)
400                                 {
401                                 case ' ':
402                                     _state = s_res_status_start;
403                                     break;
404                                 case CR:
405                                     _state = s_res_line_almost_done;
406                                     break;
407                                 case LF:
408                                     _state = s_header_field_start;
409                                     break;
410                                 default:
411                                     throw new Http1xParserExcetion(HPE_INVALID_STATUS);
412                                 }
413                                 break;
414                             }
415 
416                             _statusCode *= 10;
417                             _statusCode += ch - '0';
418 
419                             if (_statusCode > 999)
420                                 throw new Http1xParserExcetion(HPE_INVALID_STATUS);
421                         }
422                         break;
423 
424                     case s_res_status_start:
425                         {
426                             if (ch == CR)
427                             {
428                                 _state = s_res_line_almost_done;
429                                 break;
430                             }
431 
432                             if (ch == LF)
433                             {
434                                 _state = s_header_field_start;
435                                 break;
436                             }
437 
438                             //MARK(status);
439                             if (mStatusMark == size_t.max)
440                                 mStatusMark = p;
441                             _state = s_res_status;
442                             _index = 0;
443                         }
444                         break;
445 
446                     case s_res_status:
447                         if (ch == CR)
448                         {
449                             _state = s_res_line_almost_done;
450                             mixin(CALLBACK_DATA("Status"));
451                             break;
452                         }
453 
454                         if (ch == LF)
455                         {
456                             _state = s_header_field_start;
457                             mixin(CALLBACK_DATA("Status"));
458                             break;
459                         }
460 
461                         break;
462 
463                     case s_res_line_almost_done:
464                         STRICT_CHECK(ch != LF);
465                         _state = s_header_field_start;
466                         break;
467 
468                     case s_start_req:
469                         {
470                             if (ch == CR || ch == LF)
471                                 break;
472                             _flags = HTTPParserFlags.F_ZERO;
473                             _contentLength = ulong.max;
474 
475                             if (!mixin(IS_ALPHA("ch")))
476                                 throw new Http1xParserExcetion(HPE_INVALID_METHOD);
477 
478                             _index = 1;
479                             switch (ch) with (HTTPMethod)
480                             {
481                             case 'A':
482                                 _method = ACL;
483                                 break;
484                             case 'B':
485                                 _method = BIND;
486                                 break;
487                             case 'C':
488                                 _method = CONNECT; /* or COPY, CHECKOUT */ break;
489                             case 'D':
490                                 _method = DELETE;
491                                 break;
492                             case 'G':
493                                 _method = GET;
494                                 break;
495                             case 'H':
496                                 _method = HEAD;
497                                 break;
498                             case 'L':
499                                 _method = LOCK; /* or LINK */ break;
500                             case 'M':
501                                 _method = MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break;
502                             case 'N':
503                                 _method = NOTIFY;
504                                 break;
505                             case 'O':
506                                 _method = OPTIONS;
507                                 break;
508                             case 'P':
509                                 _method = POST;
510                                 /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
511                                 break;
512                             case 'R':
513                                 _method = REPORT; /* or REBIND */ break;
514                             case 'S':
515                                 _method = SUBSCRIBE; /* or SEARCH */ break;
516                             case 'T':
517                                 _method = TRACE;
518                                 break;
519                             case 'U':
520                                 _method = UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break;
521                             default:
522                                 throw new Http1xParserExcetion(HPE_INVALID_METHOD);
523                             }
524                             _state = HTTPParserState.s_req_method;
525                             mixin(CALLBACK_NOTIFY("MessageBegin"));
526                         }
527                         break;
528 
529                     case s_req_method:
530                         {
531                             if (ch == '\0')
532                                 throw new Http1xParserExcetion(HPE_INVALID_METHOD);
533 
534                             string matcher = method_strings[_method];
535                             if (ch == ' ' && matcher.length == _index)
536                                 _state = HTTPParserState.s_req_spaces_before_url;
537                             else if (ch == matcher[_index])
538                             {
539                                 /* nada */
540                             }
541                             else if (_method == HTTPMethod.CONNECT)
542                             {
543                                 if (_index == 1 && ch == 'H')
544                                     _method = HTTPMethod.CHECKOUT;
545                                 else if (_index == 2 && ch == 'P')
546                                     _method = HTTPMethod.COPY;
547                                 else
548                                     throw new Http1xParserExcetion(HPE_INVALID_METHOD);
549                             }
550                             else if (_method == HTTPMethod.MKCOL)
551                             {
552                                 if (_index == 1 && ch == 'O')
553                                     _method = HTTPMethod.MOVE;
554                                 else if (_index == 1 && ch == 'E')
555                                     _method = HTTPMethod.MERGE;
556                                 else if (_index == 1 && ch == '-')
557                                     _method = HTTPMethod.MSEARCH;
558                                 else if (_index == 2 && ch == 'A')
559                                     _method = HTTPMethod.MKACTIVITY;
560                                 else if (_index == 3 && ch == 'A')
561                                     _method = HTTPMethod.MKCALENDAR;
562                                 else
563                                     throw new Http1xParserExcetion(HPE_INVALID_METHOD);
564                             }
565                             else if (_method == HTTPMethod.SUBSCRIBE)
566                             {
567                                 if (_index == 1 && ch == 'E')
568                                     _method = HTTPMethod.SEARCH;
569                                 else
570                                     throw new Http1xParserExcetion(HPE_INVALID_METHOD);
571                             }
572                             else if (_method == HTTPMethod.REPORT)
573                             {
574                                 if (_index == 2 && ch == 'B')
575                                     _method = HTTPMethod.REBIND;
576                                 else
577                                     throw new Http1xParserExcetion(HPE_INVALID_METHOD);
578                             }
579                             else if (_index == 1)
580                             {
581                                 if (_method == HTTPMethod.POST)
582                                 {
583                                     if (ch == 'R')
584                                         _method = HTTPMethod.PROPFIND; /* or HTTP_PROPPATCH */
585                                     else if (ch == 'U')
586                                         _method = HTTPMethod.PUT; /* or HTTP_PURGE */
587                                     else if (ch == 'A')
588                                         _method = HTTPMethod.PATCH;
589                                     else
590                                         throw new Http1xParserExcetion(HPE_INVALID_METHOD);
591                                 }
592                                 else if (_method == HTTPMethod.LOCK)
593                                 {
594                                     if (ch == 'I')
595                                         _method = HTTPMethod.LINK;
596                                     else
597                                         throw new Http1xParserExcetion(HPE_INVALID_METHOD);
598                                 }
599                             }
600                             else if (_index == 2)
601                             {
602                                 if (_method == HTTPMethod.PUT)
603                                 {
604                                     if (ch == 'R')
605                                         _method = HTTPMethod.PURGE;
606                                     else
607                                         throw new Http1xParserExcetion(HPE_INVALID_METHOD);
608                                 }
609                                 else if (_method == HTTPMethod.UNLOCK)
610                                 {
611                                     if (ch == 'S')
612                                         _method = HTTPMethod.UNSUBSCRIBE;
613                                     else if (ch == 'B')
614                                         _method = HTTPMethod.UNBIND;
615                                     else
616                                         throw new Http1xParserExcetion(HPE_INVALID_METHOD);
617                                 }
618                                 else
619                                     throw new Http1xParserExcetion(HPE_INVALID_METHOD);
620                             }
621                             else if (_index == 4 && _method == HTTPMethod.PROPFIND && ch == 'P')
622                             {
623                                 _method = HTTPMethod.PROPPATCH;
624                             }
625                             else if (_index == 3 && _method == HTTPMethod.UNLOCK && ch == 'I')
626                             {
627                                 _method = HTTPMethod.UNLINK;
628                             }
629                             else
630                                 throw new Http1xParserExcetion(HPE_INVALID_METHOD);
631                             ++_index;
632                         }
633                         break;
634 
635                     case s_req_spaces_before_url:
636                         {
637                             if (ch == ' ')
638                                 break;
639                             if (mUrlMark == size_t.max)
640                                 mUrlMark = p;
641                             if (_method == HTTPMethod.CONNECT)
642                                 _state = s_req_server_start;
643                             _state = parseURLchar(_state, ch);
644                             if (_state == s_dead)
645                                 throw new Http1xParserExcetion(HPE_INVALID_URL);
646                         }
647                         break;
648                     case s_req_schema:
649                     case s_req_schema_slash:
650                     case s_req_schema_slash_slash:
651                     case s_req_server_start:
652                         {
653                             switch (ch)
654                             {
655                             case ' ': /* No whitespace allowed here */
656                             case CR:
657                             case LF:
658                                 throw new Http1xParserExcetion(HPE_INVALID_URL);
659                             default:
660                                 _state = parseURLchar(_state, ch);
661                                 if (_state == s_dead)
662                                     throw new Http1xParserExcetion(HPE_INVALID_URL);
663                             }
664                         }
665                         break;
666                     case s_req_server:
667                     case s_req_server_with_at:
668                     case s_req_path:
669                     case s_req_query_string_start:
670                     case s_req_query_string:
671                     case s_req_fragment_start:
672                     case s_req_fragment:
673                         {
674                             switch (ch)
675                             {
676                             case ' ':
677                                 _state = s_req_http_start;
678                                 mixin(CALLBACK_DATA("Url"));
679                                 break;
680                             case CR:
681                             case LF:
682                                 _httpMajor = 0;
683                                 _httpMinor = 9;
684                                 _state = (ch == CR) ? s_req_line_almost_done : s_header_field_start;
685                                 mixin(CALLBACK_DATA("Url"));
686                                 break;
687                             default:
688                                 _state = parseURLchar(_state, ch);
689                                 if (_state == s_dead)
690                                     throw new Http1xParserExcetion(HPE_INVALID_URL);
691                             }
692                         }
693                         break;
694                     case s_req_http_start:
695                         switch (ch)
696                         {
697                         case 'H':
698                             _state = s_req_http_H;
699                             break;
700                         case ' ':
701                             break;
702                         default:
703                             throw new Http1xParserExcetion(HPE_INVALID_CONSTANT);
704                         }
705                         break;
706 
707                     case s_req_http_H:
708                         STRICT_CHECK(ch != 'T');
709                         _state = s_req_http_HT;
710                         break;
711 
712                     case s_req_http_HT:
713                         STRICT_CHECK(ch != 'T');
714                         _state = s_req_http_HTT;
715                         break;
716 
717                     case s_req_http_HTT:
718                         STRICT_CHECK(ch != 'P');
719                         _state = s_req_http_HTTP;
720                         break;
721 
722                     case s_req_http_HTTP:
723                         STRICT_CHECK(ch != '/');
724                         _state = s_req_first_http_major;
725                         break;
726 
727                         /* first digit of major HTTP version */
728                     case s_req_first_http_major:
729                         if (ch < '1' || ch > '9')
730                             throw new Http1xParserExcetion(HPE_INVALID_VERSION);
731 
732                         _httpMajor = cast(ushort)(ch - '0');
733                         _state = s_req_http_major;
734                         break;
735 
736                         /* major HTTP version or dot */
737                     case s_req_http_major:
738                         {
739                             if (ch == '.')
740                             {
741                                 _state = s_req_first_http_minor;
742                                 break;
743                             }
744 
745                             if (!mixin(IS_NUM("ch")))
746                                 throw new Http1xParserExcetion(HPE_INVALID_VERSION);
747 
748                             _httpMajor *= 10;
749                             _httpMajor += ch - '0';
750 
751                             if (_httpMajor > 999)
752                                 throw new Http1xParserExcetion(HPE_INVALID_VERSION);
753                         }
754                         break;
755                         /* first digit of minor HTTP version */
756                     case s_req_first_http_minor:
757                         if (!mixin(IS_NUM("ch")))
758                             throw new Http1xParserExcetion(HPE_INVALID_VERSION);
759 
760                         _httpMinor = cast(ushort)(ch - '0');
761                         _state = s_req_http_minor;
762                         break;
763 
764                         /* minor HTTP version or end of request line */
765                     case s_req_http_minor:
766                         {
767                             if (ch == CR)
768                             {
769                                 _state = s_req_line_almost_done;
770                                 break;
771                             }
772 
773                             if (ch == LF)
774                             {
775                                 _state = s_header_field_start;
776                                 break;
777                             }
778 
779                             /* XXX allow spaces after digit? */
780 
781                             if (!mixin(IS_NUM("ch")))
782                                 throw new Http1xParserExcetion(HPE_INVALID_VERSION);
783 
784                             _httpMinor *= 10;
785                             _httpMinor += ch - '0';
786 
787                             if (_httpMinor > 999)
788                                 throw new Http1xParserExcetion(HPE_INVALID_VERSION);
789                         }
790                         break;
791 
792                         /* end of request line */
793                     case s_req_line_almost_done:
794                         {
795                             if (ch != LF)
796                                 throw new Http1xParserExcetion(HPE_LF_EXPECTED);
797 
798                             _state = s_header_field_start;
799                         }
800                         break;
801                     case s_header_field_start:
802                         {
803                             if (ch == CR)
804                             {
805                                 _state = s_headers_almost_done;
806                                 break;
807                             }
808 
809                             if (ch == LF)
810                             {
811                                 /* they might be just sending \n instead of \r\n so this would be
812 						 * the second \n to denote the end of headers*/
813                                 _state = s_headers_almost_done;
814                                 continue;
815                             }
816 
817                             c = tokens[ch];
818 
819                             if (!c)
820                                 throw new Http1xParserExcetion(HPE_INVALID_HEADER_TOKEN);
821 
822                             if (mHeaderFieldMark == size_t.max)
823                                 mHeaderFieldMark = p;
824 
825                             _index = 0;
826                             _state = s_header_field;
827 
828                             switch (c) with (HTTPParserHeaderstates)
829                             {
830                             case 'c':
831                                 _headerState = h_C;
832                                 break;
833 
834                             case 'p':
835                                 _headerState = h_matching_proxy_connection;
836                                 break;
837 
838                             case 't':
839                                 _headerState = h_matching_transfer_encoding;
840                                 break;
841 
842                             case 'u':
843                                 _headerState = h_matching_upgrade;
844                                 break;
845 
846                             default:
847                                 _headerState = h_general;
848                                 break;
849                             }
850                         }
851                         break;
852                     case s_header_field:
853                         {
854                             const long start = p;
855                             for (; p < maxP; p++)
856                             {
857                                 ch = data[p];
858                                 c = tokens[ch];
859                                 if (!c)
860                                     break;
861 
862                                 switch (_headerState) with (HTTPParserHeaderstates)
863                                 {
864                                 case h_general:
865                                     break;
866 
867                                 case h_C:
868                                     _index++;
869                                     _headerState = (c == 'o' ? h_CO : h_general);
870                                     break;
871 
872                                 case h_CO:
873                                     _index++;
874                                     _headerState = (c == 'n' ? h_CON : h_general);
875                                     break;
876 
877                                 case h_CON:
878                                     _index++;
879                                     switch (c)
880                                     {
881                                     case 'n':
882                                         _headerState = h_matching_connection;
883                                         break;
884                                     case 't':
885                                         _headerState = h_matching_content_length;
886                                         break;
887                                     default:
888                                         _headerState = h_general;
889                                         break;
890                                     }
891                                     break;
892                                     /* connection */
893                                 case h_matching_connection:
894                                     _index++;
895                                     if (_index > CONNECTION.length || c != CONNECTION[_index])
896                                     {
897                                         _headerState = HTTPParserHeaderstates.h_general;
898                                     }
899                                     else if (_index == CONNECTION.length - 1)
900                                     {
901                                         _headerState = h_connection;
902                                     }
903                                     break;
904                                     /* proxy-connection */
905                                 case h_matching_proxy_connection:
906                                     _index++;
907                                     if (_index > PROXY_CONNECTION.length
908                                             || c != PROXY_CONNECTION[_index])
909                                     {
910                                         _headerState = h_general;
911                                     }
912                                     else if (_index == PROXY_CONNECTION.length)
913                                     {
914                                         _headerState = h_connection;
915                                     }
916                                     break;
917                                     /* content-length */
918                                 case h_matching_content_length:
919                                     _index++;
920                                     if (_index > CONTENT_LENGTH.length || c != CONTENT_LENGTH[
921                                         _index])
922                                     {
923                                         _headerState = h_general;
924                                     }
925                                     else if (_index == CONTENT_LENGTH.length - 1)
926                                     {
927                                         if (_flags & HTTPParserFlags.F_CONTENTLENGTH)
928                                             throw new Http1xParserExcetion(
929                                                     HPE_UNEXPECTED_CONTENT_LENGTH);
930                                         _headerState = HTTPParserHeaderstates.h_content_length;
931                                         _flags |= HTTPParserFlags.F_CONTENTLENGTH;
932                                     }
933                                     break;
934                                     /* transfer-encoding */
935                                 case h_matching_transfer_encoding:
936                                     _index++;
937                                     if (_index > TRANSFER_ENCODING.length
938                                             || c != TRANSFER_ENCODING[_index])
939                                     {
940                                         _headerState = h_general;
941                                     }
942                                     else if (_index == TRANSFER_ENCODING.length - 1)
943                                     {
944                                         _headerState = h_transfer_encoding;
945                                     }
946                                     break;
947 
948                                     /* upgrade */
949 
950                                 case h_matching_upgrade:
951                                     _index++;
952                                     if (_index > UPGRADE.length || c != UPGRADE[_index])
953                                     {
954                                         _headerState = h_general;
955                                     }
956                                     else if (_index == UPGRADE.length - 1)
957                                     {
958                                         _headerState = h_upgrade;
959                                     }
960                                     break;
961 
962                                 case h_connection:
963                                 case h_content_length:
964                                 case h_transfer_encoding:
965                                 case h_upgrade:
966                                     if (ch != ' ')
967                                         _headerState = HTTPParserHeaderstates.h_general;
968                                     break;
969                                 default:
970                                     assert(false, "Unknown  _headerState");
971                                     //	break;
972                                 }
973                             }
974                             _nread += (p - start);
975                             if (_nread > _maxHeaderSize)
976                                 throw new Http1xParserExcetion(HTTPParserErrno.HPE_HEADER_OVERFLOW);
977                             if (p == maxP)
978                             {
979                                 --p;
980                             }
981                             else if (ch == ':')
982                             {
983                                 _state = HTTPParserState.s_header_value_discard_ws;
984                                 mixin(CALLBACK_DATA("HeaderField"));
985                             }
986                             else
987                                 throw new Http1xParserExcetion(HPE_INVALID_HEADER_TOKEN);
988                         }
989                         break;
990                     case s_header_value_discard_ws:
991                         if (ch == ' ' || ch == '\t')
992                             break;
993                         if (ch == CR)
994                         {
995                             _state = s_header_value_discard_ws_almost_done;
996                             break;
997                         }
998                         if (ch == LF)
999                         {
1000                             _state = s_header_value_discard_lws;
1001                             break;
1002                         }
1003                         goto case;
1004                         /* FALLTHROUGH */
1005                     case s_header_value_start:
1006                         {
1007                             //MARK(header_value);
1008                             if (mHeaderValueMark == size_t.max)
1009                                 mHeaderValueMark = p;
1010                             _state = s_header_value;
1011                             _index = 0;
1012 
1013                             c = ch | 0x20; //LOWER(ch);
1014                             switch (_headerState) with (HTTPParserHeaderstates)
1015                             {
1016                             case h_upgrade:
1017                                 _flags |= HTTPParserFlags.F_UPGRADE;
1018                                 _headerState = h_general;
1019                                 break;
1020 
1021                             case h_transfer_encoding:
1022                                 /* looking for 'Transfer-Encoding: chunked' */
1023                                 if ('c' == c)
1024                                 {
1025                                     _headerState = h_matching_transfer_encoding_chunked;
1026                                 }
1027                                 else
1028                                 {
1029                                     _headerState = h_general;
1030                                 }
1031                                 break;
1032 
1033                             case h_content_length:
1034                                 if (!mixin(IS_NUM("ch")))
1035                                     throw new Http1xParserExcetion(HPE_INVALID_CONTENT_LENGTH);
1036                                 _contentLength = ch - '0';
1037                                 break;
1038 
1039                             case h_connection:
1040                                 /* looking for 'Connection: keep-alive' */
1041                                 if (c == 'k')
1042                                 {
1043                                     _headerState = h_matching_connection_keep_alive;
1044                                     _keepAlive = 0x01;
1045                                     /* looking for 'Connection: close' */
1046                                 }
1047                                 else if (c == 'c')
1048                                 {
1049                                     _headerState = h_matching_connection_close;
1050                                     _keepAlive = 0x02;
1051                                 }
1052                                 else if (c == 'u')
1053                                 {
1054                                     _headerState = h_matching_connection_upgrade;
1055                                     _keepAlive = 0x03;
1056                                 }
1057                                 else
1058                                 {
1059                                     _headerState = h_matching_connection_token;
1060                                     _keepAlive = 0x04;
1061                                 }
1062                                 break;
1063 
1064                                 /* Multi-value `Connection` header */
1065                             case h_matching_connection_token_start:
1066                                 break;
1067 
1068                             default:
1069                                 _headerState = h_general;
1070                                 break;
1071                             }
1072                         }
1073                         break;
1074                     case s_header_value:
1075                         {
1076                             const long start = p;
1077                             auto h_state = _headerState;
1078                             for (; p < maxP; p++)
1079                             {
1080                                 ch = data[p];
1081                                 if (ch == CR)
1082                                 {
1083                                     _state = s_header_almost_done;
1084                                     _headerState = h_state;
1085                                     mixin(CALLBACK_DATA("HeaderValue"));
1086                                     break;
1087                                 }
1088 
1089                                 if (ch == LF)
1090                                 {
1091                                     _state = s_header_almost_done;
1092                                     //COUNT_HEADER_SIZE(p - start);
1093                                     _nread += (p - start);
1094                                     if (_nread > _maxHeaderSize)
1095                                         throw new Http1xParserExcetion(HPE_HEADER_OVERFLOW);
1096                                     _headerState = h_state;
1097                                     mixin(CALLBACK_DATA_NOADVANCE("HeaderValue"));
1098                                     continue;
1099                                 }
1100 
1101                                 if (!_lenientHttpHeaders && !(ch == CR
1102                                         || ch == LF || ch == 9 || (ch > 31 && ch != 127)))
1103                                     throw new Http1xParserExcetion(HPE_INVALID_HEADER_TOKEN);
1104                                 c = ch | 0x20; //LOWER(ch);
1105                                 switch (h_state) with (HTTPParserHeaderstates)
1106                                 {
1107                                 case h_general:
1108                                     {
1109                                         //import std.string;
1110                                         import core.stdc.string;
1111 
1112                                         size_t limit = maxP - p;
1113                                         limit = (limit < _maxHeaderSize ? limit : _maxHeaderSize); //MIN(limit, TTPConfig.instance.MaxHeaderSize);
1114                                         auto str = data[p .. maxP];
1115                                         auto tptr = cast(ubyte*) memchr(str.ptr, CR, str.length);
1116                                         auto p_cr = tptr - str.ptr; //str._indexOf(CR); // memchr(p, CR, limit);
1117                                         tptr = cast(ubyte*) memchr(str.ptr, LF, str.length);
1118                                         auto p_lf = tptr - str.ptr; //str._indexOf(LF); // memchr(p, LF, limit);
1119                                         ++p_cr;
1120                                         ++p_lf;
1121                                         if (p_cr > 0)
1122                                         {
1123                                             if (p_lf > 0 && p_cr >= p_lf)
1124                                                 p += p_lf;
1125                                             else
1126                                                 p += p_cr;
1127                                         }
1128                                         else if (p_lf > 0)
1129                                         {
1130                                             p += p_lf;
1131                                         }
1132                                         else
1133                                         {
1134                                             p = maxP;
1135                                         }
1136                                         p -= 2;
1137                                     }
1138                                     break;
1139                                 case h_connection:
1140                                 case h_transfer_encoding:
1141                                     assert(0, "Shouldn't get here.");
1142                                     //break;
1143 
1144                                 case h_content_length:
1145                                     {
1146                                         ulong t;
1147 
1148                                         if (ch == ' ')
1149                                             break;
1150 
1151                                         if (!mixin(IS_NUM("ch")))
1152                                             throw new Http1xParserExcetion(
1153                                                     HPE_INVALID_CONTENT_LENGTH);
1154 
1155                                         t = _contentLength;
1156                                         t *= 10;
1157                                         t += ch - '0';
1158 
1159                                         /* Overflow? Test against a conservative limit for simplicity. */
1160                                         if ((ulong.max - 10) / 10 < _contentLength)
1161                                             throw new Http1xParserExcetion(
1162                                                     HPE_INVALID_CONTENT_LENGTH);
1163                                         _contentLength = t;
1164                                     }
1165                                     break;
1166                                     /* Transfer-Encoding: chunked */
1167                                 case h_matching_transfer_encoding_chunked: {
1168                                     _index++;
1169                                     if (_index > CHUNKED.length || c != CHUNKED[_index])
1170                                         h_state = h_general;
1171                                     else if (_index == CHUNKED.length - 1)
1172                                         h_state = h_transfer_encoding_chunked;
1173                                 }
1174                                     break;
1175 
1176                                 case HTTPParserHeaderstates.h_matching_connection_token_start:
1177                                     /* looking for 'Connection: keep-alive' */
1178                                     if (c == 'k')
1179                                         h_state = h_matching_connection_keep_alive;
1180                                     /* looking for 'Connection: close' */
1181                                     else if (c == 'c')
1182                                         h_state = h_matching_connection_close;
1183                                     else if (c == 'u')
1184                                         h_state = h_matching_connection_upgrade;
1185                                     else if (tokens[c])
1186                                         h_state = h_matching_connection_token;
1187                                     else if (c == ' ' || c == '\t')
1188                                     {
1189                                         /* Skip lws */
1190                                     }
1191                                     else
1192                                     {
1193                                         h_state = h_general;
1194                                     }
1195                                     break;
1196                                     /* looking for 'Connection: keep-alive' */
1197                                 case h_matching_connection_keep_alive:
1198                                     _index++;
1199                                     if (_index > KEEP_ALIVE.length || c != KEEP_ALIVE[_index])
1200                                         h_state = h_matching_connection_token;
1201                                     else if (_index == KEEP_ALIVE.length - 1)
1202                                         h_state = h_connection_keep_alive;
1203                                     break;
1204 
1205                                     /* looking for 'Connection: close' */
1206                                 case h_matching_connection_close:
1207                                     _index++;
1208                                     if (_index > CLOSE.length || c != CLOSE[_index])
1209                                         h_state = h_matching_connection_token;
1210                                     else if (_index == CLOSE.length - 1)
1211                                         h_state = h_connection_close;
1212                                     break;
1213 
1214                                     /* looking for 'Connection: upgrade' */
1215                                 case h_matching_connection_upgrade:
1216                                     _index++;
1217                                     if (_index > UPGRADE.length || c != UPGRADE[_index])
1218                                         h_state = h_matching_connection_token;
1219                                     else if (_index == UPGRADE.length - 1)
1220                                         h_state = h_connection_upgrade;
1221                                     break;
1222 
1223                                 case h_matching_connection_token:
1224                                     if (ch == ',')
1225                                     {
1226                                         h_state = h_matching_connection_token_start;
1227                                         _index = 0;
1228                                     }
1229                                     break;
1230 
1231                                 case h_transfer_encoding_chunked:
1232                                     if (ch != ' ')
1233                                         h_state = h_general;
1234                                     break;
1235 
1236                                 case h_connection_keep_alive:
1237                                 case h_connection_close:
1238                                 case h_connection_upgrade:
1239                                     if (ch == ',')
1240                                     {
1241                                         if (h_state == h_connection_keep_alive)
1242                                             _flags |= HTTPParserFlags.F_CONNECTION_KEEP_ALIVE;
1243                                         else if (h_state == h_connection_close)
1244                                             _flags |= HTTPParserFlags.F_CONNECTION_CLOSE;
1245                                         else if (h_state == h_connection_upgrade)
1246                                             _flags |= HTTPParserFlags.F_CONNECTION_UPGRADE;
1247                                         h_state = h_matching_connection_token_start;
1248                                         _index = 0;
1249                                     }
1250                                     else if (ch != ' ')
1251                                         h_state = h_matching_connection_token;
1252                                     break;
1253 
1254                                 default:
1255                                     _state = s_header_value;
1256                                     h_state = h_general;
1257                                     break;
1258                                 }
1259                             }
1260                             _headerState = h_state;
1261 
1262                             //COUNT_HEADER_SIZE(p - start);
1263                             _nread += (p - start);
1264                             if (_nread > _maxHeaderSize)
1265                                 throw new Http1xParserExcetion(HPE_HEADER_OVERFLOW);
1266                             if (p == maxP)
1267                                 --p;
1268                             break;
1269                         }
1270 
1271                     case s_header_almost_done:
1272                         if (ch != LF)
1273                             throw new Http1xParserExcetion(HPE_LF_EXPECTED);
1274                         _state = s_header_value_lws;
1275                         break;
1276                     case s_header_value_lws:
1277                         {
1278                             if (ch == ' ' || ch == '\t')
1279                             {
1280                                 _state = s_header_value_start;
1281                                 continue;
1282                             }
1283 
1284                             /* finished the header */
1285                             switch (_headerState) with (HTTPParserHeaderstates)
1286                             {
1287                             case h_connection_keep_alive:
1288                                 _flags |= HTTPParserFlags.F_CONNECTION_KEEP_ALIVE;
1289                                 break;
1290                             case h_connection_close:
1291                                 _flags |= HTTPParserFlags.F_CONNECTION_CLOSE;
1292                                 break;
1293                             case h_transfer_encoding_chunked:
1294                                 _flags |= HTTPParserFlags.F_CHUNKED;
1295                                 break;
1296                             case h_connection_upgrade:
1297                                 _flags |= HTTPParserFlags.F_CONNECTION_UPGRADE;
1298                                 break;
1299                             default:
1300                                 break;
1301                             }
1302 
1303                             _state = s_header_field_start;
1304                             continue;
1305                         }
1306 
1307                     case s_header_value_discard_ws_almost_done:
1308                         {
1309                             STRICT_CHECK(ch != LF);
1310                             _state = s_header_value_discard_lws;
1311                         }
1312                         break;
1313 
1314                     case s_header_value_discard_lws:
1315                         {
1316                             if (ch == ' ' || ch == '\t')
1317                             {
1318                                 _state = s_header_value_discard_ws;
1319                                 break;
1320                             }
1321                             else
1322                             {
1323                                 switch (_headerState) with (HTTPParserHeaderstates)
1324                                 {
1325                                 case h_connection_keep_alive:
1326                                     _flags |= HTTPParserFlags.F_CONNECTION_KEEP_ALIVE;
1327                                     break;
1328                                 case h_connection_close:
1329                                     _flags |= HTTPParserFlags.F_CONNECTION_CLOSE;
1330                                     break;
1331                                 case h_connection_upgrade:
1332                                     _flags |= HTTPParserFlags.F_CONNECTION_UPGRADE;
1333                                     break;
1334                                 case h_transfer_encoding_chunked:
1335                                     _flags |= HTTPParserFlags.F_CHUNKED;
1336                                     break;
1337                                 default:
1338                                     break;
1339                                 }
1340 
1341                                 /* header value was empty */
1342                                 //MARK(header_value);
1343                                 if (mHeaderValueMark == size_t.max)
1344                                 {
1345                                     mHeaderValueMark = p;
1346                                 }
1347                                 _state = s_header_field_start;
1348                                 mixin(CALLBACK_DATA_NOADVANCE("HeaderValue"));
1349                                 continue;
1350                             }
1351                         }
1352                         //TODO	
1353                     case s_headers_almost_done:
1354                         {
1355                             STRICT_CHECK(ch != LF);
1356 
1357                             if (_flags & HTTPParserFlags.F_TRAILING)
1358                             {
1359                                 /* End of a chunked request */
1360                                 _state = s_message_done;
1361                                 mixin(CALLBACK_NOTIFY_NOADVANCE("ChunkComplete"));
1362                                 continue;
1363                             }
1364 
1365                             /* Cannot use chunked encoding and a content-length header together
1366 					 per the HTTP specification. */
1367                             if ((_flags & HTTPParserFlags.F_CHUNKED)
1368                                     && (_flags & HTTPParserFlags.F_CONTENTLENGTH))
1369                                 throw new Http1xParserExcetion(HPE_UNEXPECTED_CONTENT_LENGTH);
1370                             _state = s_headers_done;
1371 
1372                             /* Set this here so that on_headers_complete() callbacks can see it */
1373                             _upgrade = ((_flags & (HTTPParserFlags.F_UPGRADE | HTTPParserFlags.F_CONNECTION_UPGRADE)) == (
1374                                     HTTPParserFlags.F_UPGRADE | HTTPParserFlags.F_CONNECTION_UPGRADE)
1375                                     || _method == HTTPMethod.CONNECT);
1376                             {
1377                                 if (_keepAlive == 0x00 && _httpMinor == 0 && _httpMajor == 1)
1378                                 {
1379                                     _keepAlive = 0x02;
1380                                 }
1381                                 else
1382                                 {
1383                                     _keepAlive = 0x01;
1384                                 }
1385                                 if (_onHeadersComplete !is null)
1386                                 {
1387                                     _onHeadersComplete(this);
1388                                     if (!handleIng)
1389                                         throw new Http1xParserStopExcetion(HPE_CB_HeadersComplete,
1390                                                 p + 1);
1391                                     if (skipBody)
1392                                         _flags |= HTTPParserFlags.F_SKIPBODY;
1393                                 }
1394                             }
1395                             continue;
1396                         }
1397                     case s_headers_done:
1398                         {
1399                             int hasBody;
1400                             STRICT_CHECK(ch != LF);
1401 
1402                             _nread = 0;
1403                             //int chunked = _flags & HTTPParserFlags.F_CHUNKED ;
1404                             //error("s_headers_done is chunked : ", chunked);
1405                             hasBody = _flags & HTTPParserFlags.F_CHUNKED
1406                                 || (_contentLength > 0 && _contentLength != ULLONG_MAX);
1407                             if (_upgrade && (_method == HTTPMethod.CONNECT
1408                                     || (_flags & HTTPParserFlags.F_SKIPBODY) || !hasBody))
1409                             {
1410                                 /* Exit, the rest of the message is in a different protocol. */
1411                                 _state = mixin(NEW_MESSAGE);
1412                                 mixin(CALLBACK_NOTIFY("MessageComplete"));
1413                                 return (p + 1);
1414                             }
1415 
1416                             if (_flags & HTTPParserFlags.F_SKIPBODY)
1417                             {
1418                                 _state = mixin(NEW_MESSAGE);
1419                                 mixin(CALLBACK_NOTIFY("MessageComplete"));
1420                             }
1421                             else if (_flags & HTTPParserFlags.F_CHUNKED)
1422                             {
1423                                 /* chunked encoding - ignore Content-Length header */
1424                                 _state = s_chunk_size_start;
1425                             }
1426                             else
1427                             {
1428                                 if (_contentLength == 0)
1429                                 {
1430                                     /* Content-Length header given but zero: Content-Length: 0\r\n */
1431                                     _state = mixin(NEW_MESSAGE);
1432                                     mixin(CALLBACK_NOTIFY("MessageComplete"));
1433                                 }
1434                                 else if (_contentLength != ULLONG_MAX)
1435                                 {
1436                                     /* Content-Length header given and non-zero */
1437                                     _state = s_body_identity;
1438                                 }
1439                                 else
1440                                 {
1441                                     if (!httpMessageNeedsEof())
1442                                     {
1443                                         /* Assume content-length 0 - read the next */
1444                                         _state = mixin(NEW_MESSAGE);
1445                                         mixin(CALLBACK_NOTIFY("MessageComplete"));
1446                                     }
1447                                     else
1448                                     {
1449                                         /* Read body until EOF */
1450                                         _state = s_body_identity_eof;
1451                                     }
1452                                 }
1453                             }
1454                             break;
1455                         }
1456 
1457                     case s_body_identity:
1458                         {
1459                             ulong to_read = _contentLength < cast(ulong)(maxP - p) ? _contentLength
1460                                 : cast(ulong)(maxP - p);
1461 
1462                             assert(_contentLength != 0 && _contentLength != ULLONG_MAX);
1463 
1464                             /* The difference between advancing _contentLength and p is because
1465 					 * the latter will automaticaly advance on the next loop iteration.
1466 					 * Further, if _contentLength ends up at 0, we want to see the last
1467 					 * byte again for our message complete callback.
1468 					 */
1469                             //MARK(body);
1470 
1471                             if (mBodyMark == size_t.max)
1472                                 mBodyMark = p;
1473                             _contentLength -= to_read;
1474                             p += to_read - 1;
1475 
1476                             if (_contentLength == 0)
1477                             {
1478                                 _state = s_message_done;
1479 
1480                                 /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
1481 						 *
1482 						 * The alternative to doing this is to wait for the next byte to
1483 						 * trigger the data callback, just as in every other case. The
1484 						 * problem with this is that this makes it difficult for the test
1485 						 * harness to distinguish between complete-on-EOF and
1486 						 * complete-on-length. It's not clear that this distinction is
1487 						 * important for applications, but let's keep it for now.
1488 						 */
1489                                 if (mBodyMark != size_t.max && _onBody !is null)
1490                                 {
1491                                     ubyte[] _data = data[mBodyMark .. p + 1];
1492                                     _onBody(this, _data, true);
1493                                     if (!handleIng)
1494                                         throw new Http1xParserStopExcetion(HPE_CB_Body, p + 1);
1495                                 }
1496                                 mBodyMark = size_t.max;
1497                                 continue;
1498                             }
1499                         }
1500                         break;
1501                         /* read until EOF */
1502                     case s_body_identity_eof:
1503                         //MARK(body);
1504                         if (mBodyMark == size_t.max)
1505                             mBodyMark = p;
1506                         p = maxP - 1;
1507                         break;
1508 
1509                     case s_message_done:
1510                         _state = mixin(NEW_MESSAGE);
1511                         mixin(CALLBACK_NOTIFY("MessageComplete"));
1512                         if (_upgrade) /* Exit, the rest of the message is in a different protocol. */
1513                             return (p + 1);
1514                         break;
1515 
1516                     case s_chunk_size_start:
1517                         {
1518                             assert(_nread == 1);
1519                             assert(_flags & HTTPParserFlags.F_CHUNKED);
1520 
1521                             unhexVal = unhex[ch];
1522                             if (unhexVal == -1)
1523                                 throw new Http1xParserExcetion(HPE_INVALID_CHUNK_SIZE);
1524 
1525                             _contentLength = unhexVal;
1526                             _state = s_chunk_size;
1527                         }
1528                         break;
1529                     case s_chunk_size:
1530                         {
1531                             ulong t;
1532 
1533                             assert(_flags & HTTPParserFlags.F_CHUNKED);
1534 
1535                             if (ch == CR)
1536                             {
1537                                 _state = s_chunk_size_almost_done;
1538                                 break;
1539                             }
1540 
1541                             unhexVal = unhex[ch];
1542 
1543                             if (unhexVal == -1)
1544                             {
1545                                 if (ch == ';' || ch == ' ')
1546                                 {
1547                                     _state = s_chunk_parameters;
1548                                     break;
1549                                 }
1550                                 throw new Http1xParserExcetion(HPE_INVALID_CHUNK_SIZE);
1551                             }
1552 
1553                             t = _contentLength;
1554                             t *= 16;
1555                             t += unhexVal;
1556 
1557                             /* Overflow? Test against a conservative limit for simplicity. */
1558                             if ((ULLONG_MAX - 16) / 16 < _contentLength)
1559                                 throw new Http1xParserExcetion(HPE_INVALID_CONTENT_LENGTH);
1560 
1561                             _contentLength = t;
1562                             break;
1563                         }
1564 
1565                     case s_chunk_parameters:
1566                         {
1567                             assert(_flags & HTTPParserFlags.F_CHUNKED);
1568                             /* just ignore this shit. TODO check for overflow */
1569                             if (ch == CR)
1570                             {
1571                                 _state = s_chunk_size_almost_done;
1572                                 break;
1573                             }
1574                         }
1575                         break;
1576 
1577                     case s_chunk_size_almost_done:
1578                         {
1579                             assert(_flags & HTTPParserFlags.F_CHUNKED);
1580                             STRICT_CHECK(ch != LF);
1581 
1582                             _nread = 0;
1583 
1584                             if (_contentLength == 0)
1585                             {
1586                                 _flags |= HTTPParserFlags.F_TRAILING;
1587                                 _state = s_header_field_start;
1588                             }
1589                             else
1590                             {
1591                                 _state = s_chunk_data;
1592                             }
1593                             mixin(CALLBACK_NOTIFY("ChunkHeader"));
1594                         }
1595                         break;
1596                     case s_chunk_data:
1597                         {
1598                             ulong to_read = _contentLength < cast(ulong)(maxP - p) ? _contentLength
1599                                 : cast(ulong)(maxP - p);
1600 
1601                             assert(_flags & HTTPParserFlags.F_CHUNKED);
1602                             assert(_contentLength != 0 && _contentLength != ULLONG_MAX);
1603 
1604                             /* See the explanation in s_body_identity for why the content
1605 					 * length and data pointers are managed this way.
1606 					 */
1607                             //MARK(body);
1608                             if (mBodyMark == size_t.max)
1609                                 mBodyMark = p;
1610                             _contentLength -= to_read;
1611                             p += to_read - 1;
1612 
1613                             if (_contentLength == 0)
1614                                 _state = HTTPParserState.s_chunk_data_almost_done;
1615                         }
1616                         break;
1617                     case s_chunk_data_almost_done:
1618                         assert(_flags & HTTPParserFlags.F_CHUNKED);
1619                         assert(_contentLength == 0);
1620                         STRICT_CHECK(ch != CR);
1621                         _state = s_chunk_data_done;
1622                         mixin(CALLBACK_DATA("Body"));
1623                         break;
1624 
1625                     case HTTPParserState.s_chunk_data_done:
1626                         assert(_flags & HTTPParserFlags.F_CHUNKED);
1627                         STRICT_CHECK(ch != LF);
1628                         _nread = 0;
1629                         _state = HTTPParserState.s_chunk_size_start;
1630                         mixin(CALLBACK_NOTIFY("ChunkComplete"));
1631                         break;
1632 
1633                     default:
1634                         throw new Http1xParserExcetion(HPE_INVALID_INTERNAL_STATE);
1635                     }
1636                     break;
1637                 }
1638             }
1639 
1640         assert(((mHeaderFieldMark != size_t.max ? 1
1641                 : 0) + (mHeaderValueMark != size_t.max ? 1
1642                 : 0) + (mUrlMark != size_t.max ? 1 : 0) + (mBodyMark != size_t.max
1643                 ? 1 : 0) + (mStatusMark != size_t.max ? 1 : 0)) <= 1);
1644 
1645         mixin(CALLBACK_DATA_NOADVANCE("HeaderField")); //最后没找到
1646         mixin(CALLBACK_DATA_NOADVANCE("HeaderValue"));
1647         mixin(CALLBACK_DATA_NOADVANCE("Url"));
1648         mixin(CALLBACK_DATA_NOADVANCE("Body"));
1649         mixin(CALLBACK_DATA_NOADVANCE("Status"));
1650 
1651         return data.length;
1652     }
1653 
1654 protected:
1655     pragma(inline, true) @property type(HTTPType ty)
1656     {
1657         _type = ty;
1658     }
1659 
1660     pragma(inline) bool httpMessageNeedsEof()
1661     {
1662         if (type == HTTPType.REQUEST)
1663             return false;
1664 
1665         /* See RFC 2616 section 4.4 */
1666         if (_statusCode / 100 == 1 || /* 1xx e.g. Continue */
1667                 _statusCode == 204 || /* No Content */
1668                 _statusCode == 304
1669                 || /* Not Modified */
1670                 _flags & HTTPParserFlags.F_SKIPBODY)
1671             return false; /* response to a HEAD request */
1672 
1673         if ((_flags & HTTPParserFlags.F_CHUNKED) || _contentLength != ULLONG_MAX)
1674             return false;
1675         return true;
1676     }
1677 
1678     pragma(inline) bool httpShouldKeepAlive()
1679     {
1680         if (_httpMajor > 0 && _httpMinor > 0)
1681         {
1682             /* HTTP/1.1 */
1683             if (_flags & HTTPParserFlags.F_CONNECTION_CLOSE)
1684                 return false;
1685         }
1686         else
1687         {
1688             /* HTTP/1.0 or earlier */
1689             if (!(_flags & HTTPParserFlags.F_CONNECTION_KEEP_ALIVE))
1690                 return false;
1691         }
1692         return !httpMessageNeedsEof();
1693     }
1694 
1695 protected:
1696     CallBackNotify _onMessageBegin;
1697 
1698     CallBackNotify _onHeadersComplete;
1699 
1700     CallBackNotify _onMessageComplete;
1701 
1702     CallBackNotify _onChunkHeader;
1703 
1704     CallBackNotify _onChunkComplete;
1705 
1706     CallBackData _onUrl;
1707 
1708     CallBackData _onStatus;
1709 
1710     CallBackData _onHeaderField;
1711 
1712     CallBackData _onHeaderValue;
1713 
1714     CallBackData _onBody;
1715 
1716 private:
1717     HTTPType _type = HTTPType.BOTH;
1718     HTTPParserFlags _flags = HTTPParserFlags.F_ZERO;
1719     HTTPParserState _state = HTTPParserState.s_start_req_or_res;
1720     HTTPParserHeaderstates _headerState;
1721     uint _index;
1722     uint _lenientHttpHeaders;
1723     uint _nread;
1724     ulong _contentLength;
1725     ushort _httpMajor;
1726     ushort _httpMinor;
1727     uint _statusCode; /* responses only */
1728     HTTPMethod _method; /* requests only */
1729     HTTPParserErrno _httpErrno = HTTPParserErrno.HPE_OK;
1730     /* 1 = Upgrade header was present and the parser has exited because of that.
1731 	 * 0 = No upgrade header present.
1732 	 * Should be checked when http_parser_execute() returns in addition to
1733 	 * error checking.
1734 	 */
1735     bool _upgrade;
1736 
1737     bool _isHandle = false;
1738 
1739     bool _skipBody = false;
1740 
1741     ubyte _keepAlive = 0x00;
1742 
1743     uint _maxHeaderSize = 4096;
1744 }
1745 
1746 
1747 
1748 unittest
1749 {
1750     import std.stdio;
1751     import std.functional;
1752     import yu.exception;
1753 
1754     writeln("\n\n\n");
1755 
1756     void on_message_begin(ref HTTP1xParser)
1757     {
1758         writeln("_onMessageBegin");
1759         writeln(" ");
1760     }
1761 
1762     void on_url(ref HTTP1xParser par, ubyte[] data, bool adv)
1763     {
1764         writeln("_onUrl, is NOADVANCE = ", adv);
1765         writeln("\" ", cast(string) data, " \"");
1766         writeln("HTTPMethod is = ", par.methodString);
1767         writeln(" ");
1768     }
1769 
1770     void on_status(ref HTTP1xParser par, ubyte[] data, bool adv)
1771     {
1772         writeln("_onStatus, is NOADVANCE = ", adv);
1773         writeln("\" ", cast(string) data, " \"");
1774         writeln(" ");
1775     }
1776 
1777     void on_header_field(ref HTTP1xParser par, ubyte[] data, bool adv)
1778     {
1779         static bool frist = true;
1780         writeln("_onHeaderField, is NOADVANCE = ", adv);
1781         writeln("len = ", data.length);
1782         writeln("\" ", cast(string) data, " \"");
1783         if (frist)
1784         {
1785             writeln("\t _httpMajor", par.major);
1786             writeln("\t _httpMinor", par.minor);
1787             frist = false;
1788         }
1789         writeln(" ");
1790     }
1791 
1792     void on_header_value(ref HTTP1xParser par, ubyte[] data, bool adv)
1793     {
1794         writeln("_onHeaderValue, is NOADVANCE = ", adv);
1795         writeln("\" ", cast(string) data, " \"");
1796         writeln(" ");
1797     }
1798 
1799     void on_headers_complete(ref HTTP1xParser par)
1800     {
1801         writeln("_onHeadersComplete");
1802         writeln(" ");
1803     }
1804 
1805     void on_body(ref HTTP1xParser par, ubyte[] data, bool adv)
1806     {
1807         writeln("_onBody, is NOADVANCE = ", adv);
1808         writeln("\" ", cast(string) data, " \"");
1809         writeln(" ");
1810     }
1811 
1812     void on_message_complete(ref HTTP1xParser par)
1813     {
1814         writeln("_onMessageComplete");
1815         writeln(" ");
1816     }
1817 
1818     void on_chunk_header(ref HTTP1xParser par)
1819     {
1820         writeln("_onChunkHeader");
1821         writeln(" ");
1822     }
1823 
1824     void on_chunk_complete(ref HTTP1xParser par)
1825     {
1826         writeln("_onChunkComplete");
1827         writeln(" ");
1828     }
1829 
1830     string data = "GET /test HTTP/1.1\r\nUser-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\nHost:0.0.0.0=5000\r\nAccept: */*\r\n\r\n";
1831     HTTP1xParser par = HTTP1xParser();
1832     par.onMessageBegin = toDelegate(&on_message_begin);
1833     par.onMessageComplete = toDelegate(&on_message_complete);
1834     par.onUrl = toDelegate(&on_url);
1835     par.onStatus = toDelegate(&on_status);
1836     par.onHeaderField = toDelegate(&on_header_field);
1837     par.onHeaderValue = toDelegate(&on_header_value);
1838     par.onChunkHeader = toDelegate(&on_chunk_header);
1839     par.onChunkComplete = toDelegate(&on_chunk_complete);
1840     par.onBody = toDelegate(&on_body);
1841 
1842     showException(yuCathException(par.httpParserExecute(cast(ubyte[]) data)));
1843 
1844     par.rest(HTTPType.BOTH);
1845     data = "POST /post_chunked_all_your_base HTTP/1.1\r\nHost:0.0.0.0=5000\r\nTransfer-Encoding:chunked\r\n\r\n5\r\nhello\r\n";
1846 
1847     auto data2 = "0\r\n\r\n";
1848 
1849     showException(yuCathException(par.httpParserExecute(cast(ubyte[]) data)));
1850     writeln("data 1 is over!");
1851     showException(yuCathException(par.httpParserExecute(cast(ubyte[]) data2)));
1852 }