Expose reusable WebSocket code for WebSocketServer.
authorjocelyn.turcotte@nokia.com <jocelyn.turcotte@nokia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Apr 2012 13:23:46 +0000 (13:23 +0000)
committerjocelyn.turcotte@nokia.com <jocelyn.turcotte@nokia.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Apr 2012 13:23:46 +0000 (13:23 +0000)
https://bugs.webkit.org/show_bug.cgi?id=73852

Reviewed by Kent Tamura.

Keep the majority the web socket handshake HTTP request and response logic
inside WebSocketHandshake and expose it through WebSocketFrame to make it
available for the web socket server implementation.

This also re-add the masking code that was removed in r111829 since it is
needed for the server implementation.

* CMakeLists.txt:
* GNUmakefile.list.am:
* Modules/websockets/WebSocketChannel.cpp:
(WebCore):
(WebCore::WebSocketChannel::processFrame): now using WebSocketChannel::parseFrame. Extracted the !frame.masked check.
(WebCore::WebSocketChannel::sendFrame):
* Modules/websockets/WebSocketChannel.h:
(WebSocketChannel):
* Modules/websockets/WebSocketFrame.cpp: Added.
(WebCore):
(WebCore::WebSocketFrame::needsExtendedLengthField):
(WebCore::WebSocketFrame::parseFrame): moved from WebSocketChannel::parseFrame.
(WebCore::appendMaskedFramePayload):
(WebCore::WebSocketFrame::makeFrameData): moved from makeFrameData in WebSocketChannel.cpp.
(WebCore::WebSocketFrame::WebSocketFrame): moved from the header.
* Modules/websockets/WebSocketFrame.h:
(WebSocketFrame):
* Modules/websockets/WebSocketHandshake.cpp:
(WebCore::WebSocketHandshake::getExpectedWebSocketAccept): expose this object-static function.
* Modules/websockets/WebSocketHandshake.h:
* Target.pri:
* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@113025 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Modules/websockets/WebSocketChannel.cpp
Source/WebCore/Modules/websockets/WebSocketChannel.h
Source/WebCore/Modules/websockets/WebSocketFrame.cpp [new file with mode: 0644]
Source/WebCore/Modules/websockets/WebSocketFrame.h
Source/WebCore/Modules/websockets/WebSocketHandshake.cpp
Source/WebCore/Modules/websockets/WebSocketHandshake.h
Source/WebCore/Target.pri
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj

index 05fa0af..3c4cd44 100644 (file)
@@ -2131,6 +2131,7 @@ IF (ENABLE_WEB_SOCKETS)
         Modules/websockets/WebSocketDeflater.cpp
         Modules/websockets/WebSocketDeflateFramer.cpp
         Modules/websockets/WebSocketExtensionDispatcher.cpp
+        Modules/websockets/WebSocketFrame.cpp
         Modules/websockets/WebSocketHandshake.cpp
         Modules/websockets/WebSocketHandshakeRequest.cpp
         Modules/websockets/WebSocketHandshakeResponse.cpp
