OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "net/websockets/websocket_frame.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/basictypes.h" |
| 10 #include "net/base/net_errors.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" |
| 12 |
| 13 namespace net { |
| 14 |
| 15 TEST(WebSocketFrameHeaderTest, FrameLengths) { |
| 16 struct TestCase { |
| 17 const char* frame_header; |
| 18 size_t frame_header_length; |
| 19 uint64 frame_length; |
| 20 }; |
| 21 static const TestCase kTests[] = { |
| 22 { "\x81\x00", 2, GG_UINT64_C(0) }, |
| 23 { "\x81\x7D", 2, GG_UINT64_C(125) }, |
| 24 { "\x81\x7E\x00\x7E", 4, GG_UINT64_C(126) }, |
| 25 { "\x81\x7E\xFF\xFF", 4, GG_UINT64_C(0xFFFF) }, |
| 26 { "\x81\x7F\x00\x00\x00\x00\x00\x01\x00\x00", 10, GG_UINT64_C(0x10000) }, |
| 27 { "\x81\x7F\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 10, |
| 28 GG_UINT64_C(0x7FFFFFFFFFFFFFFF) } |
| 29 }; |
| 30 static const int kNumTests = ARRAYSIZE_UNSAFE(kTests); |
| 31 |
| 32 for (int i = 0; i < kNumTests; ++i) { |
| 33 WebSocketFrameHeader header; |
| 34 header.final = true; |
| 35 header.reserved1 = false; |
| 36 header.reserved2 = false; |
| 37 header.reserved3 = false; |
| 38 header.opcode = WebSocketFrameHeader::kOpCodeText; |
| 39 header.masked = false; |
| 40 header.payload_length = kTests[i].frame_length; |
| 41 |
| 42 std::vector<char> expected_output( |
| 43 kTests[i].frame_header, |
| 44 kTests[i].frame_header + kTests[i].frame_header_length); |
| 45 std::vector<char> output(expected_output.size()); |
| 46 EXPECT_EQ(static_cast<int>(expected_output.size()), |
| 47 WriteWebSocketFrameHeader(header, NULL, &output.front(), |
| 48 output.size())); |
| 49 EXPECT_EQ(expected_output, output); |
| 50 } |
| 51 } |
| 52 |
| 53 TEST(WebSocketFrameHeaderTest, FrameLengthsWithMasking) { |
| 54 static const char kMaskingKey[] = "\xDE\xAD\xBE\xEF"; |
| 55 COMPILE_ASSERT(ARRAYSIZE_UNSAFE(kMaskingKey) - 1 == |
| 56 WebSocketFrameHeader::kMaskingKeyLength, |
| 57 incorrect_masking_key_size); |
| 58 |
| 59 struct TestCase { |
| 60 const char* frame_header; |
| 61 size_t frame_header_length; |
| 62 uint64 frame_length; |
| 63 }; |
| 64 static const TestCase kTests[] = { |
| 65 { "\x81\x80\xDE\xAD\xBE\xEF", 6, GG_UINT64_C(0) }, |
| 66 { "\x81\xFD\xDE\xAD\xBE\xEF", 6, GG_UINT64_C(125) }, |
| 67 { "\x81\xFE\x00\x7E\xDE\xAD\xBE\xEF", 8, GG_UINT64_C(126) }, |
| 68 { "\x81\xFE\xFF\xFF\xDE\xAD\xBE\xEF", 8, GG_UINT64_C(0xFFFF) }, |
| 69 { "\x81\xFF\x00\x00\x00\x00\x00\x01\x00\x00\xDE\xAD\xBE\xEF", 14, |
| 70 GG_UINT64_C(0x10000) }, |
| 71 { "\x81\xFF\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xDE\xAD\xBE\xEF", 14, |
| 72 GG_UINT64_C(0x7FFFFFFFFFFFFFFF) } |
| 73 }; |
| 74 static const int kNumTests = ARRAYSIZE_UNSAFE(kTests); |
| 75 |
| 76 WebSocketMaskingKey masking_key; |
| 77 std::copy(kMaskingKey, kMaskingKey + WebSocketFrameHeader::kMaskingKeyLength, |
| 78 masking_key.key); |
| 79 |
| 80 for (int i = 0; i < kNumTests; ++i) { |
| 81 WebSocketFrameHeader header; |
| 82 header.final = true; |
| 83 header.reserved1 = false; |
| 84 header.reserved2 = false; |
| 85 header.reserved3 = false; |
| 86 header.opcode = WebSocketFrameHeader::kOpCodeText; |
| 87 header.masked = true; |
| 88 header.payload_length = kTests[i].frame_length; |
| 89 |
| 90 std::vector<char> expected_output( |
| 91 kTests[i].frame_header, |
| 92 kTests[i].frame_header + kTests[i].frame_header_length); |
| 93 std::vector<char> output(expected_output.size()); |
| 94 EXPECT_EQ(static_cast<int>(expected_output.size()), |
| 95 WriteWebSocketFrameHeader(header, &masking_key, |
| 96 &output.front(), output.size())); |
| 97 EXPECT_EQ(expected_output, output); |
| 98 } |
| 99 } |
| 100 |
| 101 TEST(WebSocketFrameHeaderTest, FrameOpCodes) { |
| 102 struct TestCase { |
| 103 const char* frame_header; |
| 104 size_t frame_header_length; |
| 105 WebSocketFrameHeader::OpCode opcode; |
| 106 }; |
| 107 static const TestCase kTests[] = { |
| 108 { "\x80\x00", 2, WebSocketFrameHeader::kOpCodeContinuation }, |
| 109 { "\x81\x00", 2, WebSocketFrameHeader::kOpCodeText }, |
| 110 { "\x82\x00", 2, WebSocketFrameHeader::kOpCodeBinary }, |
| 111 { "\x88\x00", 2, WebSocketFrameHeader::kOpCodeClose }, |
| 112 { "\x89\x00", 2, WebSocketFrameHeader::kOpCodePing }, |
| 113 { "\x8A\x00", 2, WebSocketFrameHeader::kOpCodePong }, |
| 114 // These are undefined opcodes, but the builder should accept them anyway. |
| 115 { "\x83\x00", 2, 0x3 }, |
| 116 { "\x84\x00", 2, 0x4 }, |
| 117 { "\x85\x00", 2, 0x5 }, |
| 118 { "\x86\x00", 2, 0x6 }, |
| 119 { "\x87\x00", 2, 0x7 }, |
| 120 { "\x8B\x00", 2, 0xB }, |
| 121 { "\x8C\x00", 2, 0xC }, |
| 122 { "\x8D\x00", 2, 0xD }, |
| 123 { "\x8E\x00", 2, 0xE }, |
| 124 { "\x8F\x00", 2, 0xF } |
| 125 }; |
| 126 static const int kNumTests = ARRAYSIZE_UNSAFE(kTests); |
| 127 |
| 128 for (int i = 0; i < kNumTests; ++i) { |
| 129 WebSocketFrameHeader header; |
| 130 header.final = true; |
| 131 header.reserved1 = false; |
| 132 header.reserved2 = false; |
| 133 header.reserved3 = false; |
| 134 header.opcode = kTests[i].opcode; |
| 135 header.masked = false; |
| 136 header.payload_length = 0; |
| 137 |
| 138 std::vector<char> expected_output( |
| 139 kTests[i].frame_header, |
| 140 kTests[i].frame_header + kTests[i].frame_header_length); |
| 141 std::vector<char> output(expected_output.size()); |
| 142 EXPECT_EQ(static_cast<int>(expected_output.size()), |
| 143 WriteWebSocketFrameHeader(header, NULL, |
| 144 &output.front(), output.size())); |
| 145 EXPECT_EQ(expected_output, output); |
| 146 } |
| 147 } |
| 148 |
| 149 TEST(WebSocketFrameHeaderTest, FinalBitAndReservedBits) { |
| 150 struct TestCase { |
| 151 const char* frame_header; |
| 152 size_t frame_header_length; |
| 153 bool final; |
| 154 bool reserved1; |
| 155 bool reserved2; |
| 156 bool reserved3; |
| 157 }; |
| 158 static const TestCase kTests[] = { |
| 159 { "\x81\x00", 2, true, false, false, false }, |
| 160 { "\x01\x00", 2, false, false, false, false }, |
| 161 { "\xC1\x00", 2, true, true, false, false }, |
| 162 { "\xA1\x00", 2, true, false, true, false }, |
| 163 { "\x91\x00", 2, true, false, false, true }, |
| 164 { "\x71\x00", 2, false, true, true, true }, |
| 165 { "\xF1\x00", 2, true, true, true, true } |
| 166 }; |
| 167 static const int kNumTests = ARRAYSIZE_UNSAFE(kTests); |
| 168 |
| 169 for (int i = 0; i < kNumTests; ++i) { |
| 170 WebSocketFrameHeader header; |
| 171 header.final = kTests[i].final; |
| 172 header.reserved1 = kTests[i].reserved1; |
| 173 header.reserved2 = kTests[i].reserved2; |
| 174 header.reserved3 = kTests[i].reserved3; |
| 175 header.opcode = WebSocketFrameHeader::kOpCodeText; |
| 176 header.masked = false; |
| 177 header.payload_length = 0; |
| 178 |
| 179 std::vector<char> expected_output( |
| 180 kTests[i].frame_header, |
| 181 kTests[i].frame_header + kTests[i].frame_header_length); |
| 182 std::vector<char> output(expected_output.size()); |
| 183 EXPECT_EQ(static_cast<int>(expected_output.size()), |
| 184 WriteWebSocketFrameHeader(header, NULL, |
| 185 &output.front(), output.size())); |
| 186 EXPECT_EQ(expected_output, output); |
| 187 } |
| 188 } |
| 189 |
| 190 TEST(WebSocketFrameHeaderTest, InsufficientBufferSize) { |
| 191 struct TestCase { |
| 192 uint64 payload_length; |
| 193 bool masked; |
| 194 size_t expected_header_size; |
| 195 }; |
| 196 static const TestCase kTests[] = { |
| 197 { GG_UINT64_C(0), false, 2u }, |
| 198 { GG_UINT64_C(125), false, 2u }, |
| 199 { GG_UINT64_C(126), false, 4u }, |
| 200 { GG_UINT64_C(0xFFFF), false, 4u }, |
| 201 { GG_UINT64_C(0x10000), false, 10u }, |
| 202 { GG_UINT64_C(0x7FFFFFFFFFFFFFFF), false, 10u }, |
| 203 { GG_UINT64_C(0), true, 6u }, |
| 204 { GG_UINT64_C(125), true, 6u }, |
| 205 { GG_UINT64_C(126), true, 8u }, |
| 206 { GG_UINT64_C(0xFFFF), true, 8u }, |
| 207 { GG_UINT64_C(0x10000), true, 14u }, |
| 208 { GG_UINT64_C(0x7FFFFFFFFFFFFFFF), true, 14u } |
| 209 }; |
| 210 static const int kNumTests = ARRAYSIZE_UNSAFE(kTests); |
| 211 |
| 212 for (int i = 0; i < kNumTests; ++i) { |
| 213 WebSocketFrameHeader header; |
| 214 header.final = true; |
| 215 header.reserved1 = false; |
| 216 header.reserved2 = false; |
| 217 header.reserved3 = false; |
| 218 header.opcode = WebSocketFrameHeader::kOpCodeText; |
| 219 header.masked = kTests[i].masked; |
| 220 header.payload_length = kTests[i].payload_length; |
| 221 |
| 222 char dummy_buffer[14]; |
| 223 // Set an insufficient size to |buffer_size|. |
| 224 EXPECT_EQ(ERR_INVALID_ARGUMENT, |
| 225 WriteWebSocketFrameHeader(header, NULL, dummy_buffer, |
| 226 kTests[i].expected_header_size - 1)); |
| 227 } |
| 228 } |
| 229 |
| 230 TEST(WebSocketFrameTest, MaskPayload) { |
| 231 struct TestCase { |
| 232 const char* masking_key; |
| 233 uint64 frame_offset; |
| 234 const char* input; |
| 235 const char* output; |
| 236 size_t data_length; |
| 237 }; |
| 238 static const TestCase kTests[] = { |
| 239 { "\xDE\xAD\xBE\xEF", 0, "FooBar", "\x98\xC2\xD1\xAD\xBF\xDF", 6 }, |
| 240 { "\xDE\xAD\xBE\xEF", 1, "FooBar", "\xEB\xD1\x80\x9C\xCC\xCC", 6 }, |
| 241 { "\xDE\xAD\xBE\xEF", 2, "FooBar", "\xF8\x80\xB1\xEF\xDF\x9D", 6 }, |
| 242 { "\xDE\xAD\xBE\xEF", 3, "FooBar", "\xA9\xB1\xC2\xFC\x8E\xAC", 6 }, |
| 243 { "\xDE\xAD\xBE\xEF", 4, "FooBar", "\x98\xC2\xD1\xAD\xBF\xDF", 6 }, |
| 244 { "\xDE\xAD\xBE\xEF", 42, "FooBar", "\xF8\x80\xB1\xEF\xDF\x9D", 6 }, |
| 245 { "\xDE\xAD\xBE\xEF", 0, "", "", 0 }, |
| 246 { "\xDE\xAD\xBE\xEF", 0, "\xDE\xAD\xBE\xEF", "\x00\x00\x00\x00", 4 }, |
| 247 { "\xDE\xAD\xBE\xEF", 0, "\x00\x00\x00\x00", "\xDE\xAD\xBE\xEF", 4 }, |
| 248 { "\x00\x00\x00\x00", 0, "FooBar", "FooBar", 6 }, |
| 249 { "\xFF\xFF\xFF\xFF", 0, "FooBar", "\xB9\x90\x90\xBD\x9E\x8D", 6 }, |
| 250 }; |
| 251 static const int kNumTests = ARRAYSIZE_UNSAFE(kTests); |
| 252 |
| 253 for (int i = 0; i < kNumTests; ++i) { |
| 254 WebSocketMaskingKey masking_key; |
| 255 std::copy(kTests[i].masking_key, |
| 256 kTests[i].masking_key + WebSocketFrameHeader::kMaskingKeyLength, |
| 257 masking_key.key); |
| 258 std::vector<char> frame_data(kTests[i].input, |
| 259 kTests[i].input + kTests[i].data_length); |
| 260 std::vector<char> expected_output(kTests[i].output, |
| 261 kTests[i].output + kTests[i].data_length); |
| 262 MaskWebSocketFramePayload(masking_key, |
| 263 kTests[i].frame_offset, |
| 264 frame_data.empty() ? NULL : &frame_data.front(), |
| 265 frame_data.size()); |
| 266 EXPECT_EQ(expected_output, frame_data); |
| 267 } |
| 268 } |
| 269 |
| 270 } // namespace net |
OLD | NEW |