1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/test/embedded_test_server/websocket_close_observer_handler.h"
#include "base/containers/span.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "net/base/url_util.h"
#include "net/test/embedded_test_server/websocket_connection.h"
namespace net::test_server {
namespace {
// Global variables for managing connection state and close code. These values
// are shared across different instances of WebSocketCloseObserverHandler to
// enable coordination between "observer" and "observed" WebSocket roles.
constinit std::optional<uint16_t> g_code = std::nullopt;
constinit base::OnceClosure g_on_closed;
} // namespace
WebSocketCloseObserverHandler::WebSocketCloseObserverHandler(
scoped_refptr<WebSocketConnection> connection)
: WebSocketHandler(std::move(connection)) {}
WebSocketCloseObserverHandler::~WebSocketCloseObserverHandler() = default;
void WebSocketCloseObserverHandler::SendBadRequest(std::string_view message) {
const std::string response_content = base::StrCat({"Error: ", message});
const std::string response =
base::StrCat({"HTTP/1.1 400 Bad Request\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: ",
base::NumberToString(response_content.size()),
"\r\n"
"\r\n",
response_content});
connection()->SendRaw(base::as_byte_span(response));
connection()->DisconnectAfterAnyWritesDone();
}
void WebSocketCloseObserverHandler::OnHandshake(const HttpRequest& request) {
CHECK(connection());
std::string role;
if (!GetValueForKeyInQuery(request.GetURL(), "role", &role)) {
DVLOG(1) << "Missing required 'role' parameter.";
SendBadRequest("Missing required 'role' parameter.");
return;
}
// Map the role string to the Role enum
if (role == "observer") {
role_ = Role::kObserver;
BeObserver();
} else if (role == "observed") {
role_ = Role::kObserved;
} else {
DVLOG(1) << "Invalid 'role' parameter: " << role;
SendBadRequest("Invalid 'role' parameter.");
return;
}
}
void WebSocketCloseObserverHandler::OnClosingHandshake(
std::optional<uint16_t> code,
std::string_view message) {
DVLOG(3) << "OnClosingHandshake()";
if (role_ == Role::kObserved) {
g_code = code.value_or(1006);
if (g_on_closed) {
std::move(g_on_closed).Run();
}
}
}
void WebSocketCloseObserverHandler::BeObserver() {
DVLOG(3) << "BeObserver()";
if (g_code) {
SendCloseCode();
} else {
g_on_closed = base::BindOnce(&WebSocketCloseObserverHandler::SendCloseCode,
base::Unretained(this));
}
}
void WebSocketCloseObserverHandler::SendCloseCode() {
CHECK(g_code);
const std::string response =
(*g_code == 1001) ? "OK" : "WRONG CODE " + base::NumberToString(*g_code);
connection()->SendTextMessage(response);
}
} // namespace net::test_server
|