[WebSocket] Move WebSocketChannel::FrameData into a separate header file
authorbashi@chromium.org <bashi@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Feb 2012 14:54:49 +0000 (14:54 +0000)
committerbashi@chromium.org <bashi@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 20 Feb 2012 14:54:49 +0000 (14:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=78682

Extract WebSocketChannel::FrameData as WebSocketFrame. This brings
flexibility to add classes which want to do something for
incoming/outgoing frames (e.g. compression/decompression).

Reviewed by Kent Tamura.

No new tests. No behavior change.

* GNUmakefile.list.am: AddedWebSocketFrame.h
* Target.pri: Ditto.
* WebCore.gypi: Ditto.
* WebCore.vcproj/WebCore.vcproj: Ditto.
* WebCore.xcodeproj/project.pbxproj: Ditto.
* websockets/WebSocketChannel.cpp: Modified to use WebSocketFrame instead of FrameData
(WebCore):
(WebCore::WebSocketChannel::send):
(WebCore::WebSocketChannel::startClosingHandshake):
(WebCore::WebSocketChannel::parseFrame):
(WebCore::WebSocketChannel::processFrame):
(WebCore::WebSocketChannel::enqueueTextFrame):
(WebCore::WebSocketChannel::enqueueRawFrame):
(WebCore::WebSocketChannel::enqueueBlobFrame):
(WebCore::appendMaskedFramePayload): Added.
(WebCore::makeFrameData): Added.
(WebCore::WebSocketChannel::sendFrame):
* websockets/WebSocketChannel.h: Removed FrameData.
(WebSocketChannel):
(QueuedFrame):
* websockets/WebSocketFrame.h: Added.
(WebCore):
(WebSocketFrame):
(WebCore::WebSocketFrame::isNonControlOpCode):
(WebCore::WebSocketFrame::isControlOpCode):
(WebCore::WebSocketFrame::isReservedOpCode):
(WebCore::WebSocketFrame::WebSocketFrame):

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

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

index cf33b92..d9207e1 100644 (file)
@@ -1,3 +1,44 @@
+2012-02-20  Kenichi Ishibashi  <bashi@chromium.org>
+
+        [WebSocket] Move WebSocketChannel::FrameData into a separate header file
+        https://bugs.webkit.org/show_bug.cgi?id=78682
+
+        Extract WebSocketChannel::FrameData as WebSocketFrame. This brings
+        flexibility to add classes which want to do something for
+        incoming/outgoing frames (e.g. compression/decompression).
+
+        Reviewed by Kent Tamura.
+
+        No new tests. No behavior change.
+
+        * GNUmakefile.list.am: AddedWebSocketFrame.h
+        * Target.pri: Ditto.
+        * WebCore.gypi: Ditto.
+        * WebCore.vcproj/WebCore.vcproj: Ditto.
+        * WebCore.xcodeproj/project.pbxproj: Ditto.
+        * websockets/WebSocketChannel.cpp: Modified to use WebSocketFrame instead of FrameData
+        (WebCore):
+        (WebCore::WebSocketChannel::send):
+        (WebCore::WebSocketChannel::startClosingHandshake):
+        (WebCore::WebSocketChannel::parseFrame):
+        (WebCore::WebSocketChannel::processFrame):
+        (WebCore::WebSocketChannel::enqueueTextFrame):
+        (WebCore::WebSocketChannel::enqueueRawFrame):
+        (WebCore::WebSocketChannel::enqueueBlobFrame):
+        (WebCore::appendMaskedFramePayload): Added.
+        (WebCore::makeFrameData): Added.
+        (WebCore::WebSocketChannel::sendFrame):
+        * websockets/WebSocketChannel.h: Removed FrameData.
+        (WebSocketChannel):
+        (QueuedFrame):
+        * websockets/WebSocketFrame.h: Added.
+        (WebCore):
+        (WebSocketFrame):
+        (WebCore::WebSocketFrame::isNonControlOpCode):
+        (WebCore::WebSocketFrame::isControlOpCode):
+        (WebCore::WebSocketFrame::isReservedOpCode):
+        (WebCore::WebSocketFrame::WebSocketFrame):
+
 2012-02-20  Adam Roben  <aroben@apple.com>
 
         32-bit build fix
index f20a408..2391875 100644 (file)
@@ -4337,6 +4337,7 @@ webcore_sources += \
        Source/WebCore/websockets/WebSocketExtensionDispatcher.cpp \
        Source/WebCore/websockets/WebSocketExtensionDispatcher.h \
        Source/WebCore/websockets/WebSocketExtensionProcessor.h \
+       Source/WebCore/websockets/WebSocketFrame.h \
        Source/WebCore/websockets/WebSocketHandshake.cpp \
        Source/WebCore/websockets/WebSocketHandshake.h \
        Source/WebCore/websockets/WebSocketHandshakeRequest.cpp \
index fbebcb5..c3190e4 100644 (file)
@@ -3668,6 +3668,7 @@ contains(DEFINES, ENABLE_WEB_SOCKETS=1) {
         websockets/WebSocketChannelClient.h \
         websockets/WebSocketExtensionDispatcher.h \
         websockets/WebSocketExtensionProcessor.h \
+        websockets/WebSocketFrame.h \
         websockets/WebSocketHandshake.h \
         websockets/WebSocketHandshakeRequest.h \
         websockets/WebSocketHandshakeResponse.h \
index b337c09..6c2a6d8 100644 (file)
             'websockets/WebSocketExtensionDispatcher.cpp',
             'websockets/WebSocketExtensionDispatcher.h',
             'websockets/WebSocketExtensionProcessor.h',
+            'websockets/WebSocketFrame.h',
             'websockets/WebSocketHandshake.cpp',
             'websockets/WebSocketHandshake.h',
             'websockets/WebSocketHandshakeRequest.cpp',
index 7d65edb..62dcdcc 100755 (executable)
                                >
                        </File>
                        <File
+                               RelativePath="..\websockets\WebSocketFrame.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\websockets\WebSocketHandshake.cpp"
                                >
                        </File>
index 59e87f7..990f405 100644 (file)
                4A1E719614E101F900626F9D /* JSHTMLShadowElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A1E719414E101F900626F9D /* JSHTMLShadowElement.h */; };
                4A1E71A514E106AC00626F9D /* JSShadowRoot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A1E71A314E106AC00626F9D /* JSShadowRoot.cpp */; };
                4A1E71A614E106AC00626F9D /* JSShadowRoot.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A1E71A414E106AC00626F9D /* JSShadowRoot.h */; };
