| 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 <algorithm> |
| 8 |
| 7 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
| 8 #include "base/logging.h" | 10 #include "base/logging.h" |
| 9 #include "base/rand_util.h" | 11 #include "base/rand_util.h" |
| 10 #include "net/base/big_endian.h" | 12 #include "net/base/big_endian.h" |
| 11 #include "net/base/io_buffer.h" | 13 #include "net/base/io_buffer.h" |
| 12 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
| 13 | 15 |
| 14 namespace { | 16 namespace { |
| 15 | 17 |
| 16 const uint8 kFinalBit = 0x80; | 18 const uint8 kFinalBit = 0x80; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 32 *masked ^= masking_key.key[masking_key_offset++]; | 34 *masked ^= masking_key.key[masking_key_offset++]; |
| 33 if (masking_key_offset == net::WebSocketFrameHeader::kMaskingKeyLength) | 35 if (masking_key_offset == net::WebSocketFrameHeader::kMaskingKeyLength) |
| 34 masking_key_offset = 0; | 36 masking_key_offset = 0; |
| 35 } | 37 } |
| 36 } | 38 } |
| 37 | 39 |
| 38 } // Unnamed namespace. | 40 } // Unnamed namespace. |
| 39 | 41 |
| 40 namespace net { | 42 namespace net { |
| 41 | 43 |
| 42 // Definitions for in-struct constants. | |
| 43 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeContinuation = | |
| 44 0x0; | |
| 45 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeText = 0x1; | |
| 46 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeBinary = 0x2; | |
| 47 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeDataUnused = | |
| 48 0x3; | |
| 49 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeClose = 0x8; | |
| 50 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodePing = 0x9; | |
| 51 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodePong = 0xA; | |
| 52 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeControlUnused = | |
| 53 0xB; | |
| 54 | |
| 55 scoped_ptr<WebSocketFrameHeader> WebSocketFrameHeader::Clone() { | 44 scoped_ptr<WebSocketFrameHeader> WebSocketFrameHeader::Clone() { |
| 56 scoped_ptr<WebSocketFrameHeader> ret(new WebSocketFrameHeader(opcode)); | 45 scoped_ptr<WebSocketFrameHeader> ret(new WebSocketFrameHeader(opcode)); |
| 57 ret->final = final; | 46 ret->final = final; |
| 58 ret->reserved1 = reserved1; | 47 ret->reserved1 = reserved1; |
| 59 ret->reserved2 = reserved2; | 48 ret->reserved2 = reserved2; |
| 60 ret->reserved3 = reserved3; | 49 ret->reserved3 = reserved3; |
| 61 ret->opcode = opcode; | 50 ret->opcode = opcode; |
| 62 ret->masked = masked; | 51 ret->masked = masked; |
| 63 ret->payload_length = payload_length; | 52 ret->payload_length = payload_length; |
| 64 return ret.Pass(); | 53 return ret.Pass(); |
| 65 } | 54 } |
| 66 | 55 |
| 67 WebSocketFrameChunk::WebSocketFrameChunk() : final_chunk(false) { | 56 WebSocketFrameChunk::WebSocketFrameChunk() : final_chunk(false) {} |
| 68 } | |
| 69 | 57 |
| 70 WebSocketFrameChunk::~WebSocketFrameChunk() { | 58 WebSocketFrameChunk::~WebSocketFrameChunk() {} |
| 71 } | |
| 72 | 59 |
| 73 int GetWebSocketFrameHeaderSize(const WebSocketFrameHeader& header) { | 60 int GetWebSocketFrameHeaderSize(const WebSocketFrameHeader& header) { |
| 74 int extended_length_size = 0; | 61 int extended_length_size = 0; |
| 75 if (header.payload_length > kMaxPayloadLengthWithoutExtendedLengthField && | 62 if (header.payload_length > kMaxPayloadLengthWithoutExtendedLengthField && |
| 76 header.payload_length <= kuint16max) { | 63 header.payload_length <= kuint16max) { |
| 77 extended_length_size = 2; | 64 extended_length_size = 2; |
| 78 } else if (header.payload_length > kuint16max) { | 65 } else if (header.payload_length > kuint16max) { |
| 79 extended_length_size = 8; | 66 extended_length_size = 8; |
| 80 } | 67 } |
| 81 | 68 |
| 82 return (WebSocketFrameHeader::kBaseHeaderSize + | 69 return (WebSocketFrameHeader::kBaseHeaderSize + extended_length_size + |
| 83 extended_length_size + | |
| 84 (header.masked ? WebSocketFrameHeader::kMaskingKeyLength : 0)); | 70 (header.masked ? WebSocketFrameHeader::kMaskingKeyLength : 0)); |
| 85 } | 71 } |
| 86 | 72 |
| 87 int WriteWebSocketFrameHeader(const WebSocketFrameHeader& header, | 73 int WriteWebSocketFrameHeader(const WebSocketFrameHeader& header, |
| 88 const WebSocketMaskingKey* masking_key, | 74 const WebSocketMaskingKey* masking_key, |
| 89 char* buffer, | 75 char* buffer, |
| 90 int buffer_size) { | 76 int buffer_size) { |
| 91 DCHECK((header.opcode & kOpCodeMask) == header.opcode) | 77 DCHECK((header.opcode & kOpCodeMask) == header.opcode) |
| 92 << "header.opcode must fit to kOpCodeMask."; | 78 << "header.opcode must fit to kOpCodeMask."; |
| 93 DCHECK(header.payload_length <= static_cast<uint64>(kint64max)) | 79 DCHECK(header.payload_length <= static_cast<uint64>(kint64max)) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 115 first_byte |= header.final ? kFinalBit : 0u; | 101 first_byte |= header.final ? kFinalBit : 0u; |
| 116 first_byte |= header.reserved1 ? kReserved1Bit : 0u; | 102 first_byte |= header.reserved1 ? kReserved1Bit : 0u; |
| 117 first_byte |= header.reserved2 ? kReserved2Bit : 0u; | 103 first_byte |= header.reserved2 ? kReserved2Bit : 0u; |
| 118 first_byte |= header.reserved3 ? kReserved3Bit : 0u; | 104 first_byte |= header.reserved3 ? kReserved3Bit : 0u; |
| 119 first_byte |= header.opcode & kOpCodeMask; | 105 first_byte |= header.opcode & kOpCodeMask; |
| 120 buffer[buffer_index++] = first_byte; | 106 buffer[buffer_index++] = first_byte; |
| 121 | 107 |
| 122 int extended_length_size = 0; | 108 int extended_length_size = 0; |
| 123 uint8 second_byte = 0u; | 109 uint8 second_byte = 0u; |
| 124 second_byte |= header.masked ? kMaskBit : 0u; | 110 second_byte |= header.masked ? kMaskBit : 0u; |
| 125 if (header.payload_length <= | 111 if (header.payload_length <= kMaxPayloadLengthWithoutExtendedLengthField) { |
| 126 kMaxPayloadLengthWithoutExtendedLengthField) { | |
| 127 second_byte |= header.payload_length; | 112 second_byte |= header.payload_length; |
| 128 } else if (header.payload_length <= kuint16max) { | 113 } else if (header.payload_length <= kuint16max) { |
| 129 second_byte |= kPayloadLengthWithTwoByteExtendedLengthField; | 114 second_byte |= kPayloadLengthWithTwoByteExtendedLengthField; |
| 130 extended_length_size = 2; | 115 extended_length_size = 2; |
| 131 } else { | 116 } else { |
| 132 second_byte |= kPayloadLengthWithEightByteExtendedLengthField; | 117 second_byte |= kPayloadLengthWithEightByteExtendedLengthField; |
| 133 extended_length_size = 8; | 118 extended_length_size = 8; |
| 134 } | 119 } |
| 135 buffer[buffer_index++] = second_byte; | 120 buffer[buffer_index++] = second_byte; |
| 136 | 121 |
| 137 // Writes "extended payload length" field. | 122 // Writes "extended payload length" field. |
| 138 if (extended_length_size == 2) { | 123 if (extended_length_size == 2) { |
| 139 uint16 payload_length_16 = static_cast<uint16>(header.payload_length); | 124 uint16 payload_length_16 = static_cast<uint16>(header.payload_length); |
| 140 WriteBigEndian(buffer + buffer_index, payload_length_16); | 125 WriteBigEndian(buffer + buffer_index, payload_length_16); |
| 141 buffer_index += sizeof(uint16); | 126 buffer_index += sizeof(payload_length_16); |
| 142 } else if (extended_length_size == 8) { | 127 } else if (extended_length_size == 8) { |
| 143 WriteBigEndian(buffer + buffer_index, header.payload_length); | 128 WriteBigEndian(buffer + buffer_index, header.payload_length); |
| 144 buffer_index += sizeof(uint64); | 129 buffer_index += sizeof(header.payload_length); |
| 145 } | 130 } |
| 146 | 131 |
| 147 // Writes "masking key" field, if needed. | 132 // Writes "masking key" field, if needed. |
| 148 if (header.masked) { | 133 if (header.masked) { |
| 149 DCHECK(masking_key); | 134 DCHECK(masking_key); |
| 150 std::copy(masking_key->key, | 135 std::copy(masking_key->key, |
| 151 masking_key->key + WebSocketFrameHeader::kMaskingKeyLength, | 136 masking_key->key + WebSocketFrameHeader::kMaskingKeyLength, |
| 152 buffer + buffer_index); | 137 buffer + buffer_index); |
| 153 buffer_index += WebSocketFrameHeader::kMaskingKeyLength; | 138 buffer_index += WebSocketFrameHeader::kMaskingKeyLength; |
| 154 } else { | 139 } else { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 184 typedef size_t PackedMaskType; | 169 typedef size_t PackedMaskType; |
| 185 PackedMaskType packed_mask_key = 0; | 170 PackedMaskType packed_mask_key = 0; |
| 186 static const size_t kPackedMaskKeySize = sizeof(packed_mask_key); | 171 static const size_t kPackedMaskKeySize = sizeof(packed_mask_key); |
| 187 COMPILE_ASSERT((kPackedMaskKeySize >= kMaskingKeyLength && | 172 COMPILE_ASSERT((kPackedMaskKeySize >= kMaskingKeyLength && |
| 188 kPackedMaskKeySize % kMaskingKeyLength == 0), | 173 kPackedMaskKeySize % kMaskingKeyLength == 0), |
| 189 word_size_is_not_multiple_of_mask_length); | 174 word_size_is_not_multiple_of_mask_length); |
| 190 char* const end = data + data_size; | 175 char* const end = data + data_size; |
| 191 // If the buffer is too small for the vectorised version to be useful, revert | 176 // If the buffer is too small for the vectorised version to be useful, revert |
| 192 // to the byte-at-a-time implementation early. | 177 // to the byte-at-a-time implementation early. |
| 193 if (data_size <= static_cast<int>(kPackedMaskKeySize * 2)) { | 178 if (data_size <= static_cast<int>(kPackedMaskKeySize * 2)) { |
| 194 MaskWebSocketFramePayloadByBytes(masking_key, | 179 MaskWebSocketFramePayloadByBytes( |
| 195 frame_offset % kMaskingKeyLength, | 180 masking_key, frame_offset % kMaskingKeyLength, data, end); |
| 196 data, end); | |
| 197 return; | 181 return; |
| 198 } | 182 } |
| 199 const size_t data_modulus = | 183 const size_t data_modulus = |
| 200 reinterpret_cast<size_t>(data) % kPackedMaskKeySize; | 184 reinterpret_cast<size_t>(data) % kPackedMaskKeySize; |
| 201 char* const aligned_begin = data_modulus == 0 ? data : | 185 char* const aligned_begin = |
| 202 (data + kPackedMaskKeySize - data_modulus); | 186 data_modulus == 0 ? data : (data + kPackedMaskKeySize - data_modulus); |
| 203 // Guaranteed by the above check for small data_size. | 187 // Guaranteed by the above check for small data_size. |
| 204 DCHECK(aligned_begin < end); | 188 DCHECK(aligned_begin < end); |
| 205 MaskWebSocketFramePayloadByBytes(masking_key, | 189 MaskWebSocketFramePayloadByBytes( |
| 206 frame_offset % kMaskingKeyLength, | 190 masking_key, frame_offset % kMaskingKeyLength, data, aligned_begin); |
| 207 data, aligned_begin); | |
| 208 const size_t end_modulus = reinterpret_cast<size_t>(end) % kPackedMaskKeySize; | 191 const size_t end_modulus = reinterpret_cast<size_t>(end) % kPackedMaskKeySize; |
| 209 char* const aligned_end = end - end_modulus; | 192 char* const aligned_end = end - end_modulus; |
| 210 // Guaranteed by the above check for small data_size. | 193 // Guaranteed by the above check for small data_size. |
| 211 DCHECK(aligned_end > aligned_begin); | 194 DCHECK(aligned_end > aligned_begin); |
| 212 // Create a version of the mask which is rotated by the appropriate offset | 195 // Create a version of the mask which is rotated by the appropriate offset |
| 213 // for our alignment. The "trick" here is that 0 XORed with the mask will | 196 // for our alignment. The "trick" here is that 0 XORed with the mask will |
| 214 // give the value of the mask for the appropriate byte. | 197 // give the value of the mask for the appropriate byte. |
| 215 char realigned_mask[kMaskingKeyLength] = { 0 }; | 198 char realigned_mask[kMaskingKeyLength] = { 0 }; |
| 216 MaskWebSocketFramePayloadByBytes(masking_key, | 199 MaskWebSocketFramePayloadByBytes( |
| 217 (frame_offset + aligned_begin - data) | 200 masking_key, |
| 218 % kMaskingKeyLength, | 201 (frame_offset + aligned_begin - data) % kMaskingKeyLength, |
| 219 realigned_mask, | 202 realigned_mask, |
| 220 realigned_mask + kMaskingKeyLength); | 203 realigned_mask + kMaskingKeyLength); |
| 221 | 204 |
| 222 for (size_t i = 0; i < kPackedMaskKeySize; i += kMaskingKeyLength) { | 205 for (size_t i = 0; i < kPackedMaskKeySize; i += kMaskingKeyLength) { |
| 223 // memcpy() is allegedly blessed by the C++ standard for type-punning. | 206 // memcpy() is allegedly blessed by the C++ standard for type-punning. |
| 224 memcpy(reinterpret_cast<char*>(&packed_mask_key) + i, | 207 memcpy(reinterpret_cast<char*>(&packed_mask_key) + i, |
| 225 realigned_mask, kMaskingKeyLength); | 208 realigned_mask, |
| 209 kMaskingKeyLength); |
| 226 } | 210 } |
| 227 | 211 |
| 228 // The main loop. | 212 // The main loop. |
| 229 for (char* merged = aligned_begin; | 213 for (char* merged = aligned_begin; merged != aligned_end; |
| 230 merged != aligned_end; | |
| 231 merged += kPackedMaskKeySize) { | 214 merged += kPackedMaskKeySize) { |
| 232 // This is not quite standard-compliant C++. However, the standard-compliant | 215 // This is not quite standard-compliant C++. However, the standard-compliant |
| 233 // equivalent (using memcpy()) compiles to slower code using g++. In | 216 // equivalent (using memcpy()) compiles to slower code using g++. In |
| 234 // practice, this will work for the compilers and architectures currently | 217 // practice, this will work for the compilers and architectures currently |
| 235 // supported by Chromium, and the tests are extremely unlikely to pass if a | 218 // supported by Chromium, and the tests are extremely unlikely to pass if a |
| 236 // future compiler/architecture breaks it. | 219 // future compiler/architecture breaks it. |
| 237 *reinterpret_cast<PackedMaskType*>(merged) ^= packed_mask_key; | 220 *reinterpret_cast<PackedMaskType*>(merged) ^= packed_mask_key; |
| 238 } | 221 } |
| 239 | 222 |
| 240 MaskWebSocketFramePayloadByBytes(masking_key, | 223 MaskWebSocketFramePayloadByBytes( |
| 241 (frame_offset + (aligned_end - data)) | 224 masking_key, |
| 242 % kMaskingKeyLength, | 225 (frame_offset + (aligned_end - data)) % kMaskingKeyLength, |
| 243 aligned_end, end); | 226 aligned_end, |
| 227 end); |
| 244 } | 228 } |
| 245 | 229 |
| 246 } // namespace net | 230 } // namespace net |
| OLD | NEW |