Skip to content
Open
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
12 changes: 9 additions & 3 deletions ixwebsocket/IXWebSocketHandshake.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ namespace ix
return s;
}

WebSocketInitResult WebSocketHandshake::sendErrorResponse(int code, const std::string& reason)
WebSocketInitResult WebSocketHandshake::sendErrorResponse(int code,
const std::string& reason,
const std::string& extraHeaders)
{
std::stringstream ss;
ss << "HTTP/1.1 ";
Expand All @@ -72,6 +74,8 @@ namespace ix
ss << reason;
ss << "\r\n";
ss << "Server: " << userAgent() << "\r\n";
ss << extraHeaders;
ss << "\r\n";

// Socket write can only be cancelled through a timeout here, not manually.
static std::atomic<bool> requestInitCancellation(false);
Expand Down Expand Up @@ -354,10 +358,12 @@ namespace ix

if (version != 13)
{
return sendErrorResponse(400,
// Tell the client which version is supported (RFC 6455 section 4.2.2)
return sendErrorResponse(426,
"Invalid Sec-WebSocket-Version, "
"need 13, got " +
ss.str());
ss.str(),
"Sec-WebSocket-Version: 13\r\n");
}
}

Expand Down
4 changes: 3 additions & 1 deletion ixwebsocket/IXWebSocketHandshake.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ namespace ix
std::string genRandomString(const int len);

// Parse HTTP headers
WebSocketInitResult sendErrorResponse(int code, const std::string& reason);
WebSocketInitResult sendErrorResponse(int code,
const std::string& reason,
const std::string& extraHeaders = std::string());

bool insensitiveStringCompare(const std::string& a, const std::string& b);

Expand Down
54 changes: 54 additions & 0 deletions test/IXWebSocketServerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,60 @@ TEST_CASE("Websocket_server", "[websocket_server]")
REQUIRE(server.getClients().size() == 0);
}

SECTION("Send a request with an unsupported version. Should return 426 with the supported "
"version and end the response headers")
{
int port = getFreePort();
ix::WebSocketServer server(port);
std::string connectionId;
REQUIRE(startServer(server, connectionId));

std::string errMsg;
bool tls = false;
SocketTLSOptions tlsOptions;
std::shared_ptr<Socket> socket = createSocket(tls, -1, errMsg, tlsOptions);
std::string host("127.0.0.1");
auto isCancellationRequested = []() -> bool { return false; };
bool success = socket->connect(host, port, errMsg, isCancellationRequested);
REQUIRE(success);

socket->writeBytes("GET / HTTP/1.1\r\n"
"Upgrade: websocket\r\n"
"Sec-WebSocket-Version: 8\r\n"
"Sec-WebSocket-Key: foobar\r\n"
"\r\n",
isCancellationRequested);

auto lineResult = socket->readLine(isCancellationRequested);
REQUIRE(lineResult.first);

int status = -1;
REQUIRE(sscanf(lineResult.second.c_str(), "HTTP/1.1 %d", &status) == 1);
REQUIRE(status == 426);

bool supportedVersionSent = false;
bool headersEnded = false;
while (true)
{
lineResult = socket->readLine(isCancellationRequested);
if (!lineResult.first) break;
if (lineResult.second == "\r\n")
{
headersEnded = true;
break;
}
if (lineResult.second == "Sec-WebSocket-Version: 13\r\n")
{
supportedVersionSent = true;
}
}
REQUIRE(supportedVersionSent);
REQUIRE(headersEnded);

server.stop();
REQUIRE(server.getClients().size() == 0);
}

SECTION("Connect to the server. Send GET request with correct header")
{
int port = getFreePort();
Expand Down