+               4A4A234614F1E1440046FBF1 /* WebSocketFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A4A234514F1E1440046FBF1 /* WebSocketFrame.h */; };
                4A6E9FC313C17D1D0046A7F8 /* FontFeatureValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A6E9FC113C17D1D0046A7F8 /* FontFeatureValue.cpp */; };
                4A6E9FC413C17D1D0046A7F8 /* FontFeatureValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A6E9FC213C17D1D0046A7F8 /* FontFeatureValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
                4A6E9FC713C17D570046A7F8 /* FontFeatureSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A6E9FC513C17D570046A7F8 /* FontFeatureSettings.cpp */; };
                4A1E719414E101F900626F9D /* JSHTMLShadowElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSHTMLShadowElement.h; sourceTree = "<group>"; };
                4A1E71A314E106AC00626F9D /* JSShadowRoot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSShadowRoot.cpp; sourceTree = "<group>"; };
                4A1E71A414E106AC00626F9D /* JSShadowRoot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSShadowRoot.h; sourceTree = "<group>"; };
+               4A4A234514F1E1440046FBF1 /* WebSocketFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketFrame.h; sourceTree = "<group>"; };
                4A6E9FC113C17D1D0046A7F8 /* FontFeatureValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FontFeatureValue.cpp; sourceTree = "<group>"; };
                4A6E9FC213C17D1D0046A7F8 /* FontFeatureValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontFeatureValue.h; sourceTree = "<group>"; };
                4A6E9FC513C17D570046A7F8 /* FontFeatureSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FontFeatureSettings.cpp; sourceTree = "<group>"; };
                                4A957F0314E241100049DBFB /* WebSocketExtensionDispatcher.cpp */,
                                4A957F0414E241100049DBFB /* WebSocketExtensionDispatcher.h */,
                                4ADE25F914E3BB4C004C2213 /* WebSocketExtensionProcessor.h */,
