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) {
850 server_port_end = uri.size();
855 t = uri.substr(proto_len, server_port_end - proto_len);
856 size_t port_pos = t.find(
':', 0);
860 host = t.substr(0, port_pos);
861 if(host.length() == 0) {
866 if(port_pos != std::string::npos) {
868 port = boost::lexical_cast<
int>(t.substr(port_pos+1));
869 }
catch (boost::bad_lexical_cast &) {
872 }
else if (proto ==
"http" || proto ==
"HTTP") {
874 }
else if (proto ==
"https" || proto ==
"HTTPS") {
880 if (server_port_end < uri.size()) {
882 path = uri.substr(server_port_end);
885 size_t query_pos = path.find(
'?', 0);
887 if(query_pos != std::string::npos) {
888 query = path.substr(query_pos + 1, path.length() - query_pos - 1);
889 path = path.substr(0, query_pos);
899 const char *ptr,
const size_t len)
902 if (ptr == NULL || len == 0)
906 enum QueryParseState {
907 QUERY_PARSE_NAME, QUERY_PARSE_VALUE
908 } parse_state = QUERY_PARSE_NAME;
911 const char *
const end = ptr + len;
912 std::string query_name;
913 std::string query_value;
917 switch (parse_state) {
919 case QUERY_PARSE_NAME:
923 parse_state = QUERY_PARSE_VALUE;
924 }
else if (*ptr ==
'&') {
926 if (! query_name.empty()) {
931 }
else if (*ptr ==
'\r' || *ptr ==
'\n' || *ptr ==
'\t') {
933 }
else if (is_control(*ptr) || query_name.size() >=
QUERY_NAME_MAX) {
938 query_name.push_back(*ptr);
942 case QUERY_PARSE_VALUE:
946 if (! query_name.empty()) {
951 parse_state = QUERY_PARSE_NAME;
952 }
else if (*ptr ==
',') {
954 if (! query_name.empty())
957 }
else if (*ptr ==
'\r' || *ptr ==
'\n' || *ptr ==
'\t') {
959 }
else if (is_control(*ptr) || query_value.size() >=
QUERY_VALUE_MAX) {
964 query_value.push_back(*ptr);
973 if (! query_name.empty())
980 const std::string& content_type,
981 const char *ptr,
const size_t len)
984 if (ptr == NULL || len == 0)
988 std::size_t pos = content_type.find(
"boundary=");
989 if (pos == std::string::npos)
991 const std::string boundary = std::string(
"--") + content_type.substr(pos+9);
994 enum MultiPartParseState {
996 MP_PARSE_HEADER_CR, MP_PARSE_HEADER_LF,
997 MP_PARSE_HEADER_NAME, MP_PARSE_HEADER_SPACE, MP_PARSE_HEADER_VALUE,
998 MP_PARSE_HEADER_LAST_LF, MP_PARSE_FIELD_DATA
999 } parse_state = MP_PARSE_START;
1002 std::string header_name;
1003 std::string header_value;
1004 std::string field_name;
1005 std::string field_value;
1006 bool found_parameter =
false;
1007 bool save_current_field =
true;
1008 const char *
const end_ptr = ptr + len;
1010 ptr = std::search(ptr, end_ptr, boundary.begin(), boundary.end());
1012 while (ptr != NULL && ptr < end_ptr) {
1013 switch (parse_state) {
1014 case MP_PARSE_START:
1016 header_name.clear();
1017 header_value.clear();
1019 field_value.clear();
1020 save_current_field =
true;
1021 ptr += boundary.size() - 1;
1022 parse_state = MP_PARSE_HEADER_CR;
1024 case MP_PARSE_HEADER_CR:
1028 parse_state = MP_PARSE_HEADER_LF;
1029 }
else if (*ptr ==
'\n') {
1031 parse_state = MP_PARSE_HEADER_NAME;
1032 }
else if (*ptr ==
'-' && ptr+1 < end_ptr && ptr[1] ==
'-') {
1035 }
else return false;
1037 case MP_PARSE_HEADER_LF:
1041 parse_state = MP_PARSE_HEADER_NAME;
1042 }
else return false;
1044 case MP_PARSE_HEADER_NAME:
1046 if (*ptr ==
'\r' || *ptr ==
'\n') {
1047 if (header_name.empty()) {
1049 parse_state = (*ptr ==
'\r' ? MP_PARSE_HEADER_LAST_LF : MP_PARSE_FIELD_DATA);
1052 parse_state = (*ptr ==
'\r' ? MP_PARSE_HEADER_LF : MP_PARSE_HEADER_NAME);
1054 }
else if (*ptr ==
':') {
1056 parse_state = MP_PARSE_HEADER_SPACE;
1059 header_name += *ptr;
1062 case MP_PARSE_HEADER_SPACE:
1066 parse_state = MP_PARSE_HEADER_LF;
1067 }
else if (*ptr ==
'\n') {
1069 parse_state = MP_PARSE_HEADER_NAME;
1070 }
else if (*ptr !=
' ') {
1072 header_value += *ptr;
1073 parse_state = MP_PARSE_HEADER_VALUE;
1077 case MP_PARSE_HEADER_VALUE:
1079 if (*ptr ==
'\r' || *ptr ==
'\n') {
1081 if (boost::algorithm::iequals(header_name, types::HEADER_CONTENT_TYPE)) {
1083 save_current_field = boost::algorithm::iequals(header_value.substr(0, 5),
"text/");
1084 }
else if (boost::algorithm::iequals(header_name, types::HEADER_CONTENT_DISPOSITION)) {
1086 std::size_t name_pos = header_value.find(
"name=\"");
1087 if (name_pos != std::string::npos) {
1088 for (name_pos += 6; name_pos < header_value.size() && header_value[name_pos] !=
'\"'; ++name_pos) {
1089 field_name += header_value[name_pos];
1094 header_name.clear();
1095 header_value.clear();
1096 parse_state = (*ptr ==
'\r' ? MP_PARSE_HEADER_LF : MP_PARSE_HEADER_NAME);
1099 header_value += *ptr;
1102 case MP_PARSE_HEADER_LAST_LF:
1106 if (save_current_field && !field_name.empty()) {
1108 parse_state = MP_PARSE_FIELD_DATA;
1111 parse_state = MP_PARSE_START;
1112 ptr = std::search(ptr, end_ptr, boundary.begin(), boundary.end());
1114 }
else return false;
1116 case MP_PARSE_FIELD_DATA:
1118 const char *field_end_ptr = end_ptr;
1119 const char *next_ptr = std::search(ptr, end_ptr, boundary.begin(), boundary.end());
1122 const char *temp_ptr = next_ptr - 2;
1123 if (temp_ptr[0] ==
'\r' && temp_ptr[1] ==
'\n')
1124 field_end_ptr = temp_ptr;
1125 else field_end_ptr = next_ptr;
1127 field_value.assign(ptr, field_end_ptr - ptr);
1129 dict.insert( std::make_pair(field_name, field_value) );
1130 found_parameter =
true;
1132 parse_state = MP_PARSE_START;
1137 if (parse_state != MP_PARSE_START)
1141 return found_parameter;
1145 const char *ptr,
const size_t len,
1146 bool set_cookie_header)
1155 enum CookieParseState {
1156 COOKIE_PARSE_NAME, COOKIE_PARSE_VALUE, COOKIE_PARSE_IGNORE
1157 } parse_state = COOKIE_PARSE_NAME;
1160 const char *
const end = ptr + len;
1161 std::string cookie_name;
1162 std::string cookie_value;
1163 char value_quote_character =
'\0';
1167 switch (parse_state) {
1169 case COOKIE_PARSE_NAME:
1173 value_quote_character =
'\0';
1174 parse_state = COOKIE_PARSE_VALUE;
1175 }
else if (*ptr ==
';' || *ptr ==
',') {
1178 if (! cookie_name.empty()) {
1180 if (! is_cookie_attribute(cookie_name, set_cookie_header))
1181 dict.insert( std::make_pair(cookie_name, cookie_value) );
1182 cookie_name.erase();
1184 }
else if (*ptr !=
' ') {
1189 cookie_name.push_back(*ptr);
1193 case COOKIE_PARSE_VALUE:
1195 if (value_quote_character ==
'\0') {
1197 if (*ptr ==
';' || *ptr ==
',') {
1199 if (! is_cookie_attribute(cookie_name, set_cookie_header))
1200 dict.insert( std::make_pair(cookie_name, cookie_value) );
1201 cookie_name.erase();
1202 cookie_value.erase();
1203 parse_state = COOKIE_PARSE_NAME;
1204 }
else if (*ptr ==
'\'' || *ptr ==
'"') {
1205 if (cookie_value.empty()) {
1207 value_quote_character = *ptr;
1213 cookie_value.push_back(*ptr);
1215 }
else if (*ptr !=
' ' || !cookie_value.empty()) {
1220 cookie_value.push_back(*ptr);
1224 if (*ptr == value_quote_character) {
1226 if (! is_cookie_attribute(cookie_name, set_cookie_header))
1227 dict.insert( std::make_pair(cookie_name, cookie_value) );
1228 cookie_name.erase();
1229 cookie_value.erase();
1230 parse_state = COOKIE_PARSE_IGNORE;
1236 cookie_value.push_back(*ptr);
1241 case COOKIE_PARSE_IGNORE:
1243 if (*ptr ==
';' || *ptr ==
',')
1244 parse_state = COOKIE_PARSE_NAME;
1252 if (! is_cookie_attribute(cookie_name, set_cookie_header))
1253 dict.insert( std::make_pair(cookie_name, cookie_value) );
1259 boost::system::error_code& ec)
1269 m_bytes_last_read = 0;
1272 switch (m_chunked_content_parse_state) {
1273 case PARSE_CHUNK_SIZE_START:
1276 m_chunk_size_str.erase();
1278 m_chunked_content_parse_state = PARSE_CHUNK_SIZE;
1289 case PARSE_CHUNK_SIZE:
1293 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE;
1297 m_chunked_content_parse_state = PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE;
1301 m_chunked_content_parse_state = PARSE_EXPECTING_IGNORED_TEXT_AFTER_CHUNK_SIZE;
1308 case PARSE_EXPECTING_IGNORED_TEXT_AFTER_CHUNK_SIZE:
1310 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE;
1314 case PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE:
1316 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE;
1327 case PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE:
1331 m_bytes_read_in_current_chunk = 0;
1332 m_size_of_current_chunk = strtol(m_chunk_size_str.c_str(), 0, 16);
1333 if (m_size_of_current_chunk == 0) {
1334 m_chunked_content_parse_state = PARSE_EXPECTING_FINAL_CR_OR_FOOTERS_AFTER_LAST_CHUNK;
1336 m_chunked_content_parse_state = PARSE_CHUNK;
1345 if (m_bytes_read_in_current_chunk < m_size_of_current_chunk) {
1346 if (m_payload_handler) {
1348 const std::size_t bytes_in_chunk = m_size_of_current_chunk - m_bytes_read_in_current_chunk;
1349 const std::size_t len = (bytes_in_chunk > bytes_avail) ? bytes_avail : bytes_in_chunk;
1351 m_bytes_read_in_current_chunk += len;
1353 }
else if (chunks.size() < m_max_content_length) {
1355 m_bytes_read_in_current_chunk++;
1358 if (m_bytes_read_in_current_chunk == m_size_of_current_chunk) {
1359 m_chunked_content_parse_state = PARSE_EXPECTING_CR_AFTER_CHUNK;
1363 case PARSE_EXPECTING_CR_AFTER_CHUNK:
1366 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK;
1373 case PARSE_EXPECTING_LF_AFTER_CHUNK:
1376 m_chunked_content_parse_state = PARSE_CHUNK_SIZE_START;
1383 case PARSE_EXPECTING_FINAL_CR_OR_FOOTERS_AFTER_LAST_CHUNK:
1386 m_chunked_content_parse_state = PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK;
1390 m_message_parse_state = PARSE_FOOTERS;
1391 m_headers_parse_state = PARSE_HEADER_START;
1392 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
1393 m_bytes_total_read += m_bytes_last_read;
1394 m_bytes_content_read += m_bytes_last_read;
1395 PION_LOG_DEBUG(
m_logger,
"Parsed " << m_bytes_last_read <<
" chunked payload content bytes; chunked content complete.");
1400 case PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK:
1404 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
1405 m_bytes_total_read += m_bytes_last_read;
1406 m_bytes_content_read += m_bytes_last_read;
1407 PION_LOG_DEBUG(
m_logger,
"Parsed " << m_bytes_last_read <<
" chunked payload content bytes; chunked content complete.");
1418 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
1419 m_bytes_total_read += m_bytes_last_read;
1420 m_bytes_content_read += m_bytes_last_read;
1421 return boost::indeterminate;
1425 boost::system::error_code& ec)
1427 size_t content_bytes_to_read;
1429 boost::tribool rc = boost::indeterminate;
1431 if (m_bytes_content_remaining == 0) {
1435 if (content_bytes_available >= m_bytes_content_remaining) {
1438 content_bytes_to_read = m_bytes_content_remaining;
1441 content_bytes_to_read = content_bytes_available;
1443 m_bytes_content_remaining -= content_bytes_to_read;
1447 if (m_payload_handler) {
1448 m_payload_handler(
m_read_ptr, content_bytes_to_read);
1449 }
else if (m_bytes_content_read < m_max_content_length) {
1450 if (m_bytes_content_read + content_bytes_to_read > m_max_content_length) {
1454 m_max_content_length - m_bytes_content_read);
1462 m_bytes_content_read += content_bytes_to_read;
1463 m_bytes_total_read += content_bytes_to_read;
1464 m_bytes_last_read = content_bytes_to_read;
1472 m_bytes_last_read = 0;
1476 if (m_payload_handler) {
1477 m_payload_handler(
m_read_ptr, m_bytes_last_read);
1481 if (chunks.size() < m_max_content_length)
1486 m_bytes_total_read += m_bytes_last_read;
1487 m_bytes_content_read += m_bytes_last_read;
1489 return m_bytes_last_read;
1494 switch (m_message_parse_state) {
1516 http_msg.
set_is_valid(m_chunked_content_parse_state==PARSE_CHUNK_SIZE_START);
1517 if (!m_payload_handler)
1520 case PARSE_CONTENT_NO_LENGTH:
1522 if (!m_payload_handler)
1533 http::request& http_request(dynamic_cast<http::request&>(http_msg));
1534 const std::string& content_type_header = http_request.
get_header(http::types::HEADER_CONTENT_TYPE);
1535 if (content_type_header.compare(0, http::types::CONTENT_TYPE_URLENCODED.length(),
1536 http::types::CONTENT_TYPE_URLENCODED) == 0)
1541 PION_LOG_WARN(
m_logger,
"Request form data parsing failed (POST urlencoded)");
1542 }
else if (content_type_header.compare(0, http::types::CONTENT_TYPE_MULTIPART_FORM_DATA.length(),
1543 http::types::CONTENT_TYPE_MULTIPART_FORM_DATA) == 0)
1546 content_type_header,
1549 PION_LOG_WARN(
m_logger,
"Request form data parsing failed (POST multipart)");
1560 http::message::STATUS_PARTIAL : http::message::STATUS_TRUNCATED;
1562 st = msg_parsed_ok ? http::message::STATUS_OK : http::message::STATUS_TRUNCATED;
1565 http_msg.set_status(st);
1571 m_error_category_ptr = &UNIQUE_ERROR_CATEGORY;
1577 static const boost::regex IPV4_ADDR_RX(
"[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
1584 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}");
1591 boost::match_results<std::string::const_iterator> m;
1592 std::string::const_iterator start_it = header.begin();
1595 while (boost::regex_search(start_it, header.end(), m, IPV4_ADDR_RX)) {
1597 std::string ip_str(m[0].first, m[0].second);
1599 if (! boost::regex_match(ip_str, PRIVATE_NET_RX) ) {
1605 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)