28#include <boost/regex.hpp>
29#include <boost/lexical_cast.hpp>
37#undef MONERO_DEFAULT_LOG_CATEGORY
38#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
40#define HTTP_MAX_URI_LEN 9000
41#define HTTP_MAX_HEADER_LEN 100000
42#define HTTP_MAX_STARTING_NEWLINES 8
62 STATIC_REGEXP_EXPR_1(rexp_match_boundary,
"boundary=(.*?)(($)|([;\\s,]))", boost::regex::icase | boost::regex::normal);
65 if(boost::regex_search(content_type,
result, rexp_match_boundary, boost::match_default) &&
result[0].matched)
78 "\n?((Content-Disposition)|(Content-Type)"
80 "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]",
82 boost::regex::icase | boost::regex::normal);
85 std::string::const_iterator it_current_bound = it_begin;
86 std::string::const_iterator it_end_bound = it_end;
89 while( boost::regex_search( it_current_bound, it_end_bound,
result, rexp_mach_field, boost::match_default) &&
result[0].matched)
91 const size_t field_val = 6;
92 const size_t field_etc_name = 4;
96 entry.m_content_disposition =
result[field_val];
98 entry.m_content_type =
result[field_val];
99 else if(
result[i++].matched)
100 entry.m_etc_header_fields.push_back(std::pair<std::string, std::string>(
result[field_etc_name],
result[field_val]));
103 LOG_ERROR(
"simple_http_connection_handler::parse_header() not matched last entry in:"<<std::string(it_current_bound, it_end));
114 std::string end_str =
"\r\n\r\n";
115 std::string::const_iterator end_header_it = std::search(it_begin, it_end, end_str.begin(), end_str.end());
116 if(end_header_it == it_end)
124 LOG_ERROR(
"Failed to parse header:" << std::string(it_begin, end_header_it+2));
128 entry.
m_body.assign(end_header_it+4, it_end);
134 bool parse_multipart_body(
const std::string& content_type,
const std::string& body, std::list<multipart_entry>& out_values)
138 std::string boundary;
141 MERROR(
"Failed to match boundary in content type: " << content_type);
146 bool is_stop =
false;
147 bool first_step =
true;
149 std::string::const_iterator it_begin = body.begin();
150 std::string::const_iterator it_end;
153 std::string::size_type pos = body.find(boundary, std::distance(body.begin(), it_begin));
155 if(std::string::npos == pos)
158 boundary.erase(boundary.size()-2, 2);
160 pos = body.find(boundary, std::distance(body.begin(), it_begin));
161 if(std::string::npos == pos)
163 MERROR(
"Error: Filed to match closing multipart tag");
167 it_end = body.begin() + pos;
170 it_end = body.begin() + pos;
173 if(first_step && !is_stop)
176 it_begin = it_end + boundary.size();
177 std::string temp =
"\r\n--";
178 boundary = temp + boundary;
182 out_values.push_back(multipart_entry());
185 MERROR(
"Failed to handle_part_of_multipart");
189 it_begin = it_end + boundary.size();
199 template<
class t_connection_context>
201 m_state(http_state_retriving_comand_line),
202 m_body_transfer_type(http_body_transfer_undefined),
203 m_is_stop_handling(
false),
210 m_psnd_hndlr(psnd_hndlr),
211 m_conn_context(conn_context),
217 template<
class t_connection_context>
225 if (m_config.m_connection_count)
226 --m_config.m_connection_count;
227 auto elem = m_config.m_connections.find(m_conn_context.m_remote_address.host_str());
228 if (elem != m_config.m_connections.end())
230 if (elem->second == 1 || elem->second == 0)
231 m_config.m_connections.erase(elem);
241 template<
class t_connection_context>
245 ++m_config.m_connections[m_conn_context.m_remote_address.host_str()];
246 ++m_config.m_connection_count;
247 m_initialized =
true;
251 template<
class t_connection_context>
254 m_is_stop_handling =
false;
255 m_state = http_state_retriving_comand_line;
256 m_body_transfer_type = http_body_transfer_undefined;
257 m_query_info.clear();
264 template<
class t_connection_context>
267 std::string
buf((
const char*)ptr, cb);
271 bool res = handle_buff_in(
buf);
277 template<
class t_connection_context>
283 m_bytes_read +=
buf.size();
284 if (m_bytes_read > m_config.m_max_content_length)
286 LOG_ERROR(
"simple_http_connection_handler::handle_buff_in: Too much data: got " << m_bytes_read);
287 m_state = http_state_error;
296 m_is_stop_handling =
false;
297 while(!m_is_stop_handling)
301 case http_state_retriving_comand_line:
308 ndel = m_cache.find_first_not_of(
"\r\n");
313 m_newlines += std::string::npos == ndel ? m_cache.size() : ndel;
316 LOG_ERROR(
"simple_http_connection_handler::handle_buff_out: Too many starting newlines");
317 m_state = http_state_error;
320 m_cache.erase(0, ndel);
324 if(std::string::npos != m_cache.find(
'\n', 0))
325 handle_invoke_query_line();
328 m_is_stop_handling =
true;
331 LOG_ERROR_CC(m_conn_context,
"simple_http_connection_handler::handle_buff_out: Too long URI line");
332 m_state = http_state_error;
337 case http_state_retriving_header:
339 std::string::size_type pos = match_end_of_header(m_cache);
340 if(std::string::npos == pos)
342 m_is_stop_handling =
true;
345 LOG_ERROR_CC(m_conn_context,
"simple_http_connection_handler::handle_buff_in: Too long header area");
346 m_state = http_state_error;
351 if (!analize_cached_request_header_and_invoke_state(pos))
355 case http_state_retriving_body:
356 return handle_retriving_query_body();
357 case http_state_connection_close:
360 LOG_ERROR_CC(m_conn_context,
"simple_http_connection_handler::handle_char_out: Wrong state: " << m_state);
362 case http_state_error:
363 LOG_ERROR_CC(m_conn_context,
"simple_http_connection_handler::handle_char_out: Error state!!!");
368 m_is_stop_handling =
true;
376 CHECK_AND_ASSERT_MES(
result[0].matched,
false,
"simple_http_connection_handler::analize_http_method() assert failed...");
377 if (!boost::conversion::try_lexical_convert<int>(
result[11], http_ver_major))
379 if (!boost::conversion::try_lexical_convert<int>(
result[12], http_ver_minor))
384 else if(
result[4].matched)
386 else if(
result[5].matched)
388 else if(
result[6].matched)
390 else if(
result[7].matched)
399 template<
class t_connection_context>
402 STATIC_REGEXP_EXPR_1(rexp_match_command_line,
"^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+)\\.(\\d+))\r?\n", boost::regex::icase | boost::regex::normal);
406 if(boost::regex_search(m_cache,
result, rexp_match_command_line, boost::match_default) &&
result[0].matched)
410 m_state = http_state_error;
411 MERROR(
"Failed to analyze method");
414 m_query_info.m_URI =
result[10];
415 if (!
parse_uri(m_query_info.m_URI, m_query_info.m_uri_content))
417 m_state = http_state_error;
418 MERROR(
"Failed to parse URI: m_query_info.m_URI");
421 m_query_info.m_http_method_str =
result[2];
422 m_query_info.m_full_request_str =
result[0];
424 m_cache.erase(m_cache.begin(),
result[0].second);
426 m_state = http_state_retriving_header;
431 m_state = http_state_error;
432 LOG_ERROR_CC(m_conn_context,
"simple_http_connection_handler<t_connection_context>::handle_invoke_query_line(): Failed to match first line: " << m_cache);
439 template<
class t_connection_context>
444 std::string::size_type
res =
buf.find(
"\r\n\r\n");
445 if(std::string::npos !=
res)
448 if(std::string::npos !=
res)
453 template<
class t_connection_context>
456 LOG_PRINT_L3(
"HTTP HEAD:\r\n" << m_cache.substr(0, pos));
458 m_query_info.m_full_request_buf_size = pos;
459 m_query_info.m_request_head.assign(m_cache.begin(), m_cache.begin()+pos);
461 if(!parse_cached_header(m_query_info.m_header_info, m_cache, pos))
463 LOG_ERROR_CC(m_conn_context,
"simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): failed to anilize request header: " << m_cache);
464 m_state = http_state_error;
468 m_cache.erase(0, pos);
470 std::string req_command_str = m_query_info.m_full_request_str;
473 if(m_query_info.m_header_info.m_content_length.size())
475 m_state = http_state_retriving_body;
476 m_body_transfer_type = http_body_transfer_measure;
477 if(!get_len_from_content_lenght(m_query_info.m_header_info.m_content_length, m_len_summary))
479 LOG_ERROR_CC(m_conn_context,
"simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<<m_query_info.m_header_info.m_content_length);
480 m_state = http_state_error;
483 if(0 == m_len_summary)
485 if(handle_request_and_send_response(m_query_info))
488 m_state = http_state_error;
490 m_len_remain = m_len_summary;
493 handle_request_and_send_response(m_query_info);
500 template<
class t_connection_context>
503 switch(m_body_transfer_type)
505 case http_body_transfer_measure:
506 return handle_query_measure();
507 case http_body_transfer_chunked:
508 case http_body_transfer_connection_close:
509 case http_body_transfer_multipart:
510 case http_body_transfer_undefined:
512 LOG_ERROR_CC(m_conn_context,
"simple_http_connection_handler<t_connection_context>::handle_retriving_query_body(): Unexpected m_body_query_type state:" << m_body_transfer_type);
513 m_state = http_state_error;
520 template<
class t_connection_context>
524 if(m_len_remain >= m_cache.size())
526 m_len_remain -= m_cache.size();
527 m_query_info.m_body += m_cache;
531 m_query_info.m_body.append(m_cache.begin(), m_cache.begin() + m_len_remain);
532 m_cache.erase(0, m_len_remain);
538 if(handle_request_and_send_response(m_query_info))
541 m_state = http_state_error;
546 template<
class t_connection_context>
550 "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)|(User-Agent)|(Origin)"
552 "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]",
554 boost::regex::icase | boost::regex::normal);
557 std::string::const_iterator it_current_bound = m_cache_to_process.begin();
558 std::string::const_iterator it_end_bound = m_cache_to_process.begin()+pos;
563 while( boost::regex_search( it_current_bound, it_end_bound,
result, rexp_mach_field, boost::match_default) &&
result[0].matched)
565 const size_t field_val = 14;
566 const size_t field_etc_name = 12;
571 else if(
result[i++].matched)
573 else if(
result[i++].matched)
575 else if(
result[i++].matched)
577 else if(
result[i++].matched)
579 else if(
result[i++].matched)
581 else if(
result[i++].matched)
583 else if(
result[i++].matched)
585 else if(
result[i++].matched)
587 else if(
result[i++].matched)
589 else if(
result[i++].matched)
593 LOG_ERROR_CC(m_conn_context,
"simple_http_connection_handler<t_connection_context>::parse_cached_header() not matched last entry in:" << m_cache_to_process);
601 template<
class t_connection_context>
607 if(!(boost::regex_search(
str,
result, rexp_mach_field, boost::match_default) &&
result[0].matched))
610 try { len = boost::lexical_cast<size_t>(
result[0]); }
611 catch(...) {
return false; }
615 template<
class t_connection_context>
624 res = handle_request(query_info, response);
625 if (response.m_response_code == 500)
632 response.m_response_code = 200;
633 response.m_response_comment =
"OK";
636 std::string response_data = get_response_header(response);
639 LOG_PRINT_L3(
"HTTP_RESPONSE_HEAD: << \r\n" << response_data);
642 response_data += response.m_body;
644 m_psnd_hndlr->do_send(
byte_slice{std::move(response_data)});
645 m_psnd_hndlr->send_done();
649 template<
class t_connection_context>
654 if(
"/" == uri_to_path)
655 uri_to_path =
"/index.html";
658 m_config.m_lock.lock();
659 std::string destination_file_path = m_config.m_folder + uri_to_path;
660 m_config.m_lock.unlock();
664 response.
m_body = get_not_found_response_body(query_info.
m_URI);
674 response.
m_mime_tipe = get_file_mime_tipe(uri_to_path);
679 template<
class t_connection_context>
682 std::string
buf =
"HTTP/1.1 ";
684 "Server: Epee-based\r\n"
686 buf += boost::lexical_cast<std::string>(response.
m_body.size()) +
"\r\n";
690 buf +=
"Content-Type: ";
694 buf +=
"Last-Modified: ";
698 buf +=
"Accept-Ranges: bytes\r\n";
702 if(m_query_info.m_header_info.m_connection.size())
707 buf +=
"Connection: close\r\n";
708 m_state = http_state_connection_close;
714 if(m_query_info.m_header_info.m_origin.size())
716 if (std::binary_search(m_config.m_access_control_origins.begin(), m_config.m_access_control_origins.end(),
"*") || std::binary_search(m_config.m_access_control_origins.begin(), m_config.m_access_control_origins.end(), m_query_info.m_header_info.m_origin))
718 buf +=
"Access-Control-Allow-Origin: ";
719 buf += m_query_info.m_header_info.m_origin;
721 buf +=
"Access-Control-Expose-Headers: www-authenticate\r\n";
723 buf +=
"Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With\r\n";
724 buf +=
"Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS\r\n";
730 buf += it->first +
": " + it->second +
"\r\n";
737 template<
class t_connection_context>
751 result =
"application/x-javascript";
755 result =
"application/xml";
763 template<
class t_connection_context>
767 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
769 "<title>404 Not Found</title>\r\n"
771 "<h1>Not Found</h1>\r\n"
772 "<p>The requested URL \r\n";
774 body +=
"was not found on this server.</p>\r\n"
775 "</body></html>\r\n";
780 template<
class t_connection_context>
783 for(std::string::iterator it =
str.begin(); it!=
str.end(); it++)
Definition byte_slice.h:69
bool get_len_from_content_lenght(const std::string &str, size_t &len)
Definition http_protocol_handler.inl:602
bool parse_cached_header(http_header_info &body_info, const std::string &m_cache_to_process, size_t pos)
Definition http_protocol_handler.inl:547
bool after_init_connection()
Definition http_protocol_handler.inl:242
virtual ~simple_http_connection_handler()
Definition http_protocol_handler.inl:218
bool handle_retriving_query_body()
Definition http_protocol_handler.inl:501
bool slash_to_back_slash(std::string &str)
Definition http_protocol_handler.inl:781
std::string get_file_mime_tipe(const std::string &path)
Definition http_protocol_handler.inl:738
bool handle_invoke_query_line()
Definition http_protocol_handler.inl:400
bool handle_buff_in(std::string &buf)
Definition http_protocol_handler.inl:278
bool handle_query_measure()
Definition http_protocol_handler.inl:521
bool set_ready_state()
Definition http_protocol_handler.inl:252
bool handle_request_and_send_response(const http::http_request_info &query_info)
Definition http_protocol_handler.inl:616
bool analize_cached_request_header_and_invoke_state(size_t pos)
Definition http_protocol_handler.inl:454
std::string get_response_header(const http_response_info &response)
Definition http_protocol_handler.inl:680
std::string::size_type match_end_of_header(const std::string &buf)
Definition http_protocol_handler.inl:440
virtual bool handle_request(const http::http_request_info &query_info, http_response_info &response)
Definition http_protocol_handler.inl:650
virtual bool handle_recv(const void *ptr, size_t cb)
Definition http_protocol_handler.inl:265
std::string get_not_found_response_body(const std::string &URI)
Definition http_protocol_handler.inl:764
simple_http_connection_handler(i_service_endpoint *psnd_hndlr, config_type &config, t_connection_context &conn_context)
Definition http_protocol_handler.inl:200
const char * res
Definition hmac_keccak.cpp:42
#define HTTP_MAX_STARTING_NEWLINES
Definition http_protocol_handler.inl:42
#define HTTP_MAX_URI_LEN
Definition http_protocol_handler.inl:40
#define HTTP_MAX_HEADER_LEN
Definition http_protocol_handler.inl:41
Definition cryptonote_config.h:221
bool load_file_to_string(const std::string &path_to_file, std::string &target_str, size_t max_size=1000000000)
Definition file_io_utils.cpp:105
std::string get_internet_time_str(const time_t &time_)
Definition time_helper.h:49
Definition abstract_http_client.h:60
http_method
Definition http_base.h:49
@ http_method_head
Definition http_base.h:54
@ http_method_etc
Definition http_base.h:55
@ http_method_put
Definition http_base.h:53
@ http_method_get
Definition http_base.h:51
@ http_method_post
Definition http_base.h:52
@ http_method_options
Definition http_base.h:50
bool match_boundary(const std::string &content_type, std::string &boundary)
Definition http_protocol_handler.inl:60
bool parse_header(std::string::const_iterator it_begin, std::string::const_iterator it_end, multipart_entry &entry)
Definition http_protocol_handler.inl:75
bool parse_multipart_body(const std::string &content_type, const std::string &body, std::list< multipart_entry > &out_values)
Definition http_protocol_handler.inl:134
bool analize_http_method(const boost::smatch &result, http::http_method &method, int &http_ver_major, int &http_ver_minor)
Definition http_protocol_handler.inl:374
bool handle_part_of_multipart(std::string::const_iterator it_begin, std::string::const_iterator it_end, multipart_entry &entry)
Definition http_protocol_handler.inl:112
bool parse_uri(const std::string uri, http::uri_content &content)
Definition net_parse_helpers.cpp:102
TODO: (mj-xmr) This will be reduced in an another PR.
Definition byte_slice.h:40
#define LOG_ERROR_CC(ct, message)
Definition net_utils_base.h:469
const char *const str
Definition portlistingparse.c:23
#define STATIC_REGEXP_EXPR_1(var_name, xpr_text, reg_exp_flags)
Definition reg_exp_definer.h:48
tools::wallet2::message_signature_result_t result
Definition signature.cpp:62
const char * buf
Definition slow_memmem.cpp:73
#define false
Definition stdbool.h:37
Definition http_base.h:133
std::string m_full_request_str
Definition http_base.h:144
uri_content m_uri_content
Definition http_base.h:151
http_method m_http_method
Definition http_base.h:141
std::string m_URI
Definition http_base.h:142
Definition http_base.h:164
std::string m_response_comment
Definition http_base.h:166
std::string m_mime_tipe
Definition http_base.h:169
int m_response_code
Definition http_base.h:165
std::string m_body
Definition http_base.h:168
fields_list m_additional_fields
Definition http_base.h:167
Definition http_protocol_handler.h:55
Definition http_protocol_handler.inl:52
std::string m_body
Definition http_protocol_handler.inl:56
std::list< std::pair< std::string, std::string > > m_etc_header_fields
Definition http_protocol_handler.inl:53
std::string m_content_type
Definition http_protocol_handler.inl:55
std::string m_content_disposition
Definition http_protocol_handler.inl:54
std::string m_path
Definition http_base.h:116
Definition net_utils_base.h:442
#define CRITICAL_REGION_LOCAL(x)
Definition syncobj.h:153