index 1a933ba..f835928 100644 (file)
@@ -1,3 +1,42 @@
+2012-04-01  Jocelyn Turcotte  <jocelyn.turcotte@nokia.com>
+
+        Expose reusable WebSocket code for WebSocketServer.
+        https://bugs.webkit.org/show_bug.cgi?id=73852
+
+        Reviewed by Kent Tamura.
+
+        Keep the majority the web socket handshake HTTP request and response logic
+        inside WebSocketHandshake and expose it through WebSocketFrame to make it
+        available for the web socket server implementation.
+
+        This also re-add the masking code that was removed in r111829 since it is
+        needed for the server implementation.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * Modules/websockets/WebSocketChannel.cpp:
+        (WebCore):
+        (WebCore::WebSocketChannel::processFrame): now using WebSocketChannel::parseFrame. Extracted the !frame.masked check.
+        (WebCore::WebSocketChannel::sendFrame):
+        * Modules/websockets/WebSocketChannel.h:
+        (WebSocketChannel):
+        * Modules/websockets/WebSocketFrame.cpp: Added.
+        (WebCore):
+        (WebCore::WebSocketFrame::needsExtendedLengthField):
+        (WebCore::WebSocketFrame::parseFrame): moved from WebSocketChannel::parseFrame.
+        (WebCore::appendMaskedFramePayload):
+        (WebCore::WebSocketFrame::makeFrameData): moved from makeFrameData in WebSocketChannel.cpp.
+        (WebCore::WebSocketFrame::WebSocketFrame): moved from the header.
+        * Modules/websockets/WebSocketFrame.h:
+        (WebSocketFrame):
+        * Modules/websockets/WebSocketHandshake.cpp:
+        (WebCore::WebSocketHandshake::getExpectedWebSocketAccept): expose this object-static function.
+        * Modules/websockets/WebSocketHandshake.h:
+        * Target.pri:
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+
 2012-03-29  Joseph Pecoraro  <joepeck@webkit.org> and Jocelyn Turcotte  <jocelyn.turcotte@nokia.com>
 
         Add Generic HTTP Request Class. Generalized HTTP Parsing.
index 672f5b0..401d303 100644 (file)
@@ -1210,6 +1210,7 @@ webcore_sources += \
        Source/WebCore/Modules/websockets/WebSocketExtensionDispatcher.cpp \
        Source/WebCore/Modules/websockets/WebSocketExtensionDispatcher.h \
        Source/WebCore/Modules/websockets/WebSocketExtensionProcessor.h \
+       Source/WebCore/Modules/websockets/WebSocketFrame.cpp \
        Source/WebCore/Modules/websockets/WebSocketFrame.h \
        Source/WebCore/Modules/websockets/WebSocketHandshake.cpp \
        Source/WebCore/Modules/websockets/WebSocketHandshake.h \
index 7156953..8f9b675 100644 (file)
@@ -55,7 +55,6 @@
 #include "WebSocketHandshake.h"
 
 #include <wtf/ArrayBuffer.h>
-#include <wtf/CryptographicallyRandomNumber.h>
 #include <wtf/Deque.h>
 #include <wtf/FastMalloc.h>
 #include <wtf/HashMap.h>
@@ -71,19 +70,6 @@ namespace WebCore {
 
 const double TCPMaximumSegmentLifetime = 2 * 60.0;
 
-// Constants for hybi-10 frame format.
-const unsigned char finalBit = 0x80;
-const unsigned char compressBit = 0x40;
-const unsigned char reserved2Bit = 0x20;
-const unsigned char reserved3Bit = 0x10;
-const unsigned char opCodeMask = 0xF;
-const unsigned char maskBit = 0x80;
-const unsigned char payloadLengthMask = 0x7F;
-const size_t maxPayloadLengthWithoutExtendedLengthField = 125;
-const size_t payloadLengthWithTwoByteExtendedLengthField = 126;
-const size_t payloadLengthWithEightByteExtendedLengthField = 127;
-const size_t maskingKeyWidthInBytes = 4;
-
 WebSocketChannel::WebSocketChannel(Document* document, WebSocketChannelClient* client)
     : m_document(document)
     , m_client(client)
@@ -551,80 +537,6 @@ void WebSocketChannel::closingTimerFired(Timer<WebSocketChannel>* timer)
         m_handle->disconnect();
 }
 
