From 1dc9934d093db7353158f0376cac2f8689042d4e Mon Sep 17 00:00:00 2001 From: Gergely Lukacsy Date: Tue, 10 Nov 2015 14:52:23 +0000 Subject: [PATCH] Add unsolicited pong support with integration tests --- Release/include/cpprest/ws_msg.h | 17 ++++++++++ .../src/websockets/client/ws_client_wspp.cpp | 11 ++++-- .../websockets/client/send_msg_tests.cpp | 34 +++++++++++++++++++ .../utilities/test_websocket_server.cpp | 19 +++++++++-- .../utilities/test_websocket_server.h | 3 +- 5 files changed, 78 insertions(+), 6 deletions(-) diff --git a/Release/include/cpprest/ws_msg.h b/Release/include/cpprest/ws_msg.h index 9b3fe713a7..171234edf0 100644 --- a/Release/include/cpprest/ws_msg.h +++ b/Release/include/cpprest/ws_msg.h @@ -73,6 +73,15 @@ class websocket_outgoing_message { public: + /// + /// Sets a the outgoing message to be an unsolicited pong message. + /// This is useful when the client side wants to check whether the server is alive. + /// + void set_pong_message() + { + this->set_message_pong(); + } + /// /// Sets a UTF-8 message as the message body. /// @@ -152,6 +161,14 @@ class websocket_outgoing_message const pplx::task_completion_event & body_sent() const { return m_body_sent; } + void set_message_pong() + { + concurrency::streams::container_buffer buffer(""); + m_msg_type = websocket_message_type::pong; + m_length = static_cast(buffer.size()); + m_body = buffer; + } + void set_message(const concurrency::streams::container_buffer &buffer) { m_msg_type = websocket_message_type::text_message; diff --git a/Release/src/websockets/client/ws_client_wspp.cpp b/Release/src/websockets/client/ws_client_wspp.cpp index 1e53f69e39..bd17af922e 100644 --- a/Release/src/websockets/client/ws_client_wspp.cpp +++ b/Release/src/websockets/client/ws_client_wspp.cpp @@ -373,13 +373,14 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: { case websocket_message_type::text_message: case websocket_message_type::binary_message: + case websocket_message_type::pong: break; default: return pplx::task_from_exception(websocket_exception("Invalid message type")); } const auto length = msg.m_length; - if (length == 0) + if (length == 0 && msg.m_msg_type != websocket_message_type::pong) { return pplx::task_from_exception(websocket_exception("Cannot send empty message.")); } @@ -639,13 +640,19 @@ class wspp_callback_client : public websocket_client_callback_impl, public std:: ec); break; case websocket_message_type::binary_message: - client.send( + client.send( this_client->m_con, sp_allocated.get(), length, websocketpp::frame::opcode::binary, ec); break; + case websocket_message_type::pong: + client.pong( + this_client->m_con, + "", + ec); + break; default: // This case should have already been filtered above. std::abort(); diff --git a/Release/tests/functional/websockets/client/send_msg_tests.cpp b/Release/tests/functional/websockets/client/send_msg_tests.cpp index f0cd3ea82a..1303207a0e 100644 --- a/Release/tests/functional/websockets/client/send_msg_tests.cpp +++ b/Release/tests/functional/websockets/client/send_msg_tests.cpp @@ -103,6 +103,21 @@ pplx::task send_text_msg_helper(SocketClientClass& client, web::uri uri, t return client.send(msg); } +template +pplx::task send_pong_msg_helper(SocketClientClass& client, web::uri uri, test_websocket_server& server) +{ + server.next_message([](test_websocket_msg msg) // Handler to verify the message sent by the client. + { + websocket_asserts::assert_message_equals(msg, "", test_websocket_message_type::WEB_SOCKET_PONG_TYPE); + }); + + client.connect(uri).wait(); + + websocket_outgoing_message msg; + msg.set_pong_message(); + return client.send(msg); +} + pplx::task send_msg_from_stream(websocket_client& client, test_websocket_server& server, web::uri uri, @@ -456,6 +471,25 @@ TEST_FIXTURE(uri_address, send_stream_binary_msg_no_length) client.close().wait(); } +// Send an unsolicited pong message to the server +TEST_FIXTURE(uri_address, send_pong_msg) +{ + test_websocket_server server; + websocket_client client; + send_pong_msg_helper(client, m_uri, server).wait(); + client.close().wait(); +} + +// Send an unsolicited pong message to the server with websocket_callback_client +TEST_FIXTURE(uri_address, send_pong_msg_callback_client) +{ + test_websocket_server server; + websocket_callback_client client; + send_pong_msg_helper(client, m_uri, server).wait(); + client.close().wait(); +} + + } // SUITE(send_msg_tests) }}}} diff --git a/Release/tests/functional/websockets/utilities/test_websocket_server.cpp b/Release/tests/functional/websockets/utilities/test_websocket_server.cpp index c1377ee4ec..4485e93f86 100644 --- a/Release/tests/functional/websockets/utilities/test_websocket_server.cpp +++ b/Release/tests/functional/websockets/utilities/test_websocket_server.cpp @@ -134,6 +134,19 @@ namespace utilities { m_server_connected.set_exception(std::runtime_error("Connection attempt failed.")); }); + m_srv.set_pong_handler([this](websocketpp::connection_hdl hdl, std::string input) + { + auto fn = m_test_srv->get_next_message_handler(); + assert(fn); + + test_websocket_msg wsmsg; + + wsmsg.set_data(std::vector(input.begin(), input.end())); + + wsmsg.set_msg_type(WEB_SOCKET_PONG_TYPE); + fn(wsmsg); + }); + m_srv.set_message_handler([this](websocketpp::connection_hdl hdl, server::message_ptr msg) { auto pay = msg->get_payload(); @@ -151,12 +164,12 @@ namespace utilities { wsmsg.set_msg_type(utilities::WEB_SOCKET_BINARY_MESSAGE_TYPE); break; case websocketpp::frame::opcode::text: - wsmsg.set_msg_type(utilities::WEB_SOCKET_UTF8_MESSAGE_TYPE); + wsmsg.set_msg_type(utilities::WEB_SOCKET_UTF8_MESSAGE_TYPE); break; case websocketpp::frame::opcode::close: wsmsg.set_msg_type(utilities::WEB_SOCKET_CLOSE_TYPE); break; - default: + default: // Websocketspp does not currently support explicit fragmentation. We should not get here. std::abort(); } @@ -262,7 +275,7 @@ namespace utilities { case test_websocket_message_type::WEB_SOCKET_CLOSE_TYPE: flags = websocketpp::frame::opcode::close; // WebSocket::FRAME_OP_CLOSE; break; - case test_websocket_message_type::WEB_SOCKET_UTF8_FRAGMENT_TYPE: + case test_websocket_message_type::WEB_SOCKET_UTF8_FRAGMENT_TYPE: case test_websocket_message_type::WEB_SOCKET_BINARY_FRAGMENT_TYPE: default: throw std::runtime_error("invalid message type"); diff --git a/Release/tests/functional/websockets/utilities/test_websocket_server.h b/Release/tests/functional/websockets/utilities/test_websocket_server.h index b5440068b2..5126c8281d 100644 --- a/Release/tests/functional/websockets/utilities/test_websocket_server.h +++ b/Release/tests/functional/websockets/utilities/test_websocket_server.h @@ -50,7 +50,8 @@ enum test_websocket_message_type WEB_SOCKET_BINARY_FRAGMENT_TYPE, WEB_SOCKET_UTF8_MESSAGE_TYPE, WEB_SOCKET_UTF8_FRAGMENT_TYPE, - WEB_SOCKET_CLOSE_TYPE + WEB_SOCKET_CLOSE_TYPE, + WEB_SOCKET_PONG_TYPE }; // Interface containing details about the HTTP handshake request received by the test server.