2 #include <websocketpp/config/asio_client.hpp>
3 #include <websocketpp/config/asio.hpp>
4 #include <websocketpp/server.hpp>
5 #include <websocketpp/config/asio_client.hpp>
6 #include <websocketpp/client.hpp>
7 #include <websocketpp/logger/stub.hpp>
10 #include <websocketpp/extensions/permessage_deflate/enabled.hpp>
12 #include <websocketpp/extensions/permessage_deflate/disabled.hpp>
28 # undef DEFAULT_LOGGER
30 #define DEFAULT_LOGGER "rpc"
32 namespace fc {
namespace http {
37 static void add_windows_root_certs(boost::asio::ssl::context &ctx)
39 HCERTSTORE hStore = CertOpenSystemStore( 0,
"ROOT" );
43 X509_STORE *store = X509_STORE_new();
44 PCCERT_CONTEXT pContext = NULL;
45 while( (pContext = CertEnumCertificatesInStore( hStore, pContext )) != NULL )
47 X509 *x509 = d2i_X509( NULL, (
const unsigned char **)&pContext->pbCertEncoded,
48 pContext->cbCertEncoded);
51 X509_STORE_add_cert( store, x509 );
56 CertFreeCertificateContext( pContext );
57 CertCloseStore( hStore, 0 );
59 SSL_CTX_set_cert_store( ctx.native_handle(), store );
90 typedef websocketpp::transport::asio::endpoint<transport_config>
transport_type;
95 typedef websocketpp::extensions::permessage_deflate::enabled <permessage_deflate_config>
98 typedef websocketpp::extensions::permessage_deflate::disabled <permessage_deflate_config>
135 typedef websocketpp::extensions::permessage_deflate::enabled <permessage_deflate_config>
138 typedef websocketpp::extensions::permessage_deflate::disabled <permessage_deflate_config>
174 typedef websocketpp::extensions::permessage_deflate::enabled <permessage_deflate_config>
177 typedef websocketpp::extensions::permessage_deflate::disabled <permessage_deflate_config>
197 ilog(
"[OUT] ${remote_endpoint} ${msg}",
200 FC_ASSERT( !ec,
"websocket send failed: ${msg}", (
"msg",ec.message() ) );
202 virtual void close( int64_t code,
const std::string& reason )
override
224 if( !forward_header_key.empty() )
237 typedef websocketpp::lib::shared_ptr<boost::asio::ssl::context>
context_ptr;
239 using websocketpp::connection_hdl;
248 _server.clear_access_channels( websocketpp::log::alevel::all );
250 _server.set_reuse_addr(
true );
251 _server.set_open_handler( [
this]( connection_hdl hdl ){
259 _server.set_message_handler( [
this]( connection_hdl hdl,
260 typename websocketpp::server<T>::message_ptr msg ){
265 auto payload = msg->get_payload();
266 std::shared_ptr<websocket_connection> con = current_con->second;
267 wlog(
"[IN] ${remote_endpoint} ${msg}",
268 (
"remote_endpoint",con->get_remote_endpoint_string()) (
"msg",payload) );
273 con->on_message( payload );
285 _server.set_socket_init_handler( []( websocketpp::connection_hdl hdl,
286 typename websocketpp::server<T>::connection_type::socket_type& s ) {
287 boost::asio::ip::tcp::no_delay option(
true);
288 s.lowest_layer().set_option(option);
291 _server.set_http_handler( [
this]( connection_hdl hdl ){
293 auto con =
_server.get_con_from_hdl(hdl);
298 con->defer_http_response();
300 std::string remote_endpoint = current_con->get_remote_endpoint_string();
301 std::string request_body = con->get_request_body();
302 wlog(
"[HTTP-IN] ${remote_endpoint} ${msg}",
303 (
"remote_endpoint",remote_endpoint) (
"msg",request_body) );
305 fc::async([current_con, request_body, con, remote_endpoint] {
307 ilog(
"[HTTP-OUT] ${remote_endpoint} ${status} ${msg}",
308 (
"remote_endpoint",remote_endpoint)
309 (
"status",response.
status)
312 con->set_status( websocketpp::http::status_code::value(response.
status) );
313 con->send_http_response();
314 current_con->closed();
319 _server.set_close_handler( [
this]( connection_hdl hdl ){
330 wlog(
"unknown connection closed" );
335 _server.set_fail_handler( [
this]( connection_hdl hdl ){
350 wlog(
"unknown connection failed" );
378 websocketpp::lib::error_code ec;
379 for(
auto& item : cpy_con )
380 _server.close( item.first, 0,
"server exit", ec );
389 typedef std::map<connection_hdl, websocket_connection_ptr, std::owner_less<connection_hdl> >
con_map;
417 const std::string& forward_header_key )
420 _server.set_tls_init_handler( [server_pem,ssl_password]( websocketpp::connection_hdl hdl ) {
421 context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(
422 boost::asio::ssl::context::tlsv12 );
424 ctx->set_options( boost::asio::ssl::context::default_workarounds |
425 boost::asio::ssl::context::no_sslv2 |
426 boost::asio::ssl::context::no_sslv3 |
427 boost::asio::ssl::context::no_tlsv1 |
428 boost::asio::ssl::context::no_tlsv1_1 |
429 boost::asio::ssl::context::single_dh_use );
430 ctx->set_password_callback(
431 [ssl_password](std::size_t max_length, boost::asio::ssl::context::password_purpose){
434 ctx->use_certificate_chain_file(server_pem);
435 ctx->use_private_key_file(server_pem, boost::asio::ssl::context::pem);
436 }
catch (std::exception& e) {
455 _client.clear_access_channels( websocketpp::log::alevel::all );
456 _client.set_message_handler( [
this]( connection_hdl hdl,
457 typename websocketpp::client<T>::message_ptr msg ){
459 wdump((msg->get_payload()));
460 auto received = msg->get_payload();
467 _client.set_close_handler( [
this]( connection_hdl hdl ){
477 _client.set_fail_handler( [
this]( connection_hdl hdl ){
478 auto con =
_client.get_con_from_hdl(hdl);
479 auto message = con->get_ec().message();
514 websocketpp::lib::error_code ec;
519 _client.set_open_handler( [
this]( websocketpp::connection_hdl hdl ){
521 auto con =
_client.get_con_from_hdl(hdl);
528 auto con =
_client.get_connection( uri, ec );
532 con->append_header( h.key, h.val );
535 FC_ASSERT( !ec,
"error: ${e}", (
"e",ec.message()) );
583 std::string ca_filename_copy = ca_filename;
585 _client.set_tls_init_handler( [
this,ca_filename_copy](websocketpp::connection_hdl) {
586 context_ptr ctx = websocketpp::lib::make_shared<boost::asio::ssl::context>(
587 boost::asio::ssl::context::tlsv12);
589 ctx->set_options( boost::asio::ssl::context::default_workarounds |
590 boost::asio::ssl::context::no_sslv2 |
591 boost::asio::ssl::context::no_sslv3 |
592 boost::asio::ssl::context::no_tlsv1 |
593 boost::asio::ssl::context::no_tlsv1_1 |
594 boost::asio::ssl::context::single_dh_use );
597 }
catch (std::exception& e) {
609 return websocketpp::uri(
_uri ).get_host();
614 if( ca_filename ==
"_none" )
616 ctx->set_verify_mode( boost::asio::ssl::verify_peer );
617 if( ca_filename ==
"_default" )
620 add_windows_root_certs( *ctx );
622 ctx->set_default_verify_paths();
626 ctx->load_verify_file( ca_filename );
627 ctx->set_verify_depth(10);
628 ctx->set_verify_callback( boost::asio::ssl::rfc2818_verification(
get_host() ) );
637 :my( new detail::websocket_server_impl( forward_header_key ) ) {}
642 my->_on_connection = handler;
647 my->_server.listen(port);
657 websocketpp::lib::asio::error_code ec;
658 return my->_server.get_local_endpoint(ec).port();
662 my->_server.start_accept();
667 my->_server.stop_listening();
672 auto cpy_con = my->_connections;
673 websocketpp::lib::error_code ec;
675 my->_server.close(
connection.first, websocketpp::close::status::normal,
"Goodbye", ec );
679 const std::string& forward_header_key )
680 :my( new detail::websocket_tls_server_impl(server_pem, ssl_password, forward_header_key) )
687 my->_on_connection = handler;
692 my->_server.listen(port);
702 websocketpp::lib::asio::error_code ec;
703 return my->_server.get_local_endpoint(ec).port();
707 my->_server.start_accept();
712 my->_server.stop_listening();
717 auto cpy_con = my->_connections;
718 websocketpp::lib::error_code ec;
720 my->_server.close(
connection.first, websocketpp::close::status::normal,
"Goodbye", ec );
725 :my( new detail::websocket_client_impl() ),
726 smy(new detail::websocket_tls_client_impl( ca_filename ))
734 FC_ASSERT( uri.substr(0,4) ==
"wss:" || uri.substr(0,3) ==
"ws:",
"Unsupported protocol" );
737 if( uri.substr(0,4) ==
"wss:" )
738 return smy->connect( uri, _headers );
741 return my->connect( uri, _headers );
753 my->_client.close( *my->_hdl, websocketpp::close::status::normal,
"Goodbye" );
765 _headers.emplace_back( key, value );