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