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" | |
8 #include "base/logging.h" | |
9 #include "base/rand_util.h" | |
10 #include "net/base/big_endian.h" | |
11 #include "net/base/net_errors.h" | |
12 | |
13 namespace { | |
14 | |
15 const uint8 kFinalBit = 0x80; | |
16 const uint8 kReserved1Bit = 0x40; | |
17 const uint8 kReserved2Bit = 0x20; | |
18 const uint8 kReserved3Bit = 0x10; | |
19 const uint8 kOpCodeMask = 0xF; | |
20 const uint8 kMaskBit = 0x80; | |
21 const uint64 kMaxPayloadLengthWithoutExtendedLengthField = 125; | |
22 const uint64 kPayloadLengthWithTwoByteExtendedLengthField = 126; | |
23 const uint64 kPayloadLengthWithEightByteExtendedLengthField = 127; | |
24 | |
25 } // Unnamed namespace. | |
26 | |
7 namespace net { | 27 namespace net { |
8 | 28 |
9 // Definitions for in-struct constants. | 29 // Definitions for in-struct constants. |
10 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeContinuation = | 30 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeContinuation = |
11 0x0; | 31 0x0; |
12 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeText = 0x1; | 32 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeText = 0x1; |
13 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeBinary = 0x2; | 33 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeBinary = 0x2; |
14 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeClose = 0x8; | 34 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodeClose = 0x8; |
15 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodePing = 0x9; | 35 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodePing = 0x9; |
16 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodePong = 0xA; | 36 const WebSocketFrameHeader::OpCode WebSocketFrameHeader::kOpCodePong = 0xA; |
17 | 37 |
18 WebSocketFrameChunk::WebSocketFrameChunk() : final_chunk(false) { | 38 WebSocketFrameChunk::WebSocketFrameChunk() : final_chunk(false) { |
19 } | 39 } |
20 | 40 |
21 WebSocketFrameChunk::~WebSocketFrameChunk() { | 41 WebSocketFrameChunk::~WebSocketFrameChunk() { |
22 } | 42 } |
23 | 43 |
44 int WriteWebSocketFrameHeader(const WebSocketFrameHeader& header, | |
45 const WebSocketMaskingKey* masking_key, | |
46 char* buffer, | |
47 int buffer_size) { | |
48 DCHECK((header.opcode & kOpCodeMask) == header.opcode) | |
49 << "header.opcode must fit to kOpCodeMask."; | |
50 DCHECK(header.payload_length <= static_cast<uint64>(kint64max)) | |
51 << "WebSocket specification doesn't allow a frame longer than " | |
52 << "kint64max (0x7FFFFFFFFFFFFFFF) bytes."; | |
53 DCHECK_GE(buffer_size, 0); | |
54 | |
55 // WebSocket frame format is as follows: | |
56 // - Common header (2 bytes) | |
57 // - Optional extended payload length | |
58 // (2 or 8 bytes, present if actual payload length is more than 125 bytes) | |
59 // - Optional masking key (4 bytes, present if MASK bit is on) | |
60 // - Actual payload (XOR masked with masking key if MASK bit is on) | |
61 // | |
62 // This function constructs frame header (the first three in the list | |
63 // above). | |
64 | |
65 size_t extended_length_size = 0; | |
66 if (header.payload_length > kMaxPayloadLengthWithoutExtendedLengthField && | |
67 header.payload_length <= kuint16max) { | |
68 extended_length_size = 2; | |
69 } else if (header.payload_length > kuint16max) { | |
70 extended_length_size = 8; | |
71 } | |
72 int header_size = | |
73 WebSocketFrameHeader::kBaseHeaderSize + | |
74 extended_length_size + | |
75 (header.masked ? WebSocketFrameHeader::kMaskingKeyLength : 0); | |
76 if (header_size > buffer_size) | |
77 return ERR_INVALID_ARGUMENT; | |
78 | |
79 int buffer_index = 0; | |
80 | |
81 uint8 first_byte = 0u; | |
82 first_byte |= header.final ? kFinalBit : 0u; | |
83 first_byte |= header.reserved1 ? kReserved1Bit : 0u; | |
84 first_byte |= header.reserved2 ? kReserved2Bit : 0u; | |
85 first_byte |= header.reserved3 ? kReserved3Bit : 0u; | |
86 first_byte |= header.opcode; | |
mmenke
2012/06/08 16:00:03
May want to use header.opcode & kOpCodeMask here,
Yuta Kitamura
2012/06/11 15:56:01
Done.
| |
87 buffer[buffer_index++] = first_byte; | |
88 | |
89 uint8 second_byte = 0u; | |
90 second_byte |= header.masked ? kMaskBit : 0u; | |
91 if (header.payload_length <= | |
92 kMaxPayloadLengthWithoutExtendedLengthField) { | |
93 second_byte |= header.payload_length; | |
94 } else if (header.payload_length <= kuint16max) { | |
95 second_byte |= kPayloadLengthWithTwoByteExtendedLengthField; | |
96 } else { | |
97 second_byte |= kPayloadLengthWithEightByteExtendedLengthField; | |
98 } | |
99 buffer[buffer_index++] = second_byte; | |
100 | |
101 // Writes "extended payload length" field. | |
102 if (extended_length_size == 2u) { | |
103 uint16 payload_length_16 = static_cast<uint16>(header.payload_length); | |
104 WriteBigEndian(buffer + buffer_index, payload_length_16); | |
105 buffer_index += sizeof(uint16); | |
106 } else if (extended_length_size == 8u) { | |
107 WriteBigEndian(buffer + buffer_index, header.payload_length); | |
108 buffer_index += sizeof(uint64); | |
109 } | |
110 | |
111 // Writes "masking key" field, if needed. | |
112 if (header.masked) { | |
113 DCHECK(masking_key); | |
114 std::copy(masking_key->key, | |
115 masking_key->key + WebSocketFrameHeader::kMaskingKeyLength, | |
116 buffer + buffer_index); | |
117 buffer_index += WebSocketFrameHeader::kMaskingKeyLength; | |
118 } else { | |
119 DCHECK(!masking_key); | |
120 } | |
121 | |
122 DCHECK_EQ(header_size, buffer_index); | |
123 return header_size; | |
124 } | |
125 | |
126 WebSocketMaskingKey GenerateWebSocketMaskingKey() { | |
127 // Masking keys should be generated from a cryptographically secure random | |
128 // number generator, which means web application authors should not be able | |
129 // to guess the next value of masking key. | |
130 WebSocketMaskingKey masking_key; | |
131 base::RandBytes(masking_key.key, WebSocketFrameHeader::kMaskingKeyLength); | |
132 return masking_key; | |
133 } | |
134 | |
135 void MaskWebSocketFramePayload(const WebSocketMaskingKey& masking_key, | |
136 uint64 frame_offset, | |
137 char* data, | |
138 int data_size) { | |
139 static const size_t kMaskingKeyLength = | |
140 WebSocketFrameHeader::kMaskingKeyLength; | |
141 | |
142 DCHECK_GE(data_size, 0); | |
143 | |
144 // TODO(yutak): Make masking more efficient by XOR'ing every machine word | |
145 // (4 or 8 bytes), instead of XOR'ing every byte. | |
146 size_t masking_key_offset = frame_offset % kMaskingKeyLength; | |
147 for (int i = 0; i < data_size; ++i) { | |
148 data[i] ^= masking_key.key[masking_key_offset++]; | |
149 if (masking_key_offset == kMaskingKeyLength) | |
150 masking_key_offset = 0; | |
151 } | |
152 } | |
153 | |
24 } // namespace net | 154 } // namespace net |
OLD | NEW |