-WebSocketChannel::ParseFrameResult WebSocketChannel::parseFrame(WebSocketFrame& frame, const char*& frameEnd)
-{
-    const char* p = m_buffer;
-    const char* bufferEnd = m_buffer + m_bufferSize;
-
-    if (m_bufferSize < 2)
-        return FrameIncomplete;
-
-    unsigned char firstByte = *p++;
-    unsigned char secondByte = *p++;
-
-    bool final = firstByte & finalBit;
-    bool compress = firstByte & compressBit;
-    bool reserved2 = firstByte & reserved2Bit;
-    bool reserved3 = firstByte & reserved3Bit;
-    unsigned char opCode = firstByte & opCodeMask;
-
-    bool masked = secondByte & maskBit;
-    if (masked) {
-        fail("A server must not mask any frames that it sends to the client.");
-        return FrameError;
-    }
-    uint64_t payloadLength64 = secondByte & payloadLengthMask;
-    if (payloadLength64 > maxPayloadLengthWithoutExtendedLengthField) {
-        int extendedPayloadLengthSize;
-        if (payloadLength64 == payloadLengthWithTwoByteExtendedLengthField)
-            extendedPayloadLengthSize = 2;
-        else {
-            ASSERT(payloadLength64 == payloadLengthWithEightByteExtendedLengthField);
-            extendedPayloadLengthSize = 8;
-        }
-        if (bufferEnd - p < extendedPayloadLengthSize)
-            return FrameIncomplete;
-        payloadLength64 = 0;
-        for (int i = 0; i < extendedPayloadLengthSize; ++i) {
-            payloadLength64 <<= 8;
-            payloadLength64 |= static_cast<unsigned char>(*p++);
-        }
-        if (extendedPayloadLengthSize == 2 && payloadLength64 <= maxPayloadLengthWithoutExtendedLengthField) {
-            fail("The minimal number of bytes MUST be used to encode the length");
-            return FrameError;
-        }
-        if (extendedPayloadLengthSize == 8 && payloadLength64 <= 0xFFFF) {
-            fail("The minimal number of bytes MUST be used to encode the length");
-            return FrameError;
-        }
-    }
-
-    // FIXME: UINT64_C(0x7FFFFFFFFFFFFFFF) should be used but it did not compile on Qt bots.
-#if COMPILER(MSVC)
-    static const uint64_t maxPayloadLength = 0x7FFFFFFFFFFFFFFFui64;
-#else
-    static const uint64_t maxPayloadLength = 0x7FFFFFFFFFFFFFFFull;
-#endif
-    if (payloadLength64 > maxPayloadLength || payloadLength64 > numeric_limits<size_t>::max()) {
-        fail("WebSocket frame length too large: " + String::number(payloadLength64) + " bytes");
-        return FrameError;
-    }
-    size_t payloadLength = static_cast<size_t>(payloadLength64);
-
-    if (static_cast<size_t>(bufferEnd - p) < payloadLength)
-        return FrameIncomplete;
-
-    frame.opCode = static_cast<WebSocketFrame::OpCode>(opCode);
-    frame.final = final;
-    frame.compress = compress;
-    frame.reserved2 = reserved2;
-    frame.reserved3 = reserved3;
-    frame.masked = masked;
-    frame.payload = p;
-    frame.payloadLength = payloadLength;
-    frameEnd = p + payloadLength;
-    return FrameOK;
-}
 
 bool WebSocketChannel::processFrame()
 {
@@ -632,8 +544,14 @@ bool WebSocketChannel::processFrame()
 
     WebSocketFrame frame;
     const char* frameEnd;
-    if (parseFrame(frame, frameEnd) != FrameOK)
+    String errorString;
+    WebSocketFrame::ParseFrameResult result = WebSocketFrame::parseFrame(m_buffer, m_bufferSize, frame, frameEnd, errorString);
+    if (result == WebSocketFrame::FrameIncomplete)
+        return false;
+    if (result == WebSocketFrame::FrameError) {
+        fail(errorString);
         return false;
+    }
 
     ASSERT(m_buffer < frameEnd);
     ASSERT(frameEnd <= m_buffer + m_bufferSize);
@@ -655,6 +573,11 @@ bool WebSocketChannel::processFrame()
         return false;
     }
 
