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#if ENABLE(WEB_SOCKETS)
26
27#include "WebSocketFrame.h"
28
29#include <wtf/CryptographicallyRandomNumber.h>
30#include <wtf/MathExtras.h>
31
32namespace WebCore {
33
34// Constants for hybi-10 frame format.
35const unsigned char finalBit = 0x80;
36const unsigned char compressBit = 0x40;
37const unsigned char reserved2Bit = 0x20;
38const unsigned char reserved3Bit = 0x10;
39const unsigned char opCodeMask = 0xF;
40const unsigned char maskBit = 0x80;
41const unsigned char payloadLengthMask = 0x7F;
42const size_t maxPayloadLengthWithoutExtendedLengthField = 125;
43const size_t payloadLengthWithTwoByteExtendedLengthField = 126;
44const size_t payloadLengthWithEightByteExtendedLengthField = 127;
45const size_t maskingKeyWidthInBytes = 4;
46
47bool WebSocketFrame::needsExtendedLengthField(size_t payloadLength)
48{
49    return payloadLength > maxPayloadLengthWithoutExtendedLengthField;
50}
51
52WebSocketFrame::ParseFrameResult WebSocketFrame::parseFrame(char* data, size_t dataLength, 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 == payloadLengthWithEightByteExtendedLengthField);
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 <= maxPayloadLengthWithoutExtendedLengthField) {
87            errorString = "The minimal number of bytes MUST be used to encode the length";
88            return FrameError;
89        }
90        if (extendedPayloadLengthSize == 8 && payloadLength64 <= 0xFFFF) {
91            errorString = "The minimal number of bytes MUST be used to encode the 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(payloadLength64) + " 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
126static void appendFramePayload(const WebSocketFrame& frame, Vector<char>& frameData)
127{
128    size_t maskingKeyStart = 0;
129    if (frame.masked) {
130        maskingKeyStart = frameData.size();
131        frameData.grow(frameData.size() + maskingKeyWidthInBytes); // Add placeholder 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, maskingKeyWidthInBytes);
139        for (size_t i = 0; i < frame.payloadLength; ++i)
140            frameData[payloadStart + i] ^= frameData[maskingKeyStart + i % maskingKeyWidthInBytes];
141    }
142}
143
144void WebSocketFrame::makeFrameData(Vector<char>& frameData)
145{
146    ASSERT(!(opCode & ~opCodeMask)); // Checks whether "opCode" fits in the range of opCodes.
147
148    frameData.resize(2);
149    frameData.at(0) = (final ? finalBit : 0) | (compress ? compressBit : 0) | opCode;
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
174WebSocketFrame::WebSocketFrame(OpCode opCode, bool final, bool compress, bool masked, const char* payload, size_t payloadLength)
175    : opCode(opCode)
176    , final(final)
177    , compress(compress)
178    , reserved2(false)
179    , reserved3(false)
180    , masked(masked)
181    , payload(payload)
182    , payloadLength(payloadLength)
183{
184}
185
186} // namespace WebCore
187
188#endif // ENABLE(WEB_SOCKETS)
189