OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/websockets/websocket_frame.h" | 5 #include "net/websockets/websocket_frame.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/rand_util.h" | 9 #include "base/rand_util.h" |
10 #include "net/base/big_endian.h" | 10 #include "net/base/big_endian.h" |
11 #include "net/base/io_buffer.h" | 11 #include "net/base/io_buffer.h" |
12 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
13 | 13 |
14 namespace { | 14 namespace { |
15 | 15 |
16 const uint8 kFinalBit = 0x80; | 16 const uint8 kFinalBit = 0x80; |
17 const uint8 kReserved1Bit = 0x40; | 17 const uint8 kReserved1Bit = 0x40; |
18 const uint8 kReserved2Bit = 0x20; | 18 const uint8 kReserved2Bit = 0x20; |
19 const uint8 kReserved3Bit = 0x10; | 19 const uint8 kReserved3Bit = 0x10; |
20 const uint8 kOpCodeMask = 0xF; | 20 const uint8 kOpCodeMask = 0xF; |
21 const uint8 kMaskBit = 0x80; | 21 const uint8 kMaskBit = 0x80; |
22 const uint64 kMaxPayloadLengthWithoutExtendedLengthField = 125; | 22 const uint64 kMaxPayloadLengthWithoutExtendedLengthField = 125; |
23 const uint64 kPayloadLengthWithTwoByteExtendedLengthField = 126; | 23 const uint64 kPayloadLengthWithTwoByteExtendedLengthField = 126; |
24 const uint64 kPayloadLengthWithEightByteExtendedLengthField = 127; | 24 const uint64 kPayloadLengthWithEightByteExtendedLengthField = 127; |
25 | 25 |
| 26 inline void MaskWebSocketFramePayloadByBytes( |
| 27 const net::WebSocketMaskingKey& masking_key, |
| 28 size_t masking_key_offset, |
| 29 char* const begin, |
| 30 char* const end) { |
| 31 for (char* masked = begin; masked != end; ++masked) { |
| 32 *masked ^= masking_key.key[masking_key_offset++]; |
| 33 if (masking_key_offset == net::WebSocketFrameHeader::kMaskingKeyLength) |
| 34 masking_key_offset = 0; |
| 35 } |
| 36 } |
| 37 |
26 } // Unnamed namespace. | 38 } // Unnamed namespace. |
27 | 39 |
28 namespace net { | 40 namespace net { |
29 | 41 |
30 // Definitions for in-struct constants. | 42 // Definitions for in-struct constants. |
31 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeContinuation = | 43 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeContinuation = |
32 0x0; | 44 0x0; |
33 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeText = 0x1; | 45 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeText = 0x1; |
34 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeBinary = 0x2; | 46 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeBinary = 0x2; |
35 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeClose = 0x8; | 47 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeClose = 0x8; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 // Masking keys should be generated from a cryptographically secure random | 147 // Masking keys should be generated from a cryptographically secure random |
136 // number generator, which means web application authors should not be able | 148 // number generator, which means web application authors should not be able |
137 // to guess the next value of masking key. | 149 // to guess the next value of masking key. |
138 WebSocketMaskingKey masking_key; | 150 WebSocketMaskingKey masking_key; |
139 base::RandBytes(masking_key.key, WebSocketFrameHeader::kMaskingKeyLength); | 151 base::RandBytes(masking_key.key, WebSocketFrameHeader::kMaskingKeyLength); |
140 return masking_key; | 152 return masking_key; |
141 } | 153 } |
142 | 154 |
143 void MaskWebSocketFramePayload(const WebSocketMaskingKey& masking_key, | 155 void MaskWebSocketFramePayload(const WebSocketMaskingKey& masking_key, |
144 uint64 frame_offset, | 156 uint64 frame_offset, |
145 char* data, | 157 char* const data, |
146 int data_size) { | 158 int data_size) { |
147 static const size_t kMaskingKeyLength = | 159 static const size_t kMaskingKeyLength = |
148 WebSocketFrameHeader::kMaskingKeyLength; | 160 WebSocketFrameHeader::kMaskingKeyLength; |
149 | 161 |
150 DCHECK_GE(data_size, 0); | 162 DCHECK_GE(data_size, 0); |
151 | 163 |
152 // TODO(yutak): Make masking more efficient by XOR'ing every machine word | 164 // Most of the masking is done one word at a time, except for the beginning |
153 // (4 or 8 bytes), instead of XOR'ing every byte. | 165 // and the end of the buffer which may be unaligned. We use size_t to get the |
154 size_t masking_key_offset = frame_offset % kMaskingKeyLength; | 166 // word size for this architecture. We require it be a multiple of |
155 for (int i = 0; i < data_size; ++i) { | 167 // kMaskingKeyLength in size. |
156 data[i] ^= masking_key.key[masking_key_offset++]; | 168 typedef size_t PackedMaskType; |
157 if (masking_key_offset == kMaskingKeyLength) | 169 PackedMaskType packed_mask_key = 0; |
158 masking_key_offset = 0; | 170 static const size_t kPackedMaskKeySize = sizeof(packed_mask_key); |
| 171 COMPILE_ASSERT((kPackedMaskKeySize >= kMaskingKeyLength && |
| 172 kPackedMaskKeySize % kMaskingKeyLength == 0), |
| 173 word_size_is_not_multiple_of_mask_length); |
| 174 char* const end = data + data_size; |
| 175 // If the buffer is too small for the vectorised version to be useful, revert |
| 176 // to the byte-at-a-time implementation early. |
| 177 if (data_size <= static_cast<int>(kPackedMaskKeySize * 2)) { |
| 178 MaskWebSocketFramePayloadByBytes(masking_key, |
| 179 frame_offset % kMaskingKeyLength, |
| 180 data, end); |
| 181 return; |
159 } | 182 } |
| 183 const size_t data_modulus = |
| 184 reinterpret_cast<size_t>(data) % kPackedMaskKeySize; |
| 185 char* const aligned_begin = data_modulus == 0 ? data : |
| 186 (data + kPackedMaskKeySize - data_modulus); |
| 187 // Guaranteed by the above check for small data_size. |
| 188 DCHECK(aligned_begin < end); |
| 189 MaskWebSocketFramePayloadByBytes(masking_key, |
| 190 frame_offset % kMaskingKeyLength, |
| 191 data, aligned_begin); |
| 192 const size_t end_modulus = reinterpret_cast<size_t>(end) % kPackedMaskKeySize; |
| 193 char* const aligned_end = end - end_modulus; |
| 194 // Guaranteed by the above check for small data_size. |
| 195 DCHECK(aligned_end > aligned_begin); |
| 196 // Create a version of the mask which is rotated by the appropriate offset |
| 197 // for our alignment. The "trick" here is that 0 XORed with the mask will |
| 198 // give the value of the mask for the appropriate byte. |
| 199 char realigned_mask[kMaskingKeyLength] = { 0 }; |
| 200 MaskWebSocketFramePayloadByBytes(masking_key, |
| 201 (frame_offset + aligned_begin - data) |
| 202 % kMaskingKeyLength, |
| 203 realigned_mask, |
| 204 realigned_mask + kMaskingKeyLength); |
| 205 |
| 206 for (size_t i = 0; i < kPackedMaskKeySize; i += kMaskingKeyLength) { |
| 207 // memcpy() is allegedly blessed by the C++ standard for type-punning. |
| 208 memcpy(reinterpret_cast<char*>(&packed_mask_key) + i, |
| 209 realigned_mask, kMaskingKeyLength); |
| 210 } |
| 211 |
| 212 // The main loop. |
| 213 for (char* merged = aligned_begin; |
| 214 merged != aligned_end; |
| 215 merged += kPackedMaskKeySize) { |
| 216 // This is not quite standard-compliant C++. However, the standard-compliant |
| 217 // equivalent (using memcpy()) compiles to slower code using g++. In |
| 218 // practice, this will work for the compilers and architectures currently |
| 219 // supported by Chromium, and the tests are extremely unlikely to pass if a |
| 220 // future compiler/architecture breaks it. |
| 221 *reinterpret_cast<PackedMaskType*>(merged) ^= packed_mask_key; |
| 222 } |
| 223 |
| 224 MaskWebSocketFramePayloadByBytes(masking_key, |
| 225 (frame_offset + (aligned_end - data)) |
| 226 % kMaskingKeyLength, |
| 227 aligned_end, end); |
160 } | 228 } |
161 | 229 |
162 } // namespace net | 230 } // namespace net |
OLD | NEW |