+    if (frame.masked) {
+        fail("A server must not mask any frames that it sends to the client.");
+        return false;
+    }
+
     // All control frames must not be fragmented.
     if (WebSocketFrame::isControlOpCode(frame.opCode) && !frame.final) {
         fail("Received fragmented control frame: opcode = " + String::number(frame.opCode));
@@ -663,7 +586,7 @@ bool WebSocketChannel::processFrame()
 
     // All control frames must have a payload of 125 bytes or less, which means the frame must not contain
     // the "extended payload length" field.
-    if (WebSocketFrame::isControlOpCode(frame.opCode) && frame.payloadLength > maxPayloadLengthWithoutExtendedLengthField) {
+    if (WebSocketFrame::isControlOpCode(frame.opCode) && WebSocketFrame::needsExtendedLengthField(frame.payloadLength)) {
         fail("Received control frame having too long payload: " + String::number(frame.payloadLength) + " bytes");
         return false;
     }
@@ -989,52 +912,11 @@ void WebSocketChannel::abortOutgoingFrameQueue()
 #endif
 }
 
-static void appendMaskedFramePayload(const WebSocketFrame& frame, Vector<char>& frameData)
-{
-    size_t maskingKeyStart = frameData.size();
-    frameData.grow(frameData.size() + maskingKeyWidthInBytes); // Add placeholder for masking key. Will be overwritten.
-    size_t payloadStart = frameData.size();
-    frameData.append(frame.payload, frame.payloadLength);
-
-    cryptographicallyRandomValues(frameData.data() + maskingKeyStart, maskingKeyWidthInBytes);
-    for (size_t i = 0; i < frame.payloadLength; ++i)
-        frameData[payloadStart + i] ^= frameData[maskingKeyStart + i % maskingKeyWidthInBytes];
-}
-
-static void makeFrameData(const WebSocketFrame& frame, Vector<char>& frameData)
-{
-    unsigned char firstByte = (frame.final ? finalBit : 0) | frame.opCode;
-    if (frame.compress)
-        firstByte |= compressBit;
-    frameData.append(firstByte);
-    if (frame.payloadLength <= maxPayloadLengthWithoutExtendedLengthField)
-        frameData.append(maskBit | frame.payloadLength);
-    else if (frame.payloadLength <= 0xFFFF) {
-        frameData.append(maskBit | payloadLengthWithTwoByteExtendedLengthField);
-        frameData.append((frame.payloadLength & 0xFF00) >> 8);
-        frameData.append(frame.payloadLength & 0xFF);
-    } else {
-        frameData.append(maskBit | payloadLengthWithEightByteExtendedLengthField);
-        char extendedPayloadLength[8];
-        size_t remaining = frame.payloadLength;
-        // Fill the length into extendedPayloadLength in the network byte order.
-        for (int i = 0; i < 8; ++i) {
-            extendedPayloadLength[7 - i] = remaining & 0xFF;
-            remaining >>= 8;
-        }
-        ASSERT(!remaining);
-        frameData.append(extendedPayloadLength, 8);
-    }
-
-    appendMaskedFramePayload(frame, frameData);
-}
-
 bool WebSocketChannel::sendFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength)
 {
     ASSERT(m_handle);
     ASSERT(!m_suspended);
 
-    ASSERT(!(opCode & ~opCodeMask)); // Checks whether "opCode" fits in the range of opCodes.
     WebSocketFrame frame(opCode, true, false, true, data, dataLength);
 
     OwnPtr<DeflateResultHolder> deflateResult = m_deflateFramer.deflate(frame);
@@ -1044,7 +926,7 @@ bool WebSocketChannel::sendFrame(WebSocketFrame::OpCode opCode, const char* data
     }
 
     Vector<char> frameData;
-    makeFrameData(frame, frameData);
+    frame.makeFrameData(frameData);
 
     return m_handle->send(frameData.data(), frameData.size());
 }
index 542871e..0b7607f 100644 (file)
@@ -132,14 +132,6 @@ private:
     void startClosingHandshake(int code, const String& reason);
     void closingTimerFired(Timer<WebSocketChannel>*);
 
