OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
3 * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 3 * Copyright (C) Research In Motion Limited 2011. All rights reserved. |
4 * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) | 4 * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) |
5 * | 5 * |
6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
10 * | 10 * |
11 * This program is distributed in the hope that it will be useful, | 11 * This program is distributed in the hope that it will be useful, |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 * Library General Public License for more details. | 14 * Library General Public License for more details. |
15 * | 15 * |
16 * You should have received a copy of the GNU Library General Public License | 16 * You should have received a copy of the GNU Library General Public License |
17 * along with this program; see the file COPYING.LIB. If not, write to | 17 * along with this program; see the file COPYING.LIB. If not, write to |
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 * Boston, MA 02110-1301, USA. | 19 * Boston, MA 02110-1301, USA. |
20 * | 20 * |
21 */ | 21 */ |
22 | 22 |
23 #include "config.h" | 23 #include "config.h" |
24 | 24 |
25 #include "modules/websockets/WebSocketFrame.h" | 25 #include "modules/websockets/WebSocketFrame.h" |
26 | 26 |
27 #include "wtf/CryptographicallyRandomNumber.h" | |
28 #include "wtf/MathExtras.h" | |
29 | |
30 namespace blink { | 27 namespace blink { |
31 | 28 |
32 // Constants for hybi-10 frame format. | |
33 // These are bitmasks for frame composition / decomposition. | |
34 // Do not mistake these constants for the flags given to the WebSocketFrame cons
tructor. | |
35 const unsigned char finalBit = 0x80; | |
36 const unsigned char compressBit = 0x40; | |
37 const unsigned char reserved2Bit = 0x20; | |
38 const unsigned char reserved3Bit = 0x10; | |
39 const unsigned char opCodeMask = 0xF; | |
40 const unsigned char maskBit = 0x80; | |
41 const unsigned char payloadLengthMask = 0x7F; | |
42 const size_t maxPayloadLengthWithoutExtendedLengthField = 125; | |
43 const size_t payloadLengthWithTwoByteExtendedLengthField = 126; | |
44 const size_t payloadLengthWithEightByteExtendedLengthField = 127; | |
45 const size_t maskingKeyWidthInBytes = 4; | |
46 | |
47 bool WebSocketFrame::needsExtendedLengthField(size_t payloadLength) | |
48 { | |
49 return payloadLength > maxPayloadLengthWithoutExtendedLengthField; | |
50 } | |
51 | |
52 WebSocketFrame::ParseFrameResult WebSocketFrame::parseFrame(char* data, size_t d
ataLength, WebSocketFrame& frame, const char*& frameEnd, String& errorString) | |
53 { | |
54 char* p = data; | |
55 const char* bufferEnd = data + dataLength; | |
56 | |
57 if (dataLength < 2) | |
58 return FrameIncomplete; | |
59 | |
60 unsigned char firstByte = *p++; | |
61 unsigned char secondByte = *p++; | |
62 | |
63 bool final = firstByte & finalBit; | |
64 bool compress = firstByte & compressBit; | |
65 bool reserved2 = firstByte & reserved2Bit; | |
66 bool reserved3 = firstByte & reserved3Bit; | |
67 unsigned char opCode = firstByte & opCodeMask; | |
68 | |
69 bool masked = secondByte & maskBit; | |
70 uint64_t payloadLength64 = secondByte & payloadLengthMask; | |
71 if (payloadLength64 > maxPayloadLengthWithoutExtendedLengthField) { | |
72 int extendedPayloadLengthSize; | |
73 if (payloadLength64 == payloadLengthWithTwoByteExtendedLengthField) | |
74 extendedPayloadLengthSize = 2; | |
75 else { | |
76 ASSERT(payloadLength64 == payloadLengthWithEightByteExtendedLengthFi
eld); | |
77 extendedPayloadLengthSize = 8; | |
78 } | |
79 if (bufferEnd - p < extendedPayloadLengthSize) | |
80 return FrameIncomplete; | |
81 payloadLength64 = 0; | |
82 for (int i = 0; i < extendedPayloadLengthSize; ++i) { | |
83 payloadLength64 <<= 8; | |
84 payloadLength64 |= static_cast<unsigned char>(*p++); | |
85 } | |
86 if (extendedPayloadLengthSize == 2 && payloadLength64 <= maxPayloadLengt
hWithoutExtendedLengthField) { | |
87 errorString = "The minimal number of bytes MUST be used to encode th
e length"; | |
88 return FrameError; | |
89 } | |
90 if (extendedPayloadLengthSize == 8 && payloadLength64 <= 0xFFFF) { | |
91 errorString = "The minimal number of bytes MUST be used to encode th
e length"; | |
92 return FrameError; | |
93 } | |
94 } | |
95 | |
96 static const uint64_t maxPayloadLength = UINT64_C(0x7FFFFFFFFFFFFFFF); | |
97 size_t maskingKeyLength = masked ? maskingKeyWidthInBytes : 0; | |
98 if (payloadLength64 > maxPayloadLength || payloadLength64 + maskingKeyLength
> std::numeric_limits<size_t>::max()) { | |
99 errorString = "WebSocket frame length too large: " + String::number(payl
oadLength64) + " bytes"; | |
100 return FrameError; | |
101 } | |
102 size_t payloadLength = static_cast<size_t>(payloadLength64); | |
103 | |
104 if (static_cast<size_t>(bufferEnd - p) < maskingKeyLength + payloadLength) | |
105 return FrameIncomplete; | |
106 | |
107 if (masked) { | |
108 const char* maskingKey = p; | |
109 char* payload = p + maskingKeyWidthInBytes; | |
110 for (size_t i = 0; i < payloadLength; ++i) | |
111 payload[i] ^= maskingKey[i % maskingKeyWidthInBytes]; // Unmask the
payload. | |
112 } | |
113 | |
114 frame.opCode = static_cast<WebSocketFrame::OpCode>(opCode); | |
115 frame.final = final; | |
116 frame.compress = compress; | |
117 frame.reserved2 = reserved2; | |
118 frame.reserved3 = reserved3; | |
119 frame.masked = masked; | |
120 frame.payload = p + maskingKeyLength; | |
121 frame.payloadLength = payloadLength; | |
122 frameEnd = p + maskingKeyLength + payloadLength; | |
123 return FrameOK; | |
124 } | |
125 | |
126 static void appendFramePayload(const WebSocketFrame& frame, Vector<char>& frameD
ata) | |
127 { | |
128 size_t maskingKeyStart = 0; | |
129 if (frame.masked) { | |
130 maskingKeyStart = frameData.size(); | |
131 frameData.grow(frameData.size() + maskingKeyWidthInBytes); // Add placeh
older for masking key. Will be overwritten. | |
132 } | |
133 | |
134 size_t payloadStart = frameData.size(); | |
135 frameData.append(frame.payload, frame.payloadLength); | |
136 | |
137 if (frame.masked) { | |
138 cryptographicallyRandomValues(frameData.data() + maskingKeyStart, maskin
gKeyWidthInBytes); | |
139 for (size_t i = 0; i < frame.payloadLength; ++i) | |
140 frameData[payloadStart + i] ^= frameData[maskingKeyStart + i % maski
ngKeyWidthInBytes]; | |
141 } | |
142 } | |
143 | |
144 void WebSocketFrame::makeFrameData(Vector<char>& frameData) | |
145 { | |
146 ASSERT(!(opCode & ~opCodeMask)); // Checks whether "opCode" fits in the rang
e of opCodes. | |
147 | |
148 frameData.resize(2); | |
149 frameData.at(0) = (final ? finalBit : 0) | (compress ? compressBit : 0) | op
Code; | |
150 frameData.at(1) = masked ? maskBit : 0; | |
151 | |
152 if (payloadLength <= maxPayloadLengthWithoutExtendedLengthField) | |
153 frameData.at(1) |= payloadLength; | |
154 else if (payloadLength <= 0xFFFF) { | |
155 frameData.at(1) |= payloadLengthWithTwoByteExtendedLengthField; | |
156 frameData.append((payloadLength & 0xFF00) >> 8); | |
157 frameData.append(payloadLength & 0xFF); | |
158 } else { | |
159 frameData.at(1) |= payloadLengthWithEightByteExtendedLengthField; | |
160 char extendedPayloadLength[8]; | |
161 size_t remaining = payloadLength; | |
162 // Fill the length into extendedPayloadLength in the network byte order. | |
163 for (int i = 0; i < 8; ++i) { | |
164 extendedPayloadLength[7 - i] = remaining & 0xFF; | |
165 remaining >>= 8; | |
166 } | |
167 ASSERT(!remaining); | |
168 frameData.append(extendedPayloadLength, 8); | |
169 } | |
170 | |
171 appendFramePayload(*this, frameData); | |
172 } | |
173 | |
174 WebSocketFrame::WebSocketFrame() | |
175 : opCode(OpCodeInvalid) | |
176 , final(false) | |
177 , compress(false) | |
178 , reserved2(false) | |
179 , reserved3(false) | |
180 , masked(false) | |
181 , payload(0) | |
182 , payloadLength(0) | |
183 { | |
184 } | |
185 | |
186 WebSocketFrame::WebSocketFrame(OpCode opCode, const char* payload, size_t payloa
dLength, Flags flags) | 29 WebSocketFrame::WebSocketFrame(OpCode opCode, const char* payload, size_t payloa
dLength, Flags flags) |
187 : opCode(opCode) | 30 : opCode(opCode) |
188 , final(flags & Final) | 31 , final(flags & Final) |
189 , compress(flags & Compress) | 32 , compress(flags & Compress) |
190 , reserved2(flags & Reserved2) | 33 , reserved2(flags & Reserved2) |
191 , reserved3(flags & Reserved3) | 34 , reserved3(flags & Reserved3) |
192 , masked(flags & Masked) | 35 , masked(flags & Masked) |
193 , payload(payload) | 36 , payload(payload) |
194 , payloadLength(payloadLength) | 37 , payloadLength(payloadLength) |
195 { | 38 { |
196 } | 39 } |
197 | 40 |
198 } // namespace blink | 41 } // namespace blink |
OLD | NEW |