+                               4A4A234514F1E1440046FBF1 /* WebSocketFrame.h */,
                                51ABAE421043AB4A008C5260 /* WebSocketHandshake.cpp */,
                                51ABAE431043AB4A008C5260 /* WebSocketHandshake.h */,
                                7637C540112E7B74003D6CDC /* WebSocketHandshakeRequest.cpp */,
                                4AE02ABE14E8A9D200BC3BA7 /* WebSocketDeflater.h in Headers */,
                                4A957F0714E241300049DBFB /* WebSocketExtensionDispatcher.h in Headers */,
                                4ADE25FA14E3BB4C004C2213 /* WebSocketExtensionProcessor.h in Headers */,
+                               4A4A234614F1E1440046FBF1 /* WebSocketFrame.h in Headers */,
                                51ABAE451043AB4A008C5260 /* WebSocketHandshake.h in Headers */,
                                7637C543112E7B7E003D6CDC /* WebSocketHandshakeRequest.h in Headers */,
                                767F99C011A119560080C51D /* WebSocketHandshakeResponse.h in Headers */,
index 8728e16..1c478e6 100644 (file)
@@ -81,13 +81,6 @@ const size_t payloadLengthWithTwoByteExtendedLengthField = 126;
 const size_t payloadLengthWithEightByteExtendedLengthField = 127;
 const size_t maskingKeyWidthInBytes = 4;
 
-const WebSocketChannel::OpCode WebSocketChannel::OpCodeContinuation = 0x0;
-const WebSocketChannel::OpCode WebSocketChannel::OpCodeText = 0x1;
-const WebSocketChannel::OpCode WebSocketChannel::OpCodeBinary = 0x2;
-const WebSocketChannel::OpCode WebSocketChannel::OpCodeClose = 0x8;
-const WebSocketChannel::OpCode WebSocketChannel::OpCodePing = 0x9;
-const WebSocketChannel::OpCode WebSocketChannel::OpCodePong = 0xA;
-
 WebSocketChannel::WebSocketChannel(Document* document, WebSocketChannelClient* client)
     : m_document(document)
     , m_client(client)
@@ -183,7 +176,7 @@ bool WebSocketChannel::send(const ArrayBuffer& binaryData)
 {
     LOG(Network, "WebSocketChannel %p send arraybuffer %p", this, &binaryData);
     ASSERT(!m_useHixie76Protocol);
-    enqueueRawFrame(OpCodeBinary, static_cast<const char*>(binaryData.data()), binaryData.byteLength());
+    enqueueRawFrame(WebSocketFrame::OpCodeBinary, static_cast<const char*>(binaryData.data()), binaryData.byteLength());
     return true;
 }
 
@@ -191,7 +184,7 @@ bool WebSocketChannel::send(const Blob& binaryData)
 {
     LOG(Network, "WebSocketChannel %p send blob %s", this, binaryData.url().string().utf8().data());
     ASSERT(!m_useHixie76Protocol);
-    enqueueBlobFrame(OpCodeBinary, binaryData);
+    enqueueBlobFrame(WebSocketFrame::OpCodeBinary, binaryData);
     return true;
 }
 
