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 49 bool WebSocketFrame::needsExtendedLengthField(size_t payloadLength) 50 { 51 return payloadLength > maxPayloadLengthWithoutExtendedLengthField; 52 } 53 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 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 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 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 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