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

Add unsolicited pong support with integration tests #20

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions Release/include/cpprest/ws_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ class websocket_outgoing_message
{
public:

/// <summary>
/// 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.
/// </summary>
void set_pong_message()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: This will fail on WinRT with an exception "Message Type not supported.".
I think this behavior is acceptable.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, great.

{
this->set_message_pong();
}

/// <summary>
/// Sets a UTF-8 message as the message body.
/// </summary>
Expand Down Expand Up @@ -152,6 +161,14 @@ class websocket_outgoing_message

const pplx::task_completion_event<void> & body_sent() const { return m_body_sent; }

void set_message_pong()
{
concurrency::streams::container_buffer<std::string> buffer("");
m_msg_type = websocket_message_type::pong;
m_length = static_cast<size_t>(buffer.size());
m_body = buffer;
}

void set_message(const concurrency::streams::container_buffer<std::string> &buffer)
{
m_msg_type = websocket_message_type::text_message;
Expand Down
11 changes: 9 additions & 2 deletions Release/src/websockets/client/ws_client_wspp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>(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<void>(websocket_exception("Cannot send empty message."));
}
Expand Down Expand Up @@ -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();
Expand Down
34 changes: 34 additions & 0 deletions Release/tests/functional/websockets/client/send_msg_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,21 @@ pplx::task<void> send_text_msg_helper(SocketClientClass& client, web::uri uri, t
return client.send(msg);
}

template<class SocketClientClass>
pplx::task<void> 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<void> send_msg_from_stream(websocket_client& client,
test_websocket_server& server,
web::uri uri,
Expand Down Expand Up @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests will fail on WinRT since our WinRT websocket implementation does not support ping/pong messages. We should disable these tests on winrt (#if !defined(__cplusplus_winrt)).
Alternatively, I can also disable these tests for WinRT once we accept the PR.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am happy adding the ifdef myself, but I am also happy if you do that :) Let me know how you want me to proceed.

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

}}}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t>(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();
Expand All @@ -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();
}
Expand Down Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down