Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log host information from websocket requests #134

Merged
merged 25 commits into from
May 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
82935ac
Add host information to log messages
jmjatlanta May 23, 2019
8b4ef5a
Fix bad_alloc
jmjatlanta May 23, 2019
d821e86
Add configurable header
jmjatlanta May 24, 2019
4906d8b
Allow configurable proxy header for logging
jmjatlanta May 24, 2019
0df5f7e
Use an api call instead of constructor
jmjatlanta May 24, 2019
94200c1
clarify method name, cache value
jmjatlanta May 27, 2019
99d7e63
revert adjustment to capture
jmjatlanta May 27, 2019
550e092
Merge branch 'master' into jmj_844b
oxarbitrage Jun 21, 2019
5d8e9e1
fix remove appender()
oxarbitrage Jun 21, 2019
e907429
fix tests
oxarbitrage Jun 21, 2019
7ec8ead
chanmge comment from hostname to IP
oxarbitrage Jun 21, 2019
e336649
lambda capture only whats required
oxarbitrage Jun 21, 2019
ba394e0
Refactor code about logging remote host info
abitmore May 1, 2020
9c506d0
Fix test cases
abitmore May 1, 2020
e50067d
Tweak code slightly
abitmore May 1, 2020
8ffe08f
Merge 'master' branch
abitmore May 1, 2020
e778cf1
Revert to simple WS connection for clients
abitmore May 1, 2020
8ddcc87
Add todo
abitmore May 1, 2020
c6df78b
Rename a function to avoid accidental misuse
abitmore May 2, 2020
3e07edf
Remove unused header inclusion
abitmore May 2, 2020
c8fcefb
Update RPC logging format
abitmore May 2, 2020
c58ae55
Update test cases about RPC logging level
abitmore May 2, 2020
ffbda4e
Add test cases about on_http for websocket servers
abitmore May 2, 2020
aa54e39
Remove unused websocket_tls_client class
abitmore May 2, 2020
ea96a5a
Fix websocket_client::secure_connect()
abitmore May 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions include/fc/network/http/websocket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -32,7 +34,11 @@ namespace fc { namespace http {

virtual std::string get_request_header(const std::string& key) = 0;

const std::string& get_remote_endpoint_string()const { return _remote_endpoint; }

fc::signal<void()> closed;
protected:
std::string _remote_endpoint; // for logging
private:
boost::any _session_data;
std::function<void(const std::string&)> _on_message;
Expand All @@ -45,7 +51,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);
Expand All @@ -66,15 +72,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();

private:
friend class detail::websocket_tls_server_impl;
std::unique_ptr<detail::websocket_tls_server_impl> my;
Expand All @@ -91,19 +97,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<detail::websocket_client_impl> my;
std::unique_ptr<detail::websocket_tls_client_impl> 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<detail::websocket_tls_client_impl> my;
std::vector<std::pair<std::string,std::string>> headers;
};

} }
7 changes: 7 additions & 0 deletions src/log/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ namespace fc {
void logger::add_appender( const appender::ptr& a )
{ my->_appenders.push_back(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())
my->_appenders.erase(item);
}

std::vector<appender::ptr> logger::get_appenders()const
{
return my->_appenders;
Expand Down
204 changes: 104 additions & 100 deletions src/network/http/websocket.cpp

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,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 )
Expand Down
4 changes: 2 additions & 2 deletions tests/api_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(login_test) {
try {
fc::api<fc::test::calculator> calc_api( std::make_shared<fc::test::some_calculator>() );

auto server = std::make_shared<fc::http::websocket_server>();
auto server = std::make_shared<fc::http::websocket_server>("");
server->on_connection([&]( const websocket_connection_ptr& c ){
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
auto login = std::make_shared<fc::test::login_api>();
Expand Down Expand Up @@ -116,7 +116,7 @@ BOOST_AUTO_TEST_CASE(optionals_test) {
BOOST_CHECK_EQUAL(oapi->bar("a", "b", "c"), "[\"a\",\"b\",\"c\"]");
BOOST_CHECK_EQUAL(oapi->bar("a", {}, "c"), "[\"a\",null,\"c\"]");

auto server = std::make_shared<fc::http::websocket_server>();
auto server = std::make_shared<fc::http::websocket_server>("");
server->on_connection([&]( const websocket_connection_ptr& c ){
auto wsc = std::make_shared<websocket_api_connection>(c, MAX_DEPTH);
wsc->register_api(fc::api<fc::test::optionals_api>(optionals));
Expand Down
110 changes: 109 additions & 1 deletion tests/network/http/websocket_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,112 @@
#include <fc/network/http/websocket.hpp>

#include <iostream>
#include <fc/log/logger.hpp>
#include <fc/log/console_appender.hpp>

BOOST_AUTO_TEST_SUITE(fc_network)

BOOST_AUTO_TEST_CASE(websocket_test)
{
// set up logging
fc::appender::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;
{
fc::http::websocket_server server;
// even with this key set, if the remote does not provide it, it will revert to
// the remote endpoint
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);
});
c->on_http_handler([&](const std::string& s){
fc::http::reply reply;
reply.body_as_string = "http-echo: " + s;
return reply;
});
});

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);

// 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);
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::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;
// 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);
});
c->on_http_handler([&](const std::string& s){
fc::http::reply reply;
reply.body_as_string = "http-echo: " + s;
return reply;
});
});

server.listen( 0 );
Expand Down Expand Up @@ -48,10 +139,27 @@ 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::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);
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()
41 changes: 41 additions & 0 deletions tests/ws_test_client.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <fc/network/http/websocket.hpp>
#include <websocketpp/error.hpp>

#include <iostream>
#include <string>
#include <fc/log/logger.hpp>
#include <fc/log/console_appender.hpp>

int main(int argc, char** argv)
{
try
{
// set up logging
fc::appender::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;
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){
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()) );
}
}
33 changes: 33 additions & 0 deletions tests/ws_test_server.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include <fc/network/http/websocket.hpp>
#include <fc/asio.hpp>

#include <iostream>
#include <chrono>
#include <fc/log/logger.hpp>
#include <fc/log/console_appender.hpp>

int main(int argc, char** argv)
{
// set up logging
fc::appender::ptr ca(new fc::console_appender);
fc::logger l = fc::logger::get("rpc");
l.add_appender( ca );

fc::http::websocket_server server("MyForwardHeaderKey");

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) );
}
}