1 /* 2 * Collie - An asynchronous event-driven network framework using Dlang development 3 * 4 * Copyright (C) 2015-2016 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: putao's Dlang team 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 module collie.codec.http.parser; 12 13 public import collie.codec.http.parser.parsertype; 14 15 /** ubyte[] 为传过去字段里的位置引用,没有数据拷贝,自己使用的时候注意拷贝数据, 16 bool 此段数据是否完结,可能只是数据的一部分。 17 */ 18 alias CallBackData = void delegate(ref HTTPParser, ubyte[], bool); 19 alias CallBackNotify = void delegate(ref HTTPParser); 20 21 struct HTTPParser 22 { 23 this(HTTPParserType ty, uint maxHeaderSize = 4096) 24 { 25 rest(ty, maxHeaderSize); 26 } 27 28 pragma(inline,true) 29 @property type() 30 { 31 return _type; 32 } 33 34 pragma(inline,true) 35 @property isUpgrade() 36 { 37 return _upgrade; 38 } 39 40 pragma(inline,true) 41 @property contentLength() 42 { 43 return _contentLength; 44 } 45 46 pragma(inline,true) 47 @property isChunked() 48 { 49 return (_flags & HTTPParserFlags.F_CHUNKED) == 0 ? false : true; 50 } 51 //@property status() {return _statusCode;} 52 pragma(inline,true) 53 @property error() 54 { 55 return _httpErrno; 56 } 57 58 pragma(inline,true) 59 @property errorString() 60 { 61 return error_string[_httpErrno]; 62 } 63 64 pragma(inline,true) 65 @property methodCode() 66 { 67 return _method; 68 } 69 70 pragma(inline,true) 71 @property methodString() 72 { 73 return method_strings[_method]; 74 } 75 76 pragma(inline,true) 77 @property major() 78 { 79 return _httpMajor; 80 } 81 82 //版本号首位 83 pragma(inline,true) 84 @property minor() 85 { 86 return _httpMinor; 87 } 88 89 //版本号末尾 90 pragma(inline,true) 91 @property handleIng() 92 { 93 return _isHandle; 94 } 95 96 pragma(inline) 97 @property handleIng(bool handle) 98 { 99 _isHandle = handle; 100 } 101 102 pragma(inline,true) 103 @property skipBody() 104 { 105 return _skipBody; 106 } 107 108 pragma(inline) 109 @property skipBody(bool skip) 110 { 111 return _skipBody = skip; 112 } 113 114 pragma(inline,true) 115 @property keepalive() 116 { 117 return _keepAlive; 118 } 119 120 /** 回调函数指定 */ 121 pragma(inline) 122 @property onMessageBegin(CallBackNotify cback) 123 { 124 _onMessageBegin = cback; 125 } 126 127 pragma(inline) 128 @property onMessageComplete(CallBackNotify cback) 129 { 130 _onMessageComplete = cback; 131 } 132 133 pragma(inline) 134 @property onHeaderComplete(CallBackNotify cback) 135 { 136 _onHeadersComplete = cback; 137 } 138 139 pragma(inline) 140 @property onChunkHeader(CallBackNotify cback) 141 { 142 _onChunkHeader = cback; 143 } 144 145 pragma(inline) 146 @property onChunkComplete(CallBackNotify cback) 147 { 148 _onChunkComplete = cback; 149 } 150 151 pragma(inline) 152 @property onUrl(CallBackData cback) 153 { 154 _onUrl = cback; 155 } 156 157 pragma(inline) 158 @property onStatus(CallBackData cback) 159 { 160 _onStatus = cback; 161 } 162 163 pragma(inline) 164 @property onHeaderField(CallBackData cback) 165 { 166 _onHeaderField = cback; 167 } 168 169 pragma(inline) 170 @property onHeaderValue(CallBackData cback) 171 { 172 _onHeaderValue = cback; 173 } 174 175 pragma(inline) 176 @property onBody(CallBackData cback) 177 { 178 _onBody = cback; 179 } 180 181 pragma(inline) 182 void rest(HTTPParserType ty, uint maxHeaderSize = 4096) 183 { 184 type = ty; 185 _maxHeaderSize = maxHeaderSize; 186 _state = ( 187 type == HTTPParserType.HTTP_REQUEST ? HTTPParserState.s_start_req : ( 188 type == HTTPParserType.HTTP_RESPONSE ? HTTPParserState.s_start_res 189 : HTTPParserState.s_start_req_or_res)); 190 _httpErrno = HTTPParserErrno.HPE_OK; 191 _flags = HTTPParserFlags.F_ZERO; 192 _isHandle = false; 193 _skipBody = false; 194 _keepAlive = 0x00; 195 } 196 197 protected: 198 CallBackNotify _onMessageBegin; 199 200 CallBackNotify _onHeadersComplete; 201 202 CallBackNotify _onMessageComplete; 203 204 CallBackNotify _onChunkHeader; 205 206 CallBackNotify _onChunkComplete; 207 208 CallBackData _onUrl; 209 210 CallBackData _onStatus; 211 212 CallBackData _onHeaderField; 213 214 CallBackData _onHeaderValue; 215 216 CallBackData _onBody; 217 218 public: 219 220 pragma(inline) 221 bool bodyIsFinal() 222 { 223 return _state == HTTPParserState.s_message_done; 224 } 225 226 ulong httpParserExecute(ubyte[] data) 227 { 228 handleIng = true; 229 scope (exit) 230 handleIng = false; 231 ubyte c, ch; 232 byte unhexVal; 233 size_t mHeaderFieldMark = size_t.max; 234 size_t mHeaderValueMark = size_t.max; 235 size_t mUrlMark = size_t.max; 236 size_t mBodyMark = size_t.max; 237 size_t mStatusMark = size_t.max; 238 size_t maxP = cast(long) data.length; 239 size_t p = 0; 240 if (_httpErrno != HTTPParserErrno.HPE_OK) 241 { 242 return 0; 243 } 244 if (data.length == 0) 245 { 246 switch (_state) 247 { 248 case HTTPParserState.s_body_identity_eof: 249 /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if 250 * we got paused. 251 */ 252 mixin( 253 CALLBACK_NOTIFY_NOADVANCE("MessageComplete")); 254 return 0; 255 256 case HTTPParserState.s_dead: 257 case HTTPParserState.s_start_req_or_res: 258 case HTTPParserState.s_start_res: 259 case HTTPParserState.s_start_req: 260 return 0; 261 262 default: 263 //_httpErrno = HTTPParserErrno.HPE_INVALID_EOF_STATE); 264 _httpErrno = HTTPParserErrno.HPE_INVALID_EOF_STATE; 265 return 1; 266 } 267 } 268 269 if (_state == HTTPParserState.s_header_field) 270 mHeaderFieldMark = 0; 271 if (_state == HTTPParserState.s_header_value) 272 mHeaderValueMark = 0; 273 switch (_state) 274 { 275 case HTTPParserState.s_req_path: 276 case HTTPParserState.s_req_schema: 277 case HTTPParserState.s_req_schema_slash: 278 case HTTPParserState.s_req_schema_slash_slash: 279 case HTTPParserState.s_req_server_start: 280 case HTTPParserState.s_req_server: 281 case HTTPParserState.s_req_server_with_at: 282 case HTTPParserState.s_req_query_string_start: 283 case HTTPParserState.s_req_query_string: 284 case HTTPParserState.s_req_fragment_start: 285 case HTTPParserState.s_req_fragment: 286 mUrlMark = 0; 287 break; 288 case HTTPParserState.s_res_status: 289 mStatusMark = 0; 290 break; 291 default: 292 break; 293 } 294 for (; p < maxP; ++p) 295 { 296 ch = data[p]; 297 if (_state <= HTTPParserState.s_headers_done) 298 { 299 _nread += 1; 300 if (_nread > _maxHeaderSize) 301 { 302 _httpErrno = HTTPParserErrno.HPE_HEADER_OVERFLOW; 303 goto error; 304 } 305 } 306 307 reexecute: 308 switch (_state) 309 { 310 case HTTPParserState.s_dead: 311 /* this _state is used after a 'Connection: close' message 312 * the parser will error out if it reads another message 313 */ 314 if (ch == CR || ch == LF) 315 break; 316 317 _httpErrno = HTTPParserErrno.HPE_CLOSED_CONNECTION; 318 goto error; 319 case HTTPParserState.s_start_req_or_res: 320 { 321 if (ch == CR || ch == LF) 322 break; 323 _flags = HTTPParserFlags.F_ZERO; 324 _contentLength = ulong.max; 325 326 if (ch == 'H') 327 { 328 _state = HTTPParserState.s_res_or_resp_H; 329 330 mixin(CALLBACK_NOTIFY("MessageBegin")); // 开始处理 331 332 } 333 else 334 { 335 type = HTTPParserType.HTTP_REQUEST; 336 _state = HTTPParserState.s_start_req; 337 goto reexecute; 338 } 339 340 break; 341 } 342 case HTTPParserState.s_res_or_resp_H: 343 if (ch == 'T') 344 { 345 type = HTTPParserType.HTTP_RESPONSE; 346 _state = HTTPParserState.s_res_HT; 347 } 348 else 349 { 350 if (ch != 'E') 351 { 352 _httpErrno = HTTPParserErrno.HPE_INVALID_CONSTANT; 353 goto error; 354 } 355 356 type = HTTPParserType.HTTP_REQUEST; 357 _method = HTTPMethod.HTTP_HEAD; 358 _index = 2; 359 _state = HTTPParserState.s_req_method; 360 } 361 break; 362 363 case HTTPParserState.s_start_res: 364 { 365 _flags = HTTPParserFlags.F_ZERO; 366 _contentLength = ulong.max; 367 368 switch (ch) 369 { 370 case 'H': 371 _state = HTTPParserState.s_res_H; 372 break; 373 374 case CR: 375 case LF: 376 break; 377 378 default: 379 _httpErrno = HTTPParserErrno.HPE_INVALID_CONSTANT; 380 goto error; 381 } 382 mixin(CALLBACK_NOTIFY("MessageBegin")); 383 break; 384 } 385 case HTTPParserState.s_res_H: 386 mixin(STRICT_CHECK("ch != 'T'")); 387 _state = HTTPParserState.s_res_HT; 388 break; 389 390 case HTTPParserState.s_res_HT: 391 //STRICT_CHECK(ch != 'T'); 392 mixin(STRICT_CHECK("ch != 'T'")); 393 _state = HTTPParserState.s_res_HTT; 394 break; 395 396 case HTTPParserState.s_res_HTT: 397 //STRICT_CHECK(ch != 'P'); 398 mixin(STRICT_CHECK("ch != 'P'")); 399 _state = HTTPParserState.s_res_HTTP; 400 break; 401 402 case HTTPParserState.s_res_HTTP: 403 //STRICT_CHECK(ch != '/'); 404 mixin(STRICT_CHECK("ch != '/'")); 405 _state = HTTPParserState.s_res_first_http_major; 406 break; 407 408 case HTTPParserState.s_res_first_http_major: 409 if (ch < '0' || ch > '9') 410 { 411 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 412 goto error; 413 } 414 415 _httpMajor = cast(ushort)(ch - '0'); 416 _state = HTTPParserState.s_res_http_major; 417 break; 418 419 /* major HTTP version or dot */ 420 case HTTPParserState.s_res_http_major: 421 { 422 if (ch == '.') 423 { 424 _state = HTTPParserState.s_res_first_http_minor; 425 break; 426 } 427 428 if (!mixin(IS_NUM("ch"))) 429 { 430 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 431 goto error; 432 } 433 434 _httpMajor *= 10; 435 _httpMajor += ch - '0'; 436 437 if (_httpMajor > 999) 438 { 439 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 440 goto error; 441 } 442 443 break; 444 } 445 446 /* first digit of minor HTTP version */ 447 case HTTPParserState.s_res_first_http_minor: 448 if (!mixin(IS_NUM("ch"))) 449 { 450 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 451 goto error; 452 } 453 454 _httpMinor = cast(ushort)(ch - '0'); 455 _state = HTTPParserState.s_res_http_minor; 456 break; 457 458 /* minor HTTP version or end of request line */ 459 case HTTPParserState.s_res_http_minor: 460 { 461 if (ch == ' ') 462 { 463 _state = HTTPParserState.s_res_first_status_code; 464 break; 465 } 466 467 if (!mixin(IS_NUM("ch"))) 468 { 469 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 470 goto error; 471 } 472 473 _httpMinor *= 10; 474 _httpMinor += ch - '0'; 475 476 if (_httpMinor > 999) 477 { 478 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 479 goto error; 480 } 481 482 break; 483 } 484 485 case HTTPParserState.s_res_first_status_code: 486 { 487 if (!mixin(IS_NUM("ch"))) 488 { 489 if (ch == ' ') 490 { 491 break; 492 } 493 494 _httpErrno = HTTPParserErrno.HPE_INVALID_STATUS; 495 goto error; 496 } 497 _statusCode = ch - '0'; 498 _state = HTTPParserState.s_res_status_code; 499 break; 500 } 501 502 case HTTPParserState.s_res_status_code: 503 { 504 if (!mixin(IS_NUM("ch"))) 505 { 506 switch (ch) 507 { 508 case ' ': 509 _state = HTTPParserState.s_res_status_start; 510 break; 511 case CR: 512 _state = HTTPParserState.s_res_line_almost_done; 513 break; 514 case LF: 515 _state = HTTPParserState.s_header_field_start; 516 break; 517 default: 518 _httpErrno = HTTPParserErrno.HPE_INVALID_STATUS; 519 goto error; 520 } 521 break; 522 } 523 524 _statusCode *= 10; 525 _statusCode += ch - '0'; 526 527 if (_statusCode > 999) 528 { 529 _httpErrno = HTTPParserErrno.HPE_INVALID_STATUS; 530 goto error; 531 } 532 533 break; 534 } 535 536 case HTTPParserState.s_res_status_start: 537 { 538 if (ch == CR) 539 { 540 _state = HTTPParserState.s_res_line_almost_done; 541 break; 542 } 543 544 if (ch == LF) 545 { 546 _state = HTTPParserState.s_header_field_start; 547 break; 548 } 549 550 //MARK(status); 551 if (mStatusMark == size_t.max) 552 { 553 mStatusMark = p; 554 } 555 _state = HTTPParserState.s_res_status; 556 _index = 0; 557 break; 558 } 559 560 case HTTPParserState.s_res_status: 561 if (ch == CR) 562 { 563 _state = HTTPParserState.s_res_line_almost_done; 564 mixin(CALLBACK_DATA("Status")); 565 break; 566 } 567 568 if (ch == LF) 569 { 570 _state = HTTPParserState.s_header_field_start; 571 //statusCall(); 572 mixin(CALLBACK_DATA("Status")); 573 break; 574 } 575 576 break; 577 578 case HTTPParserState.s_res_line_almost_done: 579 mixin(STRICT_CHECK("ch != LF")); 580 _state = HTTPParserState.s_header_field_start; 581 break; 582 583 case HTTPParserState.s_start_req: 584 { 585 if (ch == CR || ch == LF) 586 break; 587 _flags = HTTPParserFlags.F_ZERO; 588 _contentLength = ulong.max; 589 590 if (!mixin(IS_ALPHA("ch"))) 591 { 592 //error("err0"); 593 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 594 goto error; 595 } 596 597 _index = 1; 598 switch (ch) 599 { 600 case 'A': 601 _method = HTTPMethod.HTTP_ACL; 602 break; 603 case 'B': 604 _method = HTTPMethod.HTTP_BIND; 605 break; 606 case 'C': 607 _method = HTTPMethod.HTTP_CONNECT; /* or COPY, CHECKOUT */ break; 608 case 'D': 609 _method = HTTPMethod.HTTP_DELETE; 610 break; 611 case 'G': 612 _method = HTTPMethod.HTTP_GET; 613 break; 614 case 'H': 615 _method = HTTPMethod.HTTP_HEAD; 616 break; 617 case 'L': 618 _method = HTTPMethod.HTTP_LOCK; /* or LINK */ break; 619 case 'M': 620 _method = HTTPMethod.HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; 621 case 'N': 622 _method = HTTPMethod.HTTP_NOTIFY; 623 break; 624 case 'O': 625 _method = HTTPMethod.HTTP_OPTIONS; 626 break; 627 case 'P': 628 _method = HTTPMethod.HTTP_POST; 629 /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ 630 break; 631 case 'R': 632 _method = HTTPMethod.HTTP_REPORT; /* or REBIND */ break; 633 case 'S': 634 _method = HTTPMethod.HTTP_SUBSCRIBE; /* or SEARCH */ break; 635 case 'T': 636 _method = HTTPMethod.HTTP_TRACE; 637 break; 638 case 'U': 639 _method = HTTPMethod.HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break; 640 default: 641 //error("err0"); 642 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 643 goto error; 644 } 645 _state = HTTPParserState.s_req_method; 646 647 mixin(CALLBACK_NOTIFY("MessageBegin")); 648 break; 649 } 650 651 case HTTPParserState.s_req_method: 652 { 653 if (ch == '\0') 654 { 655 //error("err0"); 656 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 657 goto error; 658 } 659 660 string matcher = method_strings[_method]; 661 if (ch == ' ' && matcher.length == _index) 662 { 663 _state = HTTPParserState.s_req_spaces_before_url; 664 } 665 else if (ch == matcher[_index]) 666 { 667 //; /* nada */ 668 } 669 else if (_method == HTTPMethod.HTTP_CONNECT) 670 { 671 if (_index == 1 && ch == 'H') 672 { 673 _method = HTTPMethod.HTTP_CHECKOUT; 674 } 675 else if (_index == 2 && ch == 'P') 676 { 677 _method = HTTPMethod.HTTP_COPY; 678 } 679 else 680 { 681 //error("err0"); 682 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 683 goto error; 684 } 685 } 686 else if (_method == HTTPMethod.HTTP_MKCOL) 687 { 688 if (_index == 1 && ch == 'O') 689 { 690 _method = HTTPMethod.HTTP_MOVE; 691 } 692 else if (_index == 1 && ch == 'E') 693 { 694 _method = HTTPMethod.HTTP_MERGE; 695 } 696 else if (_index == 1 && ch == '-') 697 { 698 _method = HTTPMethod.HTTP_MSEARCH; 699 } 700 else if (_index == 2 && ch == 'A') 701 { 702 _method = HTTPMethod.HTTP_MKACTIVITY; 703 } 704 else if (_index == 3 && ch == 'A') 705 { 706 _method = HTTPMethod.HTTP_MKCALENDAR; 707 } 708 else 709 { 710 //error("err0"); 711 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 712 goto error; 713 } 714 } 715 else if (_method == HTTPMethod.HTTP_SUBSCRIBE) 716 { 717 if (_index == 1 && ch == 'E') 718 { 719 _method = HTTPMethod.HTTP_SEARCH; 720 } 721 else 722 { 723 //error("err0"); 724 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 725 goto error; 726 } 727 } 728 else if (_method == HTTPMethod.HTTP_REPORT) 729 { 730 if (_index == 2 && ch == 'B') 731 { 732 //error("err0"); 733 _method = HTTPMethod.HTTP_REBIND; 734 } 735 else 736 { 737 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 738 goto error; 739 } 740 } 741 else if (_index == 1) 742 { 743 if (_method == HTTPMethod.HTTP_POST) 744 { 745 746 if (ch == 'R') 747 { 748 _method = HTTPMethod.HTTP_PROPFIND; /* or HTTP_PROPPATCH */ 749 } 750 else if (ch == 'U') 751 { 752 _method = HTTPMethod.HTTP_PUT; /* or HTTP_PURGE */ 753 } 754 else if (ch == 'A') 755 { 756 _method = HTTPMethod.HTTP_PATCH; 757 } 758 else 759 { 760 //error("err0"); 761 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 762 goto error; 763 } 764 } 765 else if (_method == HTTPMethod.HTTP_LOCK) 766 { 767 if (ch == 'I') 768 { 769 _method = HTTPMethod.HTTP_LINK; 770 } 771 else 772 { 773 //error("err0"); 774 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 775 goto error; 776 } 777 } 778 } 779 else if (_index == 2) 780 { 781 if (_method == HTTPMethod.HTTP_PUT) 782 { 783 if (ch == 'R') 784 { 785 _method = HTTPMethod.HTTP_PURGE; 786 } 787 else 788 { 789 //error("err0"); 790 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 791 goto error; 792 } 793 } 794 else if (_method == HTTPMethod.HTTP_UNLOCK) 795 { 796 if (ch == 'S') 797 { 798 _method = HTTPMethod.HTTP_UNSUBSCRIBE; 799 } 800 else if (ch == 'B') 801 { 802 _method = HTTPMethod.HTTP_UNBIND; 803 } 804 else 805 { 806 //error("err0"); 807 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 808 goto error; 809 } 810 } 811 else 812 { 813 //error("err0"); 814 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 815 goto error; 816 } 817 } 818 else if (_index == 4 && _method == HTTPMethod.HTTP_PROPFIND && ch == 'P') 819 { 820 _method = HTTPMethod.HTTP_PROPPATCH; 821 } 822 else if (_index == 3 && _method == HTTPMethod.HTTP_UNLOCK && ch == 'I') 823 { 824 _method = HTTPMethod.HTTP_UNLINK; 825 } 826 else 827 { 828 //error("err0"); 829 _httpErrno = HTTPParserErrno.HPE_INVALID_METHOD; 830 goto error; 831 } 832 833 ++_index; 834 break; 835 } 836 837 case HTTPParserState.s_req_spaces_before_url: 838 { 839 if (ch == ' ') 840 break; 841 842 //MARK(url); 843 if (mUrlMark == size_t.max) 844 { 845 mUrlMark = p; 846 } 847 if (_method == HTTPMethod.HTTP_CONNECT) 848 { 849 _state = HTTPParserState.s_req_server_start; 850 } 851 852 _state = parseURLchar(_state, ch); 853 if (_state == HTTPParserState.s_dead) 854 { 855 _httpErrno = HTTPParserErrno.HPE_INVALID_URL; 856 goto error; 857 } 858 859 break; 860 } 861 862 case HTTPParserState.s_req_schema: 863 case HTTPParserState.s_req_schema_slash: 864 case HTTPParserState.s_req_schema_slash_slash: 865 case HTTPParserState.s_req_server_start: 866 { 867 switch (ch) 868 { 869 /* No whitespace allowed here */ 870 case ' ': 871 case CR: 872 case LF: 873 _httpErrno = HTTPParserErrno.HPE_INVALID_URL; 874 goto error; 875 default: 876 _state = parseURLchar(_state, ch); 877 if (_state == HTTPParserState.s_dead) 878 { 879 _httpErrno = HTTPParserErrno.HPE_INVALID_URL; 880 goto error; 881 } 882 } 883 884 break; 885 } 886 887 case HTTPParserState.s_req_server: 888 case HTTPParserState.s_req_server_with_at: 889 case HTTPParserState.s_req_path: 890 case HTTPParserState.s_req_query_string_start: 891 case HTTPParserState.s_req_query_string: 892 case HTTPParserState.s_req_fragment_start: 893 case HTTPParserState.s_req_fragment: 894 { 895 switch (ch) 896 { 897 case ' ': 898 _state = HTTPParserState.s_req_http_start; 899 mixin(CALLBACK_DATA("Url")); 900 break; 901 case CR: 902 case LF: 903 _httpMajor = 0; 904 _httpMinor = 9; 905 _state = (ch == CR) ? HTTPParserState.s_req_line_almost_done 906 : HTTPParserState.s_header_field_start; 907 mixin(CALLBACK_DATA("Url")); 908 break; 909 default: 910 _state = parseURLchar(_state, ch); 911 if (_state == HTTPParserState.s_dead) 912 { 913 _httpErrno = HTTPParserErrno.HPE_INVALID_URL; 914 goto error; 915 } 916 } 917 break; 918 } 919 920 case HTTPParserState.s_req_http_start: 921 switch (ch) 922 { 923 case 'H': 924 _state = HTTPParserState.s_req_http_H; 925 break; 926 case ' ': 927 break; 928 default: 929 _httpErrno = HTTPParserErrno.HPE_INVALID_CONSTANT; 930 goto error; 931 } 932 break; 933 934 case HTTPParserState.s_req_http_H: 935 mixin(STRICT_CHECK("ch != 'T'")); 936 _state = HTTPParserState.s_req_http_HT; 937 break; 938 939 case HTTPParserState.s_req_http_HT: 940 //STRICT_CHECK(ch != 'T'); 941 mixin(STRICT_CHECK("ch != 'T'")); 942 _state = HTTPParserState.s_req_http_HTT; 943 break; 944 945 case HTTPParserState.s_req_http_HTT: 946 //STRICT_CHECK(ch != 'P'); 947 mixin(STRICT_CHECK("ch != 'P'")); 948 _state = HTTPParserState.s_req_http_HTTP; 949 break; 950 951 case HTTPParserState.s_req_http_HTTP: 952 //STRICT_CHECK(ch != '/'); 953 mixin(STRICT_CHECK("ch != '/'")); 954 _state = HTTPParserState.s_req_first_http_major; 955 break; 956 957 /* first digit of major HTTP version */ 958 case HTTPParserState.s_req_first_http_major: 959 if (ch < '1' || ch > '9') 960 { 961 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 962 goto error; 963 } 964 965 _httpMajor = cast(ushort)(ch - '0'); 966 _state = HTTPParserState.s_req_http_major; 967 break; 968 969 /* major HTTP version or dot */ 970 case HTTPParserState.s_req_http_major: 971 { 972 if (ch == '.') 973 { 974 _state = HTTPParserState.s_req_first_http_minor; 975 break; 976 } 977 978 if (!mixin(IS_NUM("ch"))) 979 { 980 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 981 goto error; 982 } 983 984 _httpMajor *= 10; 985 _httpMajor += ch - '0'; 986 987 if (_httpMajor > 999) 988 { 989 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 990 goto error; 991 } 992 993 break; 994 } 995 996 /* first digit of minor HTTP version */ 997 case HTTPParserState.s_req_first_http_minor: 998 if (!mixin(IS_NUM("ch"))) 999 { 1000 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 1001 goto error; 1002 } 1003 1004 _httpMinor = cast(ushort)(ch - '0'); 1005 _state = HTTPParserState.s_req_http_minor; 1006 break; 1007 1008 /* minor HTTP version or end of request line */ 1009 case HTTPParserState.s_req_http_minor: 1010 { 1011 if (ch == CR) 1012 { 1013 _state = HTTPParserState.s_req_line_almost_done; 1014 break; 1015 } 1016 1017 if (ch == LF) 1018 { 1019 _state = HTTPParserState.s_header_field_start; 1020 break; 1021 } 1022 1023 /* XXX allow spaces after digit? */ 1024 1025 if (!mixin(IS_NUM("ch"))) 1026 { 1027 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 1028 goto error; 1029 } 1030 1031 _httpMinor *= 10; 1032 _httpMinor += ch - '0'; 1033 1034 if (_httpMinor > 999) 1035 { 1036 _httpErrno = HTTPParserErrno.HPE_INVALID_VERSION; 1037 goto error; 1038 } 1039 1040 break; 1041 } 1042 1043 /* end of request line */ 1044 case HTTPParserState.s_req_line_almost_done: 1045 { 1046 if (ch != LF) 1047 { 1048 _httpErrno = HTTPParserErrno.HPE_LF_EXPECTED; 1049 goto error; 1050 } 1051 1052 _state = HTTPParserState.s_header_field_start; 1053 break; 1054 } 1055 1056 case HTTPParserState.s_header_field_start: 1057 { 1058 if (ch == CR) 1059 { 1060 _state = HTTPParserState.s_headers_almost_done; 1061 break; 1062 } 1063 1064 if (ch == LF) 1065 { 1066 /* they might be just sending \n instead of \r\n so this would be 1067 * the second \n to denote the end of headers*/ 1068 _state = HTTPParserState.s_headers_almost_done; 1069 //goto reexecute; 1070 goto reexecute; 1071 } 1072 1073 c = tokens[ch]; 1074 1075 if (!c) 1076 { 1077 _httpErrno = HTTPParserErrno.HPE_INVALID_HEADER_TOKEN; 1078 goto error; 1079 } 1080 1081 if (mHeaderFieldMark == size_t.max) 1082 { 1083 mHeaderFieldMark = p; 1084 } 1085 1086 _index = 0; 1087 _state = HTTPParserState.s_header_field; 1088 1089 switch (c) 1090 { 1091 case 'c': 1092 _headerState = HTTPParserHeaderstates.h_C; 1093 break; 1094 1095 case 'p': 1096 _headerState = HTTPParserHeaderstates.h_matching_proxy_connection; 1097 break; 1098 1099 case 't': 1100 _headerState = HTTPParserHeaderstates.h_matching_transfer_encoding; 1101 break; 1102 1103 case 'u': 1104 _headerState = HTTPParserHeaderstates.h_matching_upgrade; 1105 break; 1106 1107 default: 1108 _headerState = HTTPParserHeaderstates.h_general; 1109 break; 1110 } 1111 break; 1112 } 1113 1114 case HTTPParserState.s_header_field: 1115 { 1116 const long start = p; 1117 for (; p < maxP; p++) 1118 { 1119 ch = data[p]; 1120 c = tokens[ch]; 1121 1122 if (!c) 1123 break; 1124 1125 switch ( _headerState) 1126 { 1127 case HTTPParserHeaderstates.h_general: 1128 break; 1129 1130 case HTTPParserHeaderstates.h_C: 1131 _index++; 1132 _headerState = ( 1133 c == 'o' ? HTTPParserHeaderstates.h_CO 1134 : HTTPParserHeaderstates.h_general); 1135 break; 1136 1137 case HTTPParserHeaderstates.h_CO: 1138 _index++; 1139 _headerState = ( 1140 c == 'n' ? HTTPParserHeaderstates.h_CON 1141 : HTTPParserHeaderstates.h_general); 1142 break; 1143 1144 case HTTPParserHeaderstates.h_CON: 1145 _index++; 1146 switch (c) 1147 { 1148 case 'n': 1149 _headerState = HTTPParserHeaderstates.h_matching_connection; 1150 break; 1151 case 't': 1152 _headerState = HTTPParserHeaderstates.h_matching_content_length; 1153 break; 1154 default: 1155 _headerState = HTTPParserHeaderstates.h_general; 1156 break; 1157 } 1158 break; 1159 1160 /* connection */ 1161 1162 case HTTPParserHeaderstates.h_matching_connection: 1163 _index++; 1164 if (_index > CONNECTION.length || c != CONNECTION[_index]) 1165 { 1166 _headerState = HTTPParserHeaderstates.h_general; 1167 } 1168 else if (_index == CONNECTION.length - 1) 1169 { 1170 _headerState = HTTPParserHeaderstates.h_connection; 1171 } 1172 break; 1173 1174 /* proxy-connection */ 1175 1176 case HTTPParserHeaderstates.h_matching_proxy_connection: 1177 _index++; 1178 if (_index > PROXY_CONNECTION.length || c != PROXY_CONNECTION[_index]) 1179 { 1180 _headerState = HTTPParserHeaderstates.h_general; 1181 } 1182 else if (_index == PROXY_CONNECTION.length) 1183 { 1184 _headerState = HTTPParserHeaderstates.h_connection; 1185 } 1186 break; 1187 1188 /* content-length */ 1189 1190 case HTTPParserHeaderstates.h_matching_content_length: 1191 _index++; 1192 if (_index > CONTENT_LENGTH.length || c != CONTENT_LENGTH[_index]) 1193 { 1194 _headerState = HTTPParserHeaderstates.h_general; 1195 } 1196 else if (_index == CONTENT_LENGTH.length - 1) 1197 { 1198 if (_flags & HTTPParserFlags.F_CONTENTLENGTH) 1199 { 1200 _httpErrno = HTTPParserErrno.HPE_UNEXPECTED_CONTENT_LENGTH; 1201 goto error; 1202 } 1203 _headerState = HTTPParserHeaderstates.h_content_length; 1204 _flags |= HTTPParserFlags.F_CONTENTLENGTH; 1205 } 1206 break; 1207 1208 /* transfer-encoding */ 1209 1210 case HTTPParserHeaderstates.h_matching_transfer_encoding: 1211 _index++; 1212 if (_index > TRANSFER_ENCODING.length || c != TRANSFER_ENCODING[_index]) 1213 { 1214 _headerState = HTTPParserHeaderstates.h_general; 1215 } 1216 else if (_index == TRANSFER_ENCODING.length - 1) 1217 { 1218 _headerState = HTTPParserHeaderstates.h_transfer_encoding; 1219 } 1220 break; 1221 1222 /* upgrade */ 1223 1224 case HTTPParserHeaderstates.h_matching_upgrade: 1225 _index++; 1226 if (_index > UPGRADE.length || c != UPGRADE[_index]) 1227 { 1228 _headerState = HTTPParserHeaderstates.h_general; 1229 } 1230 else if (_index == UPGRADE.length - 1) 1231 { 1232 _headerState = HTTPParserHeaderstates.h_upgrade; 1233 } 1234 break; 1235 1236 case HTTPParserHeaderstates.h_connection: 1237 case HTTPParserHeaderstates.h_content_length: 1238 case HTTPParserHeaderstates.h_transfer_encoding: 1239 case HTTPParserHeaderstates.h_upgrade: 1240 if ( 1241 ch != ' ') 1242 _headerState = HTTPParserHeaderstates.h_general; 1243 break; 1244 1245 default: 1246 assert(false, "Unknown _headerState"); 1247 // break; 1248 } 1249 } 1250 1251 //COUNT_HEADER_SIZE(p - start); 1252 _nread += (p - start); 1253 if (_nread > _maxHeaderSize) 1254 { 1255 _httpErrno = HTTPParserErrno.HPE_HEADER_OVERFLOW; 1256 goto error; 1257 } 1258 1259 if (p == maxP) 1260 { 1261 --p; 1262 break; 1263 } 1264 1265 if (ch == ':') 1266 { 1267 _state = HTTPParserState.s_header_value_discard_ws; 1268 mixin(CALLBACK_DATA("HeaderField")); 1269 break; 1270 } 1271 1272 _httpErrno = HTTPParserErrno.HPE_INVALID_HEADER_TOKEN; 1273 goto error; 1274 } 1275 1276 case HTTPParserState.s_header_value_discard_ws: 1277 if (ch == ' ' || ch == '\t') 1278 break; 1279 1280 if (ch == CR) 1281 { 1282 _state = HTTPParserState.s_header_value_discard_ws_almost_done; 1283 break; 1284 } 1285 1286 if (ch == LF) 1287 { 1288 _state = HTTPParserState.s_header_value_discard_lws; 1289 break; 1290 } 1291 goto case; 1292 /* FALLTHROUGH */ 1293 1294 case HTTPParserState.s_header_value_start: 1295 { 1296 //MARK(header_value); 1297 if (mHeaderValueMark == size_t.max) 1298 { 1299 mHeaderValueMark = p; 1300 } 1301 _state = HTTPParserState.s_header_value; 1302 _index = 0; 1303 1304 c = ch | 0x20; //LOWER(ch); 1305 1306 switch ( _headerState) 1307 { 1308 case HTTPParserHeaderstates.h_upgrade: 1309 _flags |= HTTPParserFlags.F_UPGRADE; 1310 _headerState = HTTPParserHeaderstates.h_general; 1311 break; 1312 1313 case HTTPParserHeaderstates.h_transfer_encoding: 1314 /* looking for 'Transfer-Encoding: chunked' */ 1315 if ('c' == c) 1316 { 1317 _headerState = HTTPParserHeaderstates 1318 .h_matching_transfer_encoding_chunked; 1319 } 1320 else 1321 { 1322 _headerState = HTTPParserHeaderstates.h_general; 1323 } 1324 break; 1325 1326 case HTTPParserHeaderstates.h_content_length: 1327 if (!mixin(IS_NUM("ch"))) 1328 { 1329 _httpErrno = HTTPParserErrno.HPE_INVALID_CONTENT_LENGTH; 1330 goto error; 1331 } 1332 1333 _contentLength = ch - '0'; 1334 break; 1335 1336 case HTTPParserHeaderstates.h_connection: 1337 /* looking for 'Connection: keep-alive' */ 1338 if (c == 'k') 1339 { 1340 _headerState = HTTPParserHeaderstates.h_matching_connection_keep_alive; 1341 _keepAlive = 0x01; 1342 /* looking for 'Connection: close' */ 1343 } 1344 else if (c == 'c') 1345 { 1346 _headerState = HTTPParserHeaderstates.h_matching_connection_close; 1347 _keepAlive = 0x02; 1348 } 1349 else if (c == 'u') 1350 { 1351 _headerState = HTTPParserHeaderstates.h_matching_connection_upgrade; 1352 _keepAlive = 0x03; 1353 } 1354 else 1355 { 1356 _headerState = HTTPParserHeaderstates.h_matching_connection_token; 1357 _keepAlive = 0x04; 1358 } 1359 break; 1360 1361 /* Multi-value `Connection` header */ 1362 case HTTPParserHeaderstates.h_matching_connection_token_start: 1363 break; 1364 1365 default: 1366 _headerState = HTTPParserHeaderstates.h_general; 1367 break; 1368 } 1369 break; 1370 } 1371 1372 case HTTPParserState.s_header_value: //BUG,找不到结束 1373 { 1374 const long start = p; 1375 auto h_state = _headerState; 1376 for (; p < maxP; p++) 1377 { 1378 ch = data[p]; 1379 if (ch == CR) 1380 { 1381 _state = HTTPParserState.s_header_almost_done; 1382 _headerState = h_state; 1383 mixin(CALLBACK_DATA("HeaderValue")); 1384 break; 1385 } 1386 1387 if (ch == LF) 1388 { 1389 _state = HTTPParserState.s_header_almost_done; 1390 //COUNT_HEADER_SIZE(p - start); 1391 _nread += (p - start); 1392 if (_nread > _maxHeaderSize) 1393 { 1394 _httpErrno = HTTPParserErrno.HPE_HEADER_OVERFLOW; 1395 goto error; 1396 } 1397 _headerState = h_state; 1398 mixin(CALLBACK_DATA_NOADVANCE("HeaderValue")); 1399 goto reexecute; 1400 } 1401 1402 if (!_lenientHttpHeaders && !(ch == CR || ch == LF 1403 || ch == 9 || (ch > 31 && ch != 127))) 1404 { 1405 _httpErrno = HTTPParserErrno.HPE_INVALID_HEADER_TOKEN; 1406 goto error; 1407 } 1408 1409 c = ch | 0x20; //LOWER(ch); 1410 1411 switch (h_state) 1412 { 1413 case HTTPParserHeaderstates.h_general: 1414 { 1415 import std.string; 1416 import core.stdc.string; 1417 1418 size_t limit = maxP - p; 1419 1420 limit = (limit < _maxHeaderSize ? limit : _maxHeaderSize); //MIN(limit, TTPConfig.instance.MaxHeaderSize); 1421 auto str = data[p .. maxP]; 1422 auto tptr = cast(ubyte *)memchr(str.ptr, CR, str.length); 1423 auto p_cr = tptr - str.ptr;//str._indexOf(CR); // memchr(p, CR, limit); 1424 tptr = cast(ubyte *)memchr(str.ptr, LF, str.length); 1425 auto p_lf = tptr - str.ptr ;//str._indexOf(LF); // memchr(p, LF, limit); 1426 ++p_cr; 1427 ++p_lf; 1428 if (p_cr > 0) 1429 { 1430 if (p_lf > 0 && p_cr >= p_lf) 1431 p += p_lf; 1432 else 1433 p += p_cr; 1434 } 1435 else if (p_lf > 0) 1436 { 1437 p += p_lf; 1438 } 1439 else 1440 { 1441 p = maxP; 1442 } 1443 p -= 2; 1444 1445 break; 1446 } 1447 1448 case HTTPParserHeaderstates.h_connection: 1449 case HTTPParserHeaderstates.h_transfer_encoding: 1450 assert(0, 1451 "Shouldn't get here."); 1452 //break; 1453 1454 case HTTPParserHeaderstates.h_content_length: 1455 { 1456 ulong t; 1457 1458 if (ch == ' ') 1459 break; 1460 1461 if (!mixin(IS_NUM("ch"))) 1462 { 1463 _httpErrno = HTTPParserErrno.HPE_INVALID_CONTENT_LENGTH; 1464 _headerState = h_state; 1465 goto error; 1466 } 1467 1468 t = _contentLength; 1469 t *= 10; 1470 t += ch - '0'; 1471 1472 /* Overflow? Test against a conservative limit for simplicity. */ 1473 if ((ulong.max - 10) / 10 < _contentLength) 1474 { 1475 _httpErrno = HTTPParserErrno.HPE_INVALID_CONTENT_LENGTH; 1476 _headerState = h_state; 1477 goto error; 1478 } 1479 1480 _contentLength = t; 1481 break; 1482 } 1483 1484 /* Transfer-Encoding: chunked */ 1485 case HTTPParserHeaderstates.h_matching_transfer_encoding_chunked: 1486 _index++; 1487 if (_index > CHUNKED.length || c != CHUNKED[_index]) 1488 { 1489 h_state = HTTPParserHeaderstates.h_general; 1490 } 1491 else if (_index == CHUNKED.length - 1) 1492 { 1493 h_state = HTTPParserHeaderstates.h_transfer_encoding_chunked; 1494 } 1495 break; 1496 1497 case HTTPParserHeaderstates.h_matching_connection_token_start: 1498 /* looking for 'Connection: keep-alive' */ 1499 if (c == 'k') 1500 { 1501 h_state = HTTPParserHeaderstates.h_matching_connection_keep_alive; 1502 /* looking for 'Connection: close' */ 1503 } 1504 else if (c == 'c') 1505 { 1506 h_state = HTTPParserHeaderstates.h_matching_connection_close; 1507 } 1508 else if (c == 'u') 1509 { 1510 h_state = HTTPParserHeaderstates.h_matching_connection_upgrade; 1511 } 1512 else if (tokens[c]) 1513 { 1514 h_state = HTTPParserHeaderstates.h_matching_connection_token; 1515 } 1516 else if (c == ' ' || c == '\t') 1517 { 1518 /* Skip lws */ 1519 } 1520 else 1521 { 1522 h_state = HTTPParserHeaderstates.h_general; 1523 } 1524 break; 1525 1526 /* looking for 'Connection: keep-alive' */ 1527 case HTTPParserHeaderstates.h_matching_connection_keep_alive: 1528 _index++; 1529 if (_index > KEEP_ALIVE.length || c != KEEP_ALIVE[_index]) 1530 { 1531 h_state = HTTPParserHeaderstates.h_matching_connection_token; 1532 } 1533 else if (_index == KEEP_ALIVE.length - 1) 1534 { 1535 h_state = HTTPParserHeaderstates.h_connection_keep_alive; 1536 } 1537 break; 1538 1539 /* looking for 'Connection: close' */ 1540 case HTTPParserHeaderstates.h_matching_connection_close: 1541 _index++; 1542 if (_index > CLOSE.length || c != CLOSE[_index]) 1543 { 1544 h_state = HTTPParserHeaderstates.h_matching_connection_token; 1545 } 1546 else if (_index == CLOSE.length - 1) 1547 { 1548 h_state = HTTPParserHeaderstates.h_connection_close; 1549 } 1550 break; 1551 1552 /* looking for 'Connection: upgrade' */ 1553 case HTTPParserHeaderstates.h_matching_connection_upgrade: 1554 _index++; 1555 if (_index > UPGRADE.length || c != UPGRADE[_index]) 1556 { 1557 h_state = HTTPParserHeaderstates.h_matching_connection_token; 1558 } 1559 else if (_index == UPGRADE.length - 1) 1560 { 1561 h_state = HTTPParserHeaderstates.h_connection_upgrade; 1562 } 1563 break; 1564 1565 case HTTPParserHeaderstates.h_matching_connection_token: 1566 if (ch == ',') 1567 { 1568 h_state = HTTPParserHeaderstates.h_matching_connection_token_start; 1569 _index = 0; 1570 } 1571 break; 1572 1573 case HTTPParserHeaderstates.h_transfer_encoding_chunked: 1574 if ( 1575 ch != ' ') 1576 h_state = HTTPParserHeaderstates.h_general; 1577 break; 1578 1579 case HTTPParserHeaderstates.h_connection_keep_alive: 1580 case HTTPParserHeaderstates.h_connection_close: 1581 case HTTPParserHeaderstates.h_connection_upgrade: 1582 if (ch == ',') 1583 { 1584 if (h_state == HTTPParserHeaderstates.h_connection_keep_alive) 1585 { 1586 _flags |= HTTPParserFlags.F_CONNECTION_KEEP_ALIVE; 1587 } 1588 else if (h_state == HTTPParserHeaderstates.h_connection_close) 1589 { 1590 _flags |= HTTPParserFlags.F_CONNECTION_CLOSE; 1591 } 1592 else if (h_state == HTTPParserHeaderstates.h_connection_upgrade) 1593 { 1594 _flags |= HTTPParserFlags.F_CONNECTION_UPGRADE; 1595 } 1596 h_state = HTTPParserHeaderstates.h_matching_connection_token_start; 1597 _index = 0; 1598 } 1599 else if (ch != ' ') 1600 { 1601 h_state = HTTPParserHeaderstates.h_matching_connection_token; 1602 } 1603 break; 1604 1605 default: 1606 _state = HTTPParserState.s_header_value; 1607 h_state = HTTPParserHeaderstates.h_general; 1608 break; 1609 } 1610 } 1611 1612 _headerState = h_state; 1613 1614 //COUNT_HEADER_SIZE(p - start); 1615 _nread += (p - start); 1616 if (_nread > _maxHeaderSize) 1617 { 1618 _httpErrno = HTTPParserErrno.HPE_HEADER_OVERFLOW; 1619 goto error; 1620 } 1621 1622 if (p == maxP) 1623 --p; 1624 break; 1625 } 1626 1627 case HTTPParserState.s_header_almost_done: 1628 { 1629 if (ch != LF) 1630 { 1631 _httpErrno = HTTPParserErrno.HPE_LF_EXPECTED; 1632 goto error; 1633 } 1634 1635 _state = HTTPParserState.s_header_value_lws; 1636 break; 1637 } 1638 1639 case HTTPParserState.s_header_value_lws: 1640 { 1641 if (ch == ' ' || ch == '\t') 1642 { 1643 _state = HTTPParserState.s_header_value_start; 1644 goto reexecute; 1645 } 1646 1647 /* finished the header */ 1648 switch ( _headerState) 1649 { 1650 case HTTPParserHeaderstates.h_connection_keep_alive: 1651 _flags |= HTTPParserFlags.F_CONNECTION_KEEP_ALIVE; 1652 break; 1653 case HTTPParserHeaderstates.h_connection_close: 1654 _flags |= HTTPParserFlags.F_CONNECTION_CLOSE; 1655 break; 1656 case HTTPParserHeaderstates.h_transfer_encoding_chunked: 1657 _flags |= HTTPParserFlags.F_CHUNKED; 1658 break; 1659 case HTTPParserHeaderstates.h_connection_upgrade: 1660 _flags |= HTTPParserFlags.F_CONNECTION_UPGRADE; 1661 break; 1662 default: 1663 break; 1664 } 1665 1666 _state = HTTPParserState.s_header_field_start; 1667 goto reexecute; 1668 } 1669 1670 case HTTPParserState.s_header_value_discard_ws_almost_done: 1671 { 1672 mixin(STRICT_CHECK("ch != LF")); 1673 _state = HTTPParserState.s_header_value_discard_lws; 1674 break; 1675 } 1676 1677 case HTTPParserState.s_header_value_discard_lws: 1678 { 1679 if (ch == ' ' || ch == '\t') 1680 { 1681 _state = HTTPParserState.s_header_value_discard_ws; 1682 break; 1683 } 1684 else 1685 { 1686 switch ( _headerState) 1687 { 1688 case HTTPParserHeaderstates.h_connection_keep_alive: 1689 _flags |= HTTPParserFlags.F_CONNECTION_KEEP_ALIVE; 1690 break; 1691 case HTTPParserHeaderstates.h_connection_close: 1692 _flags |= HTTPParserFlags.F_CONNECTION_CLOSE; 1693 break; 1694 case HTTPParserHeaderstates.h_connection_upgrade: 1695 _flags |= HTTPParserFlags.F_CONNECTION_UPGRADE; 1696 break; 1697 case HTTPParserHeaderstates.h_transfer_encoding_chunked: 1698 _flags |= HTTPParserFlags.F_CHUNKED; 1699 break; 1700 default: 1701 break; 1702 } 1703 1704 /* header value was empty */ 1705 //MARK(header_value); 1706 if (mHeaderValueMark == size_t.max) 1707 { 1708 mHeaderValueMark = p; 1709 } 1710 _state = HTTPParserState.s_header_field_start; 1711 mixin(CALLBACK_DATA_NOADVANCE("HeaderValue")); 1712 goto reexecute; 1713 } 1714 } 1715 //TODO 1716 case HTTPParserState.s_headers_almost_done: 1717 { 1718 mixin(STRICT_CHECK("ch != LF")); 1719 1720 if (_flags & HTTPParserFlags.F_TRAILING) 1721 { 1722 /* End of a chunked request */ 1723 _state = HTTPParserState.s_message_done; 1724 mixin(CALLBACK_NOTIFY_NOADVANCE("ChunkComplete")); 1725 goto reexecute; 1726 } 1727 1728 /* Cannot use chunked encoding and a content-length header together 1729 per the HTTP specification. */ 1730 if ((_flags & HTTPParserFlags.F_CHUNKED) 1731 && (_flags & HTTPParserFlags.F_CONTENTLENGTH)) 1732 { 1733 _httpErrno = HTTPParserErrno.HPE_UNEXPECTED_CONTENT_LENGTH; 1734 goto error; 1735 } 1736 1737 _state = HTTPParserState.s_headers_done; 1738 1739 /* Set this here so that on_headers_complete() callbacks can see it */ 1740 _upgrade = ( 1741 (_flags & (HTTPParserFlags.F_UPGRADE | HTTPParserFlags.F_CONNECTION_UPGRADE)) == ( 1742 HTTPParserFlags.F_UPGRADE | HTTPParserFlags.F_CONNECTION_UPGRADE) 1743 || _method == HTTPMethod.HTTP_CONNECT); 1744 { 1745 if(_keepAlive == 0x00 && _httpMinor == 0 && _httpMajor == 1){ 1746 _keepAlive = 0x02; 1747 }else { 1748 _keepAlive = 0x01; 1749 } 1750 if (_onHeadersComplete !is null) 1751 { 1752 _onHeadersComplete(this); 1753 //error("_onHeadersComplete " , errorString); 1754 //error("handleIng " , handleIng); 1755 //error("handleIng " , skipBody); 1756 //error("state " , state); 1757 if (!handleIng) 1758 { 1759 _httpErrno = HTTPParserErrno.HPE_CB_HeadersComplete; 1760 return p; /* Error */ 1761 } 1762 if (skipBody) 1763 _flags |= HTTPParserFlags.F_SKIPBODY; 1764 1765 } 1766 1767 } 1768 1769 goto reexecute; 1770 } 1771 1772 case HTTPParserState.s_headers_done: 1773 { 1774 int hasBody; 1775 mixin(STRICT_CHECK("ch != LF")); 1776 1777 _nread = 0; 1778 //int chunked = _flags & HTTPParserFlags.F_CHUNKED ; 1779 //error("s_headers_done is chunked : ", chunked); 1780 hasBody = _flags & HTTPParserFlags.F_CHUNKED 1781 || (_contentLength > 0 && _contentLength != ULLONG_MAX); 1782 if (_upgrade && (_method == HTTPMethod.HTTP_CONNECT 1783 || (_flags & HTTPParserFlags.F_SKIPBODY) || !hasBody)) 1784 { 1785 /* Exit, the rest of the message is in a different protocol. */ 1786 _state = mixin(NEW_MESSAGE); 1787 mixin(CALLBACK_NOTIFY("MessageComplete")); 1788 return (p + 1); 1789 } 1790 1791 if (_flags & HTTPParserFlags.F_SKIPBODY) 1792 { 1793 _state = mixin(NEW_MESSAGE); 1794 mixin(CALLBACK_NOTIFY("MessageComplete")); 1795 } 1796 else if (_flags & HTTPParserFlags.F_CHUNKED) 1797 { 1798 /* chunked encoding - ignore Content-Length header */ 1799 _state = HTTPParserState.s_chunk_size_start; 1800 } 1801 else 1802 { 1803 if (_contentLength == 0) 1804 { 1805 /* Content-Length header given but zero: Content-Length: 0\r\n */ 1806 _state = mixin(NEW_MESSAGE); 1807 mixin(CALLBACK_NOTIFY("MessageComplete")); 1808 } 1809 else if (_contentLength != ULLONG_MAX) 1810 { 1811 /* Content-Length header given and non-zero */ 1812 _state = HTTPParserState.s_body_identity; 1813 } 1814 else 1815 { 1816 if (!httpMessageNeedsEof()) 1817 { 1818 /* Assume content-length 0 - read the next */ 1819 _state = mixin(NEW_MESSAGE); 1820 mixin(CALLBACK_NOTIFY("MessageComplete")); 1821 } 1822 else 1823 { 1824 /* Read body until EOF */ 1825 _state = HTTPParserState.s_body_identity_eof; 1826 } 1827 } 1828 } 1829 1830 break; 1831 } 1832 1833 case HTTPParserState.s_body_identity: 1834 { 1835 ulong to_read = _contentLength < cast(ulong)(maxP - p) ? _contentLength : cast( 1836 ulong)(maxP - p); 1837 1838 assert(_contentLength != 0 && _contentLength != ULLONG_MAX); 1839 1840 /* The difference between advancing _contentLength and p is because 1841 * the latter will automaticaly advance on the next loop iteration. 1842 * Further, if _contentLength ends up at 0, we want to see the last 1843 * byte again for our message complete callback. 1844 */ 1845 //MARK(body); 1846 1847 if (mBodyMark == size_t.max) 1848 { 1849 mBodyMark = p; 1850 } 1851 _contentLength -= to_read; 1852 p += to_read - 1; 1853 1854 if (_contentLength == 0) 1855 { 1856 _state = HTTPParserState.s_message_done; 1857 1858 /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. 1859 * 1860 * The alternative to doing this is to wait for the next byte to 1861 * trigger the data callback, just as in every other case. The 1862 * problem with this is that this makes it difficult for the test 1863 * harness to distinguish between complete-on-EOF and 1864 * complete-on-length. It's not clear that this distinction is 1865 * important for applications, but let's keep it for now. 1866 */ 1867 if (mBodyMark != size_t.max && _onBody !is null) 1868 { 1869 ubyte[] _data = data[mBodyMark .. p + 1]; 1870 _onBody(this, _data, true); 1871 if (!handleIng) 1872 { 1873 _httpErrno = HTTPParserErrno.HPE_CB_Body; 1874 return p + 1; 1875 } 1876 } 1877 mBodyMark = size_t.max; 1878 goto reexecute; 1879 } 1880 1881 break; 1882 } 1883 1884 /* read until EOF */ 1885 case HTTPParserState.s_body_identity_eof: 1886 //MARK(body); 1887 if (mBodyMark == size_t.max) 1888 { 1889 mBodyMark = p; 1890 } 1891 1892 p = maxP - 1; 1893 1894 break; 1895 1896 case HTTPParserState.s_message_done: 1897 _state = mixin(NEW_MESSAGE); 1898 mixin(CALLBACK_NOTIFY("MessageComplete")); 1899 if (_upgrade) 1900 { 1901 /* Exit, the rest of the message is in a different protocol. */ 1902 return (p + 1); 1903 } 1904 break; 1905 1906 case HTTPParserState.s_chunk_size_start: 1907 { 1908 assert(_nread == 1); 1909 assert(_flags & HTTPParserFlags.F_CHUNKED); 1910 1911 unhexVal = unhex[ch]; 1912 if (unhexVal == -1) 1913 { 1914 _httpErrno = HTTPParserErrno.HPE_INVALID_CHUNK_SIZE; 1915 goto error; 1916 } 1917 1918 _contentLength = unhexVal; 1919 _state = HTTPParserState.s_chunk_size; 1920 break; 1921 } 1922 1923 case HTTPParserState.s_chunk_size: 1924 { 1925 ulong t; 1926 1927 assert(_flags & HTTPParserFlags.F_CHUNKED); 1928 1929 if (ch == CR) 1930 { 1931 _state = HTTPParserState.s_chunk_size_almost_done; 1932 break; 1933 } 1934 1935 unhexVal = unhex[ch]; 1936 1937 if (unhexVal == -1) 1938 { 1939 if (ch == ';' || ch == ' ') 1940 { 1941 _state = HTTPParserState.s_chunk_parameters; 1942 break; 1943 } 1944 1945 _httpErrno = HTTPParserErrno.HPE_INVALID_CHUNK_SIZE; 1946 goto error; 1947 } 1948 1949 t = _contentLength; 1950 t *= 16; 1951 t += unhexVal; 1952 1953 /* Overflow? Test against a conservative limit for simplicity. */ 1954 if ((ULLONG_MAX - 16) / 16 < _contentLength) 1955 { 1956 _httpErrno = HTTPParserErrno.HPE_INVALID_CONTENT_LENGTH; 1957 goto error; 1958 } 1959 1960 _contentLength = t; 1961 break; 1962 } 1963 1964 case HTTPParserState.s_chunk_parameters: 1965 { 1966 assert(_flags & HTTPParserFlags.F_CHUNKED); 1967 /* just ignore this shit. TODO check for overflow */ 1968 if (ch == CR) 1969 { 1970 _state = HTTPParserState.s_chunk_size_almost_done; 1971 break; 1972 } 1973 break; 1974 } 1975 1976 case HTTPParserState.s_chunk_size_almost_done: 1977 { 1978 assert(_flags & HTTPParserFlags.F_CHUNKED); 1979 mixin(STRICT_CHECK("ch != LF")); 1980 1981 _nread = 0; 1982 1983 if (_contentLength == 0) 1984 { 1985 _flags |= HTTPParserFlags.F_TRAILING; 1986 _state = HTTPParserState.s_header_field_start; 1987 } 1988 else 1989 { 1990 _state = HTTPParserState.s_chunk_data; 1991 } 1992 mixin(CALLBACK_NOTIFY("ChunkHeader")); 1993 break; 1994 } 1995 1996 case HTTPParserState.s_chunk_data: 1997 { 1998 ulong to_read = _contentLength < cast(ulong)(maxP - p) ? _contentLength : cast( 1999 ulong)(maxP - p); 2000 2001 assert(_flags & HTTPParserFlags.F_CHUNKED); 2002 assert(_contentLength != 0 && _contentLength != ULLONG_MAX); 2003 2004 /* See the explanation in s_body_identity for why the content 2005 * length and data pointers are managed this way. 2006 */ 2007 //MARK(body); 2008 if (mBodyMark == size_t.max) 2009 { 2010 mBodyMark = p; 2011 } 2012 _contentLength -= to_read; 2013 p += to_read - 1; 2014 2015 if (_contentLength == 0) 2016 { 2017 _state = HTTPParserState.s_chunk_data_almost_done; 2018 } 2019 2020 break; 2021 } 2022 2023 case HTTPParserState.s_chunk_data_almost_done: 2024 assert(_flags & HTTPParserFlags.F_CHUNKED); 2025 assert(_contentLength == 0); 2026 mixin(STRICT_CHECK("ch != CR")); 2027 _state = HTTPParserState.s_chunk_data_done; 2028 mixin(CALLBACK_DATA("Body")); 2029 break; 2030 2031 case HTTPParserState.s_chunk_data_done: 2032 assert(_flags & HTTPParserFlags.F_CHUNKED); 2033 mixin(STRICT_CHECK("ch != LF")); 2034 _nread = 0; 2035 _state = HTTPParserState.s_chunk_size_start; 2036 mixin(CALLBACK_NOTIFY("ChunkComplete")); 2037 break; 2038 2039 default: 2040 //assert(0 && "unhandled state"); 2041 _httpErrno = HTTPParserErrno.HPE_INVALID_INTERNAL_STATE; 2042 goto error; 2043 } 2044 } 2045 2046 assert( 2047 ( 2048 (mHeaderFieldMark != size_t.max ? 1 : 0) + (mHeaderValueMark != size_t.max ? 1 : 0) + ( 2049 mUrlMark != size_t.max ? 1 : 0) + (mBodyMark != size_t.max ? 1 : 0) + ( 2050 mStatusMark != size_t.max ? 1 : 0)) <= 1); 2051 2052 mixin(CALLBACK_DATA_NOADVANCE("HeaderField")); //最后没找到 2053 mixin(CALLBACK_DATA_NOADVANCE("HeaderValue")); 2054 mixin(CALLBACK_DATA_NOADVANCE("Url")); 2055 mixin(CALLBACK_DATA_NOADVANCE("Body")); 2056 mixin(CALLBACK_DATA_NOADVANCE("Status")); 2057 2058 return data.length; 2059 2060 error: 2061 if (_httpErrno == HTTPParserErrno.HPE_OK) 2062 { 2063 _httpErrno = HTTPParserErrno.HPE_UNKNOWN; 2064 } 2065 2066 return p; 2067 } 2068 2069 private: 2070 HTTPParserType _type = HTTPParserType.HTTP_BOTH; 2071 HTTPParserFlags _flags = HTTPParserFlags.F_ZERO; 2072 HTTPParserState _state = HTTPParserState.s_start_req_or_res; 2073 HTTPParserHeaderstates _headerState; 2074 uint _index; 2075 uint _lenientHttpHeaders; 2076 uint _nread; 2077 ulong _contentLength; 2078 ushort _httpMajor; 2079 ushort _httpMinor; 2080 uint _statusCode; /* responses only */ 2081 HTTPMethod _method; /* requests only */ 2082 HTTPParserErrno _httpErrno = HTTPParserErrno.HPE_OK; 2083 /* 1 = Upgrade header was present and the parser has exited because of that. 2084 * 0 = No upgrade header present. 2085 * Should be checked when http_parser_execute() returns in addition to 2086 * error checking. 2087 */ 2088 bool _upgrade; 2089 2090 bool _isHandle = false; 2091 2092 bool _skipBody = false; 2093 2094 ubyte _keepAlive = 0x00; 2095 2096 uint _maxHeaderSize = 4096; 2097 2098 protected: 2099 @property type(HTTPParserType ty) 2100 { 2101 _type = ty; 2102 } 2103 2104 pragma(inline) 2105 bool httpMessageNeedsEof() 2106 { 2107 if (type == HTTPParserType.HTTP_REQUEST) 2108 { 2109 return false; 2110 } 2111 2112 /* See RFC 2616 section 4.4 */ 2113 if (_statusCode / 100 == 1 || /* 1xx e.g. Continue */ 2114 _statusCode == 204 || /* No Content */ 2115 _statusCode == 304 2116 || /* Not Modified */ 2117 _flags & HTTPParserFlags.F_SKIPBODY) 2118 { /* response to a HEAD request */ 2119 return false; 2120 } 2121 2122 if ((_flags & HTTPParserFlags.F_CHUNKED) || _contentLength != ULLONG_MAX) 2123 { 2124 return false; 2125 } 2126 2127 return true; 2128 } 2129 2130 pragma(inline) 2131 bool httpShouldKeepAlive() 2132 { 2133 if (_httpMajor > 0 && _httpMinor > 0) 2134 { 2135 /* HTTP/1.1 */ 2136 if (_flags & HTTPParserFlags.F_CONNECTION_CLOSE) 2137 { 2138 return false; 2139 } 2140 } 2141 else 2142 { 2143 /* HTTP/1.0 or earlier */ 2144 if (!(_flags & HTTPParserFlags.F_CONNECTION_KEEP_ALIVE)) 2145 { 2146 return false; 2147 } 2148 } 2149 2150 return !httpMessageNeedsEof(); 2151 } 2152 2153 HTTPParserState parseURLchar(HTTPParserState s, ubyte ch) 2154 { 2155 if (ch == ' ' || ch == '\r' || ch == '\n') 2156 { 2157 return HTTPParserState.s_dead; 2158 } 2159 2160 version (HTTP_PARSER_STRICT) 2161 { 2162 if (ch == '\t' || ch == '\f') 2163 { 2164 return s_dead; 2165 } 2166 } 2167 2168 switch (s) 2169 { 2170 case HTTPParserState.s_req_spaces_before_url: 2171 /* Proxied requests are followed by scheme of an absolute URI (alpha). 2172 * All methods except CONNECT are followed by '/' or '*'. 2173 */ 2174 2175 if (ch == '/' || ch == '*') 2176 { 2177 return HTTPParserState.s_req_path; 2178 } 2179 2180 if (mixin(IS_ALPHA("ch"))) 2181 { 2182 return HTTPParserState.s_req_schema; 2183 } 2184 2185 break; 2186 2187 case HTTPParserState.s_req_schema: 2188 if (mixin(IS_ALPHA("ch"))) 2189 { 2190 return s; 2191 } 2192 2193 if (ch == ':') 2194 { 2195 return HTTPParserState.s_req_schema_slash; 2196 } 2197 2198 break; 2199 2200 case HTTPParserState.s_req_schema_slash: 2201 if (ch == '/') 2202 { 2203 return HTTPParserState.s_req_schema_slash_slash; 2204 } 2205 2206 break; 2207 2208 case HTTPParserState.s_req_schema_slash_slash: 2209 if (ch == '/') 2210 { 2211 return HTTPParserState.s_req_server_start; 2212 } 2213 2214 break; 2215 2216 case HTTPParserState.s_req_server_with_at: 2217 if (ch == '@') 2218 { 2219 return HTTPParserState.s_dead; 2220 } 2221 goto case; 2222 /* FALLTHROUGH */ 2223 case HTTPParserState.s_req_server_start: 2224 case HTTPParserState.s_req_server: 2225 { 2226 if (ch == '/') 2227 { 2228 return HTTPParserState.s_req_path; 2229 } 2230 2231 if (ch == '?') 2232 { 2233 return HTTPParserState.s_req_query_string_start; 2234 } 2235 2236 if (ch == '@') 2237 { 2238 return HTTPParserState.s_req_server_with_at; 2239 } 2240 2241 if (IS_USERINFO_CHAR2(ch) || ch == '[' || ch == ']') 2242 { 2243 return HTTPParserState.s_req_server; 2244 } 2245 } 2246 break; 2247 2248 case HTTPParserState.s_req_path: 2249 { 2250 if (mixin(IS_URL_CHAR("ch"))) 2251 { 2252 return s; 2253 } 2254 2255 switch (ch) 2256 { 2257 case '?': 2258 return HTTPParserState.s_req_query_string_start; 2259 2260 case '#': 2261 return HTTPParserState.s_req_fragment_start; 2262 default: 2263 break; 2264 } 2265 break; 2266 } 2267 2268 case HTTPParserState.s_req_query_string_start: 2269 case HTTPParserState.s_req_query_string: 2270 { 2271 if (mixin(IS_URL_CHAR("ch"))) 2272 { 2273 return HTTPParserState.s_req_query_string; 2274 } 2275 2276 switch (ch) 2277 { 2278 case '?': 2279 /* allow extra '?' in query string */ 2280 return HTTPParserState.s_req_query_string; 2281 2282 case '#': 2283 return HTTPParserState.s_req_fragment_start; 2284 default: 2285 break; 2286 } 2287 break; 2288 } 2289 2290 case HTTPParserState.s_req_fragment_start: 2291 { 2292 if (mixin(IS_URL_CHAR("ch"))) 2293 { 2294 return HTTPParserState.s_req_fragment; 2295 } 2296 2297 switch (ch) 2298 { 2299 case '?': 2300 return HTTPParserState.s_req_fragment; 2301 2302 case '#': 2303 return s; 2304 default: 2305 break; 2306 } 2307 break; 2308 } 2309 2310 case HTTPParserState.s_req_fragment: 2311 { 2312 if (mixin(IS_URL_CHAR("ch"))) 2313 { 2314 return s; 2315 } 2316 2317 switch (ch) 2318 { 2319 case '?': 2320 case '#': 2321 return s; 2322 default: 2323 break; 2324 } 2325 break; 2326 } 2327 default: 2328 break; 2329 } 2330 2331 /* We should never fall out of the switch above unless there's an error */ 2332 return HTTPParserState.s_dead; 2333 } 2334 2335 } 2336 2337 private: 2338 2339 pragma(inline,true) 2340 bool IS_USERINFO_CHAR2(ubyte c) 2341 { 2342 bool alpha = mixin(IS_ALPHA("c")); 2343 bool sum = mixin(IS_NUM("c")); 2344 bool b1 = (c == '%' || c == ';' || c == ':' || c == '&' || c == '=' 2345 || c == '+' || c == '$' || c == ','); 2346 bool b2 = (c == '-' || '_' == c || '.' == c || '!' == c || '~' == c || '*' == c 2347 || '\'' == c || '(' == c || ')' == c); 2348 return (b2 || b1 || sum || alpha); 2349 } 2350 2351 string IS_USERINFO_CHAR(string c) 2352 { 2353 return "( " ~ IS_ALPHA(c) ~ " || " ~ IS_NUM(c) ~ " || " ~ c ~ " == '%' || " ~ c ~ " == ';' || " ~ c ~ " == ':' || " ~ c ~ " == '&' || " ~ c ~ " == '=' || " ~ c ~ " == '+' || " ~ c ~ " == '$' || " ~ c ~ " == ','" ~ c ~ " == '-' || '_' == " ~ c ~ "|| '.' == " ~ c ~ "|| '!' == " ~ c ~ "|| '~' == " ~ c ~ "|| '*' == " ~ c ~ "|| '\'' == " ~ c ~ "|| '(' == " ~ c ~ "|| ')' == " ~ c ~ ")"; 2354 } 2355 2356 string STRICT_CHECK(string cond) 2357 { 2358 string code = "if ("; 2359 code = code ~ cond ~ ") { 2360 _httpErrno = HTTPParserErrno.HPE_STRICT; 2361 goto error; 2362 } "; 2363 return code; 2364 } 2365 2366 // string IS_MARK(string c) { return "(" ~ c ~ " == '-' || " ~ c ~ " == '_' || "~ c ~ " == '.' || " ~ c ~ " == '!' || " ~ c ~ " == '~' || " ~ c ~ " == '*' || " ~ c ~ " == '\'' || " ~ c ~ " == '(' || " ~ c ~ " == ')')";} 2367 string IS_NUM(string c) 2368 { 2369 return "(" ~ c ~ " >= '0' && " ~ c ~ " <= '9')"; 2370 } 2371 2372 string IS_ALPHA(string c) 2373 { 2374 return "((" ~ c ~ "| 0x20) >= 'a' && (" ~ c ~ " | 0x20) <= 'z')"; 2375 } 2376 2377 string IS_URL_CHAR(string c) 2378 { 2379 return "(!!(cast(uint) (normal_url_char[cast(uint) (" ~ c ~ ") >> 3] ) & 2380 (1 << (cast(uint)" ~ c ~ " & 7))))"; 2381 } 2382 2383 enum NEW_MESSAGE = "httpShouldKeepAlive() ? (type == HTTPParserType.HTTP_REQUEST ? HTTPParserState.s_start_req : HTTPParserState.s_start_res) : HTTPParserState.s_dead"; 2384 string CALLBACK_NOTIFY(string code) 2385 { 2386 string _s = " {if (_on" ~ code ~ " !is null){ 2387 _on" ~ code ~ "(this); if(!handleIng){ 2388 _httpErrno = HTTPParserErrno.HPE_CB_" ~ code ~ "; 2389 return p + 1;}} }"; 2390 return _s; 2391 } 2392 2393 string CALLBACK_NOTIFY_NOADVANCE(string code) 2394 { 2395 string _s = " {if (_on" ~ code ~ " != null){ 2396 _on" ~ code ~ "(this); if(!handleIng){ 2397 _httpErrno = HTTPParserErrno.HPE_CB_" ~ code ~ "; 2398 return p;} }}"; 2399 return _s; 2400 } 2401 2402 string CALLBACK_DATA(string code) 2403 { 2404 string _s = "{ if( m" ~ code ~ "Mark != size_t.max && _on" ~ code ~ " !is null){ 2405 ulong len = (p - m" ~ code ~ "Mark) ; 2406 2407 if(len > 0) { 2408 /* writeln(\"CALLBACK_DATA at \",__LINE__, \" " ~ code ~ "\");*/ 2409 ubyte[] _data = data[m" ~ code ~ "Mark..p]; 2410 _on" ~ code ~ "(this,_data,true); 2411 if (!handleIng){ 2412 _httpErrno = HTTPParserErrno.HPE_CB_" ~ code ~ "; 2413 return p + 1;}} } m" ~ code ~ "Mark = size_t.max;}"; 2414 return _s; 2415 } 2416 2417 string CALLBACK_DATA_NOADVANCE(string code) 2418 { 2419 string _s = "{ if(m" ~ code ~ "Mark != size_t.max && _on" ~ code ~ " !is null){ 2420 ulong len = (p - m" ~ code ~ "Mark) ; 2421 if(len > 0) { 2422 /*writeln(\"CALLBACK_DATA_NOADVANCE at \",__LINE__, \" " ~ code ~ "\");*/ 2423 ubyte[] _data = data[m" ~ code ~ "Mark..p]; 2424 _on" ~ code ~ "(this,_data,false); 2425 if (!handleIng){ 2426 _httpErrno = HTTPParserErrno.HPE_CB_" ~ code ~ "; 2427 return p;} }}m" ~ code ~ "Mark = size_t.max;}"; 2428 return _s; 2429 } 2430 2431 unittest 2432 { 2433 import std.stdio; 2434 import std.functional; 2435 2436 writeln("\n\n\n"); 2437 2438 void on_message_begin(ref HTTPParser) 2439 { 2440 writeln("_onMessageBegin"); 2441 writeln(" "); 2442 } 2443 2444 void on_url(ref HTTPParser par, ubyte[] data, bool adv) 2445 { 2446 writeln("_onUrl, is NOADVANCE = ", adv); 2447 writeln("\" ", cast(string) data, " \""); 2448 writeln("HTTPMethod is = ", par.methodString); 2449 writeln(" "); 2450 } 2451 2452 void on_status(ref HTTPParser par, ubyte[] data, bool adv) 2453 { 2454 writeln("_onStatus, is NOADVANCE = ", adv); 2455 writeln("\" ", cast(string) data, " \""); 2456 writeln(" "); 2457 } 2458 2459 void on_header_field(ref HTTPParser par, ubyte[] data, bool adv) 2460 { 2461 static bool frist = true; 2462 writeln("_onHeaderField, is NOADVANCE = ", adv); 2463 writeln("len = ", data.length); 2464 writeln("\" ", cast(string) data, " \""); 2465 if (frist) 2466 { 2467 writeln("\t _httpMajor", par.major); 2468 writeln("\t _httpMinor", par.minor); 2469 frist = false; 2470 } 2471 writeln(" "); 2472 } 2473 2474 void on_header_value(ref HTTPParser par, ubyte[] data, bool adv) 2475 { 2476 writeln("_onHeaderValue, is NOADVANCE = ", adv); 2477 writeln("\" ", cast(string) data, " \""); 2478 writeln(" "); 2479 } 2480 2481 void on_headers_complete(ref HTTPParser par) 2482 { 2483 writeln("_onHeadersComplete"); 2484 writeln(" "); 2485 } 2486 2487 void on_body(ref HTTPParser par, ubyte[] data, bool adv) 2488 { 2489 writeln("_onBody, is NOADVANCE = ", adv); 2490 writeln("\" ", cast(string) data, " \""); 2491 writeln(" "); 2492 } 2493 2494 void on_message_complete(ref HTTPParser par) 2495 { 2496 writeln("_onMessageComplete"); 2497 writeln(" "); 2498 } 2499 2500 void on_chunk_header(ref HTTPParser par) 2501 { 2502 writeln("_onChunkHeader"); 2503 writeln(" "); 2504 } 2505 2506 void on_chunk_complete(ref HTTPParser par) 2507 { 2508 writeln("_onChunkComplete"); 2509 writeln(" "); 2510 } 2511 2512 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"; 2513 HTTPParser par = HTTPParser(); 2514 par.onMessageBegin = toDelegate(&on_message_begin); 2515 par.onMessageComplete = toDelegate(&on_message_complete); 2516 par.onUrl = toDelegate(&on_url); 2517 par.onStatus = toDelegate(&on_status); 2518 par.onHeaderField = toDelegate(&on_header_field); 2519 par.onHeaderValue = toDelegate(&on_header_value); 2520 par.onChunkHeader = toDelegate(&on_chunk_header); 2521 par.onChunkComplete = toDelegate(&on_chunk_complete); 2522 par.onBody = toDelegate(&on_body); 2523 2524 ulong len = par.httpParserExecute(cast(ubyte[]) data); 2525 if (data.length != len) 2526 { 2527 writeln("\t error ! ", par.error); 2528 } 2529 par.rest(HTTPParserType.HTTP_BOTH); 2530 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"; 2531 2532 auto data2 = "0\r\n\r\n"; 2533 2534 len = par.httpParserExecute(cast(ubyte[]) data); 2535 if (data.length != len) 2536 { 2537 writeln("error1 ! ", par.error); 2538 writeln("\t error1 ! ", par.errorString); 2539 return; 2540 } 2541 writeln("data 1 is over!"); 2542 len = par.httpParserExecute(cast(ubyte[]) data2); 2543 writeln("last len = ", len); 2544 if (data2.length != len) 2545 { 2546 writeln("\t error ! ", par.errorString); 2547 writeln("HTTPMethod is = ", par.methodString); 2548 writeln("erro!!!!!"); 2549 } 2550 }