-    enum ParseFrameResult {
-        FrameOK,
-        FrameIncomplete,
-        FrameError
-    };
-
-    ParseFrameResult parseFrame(WebSocketFrame&, const char*& frameEnd);
-
     bool processFrame();
     bool processFrameHixie76();
 
diff --git a/Source/WebCore/Modules/websockets/WebSocketFrame.cpp b/Source/WebCore/Modules/websockets/WebSocketFrame.cpp
new file mode 100644 (file)
index 0000000..1211cb9
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2011 Google Inc.  All rights reserved.
+ * Copyright (C) Research In Motion Limited 2011. All rights reserved.
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this program; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_SOCKETS)
+
+#include "WebSocketFrame.h"
+
+#include <wtf/CryptographicallyRandomNumber.h>
+
+using namespace std;
+
+namespace WebCore {
+
+// Constants for hybi-10 frame format.
+const unsigned char finalBit = 0x80;
+const unsigned char compressBit = 0x40;
+const unsigned char reserved2Bit = 0x20;
+const unsigned char reserved3Bit = 0x10;
+const unsigned char opCodeMask = 0xF;
+const unsigned char maskBit = 0x80;
+const unsigned char payloadLengthMask = 0x7F;
+const size_t maxPayloadLengthWithoutExtendedLengthField = 125;
+const size_t payloadLengthWithTwoByteExtendedLengthField = 126;
+const size_t payloadLengthWithEightByteExtendedLengthField = 127;
+const size_t maskingKeyWidthInBytes = 4;
+
+bool WebSocketFrame::needsExtendedLengthField(size_t payloadLength)
+{
+    return payloadLength > maxPayloadLengthWithoutExtendedLengthField;
+}
+
+WebSocketFrame::ParseFrameResult WebSocketFrame::parseFrame(char* data, size_t dataLength, WebSocketFrame& frame, const char*& frameEnd, String& errorString)
+{
+    char* p = data;
+    const char* bufferEnd = data + dataLength;
+
+    if (dataLength < 2)
+        return FrameIncomplete;
+
+    unsigned char firstByte = *p++;
+    unsigned char secondByte = *p++;
+
+    bool final = firstByte & finalBit;
+    bool compress = firstByte & compressBit;
+    bool reserved2 = firstByte & reserved2Bit;
+    bool reserved3 = firstByte & reserved3Bit;
+    unsigned char opCode = firstByte & opCodeMask;
+
+    bool masked = secondByte & maskBit;
+    uint64_t payloadLength64 = secondByte & payloadLengthMask;
+    if (payloadLength64 > maxPayloadLengthWithoutExtendedLengthField) {
+        int extendedPayloadLengthSize;
+        if (payloadLength64 == payloadLengthWithTwoByteExtendedLengthField)
+            extendedPayloadLengthSize = 2;
+        else {
+            ASSERT(payloadLength64 == payloadLengthWithEightByteExtendedLengthField);
+            extendedPayloadLengthSize = 8;
+        }
+        if (bufferEnd - p < extendedPayloadLengthSize)
+            return FrameIncomplete;
+        payloadLength64 = 0;
+        for (int i = 0; i < extendedPayloadLengthSize; ++i) {
+            payloadLength64 <<= 8;
+            payloadLength64 |= static_cast<unsigned char>(*p++);
+        }
+        if (extendedPayloadLengthSize == 2 && payloadLength64 <= maxPayloadLengthWithoutExtendedLengthField) {
+            errorString = "The minimal number of bytes MUST be used to encode the length";
+            return FrameError;
+        }
+        if (extendedPayloadLengthSize == 8 && payloadLength64 <= 0xFFFF) {
+            errorString = "The minimal number of bytes MUST be used to encode the length";
+            return FrameError;
+        }
+    }
+
+    // FIXME: UINT64_C(0x7FFFFFFFFFFFFFFF) should be used but it did not compile on Qt bots.
+#if COMPILER(MSVC)
+    static const uint64_t maxPayloadLength = 0x7FFFFFFFFFFFFFFFui64;
+#else
+    static const uint64_t maxPayloadLength = 0x7FFFFFFFFFFFFFFFull;
+#endif
+    size_t maskingKeyLength = masked ? maskingKeyWidthInBytes : 0;
+    if (payloadLength64 > maxPayloadLength || payloadLength64 + maskingKeyLength > numeric_limits<size_t>::max()) {
+        errorString = "WebSocket frame length too large: " + String::number(payloadLength64) + " bytes";
+        return FrameError;
+    }
+    size_t payloadLength = static_cast<size_t>(payloadLength64);
+
+    if (static_cast<size_t>(bufferEnd - p) < maskingKeyLength + payloadLength)
+        return FrameIncomplete;
+
+    if (masked) {
+        const char* maskingKey = p;
+        char* payload = p + maskingKeyWidthInBytes;
+        for (size_t i = 0; i < payloadLength; ++i)
+            payload[i] ^= maskingKey[i % maskingKeyWidthInBytes]; // Unmask the payload.
+    }
+
+    frame.opCode = static_cast<WebSocketFrame::OpCode>(opCode);
+    frame.final = final;
+    frame.compress = compress;
+    frame.reserved2 = reserved2;
+    frame.reserved3 = reserved3;
+    frame.masked = masked;
+    frame.payload = p + maskingKeyLength;
+    frame.payloadLength = payloadLength;
+    frameEnd = p + maskingKeyLength + payloadLength;
+    return FrameOK;
+}
+
+static void appendMaskedFramePayload(const WebSocketFrame& frame, Vector<char>& frameData)
+{
+    size_t maskingKeyStart = frameData.size();
+    frameData.grow(frameData.size() + maskingKeyWidthInBytes); // Add placeholder for masking key. Will be overwritten.
+    size_t payloadStart = frameData.size();
+    frameData.append(frame.payload, frame.payloadLength);
+
+    cryptographicallyRandomValues(frameData.data() + maskingKeyStart, maskingKeyWidthInBytes);
+    for (size_t i = 0; i < frame.payloadLength; ++i)
+        frameData[payloadStart + i] ^= frameData[maskingKeyStart + i % maskingKeyWidthInBytes];
+}
+
+void WebSocketFrame::makeFrameData(Vector<char>& frameData)
+{
+    ASSERT(!(opCode & ~opCodeMask)); // Checks whether "opCode" fits in the range of opCodes.
+
+    unsigned char firstByte = (final ? finalBit : 0) | opCode;
+    if (compress)
+        firstByte |= compressBit;
+    frameData.append(firstByte);
+    if (payloadLength <= maxPayloadLengthWithoutExtendedLengthField)
+        frameData.append(maskBit | payloadLength);
+    else if (payloadLength <= 0xFFFF) {
+        frameData.append(maskBit | payloadLengthWithTwoByteExtendedLengthField);
+        frameData.append((payloadLength & 0xFF00) >> 8);
+        frameData.append(payloadLength & 0xFF);
+    } else {
+        frameData.append(maskBit | payloadLengthWithEightByteExtendedLengthField);
+        char extendedPayloadLength[8];
+        size_t remaining = payloadLength;
+        // Fill the length into extendedPayloadLength in the network byte order.
+        for (int i = 0; i < 8; ++i) {
+            extendedPayloadLength[7 - i] = remaining & 0xFF;
+            remaining >>= 8;
+        }
+        ASSERT(!remaining);
+        frameData.append(extendedPayloadLength, 8);
+    }
+
+    appendMaskedFramePayload(*this, frameData);
+}
+
+WebSocketFrame::WebSocketFrame(OpCode opCode, bool final, bool compress, bool masked, const char* payload, size_t payloadLength)
+    : opCode(opCode)
+    , final(final)
+    , compress(compress)
+    , reserved2(false)
+    , reserved3(false)
+    , masked(masked)
+    , payload(payload)
+    , payloadLength(payloadLength)
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_SOCKETS)
index 7efea78..c189362 100644 (file)
@@ -33,6 +33,8 @@
 
 #if ENABLE(WEB_SOCKETS)
 
