Source/WebCore: [WebSocket] Add deflater/inflater classes
authorbashi@chromium.org <bashi@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 15 Feb 2012 02:02:53 +0000 (02:02 +0000)
committerbashi@chromium.org <bashi@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 15 Feb 2012 02:02:53 +0000 (02:02 +0000)
https://bugs.webkit.org/show_bug.cgi?id=78449

Add WebSocketDeflater/WebSocketInflater classes which wrap zlib
functions. These classes are not used yet, but will be used for
supporting WebSocket deflate-frame extension.

Reviewed by Kent Tamura.

No new tests except for chromium port. Behavior is unchanged.

* GNUmakefile.list.am: Added.WebSocketDeflater.(cpp|h).
* WebCore.gypi: Ditto.
* WebCore.vcproj/WebCore.vcproj: Ditto.
* WebCore.xcodeproj/project.pbxproj: Ditto.
* websockets/WebSocketDeflater.cpp: Added.
(WebCore):
(WebCore::WebSocketDeflater::create):
(WebCore::WebSocketDeflater::WebSocketDeflater):
(WebCore::WebSocketDeflater::initialize):
(WebCore::WebSocketDeflater::~WebSocketDeflater):
(WebCore::WebSocketDeflater::addBytes):
(WebCore::WebSocketDeflater::finish):
(WebCore::WebSocketDeflater::reset):
(WebCore::WebSocketInflater::create):
(WebCore::WebSocketInflater::WebSocketInflater):
(WebCore::WebSocketInflater::initialize):
(WebCore::WebSocketInflater::~WebSocketInflater):
(WebCore::WebSocketInflater::addBytes):
(WebCore::WebSocketInflater::finish):
(WebCore::WebSocketInflater::reset):
* websockets/WebSocketDeflater.h: Added.
(WebCore):
(WebSocketDeflater):
(WebCore::WebSocketDeflater::data):
(WebCore::WebSocketDeflater::size):
(WebSocketInflater):
(WebCore::WebSocketInflater::data):
(WebCore::WebSocketInflater::size):

Source/WebKit/chromium: [WebSocket] Add deflater/inflater classes.
https://bugs.webkit.org/show_bug.cgi?id=78449

Add tests which ensure WebSocketDeflater/WebSocketInflater can
compress/decompress data correctly.

Reviewed by Kent Tamura.

* WebKit.gypi:
* tests/WebSocketDeflaterTest.cpp: Added.
(WebCore):
(WebCore::TEST):

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

Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/websockets/WebSocketDeflater.cpp [new file with mode: 0644]
Source/WebCore/websockets/WebSocketDeflater.h [new file with mode: 0644]
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/WebKit.gypi
Source/WebKit/chromium/tests/WebSocketDeflaterTest.cpp [new file with mode: 0644]

index e087ea0..57c77f1 100644 (file)
@@ -1,3 +1,45 @@
+2012-02-14  Kenichi Ishibashi  <bashi@chromium.org>
+
+        [WebSocket] Add deflater/inflater classes
+        https://bugs.webkit.org/show_bug.cgi?id=78449
+
+        Add WebSocketDeflater/WebSocketInflater classes which wrap zlib
+        functions. These classes are not used yet, but will be used for
+        supporting WebSocket deflate-frame extension.
+
+        Reviewed by Kent Tamura.
+
+        No new tests except for chromium port. Behavior is unchanged.
+
+        * GNUmakefile.list.am: Added.WebSocketDeflater.(cpp|h).
+        * WebCore.gypi: Ditto.
+        * WebCore.vcproj/WebCore.vcproj: Ditto.
+        * WebCore.xcodeproj/project.pbxproj: Ditto.
+        * websockets/WebSocketDeflater.cpp: Added.
+        (WebCore):
+        (WebCore::WebSocketDeflater::create):
+        (WebCore::WebSocketDeflater::WebSocketDeflater):
+        (WebCore::WebSocketDeflater::initialize):
+        (WebCore::WebSocketDeflater::~WebSocketDeflater):
+        (WebCore::WebSocketDeflater::addBytes):
+        (WebCore::WebSocketDeflater::finish):
+        (WebCore::WebSocketDeflater::reset):
+        (WebCore::WebSocketInflater::create):
+        (WebCore::WebSocketInflater::WebSocketInflater):
+        (WebCore::WebSocketInflater::initialize):
+        (WebCore::WebSocketInflater::~WebSocketInflater):
+        (WebCore::WebSocketInflater::addBytes):
+        (WebCore::WebSocketInflater::finish):
+        (WebCore::WebSocketInflater::reset):
+        * websockets/WebSocketDeflater.h: Added.
+        (WebCore):
+        (WebSocketDeflater):
+        (WebCore::WebSocketDeflater::data):
+        (WebCore::WebSocketDeflater::size):
+        (WebSocketInflater):
+        (WebCore::WebSocketInflater::data):
+        (WebCore::WebSocketInflater::size):
+
 2012-02-14  Dana Jansens  <danakj@chromium.org>
 
         [chromium] Compare filters on impl thread when setting them, and test setting in unit tests
