summaryrefslogtreecommitdiffhomepage
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/test-webserver.cpp85
1 files changed, 85 insertions, 0 deletions
diff --git a/tests/test-webserver.cpp b/tests/test-webserver.cpp
index ef3b15f..7059bc6 100644
--- a/tests/test-webserver.cpp
+++ b/tests/test-webserver.cpp
@@ -15,10 +15,14 @@
#include <boost/algorithm/string.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
+#include <boost/beast/websocket.hpp>
+#include <boost/beast/websocket/ssl.hpp>
#ifdef BOOST_LATEST
#include <boost/beast/ssl.hpp>
#endif
#include <boost/beast/version.hpp>
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/buffers_iterator.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
@@ -441,3 +445,84 @@ BOOST_DATA_TEST_CASE_F(Fixture, http_get_file_not_found, data::make({false, true
BOOST_REQUIRE_EQUAL(response.second, method == boost::beast::http::verb::head ? "" : "404 Not found: /webserver.confSUFFIX");
}
+BOOST_FIXTURE_TEST_CASE(websocket, Fixture)
+{
+ WebserverProcess serverProcess;
+ BOOST_REQUIRE(serverProcess.isRunning());
+
+
+ std::string host = "::1";
+ auto const port = "8081" ;
+ auto const text = "request1";
+
+ // The io_context is required for all I/O
+ boost::asio::io_context ioc;
+
+ // The SSL context is required, and holds certificates
+ boost::asio::ssl::context ctx{boost::asio::ssl::context::tlsv13_client};
+
+ // This holds the root certificate used for verification
+ load_root_certificates(ctx);
+
+ // These objects perform our I/O
+ boost::asio::ip::tcp::resolver resolver{ioc};
+ boost::beast::websocket::stream<boost::beast::ssl_stream<boost::asio::ip::tcp::socket>> ws{ioc, ctx};
+
+ // Look up the domain name
+ auto const results = resolver.resolve(host, port);
+
+ // Make the connection on the IP address we get from a lookup
+ auto ep = boost::asio::connect(get_lowest_layer(ws), results);
+
+ // Set SNI Hostname (many hosts need this to handshake successfully)
+ if(! SSL_set_tlsext_host_name(ws.next_layer().native_handle(), host.c_str()))
+ throw boost::beast::system_error(
+ boost::beast::error_code(
+ static_cast<int>(::ERR_get_error()),
+ boost::asio::error::get_ssl_category()),
+ "Failed to set SNI Hostname");
+
+ // Update the host_ string. This will provide the value of the
+ // Host HTTP header during the WebSocket handshake.
+ // See https://tools.ietf.org/html/rfc7230#section-5.4
+ host += ':' + std::to_string(ep.port());
+
+ // Perform the SSL handshake
+ ws.next_layer().handshake(boost::asio::ssl::stream_base::client);
+
+ // Set a decorator to change the User-Agent of the handshake
+ ws.set_option(boost::beast::websocket::stream_base::decorator(
+ [](boost::beast::websocket::request_type& req)
+ {
+ req.set(boost::beast::http::field::user_agent,
+ std::string(BOOST_BEAST_VERSION_STRING) +
+ " websocket-client-coro");
+ }));
+
+ // Perform the websocket handshake
+ ws.handshake(host, "/");
+
+ // Send the message
+ ws.write(boost::asio::buffer(std::string(text)));
+
+ // This buffer will hold the incoming message
+ boost::beast::flat_buffer buffer;
+
+ // Read a message into our buffer
+ ws.read(buffer);
+ std::string data(boost::asio::buffers_begin(buffer.data()), boost::asio::buffers_end(buffer.data()));
+ BOOST_CHECK_EQUAL(data, "request1: 0");
+
+ buffer.consume(buffer.size());
+
+ ws.write(boost::asio::buffer(std::string(text)));
+ ws.read(buffer);
+ data = std::string(boost::asio::buffers_begin(buffer.data()), boost::asio::buffers_end(buffer.data()));
+ BOOST_CHECK_EQUAL(data, "request1: 1");
+
+ // Close the WebSocket connection
+ ws.close(boost::beast::websocket::close_code::normal);
+
+ BOOST_REQUIRE(serverProcess.isRunning());
+}
+