Home | History | Annotate | Download | only in websockets
      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