3c77ce3cc7
The HTTP request processing code was expecting that the http response state would be `deferred` after a call to an HTTP handler that deferred the response. If, in addition to deferring, you also sent the response the HTTP state advanced past `deferred` to `response_written`. This doesn't easily show up in unit tests because the bug requires that the async write still be in flight and the connection still be open when the HTTP handler returns. An asynchronous network transport (like Asio) combined with a sufficiently large message that Asio yields control back to WebSocket++ before the response is fully written will trigger a second write on the same connection while the first is in flight. This is not allowed per the Asio spec and results in undefined behavior. The HTTP request processing code now checks if the http state is init, i.e. not deferred and no response has been started rather than just if it was deferred.
66 lines
1.9 KiB
C++
66 lines
1.9 KiB
C++
#include <websocketpp/config/asio_no_tls.hpp>
|
|
|
|
#include <websocketpp/server.hpp>
|
|
|
|
#include <iostream>
|
|
|
|
typedef websocketpp::server<websocketpp::config::asio> server;
|
|
|
|
using websocketpp::lib::placeholders::_1;
|
|
using websocketpp::lib::placeholders::_2;
|
|
using websocketpp::lib::bind;
|
|
|
|
// pull out the type of messages sent by our config
|
|
typedef server::message_ptr message_ptr;
|
|
|
|
// Define a callback to handle incoming messages
|
|
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
|
|
std::cout << "on_message called with hdl: " << hdl.lock().get()
|
|
<< " and message: " << msg->get_payload()
|
|
<< std::endl;
|
|
|
|
// check for a special command to instruct the server to stop listening so
|
|
// it can be cleanly exited.
|
|
if (msg->get_payload() == "stop-listening") {
|
|
s->stop_listening();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
s->send(hdl, msg->get_payload(), msg->get_opcode());
|
|
} catch (const websocketpp::lib::error_code& e) {
|
|
std::cout << "Echo failed because: " << e
|
|
<< "(" << e.message() << ")" << std::endl;
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
// Create a server endpoint
|
|
server echo_server;
|
|
|
|
try {
|
|
// Set logging settings
|
|
echo_server.set_access_channels(websocketpp::log::alevel::all);
|
|
echo_server.clear_access_channels(websocketpp::log::alevel::frame_payload);
|
|
|
|
// Initialize Asio
|
|
echo_server.init_asio();
|
|
|
|
// Register our message handler
|
|
echo_server.set_message_handler(bind(&on_message,&echo_server,::_1,::_2));
|
|
|
|
// Listen on port 9002
|
|
echo_server.listen(9002);
|
|
|
|
// Start the server accept loop
|
|
echo_server.start_accept();
|
|
|
|
// Start the ASIO io_service run loop
|
|
echo_server.run();
|
|
} catch (websocketpp::exception const & e) {
|
|
std::cout << e.what() << std::endl;
|
|
} catch (...) {
|
|
std::cout << "other exception" << std::endl;
|
|
}
|
|
}
|