15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2012 Google Inc.  All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions are
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * met:
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions of source code must retain the above copyright
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Redistributions in binary form must reproduce the above
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * in the documentation and/or other materials provided with the
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * distribution.
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *     * Neither the name of Google Inc. nor the names of its
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * contributors may be used to endorse or promote products derived from
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * this software without specific prior written permission.
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
3253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "modules/websockets/WebSocketDeflater.h"
3353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
3453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/platform/Logging.h"
3553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/FastMalloc.h"
3653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/HashMap.h"
3753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/StdLibExtras.h"
3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/StringExtras.h"
3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/text/StringHash.h"
4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "wtf/text/WTFString.h"
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <zlib.h>
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore {
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const int defaultMemLevel = 1;
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const size_t bufferIncrementUnit = 4096;
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)PassOwnPtr<WebSocketDeflater> WebSocketDeflater::create(int windowBits, ContextTakeOverMode contextTakeOverMode)
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return adoptPtr(new WebSocketDeflater(windowBits, contextTakeOverMode));
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebSocketDeflater::WebSocketDeflater(int windowBits, ContextTakeOverMode contextTakeOverMode)
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_windowBits(windowBits)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_contextTakeOverMode(contextTakeOverMode)
565267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    , m_isBytesAdded(false)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(m_windowBits >= 8);
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(m_windowBits <= 15);
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_stream = adoptPtr(new z_stream);
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    memset(m_stream.get(), 0, sizeof(z_stream));
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool WebSocketDeflater::initialize()
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return deflateInit2(m_stream.get(), Z_DEFAULT_COMPRESSION, Z_DEFLATED, -m_windowBits, defaultMemLevel, Z_DEFAULT_STRATEGY) == Z_OK;
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebSocketDeflater::~WebSocketDeflater()
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int result = deflateEnd(m_stream.get());
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (result != Z_OK)
7353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        LOG(Network, "WebSocketDeflater %p Destructor deflateEnd() failed: %d is returned", this, result);
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void setStreamParameter(z_stream* stream, const char* inputData, size_t inputLength, char* outputData, size_t outputLength)
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    stream->next_in = reinterpret_cast<Bytef*>(const_cast<char*>(inputData));
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    stream->avail_in = inputLength;
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    stream->next_out = reinterpret_cast<Bytef*>(outputData);
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    stream->avail_out = outputLength;
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool WebSocketDeflater::addBytes(const char* data, size_t length)
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!length)
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
8953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    // The estimation by deflateBound is not accurate if the zlib has some remaining input of the last compression.
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size_t maxLength = deflateBound(m_stream.get(), length);
9153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    do {
9253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        size_t writePosition = m_buffer.size();
9353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        m_buffer.grow(writePosition + maxLength);
9453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        setStreamParameter(m_stream.get(), data, length, m_buffer.data() + writePosition, maxLength);
9553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        int result = deflate(m_stream.get(), Z_NO_FLUSH);
9653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        if (result != Z_OK)
9753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)            return false;
9853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        m_buffer.shrink(writePosition + maxLength - m_stream->avail_out);
9953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        maxLength *= 2;
10053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    } while (m_stream->avail_in > 0);
1015267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    m_isBytesAdded = true;
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool WebSocketDeflater::finish()
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1075267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    if (!m_isBytesAdded) {
1085267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        // Since consecutive calls of deflate with Z_SYNC_FLUSH and no input lead to an error,
1095267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        // we create and return the output for the empty input manually.
1105267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        ASSERT(!m_buffer.size());
1115267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        m_buffer.append("\x02\x00", 2);
1125267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)        return true;
1135267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    }
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    while (true) {
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t writePosition = m_buffer.size();
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_buffer.grow(writePosition + bufferIncrementUnit);
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t availableCapacity = m_buffer.size() - writePosition;
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        setStreamParameter(m_stream.get(), 0, 0, m_buffer.data() + writePosition, availableCapacity);
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int result = deflate(m_stream.get(), Z_SYNC_FLUSH);
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_buffer.shrink(writePosition + availableCapacity - m_stream->avail_out);
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (result == Z_OK)
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            break;
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (result != Z_BUF_ERROR)
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Remove 4 octets from the tail as the specification requires.
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_buffer.size() <= 4)
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_buffer.resize(m_buffer.size() - 4);
1305267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    m_isBytesAdded = false;
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void WebSocketDeflater::reset()
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_buffer.clear();
1375267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)    m_isBytesAdded = false;
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_contextTakeOverMode == DoNotTakeOverContext)
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        deflateReset(m_stream.get());
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
14253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)void WebSocketDeflater::softReset()
14353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles){
14453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)    m_buffer.clear();
14553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)}
14653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)PassOwnPtr<WebSocketInflater> WebSocketInflater::create(int windowBits)
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return adoptPtr(new WebSocketInflater(windowBits));
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebSocketInflater::WebSocketInflater(int windowBits)
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_windowBits(windowBits)
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_stream = adoptPtr(new z_stream);
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    memset(m_stream.get(), 0, sizeof(z_stream));
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool WebSocketInflater::initialize()
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return inflateInit2(m_stream.get(), -m_windowBits) == Z_OK;
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)WebSocketInflater::~WebSocketInflater()
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int result = inflateEnd(m_stream.get());
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (result != Z_OK)
16853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)        LOG(Network, "WebSocketInflater %p Destructor inflateEnd() failed: %d is returned", this, result);
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool WebSocketInflater::addBytes(const char* data, size_t length)
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!length)
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size_t consumedSoFar = 0;
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    while (consumedSoFar < length) {
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t writePosition = m_buffer.size();
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_buffer.grow(writePosition + bufferIncrementUnit);
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t availableCapacity = m_buffer.size() - writePosition;
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t remainingLength = length - consumedSoFar;
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        setStreamParameter(m_stream.get(), data + consumedSoFar, remainingLength, m_buffer.data() + writePosition, availableCapacity);
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int result = inflate(m_stream.get(), Z_NO_FLUSH);
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        consumedSoFar += remainingLength - m_stream->avail_in;
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_buffer.shrink(writePosition + availableCapacity - m_stream->avail_out);
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (result == Z_BUF_ERROR)
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (result == Z_STREAM_END) {
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Received a block with BFINAL set to 1. Reset decompression state.
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (inflateReset(m_stream.get()) != Z_OK)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return false;
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (result != Z_OK)
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT(remainingLength > m_stream->avail_in);
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(consumedSoFar == length);
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool WebSocketInflater::finish()
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    static const char* strippedFields = "\0\0\xff\xff";
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    static const size_t strippedLength = 4;
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Appends 4 octests of 0x00 0x00 0xff 0xff
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size_t consumedSoFar = 0;
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    while (consumedSoFar < strippedLength) {
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t writePosition = m_buffer.size();
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_buffer.grow(writePosition + bufferIncrementUnit);
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t availableCapacity = m_buffer.size() - writePosition;
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        size_t remainingLength = strippedLength - consumedSoFar;
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        setStreamParameter(m_stream.get(), strippedFields + consumedSoFar, remainingLength, m_buffer.data() + writePosition, availableCapacity);
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int result = inflate(m_stream.get(), Z_FINISH);
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        consumedSoFar += remainingLength - m_stream->avail_in;
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        m_buffer.shrink(writePosition + availableCapacity - m_stream->avail_out);
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (result == Z_BUF_ERROR)
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            continue;
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (result != Z_OK && result != Z_STREAM_END)
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return false;
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT(remainingLength > m_stream->avail_in);
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(consumedSoFar == strippedLength);
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void WebSocketInflater::reset()
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_buffer.clear();
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} // namespace WebCore
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
236