11#include " catch2/catch_all.hpp"
22
33#include " crow.h"
4+ #include < cstddef>
5+ #include < thread>
46
57using namespace std ;
68using namespace crow ;
@@ -649,4 +651,90 @@ TEST_CASE("mirror_websocket_subprotocols", "[websocket]")
649651 }
650652
651653 app.stop ();
652- }
654+ }
655+
656+ TEST_CASE (" multithreaded_websockets_open_close" , " [websocket]" )
657+ {
658+ static std::string http_message =
659+ " GET /ws HTTP/1.1\r\n "
660+ " Connection: keep-alive, Upgrade\r\n "
661+ " upgrade: websocket\r\n "
662+ " Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n "
663+ " Sec-WebSocket-Version: 13\r\n "
664+ " Host: localhost\r\n "
665+ " \r\n " ;
666+
667+ CROW_LOG_INFO << " Setting up app!\n " ;
668+ SimpleApp app;
669+
670+ CROW_WEBSOCKET_ROUTE (app, " /ws" )
671+ .onaccept ([&](const crow::request& req, void **) {
672+ CROW_LOG_INFO << " Accepted websocket with URL " << req.url ;
673+ return true ;
674+ })
675+ .onopen ([&](websocket::connection&) {
676+ CROW_LOG_INFO << " Connected websocket" ;
677+ })
678+ .onmessage ([&](websocket::connection&, const std::string&, bool ) {})
679+ .onclose ([&](websocket::connection& conn, const std::string&, uint16_t ) {
680+ // There should just be one connection
681+ CHECK_FALSE (conn.get_remote_ip ().empty ());
682+ CROW_LOG_INFO << " Closing websocket" ;
683+ });
684+
685+ app.validate ();
686+
687+ CROW_LOG_WARNING << " Starting app!\n " ;
688+ auto _ = app.bindaddr (LOCALHOST_ADDRESS).port (45453 ).run_async ();
689+ app.wait_for_server_start ();
690+ CROW_LOG_WARNING << " App started!\n " ;
691+ asio::io_context ic;
692+
693+ const auto thread_function = [&]()
694+ {
695+ asio::ip::tcp::socket c (ic);
696+ c.connect (asio::ip::tcp::endpoint (
697+ asio::ip::make_address (LOCALHOST_ADDRESS), 45453 ));
698+
699+ CROW_LOG_WARNING << " Connected!\n " ;
700+
701+ char buf[2048 ];
702+
703+ // ----------Handshake----------
704+ {
705+ std::fill_n (buf, 2048 , 0 );
706+ c.send (asio::buffer (http_message));
707+
708+ c.receive (asio::buffer (buf, 2048 ));
709+ std::this_thread::sleep_for (std::chrono::milliseconds (5 ));
710+ }
711+
712+ // ----------Close websocket----------
713+ std::fill_n (buf, 2048 , 0 );
714+ // Close message with, len = 2, status code = 1000
715+ char close_message[5 ](" \x88\x02\x03\xE8 " );
716+ c.send (asio::buffer (close_message, 4 ));
717+ c.receive (asio::buffer (buf, 2048 ));
718+ std::this_thread::sleep_for (std::chrono::milliseconds (5 ));
719+ };
720+
721+ const auto multiple_run_thread_function = [&](const std::size_t count){
722+ for (std::size_t i = 0 ; i < count; ++i) {
723+ thread_function ();
724+ }
725+ };
726+
727+ constexpr std::size_t threads_count = 3 ;
728+ constexpr std::size_t thread_run = 10 ;
729+
730+ std::vector<std::thread> threads;
731+ for (std::size_t i = 0 ; i < threads_count; ++i) {
732+ threads.emplace_back (multiple_run_thread_function, thread_run);
733+ }
734+ for (std::thread& thread : threads) {
735+ thread.join ();
736+ }
737+
738+ CROW_LOG_WARNING << " Stopping app!\n " ;
739+ app.stop ();
740+ }
0 commit comments