aboutsummaryrefslogtreecommitdiff
path: root/contrib/epee/include
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/epee/include')
-rw-r--r--contrib/epee/include/misc_log_ex.h6
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl4
-rwxr-xr-x[-rw-r--r--]contrib/epee/include/net/http_base.h3
-rwxr-xr-x[-rw-r--r--]contrib/epee/include/net/http_client.h24
-rwxr-xr-x[-rw-r--r--]contrib/epee/include/net/http_protocol_handler.h2
-rwxr-xr-x[-rw-r--r--]contrib/epee/include/net/http_protocol_handler.inl55
-rwxr-xr-x[-rw-r--r--]contrib/epee/include/net/http_server_handlers_map2.h0
-rwxr-xr-x[-rw-r--r--]contrib/epee/include/net/http_server_impl_base.h5
-rw-r--r--contrib/epee/include/net/net_helper.h148
-rw-r--r--contrib/epee/include/serialization/keyvalue_serialization_overloads.h46
-rw-r--r--contrib/epee/include/storages/http_abstract_invoke.h5
-rw-r--r--contrib/epee/include/storages/portable_storage_val_converters.h27
-rw-r--r--contrib/epee/include/string_tools.h6
13 files changed, 258 insertions, 73 deletions
diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h
index 982aaea06..7ac07d112 100644
--- a/contrib/epee/include/misc_log_ex.h
+++ b/contrib/epee/include/misc_log_ex.h
@@ -105,9 +105,9 @@
#define _dbg2(x) MDEBUG(x)
#define _dbg1(x) MDEBUG(x)
#define _info(x) MINFO(x)
-#define _note(x) MINFO(x)
-#define _fact(x) MINFO(x)
-#define _mark(x) MINFO(x)
+#define _note(x) MDEBUG(x)
+#define _fact(x) MDEBUG(x)
+#define _mark(x) MDEBUG(x)
#define _warn(x) MWARNING(x)
#define _erro(x) MERROR(x)
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index 94ef7c3b3..00d03567c 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -80,7 +80,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
m_throttle_speed_in("speed_in", "throttle_speed_in"),
m_throttle_speed_out("speed_out", "throttle_speed_out")
{
- MINFO("test, connection constructor set m_connection_type="<<m_connection_type);
+ MDEBUG("test, connection constructor set m_connection_type="<<m_connection_type);
}
PRAGMA_WARNING_DISABLE_VS(4355)
//---------------------------------------------------------------------------------
@@ -264,7 +264,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
address = endpoint.address().to_string();
port = boost::lexical_cast<std::string>(endpoint.port());
}
- MINFO(" connection type " << to_string( m_connection_type ) << " "
+ MDEBUG(" connection type " << to_string( m_connection_type ) << " "
<< socket_.local_endpoint().address().to_string() << ":" << socket_.local_endpoint().port()
<< " <--> " << address << ":" << port);
}
diff --git a/contrib/epee/include/net/http_base.h b/contrib/epee/include/net/http_base.h
index 144acad9d..a66fb7c23 100644..100755
--- a/contrib/epee/include/net/http_base.h
+++ b/contrib/epee/include/net/http_base.h
@@ -46,6 +46,7 @@ namespace net_utils
{
enum http_method{
+ http_method_options,
http_method_get,
http_method_post,
http_method_put,
@@ -115,6 +116,7 @@ namespace net_utils
std::string m_host; //"Host:"
std::string m_cookie; //"Cookie:"
std::string m_user_agent; //"User-Agent:"
+ std::string m_origin; //"Origin:"
fields_list m_etc_fields;
void clear()
@@ -128,6 +130,7 @@ namespace net_utils
m_host.clear();
m_cookie.clear();
m_user_agent.clear();
+ m_origin.clear();
m_etc_fields.clear();
}
};
diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h
index 8e099e2bc..80a4504e3 100644..100755
--- a/contrib/epee/include/net/http_client.h
+++ b/contrib/epee/include/net/http_client.h
@@ -274,6 +274,7 @@ using namespace std;
chunked_state m_chunked_state;
std::string m_chunked_cache;
critical_section m_lock;
+ bool m_ssl;
public:
explicit http_simple_client()
@@ -291,33 +292,35 @@ using namespace std;
, m_chunked_state()
, m_chunked_cache()
, m_lock()
+ , m_ssl(false)
{}
const std::string &get_host() const { return m_host_buff; };
const std::string &get_port() const { return m_port; };
- bool set_server(const std::string& address, boost::optional<login> user)
+ bool set_server(const std::string& address, boost::optional<login> user, bool ssl = false)
{
http::url_content parsed{};
const bool r = parse_url(address, parsed);
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
- set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user));
+ set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), ssl);
return true;
}
- void set_server(std::string host, std::string port, boost::optional<login> user)
+ void set_server(std::string host, std::string port, boost::optional<login> user, bool ssl = false)
{
CRITICAL_REGION_LOCAL(m_lock);
disconnect();
m_host_buff = std::move(host);
m_port = std::move(port);
m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{};
+ m_ssl = ssl;
}
bool connect(std::chrono::milliseconds timeout)
{
CRITICAL_REGION_LOCAL(m_lock);
- return m_net_client.connect(m_host_buff, m_port, timeout);
+ return m_net_client.connect(m_host_buff, m_port, timeout, m_ssl);
}
//---------------------------------------------------------------------------
bool disconnect()
@@ -392,7 +395,6 @@ using namespace std;
res = m_net_client.send(body, timeout);
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
-
m_response_info.clear();
m_state = reciev_machine_state_header;
if (!handle_reciev(timeout))
@@ -747,10 +749,10 @@ using namespace std;
MTRACE("http_stream_filter::parse_cached_header(*)");
STATIC_REGEXP_EXPR_1(rexp_mach_field,
- "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)|(User-Agent)"
- // 12 3 4 5 6 7 8 9 10
+ "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)|(User-Agent)|(Origin)"
+ // 12 3 4 5 6 7 8 9 10 11
"|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]",
- //11 1213 14
+ //12 13 14 15
boost::regex::icase | boost::regex::normal);
boost::smatch result;
@@ -762,7 +764,7 @@ using namespace std;
//lookup all fields and fill well-known fields
while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched)
{
- const size_t field_val = 13;
+ const size_t field_val = 14;
//const size_t field_etc_name = 11;
int i = 2; //start position = 2
@@ -786,8 +788,10 @@ using namespace std;
body_info.m_cookie = result[field_val];
else if(result[i++].matched)//"User-Agent"
body_info.m_user_agent = result[field_val];
+ else if(result[i++].matched)//"Origin"
+ body_info.m_origin = result[field_val];
else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!)
- body_info.m_etc_fields.emplace_back(result[11], result[field_val]);
+ body_info.m_etc_fields.emplace_back(result[12], result[field_val]);
else
{CHECK_AND_ASSERT_MES(false, false, "http_stream_filter::parse_cached_header() not matched last entry in:"<<m_cache_to_process);}
diff --git a/contrib/epee/include/net/http_protocol_handler.h b/contrib/epee/include/net/http_protocol_handler.h
index babe49ad7..652d8ff6f 100644..100755
--- a/contrib/epee/include/net/http_protocol_handler.h
+++ b/contrib/epee/include/net/http_protocol_handler.h
@@ -54,6 +54,7 @@ namespace net_utils
struct http_server_config
{
std::string m_folder;
+ std::vector<std::string> m_access_control_origins;
boost::optional<login> m_user;
critical_section m_lock;
};
@@ -193,6 +194,7 @@ namespace net_utils
response.m_response_code = 200;
response.m_response_comment = "OK";
response.m_body.clear();
+
return m_config.m_phandler->handle_http_request(query_info, response, m_conn_context);
}
diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl
index c92a13bcc..c3350bf73 100644..100755
--- a/contrib/epee/include/net/http_protocol_handler.inl
+++ b/contrib/epee/include/net/http_protocol_handler.inl
@@ -316,7 +316,10 @@ namespace net_utils
CHECK_AND_ASSERT_MES(result[0].matched, false, "simple_http_connection_handler::analize_http_method() assert failed...");
http_ver_major = boost::lexical_cast<int>(result[11]);
http_ver_minor = boost::lexical_cast<int>(result[12]);
- if(result[4].matched)
+
+ if(result[3].matched)
+ method = http::http_method_options;
+ else if(result[4].matched)
method = http::http_method_get;
else if(result[5].matched)
method = http::http_method_head;
@@ -472,8 +475,8 @@ namespace net_utils
bool simple_http_connection_handler<t_connection_context>::parse_cached_header(http_header_info& body_info, const std::string& m_cache_to_process, size_t pos)
{
STATIC_REGEXP_EXPR_1(rexp_mach_field,
- "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)|(User-Agent)"
- // 12 3 4 5 6 7 8 9 10
+ "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)|(User-Agent)|(Origin)"
+ // 12 3 4 5 6 7 8 9 10 11
"|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]",
//11 1213 14
boost::regex::icase | boost::regex::normal);
@@ -487,8 +490,8 @@ namespace net_utils
//lookup all fields and fill well-known fields
while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched)
{
- const size_t field_val = 13;
- const size_t field_etc_name = 11;
+ const size_t field_val = 14;
+ const size_t field_etc_name = 12;
int i = 2; //start position = 2
if(result[i++].matched)//"Connection"
@@ -509,6 +512,8 @@ namespace net_utils
body_info.m_cookie = result[field_val];
else if(result[i++].matched)//"User-Agent"
body_info.m_user_agent = result[field_val];
+ else if(result[i++].matched)//"Origin"
+ body_info.m_origin = result[field_val];
else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!)
body_info.m_etc_fields.push_back(std::pair<std::string, std::string>(result[field_etc_name], result[field_val]));
else
@@ -537,17 +542,27 @@ namespace net_utils
template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::handle_request_and_send_response(const http::http_request_info& query_info)
{
- http_response_info response;
- bool res = handle_request(query_info, response);
+ http_response_info response{};
//CHECK_AND_ASSERT_MES(res, res, "handle_request(query_info, response) returned false" );
+ bool res = true;
+
+ if (query_info.m_http_method != http::http_method_options)
+ {
+ res = handle_request(query_info, response);
+ }
+ else
+ {
+ response.m_response_code = 200;
+ response.m_response_comment = "OK";
+ }
std::string response_data = get_response_header(response);
-
//LOG_PRINT_L0("HTTP_SEND: << \r\n" << response_data + response.m_body);
+
LOG_PRINT_L3("HTTP_RESPONSE_HEAD: << \r\n" << response_data);
m_psnd_hndlr->do_send((void*)response_data.data(), response_data.size());
- if(response.m_body.size() && (query_info.m_http_method != http::http_method_head))
+ if ((response.m_body.size() && (query_info.m_http_method != http::http_method_head)) || (query_info.m_http_method == http::http_method_options))
m_psnd_hndlr->do_send((void*)response.m_body.data(), response.m_body.size());
return res;
}
@@ -579,7 +594,6 @@ namespace net_utils
response.m_response_comment = "OK";
response.m_mime_tipe = get_file_mime_tipe(uri_to_path);
-
return true;
}
//-----------------------------------------------------------------------------------
@@ -591,8 +605,12 @@ namespace net_utils
"Server: Epee-based\r\n"
"Content-Length: ";
buf += boost::lexical_cast<std::string>(response.m_body.size()) + "\r\n";
- buf += "Content-Type: ";
- buf += response.m_mime_tipe + "\r\n";
+
+ if(!response.m_mime_tipe.empty())
+ {
+ buf += "Content-Type: ";
+ buf += response.m_mime_tipe + "\r\n";
+ }
buf += "Last-Modified: ";
time_t tm;
@@ -612,6 +630,19 @@ namespace net_utils
m_want_close = true;
}
}
+
+ // Cross-origin resource sharing
+ if(m_query_info.m_header_info.m_origin.size())
+ {
+ if (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))
+ {
+ buf += "Access-Control-Allow-Origin: ";
+ buf += m_query_info.m_header_info.m_origin;
+ buf += "\r\n";
+ buf += "Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS\r\n";
+ }
+ }
+
//add additional fields, if it is
for(fields_list::const_iterator it = response.m_additional_fields.begin(); it!=response.m_additional_fields.end(); it++)
buf += it->first + ":" + it->second + "\r\n";
diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h
index 429e3e1af..429e3e1af 100644..100755
--- a/contrib/epee/include/net/http_server_handlers_map2.h
+++ b/contrib/epee/include/net/http_server_handlers_map2.h
diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h
index acecbb2d4..0788c6a4b 100644..100755
--- a/contrib/epee/include/net/http_server_impl_base.h
+++ b/contrib/epee/include/net/http_server_impl_base.h
@@ -56,6 +56,7 @@ namespace epee
{}
bool init(const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0",
+ std::vector<std::string> access_control_origins = std::vector<std::string>(),
boost::optional<net_utils::http::login> user = boost::none)
{
@@ -65,6 +66,10 @@ namespace epee
//here set folder for hosting reqests
m_net_server.get_config_object().m_folder = "";
+ //set access control allow origins if configured
+ std::sort(access_control_origins.begin(), access_control_origins.end());
+ m_net_server.get_config_object().m_access_control_origins = std::move(access_control_origins);
+
m_net_server.get_config_object().m_user = std::move(user);
MGINFO("Binding on " << bind_ip << ":" << bind_port);
diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h
index 1d808cc4c..ee0e13fc1 100644
--- a/contrib/epee/include/net/net_helper.h
+++ b/contrib/epee/include/net/net_helper.h
@@ -36,7 +36,9 @@
#include <istream>
#include <ostream>
#include <string>
+#include <boost/version.hpp>
#include <boost/asio.hpp>
+#include <boost/asio/ssl.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/preprocessor/selection/min.hpp>
#include <boost/lambda/bind.hpp>
@@ -85,11 +87,13 @@ namespace net_utils
public:
inline
- blocked_mode_client():m_socket(m_io_service),
- m_initialized(false),
+ blocked_mode_client():m_initialized(false),
m_connected(false),
m_deadline(m_io_service),
- m_shutdowned(0)
+ m_shutdowned(0),
+ m_ssl(false),
+ m_ctx(boost::asio::ssl::context::sslv23),
+ m_ssl_socket(m_io_service,m_ctx)
{
@@ -113,18 +117,25 @@ namespace net_utils
}
inline
- bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
+ bool connect(const std::string& addr, int port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0")
{
- return connect(addr, std::to_string(port), timeout, bind_ip);
+ return connect(addr, std::to_string(port), timeout, ssl, bind_ip);
}
inline
- bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, const std::string& bind_ip = "0.0.0.0")
+ bool connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout, bool ssl = false, const std::string& bind_ip = "0.0.0.0")
{
m_connected = false;
+ m_ssl = ssl;
try
{
- m_socket.close();
+ m_ssl_socket.next_layer().close();
+
+ // Set SSL options
+ // disable sslv2
+ m_ctx.set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2);
+ m_ctx.set_default_verify_paths();
+
// Get a list of endpoints corresponding to the server name.
@@ -147,11 +158,11 @@ namespace net_utils
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
- m_socket.open(remote_endpoint.protocol());
+ m_ssl_socket.next_layer().open(remote_endpoint.protocol());
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
{
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0);
- m_socket.bind(local_endpoint);
+ m_ssl_socket.next_layer().bind(local_endpoint);
}
@@ -160,17 +171,24 @@ namespace net_utils
boost::system::error_code ec = boost::asio::error::would_block;
- //m_socket.connect(remote_endpoint);
- m_socket.async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1);
+ m_ssl_socket.next_layer().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1);
while (ec == boost::asio::error::would_block)
{
m_io_service.run_one();
}
- if (!ec && m_socket.is_open())
+ if (!ec && m_ssl_socket.next_layer().is_open())
{
m_connected = true;
m_deadline.expires_at(std::chrono::steady_clock::time_point::max());
+ // SSL Options
+ if(m_ssl) {
+ // Disable verification of host certificate
+ m_ssl_socket.set_verify_mode(boost::asio::ssl::verify_peer);
+ // Handshake
+ m_ssl_socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true));
+ m_ssl_socket.handshake(boost::asio::ssl::stream_base::client);
+ }
return true;
}else
{
@@ -193,7 +211,6 @@ namespace net_utils
return true;
}
-
inline
bool disconnect()
{
@@ -202,8 +219,9 @@ namespace net_utils
if(m_connected)
{
m_connected = false;
- m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
-
+ if(m_ssl)
+ shutdown_ssl();
+ m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both);
}
}
@@ -240,7 +258,7 @@ namespace net_utils
// object is used as a callback and will update the ec variable when the
// operation completes. The blocking_udp_client.cpp example shows how you
// can use boost::bind rather than boost::lambda.
- boost::asio::async_write(m_socket, boost::asio::buffer(buff), boost::lambda::var(ec) = boost::lambda::_1);
+ async_write(buff.c_str(), buff.size(), ec);
// Block until the asynchronous operation has completed.
while (ec == boost::asio::error::would_block)
@@ -302,9 +320,7 @@ namespace net_utils
*/
boost::system::error_code ec;
- size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec);
-
-
+ size_t writen = write(data, sz, ec);
if (!writen || ec)
{
@@ -334,10 +350,7 @@ namespace net_utils
bool is_connected()
{
- return m_connected && m_socket.is_open();
- //TRY_ENTRY()
- //return m_socket.is_open();
- //CATCH_ENTRY_L0("is_connected", false)
+ return m_connected && m_ssl_socket.next_layer().is_open();
}
inline
@@ -369,8 +382,8 @@ namespace net_utils
handler_obj hndlr(ec, bytes_transfered);
char local_buff[10000] = {0};
- //m_socket.async_read_some(boost::asio::buffer(local_buff, sizeof(local_buff)), hndlr);
- boost::asio::async_read(m_socket, boost::asio::buffer(local_buff, sizeof(local_buff)), boost::asio::transfer_at_least(1), hndlr);
+
+ async_read(local_buff, sizeof(local_buff), boost::asio::transfer_at_least(1), hndlr);
// Block until the asynchronous operation has completed.
while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned))
@@ -451,10 +464,8 @@ namespace net_utils
handler_obj hndlr(ec, bytes_transfered);
-
- //char local_buff[10000] = {0};
- boost::asio::async_read(m_socket, boost::asio::buffer((char*)buff.data(), buff.size()), boost::asio::transfer_at_least(buff.size()), hndlr);
-
+ async_read((char*)buff.data(), buff.size(), boost::asio::transfer_at_least(buff.size()), hndlr);
+
// Block until the asynchronous operation has completed.
while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned))
{
@@ -500,10 +511,18 @@ namespace net_utils
bool shutdown()
{
m_deadline.cancel();
- boost::system::error_code ignored_ec;
- m_socket.cancel(ignored_ec);
- m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
- m_socket.close(ignored_ec);
+ boost::system::error_code ec;
+ if(m_ssl)
+ shutdown_ssl();
+ m_ssl_socket.next_layer().cancel(ec);
+ if(ec)
+ MDEBUG("Problems at cancel: " << ec.message());
+ m_ssl_socket.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
+ if(ec)
+ MDEBUG("Problems at shutdown: " << ec.message());
+ m_ssl_socket.next_layer().close(ec);
+ if(ec)
+ MDEBUG("Problems at close: " << ec.message());
boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1);
m_connected = false;
return true;
@@ -520,7 +539,7 @@ namespace net_utils
boost::asio::ip::tcp::socket& get_socket()
{
- return m_socket;
+ return m_ssl_socket.next_layer();
}
private:
@@ -537,7 +556,7 @@ namespace net_utils
// connect(), read_line() or write_line() functions to return.
LOG_PRINT_L3("Timed out socket");
m_connected = false;
- m_socket.close();
+ m_ssl_socket.next_layer().close();
// There is no longer an active deadline. The expiry is set to positive
// infinity so that the actor takes no action until a new deadline is set.
@@ -547,12 +566,61 @@ namespace net_utils
// Put the actor back to sleep.
m_deadline.async_wait(boost::bind(&blocked_mode_client::check_deadline, this));
}
-
+ void shutdown_ssl() {
+ // ssl socket shutdown blocks if server doesn't respond. We close after 2 secs
+ boost::system::error_code ec = boost::asio::error::would_block;
+ m_deadline.expires_from_now(std::chrono::milliseconds(2000));
+ m_ssl_socket.async_shutdown(boost::lambda::var(ec) = boost::lambda::_1);
+ while (ec == boost::asio::error::would_block)
+ {
+ m_io_service.run_one();
+ }
+ // Ignore "short read" error
+ if (ec.category() == boost::asio::error::get_ssl_category() &&
+ ec.value() !=
+#if BOOST_VERSION >= 106200
+ boost::asio::ssl::error::stream_truncated
+#else // older Boost supports only OpenSSL 1.0, so 1.0-only macros are appropriate
+ ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ)
+#endif
+ )
+ MDEBUG("Problems at ssl shutdown: " << ec.message());
+ }
+
+ protected:
+ bool write(const void* data, size_t sz, boost::system::error_code& ec)
+ {
+ bool success;
+ if(m_ssl)
+ success = boost::asio::write(m_ssl_socket, boost::asio::buffer(data, sz), ec);
+ else
+ success = boost::asio::write(m_ssl_socket.next_layer(), boost::asio::buffer(data, sz), ec);
+ return success;
+ }
+
+ void async_write(const void* data, size_t sz, boost::system::error_code& ec)
+ {
+ if(m_ssl)
+ boost::asio::async_write(m_ssl_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
+ else
+ boost::asio::async_write(m_ssl_socket.next_layer(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
+ }
+
+ void async_read(char* buff, size_t sz, boost::asio::detail::transfer_at_least_t transfer_at_least, handler_obj& hndlr)
+ {
+ if(!m_ssl)
+ boost::asio::async_read(m_ssl_socket.next_layer(), boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
+ else
+ boost::asio::async_read(m_ssl_socket, boost::asio::buffer(buff, sz), transfer_at_least, hndlr);
+
+ }
protected:
boost::asio::io_service m_io_service;
- boost::asio::ip::tcp::socket m_socket;
+ boost::asio::ssl::context m_ctx;
+ boost::asio::ssl::stream<boost::asio::ip::tcp::socket> m_ssl_socket;
+ bool m_ssl;
bool m_initialized;
bool m_connected;
boost::asio::steady_timer m_deadline;
@@ -618,8 +686,8 @@ namespace net_utils
boost::system::error_code ec;
- size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec);
-
+ size_t writen = write(data, sz, ec);
+
if (!writen || ec)
{
LOG_PRINT_L3("Problems at write: " << ec.message());
@@ -660,7 +728,7 @@ namespace net_utils
// asynchronous operations are cancelled. This allows the blocked
// connect(), read_line() or write_line() functions to return.
LOG_PRINT_L3("Timed out socket");
- m_socket.close();
+ m_ssl_socket.next_layer().close();
// There is no longer an active deadline. The expiry is set to positive
// infinity so that the actor takes no action until a new deadline is set.
diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
index 4423f2608..a94ecacc5 100644
--- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
+++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
@@ -117,9 +117,9 @@ namespace epee
typename stl_container::value_type exchange_val;
typename t_storage::harray hval_array = stg.get_first_value(pname, exchange_val, hparent_section);
if(!hval_array) return false;
- container.push_back(std::move(exchange_val));
+ container.insert(container.end(), std::move(exchange_val));
while(stg.get_next_value(hval_array, exchange_val))
- container.push_back(std::move(exchange_val));
+ container.insert(container.end(), std::move(exchange_val));
return true;
}//--------------------------------------------------------------------------------------------------------------------
template<class stl_container, class t_storage>
@@ -152,7 +152,7 @@ namespace epee
"size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type));
size_t count = (loaded_size/sizeof(typename stl_container::value_type));
for(size_t i = 0; i < count; i++)
- container.push_back(*(pelem++));
+ container.insert(container.end(), *(pelem++));
}
return res;
}
@@ -186,12 +186,12 @@ namespace epee
typename t_storage::harray hsec_array = stg.get_first_section(pname, hchild_section, hparent_section);
if(!hsec_array || !hchild_section) return false;
res = val._load(stg, hchild_section);
- container.push_back(val);
+ container.insert(container.end(), val);
while(stg.get_next_section(hsec_array, hchild_section))
{
typename stl_container::value_type val_l = typename stl_container::value_type();
res |= val_l._load(stg, hchild_section);
- container.push_back(std::move(val_l));
+ container.insert(container.end(), std::move(val_l));
}
return res;
}
@@ -250,6 +250,18 @@ namespace epee
return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
}
//-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return serialize_stl_container_t_val(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return unserialize_stl_container_t_val(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
};
template<>
struct kv_serialization_overloads_impl_is_base_serializable_types<false>
@@ -302,6 +314,18 @@ namespace epee
{
return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
}
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return serialize_stl_container_t_obj(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ static bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return unserialize_stl_container_t_obj(d, stg, hparent_section, pname);
+ }
};
template<class t_storage>
struct base_serializable_types: public boost::mpl::vector<uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string, typename t_storage::meta_entry>::type
@@ -399,5 +423,17 @@ namespace epee
{
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
}
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ bool kv_serialize(const std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_serialize(d, stg, hparent_section, pname);
+ }
+ //-------------------------------------------------------------------------------------------------------------------
+ template<class t_type, class t_storage>
+ bool kv_unserialize(std::set<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
+ {
+ return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
+ }
}
}
diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h
index 823ce6731..6517f1253 100644
--- a/contrib/epee/include/storages/http_abstract_invoke.h
+++ b/contrib/epee/include/storages/http_abstract_invoke.h
@@ -44,8 +44,11 @@ namespace epee
if(!serialization::store_t_to_json(out_struct, req_param))
return false;
+ http::fields_list additional_params;
+ additional_params.push_back(std::make_pair("Content-Type","application/json; charset=utf-8"));
+
const http::http_response_info* pri = NULL;
- if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri)))
+ if(!transport.invoke(uri, method, req_param, timeout, std::addressof(pri), std::move(additional_params)))
{
LOG_PRINT_L1("Failed to invoke http request to " << uri);
return false;
diff --git a/contrib/epee/include/storages/portable_storage_val_converters.h b/contrib/epee/include/storages/portable_storage_val_converters.h
index e9b91c82b..f4a16cfae 100644
--- a/contrib/epee/include/storages/portable_storage_val_converters.h
+++ b/contrib/epee/include/storages/portable_storage_val_converters.h
@@ -28,6 +28,8 @@
#pragma once
+#include <regex>
+
#include "misc_language.h"
#include "portable_storage_base.h"
#include "warnings.h"
@@ -131,6 +133,31 @@ POP_WARNINGS
}
};
+ // For MyMonero/OpenMonero backend compatibility
+ // MyMonero backend sends amount, fees and timestamp values as strings.
+ // Until MM backend is updated, this is needed for compatibility between OpenMonero and MyMonero.
+ template<>
+ struct convert_to_integral<std::string, uint64_t, false>
+ {
+ static void convert(const std::string& from, uint64_t& to)
+ {
+ MTRACE("Converting std::string to uint64_t. Source: " << from);
+ // String only contains digits
+ if(std::all_of(from.begin(), from.end(), ::isdigit))
+ to = boost::lexical_cast<uint64_t>(from);
+ // MyMonero ISO 8061 timestamp (2017-05-06T16:27:06Z)
+ else if (std::regex_match (from, std::regex("\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\dZ")))
+ {
+ // Convert to unix timestamp
+ std::tm tm = {};
+ std::istringstream ss(from);
+ if (ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S"))
+ to = std::mktime(&tm);
+ } else
+ ASSERT_AND_THROW_WRONG_CONVERSION();
+ }
+ };
+
template<class from_type, class to_type>
struct is_convertable: std::integral_constant<bool,
std::is_integral<to_type>::value &&
diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h
index ce7b2fb87..25639263c 100644
--- a/contrib/epee/include/string_tools.h
+++ b/contrib/epee/include/string_tools.h
@@ -39,6 +39,7 @@
#include <cstdlib>
#include <string>
#include <type_traits>
+#include <regex>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>
@@ -349,6 +350,11 @@ POP_WARNINGS
s = *(t_pod_type*)bin_buff.data();
return true;
}
+ //----------------------------------------------------------------------------
+ inline bool validate_hex(uint64_t length, const std::string& str)
+ {
+ return std::regex_match(str, std::regex("'^[0-9abcdefABCDEF]+$'")) && str.size() == length;
+ }
//----------------------------------------------------------------------------
inline std::string get_extension(const std::string& str)
{