@@ -199,7 +192,7 @@ bool WebSocketChannel::send(const char* data, int length)
 {
     LOG(Network, "WebSocketChannel %p send binary %p (%dB)", this, data, length);
     ASSERT(!m_useHixie76Protocol);
-    enqueueRawFrame(OpCodeBinary, data, length);
+    enqueueRawFrame(WebSocketFrame::OpCodeBinary, data, length);
     return true;
 }
 
@@ -527,7 +520,7 @@ void WebSocketChannel::startClosingHandshake(int code, const String& reason)
             buf.append(static_cast<char>(lowByte));
             buf.append(reason.utf8().data(), reason.utf8().length());
         }
-        enqueueRawFrame(OpCodeClose, buf.data(), buf.size());
+        enqueueRawFrame(WebSocketFrame::OpCodeClose, buf.data(), buf.size());
     }
     m_closing = true;
     if (m_client)
@@ -542,7 +535,7 @@ void WebSocketChannel::closingTimerFired(Timer<WebSocketChannel>* timer)
         m_handle->disconnect();
 }
 
-WebSocketChannel::ParseFrameResult WebSocketChannel::parseFrame(FrameData& frame)
+WebSocketChannel::ParseFrameResult WebSocketChannel::parseFrame(WebSocketFrame& frame, const char*& frameEnd)
 {
     const char* p = m_buffer;
     const char* bufferEnd = m_buffer + m_bufferSize;
@@ -557,7 +550,7 @@ WebSocketChannel::ParseFrameResult WebSocketChannel::parseFrame(FrameData& frame
     bool reserved1 = firstByte & reserved1Bit;
     bool reserved2 = firstByte & reserved2Bit;
     bool reserved3 = firstByte & reserved3Bit;
-    OpCode opCode = firstByte & opCodeMask;
+    unsigned char opCode = firstByte & opCodeMask;
 
     bool masked = secondByte & maskBit;
     uint64_t payloadLength64 = secondByte & payloadLengthMask;
@@ -601,7 +594,7 @@ WebSocketChannel::ParseFrameResult WebSocketChannel::parseFrame(FrameData& frame
             payload[i] ^= maskingKey[i % maskingKeyWidthInBytes]; // Unmask the payload.
     }
 
-    frame.opCode = opCode;
+    frame.opCode = static_cast<WebSocketFrame::OpCode>(opCode);
     frame.final = final;
     frame.reserved1 = reserved1;
     frame.reserved2 = reserved2;
@@ -609,7 +602,7 @@ WebSocketChannel::ParseFrameResult WebSocketChannel::parseFrame(FrameData& frame
     frame.masked = masked;
     frame.payload = p + maskingKeyLength;
     frame.payloadLength = payloadLength;
-    frame.frameEnd = p + maskingKeyLength + payloadLength;
+    frameEnd = p + maskingKeyLength + payloadLength;
     return FrameOK;
 }
 
@@ -617,12 +610,16 @@ bool WebSocketChannel::processFrame()
 {
     ASSERT(m_buffer);
 
-    FrameData frame;
-    if (parseFrame(frame) != FrameOK)
+    WebSocketFrame frame;
+    const char* frameEnd;
+    if (parseFrame(frame, frameEnd) != FrameOK)
         return false;
 
+    ASSERT(m_buffer < frameEnd);
+    ASSERT(frameEnd <= m_buffer + m_bufferSize);
+
     // Validate the frame data.
-    if (isReservedOpCode(frame.opCode)) {
+    if (WebSocketFrame::isReservedOpCode(frame.opCode)) {
         fail("Unrecognized frame opcode: " + String::number(frame.opCode));
         return false;
     }
@@ -633,34 +630,34 @@ bool WebSocketChannel::processFrame()
     }
 
     // All control frames must not be fragmented.
-    if (isControlOpCode(frame.opCode) && !frame.final) {
+    if (WebSocketFrame::isControlOpCode(frame.opCode) && !frame.final) {
         fail("Received fragmented control frame: opcode = " + String::number(frame.opCode));
         return false;
     }
 
     // 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 (isControlOpCode(frame.opCode) && frame.payloadLength > maxPayloadLengthWithoutExtendedLengthField) {
+    if (WebSocketFrame::isControlOpCode(frame.opCode) && frame.payloadLength > maxPayloadLengthWithoutExtendedLengthField) {
         fail("Received control frame having too long payload: " + String::number(frame.payloadLength) + " bytes");
         return false;
     }
 
     // A new data frame is received before the previous continuous frame finishes.
     // Note that control frames are allowed to come in the middle of continuous frames.
-    if (m_hasContinuousFrame && frame.opCode != OpCodeContinuation && !isControlOpCode(frame.opCode)) {
+    if (m_hasContinuousFrame && frame.opCode != WebSocketFrame::OpCodeContinuation && !WebSocketFrame::isControlOpCode(frame.opCode)) {
         fail("Received new data frame but previous continuous frame is unfinished.");
         return false;
     }
 
     switch (frame.opCode) {
-    case OpCodeContinuation:
+    case WebSocketFrame::OpCodeContinuation:
         // An unexpected continuation frame is received without any leading frame.
         if (!m_hasContinuousFrame) {
             fail("Received unexpected continuation frame.");
             return false;
         }
         m_continuousFrameData.append(frame.payload, frame.payloadLength);
-        skipBuffer(frame.frameEnd - m_buffer);
+        skipBuffer(frameEnd - m_buffer);
         if (frame.final) {
             // onmessage handler may eventually call the other methods of this channel,
             // so we should pretend that we have finished to read this frame and
@@ -670,7 +667,7 @@ bool WebSocketChannel::processFrame()
             OwnPtr<Vector<char> > continuousFrameData = adoptPtr(new Vector<char>);
             m_continuousFrameData.swap(*continuousFrameData);
             m_hasContinuousFrame = false;
-            if (m_continuousFrameOpCode == OpCodeText) {
+            if (m_continuousFrameOpCode == WebSocketFrame::OpCodeText) {
                 String message;
                 if (continuousFrameData->size())
                     message = String::fromUTF8(continuousFrameData->data(), continuousFrameData->size());
@@ -680,48 +677,48 @@ bool WebSocketChannel::processFrame()
                     fail("Could not decode a text frame as UTF-8.");
                 else
                     m_client->didReceiveMessage(message);
-            } else if (m_continuousFrameOpCode == OpCodeBinary)
+            } else if (m_continuousFrameOpCode == WebSocketFrame::OpCodeBinary)
                 m_client->didReceiveBinaryData(continuousFrameData.release());
         }
         break;
 
-    case OpCodeText:
+    case WebSocketFrame::OpCodeText:
         if (frame.final) {
             String message;
             if (frame.payloadLength)
                 message = String::fromUTF8(frame.payload, frame.payloadLength);
             else
                 message = "";
-            skipBuffer(frame.frameEnd - m_buffer);
+            skipBuffer(frameEnd - m_buffer);
             if (message.isNull())
                 fail("Could not decode a text frame as UTF-8.");
             else
                 m_client->didReceiveMessage(message);
         } else {
             m_hasContinuousFrame = true;
-            m_continuousFrameOpCode = OpCodeText;
+            m_continuousFrameOpCode = WebSocketFrame::OpCodeText;
             ASSERT(m_continuousFrameData.isEmpty());
             m_continuousFrameData.append(frame.payload, frame.payloadLength);
-            skipBuffer(frame.frameEnd - m_buffer);
+            skipBuffer(frameEnd - m_buffer);
         }
         break;
 
-    case OpCodeBinary:
+    case WebSocketFrame::OpCodeBinary:
         if (frame.final) {
             OwnPtr<Vector<char> > binaryData = adoptPtr(new Vector<char>(frame.payloadLength));
             memcpy(binaryData->data(), frame.payload, frame.payloadLength);
-            skipBuffer(frame.frameEnd - m_buffer);
+            skipBuffer(frameEnd - m_buffer);
             m_client->didReceiveBinaryData(binaryData.release());
         } else {
             m_hasContinuousFrame = true;
-            m_continuousFrameOpCode = OpCodeBinary;
+            m_continuousFrameOpCode = WebSocketFrame::OpCodeBinary;
             ASSERT(m_continuousFrameData.isEmpty());
             m_continuousFrameData.append(frame.payload, frame.payloadLength);
-            skipBuffer(frame.frameEnd - m_buffer);
+            skipBuffer(frameEnd - m_buffer);
         }
         break;
 
-    case OpCodeClose:
+    case WebSocketFrame::OpCodeClose:
         if (frame.payloadLength >= 2) {
             unsigned char highByte = static_cast<unsigned char>(frame.payload[0]);
             unsigned char lowByte = static_cast<unsigned char>(frame.payload[1]);
@@ -732,7 +729,7 @@ bool WebSocketChannel::processFrame()
             m_closeEventReason = String::fromUTF8(&frame.payload[2], frame.payloadLength - 2);
         else
             m_closeEventReason = "";
-        skipBuffer(frame.frameEnd - m_buffer);
+        skipBuffer(frameEnd - m_buffer);
         m_receivedClosingHandshake = true;
         startClosingHandshake(m_closeEventCode, m_closeEventReason);
         if (m_closing) {
@@ -741,20 +738,20 @@ bool WebSocketChannel::processFrame()
         }
         break;
 
-    case OpCodePing:
-        enqueueRawFrame(OpCodePong, frame.payload, frame.payloadLength);
-        skipBuffer(frame.frameEnd - m_buffer);
+    case WebSocketFrame::OpCodePing:
+        enqueueRawFrame(WebSocketFrame::OpCodePong, frame.payload, frame.payloadLength);
+        skipBuffer(frameEnd - m_buffer);
         break;
 
-    case OpCodePong:
+    case WebSocketFrame::OpCodePong:
         // A server may send a pong in response to our ping, or an unsolicited pong which is not associated with
         // any specific ping. Either way, there's nothing to do on receipt of pong.
-        skipBuffer(frame.frameEnd - m_buffer);
+        skipBuffer(frameEnd - m_buffer);
         break;
 
     default:
         ASSERT_NOT_REACHED();
-        skipBuffer(frame.frameEnd - m_buffer);
+        skipBuffer(frameEnd - m_buffer);
         break;
     }
 
@@ -855,14 +852,14 @@ void WebSocketChannel::enqueueTextFrame(const String& string)
     ASSERT(!m_useHixie76Protocol);
     ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
     OwnPtr<QueuedFrame> frame = adoptPtr(new QueuedFrame);
-    frame->opCode = OpCodeText;
+    frame->opCode = WebSocketFrame::OpCodeText;
     frame->frameType = QueuedFrameTypeString;
     frame->stringData = string;
     m_outgoingFrameQueue.append(frame.release());
     processOutgoingFrameQueue();
 }
 
-void WebSocketChannel::enqueueRawFrame(OpCode opCode, const char* data, size_t dataLength)
+void WebSocketChannel::enqueueRawFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength)
 {
     ASSERT(!m_useHixie76Protocol);
     ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
@@ -876,7 +873,7 @@ void WebSocketChannel::enqueueRawFrame(OpCode opCode, const char* data, size_t d
     processOutgoingFrameQueue();
 }
 
-void WebSocketChannel::enqueueBlobFrame(OpCode opCode, const Blob& blob)
+void WebSocketChannel::enqueueBlobFrame(WebSocketFrame::OpCode opCode, const Blob& blob)
 {
     ASSERT(!m_useHixie76Protocol);
     ASSERT(m_outgoingFrameQueueStatus == OutgoingFrameQueueOpen);
@@ -967,44 +964,55 @@ void WebSocketChannel::abortOutgoingFrameQueue()
 #endif
 }
 
-bool WebSocketChannel::sendFrame(OpCode opCode, const char* data, size_t dataLength)
+static void appendMaskedFramePayload(const WebSocketFrame& frame, Vector<char>& frameData)
 {
-    ASSERT(m_handle);
-    ASSERT(!m_suspended);
+    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];
+}
 
-    Vector<char> frame;
-    ASSERT(!(opCode & ~opCodeMask)); // Checks whether "opCode" fits in the range of opCodes.
-    frame.append(finalBit | opCode);
-    if (dataLength <= maxPayloadLengthWithoutExtendedLengthField)
-        frame.append(maskBit | dataLength);
-    else if (dataLength <= 0xFFFF) {
-        frame.append(maskBit | payloadLengthWithTwoByteExtendedLengthField);
-        frame.append((dataLength & 0xFF00) >> 8);
-        frame.append(dataLength & 0xFF);
+static void makeFrameData(const WebSocketFrame& frame, Vector<char>& frameData)
+{
+    unsigned char firstByte = (frame.final ? finalBit : 0) | frame.opCode;
+    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 {
-        frame.append(maskBit | payloadLengthWithEightByteExtendedLengthField);
+        frameData.append(maskBit | payloadLengthWithEightByteExtendedLengthField);
         char extendedPayloadLength[8];
-        size_t remaining = dataLength;
+        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);
-        frame.append(extendedPayloadLength, 8);
+        frameData.append(extendedPayloadLength, 8);
     }
 
-    // Mask the frame.
-    size_t maskingKeyStart = frame.size();
-    frame.grow(frame.size() + maskingKeyWidthInBytes); // Add placeholder for masking key. Will be overwritten.
-    size_t payloadStart = frame.size();
-    frame.append(data, dataLength);
+    appendMaskedFramePayload(frame, frameData);
+}
+
+bool WebSocketChannel::sendFrame(WebSocketFrame::OpCode opCode, const char* data, size_t dataLength)
+{
+    ASSERT(m_handle);
+    ASSERT(!m_suspended);
 
-    cryptographicallyRandomValues(frame.data() + maskingKeyStart, maskingKeyWidthInBytes);
-    for (size_t i = 0; i < dataLength; ++i)
-        frame[payloadStart + i] ^= frame[maskingKeyStart + i % maskingKeyWidthInBytes];
+    ASSERT(!(opCode & ~opCodeMask)); // Checks whether "opCode" fits in the range of opCodes.
+    WebSocketFrame frame(opCode, true, true, data, dataLength);
+    Vector<char> frameData;
+    makeFrameData(frame, frameData);
 
-    return m_handle->send(frame.data(), frame.size());
+    return m_handle->send(frameData.data(), frameData.size());
 }
 
 bool WebSocketChannel::sendFrameHixie76(const char* data, size_t dataLength)
index 73fc52d..4bb28c9 100644 (file)
@@ -37,6 +37,7 @@
 #include "SocketStreamHandleClient.h"
 #include "ThreadableWebSocketChannel.h"
 #include "Timer.h"
+#include "WebSocketFrame.h"
 #include "WebSocketHandshake.h"
 #include <wtf/Deque.h>
 #include <wtf/Forward.h>
@@ -128,38 +129,13 @@ private:
     void startClosingHandshake(int code, const String& reason);
     void closingTimerFired(Timer<WebSocketChannel>*);
 
-    // Hybi-10 opcodes.
-    typedef unsigned int OpCode;
-    static const OpCode OpCodeContinuation;
-    static const OpCode OpCodeText;
-    static const OpCode OpCodeBinary;
-    static const OpCode OpCodeClose;
-    static const OpCode OpCodePing;
-    static const OpCode OpCodePong;
-
-    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); }
-
     enum ParseFrameResult {
         FrameOK,
         FrameIncomplete,
         FrameError
     };
 
-    struct FrameData {
-        OpCode opCode;
-        bool final;
-        bool reserved1;
-        bool reserved2;
-        bool reserved3;
-        bool masked;
-        const char* payload;
-        size_t payloadLength;
-        const char* frameEnd;
-    };
-
-    ParseFrameResult parseFrame(FrameData&); // May modify part of m_buffer to unmask the frame.
+    ParseFrameResult parseFrame(WebSocketFrame&, const char*& frameEnd); // May modify part of m_buffer to unmask the frame.
 
     bool processFrame();
     bool processFrameHixie76();
@@ -180,7 +156,7 @@ private:
         QueuedFrameTypeBlob
     };
     struct QueuedFrame {
-        OpCode opCode;
+        WebSocketFrame::OpCode opCode;
         QueuedFrameType frameType;
         // Only one of the following items is used, according to the value of frameType.
         String stringData;
@@ -188,8 +164,8 @@ private:
         RefPtr<Blob> blobData;
     };
     void enqueueTextFrame(const String&);
-    void enqueueRawFrame(OpCode, const char* data, size_t dataLength);
-    void enqueueBlobFrame(OpCode, const Blob&);
+    void enqueueRawFrame(WebSocketFrame::OpCode, const char* data, size_t dataLength);
+    void enqueueBlobFrame(WebSocketFrame::OpCode, const Blob&);
 
     void processOutgoingFrameQueue();
     void abortOutgoingFrameQueue();
@@ -208,7 +184,7 @@ private:
 
     // If you are going to send a hybi-10 frame, you need to use the outgoing frame queue
     // instead of call sendFrame() directly.
-    bool sendFrame(OpCode, const char* data, size_t dataLength);
+    bool sendFrame(WebSocketFrame::OpCode, const char* data, size_t dataLength);
     bool sendFrameHixie76(const char* data, size_t dataLength);
 
 #if ENABLE(BLOB)
@@ -242,7 +218,7 @@ private:
 
     // Private members only for hybi-10 protocol.
     bool m_hasContinuousFrame;
-    OpCode m_continuousFrameOpCode;
+    WebSocketFrame::OpCode m_continuousFrameOpCode;
     Vector<char> m_continuousFrameData;
     unsigned short m_closeEventCode;
     String m_closeEventReason;
diff --git a/Source/WebCore/websockets/WebSocketFrame.h b/Source/WebCore/websockets/WebSocketFrame.h
new file mode 100644 (file)
index 0000000..19dd7ab
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 Google Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebSocketFrame_h
+#define WebSocketFrame_h
+
+#if ENABLE(WEB_SOCKETS)
+
+namespace WebCore {
+
+struct WebSocketFrame {
+    // RFC6455 opcodes.
+    enum OpCode {
+        OpCodeContinuation = 0x0,
+        OpCodeText = 0x1,
+        OpCodeBinary = 0x2,
+        OpCodeClose = 0x8,
+        OpCodePing = 0x9,
+        OpCodePong = 0xA,
+        OpCodeInvalid = 0x10
+    };
+
+    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); }
+
+    WebSocketFrame(OpCode opCode = OpCodeInvalid, bool final = false, bool masked = false, const char* payload = 0, size_t payloadLength = 0)
+        : opCode(opCode)
+        , final(final)
+        , reserved1(false)
+        , reserved2(false)
+        , reserved3(false)
+        , masked(masked)
+        , payload(payload)
+        , payloadLength(payloadLength)
+    {
+    }
+
+    OpCode opCode;
+    bool final;
+    bool reserved1;
+    bool reserved2;
+    bool reserved3;
+    bool masked;
+    const char* payload;
+    size_t payloadLength;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_SOCKETS)
+
+#endif // WebSocketFrame_h