From 5a897c3b841e1564acf63fcc7ba75bc426ece5e5 Mon Sep 17 00:00:00 2001 From: pravin-battu Date: Thu, 6 Aug 2020 09:57:01 -0300 Subject: [PATCH 1/4] ws-updates --- include/fc/network/http/websocket.hpp | 14 +- include/fc/rpc/websocket_api.hpp | 124 ++++++++++++++---- src/network/http/websocket.cpp | 118 +++++++---------- src/rpc/websocket_api.cpp | 21 +-- tests/api.cpp | 4 +- vendor/websocketpp/changelog.md | 3 + .../test/connection/connection.cpp | 28 ++++ vendor/websocketpp/websocketpp/connection.hpp | 1 + .../extensions/permessage_deflate/enabled.hpp | 104 ++++++++++++--- .../websocketpp/impl/connection_impl.hpp | 11 ++ .../websocketpp/transport/asio/connection.hpp | 11 +- .../websocketpp/transport/asio/endpoint.hpp | 17 ++- .../transport/asio/security/none.hpp | 3 +- .../transport/asio/security/tls.hpp | 3 +- 14 files changed, 312 insertions(+), 150 deletions(-) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index a42c1f8..6cfd66c 100755 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -2,7 +2,7 @@ #include #include #include -#include +#include #include #include @@ -26,14 +26,14 @@ namespace fc { namespace http { void on_message_handler( const std::function& h ) { _on_message = h; } void on_http_handler( const std::function& h ) { _on_http = h; } - void set_session_data( fc::any d ){ _session_data = std::move(d); } - fc::any& get_session_data() { return _session_data; } + void set_session_data( boost::any d ){ _session_data = std::move(d); } + boost::any& get_session_data() { return _session_data; } virtual std::string get_request_header(const std::string& key) = 0; fc::signal closed; private: - fc::any _session_data; + boost::any _session_data; std::function _on_message; std::function _on_http; }; @@ -53,6 +53,8 @@ namespace fc { namespace http { uint16_t get_listening_port(); void start_accept(); + void stop_listening(); + void close(); private: friend class detail::websocket_server_impl; std::unique_ptr my; @@ -84,6 +86,10 @@ namespace fc { namespace http { websocket_connection_ptr connect( const std::string& uri ); websocket_connection_ptr secure_connect( const std::string& uri ); + + void close(); + void synchronous_close(); + private: std::unique_ptr my; std::unique_ptr smy; diff --git a/include/fc/rpc/websocket_api.hpp b/include/fc/rpc/websocket_api.hpp index ebb6fe7..6cfd66c 100755 --- a/include/fc/rpc/websocket_api.hpp +++ b/include/fc/rpc/websocket_api.hpp @@ -1,36 +1,108 @@ #pragma once -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include -namespace fc { namespace rpc { +namespace fc { namespace http { + namespace detail { + class websocket_server_impl; + class websocket_tls_server_impl; + class websocket_client_impl; + class websocket_tls_client_impl; + } // namespace detail; - class websocket_api_connection : public api_connection + class websocket_connection { public: - websocket_api_connection( fc::http::websocket_connection& c, uint32_t max_conversion_depth ); - ~websocket_api_connection(); + virtual ~websocket_connection(){} + virtual void send_message( const std::string& message ) = 0; + virtual void close( int64_t code, const std::string& reason ){}; + void on_message( const std::string& message ) { _on_message(message); } + string on_http( const std::string& message ) { return _on_http(message); } - virtual variant send_call( - api_id_type api_id, - string method_name, - variants args = variants() ) override; - virtual variant send_callback( - uint64_t callback_id, - variants args = variants() ) override; - virtual void send_notice( - uint64_t callback_id, - variants args = variants() ) override; + void on_message_handler( const std::function& h ) { _on_message = h; } + void on_http_handler( const std::function& h ) { _on_http = h; } - protected: - std::string on_message( - const std::string& message, - bool send_message = true ); + void set_session_data( boost::any d ){ _session_data = std::move(d); } + boost::any& get_session_data() { return _session_data; } - fc::http::websocket_connection& _connection; - fc::rpc::state _rpc_state; + virtual std::string get_request_header(const std::string& key) = 0; + + fc::signal closed; + private: + boost::any _session_data; + std::function _on_message; + std::function _on_http; + }; + typedef std::shared_ptr websocket_connection_ptr; + + typedef std::function on_connection_handler; + + class websocket_server + { + public: + websocket_server(); + ~websocket_server(); + + void on_connection( const on_connection_handler& handler); + void listen( uint16_t port ); + void listen( const fc::ip::endpoint& ep ); + uint16_t get_listening_port(); + void start_accept(); + + void stop_listening(); + void close(); + private: + friend class detail::websocket_server_impl; + std::unique_ptr my; }; -} } // namespace fc::rpc + + 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(); + + void on_connection( const on_connection_handler& handler); + void listen( uint16_t port ); + void listen( const fc::ip::endpoint& ep ); + void start_accept(); + + private: + friend class detail::websocket_tls_server_impl; + std::unique_ptr my; + }; + + class websocket_client + { + public: + websocket_client( const std::string& ca_filename = "_default" ); + ~websocket_client(); + + websocket_connection_ptr connect( const std::string& uri ); + websocket_connection_ptr secure_connect( const std::string& uri ); + + void close(); + void synchronous_close(); + + private: + std::unique_ptr my; + std::unique_ptr smy; + }; + 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 6440dd6..88c72be 100755 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -416,18 +416,20 @@ 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; - class websocket_client_impl + using websocketpp::connection_hdl; + + template + class generic_websocket_client_impl { public: - typedef websocket_client_type::message_ptr message_ptr; - - websocket_client_impl() + generic_websocket_client_impl() :_client_thread( fc::thread::current() ) { _client.clear_access_channels( websocketpp::log::alevel::all ); - _client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){ + _client.set_message_handler( [&]( connection_hdl hdl, + typename websocketpp::client::message_ptr msg ){ _client_thread.async( [&](){ - idump((msg->get_payload())); + wdump((msg->get_payload())); //std::cerr<<"recv: "<get_payload()<<"\n"; auto received = msg->get_payload(); fc::async( [=](){ @@ -453,73 +455,38 @@ namespace fc { namespace http { _client.init_asio( &fc::asio::default_io_service() ); } - ~websocket_client_impl() + virtual ~generic_websocket_client_impl() { - if(_connection ) + if( _connection ) { _connection->close(0, "client closed"); _connection.reset(); - _closed->wait(); } + if( _closed ) + _closed->wait(); } fc::promise::ptr _connected; fc::promise::ptr _closed; fc::thread& _client_thread; - websocket_client_type _client; + websocketpp::client _client; websocket_connection_ptr _connection; std::string _uri; + fc::optional _hdl; }; + class websocket_client_impl : public generic_websocket_client_impl + {}; - - class websocket_tls_client_impl + class websocket_tls_client_impl : public generic_websocket_client_impl { public: - typedef websocket_tls_client_type::message_ptr message_ptr; - websocket_tls_client_impl( const std::string& ca_filename ) - :_client_thread( fc::thread::current() ) + : generic_websocket_client_impl() { // ca_filename has special values: // "_none" disables cert checking (potentially insecure!) // "_default" uses default CA's provided by OS - _client.clear_access_channels( websocketpp::log::alevel::all ); - _client.set_message_handler( [&]( connection_hdl hdl, message_ptr msg ){ - _client_thread.async( [&](){ - idump((msg->get_payload())); - _connection->on_message( msg->get_payload() ); - }).wait(); - }); - _client.set_close_handler( [=]( connection_hdl hdl ){ - if( _connection ) - { - try { - _client_thread.async( [&](){ - ilog(". ${p}", ("p",uint64_t(_connection.get()))); - if( !_shutting_down && !_closed && _connection ) - _connection->closed(); - _connection.reset(); - } ).wait(); - } catch ( const fc::exception& e ) - { - if( _closed ) _closed->set_exception( e.dynamic_copy_exception() ); - } - if( _closed ) _closed->set_value(); - } - }); - _client.set_fail_handler( [=]( connection_hdl hdl ){ - elog( "." ); - auto con = _client.get_con_from_hdl(hdl); - auto message = con->get_ec().message(); - if( _connection ) - _client_thread.async( [&](){ if( _connection ) _connection->closed(); _connection.reset(); } ).wait(); - if( _connected && !_connected->ready() ) - _connected->set_exception( exception_ptr( new FC_EXCEPTION( exception, "${message}", ("message",message)) ) ); - if( _closed ) - _closed->set_value(); - }); - // // We need ca_filename to be copied into the closure, as the referenced object might be destroyed by the caller by the time // tls_init_handler() is called. According to [1], capture-by-value results in the desired behavior (i.e. creation of @@ -552,18 +519,8 @@ namespace fc { namespace http { return ctx; }); - _client.init_asio( &fc::asio::default_io_service() ); - } - ~websocket_tls_client_impl() - { - if(_connection ) - { - ilog("."); - _shutting_down = true; - _connection->close(0, "client closed"); - _closed->wait(); - } } + virtual ~websocket_tls_client_impl() {} std::string get_host()const { @@ -576,20 +533,19 @@ namespace fc { namespace http { return; ctx->set_verify_mode( boost::asio::ssl::verify_peer ); if( ca_filename == "_default" ) + { +#if WIN32 + add_windows_root_certs( *ctx ); +#else ctx->set_default_verify_paths(); +#endif + } else ctx->load_verify_file( ca_filename ); ctx->set_verify_depth(10); ctx->set_verify_callback( boost::asio::ssl::rfc2818_verification( get_host() ) ); } - bool _shutting_down = false; - fc::promise::ptr _connected; - fc::promise::ptr _closed; - fc::thread& _client_thread; - websocket_tls_client_type _client; - websocket_connection_ptr _connection; - std::string _uri; }; @@ -622,8 +578,16 @@ namespace fc { namespace http { my->_server.start_accept(); } + void websocket_server::stop_listening() + { + my->_server.stop_listening(); + } - + void websocket_server::close() + { + for (auto& connection : my->_connections) + my->_server.close(connection.first, websocketpp::close::status::normal, "Goodbye"); + } 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(){} @@ -646,7 +610,6 @@ namespace fc { namespace http { my->_server.start_accept(); } - 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(){ } @@ -709,6 +672,19 @@ namespace fc { namespace http { return smy->_connection; } FC_CAPTURE_AND_RETHROW( (uri) ) } + void websocket_client::close() + { + if (my->_hdl) + my->_client.close(*my->_hdl, websocketpp::close::status::normal, "Goodbye"); + } + + void websocket_client::synchronous_close() + { + close(); + if (my->_closed) + my->_closed->wait(); + } + websocket_connection_ptr websocket_tls_client::connect( const std::string& uri ) { try { // wlog( "connecting to ${uri}", ("uri",uri)); diff --git a/src/rpc/websocket_api.cpp b/src/rpc/websocket_api.cpp index ae4e26e..1c4ee5a 100755 --- a/src/rpc/websocket_api.cpp +++ b/src/rpc/websocket_api.cpp @@ -7,7 +7,7 @@ websocket_api_connection::~websocket_api_connection() { } -websocket_api_connection::websocket_api_connection( fc::http::websocket_connection& c, uint32_t max_depth ) +websocket_api_connection::websocket_api_connection(const std::shared_ptr& c, uint32_t max_depth ) : api_connection(max_depth),_connection(c) { _rpc_state.add_method( "call", [this]( const variants& args ) -> variant @@ -47,9 +47,12 @@ websocket_api_connection::websocket_api_connection( fc::http::websocket_connecti return this->receive_call( 0, method_name, args ); } ); - _connection.on_message_handler( [&]( const std::string& msg ){ on_message(msg,true); } ); - _connection.on_http_handler( [&]( const std::string& msg ){ return on_message(msg,false); } ); - _connection.closed.connect( [this](){ closed(); } ); + _connection->on_message_handler( [&]( const std::string& msg ){ on_message(msg,true); } ); + _connection->on_http_handler( [&]( const std::string& msg ){ return on_message(msg,false); } ); + _connection->closed.connect( [this](){ + closed(); + _connection = nullptr; + } ); } variant websocket_api_connection::send_call( @@ -58,7 +61,7 @@ variant websocket_api_connection::send_call( variants args /* = variants() */ ) { auto request = _rpc_state.start_remote_call( "call", {api_id, std::move(method_name), std::move(args) } ); - _connection.send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth), + _connection->send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); return _rpc_state.wait_for_response( *request.id ); } @@ -68,7 +71,7 @@ variant websocket_api_connection::send_callback( variants args /* = variants() */ ) { auto request = _rpc_state.start_remote_call( "callback", {callback_id, std::move(args) } ); - _connection.send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth), + _connection->send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); return _rpc_state.wait_for_response( *request.id ); } @@ -78,7 +81,7 @@ void websocket_api_connection::send_notice( variants args /* = variants() */ ) { fc::rpc::request req{ optional(), "notice", {callback_id, std::move(args)}}; - _connection.send_message( fc::json::to_string(fc::variant(req, _max_conversion_depth), + _connection->send_message( fc::json::to_string(fc::variant(req, _max_conversion_depth), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); } @@ -118,7 +121,7 @@ std::string websocket_api_connection::on_message( { auto reply = fc::json::to_string( response( *call.id, result, "2.0" ), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); if( send_message ) - _connection.send_message( reply ); + _connection->send_message( reply ); return reply; } } @@ -136,7 +139,7 @@ std::string websocket_api_connection::on_message( auto reply = fc::json::to_string( variant(response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept, _max_conversion_depth)}, "2.0" ), _max_conversion_depth ), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); if( send_message ) - _connection.send_message( reply ); + _connection->send_message( reply ); return reply; } diff --git a/tests/api.cpp b/tests/api.cpp index e0514c3..fbe42f2 100755 --- a/tests/api.cpp +++ b/tests/api.cpp @@ -61,7 +61,7 @@ int main( int argc, char** argv ) fc::http::websocket_server server; server.on_connection([&]( const websocket_connection_ptr& c ){ - auto wsc = std::make_shared(*c, MAX_DEPTH); + auto wsc = std::make_shared(c, MAX_DEPTH); auto login = std::make_shared(); login->calc = calc_api; wsc->register_api(fc::api(login)); @@ -76,7 +76,7 @@ int main( int argc, char** argv ) try { fc::http::websocket_client client; auto con = client.connect( "ws://localhost:8090" ); - auto apic = std::make_shared(*con, MAX_DEPTH); + auto apic = std::make_shared(con, MAX_DEPTH); auto remote_login_api = apic->get_remote_api(); auto remote_calc = remote_login_api->get_calc(); remote_calc->on_result( []( uint32_t r ) { elog( "callback result ${r}", ("r",r) ); } ); diff --git a/vendor/websocketpp/changelog.md b/vendor/websocketpp/changelog.md index 15846ce..a838e54 100644 --- a/vendor/websocketpp/changelog.md +++ b/vendor/websocketpp/changelog.md @@ -1,4 +1,7 @@ HEAD +- Bug: Change default listen backlog from 0 to socket_base::max_connections. + #549. Thank you derwassi and zwelab for reporting and na1pir for providing + access to hardware to debug the issue. 0.7.0 - 2016-02-22 - MINOR BREAKING SOCKET POLICY CHANGE: Asio transport socket policy method diff --git a/vendor/websocketpp/test/connection/connection.cpp b/vendor/websocketpp/test/connection/connection.cpp index 36b6d14..de79d93 100644 --- a/vendor/websocketpp/test/connection/connection.cpp +++ b/vendor/websocketpp/test/connection/connection.cpp @@ -30,6 +30,8 @@ #include "connection_tu2.hpp" +#include + // Include special debugging transport //#include #include @@ -172,6 +174,20 @@ void http_func(server* s, websocketpp::connection_hdl hdl) { BOOST_CHECK_EQUAL(con->get_response_msg(), status_code::get_string(status_code::ok)); } +void http_func_with_move(server* s, websocketpp::connection_hdl hdl) { + using namespace websocketpp::http; + + server::connection_ptr con = s->get_con_from_hdl(hdl); + + std::string res = con->get_resource(); + + con->set_body( std::move(res) ); + con->set_status(status_code::ok); + + BOOST_CHECK_EQUAL(con->get_response_code(), status_code::ok); + BOOST_CHECK_EQUAL(con->get_response_msg(), status_code::get_string(status_code::ok)); +} + void defer_http_func(server* s, bool * deferred, websocketpp::connection_hdl hdl) { *deferred = true; @@ -237,6 +253,18 @@ BOOST_AUTO_TEST_CASE( http_request ) { BOOST_CHECK_EQUAL(run_server_test(s,input), output); } +BOOST_AUTO_TEST_CASE( http_request_with_move ) { + std::string input = "GET /foo/bar HTTP/1.1\r\nHost: www.example.com\r\nOrigin: http://www.example.com\r\n\r\n"; + std::string output = "HTTP/1.1 200 OK\r\nContent-Length: 8\r\nServer: "; + output+=websocketpp::user_agent; + output+="\r\n\r\n/foo/bar"; + + server s; + s.set_http_handler(bind(&http_func_with_move,&s,::_1)); + + BOOST_CHECK_EQUAL(run_server_test(s,input), output); +} + BOOST_AUTO_TEST_CASE( deferred_http_request ) { std::string input = "GET /foo/bar HTTP/1.1\r\nHost: www.example.com\r\nOrigin: http://www.example.com\r\n\r\n"; std::string output = "HTTP/1.1 200 OK\r\nContent-Length: 8\r\nServer: "; diff --git a/vendor/websocketpp/websocketpp/connection.hpp b/vendor/websocketpp/websocketpp/connection.hpp index 3bbbbb3..b992b17 100644 --- a/vendor/websocketpp/websocketpp/connection.hpp +++ b/vendor/websocketpp/websocketpp/connection.hpp @@ -1041,6 +1041,7 @@ public: * @see websocketpp::http::response::set_body */ void set_body(std::string const & value); + void set_body( std::string&& value ); /// Append a header /** diff --git a/vendor/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp b/vendor/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp index 1581f14..cb48943 100644 --- a/vendor/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp +++ b/vendor/websocketpp/websocketpp/extensions/permessage_deflate/enabled.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,7 @@ namespace websocketpp { namespace extensions { -/// Implementation of the draft permessage-deflate WebSocket extension +/// Implementation of RFC 7692, the permessage-deflate WebSocket extension /** * ### permessage-deflate interface * @@ -174,18 +175,30 @@ namespace websocketpp { namespace extensions { namespace permessage_deflate { -/// Default value for server_max_window_bits as defined by draft 17 +/// Default value for server_max_window_bits as defined by RFC 7692 static uint8_t const default_server_max_window_bits = 15; -/// Minimum value for server_max_window_bits as defined by draft 17 +/// Minimum value for server_max_window_bits as defined by RFC 7692 +/** + * NOTE: A value of 8 is not actually supported by zlib, the deflate + * library that WebSocket++ uses. To preserve backwards compatibility + * with RFC 7692 and previous versions of the library a value of 8 + * is accepted by the library but will always be negotiated as 9. + */ static uint8_t const min_server_max_window_bits = 8; -/// Maximum value for server_max_window_bits as defined by draft 17 +/// Maximum value for server_max_window_bits as defined by RFC 7692 static uint8_t const max_server_max_window_bits = 15; -/// Default value for client_max_window_bits as defined by draft 17 +/// Default value for client_max_window_bits as defined by RFC 7692 static uint8_t const default_client_max_window_bits = 15; -/// Minimum value for client_max_window_bits as defined by draft 17 +/// Minimum value for client_max_window_bits as defined by RFC 7692 +/** + * NOTE: A value of 8 is not actually supported by zlib, the deflate + * library that WebSocket++ uses. To preserve backwards compatibility + * with RFC 7692 and previous versions of the library a value of 8 + * is accepted by the library but will always be negotiated as 9. + */ static uint8_t const min_client_max_window_bits = 8; -/// Maximum value for client_max_window_bits as defined by draft 17 +/// Maximum value for client_max_window_bits as defined by RFC 7692 static uint8_t const max_client_max_window_bits = 15; namespace mode { @@ -213,7 +226,7 @@ public: , m_server_max_window_bits_mode(mode::accept) , m_client_max_window_bits_mode(mode::accept) , m_initialized(false) - , m_compress_buffer_size(16384) + , m_compress_buffer_size(8192) { m_dstate.zalloc = Z_NULL; m_dstate.zfree = Z_NULL; @@ -292,6 +305,7 @@ public: } m_compress_buffer.reset(new unsigned char[m_compress_buffer_size]); + m_decompress_buffer.reset(new unsigned char[m_compress_buffer_size]); if ((m_server_no_context_takeover && is_server) || (m_client_no_context_takeover && !is_server)) { @@ -372,7 +386,7 @@ public: /** * The bits setting is the base 2 logarithm of the maximum window size that * the server must use to compress outgoing messages. The permitted range - * is 8 to 15 inclusive. 8 represents a 256 byte window and 15 a 32KiB + * is 9 to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB * window. The default setting is 15. * * Mode Options: @@ -386,6 +400,14 @@ public: * adjusted by the server. A server may unilaterally set this value without * client support. * + * NOTE: The permessage-deflate spec specifies that a value of 8 is allowed. + * Prior to version 0.8.0 a value of 8 was also allowed by this library. + * zlib, the deflate compression library that WebSocket++ uses has always + * silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9 + * and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0 + * continues to perform the 8->9 conversion for backwards compatibility + * purposes but this should be considered deprecated functionality. + * * @param bits The size to request for the outgoing window size * @param mode The mode to use for negotiating this parameter * @return A status code @@ -394,6 +416,12 @@ public: if (bits < min_server_max_window_bits || bits > max_server_max_window_bits) { return error::make_error_code(error::invalid_max_window_bits); } + + // See note in doc comment above about what is happening here + if (bits == 8) { + bits = 9; + } + m_server_max_window_bits = bits; m_server_max_window_bits_mode = mode; @@ -403,8 +431,8 @@ public: /// Limit client LZ77 sliding window size /** * The bits setting is the base 2 logarithm of the window size that the - * client must use to compress outgoing messages. The permitted range is 8 - * to 15 inclusive. 8 represents a 256 byte window and 15 a 32KiB window. + * client must use to compress outgoing messages. The permitted range is 9 + * to 15 inclusive. 9 represents a 512 byte window and 15 a 32KiB window. * The default setting is 15. * * Mode Options: @@ -417,6 +445,14 @@ public: * outgoing window size unilaterally. A server may only limit the client's * window size if the remote client supports that feature. * + * NOTE: The permessage-deflate spec specifies that a value of 8 is allowed. + * Prior to version 0.8.0 a value of 8 was also allowed by this library. + * zlib, the deflate compression library that WebSocket++ uses has always + * silently adjusted a value of 8 to 9. In recent versions of zlib (1.2.9 + * and greater) a value of 8 is now explicitly rejected. WebSocket++ 0.8.0 + * continues to perform the 8->9 conversion for backwards compatibility + * purposes but this should be considered deprecated functionality. + * * @param bits The size to request for the outgoing window size * @param mode The mode to use for negotiating this parameter * @return A status code @@ -425,6 +461,12 @@ public: if (bits < min_client_max_window_bits || bits > max_client_max_window_bits) { return error::make_error_code(error::invalid_max_window_bits); } + + // See note in doc comment above about what is happening here + if (bits == 8) { + bits = 9; + } + m_client_max_window_bits = bits; m_client_max_window_bits_mode = mode; @@ -555,7 +597,7 @@ public: do { m_istate.avail_out = m_compress_buffer_size; - m_istate.next_out = m_compress_buffer.get(); + m_istate.next_out = m_decompress_buffer.get(); ret = inflate(&m_istate, Z_SYNC_FLUSH); @@ -564,7 +606,7 @@ public: } out.append( - reinterpret_cast(m_compress_buffer.get()), + reinterpret_cast(m_decompress_buffer.get()), m_compress_buffer_size - m_istate.avail_out ); } while (m_istate.avail_out == 0); @@ -642,11 +684,17 @@ private: * client requested that we use. * * options: - * - decline (refuse to use the attribute) - * - accept (use whatever the client says) - * - largest (use largest possible value) + * - decline (ignore value, offer our default instead) + * - accept (use the value requested by the client) + * - largest (use largest value acceptable to both) * - smallest (use smallest possible value) * + * NOTE: As a value of 8 is no longer explicitly supported by zlib but might + * be requested for negotiation by an older client/server, if the result of + * the negotiation would be to send a value of 8, a value of 9 is offered + * instead. This ensures that WebSocket++ will only ever negotiate connections + * with compression settings explicitly supported by zlib. + * * @param [in] value The value of the attribute from the offer * @param [out] ec A reference to the error code to return errors via */ @@ -678,6 +726,11 @@ private: ec = make_error_code(error::invalid_mode); m_server_max_window_bits = default_server_max_window_bits; } + + // See note in doc comment + if (m_server_max_window_bits == 8) { + m_server_max_window_bits = 9; + } } /// Negotiate client_max_window_bits attribute @@ -687,11 +740,17 @@ private: * negotiation mode. * * options: - * - decline (refuse to use the attribute) - * - accept (use whatever the client says) - * - largest (use largest possible value) + * - decline (ignore value, offer our default instead) + * - accept (use the value requested by the client) + * - largest (use largest value acceptable to both) * - smallest (use smallest possible value) * + * NOTE: As a value of 8 is no longer explicitly supported by zlib but might + * be requested for negotiation by an older client/server, if the result of + * the negotiation would be to send a value of 8, a value of 9 is offered + * instead. This ensures that WebSocket++ will only ever negotiate connections + * with compression settings explicitly supported by zlib. + * * @param [in] value The value of the attribute from the offer * @param [out] ec A reference to the error code to return errors via */ @@ -727,6 +786,11 @@ private: ec = make_error_code(error::invalid_mode); m_client_max_window_bits = default_client_max_window_bits; } + + // See note in doc comment + if (m_client_max_window_bits == 8) { + m_client_max_window_bits = 9; + } } bool m_enabled; @@ -741,6 +805,7 @@ private: int m_flush; size_t m_compress_buffer_size; lib::unique_ptr_uchar_array m_compress_buffer; + lib::unique_ptr_uchar_array m_decompress_buffer; z_stream m_dstate; z_stream m_istate; }; @@ -750,3 +815,4 @@ private: } // namespace websocketpp #endif // WEBSOCKETPP_PROCESSOR_EXTENSION_PERMESSAGEDEFLATE_HPP + diff --git a/vendor/websocketpp/websocketpp/impl/connection_impl.hpp b/vendor/websocketpp/websocketpp/impl/connection_impl.hpp index d1f8dff..61f4e49 100644 --- a/vendor/websocketpp/websocketpp/impl/connection_impl.hpp +++ b/vendor/websocketpp/websocketpp/impl/connection_impl.hpp @@ -575,6 +575,17 @@ void connection::set_body(std::string const & value) { m_response.set_body(value); } +template +void connection::set_body( std::string&& value ) +{ + if (m_internal_state != istate::PROCESS_HTTP_REQUEST) { + throw exception("Call to set_status from invalid state", + error::make_error_code(error::invalid_state)); + } + + m_response.set_body(std::move(value)); +} + // TODO: EXCEPTION_FREE template void connection::append_header(std::string const & key, diff --git a/vendor/websocketpp/websocketpp/transport/asio/connection.hpp b/vendor/websocketpp/websocketpp/transport/asio/connection.hpp index 8eb8c75..ade6696 100644 --- a/vendor/websocketpp/websocketpp/transport/asio/connection.hpp +++ b/vendor/websocketpp/websocketpp/transport/asio/connection.hpp @@ -311,10 +311,10 @@ public: * needed. */ timer_ptr set_timer(long duration, timer_handler callback) { - timer_ptr new_timer = lib::make_shared( - lib::ref(*m_io_service), - lib::asio::milliseconds(duration) - ); + timer_ptr new_timer( + new lib::asio::steady_timer( + *m_io_service, + lib::asio::milliseconds(duration))); if (config::enable_multithreading) { new_timer->async_wait(m_strand->wrap(lib::bind( @@ -461,8 +461,7 @@ protected: m_io_service = io_service; if (config::enable_multithreading) { - m_strand = lib::make_shared( - lib::ref(*io_service)); + m_strand.reset(new lib::asio::io_service::strand(*io_service)); } lib::error_code ec = socket_con_type::init_asio(io_service, m_strand, diff --git a/vendor/websocketpp/websocketpp/transport/asio/endpoint.hpp b/vendor/websocketpp/websocketpp/transport/asio/endpoint.hpp index f64e847..a551a4d 100644 --- a/vendor/websocketpp/websocketpp/transport/asio/endpoint.hpp +++ b/vendor/websocketpp/websocketpp/transport/asio/endpoint.hpp @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -191,8 +192,7 @@ public: m_io_service = ptr; m_external_io_service = true; - m_acceptor = lib::make_shared( - lib::ref(*m_io_service)); + m_acceptor.reset(new lib::asio::ip::tcp::acceptor(*m_io_service)); m_state = READY; ec = lib::error_code(); @@ -314,8 +314,10 @@ public: * * New values affect future calls to listen only. * - * A value of zero will use the operating system default. This is the - * default value. + * The default value is specified as *::asio::socket_base::max_connections + * which uses the operating system defined maximum queue length. Your OS + * may restrict or silently lower this value. A value of zero may cause + * all connections to be rejected. * * @since 0.3.0 * @@ -660,9 +662,7 @@ public: * @since 0.3.0 */ void start_perpetual() { - m_work = lib::make_shared( - lib::ref(*m_io_service) - ); + m_work.reset(new lib::asio::io_service::work(*m_io_service)); } /// Clears the endpoint's perpetual flag, allowing it to exit when empty @@ -826,8 +826,7 @@ protected: // Create a resolver if (!m_resolver) { - m_resolver = lib::make_shared( - lib::ref(*m_io_service)); + m_resolver.reset(new lib::asio::ip::tcp::resolver(*m_io_service)); } tcon->set_uri(u); diff --git a/vendor/websocketpp/websocketpp/transport/asio/security/none.hpp b/vendor/websocketpp/websocketpp/transport/asio/security/none.hpp index 0e68a65..c05758b 100644 --- a/vendor/websocketpp/websocketpp/transport/asio/security/none.hpp +++ b/vendor/websocketpp/websocketpp/transport/asio/security/none.hpp @@ -168,8 +168,7 @@ protected: return socket::make_error_code(socket::error::invalid_state); } - m_socket = lib::make_shared( - lib::ref(*service)); + m_socket.reset(new lib::asio::ip::tcp::socket(*service)); m_state = READY; diff --git a/vendor/websocketpp/websocketpp/transport/asio/security/tls.hpp b/vendor/websocketpp/websocketpp/transport/asio/security/tls.hpp index a8aafec..c06546c 100644 --- a/vendor/websocketpp/websocketpp/transport/asio/security/tls.hpp +++ b/vendor/websocketpp/websocketpp/transport/asio/security/tls.hpp @@ -193,8 +193,7 @@ protected: if (!m_context) { return socket::make_error_code(socket::error::invalid_tls_context); } - m_socket = lib::make_shared( - _WEBSOCKETPP_REF(*service),lib::ref(*m_context)); + m_socket.reset(new socket_type(*service, *m_context)); m_io_service = service; m_strand = strand; -- 2.45.2 From 614a0dad6b75beaf810a720c5708a52818ae09aa Mon Sep 17 00:00:00 2001 From: pravin-battu Date: Thu, 6 Aug 2020 10:39:17 -0300 Subject: [PATCH 2/4] missing websocket_api.hpp changes --- include/fc/rpc/websocket_api.hpp | 124 +++++++------------------------ 1 file changed, 26 insertions(+), 98 deletions(-) diff --git a/include/fc/rpc/websocket_api.hpp b/include/fc/rpc/websocket_api.hpp index 6cfd66c..2b228aa 100755 --- a/include/fc/rpc/websocket_api.hpp +++ b/include/fc/rpc/websocket_api.hpp @@ -1,108 +1,36 @@ #pragma once -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -namespace fc { namespace http { - namespace detail { - class websocket_server_impl; - class websocket_tls_server_impl; - class websocket_client_impl; - class websocket_tls_client_impl; - } // namespace detail; +namespace fc { namespace rpc { - class websocket_connection + class websocket_api_connection : public api_connection { public: - virtual ~websocket_connection(){} - virtual void send_message( const std::string& message ) = 0; - virtual void close( int64_t code, const std::string& reason ){}; - void on_message( const std::string& message ) { _on_message(message); } - string on_http( const std::string& message ) { return _on_http(message); } + websocket_api_connection(const std::shared_ptr &c, uint32_t max_conversion_depth ); + ~websocket_api_connection(); - void on_message_handler( const std::function& h ) { _on_message = h; } - void on_http_handler( const std::function& h ) { _on_http = h; } + virtual variant send_call( + api_id_type api_id, + string method_name, + variants args = variants() ) override; + virtual variant send_callback( + uint64_t callback_id, + variants args = variants() ) override; + virtual void send_notice( + uint64_t callback_id, + variants args = variants() ) override; - void set_session_data( boost::any d ){ _session_data = std::move(d); } - boost::any& get_session_data() { return _session_data; } + protected: + std::string on_message( + const std::string& message, + bool send_message = true ); - virtual std::string get_request_header(const std::string& key) = 0; - - fc::signal closed; - private: - boost::any _session_data; - std::function _on_message; - std::function _on_http; - }; - typedef std::shared_ptr websocket_connection_ptr; - - typedef std::function on_connection_handler; - - class websocket_server - { - public: - websocket_server(); - ~websocket_server(); - - void on_connection( const on_connection_handler& handler); - void listen( uint16_t port ); - void listen( const fc::ip::endpoint& ep ); - uint16_t get_listening_port(); - void start_accept(); - - void stop_listening(); - void close(); - private: - friend class detail::websocket_server_impl; - std::unique_ptr my; + std::shared_ptr _connection; + fc::rpc::state _rpc_state; }; - - 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(); - - void on_connection( const on_connection_handler& handler); - void listen( uint16_t port ); - void listen( const fc::ip::endpoint& ep ); - void start_accept(); - - private: - friend class detail::websocket_tls_server_impl; - std::unique_ptr my; - }; - - class websocket_client - { - public: - websocket_client( const std::string& ca_filename = "_default" ); - ~websocket_client(); - - websocket_connection_ptr connect( const std::string& uri ); - websocket_connection_ptr secure_connect( const std::string& uri ); - - void close(); - void synchronous_close(); - - private: - std::unique_ptr my; - std::unique_ptr smy; - }; - 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; - }; - -} } +} } // namespace fc::rpc -- 2.45.2 From 9c84934db12b04b325f26fe7256fcd5f6107b347 Mon Sep 17 00:00:00 2001 From: pravin-battu Date: Thu, 6 Aug 2020 12:42:16 -0300 Subject: [PATCH 3/4] missing update --- 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 88c72be..a2f2e34 100755 --- a/src/network/http/websocket.cpp +++ b/src/network/http/websocket.cpp @@ -152,7 +152,7 @@ namespace fc { namespace http { :_ws_connection(con){ } - ~websocket_connection_impl() + virtual ~websocket_connection_impl() { } -- 2.45.2 From c8dfe448009061aacb3e6865fd9fb9e1254c673c Mon Sep 17 00:00:00 2001 From: blockc p Date: Wed, 12 Aug 2020 02:59:56 +0000 Subject: [PATCH 4/4] Update websocket.hpp --- include/fc/network/http/websocket.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/fc/network/http/websocket.hpp b/include/fc/network/http/websocket.hpp index 12e9119..6cfd66c 100755 --- a/include/fc/network/http/websocket.hpp +++ b/include/fc/network/http/websocket.hpp @@ -72,9 +72,6 @@ namespace fc { namespace http { void listen( uint16_t port ); void listen( const fc::ip::endpoint& ep ); void start_accept(); - uint16_t get_listening_port(); - void stop_listening(); - void close(); private: friend class detail::websocket_tls_server_impl; -- 2.45.2