12 #include <boost/regex.hpp> 13 #include <boost/assert.hpp> 14 #include <boost/logic/tribool.hpp> 15 #include <boost/algorithm/string.hpp> 16 #include <pion/algorithm.hpp> 17 #include <pion/http/parser.hpp> 18 #include <pion/http/request.hpp> 19 #include <pion/http/response.hpp> 20 #include <pion/http/message.hpp> 40 parser::error_category_t * parser::m_error_category_ptr = NULL;
41 boost::once_flag parser::m_instance_flag = BOOST_ONCE_INIT;
47 boost::system::error_code& ec)
49 BOOST_ASSERT(!
eof() );
51 boost::tribool rc = boost::indeterminate;
52 std::size_t total_bytes_parsed = 0;
55 http_msg.set_data_after_missing_packet(
true);
59 switch (m_message_parse_state) {
62 m_message_parse_state = PARSE_HEADERS;
69 total_bytes_parsed += m_bytes_last_read;
71 if (rc ==
true && m_message_parse_state == PARSE_HEADERS) {
81 total_bytes_parsed += m_bytes_last_read;
83 if (rc ==
true && !m_payload_handler) {
87 rc = ((m_message_parse_state == PARSE_FOOTERS) ?
88 boost::indeterminate : (boost::tribool)
true);
95 total_bytes_parsed += m_bytes_last_read;
99 case PARSE_CONTENT_NO_LENGTH:
101 total_bytes_parsed += m_bytes_last_read;
109 }
while ( boost::indeterminate(rc) && !
eof() );
113 m_message_parse_state = PARSE_END;
115 }
else if(rc ==
false) {
120 m_bytes_last_read = total_bytes_parsed;
126 std::size_t len, boost::system::error_code& ec)
128 static const char MISSING_DATA_CHAR =
'X';
129 boost::tribool rc = boost::indeterminate;
133 switch (m_message_parse_state) {
139 set_error(ec, ERROR_MISSING_HEADER_DATA);
146 if (m_chunked_content_parse_state == PARSE_CHUNK
147 && m_bytes_read_in_current_chunk < m_size_of_current_chunk
148 && (m_size_of_current_chunk - m_bytes_read_in_current_chunk) >= len)
151 if (m_payload_handler) {
152 for (std::size_t n = 0; n < len; ++n)
153 m_payload_handler(&MISSING_DATA_CHAR, 1);
155 for (std::size_t n = 0; n < len && http_msg.
get_chunk_cache().size() < m_max_content_length; ++n)
159 m_bytes_read_in_current_chunk += len;
160 m_bytes_last_read = len;
161 m_bytes_total_read += len;
162 m_bytes_content_read += len;
164 if (m_bytes_read_in_current_chunk == m_size_of_current_chunk) {
165 m_chunked_content_parse_state = PARSE_EXPECTING_CR_AFTER_CHUNK;
177 if (m_bytes_content_remaining == 0) {
180 }
else if (m_bytes_content_remaining < len) {
182 set_error(ec, ERROR_MISSING_TOO_MUCH_CONTENT);
187 if (m_payload_handler) {
188 for (std::size_t n = 0; n < len; ++n)
189 m_payload_handler(&MISSING_DATA_CHAR, 1);
190 }
else if ( (m_bytes_content_read+len) <= m_max_content_length) {
192 for (std::size_t n = 0; n < len; ++n)
193 http_msg.
get_content()[m_bytes_content_read++] = MISSING_DATA_CHAR;
195 m_bytes_content_read += len;
198 m_bytes_content_remaining -= len;
199 m_bytes_total_read += len;
200 m_bytes_last_read = len;
202 if (m_bytes_content_remaining == 0)
208 case PARSE_CONTENT_NO_LENGTH:
210 if (m_payload_handler) {
211 for (std::size_t n = 0; n < len; ++n)
212 m_payload_handler(&MISSING_DATA_CHAR, 1);
214 for (std::size_t n = 0; n < len && http_msg.
get_chunk_cache().size() < m_max_content_length; ++n)
217 m_bytes_last_read = len;
218 m_bytes_total_read += len;
219 m_bytes_content_read += len;
230 m_message_parse_state = PARSE_END;
232 }
else if(rc ==
false) {
240 boost::system::error_code& ec)
250 m_bytes_last_read = 0;
253 if (m_save_raw_headers)
256 switch (m_headers_parse_state) {
257 case PARSE_METHOD_START:
264 m_headers_parse_state = PARSE_METHOD;
274 m_headers_parse_state = PARSE_URI_STEM;
289 m_headers_parse_state = PARSE_HTTP_VERSION_H;
291 m_query_string.erase();
292 m_headers_parse_state = PARSE_URI_QUERY;
296 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
300 m_headers_parse_state = PARSE_EXPECTING_CR;
312 case PARSE_URI_QUERY:
315 m_headers_parse_state = PARSE_HTTP_VERSION_H;
319 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
323 m_headers_parse_state = PARSE_EXPECTING_CR;
335 case PARSE_HTTP_VERSION_H:
345 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
354 m_headers_parse_state = PARSE_EXPECTING_CR;
359 m_headers_parse_state = PARSE_HTTP_VERSION_T_1;
362 case PARSE_HTTP_VERSION_T_1:
368 m_headers_parse_state = PARSE_HTTP_VERSION_T_2;
371 case PARSE_HTTP_VERSION_T_2:
377 m_headers_parse_state = PARSE_HTTP_VERSION_P;
380 case PARSE_HTTP_VERSION_P:
386 m_headers_parse_state = PARSE_HTTP_VERSION_SLASH;
389 case PARSE_HTTP_VERSION_SLASH:
395 m_headers_parse_state = PARSE_HTTP_VERSION_MAJOR_START;
398 case PARSE_HTTP_VERSION_MAJOR_START:
405 m_headers_parse_state = PARSE_HTTP_VERSION_MAJOR;
408 case PARSE_HTTP_VERSION_MAJOR:
411 m_headers_parse_state = PARSE_HTTP_VERSION_MINOR_START;
421 case PARSE_HTTP_VERSION_MINOR_START:
428 m_headers_parse_state = PARSE_HTTP_VERSION_MINOR;
431 case PARSE_HTTP_VERSION_MINOR:
436 m_headers_parse_state = PARSE_STATUS_CODE_START;
444 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
451 m_headers_parse_state = PARSE_EXPECTING_CR;
461 case PARSE_STATUS_CODE_START:
468 m_headers_parse_state = PARSE_STATUS_CODE;
471 case PARSE_STATUS_CODE:
474 m_status_message.erase();
475 m_headers_parse_state = PARSE_STATUS_MESSAGE;
477 m_status_code = ( (m_status_code * 10) + (*
m_read_ptr -
'0') );
480 m_status_message.erase();
481 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
484 m_status_message.erase();
485 m_headers_parse_state = PARSE_EXPECTING_CR;
492 case PARSE_STATUS_MESSAGE:
495 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
497 m_headers_parse_state = PARSE_EXPECTING_CR;
509 case PARSE_EXPECTING_NEWLINE:
514 PION_LOG_DEBUG(
m_logger,
"HTTP 0.9 Simple-Request found");
516 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
517 m_bytes_total_read += m_bytes_last_read;
520 m_headers_parse_state = PARSE_HEADER_START;
527 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
528 m_bytes_total_read += m_bytes_last_read;
531 m_headers_parse_state = PARSE_HEADER_WHITESPACE;
537 m_header_name.erase();
539 m_headers_parse_state = PARSE_HEADER_NAME;
543 case PARSE_EXPECTING_CR:
546 m_headers_parse_state = PARSE_HEADER_START;
552 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
553 m_bytes_total_read += m_bytes_last_read;
556 m_headers_parse_state = PARSE_HEADER_WHITESPACE;
562 m_header_name.erase();
564 m_headers_parse_state = PARSE_HEADER_NAME;
568 case PARSE_HEADER_WHITESPACE:
571 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
573 m_headers_parse_state = PARSE_EXPECTING_CR;
580 m_header_name.erase();
582 m_headers_parse_state = PARSE_HEADER_NAME;
586 case PARSE_HEADER_START:
589 m_headers_parse_state = PARSE_EXPECTING_FINAL_NEWLINE;
591 m_headers_parse_state = PARSE_EXPECTING_FINAL_CR;
593 m_headers_parse_state = PARSE_HEADER_WHITESPACE;
599 m_header_name.erase();
601 m_headers_parse_state = PARSE_HEADER_NAME;
605 case PARSE_HEADER_NAME:
608 m_header_value.erase();
609 m_headers_parse_state = PARSE_SPACE_BEFORE_HEADER_VALUE;
622 case PARSE_SPACE_BEFORE_HEADER_VALUE:
625 m_headers_parse_state = PARSE_HEADER_VALUE;
627 http_msg.
add_header(m_header_name, m_header_value);
628 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
630 http_msg.
add_header(m_header_name, m_header_value);
631 m_headers_parse_state = PARSE_EXPECTING_CR;
638 m_headers_parse_state = PARSE_HEADER_VALUE;
642 case PARSE_HEADER_VALUE:
645 http_msg.
add_header(m_header_name, m_header_value);
646 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
648 http_msg.
add_header(m_header_name, m_header_value);
649 m_headers_parse_state = PARSE_EXPECTING_CR;
668 case PARSE_EXPECTING_FINAL_NEWLINE:
670 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
671 m_bytes_total_read += m_bytes_last_read;
674 case PARSE_EXPECTING_FINAL_CR:
676 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
677 m_bytes_total_read += m_bytes_last_read;
684 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
685 m_bytes_total_read += m_bytes_last_read;
686 return boost::indeterminate;
695 http::request& http_request(dynamic_cast<http::request&>(http_msg));
701 if (! m_query_string.empty()) {
703 m_query_string.c_str(),
704 m_query_string.size()))
705 PION_LOG_WARN(
m_logger,
"Request query string parsing failed (URI)");
709 std::pair<ihash_multimap::const_iterator, ihash_multimap::const_iterator>
710 cookie_pair = http_request.
get_headers().equal_range(http::types::HEADER_COOKIE);
711 for (ihash_multimap::const_iterator cookie_iterator = cookie_pair.first;
712 cookie_iterator != http_request.
get_headers().end()
713 && cookie_iterator != cookie_pair.second; ++cookie_iterator)
716 cookie_iterator->second,
false) )
717 PION_LOG_WARN(
m_logger,
"Cookie header parsing failed");
724 http::response& http_response(dynamic_cast<http::response&>(http_msg));
729 std::pair<ihash_multimap::const_iterator, ihash_multimap::const_iterator>
730 cookie_pair = http_response.
get_headers().equal_range(http::types::HEADER_SET_COOKIE);
731 for (ihash_multimap::const_iterator cookie_iterator = cookie_pair.first;
732 cookie_iterator != http_response.
get_headers().end()
733 && cookie_iterator != cookie_pair.second; ++cookie_iterator)
736 cookie_iterator->second,
true) )
737 PION_LOG_WARN(
m_logger,
"Set-Cookie header parsing failed");
744 boost::system::error_code& ec)
746 boost::tribool rc = boost::indeterminate;
748 m_bytes_content_remaining = m_bytes_content_read = 0;
756 m_message_parse_state = PARSE_CHUNKS;
759 if (m_parse_headers_only)
765 m_message_parse_state = PARSE_END;
771 if (http_msg.
has_header(http::types::HEADER_CONTENT_LENGTH)) {
777 PION_LOG_ERROR(
m_logger,
"Unable to update content length");
778 set_error(ec, ERROR_INVALID_CONTENT_LENGTH);
784 m_message_parse_state = PARSE_END;
787 m_message_parse_state = PARSE_CONTENT;
791 if (m_bytes_content_remaining > m_max_content_length)
794 if (m_parse_headers_only) {
813 m_message_parse_state = PARSE_CONTENT_NO_LENGTH;
816 if (m_parse_headers_only)
819 m_message_parse_state = PARSE_END;
831 std::string& host, boost::uint16_t& port,
832 std::string& path, std::string& query)
834 size_t proto_end = uri.find(
"://");
835 size_t proto_len = 0;
837 if(proto_end != std::string::npos) {
838 proto = uri.substr(0, proto_end);
839 proto_len = proto_end + 3;
846 size_t server_port_end = uri.find(
'/', proto_len);
847 if(server_port_end == std::string::npos) {
853 t = uri.substr(proto_len, server_port_end - proto_len);
854 size_t port_pos = t.find(
':', 0);
858 host = t.substr(0, port_pos);
859 if(host.length() == 0) {
864 if(port_pos != std::string::npos) {
866 port = boost::lexical_cast<
int>(t.substr(port_pos+1));
867 }
catch (boost::bad_lexical_cast &) {
870 }
else if (proto ==
"http" || proto ==
"HTTP") {
872 }
else if (proto ==
"https" || proto ==
"HTTPS") {
879 path = uri.substr(server_port_end);
882 size_t query_pos = path.find(
'?', 0);
884 if(query_pos != std::string::npos) {
885 query = path.substr(query_pos + 1, path.length() - query_pos - 1);
886 path = path.substr(0, query_pos);
895 const char *ptr,
const size_t len)
898 if (ptr == NULL || len == 0)
902 enum QueryParseState {
903 QUERY_PARSE_NAME, QUERY_PARSE_VALUE
904 } parse_state = QUERY_PARSE_NAME;
907 const char *
const end = ptr + len;
908 std::string query_name;
909 std::string query_value;
913 switch (parse_state) {
915 case QUERY_PARSE_NAME:
919 parse_state = QUERY_PARSE_VALUE;
920 }
else if (*ptr ==
'&') {
922 if (! query_name.empty()) {
927 }
else if (*ptr ==
'\r' || *ptr ==
'\n' || *ptr ==
'\t') {
929 }
else if (is_control(*ptr) || query_name.size() >=
QUERY_NAME_MAX) {
934 query_name.push_back(*ptr);
938 case QUERY_PARSE_VALUE:
942 if (! query_name.empty()) {
947 parse_state = QUERY_PARSE_NAME;
948 }
else if (*ptr ==
',') {
950 if (! query_name.empty())
953 }
else if (*ptr ==
'\r' || *ptr ==
'\n' || *ptr ==
'\t') {
955 }
else if (is_control(*ptr) || query_value.size() >=
QUERY_VALUE_MAX) {
960 query_value.push_back(*ptr);
969 if (! query_name.empty())
976 const std::string& content_type,
977 const char *ptr,
const size_t len)
980 if (ptr == NULL || len == 0)
984 std::size_t pos = content_type.find(
"boundary=");
985 if (pos == std::string::npos)
987 const std::string boundary = std::string(
"--") + content_type.substr(pos+9);
990 enum MultiPartParseState {
992 MP_PARSE_HEADER_CR, MP_PARSE_HEADER_LF,
993 MP_PARSE_HEADER_NAME, MP_PARSE_HEADER_SPACE, MP_PARSE_HEADER_VALUE,
994 MP_PARSE_HEADER_LAST_LF, MP_PARSE_FIELD_DATA
995 } parse_state = MP_PARSE_START;
998 std::string header_name;
999 std::string header_value;
1000 std::string field_name;
1001 std::string field_value;
1002 bool found_parameter =
false;
1003 bool save_current_field =
true;
1004 const char *
const end_ptr = ptr + len;
1006 ptr = std::search(ptr, end_ptr, boundary.begin(), boundary.end());
1008 while (ptr != NULL && ptr < end_ptr) {
1009 switch (parse_state) {
1010 case MP_PARSE_START:
1012 header_name.clear();
1013 header_value.clear();
1015 field_value.clear();
1016 save_current_field =
true;
1017 ptr += boundary.size() - 1;
1018 parse_state = MP_PARSE_HEADER_CR;
1020 case MP_PARSE_HEADER_CR:
1024 parse_state = MP_PARSE_HEADER_LF;
1025 }
else if (*ptr ==
'\n') {
1027 parse_state = MP_PARSE_HEADER_NAME;
1028 }
else if (*ptr ==
'-' && ptr+1 < end_ptr && ptr[1] ==
'-') {
1031 }
else return false;
1033 case MP_PARSE_HEADER_LF:
1037 parse_state = MP_PARSE_HEADER_NAME;
1038 }
else return false;
1040 case MP_PARSE_HEADER_NAME:
1042 if (*ptr ==
'\r' || *ptr ==
'\n') {
1043 if (header_name.empty()) {
1045 parse_state = (*ptr ==
'\r' ? MP_PARSE_HEADER_LAST_LF : MP_PARSE_FIELD_DATA);
1048 parse_state = (*ptr ==
'\r' ? MP_PARSE_HEADER_LF : MP_PARSE_HEADER_NAME);
1050 }
else if (*ptr ==
':') {
1052 parse_state = MP_PARSE_HEADER_SPACE;
1055 header_name += *ptr;
1058 case MP_PARSE_HEADER_SPACE:
1062 parse_state = MP_PARSE_HEADER_LF;
1063 }
else if (*ptr ==
'\n') {
1065 parse_state = MP_PARSE_HEADER_NAME;
1066 }
else if (*ptr !=
' ') {
1068 header_value += *ptr;
1069 parse_state = MP_PARSE_HEADER_VALUE;
1073 case MP_PARSE_HEADER_VALUE:
1075 if (*ptr ==
'\r' || *ptr ==
'\n') {
1077 if (boost::algorithm::iequals(header_name, types::HEADER_CONTENT_TYPE)) {
1079 save_current_field = boost::algorithm::iequals(header_value.substr(0, 5),
"text/");
1080 }
else if (boost::algorithm::iequals(header_name, types::HEADER_CONTENT_DISPOSITION)) {
1082 std::size_t name_pos = header_value.find(
"name=\"");
1083 if (name_pos != std::string::npos) {
1084 for (name_pos += 6; name_pos < header_value.size() && header_value[name_pos] !=
'\"'; ++name_pos) {
1085 field_name += header_value[name_pos];
1090 header_name.clear();
1091 header_value.clear();
1092 parse_state = (*ptr ==
'\r' ? MP_PARSE_HEADER_LF : MP_PARSE_HEADER_NAME);
1095 header_value += *ptr;
1098 case MP_PARSE_HEADER_LAST_LF:
1102 if (save_current_field && !field_name.empty()) {
1104 parse_state = MP_PARSE_FIELD_DATA;
1107 parse_state = MP_PARSE_START;
1108 ptr = std::search(ptr, end_ptr, boundary.begin(), boundary.end());
1110 }
else return false;
1112 case MP_PARSE_FIELD_DATA:
1114 const char *field_end_ptr = end_ptr;
1115 const char *next_ptr = std::search(ptr, end_ptr, boundary.begin(), boundary.end());
1118 const char *temp_ptr = next_ptr - 2;
1119 if (temp_ptr[0] ==
'\r' && temp_ptr[1] ==
'\n')
1120 field_end_ptr = temp_ptr;
1121 else field_end_ptr = next_ptr;
1123 field_value.assign(ptr, field_end_ptr - ptr);
1125 dict.insert( std::make_pair(field_name, field_value) );
1126 found_parameter =
true;
1128 parse_state = MP_PARSE_START;
1133 if (parse_state != MP_PARSE_START)
1137 return found_parameter;
1141 const char *ptr,
const size_t len,
1142 bool set_cookie_header)
1151 enum CookieParseState {
1152 COOKIE_PARSE_NAME, COOKIE_PARSE_VALUE, COOKIE_PARSE_IGNORE
1153 } parse_state = COOKIE_PARSE_NAME;
1156 const char *
const end = ptr + len;
1157 std::string cookie_name;
1158 std::string cookie_value;
1159 char value_quote_character =
'\0';
1163 switch (parse_state) {
1165 case COOKIE_PARSE_NAME:
1169 value_quote_character =
'\0';
1170 parse_state = COOKIE_PARSE_VALUE;
1171 }
else if (*ptr ==
';' || *ptr ==
',') {
1174 if (! cookie_name.empty()) {
1176 if (! is_cookie_attribute(cookie_name, set_cookie_header))
1177 dict.insert( std::make_pair(cookie_name, cookie_value) );
1178 cookie_name.erase();
1180 }
else if (*ptr !=
' ') {
1185 cookie_name.push_back(*ptr);
1189 case COOKIE_PARSE_VALUE:
1191 if (value_quote_character ==
'\0') {
1193 if (*ptr ==
';' || *ptr ==
',') {
1195 if (! is_cookie_attribute(cookie_name, set_cookie_header))
1196 dict.insert( std::make_pair(cookie_name, cookie_value) );
1197 cookie_name.erase();
1198 cookie_value.erase();
1199 parse_state = COOKIE_PARSE_NAME;
1200 }
else if (*ptr ==
'\'' || *ptr ==
'"') {
1201 if (cookie_value.empty()) {
1203 value_quote_character = *ptr;
1209 cookie_value.push_back(*ptr);
1211 }
else if (*ptr !=
' ' || !cookie_value.empty()) {
1216 cookie_value.push_back(*ptr);
1220 if (*ptr == value_quote_character) {
1222 if (! is_cookie_attribute(cookie_name, set_cookie_header))
1223 dict.insert( std::make_pair(cookie_name, cookie_value) );
1224 cookie_name.erase();
1225 cookie_value.erase();
1226 parse_state = COOKIE_PARSE_IGNORE;
1232 cookie_value.push_back(*ptr);
1237 case COOKIE_PARSE_IGNORE:
1239 if (*ptr ==
';' || *ptr ==
',')
1240 parse_state = COOKIE_PARSE_NAME;
1248 if (! is_cookie_attribute(cookie_name, set_cookie_header))
1249 dict.insert( std::make_pair(cookie_name, cookie_value) );
1255 boost::system::error_code& ec)
1265 m_bytes_last_read = 0;
1268 switch (m_chunked_content_parse_state) {
1269 case PARSE_CHUNK_SIZE_START:
1272 m_chunk_size_str.erase();
1274 m_chunked_content_parse_state = PARSE_CHUNK_SIZE;
1285 case PARSE_CHUNK_SIZE:
1289 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE;
1293 m_chunked_content_parse_state = PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE;
1297 m_chunked_content_parse_state = PARSE_EXPECTING_IGNORED_TEXT_AFTER_CHUNK_SIZE;
1304 case PARSE_EXPECTING_IGNORED_TEXT_AFTER_CHUNK_SIZE:
1306 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE;
1310 case PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE:
1312 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE;
1323 case PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE:
1327 m_bytes_read_in_current_chunk = 0;
1328 m_size_of_current_chunk = strtol(m_chunk_size_str.c_str(), 0, 16);
1329 if (m_size_of_current_chunk == 0) {
1330 m_chunked_content_parse_state = PARSE_EXPECTING_FINAL_CR_OR_FOOTERS_AFTER_LAST_CHUNK;
1332 m_chunked_content_parse_state = PARSE_CHUNK;
1341 if (m_bytes_read_in_current_chunk < m_size_of_current_chunk) {
1342 if (m_payload_handler) {
1344 const std::size_t bytes_in_chunk = m_size_of_current_chunk - m_bytes_read_in_current_chunk;
1345 const std::size_t len = (bytes_in_chunk > bytes_avail) ? bytes_avail : bytes_in_chunk;
1347 m_bytes_read_in_current_chunk += len;
1349 }
else if (chunks.size() < m_max_content_length) {
1351 m_bytes_read_in_current_chunk++;
1354 if (m_bytes_read_in_current_chunk == m_size_of_current_chunk) {
1355 m_chunked_content_parse_state = PARSE_EXPECTING_CR_AFTER_CHUNK;
1359 case PARSE_EXPECTING_CR_AFTER_CHUNK:
1362 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK;
1369 case PARSE_EXPECTING_LF_AFTER_CHUNK:
1372 m_chunked_content_parse_state = PARSE_CHUNK_SIZE_START;
1379 case PARSE_EXPECTING_FINAL_CR_OR_FOOTERS_AFTER_LAST_CHUNK:
1382 m_chunked_content_parse_state = PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK;
1386 m_message_parse_state = PARSE_FOOTERS;
1387 m_headers_parse_state = PARSE_HEADER_START;
1388 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
1389 m_bytes_total_read += m_bytes_last_read;
1390 m_bytes_content_read += m_bytes_last_read;
1391 PION_LOG_DEBUG(
m_logger,
"Parsed " << m_bytes_last_read <<
" chunked payload content bytes; chunked content complete.");
1396 case PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK:
1400 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
1401 m_bytes_total_read += m_bytes_last_read;
1402 m_bytes_content_read += m_bytes_last_read;
1403 PION_LOG_DEBUG(
m_logger,
"Parsed " << m_bytes_last_read <<
" chunked payload content bytes; chunked content complete.");
1414 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
1415 m_bytes_total_read += m_bytes_last_read;
1416 m_bytes_content_read += m_bytes_last_read;
1417 return boost::indeterminate;
1421 boost::system::error_code& ec)
1423 size_t content_bytes_to_read;
1425 boost::tribool rc = boost::indeterminate;
1427 if (m_bytes_content_remaining == 0) {
1431 if (content_bytes_available >= m_bytes_content_remaining) {
1434 content_bytes_to_read = m_bytes_content_remaining;
1437 content_bytes_to_read = content_bytes_available;
1439 m_bytes_content_remaining -= content_bytes_to_read;
1443 if (m_payload_handler) {
1444 m_payload_handler(
m_read_ptr, content_bytes_to_read);
1445 }
else if (m_bytes_content_read < m_max_content_length) {
1446 if (m_bytes_content_read + content_bytes_to_read > m_max_content_length) {
1450 m_max_content_length - m_bytes_content_read);
1458 m_bytes_content_read += content_bytes_to_read;
1459 m_bytes_total_read += content_bytes_to_read;
1460 m_bytes_last_read = content_bytes_to_read;
1468 m_bytes_last_read = 0;
1472 if (m_payload_handler) {
1473 m_payload_handler(
m_read_ptr, m_bytes_last_read);
1477 if (chunks.size() < m_max_content_length)
1482 m_bytes_total_read += m_bytes_last_read;
1483 m_bytes_content_read += m_bytes_last_read;
1485 return m_bytes_last_read;
1490 switch (m_message_parse_state) {
1512 http_msg.
set_is_valid(m_chunked_content_parse_state==PARSE_CHUNK_SIZE_START);
1513 if (!m_payload_handler)
1516 case PARSE_CONTENT_NO_LENGTH:
1518 if (!m_payload_handler)
1529 http::request& http_request(dynamic_cast<http::request&>(http_msg));
1530 const std::string& content_type_header = http_request.
get_header(http::types::HEADER_CONTENT_TYPE);
1531 if (content_type_header.compare(0, http::types::CONTENT_TYPE_URLENCODED.length(),
1532 http::types::CONTENT_TYPE_URLENCODED) == 0)
1537 PION_LOG_WARN(
m_logger,
"Request form data parsing failed (POST urlencoded)");
1538 }
else if (content_type_header.compare(0, http::types::CONTENT_TYPE_MULTIPART_FORM_DATA.length(),
1539 http::types::CONTENT_TYPE_MULTIPART_FORM_DATA) == 0)
1542 content_type_header,
1545 PION_LOG_WARN(
m_logger,
"Request form data parsing failed (POST multipart)");
1556 http::message::STATUS_PARTIAL : http::message::STATUS_TRUNCATED;
1558 st = msg_parsed_ok ? http::message::STATUS_OK : http::message::STATUS_TRUNCATED;
1561 http_msg.set_status(st);
1567 m_error_category_ptr = &UNIQUE_ERROR_CATEGORY;
1573 static const boost::regex IPV4_ADDR_RX(
"[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
1580 static const boost::regex PRIVATE_NET_RX(
"(10\\.[0-9]{1,3}|127\\.[0-9]{1,3}|192\\.168|172\\.1[6-9]|172\\.2[0-9]|172\\.3[0-1])\\.[0-9]{1,3}\\.[0-9]{1,3}");
1587 boost::match_results<std::string::const_iterator> m;
1588 std::string::const_iterator start_it = header.begin();
1591 while (boost::regex_search(start_it, header.end(), m, IPV4_ADDR_RX)) {
1593 std::string ip_str(m[0].first, m[0].second);
1595 if (! boost::regex_match(ip_str, PRIVATE_NET_RX) ) {
1601 start_it = m[0].second;
static const boost::uint32_t COOKIE_NAME_MAX
maximum length for the name of a cookie name
static void create_error_category(void)
creates the unique parser error_category_t
static const std::size_t DEFAULT_CONTENT_MAX
maximum length for HTTP payload content
boost::tribool parse_missing_data(http::message &http_msg, std::size_t len, boost::system::error_code &ec)
void update_message_with_header_data(http::message &http_msg) const
void update_content_length_using_header(void)
sets the length of the payload content using the Content-Length header
static bool parse_cookie_header(ihash_multimap &dict, const char *ptr, const std::size_t len, bool set_cookie_header)
bool is_parsing_request(void) const
returns true if the parser is being used to parse an HTTP request
static const boost::uint32_t QUERY_NAME_MAX
maximum length for the name of a query string variable
static const boost::uint32_t HEADER_VALUE_MAX
maximum length for an HTTP header value
const char * m_read_end_ptr
points to the end of the read_buffer (last byte + 1)
void add_header(const std::string &key, const std::string &value)
adds a value for the HTTP header named key
void set_status_code(unsigned int n)
sets the HTTP response status code
static const boost::uint32_t STATUS_MESSAGE_MAX
maximum length for response status message
static const boost::uint32_t RESOURCE_MAX
maximum length for the resource requested
logger m_logger
primary logging interface used by this class
class-specific error category
void set_is_valid(bool b=true)
sets whether or not the message is valid
const std::string & get_header(const std::string &key) const
returns a value for the header if any are defined; otherwise, an empty string
void set_version_minor(const boost::uint16_t n)
sets the minor HTTP version number
void set_version_major(const boost::uint16_t n)
sets the major HTTP version number
boost::uint16_t get_version_major(void) const
returns the major HTTP version number
size_t get_content_length(void) const
returns the length of the payload content (in bytes)
void set_missing_packets(bool newVal)
set to true when missing packets detected
static void set_error(boost::system::error_code &ec, error_value_t ev)
void concatenate_chunks(void)
boost::tribool parse_headers(http::message &http_msg, boost::system::error_code &ec)
static bool parse_forwarded_for(const std::string &header, std::string &public_ip)
ihash_multimap & get_headers(void)
returns a reference to the HTTP headers
bool eof(void) const
returns true if there are no more bytes available in the read buffer
static const boost::uint32_t QUERY_STRING_MAX
maximum length for the query string
void set_content_length(size_t n)
sets the length of the payload content (in bytes)
void finish(http::message &http_msg) const
static void compute_msg_status(http::message &http_msg, bool msg_parsed_ok)
std::vector< char > chunk_cache_t
used to cache chunked data
std::size_t consume_content_as_next_chunk(http::message::chunk_cache_t &chunk_buffers)
boost::tribool parse(http::message &http_msg, boost::system::error_code &ec)
const bool m_is_request
true if the message is an HTTP request; false if it is an HTTP response
bool is_valid(void) const
returns true if the message is valid
bool has_missing_packets() const
true if there were missing packets
void set_method(const std::string &str)
sets the HTTP request method (i.e. GET, POST, PUT)
virtual void finished_parsing_headers(const boost::system::error_code &ec)
Called after we have finished parsing the HTTP message headers.
static const boost::uint32_t COOKIE_VALUE_MAX
maximum length for the value of a cookie; also used for path and domain
chunk_cache_t & get_chunk_cache(void)
returns a reference to the chunk cache
const char * m_read_ptr
points to the next character to be consumed in the read_buffer
virtual bool is_content_length_implied(void) const =0
should return true if the content length can be implied without headers
static std::string url_decode(const std::string &str)
escapes URL-encoded strings (a%20value+with%20spaces)
boost::uint16_t get_version_minor(void) const
returns the minor HTTP version number
void set_status_message(const std::string &msg)
sets the HTTP response status message
static bool parse_url_encoded(ihash_multimap &dict, const char *ptr, const std::size_t len)
static const boost::uint32_t HEADER_NAME_MAX
maximum length for an HTTP header name
std::size_t get_content_bytes_read(void) const
returns the total number of bytes read while parsing the payload content
boost::tribool consume_content(http::message &http_msg, boost::system::error_code &ec)
void update_transfer_encoding_using_header(void)
sets the transfer coding using the Transfer-Encoding header
char * create_content_buffer(void)
static const boost::uint32_t QUERY_VALUE_MAX
maximum length for the value of a query string variable
data_status_t
defines message data integrity status codes
boost::tribool parse_chunks(http::message::chunk_cache_t &chunk_buffers, boost::system::error_code &ec)
char * get_content(void)
returns a pointer to the payload content, or empty string if there is none
void set_query_string(const std::string &str)
sets the uri-query or query string requested
bool is_chunked(void) const
returns true if the message content is chunked
static bool parse_multipart_form_data(ihash_multimap &dict, const std::string &content_type, const char *ptr, const std::size_t len)
boost::tribool finish_header_parsing(http::message &http_msg, boost::system::error_code &ec)
bool has_header(const std::string &key) const
returns true if at least one value for the header is defined
ihash_multimap & get_queries(void)
returns the query parameters
bool has_data_after_missing_packets() const
true if more data seen after the missing packets
ihash_multimap & get_cookies(void)
returns the cookie parameters
std::size_t bytes_available(void) const
returns the number of bytes available in the read buffer
static const boost::uint32_t METHOD_MAX
maximum length for the request method
void set_resource(const std::string &str)
sets the resource or uri-stem originally requested
static bool parse_uri(const std::string &uri, std::string &proto, std::string &host, boost::uint16_t &port, std::string &path, std::string &query)