diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
commit | ad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (patch) | |
tree | b34b0daceb7c8e7fdde4b4ec43650ab7caadb0a9 /Source/WebCore/websockets/WebSocketDeflater.cpp | |
parent | 03e12282df9aa1e1fb05a8b90f1cfc2e08764cec (diff) | |
download | qtwebkit-ad0d549d4cc13433f77c1ac8f0ab379c83d93f28.tar.gz |
Imported WebKit commit bb52bf3c0119e8a128cd93afe5572413a8617de9 (http://svn.webkit.org/repository/webkit/trunk@108790)
Diffstat (limited to 'Source/WebCore/websockets/WebSocketDeflater.cpp')
-rw-r--r-- | Source/WebCore/websockets/WebSocketDeflater.cpp | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/Source/WebCore/websockets/WebSocketDeflater.cpp b/Source/WebCore/websockets/WebSocketDeflater.cpp new file mode 100644 index 000000000..47ea94055 --- /dev/null +++ b/Source/WebCore/websockets/WebSocketDeflater.cpp @@ -0,0 +1,212 @@ +/* + * 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> +#include <zlib.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); + m_stream = adoptPtr(new z_stream); + memset(m_stream.get(), 0, sizeof(z_stream)); +} + +bool WebSocketDeflater::initialize() +{ + return deflateInit2(m_stream.get(), Z_DEFAULT_COMPRESSION, Z_DEFLATED, -m_windowBits, defaultMemLevel, Z_DEFAULT_STRATEGY) == Z_OK; +} + +WebSocketDeflater::~WebSocketDeflater() +{ + int result = deflateEnd(m_stream.get()); + 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.get(), length); + size_t writePosition = m_buffer.size(); + m_buffer.grow(writePosition + maxLength); + setStreamParameter(m_stream.get(), data, length, m_buffer.data() + writePosition, maxLength); + int result = deflate(m_stream.get(), 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.get(), 0, 0, m_buffer.data() + writePosition, availableCapacity); + int result = deflate(m_stream.get(), 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.get()); +} + +PassOwnPtr<WebSocketInflater> WebSocketInflater::create(int windowBits) +{ + return adoptPtr(new WebSocketInflater(windowBits)); +} + +WebSocketInflater::WebSocketInflater(int windowBits) + : m_windowBits(windowBits) +{ + m_stream = adoptPtr(new z_stream); + memset(m_stream.get(), 0, sizeof(z_stream)); +} + +bool WebSocketInflater::initialize() +{ + return inflateInit2(m_stream.get(), -m_windowBits) == Z_OK; +} + +WebSocketInflater::~WebSocketInflater() +{ + int result = inflateEnd(m_stream.get()); + 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.get(), data + consumedSoFar, remainingLength, m_buffer.data() + writePosition, availableCapacity); + int result = inflate(m_stream.get(), 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.get(), strippedFields + consumedSoFar, remainingLength, m_buffer.data() + writePosition, availableCapacity); + int result = inflate(m_stream.get(), 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) |