index db80211..aa65235 100644 (file)
@@ -4320,6 +4320,8 @@ webcore_sources += \
        Source/WebCore/websockets/WebSocketChannel.h \
        Source/WebCore/websockets/WebSocket.cpp \
        Source/WebCore/websockets/WebSocket.h \
+       Source/WebCore/websockets/WebSocketDeflater.cpp \
+       Source/WebCore/websockets/WebSocketDeflater.h \
        Source/WebCore/websockets/WebSocketExtensionDispatcher.cpp \
        Source/WebCore/websockets/WebSocketExtensionDispatcher.h \
        Source/WebCore/websockets/WebSocketExtensionProcessor.h \
index fb16a5f..50c0289 100644 (file)
             'websockets/WebSocketChannel.cpp',
             'websockets/WebSocketChannel.h',
             'websockets/WebSocketChannelClient.h',
+            'websockets/WebSocketDeflater.cpp',
+            'websockets/WebSocketDeflater.h',
             'websockets/WebSocketExtensionDispatcher.cpp',
             'websockets/WebSocketExtensionDispatcher.h',
             'websockets/WebSocketExtensionProcessor.h',
index 070ab3f..f4f8627 100755 (executable)
                                >
                        </File>
                        <File
+                               RelativePath="..\websockets\WebSocketDeflater.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\websockets\WebSocketDeflater.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\websockets\WebSocketExtensionDispatcher.cpp"
                                >
                        </File>
index dec174f..816b57a 100644 (file)
                4AD0173C127E82860015035F /* JSHTMLOutputElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AD0173A127E82860015035F /* JSHTMLOutputElement.cpp */; };
                4AD0173D127E82860015035F /* JSHTMLOutputElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AD0173B127E82860015035F /* JSHTMLOutputElement.h */; };
                4ADE25FA14E3BB4C004C2213 /* WebSocketExtensionProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 4ADE25F914E3BB4C004C2213 /* WebSocketExtensionProcessor.h */; };
