From 82935acd86ab7287acfdd3b0ed3f517b3b99274f Mon Sep 17 00:00:00 2001 From: John Jones Date: Thu, 23 May 2019 09:56:11 -0500 Subject: [PATCH 01/23] Add host information to log messages --- include/fc/network/http/websocket.hpp | 5 +- src/network/http/websocket.cpp | 121 +++++++++++--------------- tests/network/http/websocket_test.cpp | 7 ++ 3 files changed, 63 insertions(+), 70 deletions(-) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index 11db65ccb..675c3e9cf 100644 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -30,6 +30,7 @@ namespace fc { namespace http { boost::any& get_session_data() { return _session_data; } virtual std::string get_request_header(const std::string& key) = 0; + virtual std::string get_host() = 0; fc::signal closed; private: @@ -44,7 +45,7 @@ namespace fc { namespace http { class websocket_server { public: - websocket_server(); + websocket_server( std::string host_header_key = std::string() ); ~websocket_server(); void on_connection( const on_connection_handler& handler); @@ -66,7 +67,7 @@ namespace fc { namespace http { { public: websocket_tls_server( const std::string& server_pem = std::string(), - const std::string& ssl_password = std::string()); + const std::string& ssl_password = std::string(), std::string host_header_key = std::string() ); ~websocket_tls_server(); void on_connection( const on_connection_handler& handler); diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 6d479bfe9..8e29030a8 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -40,14 +40,6 @@ namespace fc { namespace http { typedef base::con_msg_manager_type con_msg_manager_type; typedef base::endpoint_msg_manager_type endpoint_msg_manager_type; - /// Custom Logging policies - /*typedef websocketpp::log::syslog elog_type; - typedef websocketpp::log::syslog alog_type; - */ - //typedef base::alog_type alog_type; - //typedef base::elog_type elog_type; typedef websocketpp::log::stub elog_type; typedef websocketpp::log::stub alog_type; @@ -91,14 +83,6 @@ namespace fc { namespace http { typedef base::con_msg_manager_type con_msg_manager_type; typedef base::endpoint_msg_manager_type endpoint_msg_manager_type; - /// Custom Logging policies - /*typedef websocketpp::log::syslog elog_type; - typedef websocketpp::log::syslog alog_type; - */ - //typedef base::alog_type alog_type; - //typedef base::elog_type elog_type; typedef websocketpp::log::stub elog_type; typedef websocketpp::log::stub alog_type; @@ -131,8 +115,6 @@ namespace fc { namespace http { typedef base::con_msg_manager_type con_msg_manager_type; typedef base::endpoint_msg_manager_type endpoint_msg_manager_type; - //typedef base::alog_type alog_type; - //typedef base::elog_type elog_type; typedef websocketpp::log::stub elog_type; typedef websocketpp::log::stub alog_type; @@ -151,10 +133,6 @@ namespace fc { namespace http { transport_type; }; - - - - using websocketpp::connection_hdl; typedef websocketpp::server websocket_server_type; typedef websocketpp::server websocket_tls_server_type; @@ -163,21 +141,19 @@ namespace fc { namespace http { class websocket_connection_impl : public websocket_connection { public: - websocket_connection_impl( T con ) - :_ws_connection(con){ + websocket_connection_impl( T con, std::string host_header_key = std::string() ) + :_ws_connection(con), host_header_key(host_header_key) { } - ~websocket_connection_impl() - { - } + ~websocket_connection_impl() {} virtual void send_message( const std::string& message )override { idump((message)); - //std::cerr<<"send: "<send( message ); FC_ASSERT( !ec, "websocket send failed: ${msg}", ("msg",ec.message() ) ); } + virtual void close( int64_t code, const std::string& reason )override { _ws_connection->close(code,reason); @@ -188,7 +164,19 @@ namespace fc { namespace http { return _ws_connection->get_request_header(key); } + virtual std::string get_host() override + { + if ( !host_header_key.empty() ) + { + auto header = get_request_header( host_header_key ); + if ( !header.empty() ) + return header; + } + return _ws_connection->get_host(); + } + private: T _ws_connection; + std::string host_header_key; }; typedef websocketpp::lib::shared_ptr context_ptr; @@ -196,7 +184,7 @@ namespace fc { namespace http { class websocket_server_impl { public: - websocket_server_impl() + websocket_server_impl( std::string host_header_key ) :_server_thread( fc::thread::current() ) { @@ -205,7 +193,8 @@ namespace fc { namespace http { _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); + auto new_con = std::make_shared> + ( _server.get_con_from_hdl(hdl), host_header_key ); _on_connection( _connections[hdl] = new_con ); }).wait(); }); @@ -213,11 +202,15 @@ namespace fc { namespace http { _server_thread.async( [&](){ auto current_con = _connections.find(hdl); assert( current_con != _connections.end() ); - wdump(("server")(msg->get_payload())); auto payload = msg->get_payload(); - std::shared_ptr con = current_con->second; + std::shared_ptr ws_con = current_con->second; + wdump( ("server") (ws_con->get_host()) (payload) ); ++_pending_messages; - auto f = fc::async([this,con,payload](){ if( _pending_messages ) --_pending_messages; con->on_message( payload ); }); + auto f = fc::async([this,ws_con,payload]() + { + if( _pending_messages ) --_pending_messages; + ws_con->on_message( payload ); + }); if( _pending_messages > 100 ) f.wait(); }).wait(); @@ -230,17 +223,18 @@ namespace fc { namespace http { _server.set_http_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto current_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); + auto current_con = std::make_shared>( + _server.get_con_from_hdl(hdl), host_header_key ); _on_connection( current_con ); auto con = _server.get_con_from_hdl(hdl); con->defer_http_response(); std::string request_body = con->get_request_body(); - wdump(("server")(request_body)); + wdump( ("server") (current_con->get_host()) (request_body) ); fc::async([current_con, request_body, con] { std::string response = current_con->on_http(request_body); - idump((response)); + idump( ("server") (current_con->get_host()) (response) ); con->set_body( response ); con->set_status( websocketpp::http::status_code::ok ); con->send_http_response(); @@ -312,10 +306,9 @@ namespace fc { namespace http { class websocket_tls_server_impl { public: - websocket_tls_server_impl( const string& server_pem, const string& ssl_password ) - :_server_thread( fc::thread::current() ) + websocket_tls_server_impl( const string& server_pem, const string& ssl_password, + std::string host_header_key ) :_server_thread( fc::thread::current() ) { - //if( server_pem.size() ) { _server.set_tls_init_handler( [=]( websocketpp::connection_hdl hdl ) -> context_ptr { context_ptr ctx = websocketpp::lib::make_shared(boost::asio::ssl::context::tlsv1); @@ -339,7 +332,8 @@ namespace fc { namespace http { _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); + auto new_con = std::make_shared>( + _server.get_con_from_hdl(hdl), host_header_key ); _on_connection( _connections[hdl] = new_con ); }).wait(); }); @@ -348,27 +342,29 @@ namespace fc { namespace http { auto current_con = _connections.find(hdl); assert( current_con != _connections.end() ); auto received = msg->get_payload(); - std::shared_ptr con = current_con->second; - fc::async([con,received](){ con->on_message( received ); }); + std::shared_ptr ws_con = current_con->second; + wdump( ("server") (ws_con->get_host()) (received) ); + fc::async([ws_con,received](){ ws_con->on_message( received ); }); }).wait(); }); _server.set_http_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto current_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); + auto current_con = std::make_shared>( + _server.get_con_from_hdl(hdl), host_header_key ); try{ _on_connection( current_con ); auto con = _server.get_con_from_hdl(hdl); - wdump(("server")(con->get_request_body())); + wdump(("server") (con->get_host()) (con->get_request_body()) ); auto response = current_con->on_http( con->get_request_body() ); - idump((response)); + idump( ("server") (current_con->get_host()) (response) ); con->set_body( response ); con->set_status( websocketpp::http::status_code::ok ); } catch ( const fc::exception& e ) { - edump((e.to_detail_string())); + edump( (current_con->get_host()) (e.to_detail_string()) ); } current_con->closed(); @@ -413,18 +409,6 @@ namespace fc { namespace http { fc::promise::ptr _closed; }; - - - - - - - - - - - - typedef websocketpp::client websocket_client_type; typedef websocketpp::client websocket_tls_client_type; @@ -443,8 +427,7 @@ namespace fc { namespace http { _client.clear_access_channels( websocketpp::log::alevel::all ); _client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){ _client_thread.async( [&](){ - wdump((msg->get_payload())); - //std::cerr<<"recv: "<get_payload()<<"\n"; + wdump( (_connection->get_host()) (msg->get_payload()) ); auto received = msg->get_payload(); fc::async( [=](){ if( _connection ) @@ -504,8 +487,8 @@ namespace fc { namespace http { _client.clear_access_channels( websocketpp::log::alevel::all ); _client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){ _client_thread.async( [&](){ - wdump((msg->get_payload())); - _connection->on_message( msg->get_payload() ); + wdump( (_connection->get_host()) (msg->get_payload()) ); + _connection->on_message( msg->get_payload() ); }).wait(); }); _client.set_close_handler( [=]( connection_hdl hdl ){ @@ -612,7 +595,8 @@ namespace fc { namespace http { } // namespace detail - websocket_server::websocket_server():my( new detail::websocket_server_impl() ) {} + websocket_server::websocket_server( std::string host_header_key ) + :my( new detail::websocket_server_impl( host_header_key ) ) {} websocket_server::~websocket_server(){} void websocket_server::on_connection( const on_connection_handler& handler ) @@ -652,7 +636,9 @@ namespace fc { namespace http { - websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password ):my( new detail::websocket_tls_server_impl(server_pem, ssl_password) ) {} + websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password, + std::string host_header_key ) + : my( new detail::websocket_tls_server_impl(server_pem, ssl_password, host_header_key ) ) {} websocket_tls_server::~websocket_tls_server(){} void websocket_tls_server::on_connection( const on_connection_handler& handler ) @@ -704,7 +690,7 @@ namespace fc { namespace http { auto con = my->_client.get_connection( uri, ec ); - if( ec ) FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); + if( ec ) FC_ASSERT( !ec, "uri: ${uri} error: ${e}", ("uri", uri) ("e",ec.message()) ); my->_client.connect(con); my->_connected->wait(); @@ -731,7 +717,7 @@ namespace fc { namespace http { auto con = smy->_client.get_connection( uri, ec ); if( ec ) - FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); + FC_ASSERT( !ec, "uri: ${uri} error: ${e}", ("uri", uri) ("e",ec.message()) ); smy->_client.connect(con); smy->_connected->wait(); return smy->_connection; @@ -752,7 +738,6 @@ namespace fc { namespace http { websocket_connection_ptr websocket_tls_client::connect( const std::string& uri ) { try { - // wlog( "connecting to ${uri}", ("uri",uri)); websocketpp::lib::error_code ec; my->_connected = fc::promise::ptr( new fc::promise("websocket::connect") ); @@ -767,7 +752,7 @@ namespace fc { namespace http { auto con = my->_client.get_connection( uri, ec ); if( ec ) { - FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); + FC_ASSERT( !ec, "uri: ${uri} error: ${e}", ("uri", uri) ("e",ec.message()) ); } my->_client.connect(con); my->_connected->wait(); diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp index 8c726e574..6200b085f 100644 --- a/tests/network/http/websocket_test.cpp +++ b/tests/network/http/websocket_test.cpp @@ -3,11 +3,18 @@ #include #include +#include +#include BOOST_AUTO_TEST_SUITE(fc_network) BOOST_AUTO_TEST_CASE(websocket_test) { + // set up logging + fc::shared_ptr ca(new fc::console_appender); + fc::logger l = fc::logger::get("rpc"); + l.add_appender( ca ); + fc::http::websocket_client client; fc::http::websocket_connection_ptr s_conn, c_conn; int port; From 8b4ef5aa029ce62628c9c0dd83390e22e23d775a Mon Sep 17 00:00:00 2001 From: John Jones Date: Thu, 23 May 2019 16:05:05 -0500 Subject: [PATCH 02/23] Fix bad_alloc --- include/fc/network/http/websocket.hpp | 6 +- src/network/http/websocket.cpp | 89 ++++++++++++--------------- tests/CMakeLists.txt | 6 ++ tests/ws_test_client.cpp | 41 ++++++++++++ tests/ws_test_server.cpp | 33 ++++++++++ 5 files changed, 121 insertions(+), 54 deletions(-) create mode 100644 tests/ws_test_client.cpp create mode 100644 tests/ws_test_server.cpp diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index 675c3e9cf..db67b29c1 100644 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -30,7 +30,7 @@ namespace fc { namespace http { boost::any& get_session_data() { return _session_data; } virtual std::string get_request_header(const std::string& key) = 0; - virtual std::string get_host() = 0; + virtual std::string get_remote_hostname() = 0; fc::signal closed; private: @@ -45,7 +45,7 @@ namespace fc { namespace http { class websocket_server { public: - websocket_server( std::string host_header_key = std::string() ); + websocket_server(); ~websocket_server(); void on_connection( const on_connection_handler& handler); @@ -67,7 +67,7 @@ namespace fc { namespace http { { public: websocket_tls_server( const std::string& server_pem = std::string(), - const std::string& ssl_password = std::string(), std::string host_header_key = std::string() ); + const std::string& ssl_password = std::string()); ~websocket_tls_server(); void on_connection( const on_connection_handler& handler); diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 8e29030a8..a41627e0f 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -141,11 +141,13 @@ namespace fc { namespace http { class websocket_connection_impl : public websocket_connection { public: - websocket_connection_impl( T con, std::string host_header_key = std::string() ) - :_ws_connection(con), host_header_key(host_header_key) { + websocket_connection_impl( T con ) + :_ws_connection(con){ } - ~websocket_connection_impl() {} + ~websocket_connection_impl() + { + } virtual void send_message( const std::string& message )override { @@ -153,7 +155,6 @@ namespace fc { namespace http { auto ec = _ws_connection->send( message ); FC_ASSERT( !ec, "websocket send failed: ${msg}", ("msg",ec.message() ) ); } - virtual void close( int64_t code, const std::string& reason )override { _ws_connection->close(code,reason); @@ -164,19 +165,14 @@ namespace fc { namespace http { return _ws_connection->get_request_header(key); } - virtual std::string get_host() override + virtual std::string get_remote_hostname() { - if ( !host_header_key.empty() ) - { - auto header = get_request_header( host_header_key ); - if ( !header.empty() ) - return header; - } - return _ws_connection->get_host(); + // TODO: check headers, revert to the raw connection details + // Notes: T is a pointer to a websocketpp::connection (see connection.hpp) + return _ws_connection->get_uri()->get_host(); } - private: + T _ws_connection; - std::string host_header_key; }; typedef websocketpp::lib::shared_ptr context_ptr; @@ -184,7 +180,7 @@ namespace fc { namespace http { class websocket_server_impl { public: - websocket_server_impl( std::string host_header_key ) + websocket_server_impl() :_server_thread( fc::thread::current() ) { @@ -193,8 +189,7 @@ namespace fc { namespace http { _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto new_con = std::make_shared> - ( _server.get_con_from_hdl(hdl), host_header_key ); + auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); _on_connection( _connections[hdl] = new_con ); }).wait(); }); @@ -203,14 +198,10 @@ namespace fc { namespace http { auto current_con = _connections.find(hdl); assert( current_con != _connections.end() ); auto payload = msg->get_payload(); - std::shared_ptr ws_con = current_con->second; - wdump( ("server") (ws_con->get_host()) (payload) ); + std::shared_ptr con = current_con->second; + wdump( ("server") ( con->get_remote_hostname() ) (msg->get_payload())); ++_pending_messages; - auto f = fc::async([this,ws_con,payload]() - { - if( _pending_messages ) --_pending_messages; - ws_con->on_message( payload ); - }); + auto f = fc::async([this,con,payload](){ if( _pending_messages ) --_pending_messages; con->on_message( payload ); }); if( _pending_messages > 100 ) f.wait(); }).wait(); @@ -223,18 +214,17 @@ namespace fc { namespace http { _server.set_http_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto current_con = std::make_shared>( - _server.get_con_from_hdl(hdl), host_header_key ); + auto current_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); _on_connection( current_con ); auto con = _server.get_con_from_hdl(hdl); con->defer_http_response(); std::string request_body = con->get_request_body(); - wdump( ("server") (current_con->get_host()) (request_body) ); + wdump(("server")(request_body)); fc::async([current_con, request_body, con] { std::string response = current_con->on_http(request_body); - idump( ("server") (current_con->get_host()) (response) ); + idump((response)); con->set_body( response ); con->set_status( websocketpp::http::status_code::ok ); con->send_http_response(); @@ -306,9 +296,10 @@ namespace fc { namespace http { class websocket_tls_server_impl { public: - websocket_tls_server_impl( const string& server_pem, const string& ssl_password, - std::string host_header_key ) :_server_thread( fc::thread::current() ) + websocket_tls_server_impl( const string& server_pem, const string& ssl_password ) + :_server_thread( fc::thread::current() ) { + //if( server_pem.size() ) { _server.set_tls_init_handler( [=]( websocketpp::connection_hdl hdl ) -> context_ptr { context_ptr ctx = websocketpp::lib::make_shared(boost::asio::ssl::context::tlsv1); @@ -332,8 +323,7 @@ namespace fc { namespace http { _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto new_con = std::make_shared>( - _server.get_con_from_hdl(hdl), host_header_key ); + auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); _on_connection( _connections[hdl] = new_con ); }).wait(); }); @@ -342,29 +332,27 @@ namespace fc { namespace http { auto current_con = _connections.find(hdl); assert( current_con != _connections.end() ); auto received = msg->get_payload(); - std::shared_ptr ws_con = current_con->second; - wdump( ("server") (ws_con->get_host()) (received) ); - fc::async([ws_con,received](){ ws_con->on_message( received ); }); + std::shared_ptr con = current_con->second; + fc::async([con,received](){ con->on_message( received ); }); }).wait(); }); _server.set_http_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto current_con = std::make_shared>( - _server.get_con_from_hdl(hdl), host_header_key ); + auto current_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); try{ _on_connection( current_con ); auto con = _server.get_con_from_hdl(hdl); - wdump(("server") (con->get_host()) (con->get_request_body()) ); + wdump(("server")(con->get_request_body())); auto response = current_con->on_http( con->get_request_body() ); - idump( ("server") (current_con->get_host()) (response) ); + idump((response)); con->set_body( response ); con->set_status( websocketpp::http::status_code::ok ); } catch ( const fc::exception& e ) { - edump( (current_con->get_host()) (e.to_detail_string()) ); + edump((e.to_detail_string())); } current_con->closed(); @@ -427,7 +415,8 @@ namespace fc { namespace http { _client.clear_access_channels( websocketpp::log::alevel::all ); _client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){ _client_thread.async( [&](){ - wdump( (_connection->get_host()) (msg->get_payload()) ); + wdump((msg->get_payload())); + //std::cerr<<"recv: "<get_payload()<<"\n"; auto received = msg->get_payload(); fc::async( [=](){ if( _connection ) @@ -487,8 +476,8 @@ namespace fc { namespace http { _client.clear_access_channels( websocketpp::log::alevel::all ); _client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){ _client_thread.async( [&](){ - wdump( (_connection->get_host()) (msg->get_payload()) ); - _connection->on_message( msg->get_payload() ); + wdump((msg->get_payload())); + _connection->on_message( msg->get_payload() ); }).wait(); }); _client.set_close_handler( [=]( connection_hdl hdl ){ @@ -595,8 +584,7 @@ namespace fc { namespace http { } // namespace detail - websocket_server::websocket_server( std::string host_header_key ) - :my( new detail::websocket_server_impl( host_header_key ) ) {} + websocket_server::websocket_server():my( new detail::websocket_server_impl() ) {} websocket_server::~websocket_server(){} void websocket_server::on_connection( const on_connection_handler& handler ) @@ -636,9 +624,7 @@ namespace fc { namespace http { - websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password, - std::string host_header_key ) - : my( new detail::websocket_tls_server_impl(server_pem, ssl_password, host_header_key ) ) {} + websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password ):my( new detail::websocket_tls_server_impl(server_pem, ssl_password) ) {} websocket_tls_server::~websocket_tls_server(){} void websocket_tls_server::on_connection( const on_connection_handler& handler ) @@ -690,7 +676,7 @@ namespace fc { namespace http { auto con = my->_client.get_connection( uri, ec ); - if( ec ) FC_ASSERT( !ec, "uri: ${uri} error: ${e}", ("uri", uri) ("e",ec.message()) ); + if( ec ) FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); my->_client.connect(con); my->_connected->wait(); @@ -717,7 +703,7 @@ namespace fc { namespace http { auto con = smy->_client.get_connection( uri, ec ); if( ec ) - FC_ASSERT( !ec, "uri: ${uri} error: ${e}", ("uri", uri) ("e",ec.message()) ); + FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); smy->_client.connect(con); smy->_connected->wait(); return smy->_connection; @@ -738,6 +724,7 @@ namespace fc { namespace http { websocket_connection_ptr websocket_tls_client::connect( const std::string& uri ) { try { + // wlog( "connecting to ${uri}", ("uri",uri)); websocketpp::lib::error_code ec; my->_connected = fc::promise::ptr( new fc::promise("websocket::connect") ); @@ -752,7 +739,7 @@ namespace fc { namespace http { auto con = my->_client.get_connection( uri, ec ); if( ec ) { - FC_ASSERT( !ec, "uri: ${uri} error: ${e}", ("uri", uri) ("e",ec.message()) ); + FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); } my->_client.connect(con); my->_connected->wait(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9e395c3ab..e7af90adc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -19,6 +19,12 @@ target_link_libraries( hmac_test fc ) add_executable( ecc_test crypto/ecc_test.cpp ) target_link_libraries( ecc_test fc ) +add_executable( ws_test_server ws_test_server.cpp ) +target_link_libraries( ws_test_server fc ) + +add_executable( ws_test_client ws_test_client.cpp ) +target_link_libraries( ws_test_client fc ) + #add_executable( test_aes aes_test.cpp ) #target_link_libraries( test_aes fc ${rt_library} ${pthread_library} ) #add_executable( test_sleep sleep.cpp ) diff --git a/tests/ws_test_client.cpp b/tests/ws_test_client.cpp new file mode 100644 index 000000000..55006d51d --- /dev/null +++ b/tests/ws_test_client.cpp @@ -0,0 +1,41 @@ +#include +#include + +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + try + { + // set up logging + fc::shared_ptr ca(new fc::console_appender); + fc::logger l = fc::logger::get("rpc"); + l.add_appender( ca ); + + fc::http::websocket_client client; + fc::http::websocket_connection_ptr s_conn, c_conn; + int port = std::stoi(argv[1]); + wlog( "Connecting to server at port ${port}", ("port", argv[1]) ); + c_conn = client.connect( "ws://127.0.0.1:" + fc::to_string(port) ); + + std::string echo; + c_conn->on_message_handler([&](const std::string& s){ + echo = s; + }); + c_conn->send_message( "hello world" ); + fc::usleep( fc::milliseconds(500) ); + if (echo != std::string("echo: hello world") ) + wlog( "Test1 failed, echo value: [${echo}]", ("echo", echo) ); + c_conn->send_message( "again" ); + fc::usleep( fc::milliseconds(500) ); + if ("echo: again" != echo) + wlog( "Test2 failed, echo value: [${echo}]", ("echo", echo) ); + } + catch (const websocketpp::exception& ex) + { + elog( "websocketpp::exception thrown: ${err}", ("err", ex.what()) ); + } +} diff --git a/tests/ws_test_server.cpp b/tests/ws_test_server.cpp new file mode 100644 index 000000000..14700a9ba --- /dev/null +++ b/tests/ws_test_server.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + // set up logging + fc::shared_ptr ca(new fc::console_appender); + fc::logger l = fc::logger::get("rpc"); + l.add_appender( ca ); + + fc::http::websocket_server server; + + server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ + c->on_message_handler([&](const std::string& s){ + c->send_message("echo: " + s); + }); + }); + + server.listen( 0 ); + server.start_accept(); + + wlog( "Port: ${port}", ("port", server.get_listening_port()) ); + + while( true ) + { + fc::usleep( fc::microseconds(100) ); + } +} From d821e865ed4fb252c0c3b2d6b8133f09369f8388 Mon Sep 17 00:00:00 2001 From: John Jones Date: Fri, 24 May 2019 08:53:45 -0500 Subject: [PATCH 03/23] Add configurable header --- include/fc/network/http/websocket.hpp | 4 ++-- src/network/http/websocket.cpp | 21 ++++++++++++++------- tests/network/http/websocket_test.cpp | 2 +- tests/ws_test_client.cpp | 6 +++--- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index db67b29c1..5dd2a8d8d 100644 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -30,7 +30,7 @@ namespace fc { namespace http { boost::any& get_session_data() { return _session_data; } virtual std::string get_request_header(const std::string& key) = 0; - virtual std::string get_remote_hostname() = 0; + virtual std::string get_remote_hostname(const std::string& forward_header_key) = 0; fc::signal closed; private: @@ -45,7 +45,7 @@ namespace fc { namespace http { class websocket_server { public: - websocket_server(); + websocket_server( std::string forward_header_key = std::string() ); ~websocket_server(); void on_connection( const on_connection_handler& handler); diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index a41627e0f..f315b7db7 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -165,11 +165,16 @@ namespace fc { namespace http { return _ws_connection->get_request_header(key); } - virtual std::string get_remote_hostname() + virtual std::string get_remote_hostname(const std::string& forward_header_key) { // TODO: check headers, revert to the raw connection details - // Notes: T is a pointer to a websocketpp::connection (see connection.hpp) - return _ws_connection->get_uri()->get_host(); + if (!forward_header_key.empty()) + { + std::string header_value = _ws_connection->get_request_header(forward_header_key); + if (!header_value.empty()) + return header_value; + } + return _ws_connection->get_remote_endpoint(); } T _ws_connection; @@ -180,8 +185,8 @@ namespace fc { namespace http { class websocket_server_impl { public: - websocket_server_impl() - :_server_thread( fc::thread::current() ) + websocket_server_impl(const std::string& forward_header_key = std::string() ) + :_server_thread( fc::thread::current() ) { _server.clear_access_channels( websocketpp::log::alevel::all ); @@ -199,7 +204,8 @@ namespace fc { namespace http { assert( current_con != _connections.end() ); auto payload = msg->get_payload(); std::shared_ptr con = current_con->second; - wdump( ("server") ( con->get_remote_hostname() ) (msg->get_payload())); + wlog( "Websocket Server Remote: ${host} Payload: ${body}", + ("host", con->get_remote_hostname(forward_header_key)) ("body", msg->get_payload())); ++_pending_messages; auto f = fc::async([this,con,payload](){ if( _pending_messages ) --_pending_messages; con->on_message( payload ); }); if( _pending_messages > 100 ) @@ -584,7 +590,8 @@ namespace fc { namespace http { } // namespace detail - websocket_server::websocket_server():my( new detail::websocket_server_impl() ) {} + websocket_server::websocket_server(std::string forward_header_key) + :my( new detail::websocket_server_impl(forward_header_key) ) {} websocket_server::~websocket_server(){} void websocket_server::on_connection( const on_connection_handler& handler ) diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp index 6200b085f..cfa78d0a4 100644 --- a/tests/network/http/websocket_test.cpp +++ b/tests/network/http/websocket_test.cpp @@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(websocket_test) fc::http::websocket_connection_ptr s_conn, c_conn; int port; { - fc::http::websocket_server server; + fc::http::websocket_server server("MyProxyHeaderKey"); server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ s_conn = c; c->on_message_handler([&](const std::string& s){ diff --git a/tests/ws_test_client.cpp b/tests/ws_test_client.cpp index 55006d51d..e841a34e0 100644 --- a/tests/ws_test_client.cpp +++ b/tests/ws_test_client.cpp @@ -17,9 +17,9 @@ int main(int argc, char** argv) fc::http::websocket_client client; fc::http::websocket_connection_ptr s_conn, c_conn; - int port = std::stoi(argv[1]); - wlog( "Connecting to server at port ${port}", ("port", argv[1]) ); - c_conn = client.connect( "ws://127.0.0.1:" + fc::to_string(port) ); + std::string url = argv[1]; + wlog( "Connecting to server at url ${url}", ("url", url) ); + c_conn = client.connect( "ws://" + url ); std::string echo; c_conn->on_message_handler([&](const std::string& s){ From 4906d8b2daa2cd77af50a033579448b8961e9b49 Mon Sep 17 00:00:00 2001 From: John Jones Date: Fri, 24 May 2019 10:41:21 -0500 Subject: [PATCH 04/23] Allow configurable proxy header for logging --- include/fc/network/http/websocket.hpp | 2 + src/log/logger.cpp | 8 +++- src/network/http/websocket.cpp | 34 +++++++++------ tests/network/http/websocket_test.cpp | 59 +++++++++++++++++++++++++++ tests/ws_test_server.cpp | 2 +- 5 files changed, 90 insertions(+), 15 deletions(-) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index 5dd2a8d8d..0fd208bba 100644 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -91,9 +91,11 @@ namespace fc { namespace http { void close(); void synchronous_close(); + void append_header(const std::string& key, const std::string& value); private: std::unique_ptr my; std::unique_ptr smy; + std::vector> headers; }; class websocket_tls_client { diff --git a/src/log/logger.cpp b/src/log/logger.cpp index 93241f33f..bd31afe72 100644 --- a/src/log/logger.cpp +++ b/src/log/logger.cpp @@ -99,8 +99,12 @@ namespace fc { void logger::add_appender( const fc::shared_ptr& a ) { my->_appenders.push_back(a); } -// void logger::remove_appender( const fc::shared_ptr& a ) - // { my->_appenders.erase(a); } + void logger::remove_appender( const fc::shared_ptr& a ) + { + auto item = std::find(my->_appenders.begin(), my->_appenders.end(), a); + if (item != my->_appenders.end()) + my->_appenders.erase(item); + } std::vector > logger::get_appenders()const { diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index f315b7db7..b09e4e31a 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -165,9 +165,14 @@ namespace fc { namespace http { return _ws_connection->get_request_header(key); } + /**** + * @brief retrieves the remote hostname + * + * @param forward_header_key the key to look at in the request header + * @returns the value in the header, otherwise the remote endpoint + */ virtual std::string get_remote_hostname(const std::string& forward_header_key) { - // TODO: check headers, revert to the raw connection details if (!forward_header_key.empty()) { std::string header_value = _ws_connection->get_request_header(forward_header_key); @@ -186,17 +191,16 @@ namespace fc { namespace http { { public: websocket_server_impl(const std::string& forward_header_key = std::string() ) - :_server_thread( fc::thread::current() ) + :_server_thread( fc::thread::current() ), fwd_header_key(forward_header_key) { - _server.clear_access_channels( websocketpp::log::alevel::all ); _server.init_asio(&fc::asio::default_io_service()); _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ - _server_thread.async( [&](){ - auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); - _on_connection( _connections[hdl] = new_con ); - }).wait(); + _server_thread.async( [&](){ + auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); + _on_connection( _connections[hdl] = new_con ); + }).wait(); }); _server.set_message_handler( [&]( connection_hdl hdl, websocket_server_type::message_ptr msg ){ _server_thread.async( [&](){ @@ -205,7 +209,7 @@ namespace fc { namespace http { auto payload = msg->get_payload(); std::shared_ptr con = current_con->second; wlog( "Websocket Server Remote: ${host} Payload: ${body}", - ("host", con->get_remote_hostname(forward_header_key)) ("body", msg->get_payload())); + ("host", con->get_remote_hostname(fwd_header_key)) ("body", msg->get_payload())); ++_pending_messages; auto f = fc::async([this,con,payload](){ if( _pending_messages ) --_pending_messages; con->on_message( payload ); }); if( _pending_messages > 100 ) @@ -297,6 +301,7 @@ namespace fc { namespace http { on_connection_handler _on_connection; fc::promise::ptr _closed; uint32_t _pending_messages = 0; + std::string fwd_header_key; }; class websocket_tls_server_impl @@ -422,7 +427,6 @@ namespace fc { namespace http { _client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){ _client_thread.async( [&](){ wdump((msg->get_payload())); - //std::cerr<<"recv: "<get_payload()<<"\n"; auto received = msg->get_payload(); fc::async( [=](){ if( _connection ) @@ -658,7 +662,7 @@ namespace fc { namespace http { - websocket_client::websocket_client( const std::string& ca_filename ):my( new detail::websocket_client_impl() ),smy(new detail::websocket_tls_client_impl( ca_filename )) {} + websocket_client::websocket_client( const std::string& ca_filename):my( new detail::websocket_client_impl() ),smy(new detail::websocket_tls_client_impl( ca_filename )) {} websocket_client::~websocket_client(){ } websocket_connection_ptr websocket_client::connect( const std::string& uri ) @@ -667,7 +671,6 @@ namespace fc { namespace http { return secure_connect(uri); FC_ASSERT( uri.substr(0,3) == "ws:" ); - // wlog( "connecting to ${uri}", ("uri",uri)); websocketpp::lib::error_code ec; my->_uri = uri; @@ -683,6 +686,9 @@ namespace fc { namespace http { auto con = my->_client.get_connection( uri, ec ); + std::for_each(headers.begin(), headers.end(), [con](std::pair in) { + con->append_header(in.first, in.second); + }); if( ec ) FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); my->_client.connect(con); @@ -695,7 +701,6 @@ namespace fc { namespace http { if( uri.substr(0,3) == "ws:" ) return connect(uri); FC_ASSERT( uri.substr(0,4) == "wss:" ); - // wlog( "connecting to ${uri}", ("uri",uri)); websocketpp::lib::error_code ec; smy->_uri = uri; @@ -729,6 +734,11 @@ namespace fc { namespace http { my->_closed->wait(); } + void websocket_client::append_header(const std::string& key, const std::string& value) + { + headers.push_back( std::pair(key, value)); + } + websocket_connection_ptr websocket_tls_client::connect( const std::string& uri ) { try { // wlog( "connecting to ${uri}", ("uri",uri)); diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp index cfa78d0a4..ffad3f41e 100644 --- a/tests/network/http/websocket_test.cpp +++ b/tests/network/http/websocket_test.cpp @@ -59,6 +59,65 @@ BOOST_AUTO_TEST_CASE(websocket_test) BOOST_CHECK_THROW(c_conn->send_message( "again" ), fc::assert_exception); BOOST_CHECK_THROW(client.connect( "ws://localhost:" + fc::to_string(port) ), fc::exception); + l.remove_appender(ca); +} + +BOOST_AUTO_TEST_CASE(websocket_test_with_proxy_header) +{ + // set up logging + fc::shared_ptr ca(new fc::console_appender); + fc::logger l = fc::logger::get("rpc"); + l.add_appender( ca ); + + fc::http::websocket_client client; + // add the proxy header element + client.append_header("MyProxyHeaderKey", "MyServer:8080"); + + fc::http::websocket_connection_ptr s_conn, c_conn; + int port; + { + // the server will be on the lookout for the key in the header + fc::http::websocket_server server("MyProxyHeaderKey"); + server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ + s_conn = c; + c->on_message_handler([&](const std::string& s){ + c->send_message("echo: " + s); + }); + }); + + server.listen( 0 ); + port = server.get_listening_port(); + + server.start_accept(); + + std::string echo; + c_conn = client.connect( "ws://localhost:" + fc::to_string(port) ); + c_conn->on_message_handler([&](const std::string& s){ + echo = s; + }); + c_conn->send_message( "hello world" ); + fc::usleep( fc::milliseconds(100) ); + BOOST_CHECK_EQUAL("echo: hello world", echo); + c_conn->send_message( "again" ); + fc::usleep( fc::milliseconds(100) ); + BOOST_CHECK_EQUAL("echo: again", echo); + + s_conn->close(0, "test"); + fc::usleep( fc::milliseconds(100) ); + BOOST_CHECK_THROW(c_conn->send_message( "again" ), fc::exception); + + c_conn = client.connect( "ws://localhost:" + fc::to_string(port) ); + c_conn->on_message_handler([&](const std::string& s){ + echo = s; + }); + c_conn->send_message( "hello world" ); + fc::usleep( fc::milliseconds(100) ); + BOOST_CHECK_EQUAL("echo: hello world", echo); + } + + BOOST_CHECK_THROW(c_conn->send_message( "again" ), fc::assert_exception); + BOOST_CHECK_THROW(client.connect( "ws://localhost:" + fc::to_string(port) ), fc::exception); + l.remove_appender(ca); } BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/ws_test_server.cpp b/tests/ws_test_server.cpp index 14700a9ba..e08868155 100644 --- a/tests/ws_test_server.cpp +++ b/tests/ws_test_server.cpp @@ -13,7 +13,7 @@ int main(int argc, char** argv) fc::logger l = fc::logger::get("rpc"); l.add_appender( ca ); - fc::http::websocket_server server; + fc::http::websocket_server server("MyForwardHeaderKey"); server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ c->on_message_handler([&](const std::string& s){ From 0df5f7e905c0ad76f8b67c0c323f87db9d3ed631 Mon Sep 17 00:00:00 2001 From: John Jones Date: Fri, 24 May 2019 11:15:02 -0500 Subject: [PATCH 05/23] Use an api call instead of constructor --- include/fc/network/http/websocket.hpp | 5 +++-- src/network/http/websocket.cpp | 22 ++++++++++++++++------ tests/network/http/websocket_test.cpp | 8 ++++++-- tests/ws_test_server.cpp | 3 ++- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index 0fd208bba..953db69a9 100644 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -45,7 +45,7 @@ namespace fc { namespace http { class websocket_server { public: - websocket_server( std::string forward_header_key = std::string() ); + websocket_server(); ~websocket_server(); void on_connection( const on_connection_handler& handler); @@ -53,6 +53,7 @@ namespace fc { namespace http { void listen( const fc::ip::endpoint& ep ); uint16_t get_listening_port(); void start_accept(); + void set_forward_header_key(const std::string& key); void stop_listening(); void close(); @@ -74,7 +75,7 @@ namespace fc { namespace http { void listen( uint16_t port ); void listen( const fc::ip::endpoint& ep ); void start_accept(); - + void set_forward_header_key(const std::string& key); private: friend class detail::websocket_tls_server_impl; std::unique_ptr my; diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index b09e4e31a..62f01bfbe 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -190,8 +190,8 @@ namespace fc { namespace http { class websocket_server_impl { public: - websocket_server_impl(const std::string& forward_header_key = std::string() ) - :_server_thread( fc::thread::current() ), fwd_header_key(forward_header_key) + websocket_server_impl() + :_server_thread( fc::thread::current() ), fwd_header_key("") { _server.clear_access_channels( websocketpp::log::alevel::all ); _server.init_asio(&fc::asio::default_io_service()); @@ -293,6 +293,8 @@ namespace fc { namespace http { if( _closed ) _closed->wait(); } + void set_forward_header_key(const std::string& key) { fwd_header_key = key; } + typedef std::map > con_map; con_map _connections; @@ -310,7 +312,6 @@ namespace fc { namespace http { websocket_tls_server_impl( const string& server_pem, const string& ssl_password ) :_server_thread( fc::thread::current() ) { - //if( server_pem.size() ) { _server.set_tls_init_handler( [=]( websocketpp::connection_hdl hdl ) -> context_ptr { context_ptr ctx = websocketpp::lib::make_shared(boost::asio::ssl::context::tlsv1); @@ -344,6 +345,8 @@ namespace fc { namespace http { assert( current_con != _connections.end() ); auto received = msg->get_payload(); std::shared_ptr con = current_con->second; + wlog( "Websocket TLS Server Remote: ${host} Payload: ${body}", + ("host", con->get_remote_hostname(fwd_header_key)) ("body", msg->get_payload())); fc::async([con,received](){ con->on_message( received ); }); }).wait(); }); @@ -390,6 +393,7 @@ namespace fc { namespace http { } }); } + ~websocket_tls_server_impl() { if( _server.is_listening() ) @@ -399,6 +403,8 @@ namespace fc { namespace http { _server.close( item.first, 0, "server exit" ); } + void set_forward_header_key( const std::string& key ) { fwd_header_key = key; } + typedef std::map > con_map; con_map _connections; @@ -406,6 +412,7 @@ namespace fc { namespace http { websocket_tls_server_type _server; on_connection_handler _on_connection; fc::promise::ptr _closed; + std::string fwd_header_key; }; typedef websocketpp::client websocket_client_type; @@ -594,8 +601,8 @@ namespace fc { namespace http { } // namespace detail - websocket_server::websocket_server(std::string forward_header_key) - :my( new detail::websocket_server_impl(forward_header_key) ) {} + websocket_server::websocket_server() + :my( new detail::websocket_server_impl() ) {} websocket_server::~websocket_server(){} void websocket_server::on_connection( const on_connection_handler& handler ) @@ -633,7 +640,10 @@ namespace fc { namespace http { my->_server.close(connection.first, websocketpp::close::status::normal, "Goodbye"); } - + void websocket_server::set_forward_header_key( const std::string& key ) + { + my->set_forward_header_key( key ); + } websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password ):my( new detail::websocket_tls_server_impl(server_pem, ssl_password) ) {} websocket_tls_server::~websocket_tls_server(){} diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp index ffad3f41e..4bb3e6949 100644 --- a/tests/network/http/websocket_test.cpp +++ b/tests/network/http/websocket_test.cpp @@ -19,7 +19,10 @@ BOOST_AUTO_TEST_CASE(websocket_test) fc::http::websocket_connection_ptr s_conn, c_conn; int port; { - fc::http::websocket_server server("MyProxyHeaderKey"); + fc::http::websocket_server server; + // even with this set, if the remote does not provide it, it will revert to + // the remote endpoint + server.set_forward_header_key("MyProxyHeaderKey"); server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ s_conn = c; c->on_message_handler([&](const std::string& s){ @@ -77,7 +80,8 @@ BOOST_AUTO_TEST_CASE(websocket_test_with_proxy_header) int port; { // the server will be on the lookout for the key in the header - fc::http::websocket_server server("MyProxyHeaderKey"); + fc::http::websocket_server server; + server.set_forward_header_key("MyProxyHeaderKey"); server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ s_conn = c; c->on_message_handler([&](const std::string& s){ diff --git a/tests/ws_test_server.cpp b/tests/ws_test_server.cpp index e08868155..4cb58f789 100644 --- a/tests/ws_test_server.cpp +++ b/tests/ws_test_server.cpp @@ -13,7 +13,8 @@ int main(int argc, char** argv) fc::logger l = fc::logger::get("rpc"); l.add_appender( ca ); - fc::http::websocket_server server("MyForwardHeaderKey"); + fc::http::websocket_server server; + server.set_forward_header_key("MyForwardHeaderKey"); server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ c->on_message_handler([&](const std::string& s){ From 94200c1b5790995868cea37e6a9eacd3c2848493 Mon Sep 17 00:00:00 2001 From: jmjatlanta Date: Mon, 27 May 2019 10:25:19 -0500 Subject: [PATCH 06/23] clarify method name, cache value --- include/fc/network/http/websocket.hpp | 2 +- src/network/http/websocket.cpp | 33 ++++++++++++++++++--------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index 953db69a9..4c6e374cf 100644 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -30,7 +30,7 @@ namespace fc { namespace http { boost::any& get_session_data() { return _session_data; } virtual std::string get_request_header(const std::string& key) = 0; - virtual std::string get_remote_hostname(const std::string& forward_header_key) = 0; + virtual std::string get_remote_ip(const std::string& forward_header_key) = 0; fc::signal closed; private: diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 62f01bfbe..05e417404 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -171,18 +171,28 @@ namespace fc { namespace http { * @param forward_header_key the key to look at in the request header * @returns the value in the header, otherwise the remote endpoint */ - virtual std::string get_remote_hostname(const std::string& forward_header_key) + virtual std::string get_remote_ip(const std::string& forward_header_key) override { - if (!forward_header_key.empty()) + if (last_ip.empty() || last_forward_header_key != forward_header_key) { - std::string header_value = _ws_connection->get_request_header(forward_header_key); - if (!header_value.empty()) - return header_value; + // refresh the cache + last_forward_header_key = forward_header_key; + if (!forward_header_key.empty()) + { + last_ip = get_request_header(forward_header_key); + if (!header_value.empty()) + last_ip = header_value; + } + if (last_ip.empty()) + last_ip = _ws_connection->get_remote_endpoint(); } - return _ws_connection->get_remote_endpoint(); + return last_ip; } T _ws_connection; + // cache the value of the remote IP + std::string last_forward_header_key; + std::string last_ip; }; typedef websocketpp::lib::shared_ptr context_ptr; @@ -197,8 +207,9 @@ namespace fc { namespace http { _server.init_asio(&fc::asio::default_io_service()); _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ - _server_thread.async( [&](){ - auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); + _server_thread.async( [_server, _connections](){ + auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); _on_connection( _connections[hdl] = new_con ); }).wait(); }); @@ -209,7 +220,7 @@ namespace fc { namespace http { auto payload = msg->get_payload(); std::shared_ptr con = current_con->second; wlog( "Websocket Server Remote: ${host} Payload: ${body}", - ("host", con->get_remote_hostname(fwd_header_key)) ("body", msg->get_payload())); + ("host", con->get_remote_ip(fwd_header_key)) ("body", msg->get_payload())); ++_pending_messages; auto f = fc::async([this,con,payload](){ if( _pending_messages ) --_pending_messages; con->on_message( payload ); }); if( _pending_messages > 100 ) @@ -346,7 +357,7 @@ namespace fc { namespace http { auto received = msg->get_payload(); std::shared_ptr con = current_con->second; wlog( "Websocket TLS Server Remote: ${host} Payload: ${body}", - ("host", con->get_remote_hostname(fwd_header_key)) ("body", msg->get_payload())); + ("host", con->get_remote_ip(fwd_header_key)) ("body", msg->get_payload())); fc::async([con,received](){ con->on_message( received ); }); }).wait(); }); @@ -672,7 +683,7 @@ namespace fc { namespace http { - websocket_client::websocket_client( const std::string& ca_filename):my( new detail::websocket_client_impl() ),smy(new detail::websocket_tls_client_impl( ca_filename )) {} + websocket_client::websocket_client( const std::string& ca_filename ):my( new detail::websocket_client_impl() ),smy(new detail::websocket_tls_client_impl( ca_filename )) {} websocket_client::~websocket_client(){ } websocket_connection_ptr websocket_client::connect( const std::string& uri ) From 99d7e6363634388ca39ce628e65e3f40c64de4b1 Mon Sep 17 00:00:00 2001 From: jmjatlanta Date: Mon, 27 May 2019 15:26:33 -0500 Subject: [PATCH 07/23] revert adjustment to capture --- src/network/http/websocket.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 05e417404..4ffbaecb9 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -178,11 +178,7 @@ namespace fc { namespace http { // refresh the cache last_forward_header_key = forward_header_key; if (!forward_header_key.empty()) - { last_ip = get_request_header(forward_header_key); - if (!header_value.empty()) - last_ip = header_value; - } if (last_ip.empty()) last_ip = _ws_connection->get_remote_endpoint(); } @@ -207,7 +203,7 @@ namespace fc { namespace http { _server.init_asio(&fc::asio::default_io_service()); _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ - _server_thread.async( [_server, _connections](){ + _server_thread.async( [&](){ auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); _on_connection( _connections[hdl] = new_con ); From 5d8e9e110e741a8c4f2804d047005099806cb1a0 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Fri, 21 Jun 2019 15:05:47 -0300 Subject: [PATCH 08/23] fix remove appender() --- src/log/logger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/log/logger.cpp b/src/log/logger.cpp index ee2776da6..d1004f5ee 100644 --- a/src/log/logger.cpp +++ b/src/log/logger.cpp @@ -99,7 +99,7 @@ namespace fc { void logger::add_appender( const appender::ptr& a ) { my->_appenders.push_back(a); } - void logger::remove_appender( const fc::shared_ptr& a ) + void logger::remove_appender( const appender::ptr& a ) { auto item = std::find(my->_appenders.begin(), my->_appenders.end(), a); if (item != my->_appenders.end()) From e90742995b241513f29b6bcaa5cc625317116c48 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Fri, 21 Jun 2019 15:39:16 -0300 Subject: [PATCH 09/23] fix tests --- tests/network/http/websocket_test.cpp | 4 ++-- tests/ws_test_client.cpp | 2 +- tests/ws_test_server.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp index 4bb3e6949..400d242c3 100644 --- a/tests/network/http/websocket_test.cpp +++ b/tests/network/http/websocket_test.cpp @@ -11,7 +11,7 @@ BOOST_AUTO_TEST_SUITE(fc_network) BOOST_AUTO_TEST_CASE(websocket_test) { // set up logging - fc::shared_ptr ca(new fc::console_appender); + fc::appender::ptr ca(new fc::console_appender); fc::logger l = fc::logger::get("rpc"); l.add_appender( ca ); @@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(websocket_test) BOOST_AUTO_TEST_CASE(websocket_test_with_proxy_header) { // set up logging - fc::shared_ptr ca(new fc::console_appender); + fc::appender::ptr ca(new fc::console_appender); fc::logger l = fc::logger::get("rpc"); l.add_appender( ca ); diff --git a/tests/ws_test_client.cpp b/tests/ws_test_client.cpp index e841a34e0..f18db13f6 100644 --- a/tests/ws_test_client.cpp +++ b/tests/ws_test_client.cpp @@ -11,7 +11,7 @@ int main(int argc, char** argv) try { // set up logging - fc::shared_ptr ca(new fc::console_appender); + fc::appender::ptr ca(new fc::console_appender); fc::logger l = fc::logger::get("rpc"); l.add_appender( ca ); diff --git a/tests/ws_test_server.cpp b/tests/ws_test_server.cpp index 4cb58f789..2ae2ba150 100644 --- a/tests/ws_test_server.cpp +++ b/tests/ws_test_server.cpp @@ -9,7 +9,7 @@ int main(int argc, char** argv) { // set up logging - fc::shared_ptr ca(new fc::console_appender); + fc::appender::ptr ca(new fc::console_appender); fc::logger l = fc::logger::get("rpc"); l.add_appender( ca ); From 7ec8ead573ea087dd16e0e3bfbcc8afe027e972d Mon Sep 17 00:00:00 2001 From: Alfredo Date: Fri, 21 Jun 2019 15:48:48 -0300 Subject: [PATCH 10/23] chanmge comment from hostname to IP --- src/network/http/websocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 24ea499c2..d5e9e4694 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -169,7 +169,7 @@ namespace fc { namespace http { } /**** - * @brief retrieves the remote hostname + * @brief retrieves the remote IP address * * @param forward_header_key the key to look at in the request header * @returns the value in the header, otherwise the remote endpoint From e336649b8f51f48a8cbd89467e9d82671c0db9e9 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Fri, 21 Jun 2019 16:03:00 -0300 Subject: [PATCH 11/23] lambda capture only whats required --- src/network/http/websocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index d5e9e4694..861dc31ba 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -206,7 +206,7 @@ namespace fc { namespace http { _server.init_asio(&fc::asio::default_io_service()); _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ - _server_thread.async( [&](){ + _server_thread.async( [this, hdl](){ auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); _on_connection( _connections[hdl] = new_con ); From ba394e05b35b9864e4ab5f84d2d5d2ffc07ae050 Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 1 May 2020 17:18:31 -0400 Subject: [PATCH 12/23] Refactor code about logging remote host info --- include/fc/network/http/websocket.hpp | 14 +-- src/network/http/websocket.cpp | 136 +++++++++++++------------- 2 files changed, 78 insertions(+), 72 deletions(-) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index 9513cefdb..4b2776e63 100644 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -31,9 +31,12 @@ namespace fc { namespace http { boost::any& get_session_data() { return _session_data; } virtual std::string get_request_header(const std::string& key) = 0; - virtual std::string get_remote_ip(const std::string& forward_header_key) = 0; + + const std::string& get_remote_endpoint()const { return _remote_endpoint; } fc::signal closed; + protected: + std::string _remote_endpoint; // for logging private: boost::any _session_data; std::function _on_message; @@ -46,7 +49,7 @@ namespace fc { namespace http { class websocket_server { public: - websocket_server(); + websocket_server(const std::string& forward_header_key); ~websocket_server(); void on_connection( const on_connection_handler& handler); @@ -54,7 +57,6 @@ namespace fc { namespace http { void listen( const fc::ip::endpoint& ep ); uint16_t get_listening_port(); void start_accept(); - void set_forward_header_key(const std::string& key); void stop_listening(); void close(); @@ -68,15 +70,15 @@ namespace fc { namespace http { class websocket_tls_server { public: - websocket_tls_server( const std::string& server_pem = std::string(), - const std::string& ssl_password = std::string()); + websocket_tls_server( const std::string& server_pem, + const std::string& ssl_password, + const std::string& forward_header_key ); ~websocket_tls_server(); void on_connection( const on_connection_handler& handler); void listen( uint16_t port ); void listen( const fc::ip::endpoint& ep ); void start_accept(); - void set_forward_header_key(const std::string& key); private: friend class detail::websocket_tls_server_impl; std::unique_ptr my; diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 861dc31ba..c19421703 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -20,6 +20,8 @@ #include #include +#include + #ifdef DEFAULT_LOGGER # undef DEFAULT_LOGGER #endif @@ -144,8 +146,14 @@ namespace fc { namespace http { class websocket_connection_impl : public websocket_connection { public: - websocket_connection_impl( T con ) - :_ws_connection(con){ + websocket_connection_impl( T con, const std::string& forward_header_key ) : _ws_connection(con) + { + // Firstly, try to extract remote address from a XFF-like header + if( !forward_header_key.empty() ) + _remote_endpoint = get_request_header( forward_header_key ); + // If the last step failed, retrieve the remote address from the connection + if( _remote_endpoint.empty() ) + _remote_endpoint = con->get_remote_endpoint(); } virtual ~websocket_connection_impl() @@ -154,7 +162,8 @@ namespace fc { namespace http { virtual void send_message( const std::string& message )override { - idump((message)); + ilog( "[OUT] ${remote_endpoint} ${msg}", + ("remote_endpoint",_remote_endpoint) ("msg",message) ); auto ec = _ws_connection->send( message ); FC_ASSERT( !ec, "websocket send failed: ${msg}", ("msg",ec.message() ) ); } @@ -168,30 +177,7 @@ namespace fc { namespace http { return _ws_connection->get_request_header(key); } - /**** - * @brief retrieves the remote IP address - * - * @param forward_header_key the key to look at in the request header - * @returns the value in the header, otherwise the remote endpoint - */ - virtual std::string get_remote_ip(const std::string& forward_header_key) override - { - if (last_ip.empty() || last_forward_header_key != forward_header_key) - { - // refresh the cache - last_forward_header_key = forward_header_key; - if (!forward_header_key.empty()) - last_ip = get_request_header(forward_header_key); - if (last_ip.empty()) - last_ip = _ws_connection->get_remote_endpoint(); - } - return last_ip; - } - T _ws_connection; - // cache the value of the remote IP - std::string last_forward_header_key; - std::string last_ip; }; typedef websocketpp::lib::shared_ptr context_ptr; @@ -199,8 +185,8 @@ namespace fc { namespace http { class websocket_server_impl { public: - websocket_server_impl() - :_server_thread( fc::thread::current() ), fwd_header_key("") + websocket_server_impl( const std::string& forward_header_key ) + :_server_thread( fc::thread::current() ), _forward_header_key(forward_header_key) { _server.clear_access_channels( websocketpp::log::alevel::all ); _server.init_asio(&fc::asio::default_io_service()); @@ -208,7 +194,8 @@ namespace fc { namespace http { _server.set_open_handler( [&]( connection_hdl hdl ){ _server_thread.async( [this, hdl](){ auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); + websocket_server_type::connection_ptr>>( _server.get_con_from_hdl(hdl), + _forward_header_key ); _on_connection( _connections[hdl] = new_con ); }).wait(); }); @@ -218,11 +205,15 @@ namespace fc { namespace http { assert( current_con != _connections.end() ); auto payload = msg->get_payload(); std::shared_ptr con = current_con->second; - wlog( "Websocket Server Remote: ${host} Payload: ${body}", - ("host", con->get_remote_ip(fwd_header_key)) ("body", msg->get_payload())); + wlog( "[IN] ${remote_endpoint} ${msg}", + ("remote_endpoint",con->get_remote_endpoint()) ("msg",payload) ); ++_pending_messages; - auto f = fc::async([this,con,payload](){ if( _pending_messages ) --_pending_messages; con->on_message( payload ); }); - if( _pending_messages > 100 ) + auto f = fc::async([this,con,payload](){ + if( _pending_messages ) + --_pending_messages; + con->on_message( payload ); + }); + if( _pending_messages > 100 ) f.wait(); }).wait(); }); @@ -234,17 +225,21 @@ namespace fc { namespace http { _server.set_http_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto current_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); + auto con = _server.get_con_from_hdl(hdl); + auto current_con = std::make_shared>( con, _forward_header_key ); _on_connection( current_con ); - auto con = _server.get_con_from_hdl(hdl); con->defer_http_response(); + std::string remote_endpoint = current_con->get_remote_endpoint(); std::string request_body = con->get_request_body(); - wdump(("server")(request_body)); + wlog( "[IN] ${remote_endpoint} ${msg}", + ("remote_endpoint",remote_endpoint) ("msg",request_body) ); - fc::async([current_con, request_body, con] { + fc::async([current_con, request_body, con, remote_endpoint] { fc::http::reply response = current_con->on_http(request_body); - idump( (response) ); + ilog( "[OUT] ${remote_endpoint} ${msg}", + ("remote_endpoint",remote_endpoint) ("msg",response) ); con->set_body( std::move( response.body_as_string ) ); con->set_status( websocketpp::http::status_code::value(response.status) ); con->send_http_response(); @@ -303,8 +298,6 @@ namespace fc { namespace http { if( _closed ) _closed->wait(); } - void set_forward_header_key(const std::string& key) { fwd_header_key = key; } - typedef std::map > con_map; con_map _connections; @@ -313,14 +306,15 @@ namespace fc { namespace http { on_connection_handler _on_connection; fc::promise::ptr _closed; uint32_t _pending_messages = 0; - std::string fwd_header_key; + std::string _forward_header_key; // A header like "X-Forwarded-For" (XFF), with data IP:port }; class websocket_tls_server_impl { public: - websocket_tls_server_impl( const string& server_pem, const string& ssl_password ) - :_server_thread( fc::thread::current() ) + websocket_tls_server_impl( const string& server_pem, const string& ssl_password, + const std::string& forward_header_key ) + :_server_thread( fc::thread::current() ), _forward_header_key(forward_header_key) { { _server.set_tls_init_handler( [=]( websocketpp::connection_hdl hdl ) -> context_ptr { @@ -345,7 +339,9 @@ namespace fc { namespace http { _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); + auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl), + _forward_header_key ); _on_connection( _connections[hdl] = new_con ); }).wait(); }); @@ -355,8 +351,8 @@ namespace fc { namespace http { assert( current_con != _connections.end() ); auto received = msg->get_payload(); std::shared_ptr con = current_con->second; - wlog( "Websocket TLS Server Remote: ${host} Payload: ${body}", - ("host", con->get_remote_ip(fwd_header_key)) ("body", msg->get_payload())); + wlog( "[IN] ${remote_endpoint} ${msg}", + ("remote_endpoint",con->get_remote_endpoint()) ("msg",received) ); fc::async([con,received](){ con->on_message( received ); }); }).wait(); }); @@ -364,14 +360,19 @@ namespace fc { namespace http { _server.set_http_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto current_con = std::make_shared>( _server.get_con_from_hdl(hdl) ); + auto con = _server.get_con_from_hdl(hdl); + auto current_con = std::make_shared>( con, _forward_header_key ); try{ _on_connection( current_con ); - auto con = _server.get_con_from_hdl(hdl); - wdump(("server")(con->get_request_body())); + std::string remote_endpoint = current_con->get_remote_endpoint(); + std::string request_body = con->get_request_body(); + wlog( "[IN] ${remote_endpoint} ${msg}", + ("remote_endpoint",remote_endpoint) ("msg",request_body) ); auto response = current_con->on_http( con->get_request_body() ); - idump((response)); + ilog( "[OUT] ${remote_endpoint} ${msg}", + ("remote_endpoint",remote_endpoint) ("msg",response) ); con->set_body( std::move( response.body_as_string ) ); con->set_status( websocketpp::http::status_code::value( response.status ) ); } catch ( const fc::exception& e ) @@ -413,8 +414,6 @@ namespace fc { namespace http { _server.close( item.first, 0, "server exit" ); } - void set_forward_header_key( const std::string& key ) { fwd_header_key = key; } - typedef std::map > con_map; con_map _connections; @@ -422,7 +421,7 @@ namespace fc { namespace http { websocket_tls_server_type _server; on_connection_handler _on_connection; fc::promise::ptr _closed; - std::string fwd_header_key; + std::string _forward_header_key; // A header like "X-Forwarded-For" (XFF), with data IP:port }; typedef websocketpp::client websocket_client_type; @@ -558,8 +557,8 @@ namespace fc { namespace http { } // namespace detail - websocket_server::websocket_server() - :my( new detail::websocket_server_impl() ) {} + websocket_server::websocket_server( const std::string& forward_header_key ) + :my( new detail::websocket_server_impl( forward_header_key ) ) {} websocket_server::~websocket_server(){} void websocket_server::on_connection( const on_connection_handler& handler ) @@ -597,12 +596,11 @@ namespace fc { namespace http { my->_server.close(connection.first, websocketpp::close::status::normal, "Goodbye"); } - void websocket_server::set_forward_header_key( const std::string& key ) - { - my->set_forward_header_key( key ); - } + websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password, + const std::string& forward_header_key ) + :my( new detail::websocket_tls_server_impl(server_pem, ssl_password, forward_header_key) ) + {} - websocket_tls_server::websocket_tls_server( const string& server_pem, const string& ssl_password ):my( new detail::websocket_tls_server_impl(server_pem, ssl_password) ) {} websocket_tls_server::~websocket_tls_server(){} void websocket_tls_server::on_connection( const on_connection_handler& handler ) @@ -629,7 +627,11 @@ namespace fc { namespace http { - websocket_client::websocket_client( const std::string& ca_filename ):my( new detail::websocket_client_impl() ),smy(new detail::websocket_tls_client_impl( ca_filename )) {} + websocket_client::websocket_client( const std::string& ca_filename ) + :my( new detail::websocket_client_impl() ), + smy(new detail::websocket_tls_client_impl( ca_filename )) + {} + websocket_client::~websocket_client(){ } websocket_connection_ptr websocket_client::connect( const std::string& uri ) @@ -646,7 +648,8 @@ namespace fc { namespace http { my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ my->_hdl = hdl; auto con = my->_client.get_con_from_hdl(hdl); - my->_connection = std::make_shared>( con ); + my->_connection = std::make_shared>( con, "" ); my->_closed = promise::create("websocket::closed"); my->_connected->set_value(); }); @@ -654,7 +657,7 @@ namespace fc { namespace http { auto con = my->_client.get_connection( uri, ec ); std::for_each(headers.begin(), headers.end(), [con](std::pair in) { - con->append_header(in.first, in.second); + con->append_header(in.first, in.second); }); if( ec ) FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); @@ -675,7 +678,8 @@ namespace fc { namespace http { smy->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ auto con = smy->_client.get_con_from_hdl(hdl); - smy->_connection = std::make_shared>( con ); + smy->_connection = std::make_shared>( con, "" ); smy->_closed = promise::create("websocket::closed"); smy->_connected->set_value(); }); @@ -708,14 +712,14 @@ namespace fc { namespace http { websocket_connection_ptr websocket_tls_client::connect( const std::string& uri ) { try { - // wlog( "connecting to ${uri}", ("uri",uri)); websocketpp::lib::error_code ec; my->_connected = promise::create("websocket::connect"); my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ auto con = my->_client.get_con_from_hdl(hdl); - my->_connection = std::make_shared>( con ); + my->_connection = std::make_shared>( con, "" ); my->_closed = promise::create("websocket::closed"); my->_connected->set_value(); }); From 9c506d050bc90f7dcce05431d055deccd777b1af Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 1 May 2020 17:46:19 -0400 Subject: [PATCH 13/23] Fix test cases --- tests/api_tests.cpp | 4 ++-- tests/network/http/websocket_test.cpp | 8 +++----- tests/ws_test_server.cpp | 3 +-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/tests/api_tests.cpp b/tests/api_tests.cpp index dff535077..3c41b79aa 100644 --- a/tests/api_tests.cpp +++ b/tests/api_tests.cpp @@ -65,7 +65,7 @@ BOOST_AUTO_TEST_CASE(login_test) { try { fc::api calc_api( std::make_shared() ); - auto server = std::make_shared(); + auto server = std::make_shared(""); server->on_connection([&]( const websocket_connection_ptr& c ){ auto wsc = std::make_shared(c, MAX_DEPTH); auto login = std::make_shared(); @@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(optionals_test) { BOOST_CHECK_EQUAL(oapi->foo("a", "b", "c"), "[\"a\",\"b\",\"c\"]"); BOOST_CHECK_EQUAL(oapi->foo("a", {}, "c"), "[\"a\",null,\"c\"]"); - auto server = std::make_shared(); + auto server = std::make_shared(""); server->on_connection([&]( const websocket_connection_ptr& c ){ auto wsc = std::make_shared(c, MAX_DEPTH); wsc->register_api(fc::api(optionals)); diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp index 400d242c3..9efe558ab 100644 --- a/tests/network/http/websocket_test.cpp +++ b/tests/network/http/websocket_test.cpp @@ -19,10 +19,9 @@ BOOST_AUTO_TEST_CASE(websocket_test) fc::http::websocket_connection_ptr s_conn, c_conn; int port; { - fc::http::websocket_server server; - // even with this set, if the remote does not provide it, it will revert to + // even with this key set, if the remote does not provide it, it will revert to // the remote endpoint - server.set_forward_header_key("MyProxyHeaderKey"); + fc::http::websocket_server server("MyProxyHeaderKey"); server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ s_conn = c; c->on_message_handler([&](const std::string& s){ @@ -80,8 +79,7 @@ BOOST_AUTO_TEST_CASE(websocket_test_with_proxy_header) int port; { // the server will be on the lookout for the key in the header - fc::http::websocket_server server; - server.set_forward_header_key("MyProxyHeaderKey"); + fc::http::websocket_server server("MyProxyHeaderKey"); server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ s_conn = c; c->on_message_handler([&](const std::string& s){ diff --git a/tests/ws_test_server.cpp b/tests/ws_test_server.cpp index 2ae2ba150..02be0edd2 100644 --- a/tests/ws_test_server.cpp +++ b/tests/ws_test_server.cpp @@ -13,8 +13,7 @@ int main(int argc, char** argv) fc::logger l = fc::logger::get("rpc"); l.add_appender( ca ); - fc::http::websocket_server server; - server.set_forward_header_key("MyForwardHeaderKey"); + fc::http::websocket_server server("MyForwardHeaderKey"); server.on_connection([&]( const fc::http::websocket_connection_ptr& c ){ c->on_message_handler([&](const std::string& s){ From e50067d6ed5e067b8b00424ffb18ceef1ab288fd Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 1 May 2020 17:57:21 -0400 Subject: [PATCH 14/23] Tweak code slightly --- src/network/http/websocket.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index c19421703..87c1e6510 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -370,7 +370,7 @@ namespace fc { namespace http { std::string request_body = con->get_request_body(); wlog( "[IN] ${remote_endpoint} ${msg}", ("remote_endpoint",remote_endpoint) ("msg",request_body) ); - auto response = current_con->on_http( con->get_request_body() ); + auto response = current_con->on_http( request_body ); ilog( "[OUT] ${remote_endpoint} ${msg}", ("remote_endpoint",remote_endpoint) ("msg",response) ); con->set_body( std::move( response.body_as_string ) ); @@ -707,7 +707,7 @@ namespace fc { namespace http { void websocket_client::append_header(const std::string& key, const std::string& value) { - headers.push_back( std::pair(key, value)); + headers.push_back( std::make_pair(key, value) ); } websocket_connection_ptr websocket_tls_client::connect( const std::string& uri ) From e778cf1520a6823276d576f71c585ac10f73653a Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 1 May 2020 19:11:09 -0400 Subject: [PATCH 15/23] Revert to simple WS connection for clients --- src/network/http/websocket.cpp | 45 +++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index e30c1f15d..6fb9f0685 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -176,14 +176,9 @@ namespace fc { namespace http { class websocket_connection_impl : public websocket_connection { public: - websocket_connection_impl( T con, const std::string& forward_header_key ) : _ws_connection(con) + websocket_connection_impl( T con ) : _ws_connection(con) { - // Firstly, try to extract remote address from a XFF-like header - if( !forward_header_key.empty() ) - _remote_endpoint = get_request_header( forward_header_key ); - // If the last step failed, retrieve the remote address from the connection - if( _remote_endpoint.empty() ) - _remote_endpoint = con->get_remote_endpoint(); + _remote_endpoint = con->get_remote_endpoint(); } virtual ~websocket_connection_impl() @@ -210,6 +205,28 @@ namespace fc { namespace http { T _ws_connection; }; + template + class possibly_proxied_websocket_connection : public websocket_connection_impl + { + public: + possibly_proxied_websocket_connection( T con, const std::string& forward_header_key ) + : websocket_connection_impl(con) + { + // By calling the parent's constructor, _remote_endpoint has been initialized. + // Now try to extract remote address from the header, if found, overwrite it + if( !forward_header_key.empty() ) + { + const std::string value = this->get_request_header( forward_header_key ); + if( !value.empty() ) + this->_remote_endpoint = value; + } + } + + virtual ~possibly_proxied_websocket_connection() + { + } + }; + typedef websocketpp::lib::shared_ptr context_ptr; class websocket_server_impl @@ -223,7 +240,7 @@ namespace fc { namespace http { _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ _server_thread.async( [this, hdl](){ - auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl), _forward_header_key ); _on_connection( _connections[hdl] = new_con ); @@ -256,7 +273,7 @@ namespace fc { namespace http { _server.set_http_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ auto con = _server.get_con_from_hdl(hdl); - auto current_con = std::make_shared>( con, _forward_header_key ); _on_connection( current_con ); @@ -369,7 +386,7 @@ namespace fc { namespace http { _server.set_reuse_addr(true); _server.set_open_handler( [&]( connection_hdl hdl ){ _server_thread.async( [&](){ - auto new_con = std::make_shared>( _server.get_con_from_hdl(hdl), _forward_header_key ); _on_connection( _connections[hdl] = new_con ); @@ -391,7 +408,7 @@ namespace fc { namespace http { _server_thread.async( [&](){ auto con = _server.get_con_from_hdl(hdl); - auto current_con = std::make_shared>( con, _forward_header_key ); try{ _on_connection( current_con ); @@ -685,7 +702,7 @@ namespace fc { namespace http { my->_hdl = hdl; auto con = my->_client.get_con_from_hdl(hdl); my->_connection = std::make_shared>( con, "" ); + detail::websocket_client_connection_type>>( con ); my->_closed = promise::create("websocket::closed"); my->_connected->set_value(); }); @@ -715,7 +732,7 @@ namespace fc { namespace http { smy->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ auto con = smy->_client.get_con_from_hdl(hdl); smy->_connection = std::make_shared>( con, "" ); + detail::websocket_tls_client_connection_type>>( con ); smy->_closed = promise::create("websocket::closed"); smy->_connected->set_value(); }); @@ -755,7 +772,7 @@ namespace fc { namespace http { my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ auto con = my->_client.get_con_from_hdl(hdl); my->_connection = std::make_shared>( con, "" ); + detail::websocket_tls_client_connection_type>>( con ); my->_closed = promise::create("websocket::closed"); my->_connected->set_value(); }); From 8ddcc87ee136ede5b8185ef0e358277946ec70f1 Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 1 May 2020 19:43:29 -0400 Subject: [PATCH 16/23] Add todo --- include/fc/network/http/websocket.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index 4b2776e63..c04d1d4bf 100644 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -15,6 +15,8 @@ namespace fc { namespace http { class websocket_tls_client_impl; } // namespace detail + // TODO refactor code, move stuff used by server or client only to derived class(es), + // E.G. it seems get_request_header and on_http* are for server only. class websocket_connection { public: From c6df78b0bb911c3635d07a489f65802e35a16e84 Mon Sep 17 00:00:00 2001 From: abitmore Date: Fri, 1 May 2020 20:51:47 -0400 Subject: [PATCH 17/23] Rename a function to avoid accidental misuse --- include/fc/network/http/websocket.hpp | 2 +- src/network/http/websocket.cpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index c04d1d4bf..e47646b9a 100644 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -34,7 +34,7 @@ namespace fc { namespace http { virtual std::string get_request_header(const std::string& key) = 0; - const std::string& get_remote_endpoint()const { return _remote_endpoint; } + const std::string& get_remote_endpoint_string()const { return _remote_endpoint; } fc::signal closed; protected: diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 6fb9f0685..81c35ebc3 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -253,7 +253,7 @@ namespace fc { namespace http { auto payload = msg->get_payload(); std::shared_ptr con = current_con->second; wlog( "[IN] ${remote_endpoint} ${msg}", - ("remote_endpoint",con->get_remote_endpoint()) ("msg",payload) ); + ("remote_endpoint",con->get_remote_endpoint_string()) ("msg",payload) ); ++_pending_messages; auto f = fc::async([this,con,payload](){ if( _pending_messages ) @@ -278,7 +278,7 @@ namespace fc { namespace http { _on_connection( current_con ); con->defer_http_response(); - std::string remote_endpoint = current_con->get_remote_endpoint(); + std::string remote_endpoint = current_con->get_remote_endpoint_string(); std::string request_body = con->get_request_body(); wlog( "[IN] ${remote_endpoint} ${msg}", ("remote_endpoint",remote_endpoint) ("msg",request_body) ); @@ -399,7 +399,7 @@ namespace fc { namespace http { auto received = msg->get_payload(); std::shared_ptr con = current_con->second; wlog( "[IN] ${remote_endpoint} ${msg}", - ("remote_endpoint",con->get_remote_endpoint()) ("msg",received) ); + ("remote_endpoint",con->get_remote_endpoint_string()) ("msg",received) ); fc::async([con,received](){ con->on_message( received ); }); }).wait(); }); @@ -413,7 +413,7 @@ namespace fc { namespace http { try{ _on_connection( current_con ); - std::string remote_endpoint = current_con->get_remote_endpoint(); + std::string remote_endpoint = current_con->get_remote_endpoint_string(); std::string request_body = con->get_request_body(); wlog( "[IN] ${remote_endpoint} ${msg}", ("remote_endpoint",remote_endpoint) ("msg",request_body) ); @@ -476,7 +476,6 @@ namespace fc { namespace http { typedef websocket_client_type::connection_ptr websocket_client_connection_type; typedef websocket_tls_client_type::connection_ptr websocket_tls_client_connection_type; - using websocketpp::connection_hdl; template class generic_websocket_client_impl From 3e07edf9957d75fa6280a0017d13681add25cccd Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 2 May 2020 04:03:01 -0400 Subject: [PATCH 18/23] Remove unused header inclusion --- src/network/http/websocket.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 81c35ebc3..410870445 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -20,8 +20,6 @@ #include #include -#include - #if WIN32 #include #endif From c8fcefb901684ef82b2af0a2c27e283b775bae02 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 2 May 2020 04:17:44 -0400 Subject: [PATCH 19/23] Update RPC logging format --- src/network/http/websocket.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 410870445..92491262f 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -278,13 +278,15 @@ namespace fc { namespace http { con->defer_http_response(); std::string remote_endpoint = current_con->get_remote_endpoint_string(); std::string request_body = con->get_request_body(); - wlog( "[IN] ${remote_endpoint} ${msg}", + wlog( "[HTTP-IN] ${remote_endpoint} ${msg}", ("remote_endpoint",remote_endpoint) ("msg",request_body) ); fc::async([current_con, request_body, con, remote_endpoint] { fc::http::reply response = current_con->on_http(request_body); - ilog( "[OUT] ${remote_endpoint} ${msg}", - ("remote_endpoint",remote_endpoint) ("msg",response) ); + ilog( "[HTTP-OUT] ${remote_endpoint} ${status} ${msg}", + ("remote_endpoint",remote_endpoint) + ("status",response.status) + ("msg",response.body_as_string) ); con->set_body( std::move( response.body_as_string ) ); con->set_status( websocketpp::http::status_code::value(response.status) ); con->send_http_response(); @@ -413,11 +415,13 @@ namespace fc { namespace http { std::string remote_endpoint = current_con->get_remote_endpoint_string(); std::string request_body = con->get_request_body(); - wlog( "[IN] ${remote_endpoint} ${msg}", + wlog( "[HTTP-IN] ${remote_endpoint} ${msg}", ("remote_endpoint",remote_endpoint) ("msg",request_body) ); auto response = current_con->on_http( request_body ); - ilog( "[OUT] ${remote_endpoint} ${msg}", - ("remote_endpoint",remote_endpoint) ("msg",response) ); + ilog( "[HTTP-OUT] ${remote_endpoint} ${status} ${msg}", + ("remote_endpoint",remote_endpoint) + ("status",response.status) + ("msg",response.body_as_string) ); con->set_body( std::move( response.body_as_string ) ); con->set_status( websocketpp::http::status_code::value( response.status ) ); } catch ( const fc::exception& e ) From c58ae55f44cd62c31e8a482dec7b97f481f9dc92 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 2 May 2020 04:40:28 -0400 Subject: [PATCH 20/23] Update test cases about RPC logging level --- tests/network/http/websocket_test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp index 9efe558ab..7e4453c17 100644 --- a/tests/network/http/websocket_test.cpp +++ b/tests/network/http/websocket_test.cpp @@ -69,6 +69,8 @@ BOOST_AUTO_TEST_CASE(websocket_test_with_proxy_header) // set up logging fc::appender::ptr ca(new fc::console_appender); fc::logger l = fc::logger::get("rpc"); + auto old_log_level = l.get_log_level(); + l.set_log_level( fc::log_level::info ); l.add_appender( ca ); fc::http::websocket_client client; @@ -119,7 +121,9 @@ BOOST_AUTO_TEST_CASE(websocket_test_with_proxy_header) BOOST_CHECK_THROW(c_conn->send_message( "again" ), fc::assert_exception); BOOST_CHECK_THROW(client.connect( "ws://localhost:" + fc::to_string(port) ), fc::exception); + l.remove_appender(ca); + l.set_log_level(old_log_level); } BOOST_AUTO_TEST_SUITE_END() From ffbda4e161e05be440c9720c14ccaddeb488df54 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 2 May 2020 05:46:21 -0400 Subject: [PATCH 21/23] Add test cases about on_http for websocket servers --- tests/network/http/websocket_test.cpp | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp index 7e4453c17..d70fa0da1 100644 --- a/tests/network/http/websocket_test.cpp +++ b/tests/network/http/websocket_test.cpp @@ -27,6 +27,11 @@ BOOST_AUTO_TEST_CASE(websocket_test) c->on_message_handler([&](const std::string& s){ c->send_message("echo: " + s); }); + c->on_http_handler([&](const std::string& s){ + fc::http::reply reply; + reply.body_as_string = "http-echo: " + s; + return reply; + }); }); server.listen( 0 ); @@ -57,6 +62,18 @@ BOOST_AUTO_TEST_CASE(websocket_test) c_conn->send_message( "hello world" ); fc::usleep( fc::milliseconds(100) ); BOOST_CHECK_EQUAL("echo: hello world", echo); + + // Testing on_http + std::string server_endpoint_string = "127.0.0.1:" + fc::to_string(port); + fc::ip::endpoint server_endpoint = fc::ip::endpoint::from_string( server_endpoint_string ); + fc::http::connection c_http_conn; + c_http_conn.connect_to( server_endpoint ); + + std::string url = "http://localhost:" + fc::to_string(port); + fc::http::reply reply = c_http_conn.request( "POST", url, "hello world again" ); + std::string reply_body( reply.body.begin(), reply.body.end() ); + BOOST_CHECK_EQUAL(200, reply.status); + BOOST_CHECK_EQUAL("http-echo: hello world again", reply_body ); } BOOST_CHECK_THROW(c_conn->send_message( "again" ), fc::assert_exception); @@ -87,6 +104,11 @@ BOOST_AUTO_TEST_CASE(websocket_test_with_proxy_header) c->on_message_handler([&](const std::string& s){ c->send_message("echo: " + s); }); + c->on_http_handler([&](const std::string& s){ + fc::http::reply reply; + reply.body_as_string = "http-echo: " + s; + return reply; + }); }); server.listen( 0 ); @@ -117,6 +139,20 @@ BOOST_AUTO_TEST_CASE(websocket_test_with_proxy_header) c_conn->send_message( "hello world" ); fc::usleep( fc::milliseconds(100) ); BOOST_CHECK_EQUAL("echo: hello world", echo); + + // Testing on_http + std::string server_endpoint_string = "127.0.0.1:" + fc::to_string(port); + fc::ip::endpoint server_endpoint = fc::ip::endpoint::from_string( server_endpoint_string ); + fc::http::connection c_http_conn; + c_http_conn.connect_to( server_endpoint ); + + std::string url = "http://localhost:" + fc::to_string(port); + fc::http::header fwd("MyProxyHeaderKey", "MyServer:8080"); + fc::http::headers headers {fwd}; + fc::http::reply reply = c_http_conn.request( "POST", url, "hello world again", headers ); + std::string reply_body( reply.body.begin(), reply.body.end() ); + BOOST_CHECK_EQUAL(200, reply.status); + BOOST_CHECK_EQUAL("http-echo: hello world again", reply_body ); } BOOST_CHECK_THROW(c_conn->send_message( "again" ), fc::assert_exception); From aa54e3938cfed26092896c64c6cefec696f0857a Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 2 May 2020 06:33:46 -0400 Subject: [PATCH 22/23] Remove unused websocket_tls_client class The funcionality is already covered by the websocket_client class --- include/fc/network/http/websocket.hpp | 10 --------- src/network/http/websocket.cpp | 29 --------------------------- 2 files changed, 39 deletions(-) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index e47646b9a..0c765c1f3 100644 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -103,15 +103,5 @@ namespace fc { namespace http { std::unique_ptr smy; std::vector> headers; }; - class websocket_tls_client - { - public: - websocket_tls_client( const std::string& ca_filename = "_default" ); - ~websocket_tls_client(); - - websocket_connection_ptr connect( const std::string& uri ); - private: - std::unique_ptr my; - }; } } diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 92491262f..6e6a3955c 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -676,11 +676,6 @@ namespace fc { namespace http { } - websocket_tls_client::websocket_tls_client( const std::string& ca_filename ):my( new detail::websocket_tls_client_impl( ca_filename ) ) {} - websocket_tls_client::~websocket_tls_client(){ } - - - websocket_client::websocket_client( const std::string& ca_filename ) :my( new detail::websocket_client_impl() ), smy(new detail::websocket_tls_client_impl( ca_filename )) @@ -764,28 +759,4 @@ namespace fc { namespace http { headers.push_back( std::make_pair(key, value) ); } - websocket_connection_ptr websocket_tls_client::connect( const std::string& uri ) - { try { - websocketpp::lib::error_code ec; - - my->_connected = promise::create("websocket::connect"); - - my->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ - auto con = my->_client.get_con_from_hdl(hdl); - my->_connection = std::make_shared>( con ); - my->_closed = promise::create("websocket::closed"); - my->_connected->set_value(); - }); - - auto con = my->_client.get_connection( uri, ec ); - if( ec ) - { - FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); - } - my->_client.connect(con); - my->_connected->wait(); - return my->_connection; - } FC_CAPTURE_AND_RETHROW( (uri) ) } - } } // fc::http From ea96a5a93b34ce5338e65b0e6f222ebba96159a1 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 2 May 2020 06:35:56 -0400 Subject: [PATCH 23/23] Fix websocket_client::secure_connect() Code synced from connect(), added todo to refactor later --- src/network/http/websocket.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/network/http/websocket.cpp b/src/network/http/websocket.cpp index 6e6a3955c..b2997d944 100644 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -715,6 +715,7 @@ namespace fc { namespace http { return my->_connection; } FC_CAPTURE_AND_RETHROW( (uri) ) } + // TODO most code in this function is same as ::connect, best refactor websocket_connection_ptr websocket_client::secure_connect( const std::string& uri ) { try { if( uri.substr(0,3) == "ws:" ) @@ -726,6 +727,7 @@ namespace fc { namespace http { smy->_connected = promise::create("websocket::connect"); smy->_client.set_open_handler( [=]( websocketpp::connection_hdl hdl ){ + smy->_hdl = hdl; auto con = smy->_client.get_con_from_hdl(hdl); smy->_connection = std::make_shared>( con ); @@ -734,12 +736,15 @@ namespace fc { namespace http { }); auto con = smy->_client.get_connection( uri, ec ); + std::for_each(headers.begin(), headers.end(), [con](std::pair in) { + con->append_header(in.first, in.second); + }); if( ec ) FC_ASSERT( !ec, "error: ${e}", ("e",ec.message()) ); smy->_client.connect(con); smy->_connected->wait(); return smy->_connection; - } FC_CAPTURE_AND_RETHROW( (uri) ) } + } FC_CAPTURE_AND_RETHROW( (uri) ) } void websocket_client::close() {