+#include <wtf/text/WTFString.h>
+
 namespace WebCore {
 
 struct WebSocketFrame {
@@ -47,21 +49,20 @@ struct WebSocketFrame {
         OpCodeInvalid = 0x10
     };
 
+    enum ParseFrameResult {
+        FrameOK,
+        FrameIncomplete,
+        FrameError
+    };
+
     static bool isNonControlOpCode(OpCode opCode) { return opCode == OpCodeContinuation || opCode == OpCodeText || opCode == OpCodeBinary; }
     static bool isControlOpCode(OpCode opCode) { return opCode == OpCodeClose || opCode == OpCodePing || opCode == OpCodePong; }
     static bool isReservedOpCode(OpCode opCode) { return !isNonControlOpCode(opCode) && !isControlOpCode(opCode); }
+    static bool needsExtendedLengthField(size_t payloadLength);
+    static ParseFrameResult parseFrame(char* data, size_t dataLength, WebSocketFrame&, const char*& frameEnd, String& errorString); // May modify part of data to unmask the frame.
 
-    WebSocketFrame(OpCode opCode = OpCodeInvalid, bool final = false, bool compress = false, bool masked = false, const char* payload = 0, size_t payloadLength = 0)
-        : opCode(opCode)
-        , final(final)
-        , compress(compress)
-        , reserved2(false)
-        , reserved3(false)
-        , masked(masked)
-        , payload(payload)
-        , payloadLength(payloadLength)
-    {
-    }
+    WebSocketFrame(OpCode = OpCodeInvalid, bool final = false, bool compress = false, bool masked = false, const char* payload = 0, size_t payloadLength = 0);
+    void makeFrameData(Vector<char>& frameData);
 
     OpCode opCode;
     bool final;
index 823a09e..30c0886 100644 (file)
@@ -171,7 +171,7 @@ static String generateSecWebSocketKey()
     return base64Encode(reinterpret_cast<char*>(key), nonceSize);
 }
 
-static String getExpectedWebSocketAccept(const String& secWebSocketKey)
+String WebSocketHandshake::getExpectedWebSocketAccept(const String& secWebSocketKey)
 {
     static const char* const webSocketKeyGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
     static const size_t sha1HashSize = 20; // FIXME: This should be defined in SHA1.h.
index b92cea0..21d1f3f 100644 (file)
@@ -90,6 +90,8 @@ public:
 
     void addExtensionProcessor(PassOwnPtr<WebSocketExtensionProcessor>);
 
+    static String getExpectedWebSocketAccept(const String& secWebSocketKey);
+
 private:
     KURL httpURLForAuthenticationAndCookies() const;
 
index af947f8..50e5165 100644 (file)
@@ -3723,6 +3723,7 @@ contains(DEFINES, ENABLE_WEB_SOCKETS=1) {
         Modules/websockets/WebSocketDeflateFramer.cpp \
         Modules/websockets/WebSocketDeflater.cpp \
         Modules/websockets/WebSocketExtensionDispatcher.cpp \
+        Modules/websockets/WebSocketFrame.cpp \
         Modules/websockets/WebSocketHandshake.cpp \
         Modules/websockets/WebSocketHandshakeRequest.cpp \
         Modules/websockets/WebSocketHandshakeResponse.cpp \
index 1004a5e..ba4630d 100644 (file)
             'Modules/websockets/WebSocketExtensionDispatcher.cpp',
             'Modules/websockets/WebSocketExtensionDispatcher.h',
             'Modules/websockets/WebSocketExtensionProcessor.h',
+            'Modules/websockets/WebSocketFrame.cpp',
             'Modules/websockets/WebSocketFrame.h',
             'Modules/websockets/WebSocketHandshake.cpp',
             'Modules/websockets/WebSocketHandshake.h',
index 2117902..9cebeba 100755 (executable)
                                        >
                                </File>
                                <File
+                                       RelativePath="..\Modules\websockets\WebSocketFrame.cpp"
+                                       >
+                               </File>
+                               <File
                                        RelativePath="..\Modules\websockets\WebSocketFrame.h"
                                        >
                                </File>
index 0db41b4..da01814 100644 (file)
                AA21ECCD0ABF0FC6002B834C /* CSSCursorImageValue.h in Headers */ = {isa = PBXBuildFile; fileRef = AA0978EE0ABAA6E100874480 /* CSSCursorImageValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
                AA4C3A760B2B1679002334A2 /* StyleElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AA4C3A740B2B1679002334A2 /* StyleElement.cpp */; };
                AA4C3A770B2B1679002334A2 /* StyleElement.h in Headers */ = {isa = PBXBuildFile; fileRef = AA4C3A750B2B1679002334A2 /* StyleElement.h */; };
+               AAF5B7B71524B6C50004CB49 /* WebSocketFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AAF5B7B11524B4BD0004CB49 /* WebSocketFrame.cpp */; };
                AB23A32709BBA7D00067CC53 /* BeforeTextInsertedEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB23A32509BBA7D00067CC53 /* BeforeTextInsertedEvent.cpp */; };
                AB23A32809BBA7D00067CC53 /* BeforeTextInsertedEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = AB23A32609BBA7D00067CC53 /* BeforeTextInsertedEvent.h */; };
                AB247A6C0AFD6383003FA5FD /* RenderSlider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AB247A6A0AFD6383003FA5FD /* RenderSlider.cpp */; };
                AA0978EE0ABAA6E100874480 /* CSSCursorImageValue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CSSCursorImageValue.h; sourceTree = "<group>"; };
                AA4C3A740B2B1679002334A2 /* StyleElement.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = StyleElement.cpp; sourceTree = "<group>"; };
                AA4C3A750B2B1679002334A2 /* StyleElement.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = StyleElement.h; sourceTree = "<group>"; };
+               AAF5B7B11524B4BD0004CB49 /* WebSocketFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebSocketFrame.cpp; path = Modules/websockets/WebSocketFrame.cpp; sourceTree = "<group>"; };
                AB23A32509BBA7D00067CC53 /* BeforeTextInsertedEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = BeforeTextInsertedEvent.cpp; sourceTree = "<group>"; };
                AB23A32609BBA7D00067CC53 /* BeforeTextInsertedEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BeforeTextInsertedEvent.h; sourceTree = "<group>"; };
                AB247A6A0AFD6383003FA5FD /* RenderSlider.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSlider.cpp; sourceTree = "<group>"; };
                                97AABD0714FA09D5007457AE /* WebSocketExtensionDispatcher.cpp */,
                                97AABD0814FA09D5007457AE /* WebSocketExtensionDispatcher.h */,
                                97AABD0914FA09D5007457AE /* WebSocketExtensionProcessor.h */,
+                               AAF5B7B11524B4BD0004CB49 /* WebSocketFrame.cpp */,
                                97AABD0A14FA09D5007457AE /* WebSocketFrame.h */,
                                97AABD0B14FA09D5007457AE /* WebSocketHandshake.cpp */,
                                97AABD0C14FA09D5007457AE /* WebSocketHandshake.h */,
                                4A38BF5014FE1C0900612512 /* WebSocketDeflateFramer.cpp in Sources */,
                                97AABD2014FA09D5007457AE /* WebSocketDeflater.cpp in Sources */,
                                97AABD2214FA09D5007457AE /* WebSocketExtensionDispatcher.cpp in Sources */,
+                               AAF5B7B71524B6C50004CB49 /* WebSocketFrame.cpp in Sources */,
                                97AABD2614FA09D5007457AE /* WebSocketHandshake.cpp in Sources */,
                                97AABD2814FA09D5007457AE /* WebSocketHandshakeRequest.cpp in Sources */,
                                97AABD2A14FA09D5007457AE /* WebSocketHandshakeResponse.cpp in Sources */,