@@ -923,35 +923,19 @@ namespace http
923923// ----------------------------------------------------------------------------------------------------------------
924924
925925 template <class Message >
926- void parser<Message>::reset()
927- {
928- state = start_line;
929- body_read = 0 ;
930- }
931-
932- void parse_start_line (request& req, const char * line, std::error_code& ec)
926+ parser<Message>::parser()
933927 {
934- char method[8 ] = {0 };
935- req.uri .resize (strlen (line));
936- int http_version_major = -1 ;
937- req.http_version_minor = -1 ;
938- sscanf (line, " %s %s HTTP/%i.%i" , method, &req.uri [0 ], &http_version_major, &req.http_version_minor );
939- req.verb = verb_enum (method);
940- req.uri .resize (strlen (req.uri .c_str ()));
941- if (req.verb == UNKNOWN_VERB)
942- ec = make_error_code (http_read_bad_method);
943- else if (http_version_major != 1 || !(req.http_version_minor == 0 || req.http_version_minor == 1 ))
944- ec = make_error_code (http_read_unsupported_http_version);
928+ reset ();
945929 }
946930
947- void parse_start_line (response& resp, const char * line, std::error_code& ec)
931+ template <class Message >
932+ void parser<Message>::reset()
948933 {
949- resp.status = status_type::unknown;
950- int http_version_major = -1 ;
951- resp.http_version_minor = -1 ;
952- sscanf (line, " HTTP/%i.%i %u" , &http_version_major, &resp.http_version_minor , (unsigned int *)&resp.status );
953- if (http_version_major != 1 || !(resp.http_version_minor == 0 || resp.http_version_minor == 1 ))
954- ec = make_error_code (http_read_unsupported_http_version);
934+ if constexpr (std::is_same_v<Message, request>)
935+ state = method;
936+ else
937+ state = http_version;
938+ body_read = 0 ;
955939 }
956940
957941 template <class Message >
@@ -965,8 +949,149 @@ namespace http
965949 if (buf.size () > max_header_size)
966950 ec = make_error_code (http_read_header_line_too_big);
967951
968- // Start line or header line
969- else if (state == start_line || state == header_line)
952+ // Start line method (Request only)
953+ else if (state == method)
954+ {
955+ constexpr std::size_t max_method_size{16 };
956+
957+ // Sufficient data
958+ if (buf.size () >= max_method_size)
959+ {
960+ std::string_view method_str (&buf[0 ], max_method_size);
961+ const auto end = method_str.find (" " );
962+ const verb_type method = verb_enum (method_str.substr (0 , end));
963+
964+ // Found
965+ if (method != UNKNOWN_VERB)
966+ {
967+ if constexpr (std::is_same_v<Message, request>)
968+ msg.verb = method;
969+
970+ state = uri;
971+ buf.erase (begin (buf), begin (buf) + end + 1 );
972+ }
973+
974+ // Not found
975+ else
976+ ec = make_error_code (http_read_bad_method);
977+ }
978+
979+ // Insufficient
980+ else
981+ break ;
982+ }
983+
984+ // URI (Request only)
985+ else if (state == uri)
986+ {
987+ const auto end = buf.find (" " );
988+
989+ // Found
990+ if (end != std::string_view::npos)
991+ {
992+ if constexpr (std::is_same_v<Message, request>)
993+ msg.uri = buf.substr (0 , end);
994+
995+ state = http_version;
996+ buf.erase (begin (buf), begin (buf) + end + 1 );
997+ }
998+
999+ // Not found
1000+ else
1001+ break ;
1002+ }
1003+
1004+ // HTTP version
1005+ else if (state == http_version)
1006+ {
1007+ constexpr std::size_t http_size{8 };
1008+
1009+ // Sufficient data
1010+ if (buf.size () > 10 )
1011+ {
1012+ buf[http_size] = ' \0 ' ;
1013+ int major{-1 };
1014+ int minor{-1 };
1015+ const int ret = sscanf (&buf[0 ], " HTTP/%i.%i" , &major, &minor);
1016+
1017+ // Found
1018+ if (ret == 2 && major == 1 && (minor == 0 || minor == 1 ))
1019+ {
1020+ if constexpr (std::is_same_v<Message, request>)
1021+ {
1022+ state = header_line;
1023+ buf.erase (begin (buf), begin (buf) + http_size + 2 );
1024+ }
1025+
1026+ else
1027+ {
1028+ state = status_code;
1029+ buf.erase (begin (buf), begin (buf) + http_size + 1 );
1030+ }
1031+
1032+ msg.http_version_minor = minor;
1033+ }
1034+
1035+ // Not found
1036+ else
1037+ ec = make_error_code (http_read_unsupported_http_version);
1038+ }
1039+
1040+ // Insufficient
1041+ else
1042+ break ;
1043+ }
1044+
1045+ // Status code (response only)
1046+ else if (state == status_code)
1047+ {
1048+ const auto end = buf.find (" " );
1049+
1050+ // Sufficient
1051+ if (end != std::string::npos)
1052+ {
1053+ buf[end] = ' \0 ' ;
1054+ int status{-1 };
1055+ const int ret = sscanf (&buf[0 ], " %i" , &status);
1056+
1057+ // Found
1058+ if (ret == 1 && status >= (int )status_type::continue_ && status <= 1000 )
1059+ {
1060+ if constexpr (std::is_same_v<Message, response>)
1061+ msg.status = (status_type)status;
1062+ state = status_msg;
1063+ buf.erase (begin (buf), begin (buf) + end + 1 );
1064+ }
1065+
1066+ // Not found
1067+ else
1068+ ec = make_error_code (http_read_bad_status);
1069+ }
1070+
1071+ // Insufficient
1072+ else
1073+ break ;
1074+ }
1075+
1076+ // Status label
1077+ else if (state == status_msg)
1078+ {
1079+ const auto end = buf.find (" \r\n " );
1080+
1081+ // Found
1082+ if (end != std::string::npos)
1083+ {
1084+ state = header_line;
1085+ buf.erase (begin (buf), begin (buf) + end + 2 );
1086+ }
1087+
1088+ // Not Found
1089+ else
1090+ ec = make_error_code (http_read_bad_status);
1091+ }
1092+
1093+ // Header line
1094+ else if (state == header_line)
9701095 {
9711096 // Find EOL
9721097 char * end = strstr (&buf[0 ], " \r\n " );
@@ -980,15 +1105,8 @@ namespace http
9801105 {
9811106 *end = ' \0 ' ;
9821107
983- // Start line
984- if (state == start_line)
985- {
986- state = header_line;
987- parse_start_line (msg, &buf[0 ], ec);
988- }
989-
9901108 // Header line
991- else if (std::distance (&buf[0 ], end) > 0 )
1109+ if (std::distance (&buf[0 ], end) > 0 )
9921110 {
9931111 char * kend = strstr (&buf[0 ], " : " );
9941112
@@ -1197,6 +1315,7 @@ namespace http
11971315 case http_read_bad_method: return " HTTP request method bad" ;
11981316 case http_read_unsupported_http_version: return " HTTP version either bad or unsupported" ;
11991317 case http_read_header_kv_delimiter_not_found: return " Missing delimiter in HTTP header line" ;
1318+ case http_read_bad_status: return " HTTP status code bad" ;
12001319 case http_read_header_unsupported_field: return " HTTP header field unsupported" ;
12011320 case http_write_unsupported_http_version: return " HTTP message contains bad or unsupported http minor version" ;
12021321 case http_write_request_bad_verb: return " HTTP request contains bad verb" ;
0 commit comments