11 #include <boost/regex.hpp>
12 #include <boost/logic/tribool.hpp>
13 #include <pion/net/HTTPParser.hpp>
14 #include <pion/net/HTTPRequest.hpp>
15 #include <pion/net/HTTPResponse.hpp>
16 #include <pion/net/HTTPMessage.hpp>
36 HTTPParser::ErrorCategory * HTTPParser::m_error_category_ptr = NULL;
37 boost::once_flag HTTPParser::m_instance_flag = BOOST_ONCE_INIT;
43 boost::system::error_code& ec)
45 PION_ASSERT(!
eof() );
47 boost::tribool rc = boost::indeterminate;
48 std::size_t total_bytes_parsed = 0;
51 http_msg.setDataAfterMissingPacket(
true);
55 switch (m_message_parse_state) {
58 m_message_parse_state = PARSE_HEADERS;
64 total_bytes_parsed += m_bytes_last_read;
75 total_bytes_parsed += m_bytes_last_read;
85 total_bytes_parsed += m_bytes_last_read;
89 case PARSE_CONTENT_NO_LENGTH:
91 total_bytes_parsed += m_bytes_last_read;
99 }
while ( boost::indeterminate(rc) && !
eof() );
103 m_message_parse_state = PARSE_END;
105 }
else if(rc ==
false) {
110 m_bytes_last_read = total_bytes_parsed;
116 std::size_t len, boost::system::error_code& ec)
118 static const char MISSING_DATA_CHAR =
'X';
119 boost::tribool rc = boost::indeterminate;
123 switch (m_message_parse_state) {
128 setError(ec, ERROR_MISSING_HEADER_DATA);
135 if (m_chunked_content_parse_state == PARSE_CHUNK
136 && m_bytes_read_in_current_chunk < m_size_of_current_chunk
137 && (m_size_of_current_chunk - m_bytes_read_in_current_chunk) >= len)
140 for (std::size_t n = 0; n < len && http_msg.
getChunkCache().size() < m_max_content_length; ++n)
143 m_bytes_read_in_current_chunk += len;
144 m_bytes_last_read = len;
145 m_bytes_total_read += len;
146 m_bytes_content_read += len;
148 if (m_bytes_read_in_current_chunk == m_size_of_current_chunk) {
149 m_chunked_content_parse_state = PARSE_EXPECTING_CR_AFTER_CHUNK;
153 setError(ec, ERROR_MISSING_CHUNK_DATA);
161 if (m_bytes_content_remaining == 0) {
164 }
else if (m_bytes_content_remaining < len) {
166 setError(ec, ERROR_MISSING_TOO_MUCH_CONTENT);
171 if ( (m_bytes_content_read+len) <= m_max_content_length) {
173 for (std::size_t n = 0; n < len; ++n)
174 http_msg.
getContent()[m_bytes_content_read++] = MISSING_DATA_CHAR;
176 m_bytes_content_read += len;
179 m_bytes_content_remaining -= len;
180 m_bytes_total_read += len;
181 m_bytes_last_read = len;
183 if (m_bytes_content_remaining == 0)
189 case PARSE_CONTENT_NO_LENGTH:
191 for (std::size_t n = 0; n < len && http_msg.
getChunkCache().size() < m_max_content_length; ++n)
193 m_bytes_last_read = len;
194 m_bytes_total_read += len;
195 m_bytes_content_read += len;
206 m_message_parse_state = PARSE_END;
208 }
else if(rc ==
false) {
216 boost::system::error_code& ec)
226 m_bytes_last_read = 0;
229 if (m_save_raw_headers)
232 switch (m_headers_parse_state) {
233 case PARSE_METHOD_START:
240 m_headers_parse_state = PARSE_METHOD;
250 m_headers_parse_state = PARSE_URI_STEM;
265 m_headers_parse_state = PARSE_HTTP_VERSION_H;
267 m_query_string.erase();
268 m_headers_parse_state = PARSE_URI_QUERY;
272 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
276 m_headers_parse_state = PARSE_EXPECTING_CR;
288 case PARSE_URI_QUERY:
291 m_headers_parse_state = PARSE_HTTP_VERSION_H;
303 case PARSE_HTTP_VERSION_H:
313 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
322 m_headers_parse_state = PARSE_EXPECTING_CR;
327 m_headers_parse_state = PARSE_HTTP_VERSION_T_1;
330 case PARSE_HTTP_VERSION_T_1:
336 m_headers_parse_state = PARSE_HTTP_VERSION_T_2;
339 case PARSE_HTTP_VERSION_T_2:
345 m_headers_parse_state = PARSE_HTTP_VERSION_P;
348 case PARSE_HTTP_VERSION_P:
354 m_headers_parse_state = PARSE_HTTP_VERSION_SLASH;
357 case PARSE_HTTP_VERSION_SLASH:
363 m_headers_parse_state = PARSE_HTTP_VERSION_MAJOR_START;
366 case PARSE_HTTP_VERSION_MAJOR_START:
373 m_headers_parse_state = PARSE_HTTP_VERSION_MAJOR;
376 case PARSE_HTTP_VERSION_MAJOR:
379 m_headers_parse_state = PARSE_HTTP_VERSION_MINOR_START;
389 case PARSE_HTTP_VERSION_MINOR_START:
396 m_headers_parse_state = PARSE_HTTP_VERSION_MINOR;
399 case PARSE_HTTP_VERSION_MINOR:
404 m_headers_parse_state = PARSE_STATUS_CODE_START;
412 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
419 m_headers_parse_state = PARSE_EXPECTING_CR;
429 case PARSE_STATUS_CODE_START:
436 m_headers_parse_state = PARSE_STATUS_CODE;
439 case PARSE_STATUS_CODE:
442 m_status_message.erase();
443 m_headers_parse_state = PARSE_STATUS_MESSAGE;
445 m_status_code = ( (m_status_code * 10) + (*
m_read_ptr -
'0') );
448 m_status_message.erase();
449 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
452 m_status_message.erase();
453 m_headers_parse_state = PARSE_EXPECTING_CR;
460 case PARSE_STATUS_MESSAGE:
463 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
465 m_headers_parse_state = PARSE_EXPECTING_CR;
477 case PARSE_EXPECTING_NEWLINE:
480 m_headers_parse_state = PARSE_HEADER_START;
486 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
487 m_bytes_total_read += m_bytes_last_read;
490 m_headers_parse_state = PARSE_HEADER_WHITESPACE;
496 m_header_name.erase();
498 m_headers_parse_state = PARSE_HEADER_NAME;
502 case PARSE_EXPECTING_CR:
505 m_headers_parse_state = PARSE_HEADER_START;
511 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
512 m_bytes_total_read += m_bytes_last_read;
515 m_headers_parse_state = PARSE_HEADER_WHITESPACE;
521 m_header_name.erase();
523 m_headers_parse_state = PARSE_HEADER_NAME;
527 case PARSE_HEADER_WHITESPACE:
530 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
532 m_headers_parse_state = PARSE_EXPECTING_CR;
538 m_header_name.erase();
540 m_headers_parse_state = PARSE_HEADER_NAME;
544 case PARSE_HEADER_START:
547 m_headers_parse_state = PARSE_EXPECTING_FINAL_NEWLINE;
549 m_headers_parse_state = PARSE_EXPECTING_FINAL_CR;
551 m_headers_parse_state = PARSE_HEADER_WHITESPACE;
557 m_header_name.erase();
559 m_headers_parse_state = PARSE_HEADER_NAME;
563 case PARSE_HEADER_NAME:
566 m_header_value.erase();
567 m_headers_parse_state = PARSE_SPACE_BEFORE_HEADER_VALUE;
572 setError(ec, ERROR_HEADER_NAME_SIZE);
580 case PARSE_SPACE_BEFORE_HEADER_VALUE:
583 m_headers_parse_state = PARSE_HEADER_VALUE;
585 http_msg.
addHeader(m_header_name, m_header_value);
586 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
588 http_msg.
addHeader(m_header_name, m_header_value);
589 m_headers_parse_state = PARSE_EXPECTING_CR;
596 m_headers_parse_state = PARSE_HEADER_VALUE;
600 case PARSE_HEADER_VALUE:
603 http_msg.
addHeader(m_header_name, m_header_value);
604 m_headers_parse_state = PARSE_EXPECTING_NEWLINE;
606 http_msg.
addHeader(m_header_name, m_header_value);
607 m_headers_parse_state = PARSE_EXPECTING_CR;
612 setError(ec, ERROR_HEADER_VALUE_SIZE);
620 case PARSE_EXPECTING_FINAL_NEWLINE:
622 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
623 m_bytes_total_read += m_bytes_last_read;
626 case PARSE_EXPECTING_FINAL_CR:
628 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
629 m_bytes_total_read += m_bytes_last_read;
636 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
637 m_bytes_total_read += m_bytes_last_read;
638 return boost::indeterminate;
647 HTTPRequest& http_request(dynamic_cast<HTTPRequest&>(http_msg));
653 if (! m_query_string.empty()) {
655 m_query_string.c_str(),
656 m_query_string.size()))
657 PION_LOG_WARN(
m_logger,
"Request query string parsing failed (URI)");
661 std::pair<HTTPTypes::Headers::const_iterator, HTTPTypes::Headers::const_iterator>
662 cookie_pair = http_request.
getHeaders().equal_range(HTTPTypes::HEADER_COOKIE);
663 for (HTTPTypes::Headers::const_iterator cookie_iterator = cookie_pair.first;
664 cookie_iterator != http_request.
getHeaders().end()
665 && cookie_iterator != cookie_pair.second; ++cookie_iterator)
668 cookie_iterator->second,
false) )
669 PION_LOG_WARN(
m_logger,
"Cookie header parsing failed");
676 HTTPResponse& http_response(dynamic_cast<HTTPResponse&>(http_msg));
681 std::pair<HTTPTypes::Headers::const_iterator, HTTPTypes::Headers::const_iterator>
682 cookie_pair = http_response.
getHeaders().equal_range(HTTPTypes::HEADER_SET_COOKIE);
683 for (HTTPTypes::Headers::const_iterator cookie_iterator = cookie_pair.first;
684 cookie_iterator != http_response.
getHeaders().end()
685 && cookie_iterator != cookie_pair.second; ++cookie_iterator)
688 cookie_iterator->second,
true) )
689 PION_LOG_WARN(
m_logger,
"Set-Cookie header parsing failed");
696 boost::system::error_code& ec)
698 boost::tribool rc = boost::indeterminate;
700 m_bytes_content_remaining = m_bytes_content_read = 0;
708 m_message_parse_state = PARSE_CHUNKS;
711 if (m_parse_headers_only)
717 m_message_parse_state = PARSE_END;
723 if (http_msg.
hasHeader(HTTPTypes::HEADER_CONTENT_LENGTH)) {
729 PION_LOG_ERROR(
m_logger,
"Unable to update content length");
730 setError(ec, ERROR_INVALID_CONTENT_LENGTH);
736 m_message_parse_state = PARSE_END;
739 m_message_parse_state = PARSE_CONTENT;
743 if (m_bytes_content_remaining > m_max_content_length)
747 if (m_parse_headers_only)
761 m_message_parse_state = PARSE_CONTENT_NO_LENGTH;
764 if (m_parse_headers_only)
767 m_message_parse_state = PARSE_END;
780 const char *ptr,
const size_t len)
783 enum QueryParseState {
784 QUERY_PARSE_NAME, QUERY_PARSE_VALUE
785 } parse_state = QUERY_PARSE_NAME;
788 const char *
const end = ptr + len;
789 std::string query_name;
790 std::string query_value;
794 switch (parse_state) {
796 case QUERY_PARSE_NAME:
800 parse_state = QUERY_PARSE_VALUE;
801 }
else if (*ptr ==
'&') {
803 if (! query_name.empty()) {
805 dict.insert( std::make_pair(query_name, query_value) );
808 }
else if (*ptr ==
'\r' || *ptr ==
'\n' || *ptr ==
'\t') {
810 }
else if (isControl(*ptr) || query_name.size() >=
QUERY_NAME_MAX) {
815 query_name.push_back(*ptr);
819 case QUERY_PARSE_VALUE:
823 if (! query_name.empty()) {
824 dict.insert( std::make_pair(query_name, query_value) );
828 parse_state = QUERY_PARSE_NAME;
829 }
else if (*ptr ==
'\r' || *ptr ==
'\n' || *ptr ==
'\t') {
836 query_value.push_back(*ptr);
845 if (! query_name.empty())
846 dict.insert( std::make_pair(query_name, query_value) );
852 const char *ptr,
const size_t len,
853 bool set_cookie_header)
862 enum CookieParseState {
863 COOKIE_PARSE_NAME, COOKIE_PARSE_VALUE, COOKIE_PARSE_IGNORE
864 } parse_state = COOKIE_PARSE_NAME;
867 const char *
const end = ptr + len;
868 std::string cookie_name;
869 std::string cookie_value;
870 char value_quote_character =
'\0';
874 switch (parse_state) {
876 case COOKIE_PARSE_NAME:
880 value_quote_character =
'\0';
881 parse_state = COOKIE_PARSE_VALUE;
882 }
else if (*ptr ==
';' || *ptr ==
',') {
885 if (! cookie_name.empty()) {
887 if (! isCookieAttribute(cookie_name, set_cookie_header))
888 dict.insert( std::make_pair(cookie_name, cookie_value) );
891 }
else if (*ptr !=
' ') {
896 cookie_name.push_back(*ptr);
900 case COOKIE_PARSE_VALUE:
902 if (value_quote_character ==
'\0') {
904 if (*ptr ==
';' || *ptr ==
',') {
906 if (! isCookieAttribute(cookie_name, set_cookie_header))
907 dict.insert( std::make_pair(cookie_name, cookie_value) );
909 cookie_value.erase();
910 parse_state = COOKIE_PARSE_NAME;
911 }
else if (*ptr ==
'\'' || *ptr ==
'"') {
912 if (cookie_value.empty()) {
914 value_quote_character = *ptr;
920 cookie_value.push_back(*ptr);
922 }
else if (*ptr !=
' ' || !cookie_value.empty()) {
927 cookie_value.push_back(*ptr);
931 if (*ptr == value_quote_character) {
933 if (! isCookieAttribute(cookie_name, set_cookie_header))
934 dict.insert( std::make_pair(cookie_name, cookie_value) );
936 cookie_value.erase();
937 parse_state = COOKIE_PARSE_IGNORE;
943 cookie_value.push_back(*ptr);
948 case COOKIE_PARSE_IGNORE:
950 if (*ptr ==
';' || *ptr ==
',')
951 parse_state = COOKIE_PARSE_NAME;
959 if (! isCookieAttribute(cookie_name, set_cookie_header))
960 dict.insert( std::make_pair(cookie_name, cookie_value) );
966 boost::system::error_code& ec)
976 m_bytes_last_read = 0;
979 switch (m_chunked_content_parse_state) {
980 case PARSE_CHUNK_SIZE_START:
983 m_chunk_size_str.erase();
985 m_chunked_content_parse_state = PARSE_CHUNK_SIZE;
996 case PARSE_CHUNK_SIZE:
1000 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE;
1004 m_chunked_content_parse_state = PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE;
1011 case PARSE_EXPECTING_CR_AFTER_CHUNK_SIZE:
1013 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE;
1024 case PARSE_EXPECTING_LF_AFTER_CHUNK_SIZE:
1028 m_bytes_read_in_current_chunk = 0;
1029 m_size_of_current_chunk = strtol(m_chunk_size_str.c_str(), 0, 16);
1030 if (m_size_of_current_chunk == 0) {
1031 m_chunked_content_parse_state = PARSE_EXPECTING_FINAL_CR_AFTER_LAST_CHUNK;
1033 m_chunked_content_parse_state = PARSE_CHUNK;
1042 if (m_bytes_read_in_current_chunk < m_size_of_current_chunk) {
1043 if (chunk_cache.size() < m_max_content_length)
1045 m_bytes_read_in_current_chunk++;
1047 if (m_bytes_read_in_current_chunk == m_size_of_current_chunk) {
1048 m_chunked_content_parse_state = PARSE_EXPECTING_CR_AFTER_CHUNK;
1052 case PARSE_EXPECTING_CR_AFTER_CHUNK:
1055 m_chunked_content_parse_state = PARSE_EXPECTING_LF_AFTER_CHUNK;
1062 case PARSE_EXPECTING_LF_AFTER_CHUNK:
1065 m_chunked_content_parse_state = PARSE_CHUNK_SIZE_START;
1072 case PARSE_EXPECTING_FINAL_CR_AFTER_LAST_CHUNK:
1075 m_chunked_content_parse_state = PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK;
1082 case PARSE_EXPECTING_FINAL_LF_AFTER_LAST_CHUNK:
1086 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
1087 m_bytes_total_read += m_bytes_last_read;
1088 m_bytes_content_read += m_bytes_last_read;
1089 PION_LOG_DEBUG(
m_logger,
"Parsed " << m_bytes_last_read <<
" chunked payload content bytes; chunked content complete.");
1100 m_bytes_last_read = (
m_read_ptr - read_start_ptr);
1101 m_bytes_total_read += m_bytes_last_read;
1102 m_bytes_content_read += m_bytes_last_read;
1103 return boost::indeterminate;
1107 boost::system::error_code& ec)
1109 size_t content_bytes_to_read;
1111 boost::tribool rc = boost::indeterminate;
1113 if (m_bytes_content_remaining == 0) {
1117 if (content_bytes_available >= m_bytes_content_remaining) {
1120 content_bytes_to_read = m_bytes_content_remaining;
1123 content_bytes_to_read = content_bytes_available;
1125 m_bytes_content_remaining -= content_bytes_to_read;
1129 if (m_bytes_content_read < m_max_content_length) {
1130 if (m_bytes_content_read + content_bytes_to_read > m_max_content_length) {
1134 m_max_content_length - m_bytes_content_read);
1142 m_bytes_content_read += content_bytes_to_read;
1143 m_bytes_total_read += content_bytes_to_read;
1144 m_bytes_last_read = content_bytes_to_read;
1152 m_bytes_last_read = 0;
1156 if (chunk_cache.size() < m_max_content_length)
1160 m_bytes_total_read += m_bytes_last_read;
1161 m_bytes_content_read += m_bytes_last_read;
1163 return m_bytes_last_read;
1168 switch (m_message_parse_state) {
1189 http_msg.
setIsValid(m_chunked_content_parse_state==PARSE_CHUNK_SIZE_START);
1192 case PARSE_CONTENT_NO_LENGTH:
1204 HTTPRequest& http_request(dynamic_cast<HTTPRequest&>(http_msg));
1205 const std::string& content_type_header = http_request.
getHeader(HTTPTypes::HEADER_CONTENT_TYPE);
1206 if (content_type_header.compare(0, HTTPTypes::CONTENT_TYPE_URLENCODED.length(),
1207 HTTPTypes::CONTENT_TYPE_URLENCODED) == 0)
1212 PION_LOG_WARN(
m_logger,
"Request query string parsing failed (POST content)");
1223 HTTPMessage::STATUS_PARTIAL : HTTPMessage::STATUS_TRUNCATED;
1225 st = msg_parsed_ok ? HTTPMessage::STATUS_OK : HTTPMessage::STATUS_TRUNCATED;
1228 http_msg.setStatus(st);
1234 m_error_category_ptr = &UNIQUE_ERROR_CATEGORY;
1240 static const boost::regex IPV4_ADDR_RX(
"[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");
1247 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}");
1254 boost::match_results<std::string::const_iterator> m;
1255 std::string::const_iterator start_it = header.begin();
1258 while (boost::regex_search(start_it, header.end(), m, IPV4_ADDR_RX)) {
1260 std::string ip_str(m[0].first, m[0].second);
1262 if (! boost::regex_match(ip_str, PRIVATE_NET_RX) ) {
1268 start_it = m[0].second;