summaryrefslogtreecommitdiff
path: root/chromium/net/server
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-02-02 12:21:57 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-02-12 08:13:00 +0000
commit606d85f2a5386472314d39923da28c70c60dc8e7 (patch)
treea8f4d7bf997f349f45605e6058259fba0630e4d7 /chromium/net/server
parent5786336dda477d04fb98483dca1a5426eebde2d7 (diff)
downloadqtwebengine-chromium-606d85f2a5386472314d39923da28c70c60dc8e7.tar.gz
BASELINE: Update Chromium to 96.0.4664.181
Change-Id: I762cd1da89d73aa6313b4a753fe126c34833f046 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/net/server')
-rw-r--r--chromium/net/server/BUILD.gn2
-rw-r--r--chromium/net/server/http_connection.h16
-rw-r--r--chromium/net/server/http_server.cc6
-rw-r--r--chromium/net/server/http_server.h6
-rw-r--r--chromium/net/server/http_server_fuzzer.cc6
-rw-r--r--chromium/net/server/http_server_unittest.cc162
-rw-r--r--chromium/net/server/web_socket.cc28
-rw-r--r--chromium/net/server/web_socket.h16
-rw-r--r--chromium/net/server/web_socket_encoder.cc83
-rw-r--r--chromium/net/server/web_socket_encoder.h18
-rw-r--r--chromium/net/server/web_socket_encoder_fuzzer.cc23
-rw-r--r--chromium/net/server/web_socket_encoder_unittest.cc302
12 files changed, 598 insertions, 70 deletions
diff --git a/chromium/net/server/BUILD.gn b/chromium/net/server/BUILD.gn
index 8ee35c5270f..0a439b5ea1f 100644
--- a/chromium/net/server/BUILD.gn
+++ b/chromium/net/server/BUILD.gn
@@ -16,10 +16,12 @@ static_library("http_server") {
"//chrome/browser/devtools",
"//chrome/test/chromedriver/*",
"//content/browser",
+ "//net:net_web_socket_encoder_fuzzer",
]
friend = [
":net_http_server_fuzzer",
+ "//net:net_web_socket_encoder_fuzzer",
":tests",
"//chrome/browser/devtools",
"//chrome/test/chromedriver/*",
diff --git a/chromium/net/server/http_connection.h b/chromium/net/server/http_connection.h
index e926493b5e6..e16b3826fd8 100644
--- a/chromium/net/server/http_connection.h
+++ b/chromium/net/server/http_connection.h
@@ -34,6 +34,9 @@ class HttpConnection {
ReadIOBuffer();
+ ReadIOBuffer(const ReadIOBuffer&) = delete;
+ ReadIOBuffer& operator=(const ReadIOBuffer&) = delete;
+
// Capacity.
int GetCapacity() const;
void SetCapacity(int capacity);
@@ -63,8 +66,6 @@ class HttpConnection {
scoped_refptr<GrowableIOBuffer> base_;
int max_buffer_size_;
-
- DISALLOW_COPY_AND_ASSIGN(ReadIOBuffer);
};
// IOBuffer of pending data to write which has a queue of pending data. Each
@@ -76,6 +77,9 @@ class HttpConnection {
QueuedWriteIOBuffer();
+ QueuedWriteIOBuffer(const QueuedWriteIOBuffer&) = delete;
+ QueuedWriteIOBuffer& operator=(const QueuedWriteIOBuffer&) = delete;
+
// Whether or not pending data exists.
bool IsEmpty() const;
@@ -108,11 +112,13 @@ class HttpConnection {
base::queue<std::unique_ptr<std::string>> pending_data_;
int total_size_;
int max_buffer_size_;
-
- DISALLOW_COPY_AND_ASSIGN(QueuedWriteIOBuffer);
};
HttpConnection(int id, std::unique_ptr<StreamSocket> socket);
+
+ HttpConnection(const HttpConnection&) = delete;
+ HttpConnection& operator=(const HttpConnection&) = delete;
+
~HttpConnection();
int id() const { return id_; }
@@ -130,8 +136,6 @@ class HttpConnection {
const scoped_refptr<QueuedWriteIOBuffer> write_buf_;
std::unique_ptr<WebSocket> web_socket_;
-
- DISALLOW_COPY_AND_ASSIGN(HttpConnection);
};
} // namespace net
diff --git a/chromium/net/server/http_server.cc b/chromium/net/server/http_server.cc
index e9bd64bce7f..fdfc5690d49 100644
--- a/chromium/net/server/http_server.cc
+++ b/chromium/net/server/http_server.cc
@@ -86,7 +86,8 @@ void HttpServer::SendOverWebSocket(
if (connection == nullptr)
return;
DCHECK(connection->web_socket());
- connection->web_socket()->Send(data, traffic_annotation);
+ connection->web_socket()->Send(
+ data, WebSocketFrameHeader::OpCodeEnum::kOpCodeText, traffic_annotation);
}
void HttpServer::SendRaw(int connection_id,
@@ -255,7 +256,8 @@ int HttpServer::HandleReadResult(HttpConnection* connection, int rv) {
Close(connection->id());
return ERR_CONNECTION_CLOSED;
}
- delegate_->OnWebSocketMessage(connection->id(), std::move(message));
+ if (result == WebSocket::FRAME_OK_FINAL)
+ delegate_->OnWebSocketMessage(connection->id(), std::move(message));
if (HasClosedConnection(connection))
return ERR_CONNECTION_CLOSED;
continue;
diff --git a/chromium/net/server/http_server.h b/chromium/net/server/http_server.h
index cb70b575731..f866422350f 100644
--- a/chromium/net/server/http_server.h
+++ b/chromium/net/server/http_server.h
@@ -50,6 +50,10 @@ class HttpServer {
// callbacks yet.
HttpServer(std::unique_ptr<ServerSocket> server_socket,
HttpServer::Delegate* delegate);
+
+ HttpServer(const HttpServer&) = delete;
+ HttpServer& operator=(const HttpServer&) = delete;
+
~HttpServer();
void AcceptWebSocket(int connection_id,
@@ -132,8 +136,6 @@ class HttpServer {
std::map<int, std::unique_ptr<HttpConnection>> id_to_connection_;
base::WeakPtrFactory<HttpServer> weak_ptr_factory_{this};
-
- DISALLOW_COPY_AND_ASSIGN(HttpServer);
};
} // namespace net
diff --git a/chromium/net/server/http_server_fuzzer.cc b/chromium/net/server/http_server_fuzzer.cc
index 2f16f03f614..5ebebd80014 100644
--- a/chromium/net/server/http_server_fuzzer.cc
+++ b/chromium/net/server/http_server_fuzzer.cc
@@ -24,6 +24,10 @@ class WaitTillHttpCloseDelegate : public net::HttpServer::Delegate {
done_closure_(std::move(done_closure)),
action_flags_(data_provider_->ConsumeIntegral<uint8_t>()) {}
+ WaitTillHttpCloseDelegate(const WaitTillHttpCloseDelegate&) = delete;
+ WaitTillHttpCloseDelegate& operator=(const WaitTillHttpCloseDelegate&) =
+ delete;
+
void set_server(net::HttpServer* server) { server_ = server; }
void OnConnect(int connection_id) override {
@@ -89,8 +93,6 @@ class WaitTillHttpCloseDelegate : public net::HttpServer::Delegate {
FuzzedDataProvider* const data_provider_;
base::OnceClosure done_closure_;
const uint8_t action_flags_;
-
- DISALLOW_COPY_AND_ASSIGN(WaitTillHttpCloseDelegate);
};
} // namespace
diff --git a/chromium/net/server/http_server_unittest.cc b/chromium/net/server/http_server_unittest.cc
index b32ba77c2e2..b57c5cd21c6 100644
--- a/chromium/net/server/http_server_unittest.cc
+++ b/chromium/net/server/http_server_unittest.cc
@@ -46,6 +46,7 @@
#include "net/test/gtest_util.h"
#include "net/test/test_with_task_environment.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/websockets/websocket_frame.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -311,6 +312,55 @@ class WebSocketTest : public HttpServerTest {
void OnWebSocketMessage(int connection_id, std::string data) override {}
};
+class WebSocketAcceptingTest : public WebSocketTest {
+ public:
+ void OnWebSocketRequest(int connection_id,
+ const HttpServerRequestInfo& info) override {
+ HttpServerTest::OnHttpRequest(connection_id, info);
+ server_->AcceptWebSocket(connection_id, info, TRAFFIC_ANNOTATION_FOR_TESTS);
+ }
+
+ void OnWebSocketMessage(int connection_id, std::string data) override {
+ message_ = data;
+ if (message_.length() > 0 && run_loop_) {
+ run_loop_->Quit();
+ }
+ }
+
+ std::string GetMessage() {
+ run_loop_ = std::make_unique<base::RunLoop>();
+ run_loop_->Run();
+ run_loop_.reset();
+ return message_;
+ }
+
+ private:
+ std::string message_;
+ std::unique_ptr<base::RunLoop> run_loop_;
+};
+
+std::string EncodeFrame(std::string message,
+ WebSocketFrameHeader::OpCodeEnum op_code,
+ bool mask,
+ bool finish) {
+ WebSocketFrameHeader header(op_code);
+ header.final = finish;
+ header.masked = mask;
+ header.payload_length = message.size();
+ const int header_size = GetWebSocketFrameHeaderSize(header);
+ std::string frame_header;
+ frame_header.resize(header_size);
+ if (mask) {
+ WebSocketMaskingKey masking_key = GenerateWebSocketMaskingKey();
+ WriteWebSocketFrameHeader(header, &masking_key, &frame_header[0],
+ header_size);
+ MaskWebSocketFramePayload(masking_key, 0, &message[0], message.length());
+ } else {
+ WriteWebSocketFrameHeader(header, nullptr, &frame_header[0], header_size);
+ }
+ return frame_header + message;
+}
+
TEST_F(HttpServerTest, Request) {
TestHttpClient client;
CreateConnection(&client);
@@ -485,6 +535,113 @@ TEST_F(WebSocketTest, RequestWebSocketTrailingJunk) {
client.ExpectUsedThenDisconnectedWithNoData();
}
+TEST_F(WebSocketAcceptingTest, SendPingFrameWithNoMessage) {
+ TestHttpClient client;
+ CreateConnection(&client);
+ std::string response;
+ client.Send(
+ "GET /test HTTP/1.1\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: SomethingElse, Upgrade\r\n"
+ "Sec-WebSocket-Version: 8\r\n"
+ "Sec-WebSocket-Key: key\r\n\r\n");
+ RunUntilRequestsReceived(1);
+ ASSERT_TRUE(client.ReadResponse(&response));
+ const std::string message = "";
+ const std::string ping_frame =
+ EncodeFrame(message, WebSocketFrameHeader::OpCodeEnum::kOpCodePing,
+ /* mask= */ true, /* finish= */ true);
+ const std::string pong_frame =
+ EncodeFrame(message, WebSocketFrameHeader::OpCodeEnum::kOpCodePong,
+ /* mask= */ false, /* finish= */ true);
+ client.Send(ping_frame);
+ ASSERT_TRUE(client.Read(&response, pong_frame.length()));
+ EXPECT_EQ(response, pong_frame);
+}
+
+TEST_F(WebSocketAcceptingTest, SendPingFrameWithMessage) {
+ TestHttpClient client;
+ CreateConnection(&client);
+ std::string response;
+ client.Send(
+ "GET /test HTTP/1.1\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: SomethingElse, Upgrade\r\n"
+ "Sec-WebSocket-Version: 8\r\n"
+ "Sec-WebSocket-Key: key\r\n\r\n");
+ RunUntilRequestsReceived(1);
+ ASSERT_TRUE(client.ReadResponse(&response));
+ const std::string message = "hello";
+ const std::string ping_frame =
+ EncodeFrame(message, WebSocketFrameHeader::OpCodeEnum::kOpCodePing,
+ /* mask= */ true, /* finish= */ true);
+ const std::string pong_frame =
+ EncodeFrame(message, WebSocketFrameHeader::OpCodeEnum::kOpCodePong,
+ /* mask= */ false, /* finish= */ true);
+ client.Send(ping_frame);
+ ASSERT_TRUE(client.Read(&response, pong_frame.length()));
+ EXPECT_EQ(response, pong_frame);
+}
+
+TEST_F(WebSocketAcceptingTest, SendPongFrame) {
+ TestHttpClient client;
+ CreateConnection(&client);
+ std::string response;
+ client.Send(
+ "GET /test HTTP/1.1\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: SomethingElse, Upgrade\r\n"
+ "Sec-WebSocket-Version: 8\r\n"
+ "Sec-WebSocket-Key: key\r\n\r\n");
+ RunUntilRequestsReceived(1);
+ ASSERT_TRUE(client.ReadResponse(&response));
+ const std::string ping_frame = EncodeFrame(
+ /* message= */ "", WebSocketFrameHeader::OpCodeEnum::kOpCodePing,
+ /* mask= */ true, /* finish= */ true);
+ const std::string pong_frame_send = EncodeFrame(
+ /* message= */ "", WebSocketFrameHeader::OpCodeEnum::kOpCodePong,
+ /* mask= */ true, /* finish= */ true);
+ const std::string pong_frame_receive = EncodeFrame(
+ /* message= */ "", WebSocketFrameHeader::OpCodeEnum::kOpCodePong,
+ /* mask= */ false, /* finish= */ true);
+ client.Send(pong_frame_send);
+ client.Send(ping_frame);
+ ASSERT_TRUE(client.Read(&response, pong_frame_receive.length()));
+ EXPECT_EQ(response, pong_frame_receive);
+}
+
+TEST_F(WebSocketAcceptingTest, SendLongTextFrame) {
+ TestHttpClient client;
+ CreateConnection(&client);
+ std::string response;
+ client.Send(
+ "GET /test HTTP/1.1\r\n"
+ "Upgrade: WebSocket\r\n"
+ "Connection: SomethingElse, Upgrade\r\n"
+ "Sec-WebSocket-Version: 8\r\n"
+ "Sec-WebSocket-Key: key\r\n\r\n");
+ RunUntilRequestsReceived(1);
+ ASSERT_TRUE(client.ReadResponse(&response));
+ constexpr int kMessageSize = 100000;
+ const std::string text_message(kMessageSize, 'a');
+ const std::string continuation_message(kMessageSize, 'b');
+ const std::string text_frame =
+ EncodeFrame(text_message, WebSocketFrameHeader::OpCodeEnum::kOpCodeText,
+ /* mask= */ true,
+ /* finish= */ false);
+ const std::string continuation_frame =
+ EncodeFrame(continuation_message,
+ WebSocketFrameHeader::OpCodeEnum::kOpCodeContinuation,
+ /* mask= */ true, /* finish= */ true);
+ client.Send(text_frame);
+ client.Send(continuation_frame);
+ std::string received_message = GetMessage();
+ EXPECT_EQ(
+ static_cast<int>(received_message.length()),
+ static_cast<int>(text_message.length() + continuation_message.length()));
+ EXPECT_EQ(received_message, text_message + continuation_message);
+}
+
TEST_F(HttpServerTest, RequestWithTooLargeBody) {
TestHttpClient client;
CreateConnection(&client);
@@ -563,6 +720,9 @@ class MockStreamSocket : public StreamSocket {
public:
MockStreamSocket() : connected_(true), read_buf_(nullptr), read_buf_len_(0) {}
+ MockStreamSocket(const MockStreamSocket&) = delete;
+ MockStreamSocket& operator=(const MockStreamSocket&) = delete;
+
// StreamSocket
int Connect(CompletionOnceCallback callback) override {
return ERR_NOT_IMPLEMENTED;
@@ -653,8 +813,6 @@ class MockStreamSocket : public StreamSocket {
CompletionOnceCallback read_callback_;
std::string pending_read_data_;
NetLogWithSource net_log_;
-
- DISALLOW_COPY_AND_ASSIGN(MockStreamSocket);
};
TEST_F(HttpServerTest, RequestWithBodySplitAcrossPackets) {
diff --git a/chromium/net/server/web_socket.cc b/chromium/net/server/web_socket.cc
index 89f4be2d1d2..60462221d80 100644
--- a/chromium/net/server/web_socket.cc
+++ b/chromium/net/server/web_socket.cc
@@ -96,6 +96,8 @@ void WebSocket::Accept(const HttpServerRequestInfo& request,
server_->SendRaw(connection_->id(),
ValidResponseString(encoded_hash, response_extensions),
traffic_annotation);
+ traffic_annotation_ = std::make_unique<NetworkTrafficAnnotationTag>(
+ NetworkTrafficAnnotationTag(traffic_annotation));
}
WebSocket::ParseResult WebSocket::Read(std::string* message) {
@@ -113,23 +115,41 @@ WebSocket::ParseResult WebSocket::Read(std::string* message) {
return FRAME_ERROR;
}
+ ParseResult result = FRAME_OK_MIDDLE;
HttpConnection::ReadIOBuffer* read_buf = connection_->read_buf();
base::StringPiece frame(read_buf->StartOfBuffer(), read_buf->GetSize());
int bytes_consumed = 0;
- ParseResult result = encoder_->DecodeFrame(frame, &bytes_consumed, message);
- if (result == FRAME_OK)
- read_buf->DidConsume(bytes_consumed);
+ result = encoder_->DecodeFrame(frame, &bytes_consumed, message);
+ read_buf->DidConsume(bytes_consumed);
if (result == FRAME_CLOSE)
closed_ = true;
+ if (result == FRAME_PING) {
+ if (!traffic_annotation_)
+ return FRAME_ERROR;
+ Send(*message, WebSocketFrameHeader::kOpCodePong, *traffic_annotation_);
+ }
return result;
}
void WebSocket::Send(base::StringPiece message,
+ WebSocketFrameHeader::OpCodeEnum op_code,
const NetworkTrafficAnnotationTag traffic_annotation) {
if (closed_)
return;
std::string encoded;
- encoder_->EncodeFrame(message, 0, &encoded);
+ switch (op_code) {
+ case WebSocketFrameHeader::kOpCodeText:
+ encoder_->EncodeTextFrame(message, 0, &encoded);
+ break;
+
+ case WebSocketFrameHeader::kOpCodePong:
+ encoder_->EncodePongFrame(message, 0, &encoded);
+ break;
+
+ default:
+ // Only Pong and Text frame types are supported.
+ NOTREACHED();
+ }
server_->SendRaw(connection_->id(), encoded, traffic_annotation);
}
diff --git a/chromium/net/server/web_socket.h b/chromium/net/server/web_socket.h
index 6752b740291..d5c91e06413 100644
--- a/chromium/net/server/web_socket.h
+++ b/chromium/net/server/web_socket.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/websockets/websocket_frame.h"
namespace net {
@@ -22,7 +23,12 @@ class WebSocketEncoder;
class WebSocket final {
public:
enum ParseResult {
- FRAME_OK,
+ // Final frame of a text message or compressed frame.
+ FRAME_OK_FINAL,
+ // Other frame of a text message.
+ FRAME_OK_MIDDLE,
+ FRAME_PING,
+ FRAME_PONG,
FRAME_INCOMPLETE,
FRAME_CLOSE,
FRAME_ERROR
@@ -34,7 +40,12 @@ class WebSocket final {
const NetworkTrafficAnnotationTag traffic_annotation);
ParseResult Read(std::string* message);
void Send(base::StringPiece message,
+ WebSocketFrameHeader::OpCodeEnum op_code,
const NetworkTrafficAnnotationTag traffic_annotation);
+
+ WebSocket(const WebSocket&) = delete;
+ WebSocket& operator=(const WebSocket&) = delete;
+
~WebSocket();
private:
@@ -46,8 +57,7 @@ class WebSocket final {
HttpConnection* const connection_;
std::unique_ptr<WebSocketEncoder> encoder_;
bool closed_;
-
- DISALLOW_COPY_AND_ASSIGN(WebSocket);
+ std::unique_ptr<NetworkTrafficAnnotationTag> traffic_annotation_ = nullptr;
};
} // namespace net
diff --git a/chromium/net/server/web_socket_encoder.cc b/chromium/net/server/web_socket_encoder.cc
index 760ff6b9ebd..7e5e652786b 100644
--- a/chromium/net/server/web_socket_encoder.cc
+++ b/chromium/net/server/web_socket_encoder.cc
@@ -6,15 +6,16 @@
#include <limits>
#include <utility>
-#include <vector>
#include "base/check.h"
#include "base/memory/ptr_util.h"
+#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "net/base/io_buffer.h"
#include "net/websockets/websocket_deflate_parameters.h"
#include "net/websockets/websocket_extension.h"
#include "net/websockets/websocket_extension_parser.h"
+#include "net/websockets/websocket_frame.h"
namespace net {
@@ -27,15 +28,6 @@ const int kInflaterChunkSize = 16 * 1024;
// Constants for hybi-10 frame format.
-typedef int OpCode;
-
-const OpCode kOpCodeContinuation = 0x0;
-const OpCode kOpCodeText = 0x1;
-const OpCode kOpCodeBinary = 0x2;
-const OpCode kOpCodeClose = 0x8;
-const OpCode kOpCodePing = 0x9;
-const OpCode kOpCodePong = 0xA;
-
const unsigned char kFinalBit = 0x80;
const unsigned char kReserved1Bit = 0x40;
const unsigned char kReserved2Bit = 0x20;
@@ -72,20 +64,24 @@ WebSocket::ParseResult DecodeFrameHybi17(const base::StringPiece& frame,
int op_code = first_byte & kOpCodeMask;
bool masked = (second_byte & kMaskBit) != 0;
*compressed = reserved1;
- if (!final || reserved2 || reserved3)
+ if (reserved2 || reserved3)
return WebSocket::FRAME_ERROR; // Only compression extension is supported.
bool closed = false;
switch (op_code) {
- case kOpCodeClose:
+ case WebSocketFrameHeader::OpCodeEnum::kOpCodeClose:
closed = true;
break;
- case kOpCodeText:
+
+ case WebSocketFrameHeader::OpCodeEnum::kOpCodeText:
+ case WebSocketFrameHeader::OpCodeEnum::
+ kOpCodeContinuation: // Treated in the same as kOpCodeText.
+ case WebSocketFrameHeader::OpCodeEnum::kOpCodePing:
+ case WebSocketFrameHeader::OpCodeEnum::kOpCodePong:
break;
- case kOpCodeBinary: // We don't support binary frames yet.
- case kOpCodeContinuation: // We don't support binary frames yet.
- case kOpCodePing: // We don't support binary frames yet.
- case kOpCodePong: // We don't support binary frames yet.
+
+ case WebSocketFrameHeader::OpCodeEnum::kOpCodeBinary: // We don't support
+ // binary frames yet.
default:
return WebSocket::FRAME_ERROR;
}
@@ -137,15 +133,25 @@ WebSocket::ParseResult DecodeFrameHybi17(const base::StringPiece& frame,
size_t pos = p + actual_masking_key_length + payload_length - buffer_begin;
*bytes_consumed = pos;
- return closed ? WebSocket::FRAME_CLOSE : WebSocket::FRAME_OK;
+
+ if (op_code == WebSocketFrameHeader::OpCodeEnum::kOpCodePing)
+ return WebSocket::FRAME_PING;
+
+ if (op_code == WebSocketFrameHeader::OpCodeEnum::kOpCodePong)
+ return WebSocket::FRAME_PONG;
+
+ if (closed)
+ return WebSocket::FRAME_CLOSE;
+
+ return final ? WebSocket::FRAME_OK_FINAL : WebSocket::FRAME_OK_MIDDLE;
}
void EncodeFrameHybi17(base::StringPiece message,
int masking_key,
bool compressed,
+ WebSocketFrameHeader::OpCodeEnum op_code,
std::string* output) {
std::vector<char> frame;
- OpCode op_code = kOpCodeText;
size_t data_length = message.length();
int reserved1 = compressed ? kReserved1Bit : 0;
@@ -292,23 +298,44 @@ WebSocket::ParseResult WebSocketEncoder::DecodeFrame(
int* bytes_consumed,
std::string* output) {
bool compressed;
+ std::string current_output;
WebSocket::ParseResult result = DecodeFrameHybi17(
- frame, type_ == FOR_SERVER, bytes_consumed, output, &compressed);
- if (result == WebSocket::FRAME_OK && compressed) {
- if (!Inflate(output))
- result = WebSocket::FRAME_ERROR;
+ frame, type_ == FOR_SERVER, bytes_consumed, &current_output, &compressed);
+ if (result == WebSocket::FRAME_OK_FINAL ||
+ result == WebSocket::FRAME_OK_MIDDLE || result == WebSocket::FRAME_PING) {
+ if (continuation_message_frames_.empty())
+ is_current_message_compressed_ = compressed;
+ continuation_message_frames_.push_back(current_output);
+ }
+ if (result == WebSocket::FRAME_OK_FINAL || result == WebSocket::FRAME_PING) {
+ *output = base::StrCat(continuation_message_frames_);
+ if (is_current_message_compressed_) {
+ if (!Inflate(output))
+ result = WebSocket::FRAME_ERROR;
+ }
}
+ if (result != WebSocket::FRAME_OK_MIDDLE &&
+ result != WebSocket::FRAME_INCOMPLETE)
+ continuation_message_frames_.clear();
return result;
}
-void WebSocketEncoder::EncodeFrame(base::StringPiece frame,
- int masking_key,
- std::string* output) {
+void WebSocketEncoder::EncodeTextFrame(base::StringPiece frame,
+ int masking_key,
+ std::string* output) {
std::string compressed;
+ constexpr auto op_code = WebSocketFrameHeader::OpCodeEnum::kOpCodeText;
if (Deflate(frame, &compressed))
- EncodeFrameHybi17(compressed, masking_key, true, output);
+ EncodeFrameHybi17(compressed, masking_key, true, op_code, output);
else
- EncodeFrameHybi17(frame, masking_key, false, output);
+ EncodeFrameHybi17(frame, masking_key, false, op_code, output);
+}
+
+void WebSocketEncoder::EncodePongFrame(base::StringPiece frame,
+ int masking_key,
+ std::string* output) {
+ constexpr auto op_code = WebSocketFrameHeader::OpCodeEnum::kOpCodePong;
+ EncodeFrameHybi17(frame, masking_key, false, op_code, output);
}
bool WebSocketEncoder::Inflate(std::string* message) {
diff --git a/chromium/net/server/web_socket_encoder.h b/chromium/net/server/web_socket_encoder.h
index de6bea7b550..3f18f00053b 100644
--- a/chromium/net/server/web_socket_encoder.h
+++ b/chromium/net/server/web_socket_encoder.h
@@ -7,6 +7,7 @@
#include <memory>
#include <string>
+#include <vector>
#include "base/macros.h"
#include "base/strings/string_piece.h"
@@ -22,6 +23,9 @@ class WebSocketEncoder final {
public:
static const char kClientExtensions[];
+ WebSocketEncoder(const WebSocketEncoder&) = delete;
+ WebSocketEncoder& operator=(const WebSocketEncoder&) = delete;
+
~WebSocketEncoder();
// Creates and returns an encoder for a server without extensions.
@@ -38,9 +42,12 @@ class WebSocketEncoder final {
WebSocket::ParseResult DecodeFrame(const base::StringPiece& frame,
int* bytes_consumed,
std::string* output);
- void EncodeFrame(base::StringPiece frame,
- int masking_key,
- std::string* output);
+ void EncodeTextFrame(base::StringPiece frame,
+ int masking_key,
+ std::string* output);
+ void EncodePongFrame(base::StringPiece frame,
+ int masking_key,
+ std::string* output);
bool deflate_enabled() const { return !!deflater_; }
@@ -54,14 +61,15 @@ class WebSocketEncoder final {
std::unique_ptr<WebSocketDeflater> deflater,
std::unique_ptr<WebSocketInflater> inflater);
+ std::vector<std::string> continuation_message_frames_;
+ bool is_current_message_compressed_ = false;
+
bool Inflate(std::string* message);
bool Deflate(base::StringPiece message, std::string* output);
Type type_;
std::unique_ptr<WebSocketDeflater> deflater_;
std::unique_ptr<WebSocketInflater> inflater_;
-
- DISALLOW_COPY_AND_ASSIGN(WebSocketEncoder);
};
} // namespace net
diff --git a/chromium/net/server/web_socket_encoder_fuzzer.cc b/chromium/net/server/web_socket_encoder_fuzzer.cc
new file mode 100644
index 00000000000..d738740e9dd
--- /dev/null
+++ b/chromium/net/server/web_socket_encoder_fuzzer.cc
@@ -0,0 +1,23 @@
+#include <stddef.h>
+#include <stdint.h>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <memory>
+#include <string>
+
+#include "net/server/web_socket_encoder.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fuzzed_data_provider(data, size);
+ auto server = net::WebSocketEncoder::CreateServer();
+ int bytes_consumed;
+ std::string decoded;
+
+ while (fuzzed_data_provider.remaining_bytes() > 0) {
+ size_t chunk_size = fuzzed_data_provider.ConsumeIntegralInRange(1, 125);
+ std::string chunk = fuzzed_data_provider.ConsumeBytesAsString(chunk_size);
+ server->DecodeFrame(chunk, &bytes_consumed, &decoded);
+ }
+ return 0;
+} \ No newline at end of file
diff --git a/chromium/net/server/web_socket_encoder_unittest.cc b/chromium/net/server/web_socket_encoder_unittest.cc
index 4a180ab8e34..0120ea319ac 100644
--- a/chromium/net/server/web_socket_encoder_unittest.cc
+++ b/chromium/net/server/web_socket_encoder_unittest.cc
@@ -4,8 +4,12 @@
#include "net/server/web_socket_encoder.h"
+#include <stddef.h>
+
+#include "base/strings/strcat.h"
#include "net/websockets/websocket_deflate_parameters.h"
#include "net/websockets/websocket_extension.h"
+#include "net/websockets/websocket_frame.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
@@ -86,6 +90,64 @@ class WebSocketEncoderTest : public testing::Test {
client_ = WebSocketEncoder::CreateClient("");
}
+ // Generate deflated and continuous frames from original text.
+ // The length of `original_text` must be longer than 4*partitions.
+ std::vector<std::string> GenerateFragmentedFrames(std::string original_text,
+ int mask,
+ int partitions,
+ bool compressed) {
+ constexpr uint8_t kFinalBit = 0x80;
+ constexpr uint8_t kReserved1Bit = 0x40;
+ constexpr uint8_t kMaskBit = 0x80;
+
+ // A frame consists of 3 or 2 parts: header, (mask) and payload.
+ // The first two bytes of `encoded` are the header of the frame.
+ // If there is a mask, the four bytes of the mask is inserted after the
+ // header. Finally, message contents come.
+ std::string encoded;
+ int num_mask_header;
+ char mask_key_bit;
+ std::string mask_bytes;
+
+ if (mask == 0) {
+ server_->EncodeTextFrame(original_text, mask, &encoded);
+ num_mask_header = 0;
+ mask_key_bit = 0;
+ } else {
+ client_->EncodeTextFrame(original_text, mask, &encoded);
+ num_mask_header = 4;
+ mask_key_bit = kMaskBit;
+ mask_bytes = encoded.substr(2, 4);
+ }
+ int divide_length =
+ (static_cast<int>(encoded.length()) - 2 - num_mask_header) / partitions;
+ divide_length -= divide_length % 4;
+ std::vector<std::string> encoded_frames(partitions);
+ std::string payload;
+ std::string header;
+
+ for (int i = 0; i < partitions; ++i) {
+ char first_byte = 0;
+ if (i == 0)
+ first_byte |= WebSocketFrameHeader::OpCodeEnum::kOpCodeText;
+ else
+ first_byte |= WebSocketFrameHeader::OpCodeEnum::kOpCodeContinuation;
+ if (i == partitions - 1)
+ first_byte |= kFinalBit;
+ if (compressed)
+ first_byte |= kReserved1Bit;
+
+ const int position = 2 + num_mask_header + i * divide_length;
+ const int length =
+ i < partitions - 1 ? divide_length : encoded.length() - position;
+ payload = encoded.substr(position, length);
+ header = {first_byte, static_cast<char>(payload.length() | mask_key_bit)};
+ encoded_frames[i] += header + mask_bytes + payload;
+ }
+
+ return encoded_frames;
+ }
+
protected:
std::unique_ptr<WebSocketEncoder> server_;
std::unique_ptr<WebSocketEncoder> client_;
@@ -125,10 +187,10 @@ TEST_F(WebSocketEncoderTest, ClientToServer) {
int bytes_consumed;
std::string decoded;
- client_->EncodeFrame(frame, mask, &encoded);
- EXPECT_EQ(WebSocket::FRAME_OK,
+ client_->EncodeTextFrame(frame, mask, &encoded);
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
server_->DecodeFrame(encoded, &bytes_consumed, &decoded));
- EXPECT_EQ(frame, decoded);
+ EXPECT_EQ("ClientToServer", decoded);
EXPECT_EQ((int)encoded.length(), bytes_consumed);
std::string partial = encoded.substr(0, encoded.length() - 2);
@@ -136,9 +198,9 @@ TEST_F(WebSocketEncoderTest, ClientToServer) {
server_->DecodeFrame(partial, &bytes_consumed, &decoded));
std::string extra = encoded + "more stuff";
- EXPECT_EQ(WebSocket::FRAME_OK,
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
server_->DecodeFrame(extra, &bytes_consumed, &decoded));
- EXPECT_EQ(frame, decoded);
+ EXPECT_EQ("ClientToServer", decoded);
EXPECT_EQ((int)encoded.length(), bytes_consumed);
EXPECT_EQ(
@@ -153,10 +215,10 @@ TEST_F(WebSocketEncoderTest, ServerToClient) {
int bytes_consumed;
std::string decoded;
- server_->EncodeFrame(frame, mask, &encoded);
- EXPECT_EQ(WebSocket::FRAME_OK,
+ server_->EncodeTextFrame(frame, mask, &encoded);
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
client_->DecodeFrame(encoded, &bytes_consumed, &decoded));
- EXPECT_EQ(frame, decoded);
+ EXPECT_EQ("ServerToClient", decoded);
EXPECT_EQ((int)encoded.length(), bytes_consumed);
std::string partial = encoded.substr(0, encoded.length() - 2);
@@ -164,9 +226,9 @@ TEST_F(WebSocketEncoderTest, ServerToClient) {
client_->DecodeFrame(partial, &bytes_consumed, &decoded));
std::string extra = encoded + "more stuff";
- EXPECT_EQ(WebSocket::FRAME_OK,
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
client_->DecodeFrame(extra, &bytes_consumed, &decoded));
- EXPECT_EQ(frame, decoded);
+ EXPECT_EQ("ServerToClient", decoded);
EXPECT_EQ((int)encoded.length(), bytes_consumed);
EXPECT_EQ(
@@ -174,6 +236,132 @@ TEST_F(WebSocketEncoderTest, ServerToClient) {
client_->DecodeFrame(std::string("abcde"), &bytes_consumed, &decoded));
}
+TEST_F(WebSocketEncoderTest, DecodeFragmentedMessageClientToServerDivided2) {
+ const std::string kOriginalText = "abcdefghijklmnop";
+ constexpr int kMask = 123456;
+ constexpr bool kCompressed = false;
+ constexpr int kPartitions = 2;
+ ASSERT_GT(static_cast<int>(kOriginalText.length()), 4 * kPartitions);
+ std::vector<std::string> encoded_frames =
+ GenerateFragmentedFrames(kOriginalText, kMask, kPartitions, kCompressed);
+ ASSERT_EQ(kPartitions, static_cast<int>(encoded_frames.size()));
+
+ const std::string& kEncodedFirstFrame = encoded_frames[0];
+ const std::string& kEncodedLastFrame = encoded_frames[1];
+
+ int bytes_consumed;
+ std::string decoded;
+
+ // kEncodedFirstFrame -> kEncodedLastFrame
+ EXPECT_EQ(
+ WebSocket::FRAME_OK_MIDDLE,
+ server_->DecodeFrame(kEncodedFirstFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedFirstFrame.length()), bytes_consumed);
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
+ server_->DecodeFrame(kEncodedLastFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("abcdefghijklmnop", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedLastFrame.length()), bytes_consumed);
+}
+
+TEST_F(WebSocketEncoderTest, DecodeFragmentedMessageClientToServerDivided3) {
+ const std::string kOriginalText = "abcdefghijklmnop";
+ constexpr int kMask = 123456;
+ constexpr bool kCompressed = false;
+ constexpr int kPartitions = 3;
+ ASSERT_GT(static_cast<int>(kOriginalText.length()), 4 * kPartitions);
+ std::vector<std::string> encoded_frames =
+ GenerateFragmentedFrames(kOriginalText, kMask, kPartitions, kCompressed);
+ ASSERT_EQ(kPartitions, static_cast<int>(encoded_frames.size()));
+
+ const std::string& kEncodedFirstFrame = encoded_frames[0];
+ const std::string& kEncodedSecondFrame = encoded_frames[1];
+ const std::string& kEncodedLastFrame = encoded_frames[2];
+
+ int bytes_consumed;
+ std::string decoded;
+
+ // kEncodedFirstFrame -> kEncodedSecondFrame -> kEncodedLastFrame
+ EXPECT_EQ(
+ WebSocket::FRAME_OK_MIDDLE,
+ server_->DecodeFrame(kEncodedFirstFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedFirstFrame.length()), bytes_consumed);
+ EXPECT_EQ(
+ WebSocket::FRAME_OK_MIDDLE,
+ server_->DecodeFrame(kEncodedSecondFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedSecondFrame.length()), bytes_consumed);
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
+ server_->DecodeFrame(kEncodedLastFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("abcdefghijklmnop", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedLastFrame.length()), bytes_consumed);
+}
+
+TEST_F(WebSocketEncoderTest, DecodeFragmentedMessageServerToClientDivided2) {
+ const std::string kOriginalText = "abcdefghijklmnop";
+ constexpr int kMask = 0;
+ constexpr bool kCompressed = false;
+
+ constexpr int kPartitions = 2;
+ ASSERT_GT(static_cast<int>(kOriginalText.length()), 4 * kPartitions);
+ std::vector<std::string> encoded_frames =
+ GenerateFragmentedFrames(kOriginalText, kMask, kPartitions, kCompressed);
+ ASSERT_EQ(kPartitions, static_cast<int>(encoded_frames.size()));
+
+ const std::string& kEncodedFirstFrame = encoded_frames[0];
+ const std::string& kEncodedLastFrame = encoded_frames[1];
+
+ int bytes_consumed;
+ std::string decoded;
+
+ // kEncodedFirstFrame -> kEncodedLastFrame
+ EXPECT_EQ(
+ WebSocket::FRAME_OK_MIDDLE,
+ client_->DecodeFrame(kEncodedFirstFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedFirstFrame.length()), bytes_consumed);
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
+ client_->DecodeFrame(kEncodedLastFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("abcdefghijklmnop", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedLastFrame.length()), bytes_consumed);
+}
+
+TEST_F(WebSocketEncoderTest, DecodeFragmentedMessageServerToClientDivided3) {
+ const std::string kOriginalText = "abcdefghijklmnop";
+ constexpr int kMask = 0;
+ constexpr bool kCompressed = false;
+
+ constexpr int kPartitions = 3;
+ ASSERT_GT(static_cast<int>(kOriginalText.length()), 4 * kPartitions);
+ std::vector<std::string> encoded_frames =
+ GenerateFragmentedFrames(kOriginalText, kMask, kPartitions, kCompressed);
+ ASSERT_EQ(kPartitions, static_cast<int>(encoded_frames.size()));
+
+ const std::string& kEncodedFirstFrame = encoded_frames[0];
+ const std::string& kEncodedSecondFrame = encoded_frames[1];
+ const std::string& kEncodedLastFrame = encoded_frames[2];
+
+ int bytes_consumed;
+ std::string decoded;
+
+ // kEncodedFirstFrame -> kEncodedSecondFrame -> kEncodedLastFrame
+ EXPECT_EQ(
+ WebSocket::FRAME_OK_MIDDLE,
+ client_->DecodeFrame(kEncodedFirstFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedFirstFrame.length()), bytes_consumed);
+ EXPECT_EQ(
+ WebSocket::FRAME_OK_MIDDLE,
+ client_->DecodeFrame(kEncodedSecondFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedSecondFrame.length()), bytes_consumed);
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
+ client_->DecodeFrame(kEncodedLastFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("abcdefghijklmnop", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedLastFrame.length()), bytes_consumed);
+}
+
TEST_F(WebSocketEncoderCompressionTest, ClientToServer) {
std::string frame("CompressionCompressionCompressionCompression");
int mask = 654321;
@@ -181,9 +369,9 @@ TEST_F(WebSocketEncoderCompressionTest, ClientToServer) {
int bytes_consumed;
std::string decoded;
- client_->EncodeFrame(frame, mask, &encoded);
+ client_->EncodeTextFrame(frame, mask, &encoded);
EXPECT_LT(encoded.length(), frame.length());
- EXPECT_EQ(WebSocket::FRAME_OK,
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
server_->DecodeFrame(encoded, &bytes_consumed, &decoded));
EXPECT_EQ(frame, decoded);
EXPECT_EQ((int)encoded.length(), bytes_consumed);
@@ -196,9 +384,9 @@ TEST_F(WebSocketEncoderCompressionTest, ServerToClient) {
int bytes_consumed;
std::string decoded;
- server_->EncodeFrame(frame, mask, &encoded);
+ server_->EncodeTextFrame(frame, mask, &encoded);
EXPECT_LT(encoded.length(), frame.length());
- EXPECT_EQ(WebSocket::FRAME_OK,
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
client_->DecodeFrame(encoded, &bytes_consumed, &decoded));
EXPECT_EQ(frame, decoded);
EXPECT_EQ((int)encoded.length(), bytes_consumed);
@@ -223,12 +411,94 @@ TEST_F(WebSocketEncoderCompressionTest, LongFrame) {
int bytes_consumed;
std::string decoded;
- server_->EncodeFrame(frame, mask, &encoded);
+ server_->EncodeTextFrame(frame, mask, &encoded);
EXPECT_LT(encoded.length(), frame.length());
- EXPECT_EQ(WebSocket::FRAME_OK,
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
client_->DecodeFrame(encoded, &bytes_consumed, &decoded));
EXPECT_EQ(frame, decoded);
EXPECT_EQ((int)encoded.length(), bytes_consumed);
}
+TEST_F(WebSocketEncoderCompressionTest, DecodeFragmentedMessageClientToServer) {
+ const std::string kOriginalText = "abcdefghijklmnop";
+ constexpr int kMask = 123456;
+
+ constexpr int kPartitions = 3;
+ constexpr bool kCompressed = true;
+ ASSERT_GT(static_cast<int>(kOriginalText.length()), 4 * kPartitions);
+ std::vector<std::string> encoded_frames =
+ GenerateFragmentedFrames(kOriginalText, kMask, kPartitions, kCompressed);
+ ASSERT_EQ(kPartitions, static_cast<int>(encoded_frames.size()));
+
+ const std::string& kEncodedFirstFrame = encoded_frames[0];
+ const std::string& kEncodedSecondFrame = encoded_frames[1];
+ const std::string& kEncodedLastFrame = encoded_frames[2];
+
+ int bytes_consumed;
+ std::string decoded;
+
+ // kEncodedFirstFrame -> kEncodedSecondFrame -> kEncodedLastFrame
+ EXPECT_EQ(
+ WebSocket::FRAME_OK_MIDDLE,
+ server_->DecodeFrame(kEncodedFirstFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedFirstFrame.length()), bytes_consumed);
+ EXPECT_EQ(
+ WebSocket::FRAME_OK_MIDDLE,
+ server_->DecodeFrame(kEncodedSecondFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedSecondFrame.length()), bytes_consumed);
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
+ server_->DecodeFrame(kEncodedLastFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("abcdefghijklmnop", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedLastFrame.length()), bytes_consumed);
+}
+
+TEST_F(WebSocketEncoderCompressionTest, DecodeFragmentedMessageServerToClient) {
+ const std::string kOriginalText = "abcdefghijklmnop";
+ constexpr int kMask = 0;
+
+ constexpr int kPartitions = 3;
+ constexpr bool kCompressed = true;
+ ASSERT_GT(static_cast<int>(kOriginalText.length()), 4 * kPartitions);
+ std::vector<std::string> encoded_frames =
+ GenerateFragmentedFrames(kOriginalText, kMask, kPartitions, kCompressed);
+ ASSERT_EQ(kPartitions, static_cast<int>(encoded_frames.size()));
+
+ const std::string& kEncodedFirstFrame = encoded_frames[0];
+ const std::string& kEncodedSecondFrame = encoded_frames[1];
+ const std::string& kEncodedLastFrame = encoded_frames[2];
+
+ int bytes_consumed;
+ std::string decoded;
+
+ // kEncodedFirstFrame -> kEncodedSecondFrame -> kEncodedLastFrame
+ decoded.clear();
+ EXPECT_EQ(
+ WebSocket::FRAME_OK_MIDDLE,
+ client_->DecodeFrame(kEncodedFirstFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedFirstFrame.length()), bytes_consumed);
+ EXPECT_EQ(
+ WebSocket::FRAME_OK_MIDDLE,
+ client_->DecodeFrame(kEncodedSecondFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedSecondFrame.length()), bytes_consumed);
+ EXPECT_EQ(WebSocket::FRAME_OK_FINAL,
+ client_->DecodeFrame(kEncodedLastFrame, &bytes_consumed, &decoded));
+ EXPECT_EQ("abcdefghijklmnop", decoded);
+ EXPECT_EQ(static_cast<int>(kEncodedLastFrame.length()), bytes_consumed);
+}
+
+TEST_F(WebSocketEncoderCompressionTest, CheckPongFrameNotCompressed) {
+ constexpr uint8_t kReserved1Bit = 0x40;
+ const std::string kOriginalText = "abcdefghijklmnop";
+ constexpr int kMask = 0;
+ std::string encoded;
+
+ server_->EncodePongFrame(kOriginalText, kMask, &encoded);
+ EXPECT_FALSE(encoded[1] & kReserved1Bit);
+ EXPECT_EQ(kOriginalText, encoded.substr(2));
+}
+
} // namespace net