websocket_frame_test.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. // Copyright 2013 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. #include "net/websockets/websocket_frame.h"
  5. #include <stdint.h>
  6. #include <algorithm>
  7. #include <vector>
  8. #include "base/memory/aligned_memory.h"
  9. #include "net/base/net_errors.h"
  10. #include "testing/gtest/include/gtest/gtest.h"
  11. namespace net {
  12. namespace {
  13. TEST(WebSocketFrameHeaderTest, FrameLengths) {
  14. struct TestCase {
  15. const char* frame_header;
  16. size_t frame_header_length;
  17. uint64_t frame_length;
  18. };
  19. static const TestCase kTests[] = {
  20. {"\x81\x00", 2, UINT64_C(0)},
  21. {"\x81\x7D", 2, UINT64_C(125)},
  22. {"\x81\x7E\x00\x7E", 4, UINT64_C(126)},
  23. {"\x81\x7E\xFF\xFF", 4, UINT64_C(0xFFFF)},
  24. {"\x81\x7F\x00\x00\x00\x00\x00\x01\x00\x00", 10, UINT64_C(0x10000)},
  25. {"\x81\x7F\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 10,
  26. UINT64_C(0x7FFFFFFFFFFFFFFF)}};
  27. for (const auto& test : kTests) {
  28. WebSocketFrameHeader header(WebSocketFrameHeader::kOpCodeText);
  29. header.final = true;
  30. header.payload_length = test.frame_length;
  31. std::vector<char> expected_output(
  32. test.frame_header, test.frame_header + test.frame_header_length);
  33. std::vector<char> output(expected_output.size());
  34. EXPECT_EQ(static_cast<int>(expected_output.size()),
  35. WriteWebSocketFrameHeader(header, nullptr, output.data(),
  36. output.size()));
  37. EXPECT_EQ(expected_output, output);
  38. }
  39. }
  40. TEST(WebSocketFrameHeaderTest, FrameLengthsWithMasking) {
  41. static const char kMaskingKey[] = "\xDE\xAD\xBE\xEF";
  42. static_assert(
  43. std::size(kMaskingKey) - 1 == WebSocketFrameHeader::kMaskingKeyLength,
  44. "incorrect masking key size");
  45. struct TestCase {
  46. const char* frame_header;
  47. size_t frame_header_length;
  48. uint64_t frame_length;
  49. };
  50. static const TestCase kTests[] = {
  51. {"\x81\x80\xDE\xAD\xBE\xEF", 6, UINT64_C(0)},
  52. {"\x81\xFD\xDE\xAD\xBE\xEF", 6, UINT64_C(125)},
  53. {"\x81\xFE\x00\x7E\xDE\xAD\xBE\xEF", 8, UINT64_C(126)},
  54. {"\x81\xFE\xFF\xFF\xDE\xAD\xBE\xEF", 8, UINT64_C(0xFFFF)},
  55. {"\x81\xFF\x00\x00\x00\x00\x00\x01\x00\x00\xDE\xAD\xBE\xEF", 14,
  56. UINT64_C(0x10000)},
  57. {"\x81\xFF\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xDE\xAD\xBE\xEF", 14,
  58. UINT64_C(0x7FFFFFFFFFFFFFFF)}};
  59. WebSocketMaskingKey masking_key;
  60. std::copy(kMaskingKey,
  61. kMaskingKey + WebSocketFrameHeader::kMaskingKeyLength,
  62. masking_key.key);
  63. for (const auto& test : kTests) {
  64. WebSocketFrameHeader header(WebSocketFrameHeader::kOpCodeText);
  65. header.final = true;
  66. header.masked = true;
  67. header.payload_length = test.frame_length;
  68. std::vector<char> expected_output(
  69. test.frame_header, test.frame_header + test.frame_header_length);
  70. std::vector<char> output(expected_output.size());
  71. EXPECT_EQ(static_cast<int>(expected_output.size()),
  72. WriteWebSocketFrameHeader(header, &masking_key, output.data(),
  73. output.size()));
  74. EXPECT_EQ(expected_output, output);
  75. }
  76. }
  77. TEST(WebSocketFrameHeaderTest, FrameOpCodes) {
  78. struct TestCase {
  79. const char* frame_header;
  80. size_t frame_header_length;
  81. WebSocketFrameHeader::OpCode opcode;
  82. };
  83. static const TestCase kTests[] = {
  84. {"\x80\x00", 2, WebSocketFrameHeader::kOpCodeContinuation},
  85. {"\x81\x00", 2, WebSocketFrameHeader::kOpCodeText},
  86. {"\x82\x00", 2, WebSocketFrameHeader::kOpCodeBinary},
  87. {"\x88\x00", 2, WebSocketFrameHeader::kOpCodeClose},
  88. {"\x89\x00", 2, WebSocketFrameHeader::kOpCodePing},
  89. {"\x8A\x00", 2, WebSocketFrameHeader::kOpCodePong},
  90. // These are undefined opcodes, but the builder should accept them anyway.
  91. {"\x83\x00", 2, 0x3},
  92. {"\x84\x00", 2, 0x4},
  93. {"\x85\x00", 2, 0x5},
  94. {"\x86\x00", 2, 0x6},
  95. {"\x87\x00", 2, 0x7},
  96. {"\x8B\x00", 2, 0xB},
  97. {"\x8C\x00", 2, 0xC},
  98. {"\x8D\x00", 2, 0xD},
  99. {"\x8E\x00", 2, 0xE},
  100. {"\x8F\x00", 2, 0xF}};
  101. for (const auto& test : kTests) {
  102. WebSocketFrameHeader header(test.opcode);
  103. header.final = true;
  104. header.payload_length = 0;
  105. std::vector<char> expected_output(
  106. test.frame_header, test.frame_header + test.frame_header_length);
  107. std::vector<char> output(expected_output.size());
  108. EXPECT_EQ(static_cast<int>(expected_output.size()),
  109. WriteWebSocketFrameHeader(header, nullptr, output.data(),
  110. output.size()));
  111. EXPECT_EQ(expected_output, output);
  112. }
  113. }
  114. TEST(WebSocketFrameHeaderTest, FinalBitAndReservedBits) {
  115. struct TestCase {
  116. const char* frame_header;
  117. size_t frame_header_length;
  118. bool final;
  119. bool reserved1;
  120. bool reserved2;
  121. bool reserved3;
  122. };
  123. static const TestCase kTests[] = {{"\x81\x00", 2, true, false, false, false},
  124. {"\x01\x00", 2, false, false, false, false},
  125. {"\xC1\x00", 2, true, true, false, false},
  126. {"\xA1\x00", 2, true, false, true, false},
  127. {"\x91\x00", 2, true, false, false, true},
  128. {"\x71\x00", 2, false, true, true, true},
  129. {"\xF1\x00", 2, true, true, true, true}};
  130. for (const auto& test : kTests) {
  131. WebSocketFrameHeader header(WebSocketFrameHeader::kOpCodeText);
  132. header.final = test.final;
  133. header.reserved1 = test.reserved1;
  134. header.reserved2 = test.reserved2;
  135. header.reserved3 = test.reserved3;
  136. header.payload_length = 0;
  137. std::vector<char> expected_output(
  138. test.frame_header, test.frame_header + test.frame_header_length);
  139. std::vector<char> output(expected_output.size());
  140. EXPECT_EQ(static_cast<int>(expected_output.size()),
  141. WriteWebSocketFrameHeader(header, nullptr, output.data(),
  142. output.size()));
  143. EXPECT_EQ(expected_output, output);
  144. }
  145. }
  146. TEST(WebSocketFrameHeaderTest, InsufficientBufferSize) {
  147. struct TestCase {
  148. uint64_t payload_length;
  149. bool masked;
  150. size_t expected_header_size;
  151. };
  152. static const TestCase kTests[] = {{UINT64_C(0), false, 2u},
  153. {UINT64_C(125), false, 2u},
  154. {UINT64_C(126), false, 4u},
  155. {UINT64_C(0xFFFF), false, 4u},
  156. {UINT64_C(0x10000), false, 10u},
  157. {UINT64_C(0x7FFFFFFFFFFFFFFF), false, 10u},
  158. {UINT64_C(0), true, 6u},
  159. {UINT64_C(125), true, 6u},
  160. {UINT64_C(126), true, 8u},
  161. {UINT64_C(0xFFFF), true, 8u},
  162. {UINT64_C(0x10000), true, 14u},
  163. {UINT64_C(0x7FFFFFFFFFFFFFFF), true, 14u}};
  164. for (const auto& test : kTests) {
  165. WebSocketFrameHeader header(WebSocketFrameHeader::kOpCodeText);
  166. header.final = true;
  167. header.opcode = WebSocketFrameHeader::kOpCodeText;
  168. header.masked = test.masked;
  169. header.payload_length = test.payload_length;
  170. char dummy_buffer[14];
  171. // Set an insufficient size to |buffer_size|.
  172. EXPECT_EQ(ERR_INVALID_ARGUMENT,
  173. WriteWebSocketFrameHeader(header, nullptr, dummy_buffer,
  174. test.expected_header_size - 1));
  175. }
  176. }
  177. TEST(WebSocketFrameTest, MaskPayload) {
  178. struct TestCase {
  179. const char* masking_key;
  180. uint64_t frame_offset;
  181. const char* input;
  182. const char* output;
  183. size_t data_length;
  184. };
  185. static const TestCase kTests[] = {
  186. {"\xDE\xAD\xBE\xEF", 0, "FooBar", "\x98\xC2\xD1\xAD\xBF\xDF", 6},
  187. {"\xDE\xAD\xBE\xEF", 1, "FooBar", "\xEB\xD1\x80\x9C\xCC\xCC", 6},
  188. {"\xDE\xAD\xBE\xEF", 2, "FooBar", "\xF8\x80\xB1\xEF\xDF\x9D", 6},
  189. {"\xDE\xAD\xBE\xEF", 3, "FooBar", "\xA9\xB1\xC2\xFC\x8E\xAC", 6},
  190. {"\xDE\xAD\xBE\xEF", 4, "FooBar", "\x98\xC2\xD1\xAD\xBF\xDF", 6},
  191. {"\xDE\xAD\xBE\xEF", 42, "FooBar", "\xF8\x80\xB1\xEF\xDF\x9D", 6},
  192. {"\xDE\xAD\xBE\xEF", 0, "", "", 0},
  193. {"\xDE\xAD\xBE\xEF", 0, "\xDE\xAD\xBE\xEF", "\x00\x00\x00\x00", 4},
  194. {"\xDE\xAD\xBE\xEF", 0, "\x00\x00\x00\x00", "\xDE\xAD\xBE\xEF", 4},
  195. {"\x00\x00\x00\x00", 0, "FooBar", "FooBar", 6},
  196. {"\xFF\xFF\xFF\xFF", 0, "FooBar", "\xB9\x90\x90\xBD\x9E\x8D", 6},
  197. };
  198. for (const auto& test : kTests) {
  199. WebSocketMaskingKey masking_key;
  200. std::copy(test.masking_key,
  201. test.masking_key + WebSocketFrameHeader::kMaskingKeyLength,
  202. masking_key.key);
  203. std::vector<char> frame_data(test.input, test.input + test.data_length);
  204. std::vector<char> expected_output(test.output,
  205. test.output + test.data_length);
  206. MaskWebSocketFramePayload(masking_key, test.frame_offset,
  207. frame_data.empty() ? nullptr : frame_data.data(),
  208. frame_data.size());
  209. EXPECT_EQ(expected_output, frame_data);
  210. }
  211. }
  212. // Check that all combinations of alignment, frame offset and chunk size work
  213. // correctly for MaskWebSocketFramePayload(). This is mainly used to ensure that
  214. // vectorisation optimisations don't break anything. We could take a "white box"
  215. // approach and only test the edge cases, but since the exhaustive "black box"
  216. // approach runs in acceptable time, we don't have to take the risk of being
  217. // clever.
  218. //
  219. // This brute-force approach runs in O(N^3) time where N is the size of the
  220. // maximum vector size we want to test again. This might need reconsidering if
  221. // MaskWebSocketFramePayload() is ever optimised for a dedicated vector
  222. // architecture.
  223. TEST(WebSocketFrameTest, MaskPayloadAlignment) {
  224. // This reflects what might be implemented in the future, rather than
  225. // the current implementation. FMA3 and FMA4 support 256-bit vector ops.
  226. static const size_t kMaxVectorSizeInBits = 256;
  227. static const size_t kMaxVectorSize = kMaxVectorSizeInBits / 8;
  228. static const size_t kMaxVectorAlignment = kMaxVectorSize;
  229. static const size_t kMaskingKeyLength =
  230. WebSocketFrameHeader::kMaskingKeyLength;
  231. static const size_t kScratchBufferSize =
  232. kMaxVectorAlignment + kMaxVectorSize * 2;
  233. static const char kTestMask[] = "\xd2\xba\x5a\xbe";
  234. // We use 786 bits of random input to reduce the risk of correlated errors.
  235. static const char kTestInput[] = {
  236. "\x3d\x77\x1d\x1b\x19\x8c\x48\xa3\x19\x6d\xf7\xcc\x39\xe7\x57\x0b"
  237. "\x69\x8c\xda\x4b\xfc\xac\x2c\xd3\x49\x96\x6e\x8a\x7b\x5a\x32\x76"
  238. "\xd0\x11\x43\xa0\x89\xfc\x76\x2b\x10\x2f\x4c\x7b\x4f\xa6\xdd\xe4"
  239. "\xfc\x8e\xd8\x72\xcf\x7e\x37\xcd\x31\xcd\xc1\xc0\x89\x0c\xa7\x4c"
  240. "\xda\xa8\x4b\x75\xa1\xcb\xa9\x77\x19\x4d\x6e\xdf\xc8\x08\x1c\xb6"
  241. "\x6d\xfb\x38\x04\x44\xd5\xba\x57\x9f\x76\xb0\x2e\x07\x91\xe6\xa8"
  242. };
  243. static const size_t kTestInputSize = std::size(kTestInput) - 1;
  244. static const char kTestOutput[] = {
  245. "\xef\xcd\x47\xa5\xcb\x36\x12\x1d\xcb\xd7\xad\x72\xeb\x5d\x0d\xb5"
  246. "\xbb\x36\x80\xf5\x2e\x16\x76\x6d\x9b\x2c\x34\x34\xa9\xe0\x68\xc8"
  247. "\x02\xab\x19\x1e\x5b\x46\x2c\x95\xc2\x95\x16\xc5\x9d\x1c\x87\x5a"
  248. "\x2e\x34\x82\xcc\x1d\xc4\x6d\x73\xe3\x77\x9b\x7e\x5b\xb6\xfd\xf2"
  249. "\x08\x12\x11\xcb\x73\x71\xf3\xc9\xcb\xf7\x34\x61\x1a\xb2\x46\x08"
  250. "\xbf\x41\x62\xba\x96\x6f\xe0\xe9\x4d\xcc\xea\x90\xd5\x2b\xbc\x16"
  251. };
  252. static_assert(std::size(kTestInput) == std::size(kTestOutput),
  253. "output and input arrays should have the same length");
  254. std::unique_ptr<char, base::AlignedFreeDeleter> scratch(static_cast<char*>(
  255. base::AlignedAlloc(kScratchBufferSize, kMaxVectorAlignment)));
  256. WebSocketMaskingKey masking_key;
  257. std::copy(kTestMask, kTestMask + kMaskingKeyLength, masking_key.key);
  258. for (size_t frame_offset = 0; frame_offset < kMaskingKeyLength;
  259. ++frame_offset) {
  260. for (size_t alignment = 0; alignment < kMaxVectorAlignment; ++alignment) {
  261. char* const aligned_scratch = scratch.get() + alignment;
  262. const size_t aligned_len = std::min(kScratchBufferSize - alignment,
  263. kTestInputSize - frame_offset);
  264. for (size_t chunk_size = 1; chunk_size < kMaxVectorSize; ++chunk_size) {
  265. memcpy(aligned_scratch, kTestInput + frame_offset, aligned_len);
  266. for (size_t chunk_start = 0; chunk_start < aligned_len;
  267. chunk_start += chunk_size) {
  268. const size_t this_chunk_size =
  269. std::min(chunk_size, aligned_len - chunk_start);
  270. MaskWebSocketFramePayload(masking_key,
  271. frame_offset + chunk_start,
  272. aligned_scratch + chunk_start,
  273. this_chunk_size);
  274. }
  275. // Stop the test if it fails, since we don't want to spew thousands of
  276. // failures.
  277. ASSERT_TRUE(std::equal(aligned_scratch,
  278. aligned_scratch + aligned_len,
  279. kTestOutput + frame_offset))
  280. << "Output failed to match for frame_offset=" << frame_offset
  281. << ", alignment=" << alignment << ", chunk_size=" << chunk_size;
  282. }
  283. }
  284. }
  285. }
  286. // "IsKnownDataOpCode" is currently implemented in an "obviously correct"
  287. // manner, but we test is anyway in case it changes to a more complex
  288. // implementation in future.
  289. TEST(WebSocketFrameHeaderTest, IsKnownDataOpCode) {
  290. // Make the test less verbose.
  291. typedef WebSocketFrameHeader Frame;
  292. // Known opcode, is used for data frames
  293. EXPECT_TRUE(Frame::IsKnownDataOpCode(Frame::kOpCodeContinuation));
  294. EXPECT_TRUE(Frame::IsKnownDataOpCode(Frame::kOpCodeText));
  295. EXPECT_TRUE(Frame::IsKnownDataOpCode(Frame::kOpCodeBinary));
  296. // Known opcode, is used for control frames
  297. EXPECT_FALSE(Frame::IsKnownDataOpCode(Frame::kOpCodeClose));
  298. EXPECT_FALSE(Frame::IsKnownDataOpCode(Frame::kOpCodePing));
  299. EXPECT_FALSE(Frame::IsKnownDataOpCode(Frame::kOpCodePong));
  300. // Check that unused opcodes return false
  301. EXPECT_FALSE(Frame::IsKnownDataOpCode(Frame::kOpCodeDataUnused));
  302. EXPECT_FALSE(Frame::IsKnownDataOpCode(Frame::kOpCodeControlUnused));
  303. // Check that opcodes with the 4 bit set return false
  304. EXPECT_FALSE(Frame::IsKnownDataOpCode(0x6));
  305. EXPECT_FALSE(Frame::IsKnownDataOpCode(0xF));
  306. // Check that out-of-range opcodes return false
  307. EXPECT_FALSE(Frame::IsKnownDataOpCode(-1));
  308. EXPECT_FALSE(Frame::IsKnownDataOpCode(0xFF));
  309. }
  310. // "IsKnownControlOpCode" is implemented in an "obviously correct" manner but
  311. // might be optimised in future.
  312. TEST(WebSocketFrameHeaderTest, IsKnownControlOpCode) {
  313. // Make the test less verbose.
  314. typedef WebSocketFrameHeader Frame;
  315. // Known opcode, is used for data frames
  316. EXPECT_FALSE(Frame::IsKnownControlOpCode(Frame::kOpCodeContinuation));
  317. EXPECT_FALSE(Frame::IsKnownControlOpCode(Frame::kOpCodeText));
  318. EXPECT_FALSE(Frame::IsKnownControlOpCode(Frame::kOpCodeBinary));
  319. // Known opcode, is used for control frames
  320. EXPECT_TRUE(Frame::IsKnownControlOpCode(Frame::kOpCodeClose));
  321. EXPECT_TRUE(Frame::IsKnownControlOpCode(Frame::kOpCodePing));
  322. EXPECT_TRUE(Frame::IsKnownControlOpCode(Frame::kOpCodePong));
  323. // Check that unused opcodes return false
  324. EXPECT_FALSE(Frame::IsKnownControlOpCode(Frame::kOpCodeDataUnused));
  325. EXPECT_FALSE(Frame::IsKnownControlOpCode(Frame::kOpCodeControlUnused));
  326. // Check that opcodes with the 4 bit set return false
  327. EXPECT_FALSE(Frame::IsKnownControlOpCode(0x6));
  328. EXPECT_FALSE(Frame::IsKnownControlOpCode(0xF));
  329. // Check that out-of-range opcodes return false
  330. EXPECT_FALSE(Frame::IsKnownControlOpCode(-1));
  331. EXPECT_FALSE(Frame::IsKnownControlOpCode(0xFF));
  332. }
  333. } // namespace
  334. } // namespace net