• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "modules/websockets/WebSocketFrame.h"
26 
27 #include "wtf/CryptographicallyRandomNumber.h"
28 #include "wtf/MathExtras.h"
29 
30 using namespace std;
31 
32 namespace WebCore {
33 
34 // Constants for hybi-10 frame format.
35 // These are bitmasks for frame composition / decomposition.
36 // Do not mistake these constants for the flags given to the WebSocketFrame constructor.
37 const unsigned char finalBit = 0x80;
38 const unsigned char compressBit = 0x40;
39 const unsigned char reserved2Bit = 0x20;
40 const unsigned char reserved3Bit = 0x10;
41 const unsigned char opCodeMask = 0xF;
42 const unsigned char maskBit = 0x80;
43 const unsigned char payloadLengthMask = 0x7F;
44 const size_t maxPayloadLengthWithoutExtendedLengthField = 125;
45 const size_t payloadLengthWithTwoByteExtendedLengthField = 126;
46 const size_t payloadLengthWithEightByteExtendedLengthField = 127;
47 const size_t maskingKeyWidthInBytes = 4;
48 
needsExtendedLengthField(size_t payloadLength)49 bool WebSocketFrame::needsExtendedLengthField(size_t payloadLength)
50 {
51     return payloadLength > maxPayloadLengthWithoutExtendedLengthField;
52 }
53 
parseFrame(char * data,size_t dataLength,WebSocketFrame & frame,const char * & frameEnd,String & errorString)54 WebSocketFrame::ParseFrameResult WebSocketFrame::parseFrame(char* data, size_t dataLength, WebSocketFrame& frame, const char*& frameEnd, String& errorString)
55 {
56     char* p = data;
57     const char* bufferEnd = data + dataLength;
58 
59     if (dataLength < 2)
60         return FrameIncomplete;
61 
62     unsigned char firstByte = *p++;
63     unsigned char secondByte = *p++;
64 
65     bool final = firstByte & finalBit;
66     bool compress = firstByte & compressBit;
67     bool reserved2 = firstByte & reserved2Bit;
68     bool reserved3 = firstByte & reserved3Bit;
69     unsigned char opCode = firstByte & opCodeMask;
70 
71     bool masked = secondByte & maskBit;
72     uint64_t payloadLength64 = secondByte & payloadLengthMask;
73     if (payloadLength64 > maxPayloadLengthWithoutExtendedLengthField) {
74         int extendedPayloadLengthSize;
75         if (payloadLength64 == payloadLengthWithTwoByteExtendedLengthField)
76             extendedPayloadLengthSize = 2;
77         else {
78             ASSERT(payloadLength64 == payloadLengthWithEightByteExtendedLengthField);
79             extendedPayloadLengthSize = 8;
80         }
81         if (bufferEnd - p < extendedPayloadLengthSize)
82             return FrameIncomplete;
83         payloadLength64 = 0;
84         for (int i = 0; i < extendedPayloadLengthSize; ++i) {
85             payloadLength64 <<= 8;
86             payloadLength64 |= static_cast<unsigned char>(*p++);
87         }
88         if (extendedPayloadLengthSize == 2 && payloadLength64 <= maxPayloadLengthWithoutExtendedLengthField) {
89             errorString = "The minimal number of bytes MUST be used to encode the length";
90             return FrameError;
91         }
92         if (extendedPayloadLengthSize == 8 && payloadLength64 <= 0xFFFF) {
93             errorString = "The minimal number of bytes MUST be used to encode the length";
94             return FrameError;
95         }
96     }
97 
98     static const uint64_t maxPayloadLength = UINT64_C(0x7FFFFFFFFFFFFFFF);
99     size_t maskingKeyLength = masked ? maskingKeyWidthInBytes : 0;
100     if (payloadLength64 > maxPayloadLength || payloadLength64 + maskingKeyLength > numeric_limits<size_t>::max()) {
101         errorString = "WebSocket frame length too large: " + String::number(payloadLength64) + " bytes";
102         return FrameError;
103     }
104     size_t payloadLength = static_cast<size_t>(payloadLength64);
105 
106     if (static_cast<size_t>(bufferEnd - p) < maskingKeyLength + payloadLength)
107         return FrameIncomplete;
108 
109     if (masked) {
110         const char* maskingKey = p;
111         char* payload = p + maskingKeyWidthInBytes;
112         for (size_t i = 0; i < payloadLength; ++i)
113             payload[i] ^= maskingKey[i % maskingKeyWidthInBytes]; // Unmask the payload.
114     }
115 
116     frame.opCode = static_cast<WebSocketFrame::OpCode>(opCode);
117     frame.final = final;
118     frame.compress = compress;
119     frame.reserved2 = reserved2;
120     frame.reserved3 = reserved3;
121     frame.masked = masked;
122     frame.payload = p + maskingKeyLength;
123     frame.payloadLength = payloadLength;
124     frameEnd = p + maskingKeyLength + payloadLength;
125     return FrameOK;
126 }
127 
appendFramePayload(const WebSocketFrame & frame,Vector<char> & frameData)128 static void appendFramePayload(const WebSocketFrame& frame, Vector<char>& frameData)
129 {
130     size_t maskingKeyStart = 0;
131     if (frame.masked) {
132         maskingKeyStart = frameData.size();
133         frameData.grow(frameData.size() + maskingKeyWidthInBytes); // Add placeholder for masking key. Will be overwritten.
134     }
135 
136     size_t payloadStart = frameData.size();
137     frameData.append(frame.payload, frame.payloadLength);
138 
139     if (frame.masked) {
140         cryptographicallyRandomValues(frameData.data() + maskingKeyStart, maskingKeyWidthInBytes);
141         for (size_t i = 0; i < frame.payloadLength; ++i)
142             frameData[payloadStart + i] ^= frameData[maskingKeyStart + i % maskingKeyWidthInBytes];
143     }
144 }
145 
makeFrameData(Vector<char> & frameData)146 void WebSocketFrame::makeFrameData(Vector<char>& frameData)
147 {
148     ASSERT(!(opCode & ~opCodeMask)); // Checks whether "opCode" fits in the range of opCodes.
149 
150     frameData.resize(2);
151     frameData.at(0) = (final ? finalBit : 0) | (compress ? compressBit : 0) | opCode;
152     frameData.at(1) = masked ? maskBit : 0;
153 
154     if (payloadLength <= maxPayloadLengthWithoutExtendedLengthField)
155         frameData.at(1) |= payloadLength;
156     else if (payloadLength <= 0xFFFF) {
157         frameData.at(1) |= payloadLengthWithTwoByteExtendedLengthField;
158         frameData.append((payloadLength & 0xFF00) >> 8);
159         frameData.append(payloadLength & 0xFF);
160     } else {
161         frameData.at(1) |= payloadLengthWithEightByteExtendedLengthField;
162         char extendedPayloadLength[8];
163         size_t remaining = payloadLength;
164         // Fill the length into extendedPayloadLength in the network byte order.
165         for (int i = 0; i < 8; ++i) {
166             extendedPayloadLength[7 - i] = remaining & 0xFF;
167             remaining >>= 8;
168         }
169         ASSERT(!remaining);
170         frameData.append(extendedPayloadLength, 8);
171     }
172 
173     appendFramePayload(*this, frameData);
174 }
175 
WebSocketFrame()176 WebSocketFrame::WebSocketFrame()
177     : opCode(OpCodeInvalid)
178     , final(false)
179     , compress(false)
180     , reserved2(false)
181     , reserved3(false)
182     , masked(false)
183     , payload(0)
184     , payloadLength(0)
185 {
186 }
187 
WebSocketFrame(OpCode opCode,const char * payload,size_t payloadLength,Flags flags)188 WebSocketFrame::WebSocketFrame(OpCode opCode, const char* payload, size_t payloadLength, Flags flags)
189     : opCode(opCode)
190     , final(flags & Final)
191     , compress(flags & Compress)
192     , reserved2(flags & Reserved2)
193     , reserved3(flags & Reserved3)
194     , masked(flags & Masked)
195     , payload(payload)
196     , payloadLength(payloadLength)
197 {
198 }
199 
200 } // namespace WebCore
201