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