+               4AE02ABD14E8A9D200BC3BA7 /* WebSocketDeflater.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AE02ABB14E8A9D200BC3BA7 /* WebSocketDeflater.cpp */; };
+               4AE02ABE14E8A9D200BC3BA7 /* WebSocketDeflater.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AE02ABC14E8A9D200BC3BA7 /* WebSocketDeflater.h */; };
                4AF1AD3E13FD23A400AA9590 /* EventDispatchMediator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4AF1AD3C13FD23A400AA9590 /* EventDispatchMediator.cpp */; };
                4AF1AD3F13FD23A400AA9590 /* EventDispatchMediator.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AF1AD3D13FD23A400AA9590 /* EventDispatchMediator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                4B2708C70AF19EE40065127F /* Pasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B2708C50AF19EE40065127F /* Pasteboard.h */; };
                4AD0173A127E82860015035F /* JSHTMLOutputElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSHTMLOutputElement.cpp; sourceTree = "<group>"; };
                4AD0173B127E82860015035F /* JSHTMLOutputElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSHTMLOutputElement.h; sourceTree = "<group>"; };
                4ADE25F914E3BB4C004C2213 /* WebSocketExtensionProcessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketExtensionProcessor.h; sourceTree = "<group>"; };
+               4AE02ABB14E8A9D200BC3BA7 /* WebSocketDeflater.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSocketDeflater.cpp; sourceTree = "<group>"; };
+               4AE02ABC14E8A9D200BC3BA7 /* WebSocketDeflater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketDeflater.h; sourceTree = "<group>"; };
                4AF1AD3C13FD23A400AA9590 /* EventDispatchMediator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventDispatchMediator.cpp; sourceTree = "<group>"; };
                4AF1AD3D13FD23A400AA9590 /* EventDispatchMediator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventDispatchMediator.h; sourceTree = "<group>"; };
                4B2708C50AF19EE40065127F /* Pasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pasteboard.h; sourceTree = "<group>"; };
                518A34BD1026C831001B6896 /* websockets */ = {
                        isa = PBXGroup;
                        children = (
-                               4ADE25F914E3BB4C004C2213 /* WebSocketExtensionProcessor.h */,
                                51FB54F4113E364200821176 /* CloseEvent.h */,
                                51FB54F6113E365900821176 /* CloseEvent.idl */,
                                5112247110CFB8C6008099D7 /* ThreadableWebSocketChannel.cpp */,
                                510D4A47103177A20049EA54 /* WebSocketChannel.cpp */,
                                510D4A48103177A20049EA54 /* WebSocketChannel.h */,
                                510D4A49103177A20049EA54 /* WebSocketChannelClient.h */,
+                               4AE02ABB14E8A9D200BC3BA7 /* WebSocketDeflater.cpp */,
+                               4AE02ABC14E8A9D200BC3BA7 /* WebSocketDeflater.h */,
                                4A957F0314E241100049DBFB /* WebSocketExtensionDispatcher.cpp */,
                                4A957F0414E241100049DBFB /* WebSocketExtensionDispatcher.h */,
+                               4ADE25F914E3BB4C004C2213 /* WebSocketExtensionProcessor.h */,
                                51ABAE421043AB4A008C5260 /* WebSocketHandshake.cpp */,
                                51ABAE431043AB4A008C5260 /* WebSocketHandshake.h */,
                                7637C540112E7B74003D6CDC /* WebSocketHandshakeRequest.cpp */,
                                97CC3AE314E8E4A200894988 /* NavigatorSupplement.h in Headers */,
                                C598905714E9C28000E8D18B /* PasteboardStrategy.h in Headers */,
                                C598905814E9C29900E8D18B /* PlatformPasteboard.h in Headers */,
+                               4AE02ABE14E8A9D200BC3BA7 /* WebSocketDeflater.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                572E92FB14E540580087FFBA /* ShadowRootList.cpp in Sources */,
                                97CC3AE214E8E4A200894988 /* NavigatorSupplement.cpp in Sources */,
                                C598902E14E9B0F800E8D18B /* PlatformPasteboardMac.mm in Sources */,
+                               4AE02ABD14E8A9D200BC3BA7 /* WebSocketDeflater.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
diff --git a/Source/WebCore/websockets/WebSocketDeflater.cpp b/Source/WebCore/websockets/WebSocketDeflater.cpp
new file mode 100644 (file)
index 0000000..0b868f4
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_SOCKETS)
+
+#include "WebSocketDeflater.h"
+
+#include "Logging.h"
+#include <wtf/FastMalloc.h>
+#include <wtf/HashMap.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/StringExtras.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+static const int defaultMemLevel = 1;
+static const size_t bufferIncrementUnit = 4096;
+
+PassOwnPtr<WebSocketDeflater> WebSocketDeflater::create(int windowBits, ContextTakeOverMode contextTakeOverMode)
+{
+    return adoptPtr(new WebSocketDeflater(windowBits, contextTakeOverMode));
+}
+
+WebSocketDeflater::WebSocketDeflater(int windowBits, ContextTakeOverMode contextTakeOverMode)
+    : m_windowBits(windowBits)
+    , m_contextTakeOverMode(contextTakeOverMode)
+{
+    ASSERT(m_windowBits >= 8);
+    ASSERT(m_windowBits <= 15);
+    memset(&m_stream, 0, sizeof(z_stream));
+}
+
+bool WebSocketDeflater::initialize()
+{
+    return deflateInit2(&m_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -m_windowBits, defaultMemLevel, Z_DEFAULT_STRATEGY) == Z_OK;
+}
+
+WebSocketDeflater::~WebSocketDeflater()
+{
+    int result = deflateEnd(&m_stream);
+    if (result != Z_OK)
+        LOG(Network, "deflateEnd() failed: %d", result);
+}
+
+static void setStreamParameter(z_stream& stream, const char* inputData, size_t inputLength, char* outputData, size_t outputLength)
+{
+    stream.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(inputData));
+    stream.avail_in = inputLength;
+    stream.next_out = reinterpret_cast<Bytef*>(outputData);
+    stream.avail_out = outputLength;
+}
+
+bool WebSocketDeflater::addBytes(const char* data, size_t length)
+{
+    if (!length)
+        return false;
+
+    size_t maxLength = deflateBound(&m_stream, length);
+    size_t writePosition = m_buffer.size();
+    m_buffer.grow(writePosition + maxLength);
+    setStreamParameter(m_stream, data, length, m_buffer.data() + writePosition, maxLength);
+    int result = deflate(&m_stream, Z_NO_FLUSH);
+    if (result != Z_OK || m_stream.avail_in > 0)
+        return false;
+
+    m_buffer.shrink(writePosition + maxLength - m_stream.avail_out);
+    return true;
+}
+
+bool WebSocketDeflater::finish()
+{
+    while (true) {
+        size_t writePosition = m_buffer.size();
+        m_buffer.grow(writePosition + bufferIncrementUnit);
+        size_t availableCapacity = m_buffer.size() - writePosition;
+        setStreamParameter(m_stream, 0, 0, m_buffer.data() + writePosition, availableCapacity);
+        int result = deflate(&m_stream, Z_SYNC_FLUSH);
+        m_buffer.shrink(writePosition + availableCapacity - m_stream.avail_out);
+        if (result == Z_OK)
+            break;
+        if (result != Z_BUF_ERROR)
+            return false;
+    }
+    // Remove 4 octets from the tail as the specification requires.
+    if (m_buffer.size() <= 4)
+        return false;
+    m_buffer.resize(m_buffer.size() - 4);
+    return true;
+}
+
+void WebSocketDeflater::reset()
+{
+    m_buffer.clear();
+    if (m_contextTakeOverMode == DoNotTakeOverContext)
+        deflateReset(&m_stream);
+}
+
+PassOwnPtr<WebSocketInflater> WebSocketInflater::create(int windowBits)
+{
+    return adoptPtr(new WebSocketInflater(windowBits));
+}
+
+WebSocketInflater::WebSocketInflater(int windowBits)
+    : m_windowBits(windowBits)
+{
+    memset(&m_stream, 0, sizeof(z_stream));
+}
+
+bool WebSocketInflater::initialize()
+{
+    return inflateInit2(&m_stream, -m_windowBits) == Z_OK;
+}
+
+WebSocketInflater::~WebSocketInflater()
+{
+    int result = inflateEnd(&m_stream);
+    if (result != Z_OK)
+        LOG(Network, "inflateEnd() failed: %d", result);
+}
+
+bool WebSocketInflater::addBytes(const char* data, size_t length)
+{
+    if (!length)
+        return false;
+
+    size_t consumedSoFar = 0;
+    while (consumedSoFar < length) {
+        size_t writePosition = m_buffer.size();
+        m_buffer.grow(writePosition + bufferIncrementUnit);
+        size_t availableCapacity = m_buffer.size() - writePosition;
+        size_t remainingLength = length - consumedSoFar;
+        setStreamParameter(m_stream, data + consumedSoFar, remainingLength, m_buffer.data() + writePosition, availableCapacity);
+        int result = inflate(&m_stream, Z_NO_FLUSH);
+        consumedSoFar += remainingLength - m_stream.avail_in;
+        m_buffer.shrink(writePosition + availableCapacity - m_stream.avail_out);
+        if (result == Z_BUF_ERROR)
+            continue;
+        if (result != Z_OK)
+            return false;
+    }
+    ASSERT(consumedSoFar == length);
+    return true;
+}
+
+bool WebSocketInflater::finish()
+{
+    static const char* strippedFields = "\0\0\xff\xff";
+    static const size_t strippedLength = 4;
+
+    // Appends 4 octests of 0x00 0x00 0xff 0xff
+    size_t consumedSoFar = 0;
+    while (consumedSoFar < strippedLength) {
+        size_t writePosition = m_buffer.size();
+        m_buffer.grow(writePosition + bufferIncrementUnit);
+        size_t availableCapacity = m_buffer.size() - writePosition;
+        size_t remainingLength = strippedLength - consumedSoFar;
+        setStreamParameter(m_stream, strippedFields + consumedSoFar, remainingLength, m_buffer.data() + writePosition, availableCapacity);
+        int result = inflate(&m_stream, Z_FINISH);
+        consumedSoFar += remainingLength - m_stream.avail_in;
+        m_buffer.shrink(writePosition + availableCapacity - m_stream.avail_out);
+        if (result == Z_BUF_ERROR)
+            continue;
+        if (result != Z_OK && result != Z_STREAM_END)
+            return false;
+    }
+    ASSERT(consumedSoFar == strippedLength);
+
+    return true;
+}
+
+void WebSocketInflater::reset()
+{
+    m_buffer.clear();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_SOCKETS)
diff --git a/Source/WebCore/websockets/WebSocketDeflater.h b/Source/WebCore/websockets/WebSocketDeflater.h
new file mode 100644 (file)
index 0000000..2853451
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 WebSocketDeflater_h
+#define WebSocketDeflater_h
+
+#if ENABLE(WEB_SOCKETS)
+
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+#include <zlib.h>
+
+namespace WebCore {
+
+class WebSocketDeflater {
+public:
+    enum ContextTakeOverMode {
+        DoNotTakeOverContext,
+        TakeOverContext
+    };
+    static PassOwnPtr<WebSocketDeflater> create(int windowBits, ContextTakeOverMode = TakeOverContext);
+
+    ~WebSocketDeflater();
+
+    bool initialize();
+    bool addBytes(const char*, size_t);
+    bool finish();
+    const char* data() { return m_buffer.data(); }
+    size_t size() const { return m_buffer.size(); }
+    void reset();
+
+private:
+    WebSocketDeflater(int windowBits, ContextTakeOverMode);
+
+    int m_windowBits;
+    ContextTakeOverMode m_contextTakeOverMode;
+    Vector<char> m_buffer;
+    z_stream m_stream;
+};
+
+class WebSocketInflater {
+public:
+    static PassOwnPtr<WebSocketInflater> create(int windowBits = 15);
+
+    ~WebSocketInflater();
+
+    bool initialize();
+    bool addBytes(const char*, size_t);
+    bool finish();
+    const char* data() { return m_buffer.data(); }
+    size_t size() const { return m_buffer.size(); }
+    void reset();
+
+private:
+    explicit WebSocketInflater(int windowBits);
+
+    int m_windowBits;
+    Vector<char> m_buffer;
+    z_stream m_stream;
+};
+
+}
+
+#endif // ENABLE(WEB_SOCKETS)
+
+#endif // WebSocketDeflater_h
index ea1e00f..d2048eb 100644 (file)
@@ -1,3 +1,18 @@
+2012-02-14  Kenichi Ishibashi  <bashi@chromium.org>
+
+        [WebSocket] Add deflater/inflater classes.
+        https://bugs.webkit.org/show_bug.cgi?id=78449
+
+        Add tests which ensure WebSocketDeflater/WebSocketInflater can
+        compress/decompress data correctly.
+
+        Reviewed by Kent Tamura.
+
+        * WebKit.gypi:
+        * tests/WebSocketDeflaterTest.cpp: Added.
+        (WebCore):
+        (WebCore::TEST):
+
 2012-02-14  Dana Jansens  <danakj@chromium.org>
 
         [chromium] Compare filters on impl thread when setting them, and test setting in unit tests
index 35f2b19..4ea700d 100644 (file)
             'tests/WebLayerTest.cpp',
             'tests/WebPageNewSerializerTest.cpp',
             'tests/WebPageSerializerTest.cpp',
+            'tests/WebSocketDeflaterTest.cpp',
             'tests/WebSocketExtensionDispatcherTest.cpp',
             'tests/WebURLRequestTest.cpp',
             'tests/WebViewTest.cpp',
diff --git a/Source/WebKit/chromium/tests/WebSocketDeflaterTest.cpp b/Source/WebKit/chromium/tests/WebSocketDeflaterTest.cpp
new file mode 100644 (file)
index 0000000..423a596
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+
+#include "WebSocketDeflater.h"
+
+#include <gtest/gtest.h>
+#include <wtf/Vector.h>
+
+using namespace WebCore;
+
+namespace {
+
+TEST(WebSocketDeflaterTest, TestCompressHello)
+{
+    // Test the first example on section 4.3 of the specification.
+    OwnPtr<WebSocketDeflater> deflater = WebSocketDeflater::create(15);
+    ASSERT_TRUE(deflater->initialize());
+    OwnPtr<WebSocketInflater> inflater = WebSocketInflater::create();
+    ASSERT_TRUE(inflater->initialize());
+    const char* inputData = "Hello";
+    const size_t inputLength = strlen(inputData);
+
+    ASSERT_TRUE(deflater->addBytes(inputData, inputLength));
+    ASSERT_TRUE(deflater->finish());
+    const char expectedFirst[] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00};
+    EXPECT_EQ(sizeof(expectedFirst), deflater->size());
+    EXPECT_EQ(0, memcmp(expectedFirst, deflater->data(), deflater->size()));
+    ASSERT_TRUE(inflater->addBytes(deflater->data(), deflater->size()));
+    ASSERT_TRUE(inflater->finish());
+    EXPECT_EQ(inputLength, inflater->size());
+    EXPECT_EQ(0, memcmp(inputData, inflater->data(), inflater->size()));
+
+    deflater->reset();
+    inflater->reset();
+
+    ASSERT_TRUE(deflater->addBytes(inputData, inputLength));
+    ASSERT_TRUE(deflater->finish());
+    const char expectedSecond[] = {0xf2, 0x00, 0x11, 0x00, 0x00};
+    EXPECT_EQ(sizeof(expectedSecond), deflater->size());
+    EXPECT_EQ(0, memcmp(expectedSecond, deflater->data(), deflater->size()));
+    ASSERT_TRUE(inflater->addBytes(deflater->data(), deflater->size()));
+    ASSERT_TRUE(inflater->finish());
+    EXPECT_EQ(inputLength, inflater->size());
+    EXPECT_EQ(0, memcmp(inputData, inflater->data(), inflater->size()));
+}
+
+TEST(WebSocketDeflaterTest, TestMultipleAddBytesCalls)
+{
+    OwnPtr<WebSocketDeflater> deflater = WebSocketDeflater::create(15);
+    ASSERT_TRUE(deflater->initialize());
+    OwnPtr<WebSocketInflater> inflater = WebSocketInflater::create();
+    ASSERT_TRUE(inflater->initialize());
+    Vector<char> inputData(32);
+    inputData.fill('a');
+
+    for (size_t i = 0; i < inputData.size(); ++i)
+        ASSERT_TRUE(deflater->addBytes(inputData.data() + i, 1));
+    ASSERT_TRUE(deflater->finish());
+    for (size_t i = 0; i < deflater->size(); ++i)
+        ASSERT_TRUE(inflater->addBytes(deflater->data() + i, 1));
+    ASSERT_TRUE(inflater->finish());
+    EXPECT_EQ(inputData.size(), inflater->size());
+    EXPECT_EQ(0, memcmp(inputData.data(), inflater->data(), inflater->size()));
+}
+
+TEST(WebSocketDeflaterTest, TestNoContextTakeOver)
+{
+    OwnPtr<WebSocketDeflater> deflater = WebSocketDeflater::create(15, WebSocketDeflater::DoNotTakeOverContext);
+    ASSERT_TRUE(deflater->initialize());
+    OwnPtr<WebSocketInflater> inflater = WebSocketInflater::create();
+    ASSERT_TRUE(inflater->initialize());
+    const char expected[] = {0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00};
+    const char* inputData = "Hello";
+    const size_t inputLength = strlen(inputData);
+
+    // If we don't take over context, the second result should be the identical
+    // with the first one.
+    for (size_t i = 0; i < 2; ++i) {
+        ASSERT_TRUE(deflater->addBytes(inputData, inputLength));
+        ASSERT_TRUE(deflater->finish());
+        EXPECT_EQ(sizeof(expected), deflater->size());
+        EXPECT_EQ(0, memcmp(expected, deflater->data(), deflater->size()));
+        ASSERT_TRUE(inflater->addBytes(deflater->data(), deflater->size()));
+        ASSERT_TRUE(inflater->finish());
+        EXPECT_EQ(inputLength, inflater->size());
+        EXPECT_EQ(0, memcmp(inputData, inflater->data(), inflater->size()));
+        deflater->reset();
+        inflater->reset();
+    }
+}
+
+TEST(WebSocketDeflaterTest, TestWindowBits)
+{
+    Vector<char> inputData(1024 + 64 * 2);
+    inputData.fill('a');
+    // Modify the head and tail of the inputData so that back-reference
+    // can be used if the window size is sufficiently-large.
+    for (size_t j = 0; j < 64; ++j) {
+        inputData[j] = 'b';
+        inputData[inputData.size() - j - 1] = 'b';
+    }
+
+    OwnPtr<WebSocketDeflater> deflater = WebSocketDeflater::create(8);
+    ASSERT_TRUE(deflater->initialize());
+    ASSERT_TRUE(deflater->addBytes(inputData.data(), inputData.size()));
+    ASSERT_TRUE(deflater->finish());
+
+    OwnPtr<WebSocketInflater> inflater = WebSocketInflater::create(8);
+    ASSERT_TRUE(inflater->initialize());
+    ASSERT_TRUE(inflater->addBytes(deflater->data(), deflater->size()));
+    ASSERT_TRUE(inflater->finish());
+    EXPECT_EQ(inputData.size(), inflater->size());
+    EXPECT_EQ(0, memcmp(inputData.data(), inflater->data(), inflater->size()));
+}
+
+TEST(WebSocketDeflaterTest, TestLargeData)
+{
+    OwnPtr<WebSocketDeflater> deflater = WebSocketDeflater::create(15);
+    ASSERT_TRUE(deflater->initialize());
+    OwnPtr<WebSocketInflater> inflater = WebSocketInflater::create();
+    ASSERT_TRUE(inflater->initialize());
+    Vector<char> inputData(16 * 1024 * 1024);
+    inputData.fill('a');
+
+    ASSERT_TRUE(deflater->addBytes(inputData.data(), inputData.size()));
+    ASSERT_TRUE(deflater->finish());
+    ASSERT_TRUE(inflater->addBytes(deflater->data(), deflater->size()));
+    ASSERT_TRUE(inflater->finish());
+    EXPECT_EQ(inputData.size(), inflater->size());
+    EXPECT_EQ(0, memcmp(inputData.data(), inflater->data(), inflater->size()));
+}
+
+}