agent-enviroments/builder/libs/seastar/tests/unit/websocket_test.cc
2024-09-10 17:06:08 +03:00

155 lines
5.9 KiB
C++

/*
* Copyright 2021 ScyllaDB
*/
#include <seastar/websocket/server.hh>
#include <seastar/testing/test_case.hh>
#include <seastar/testing/thread_test_case.hh>
#include <seastar/http/response_parser.hh>
#include <seastar/util/defer.hh>
#include "loopback_socket.hh"
using namespace seastar;
using namespace seastar::experimental;
SEASTAR_TEST_CASE(test_websocket_handshake) {
return seastar::async([] {
const std::string request =
"GET / HTTP/1.1\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Protocol: echo\r\n"
"\r\n";
loopback_connection_factory factory;
loopback_socket_impl lsi(factory);
auto acceptor = factory.get_server_socket().accept();
auto connector = lsi.connect(socket_address(), socket_address());
connected_socket sock = connector.get();
auto input = sock.input();
auto output = sock.output();
websocket::server dummy;
dummy.register_handler("echo", [] (input_stream<char>& in,
output_stream<char>& out) {
return repeat([&in, &out]() {
return in.read().then([&out](temporary_buffer<char> f) {
std::cerr << "f.size(): " << f.size() << "\n";
if (f.empty()) {
return make_ready_future<stop_iteration>(stop_iteration::yes);
} else {
return out.write(std::move(f)).then([&out]() {
return out.flush().then([] {
return make_ready_future<stop_iteration>(stop_iteration::no);
});
});
}
});
});
});
websocket::connection conn(dummy, acceptor.get().connection);
future<> serve = conn.process();
auto close = defer([&conn, &input, &output, &serve] () noexcept {
conn.close().get();
input.close().get();
output.close().get();
serve.get();
});
// Send the handshake
output.write(request).get();
output.flush().get();
// Check that the server correctly computed the response
// according to WebSocket handshake specification
http_response_parser parser;
parser.init();
input.consume(parser).get();
std::unique_ptr<http::reply> resp = parser.get_parsed_response();
BOOST_ASSERT(resp);
sstring websocket_accept = resp->_headers["Sec-WebSocket-Accept"];
// Trim possible whitespace prefix
auto it = std::find_if(websocket_accept.begin(), websocket_accept.end(), ::isalnum);
if (it != websocket_accept.end()) {
websocket_accept.erase(websocket_accept.begin(), it);
}
BOOST_REQUIRE_EQUAL(websocket_accept, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=");
for (auto& header : resp->_headers) {
std::cout << header.first << ':' << header.second << std::endl;
}
});
}
SEASTAR_TEST_CASE(test_websocket_handler_registration) {
return seastar::async([] {
loopback_connection_factory factory;
loopback_socket_impl lsi(factory);
auto acceptor = factory.get_server_socket().accept();
auto connector = lsi.connect(socket_address(), socket_address());
connected_socket sock = connector.get();
auto input = sock.input();
auto output = sock.output();
// Setup server
websocket::server ws;
ws.register_handler("echo", [] (input_stream<char>& in,
output_stream<char>& out) {
return repeat([&in, &out]() {
return in.read().then([&out](temporary_buffer<char> f) {
std::cerr << "f.size(): " << f.size() << "\n";
if (f.empty()) {
return make_ready_future<stop_iteration>(stop_iteration::yes);
} else {
return out.write(std::move(f)).then([&out]() {
return out.flush().then([] {
return make_ready_future<stop_iteration>(stop_iteration::no);
});
});
}
});
});
});
websocket::connection conn(ws, acceptor.get().connection);
future<> serve = conn.process();
auto close = defer([&conn, &input, &output, &serve] () noexcept {
conn.close().get();
input.close().get();
output.close().get();
serve.get();
});
// handshake
const std::string request =
"GET / HTTP/1.1\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
"Sec-WebSocket-Version: 13\r\n"
"Sec-WebSocket-Protocol: echo\r\n"
"\r\n";
output.write(request).get();
output.flush().get();
input.read_exactly(186).get();
// Sending and receiving a websocket frame
const auto ws_frame = std::string(
"\202\204" // 1000 0002 1000 0100
"TEST" // Masking Key
"\0\0\0\0", 10); // Masked Message - TEST
const auto rs_frame = std::string(
"\202\004" // 1000 0002 0000 0100
"TEST", 6); // Message - TEST
output.write(ws_frame).get();
output.flush().get();
auto response = input.read_exactly(6).get();
auto response_str = std::string(response.begin(), response.end());
BOOST_REQUIRE_EQUAL(rs_frame, response_str);
});
}