Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1439)

Unified Diff: net/websockets/websocket_frame_builder_unittest.cc

Issue 10384180: Add functions used for building WebSocket frame data. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/websockets/websocket_frame_builder_unittest.cc
diff --git a/net/websockets/websocket_frame_builder_unittest.cc b/net/websockets/websocket_frame_builder_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..399f5390aa73f49e07cb535fda076c57bc5e1888
--- /dev/null
+++ b/net/websockets/websocket_frame_builder_unittest.cc
@@ -0,0 +1,663 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/websockets/websocket_frame_builder.h"
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "net/websockets/websocket_frame.h"
+
+namespace {
+
+const char kHello[] = "Hello, world!";
+const uint64 kHelloLength = arraysize(kHello) - 1;
+
+struct ShortFrame {
+ const char* payload;
+ size_t payload_length;
+ const char* expected_output;
+ size_t expected_output_length;
+};
+static const ShortFrame kShortFrames[] = {
+ // Each output data is split into two string literals because C++ lexers
+ // consume unlimited number of hex characters in a hex character escape
+ // (e.g. "\x05F" is not treated as { '\x5', 'F', '\0' } but as
+ // { '\x5F', '\0' }).
+ { "First", 5, "\x81\x05" "First", 7 },
+ { "Second", 6, "\x81\x06" "Second", 8 },
+ { "Third", 5, "\x81\x05" "Third", 7 },
+ { "Fourth", 6, "\x81\x06" "Fourth", 8 },
+ { "Fifth", 5, "\x81\x05" "Fifth", 7 },
+ { "Sixth", 5, "\x81\x05" "Sixth", 7 },
+ { "Seventh", 7, "\x81\x07" "Seventh", 9 },
+ { "Eighth", 6, "\x81\x06" "Eighth", 8 },
+ { "Ninth", 5, "\x81\x05" "Ninth", 7 },
+ { "Tenth", 5, "\x81\x05" "Tenth", 7 }
+};
+static const int kNumShortFrames = arraysize(kShortFrames);
+
+scoped_ptr<net::WebSocketFrameChunk> CreateFrameChunkWithMessage(
+ const char* message,
+ size_t message_length) {
+ scoped_ptr<net::WebSocketFrameHeader> frame_header(
+ new net::WebSocketFrameHeader);
+ frame_header->final = true;
+ frame_header->reserved1 = false;
+ frame_header->reserved2 = false;
+ frame_header->reserved3 = false;
+ frame_header->opcode = net::WebSocketFrameHeader::kOpCodeText;
+ frame_header->masked = false;
+ frame_header->payload_length = message_length;
+
+ scoped_ptr<net::WebSocketFrameChunk> frame_chunk(
+ new net::WebSocketFrameChunk);
+ frame_chunk->header = frame_header.Pass();
+ frame_chunk->final_chunk = true;
+ frame_chunk->data.assign(message, message + message_length);
+ return frame_chunk.Pass();
+}
+
+ScopedVector<net::WebSocketFrameChunk> CreateChunksVectorWithSingleMessage(
+ const char* message,
+ size_t message_length) {
+ scoped_ptr<net::WebSocketFrameChunk> frame_chunk =
+ CreateFrameChunkWithMessage(message, message_length);
+ ScopedVector<net::WebSocketFrameChunk> frame_chunks;
+ frame_chunks.push_back(frame_chunk.release());
+ return frame_chunks.Pass();
+}
+
+void ExpectBuilderDiesOrFailsOnChunks(
+ ScopedVector<net::WebSocketFrameChunk> frame_chunks) {
+ // Note: EXPECT_DEBUG_DEATH does not work on Win32 accoring to comments in
+ // spdy_protocol_test.cc. We don't run the test in that case.
+#if !defined(WIN32) && defined(GTEST_HAS_DEATH_TEST)
+ net::WebSocketFrameBuilder builder;
+ std::vector<char> output;
+#if !defined(DCHECK_ALWAYS_ON)
+ EXPECT_DEBUG_DEATH({
+ EXPECT_FALSE(builder.Encode(frame_chunks.Pass(), &output));
+ EXPECT_TRUE(builder.failed());
+ }, "");
+#else
+ EXPECT_DEATH({
+ EXPECT_FALSE(builder.Encode(frame_chunks.Pass(), &output));
+ EXPECT_TRUE(builder.failed());
+ }, "");
+#endif
+#endif
+}
+
+} // Unnamed namespace.
+
+namespace net {
+
+TEST(WebSocketFrameBuilderTest, EncodeNormalFrame) {
+ static const char kHelloFrame[] = "\x81\x0DHello, world!";
+ static const uint64 kHelloFrameLength = arraysize(kHelloFrame) - 1;
+
+ ScopedVector<WebSocketFrameChunk> frame_chunks =
+ CreateChunksVectorWithSingleMessage(kHello, kHelloLength);
+
+ WebSocketFrameBuilder builder;
+ std::vector<char> output;
+ EXPECT_TRUE(builder.Encode(frame_chunks.Pass(), &output));
+ std::vector<char> expected_output(kHelloFrame,
+ kHelloFrame + kHelloFrameLength);
+ EXPECT_EQ(expected_output, output);
+ EXPECT_FALSE(builder.failed());
+}
+
+TEST(WebSocketFrameBuilderTest, EncodeMaskedFrame) {
+ static const size_t kMaskingKeyLength =
+ WebSocketFrameHeader::kMaskingKeyLength;
+ static const char kMaskingKey[] = "\xDE\xAD\xBE\xEF";
+ COMPILE_ASSERT(arraysize(kMaskingKey) - 1 == kMaskingKeyLength,
+ incorrect_masking_key_length);
+ static const char kMaskedHelloFrame[] =
+ "\x81\x8D\xDE\xAD\xBE\xEF"
+ "\x96\xC8\xD2\x83\xB1\x81\x9E\x98\xB1\xDF\xD2\x8B\xFF";
+ static const uint64 kMaskedHelloFrameLength =
+ arraysize(kMaskedHelloFrame) - 1;
+
+ ScopedVector<WebSocketFrameChunk> frame_chunks =
+ CreateChunksVectorWithSingleMessage(kHello, kHelloLength);
+ frame_chunks[0]->header->masked = true;
+
+ WebSocketFrameBuilder builder;
+ builder.PinMaskingKeyForTesting(kMaskingKey);
+ std::vector<char> output;
+ EXPECT_TRUE(builder.Encode(frame_chunks.Pass(), &output));
+ std::vector<char> expected_output(
+ kMaskedHelloFrame, kMaskedHelloFrame + kMaskedHelloFrameLength);
+ EXPECT_EQ(expected_output, output);
+ EXPECT_FALSE(builder.failed());
+}
+
+TEST(WebSocketFrameBuilderTest, EncodeMultipleFramesAtOnce) {
+ ScopedVector<WebSocketFrameChunk> frame_chunks;
+ std::vector<char> expected_output;
+ for (int i = 0; i < kNumShortFrames; ++i) {
+ scoped_ptr<WebSocketFrameChunk> frame_chunk = CreateFrameChunkWithMessage(
+ kShortFrames[i].payload, kShortFrames[i].payload_length);
+ frame_chunks.push_back(frame_chunk.release());
+ expected_output.insert(
+ expected_output.end(),
+ kShortFrames[i].expected_output,
+ kShortFrames[i].expected_output +
+ kShortFrames[i].expected_output_length);
+ }
+
+ WebSocketFrameBuilder builder;
+ std::vector<char> output;
+ EXPECT_TRUE(builder.Encode(frame_chunks.Pass(), &output));
+ EXPECT_EQ(expected_output, output);
+ EXPECT_FALSE(builder.failed());
+}
+
+TEST(WebSocketFrameBuilderTest, EncodeMultipleFramesSerially) {
+ WebSocketFrameBuilder builder;
+ for (int i = 0; i < kNumShortFrames; ++i) {
+ ScopedVector<WebSocketFrameChunk> frame_chunks =
+ CreateChunksVectorWithSingleMessage(kShortFrames[i].payload,
+ kShortFrames[i].payload_length);
+ std::vector<char> expected_output(
+ kShortFrames[i].expected_output,
+ kShortFrames[i].expected_output +
+ kShortFrames[i].expected_output_length);
+ std::vector<char> output;
+ EXPECT_TRUE(builder.Encode(frame_chunks.Pass(), &output));
+ EXPECT_EQ(expected_output, output);
+ EXPECT_FALSE(builder.failed());
+ }
+}
+
+TEST(WebSocketFrameBuilderTest, EncodeChunkedFrames) {
+ // Send two messages in three steps:
+ // 1. { message1[:cutting_pos1] }
+ // 2. { message1[cutting_pos1:], message2[:cutting_pos2] }
+ // 3. { message2[cutting_pos2:] }
+ // where a[x:y] is Python-style slice notation.
+ struct Message {
+ const char* payload;
+ size_t payload_length;
+ const char* expected_header;
+ size_t expected_header_length;
+ };
+ static const Message kMessage1 = { "Larry Page", 10, "\x81\x0A", 2 };
+ static const Message kMessage2 = { "Sergey Brin", 11, "\x81\x0B", 2 };
+
+ for (size_t cutting_pos1 = 0; cutting_pos1 <= kMessage1.payload_length;
+ ++cutting_pos1) {
+ for (size_t cutting_pos2 = 0; cutting_pos2 <= kMessage2.payload_length;
+ ++cutting_pos2) {
+ scoped_ptr<WebSocketFrameHeader> header1(new WebSocketFrameHeader);
+ header1->final = true;
+ header1->reserved1 = false;
+ header1->reserved2 = false;
+ header1->reserved3 = false;
+ header1->opcode = WebSocketFrameHeader::kOpCodeText;
+ header1->masked = false;
+ header1->payload_length = kMessage1.payload_length;
+
+ scoped_ptr<WebSocketFrameHeader> header2(new WebSocketFrameHeader);
+ header2->final = true;
+ header2->reserved1 = false;
+ header2->reserved2 = false;
+ header2->reserved3 = false;
+ header2->opcode = WebSocketFrameHeader::kOpCodeText;
+ header2->masked = false;
+ header2->payload_length = kMessage2.payload_length;
+
+ scoped_ptr<WebSocketFrameChunk> chunk11(new WebSocketFrameChunk);
+ chunk11->header = header1.Pass();
+ chunk11->final_chunk = false;
+ chunk11->data.assign(kMessage1.payload, kMessage1.payload + cutting_pos1);
+
+ scoped_ptr<WebSocketFrameChunk> chunk12(new WebSocketFrameChunk);
+ chunk12->final_chunk = true;
+ chunk12->data.assign(kMessage1.payload + cutting_pos1,
+ kMessage1.payload + kMessage1.payload_length);
+
+ scoped_ptr<WebSocketFrameChunk> chunk21(new WebSocketFrameChunk);
+ chunk21->header = header2.Pass();
+ chunk21->final_chunk = false;
+ chunk21->data.assign(kMessage2.payload, kMessage2.payload + cutting_pos2);
+
+ scoped_ptr<WebSocketFrameChunk> chunk22(new WebSocketFrameChunk);
+ chunk22->final_chunk = true;
+ chunk22->data.assign(kMessage2.payload + cutting_pos2,
+ kMessage2.payload + kMessage2.payload_length);
+
+ WebSocketFrameBuilder builder;
+
+ // Step 1: Encode chunk11.
+ std::vector<char> expected_output1;
+ expected_output1.insert(
+ expected_output1.end(),
+ kMessage1.expected_header,
+ kMessage1.expected_header + kMessage1.expected_header_length);
+ expected_output1.insert(
+ expected_output1.end(),
+ kMessage1.payload,
+ kMessage1.payload + cutting_pos1);
+
+ ScopedVector<WebSocketFrameChunk> chunks1;
+ chunks1.push_back(chunk11.release());
+ std::vector<char> output1;
+ EXPECT_TRUE(builder.Encode(chunks1.Pass(), &output1));
+ EXPECT_EQ(expected_output1, output1);
+ EXPECT_FALSE(builder.failed());
+
+ // Step 2: Encode chunk12 and chunk 21.
+ std::vector<char> expected_output2;
+ expected_output2.insert(
+ expected_output2.end(),
+ kMessage1.payload + cutting_pos1,
+ kMessage1.payload + kMessage1.payload_length);
+ expected_output2.insert(
+ expected_output2.end(),
+ kMessage2.expected_header,
+ kMessage2.expected_header + kMessage2.expected_header_length);
+ expected_output2.insert(
+ expected_output2.end(),
+ kMessage2.payload,
+ kMessage2.payload + cutting_pos2);
+
+ ScopedVector<WebSocketFrameChunk> chunks2;
+ chunks2.push_back(chunk12.release());
+ chunks2.push_back(chunk21.release());
+ std::vector<char> output2;
+ EXPECT_TRUE(builder.Encode(chunks2.Pass(), &output2));
+ EXPECT_EQ(expected_output2, output2);
+ EXPECT_FALSE(builder.failed());
+
+ // Step 3: Encode chunk22.
+ std::vector<char> expected_output3(
+ kMessage2.payload + cutting_pos2,
+ kMessage2.payload + kMessage2.payload_length);
+
+ ScopedVector<WebSocketFrameChunk> chunks3;
+ chunks3.push_back(chunk22.release());
+ std::vector<char> output3;
+ EXPECT_TRUE(builder.Encode(chunks3.Pass(), &output3));
+ EXPECT_EQ(expected_output3, output3);
+ EXPECT_FALSE(builder.failed());
+
+ // If we have found any test failure, let's exit the test early
+ // to avoid excessive console output.
+ if (HasFailure()) {
+ FAIL() << "Failed: cutting_pos1 = " << cutting_pos1 << ", "
+ << "cutting_pos2 = " << cutting_pos2;
+ return;
+ }
+ }
+ }
+}
+
+TEST(WebSocketFrameBuilderTest, EncodeChunkedMaskedFrames) {
+ // Same as above, but this time we mask frame payloads.
+ struct Message {
+ const char* masking_key;
+ const char* payload;
+ const char* masked_payload;
+ size_t payload_length;
+ const char* expected_header;
+ size_t expected_header_length;
+ };
+
+ static const Message kMessage1 = {
+ "\xDE\xAD\xBE\xEF",
+ "Larry Page", "\x92\xCC\xCC\x9D\xA7\x8D\xEE\x8E\xB9\xC8", 10,
+ "\x81\x8A\xDE\xAD\xBE\xEF", 6
+ };
+ static const Message kMessage2 = {
+ "\xBA\xAD\xCA\xFE",
+ "Sergey Brin", "\xE9\xC8\xB8\x99\xDF\xD4\xEA\xBC\xC8\xC4\xA4", 11,
+ "\x81\x8B\xBA\xAD\xCA\xFE", 6
+ };
+
+ for (size_t cutting_pos1 = 0; cutting_pos1 < kMessage1.payload_length;
+ ++cutting_pos1) {
+ for (size_t cutting_pos2 = 0; cutting_pos2 < kMessage2.payload_length;
+ ++cutting_pos2) {
+ scoped_ptr<WebSocketFrameHeader> header1(new WebSocketFrameHeader);
+ header1->final = true;
+ header1->reserved1 = false;
+ header1->reserved2 = false;
+ header1->reserved3 = false;
+ header1->opcode = WebSocketFrameHeader::kOpCodeText;
+ header1->masked = true;
+ header1->payload_length = kMessage1.payload_length;
+
+ scoped_ptr<WebSocketFrameHeader> header2(new WebSocketFrameHeader);
+ header2->final = true;
+ header2->reserved1 = false;
+ header2->reserved2 = false;
+ header2->reserved3 = false;
+ header2->opcode = WebSocketFrameHeader::kOpCodeText;
+ header2->masked = true;
+ header2->payload_length = kMessage2.payload_length;
+
+ scoped_ptr<WebSocketFrameChunk> chunk11(new WebSocketFrameChunk);
+ chunk11->header = header1.Pass();
+ chunk11->final_chunk = false;
+ chunk11->data.assign(kMessage1.payload, kMessage1.payload + cutting_pos1);
+
+ scoped_ptr<WebSocketFrameChunk> chunk12(new WebSocketFrameChunk);
+ chunk12->final_chunk = true;
+ chunk12->data.assign(kMessage1.payload + cutting_pos1,
+ kMessage1.payload + kMessage1.payload_length);
+
+ scoped_ptr<WebSocketFrameChunk> chunk21(new WebSocketFrameChunk);
+ chunk21->header = header2.Pass();
+ chunk21->final_chunk = false;
+ chunk21->data.assign(kMessage2.payload, kMessage2.payload + cutting_pos2);
+
+ scoped_ptr<WebSocketFrameChunk> chunk22(new WebSocketFrameChunk);
+ chunk22->final_chunk = true;
+ chunk22->data.assign(kMessage2.payload + cutting_pos2,
+ kMessage2.payload + kMessage2.payload_length);
+
+ WebSocketFrameBuilder builder;
+
+ // Step 1: Encode chunk11.
+ std::vector<char> expected_output1;
+ expected_output1.insert(
+ expected_output1.end(),
+ kMessage1.expected_header,
+ kMessage1.expected_header + kMessage1.expected_header_length);
+ expected_output1.insert(
+ expected_output1.end(),
+ kMessage1.masked_payload,
+ kMessage1.masked_payload + cutting_pos1);
+
+ ScopedVector<WebSocketFrameChunk> chunks1;
+ chunks1.push_back(chunk11.release());
+ builder.PinMaskingKeyForTesting(kMessage1.masking_key);
+ std::vector<char> output1;
+ EXPECT_TRUE(builder.Encode(chunks1.Pass(), &output1));
+ EXPECT_EQ(expected_output1, output1);
+ EXPECT_FALSE(builder.failed());
+
+ // Step 2: Encode chunk12 and chunk 21.
+ std::vector<char> expected_output2;
+ expected_output2.insert(
+ expected_output2.end(),
+ kMessage1.masked_payload + cutting_pos1,
+ kMessage1.masked_payload + kMessage1.payload_length);
+ expected_output2.insert(
+ expected_output2.end(),
+ kMessage2.expected_header,
+ kMessage2.expected_header + kMessage2.expected_header_length);
+ expected_output2.insert(
+ expected_output2.end(),
+ kMessage2.masked_payload,
+ kMessage2.masked_payload + cutting_pos2);
+
+ ScopedVector<WebSocketFrameChunk> chunks2;
+ chunks2.push_back(chunk12.release());
+ chunks2.push_back(chunk21.release());
+ builder.PinMaskingKeyForTesting(kMessage2.masking_key);
+ std::vector<char> output2;
+ EXPECT_TRUE(builder.Encode(chunks2.Pass(), &output2));
+ EXPECT_EQ(expected_output2, output2);
+ EXPECT_FALSE(builder.failed());
+
+ // Step 3: Encode chunk22.
+ std::vector<char> expected_output3(
+ kMessage2.masked_payload + cutting_pos2,
+ kMessage2.masked_payload + kMessage2.payload_length);
+
+ ScopedVector<WebSocketFrameChunk> chunks3;
+ chunks3.push_back(chunk22.release());
+ std::vector<char> output3;
+ EXPECT_TRUE(builder.Encode(chunks3.Pass(), &output3));
+ EXPECT_EQ(expected_output3, output3);
+ EXPECT_FALSE(builder.failed());
+
+ // If we have found any test failure, let's exit the test early
+ // to avoid excessive console output.
+ if (HasFailure()) {
+ FAIL() << "Failed: cutting_pos1 = " << cutting_pos1 << ", "
+ << "cutting_pos2 = " << cutting_pos2;
+ return;
+ }
+ }
+ }
+}
+
+TEST(WebSocketFrameBuilderTest, FrameHeadersOfVariousLengths) {
+ struct TestCase {
+ const char* frame_header;
+ size_t frame_header_length;
+ uint64 frame_length;
+ };
+ static const TestCase kTests[] = {
+ { "\x81\x00", 2, GG_UINT64_C(0) },
+ { "\x81\x7D", 2, GG_UINT64_C(125) },
+ { "\x81\x7E\x00\x7E", 4, GG_UINT64_C(126) },
+ { "\x81\x7E\xFF\xFF", 4, GG_UINT64_C(0xFFFF) },
+ { "\x81\x7F\x00\x00\x00\x00\x00\x01\x00\x00", 10, GG_UINT64_C(0x10000) },
+ { "\x81\x7F\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 10,
+ GG_UINT64_C(0x7FFFFFFFFFFFFFFF) }
+ };
+ static const size_t kNumTests = ARRAYSIZE_UNSAFE(kTests);
+
+ for (size_t i = 0; i < kNumTests; ++i) {
+ scoped_ptr<WebSocketFrameHeader> header(new WebSocketFrameHeader);
+ header->final = true;
+ header->reserved1 = false;
+ header->reserved2 = false;
+ header->reserved3 = false;
+ header->opcode = WebSocketFrameHeader::kOpCodeText;
+ header->masked = false;
+ header->payload_length = kTests[i].frame_length;
+
+ scoped_ptr<WebSocketFrameChunk> chunk(new WebSocketFrameChunk);
+ chunk->header = header.Pass();
+ chunk->final_chunk = false; // Let the chunk carry no data.
+
+ ScopedVector<WebSocketFrameChunk> chunks;
+ chunks.push_back(chunk.release());
+
+ std::vector<char> expected_output(
+ kTests[i].frame_header,
+ kTests[i].frame_header + kTests[i].frame_header_length);
+
+ WebSocketFrameBuilder builder;
+ std::vector<char> output;
+ EXPECT_TRUE(builder.Encode(chunks.Pass(), &output));
+ EXPECT_EQ(expected_output, output);
+ EXPECT_FALSE(builder.failed());
+ }
+}
+
+TEST(WebSocketFrameBuilderTest, EncodeTooLargeFrame) {
+ scoped_ptr<WebSocketFrameHeader> header(new WebSocketFrameHeader);
+ header->final = true;
+ header->reserved1 = false;
+ header->reserved2 = false;
+ header->reserved3 = false;
+ header->opcode = WebSocketFrameHeader::kOpCodeText;
+ header->masked = false;
+ header->payload_length = GG_UINT64_C(0x8000000000000000);
+
+ scoped_ptr<WebSocketFrameChunk> chunk(new WebSocketFrameChunk);
+ chunk->header = header.Pass();
+ chunk->final_chunk = false;
+
+ ScopedVector<WebSocketFrameChunk> chunks;
+ chunks.push_back(chunk.release());
+
+ WebSocketFrameBuilder builder;
+ std::vector<char> output;
+ EXPECT_FALSE(builder.Encode(chunks.Pass(), &output));
+ EXPECT_TRUE(builder.failed());
+
+ // Once the builder has failed, it won't accept any more chunks.
+ chunks = CreateChunksVectorWithSingleMessage("Hello!", 6);
+ EXPECT_FALSE(builder.Encode(chunks.Pass(), &output));
+ EXPECT_TRUE(builder.failed());
+}
+
+TEST(WebSocketFrameBuilderTest, FrameTypes) {
+ struct TestCase {
+ const char* frame_header;
+ size_t frame_header_length;
+ WebSocketFrameHeader::OpCode opcode;
+ };
+ static const TestCase kTests[] = {
+ { "\x80\x00", 2, WebSocketFrameHeader::kOpCodeContinuation },
+ { "\x81\x00", 2, WebSocketFrameHeader::kOpCodeText },
+ { "\x82\x00", 2, WebSocketFrameHeader::kOpCodeBinary },
+ { "\x88\x00", 2, WebSocketFrameHeader::kOpCodeClose },
+ { "\x89\x00", 2, WebSocketFrameHeader::kOpCodePing },
+ { "\x8A\x00", 2, WebSocketFrameHeader::kOpCodePong },
+ // These are undefined opcodes, but the builder should accept them anyway.
+ { "\x83\x00", 2, 0x3 },
+ { "\x84\x00", 2, 0x4 },
+ { "\x85\x00", 2, 0x5 },
+ { "\x86\x00", 2, 0x6 },
+ { "\x87\x00", 2, 0x7 },
+ { "\x8B\x00", 2, 0xB },
+ { "\x8C\x00", 2, 0xC },
+ { "\x8D\x00", 2, 0xD },
+ { "\x8E\x00", 2, 0xE },
+ { "\x8F\x00", 2, 0xF }
+ };
+ static const size_t kNumTests = ARRAYSIZE_UNSAFE(kTests);
+
+ WebSocketFrameBuilder builder;
+
+ for (size_t i = 0; i < kNumTests; ++i) {
+ scoped_ptr<WebSocketFrameHeader> header(new WebSocketFrameHeader);
+ header->final = true;
+ header->reserved1 = false;
+ header->reserved2 = false;
+ header->reserved3 = false;
+ header->opcode = kTests[i].opcode;
+ header->masked = false;
+ header->payload_length = 0;
+
+ scoped_ptr<WebSocketFrameChunk> chunk(new WebSocketFrameChunk);
+ chunk->header = header.Pass();
+ chunk->final_chunk = true;
+ // chunk->data is empty.
+
+ ScopedVector<WebSocketFrameChunk> chunks;
+ chunks.push_back(chunk.release());
+
+ std::vector<char> expected_output(
+ kTests[i].frame_header,
+ kTests[i].frame_header + kTests[i].frame_header_length);
+ std::vector<char> output;
+ EXPECT_TRUE(builder.Encode(chunks.Pass(), &output));
+ EXPECT_EQ(expected_output, output);
+ EXPECT_FALSE(builder.failed());
+ }
+}
+
+TEST(WebSocketFrameBuilderTest, FinalBitAndReservedBits) {
+ struct TestCase {
+ const char* frame_header;
+ size_t frame_header_length;
+ bool final;
+ bool reserved1;
+ bool reserved2;
+ bool reserved3;
+ };
+ static const TestCase kTests[] = {
+ { "\x81\x00", 2, true, false, false, false },
+ { "\x01\x00", 2, false, false, false, false },
+ { "\xC1\x00", 2, true, true, false, false },
+ { "\xA1\x00", 2, true, false, true, false },
+ { "\x91\x00", 2, true, false, false, true },
+ { "\x71\x00", 2, false, true, true, true },
+ { "\xF1\x00", 2, true, true, true, true }
+ };
+ static const size_t kNumTests = ARRAYSIZE_UNSAFE(kTests);
+
+ WebSocketFrameBuilder builder;
+
+ for (size_t i = 0; i < kNumTests; ++i) {
+ scoped_ptr<WebSocketFrameHeader> header(new WebSocketFrameHeader);
+ header->final = kTests[i].final;
+ header->reserved1 = kTests[i].reserved1;
+ header->reserved2 = kTests[i].reserved2;
+ header->reserved3 = kTests[i].reserved3;
+ header->opcode = WebSocketFrameHeader::kOpCodeText;
+ header->masked = false;
+ header->payload_length = 0;
+
+ scoped_ptr<WebSocketFrameChunk> chunk(new WebSocketFrameChunk);
+ chunk->header = header.Pass();
+ chunk->final_chunk = true;
+ // chunk->data is empty.
+
+ ScopedVector<WebSocketFrameChunk> chunks;
+ chunks.push_back(chunk.release());
+
+ std::vector<char> expected_output(
+ kTests[i].frame_header,
+ kTests[i].frame_header + kTests[i].frame_header_length);
+ std::vector<char> output;
+ EXPECT_TRUE(builder.Encode(chunks.Pass(), &output));
+ EXPECT_EQ(expected_output, output);
+ EXPECT_FALSE(builder.failed());
+ }
+}
+
+TEST(WebSocketFrameBuilderDeathTest, NewChunkAfterUnfinishedChunk) {
+ scoped_ptr<WebSocketFrameChunk> chunk1 =
+ CreateFrameChunkWithMessage("Hello", 5);
+ chunk1->final_chunk = false;
+ scoped_ptr<WebSocketFrameChunk> chunk2 =
+ CreateFrameChunkWithMessage("World", 5);
+
+ ScopedVector<WebSocketFrameChunk> chunks;
+ chunks.push_back(chunk1.release());
+ chunks.push_back(chunk2.release());
+
+ ExpectBuilderDiesOrFailsOnChunks(chunks.Pass());
+}
+
+TEST(WebSocketFrameBuilderDeathTest, NoHeaderInFirstChunk) {
+ scoped_ptr<WebSocketFrameChunk> chunk(new WebSocketFrameChunk);
+ chunk->final_chunk = true;
+
+ ScopedVector<WebSocketFrameChunk> chunks;
+ chunks.push_back(chunk.release());
+
+ ExpectBuilderDiesOrFailsOnChunks(chunks.Pass());
+}
+
+TEST(WebSocketFrameBuilderDeathTest, InsufficientPayloadData) {
+ scoped_ptr<WebSocketFrameChunk> chunk =
+ CreateFrameChunkWithMessage("Hello", 5);
+ chunk->data.erase(chunk->data.end() - 1);
+
+ ScopedVector<WebSocketFrameChunk> chunks;
+ chunks.push_back(chunk.release());
+
+ ExpectBuilderDiesOrFailsOnChunks(chunks.Pass());
+}
+
+TEST(WebSocketFrameBuilderDeathTest, ExcessivePayloadData) {
+ scoped_ptr<WebSocketFrameChunk> chunk =
+ CreateFrameChunkWithMessage("Hello", 5);
+ chunk->data.push_back('!');
+ chunk->final_chunk = false;
+
+ ScopedVector<WebSocketFrameChunk> chunks;
+ chunks.push_back(chunk.release());
+
+ ExpectBuilderDiesOrFailsOnChunks(chunks.Pass());
+}
+
+} // namespace net
« net/websockets/websocket_frame_builder.cc ('K') | « net/websockets/websocket_frame_builder.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698