Home | History | Annotate | Download | only in websockets
      1 /*
      2  * Copyright (C) 2012 Google Inc.  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 
     33 #include "modules/websockets/WebSocketDeflateFramer.h"
     34 
     35 #include "wtf/HashMap.h"
     36 #include "wtf/text/StringHash.h"
     37 #include "wtf/text/WTFString.h"
     38 
     39 namespace WebCore {
     40 
     41 class WebSocketExtensionDeflateFrame : public WebSocketExtensionProcessor {
     42     WTF_MAKE_FAST_ALLOCATED;
     43 public:
     44     static PassOwnPtr<WebSocketExtensionDeflateFrame> create(WebSocketDeflateFramer* framer)
     45     {
     46         return adoptPtr(new WebSocketExtensionDeflateFrame(framer));
     47     }
     48     virtual ~WebSocketExtensionDeflateFrame() { }
     49 
     50     virtual String handshakeString() OVERRIDE;
     51     virtual bool processResponse(const HashMap<String, String>&) OVERRIDE;
     52     virtual String failureReason() OVERRIDE { return m_failureReason; }
     53 
     54 private:
     55     WebSocketExtensionDeflateFrame(WebSocketDeflateFramer*);
     56 
     57     WebSocketDeflateFramer* m_framer;
     58     bool m_responseProcessed;
     59     String m_failureReason;
     60 };
     61 
     62 // FXIME: Remove vendor prefix after the specification matured.
     63 WebSocketExtensionDeflateFrame::WebSocketExtensionDeflateFrame(WebSocketDeflateFramer* framer)
     64     : WebSocketExtensionProcessor("x-webkit-deflate-frame")
     65     , m_framer(framer)
     66     , m_responseProcessed(false)
     67 {
     68     ASSERT(m_framer);
     69 }
     70 
     71 String WebSocketExtensionDeflateFrame::handshakeString()
     72 {
     73     return extensionToken(); // No parameter
     74 }
     75 
     76 bool WebSocketExtensionDeflateFrame::processResponse(const HashMap<String, String>& serverParameters)
     77 {
     78     if (m_responseProcessed) {
     79         m_failureReason = "Received duplicate deflate-frame response";
     80         return false;
     81     }
     82     m_responseProcessed = true;
     83 
     84     unsigned expectedNumParameters = 0;
     85     int windowBits = 15;
     86     HashMap<String, String>::const_iterator parameter = serverParameters.find("max_window_bits");
     87     if (parameter != serverParameters.end()) {
     88         windowBits = parameter->value.toInt();
     89         if (windowBits < 8 || windowBits > 15) {
     90             m_failureReason = "Received invalid max_window_bits parameter";
     91             return false;
     92         }
     93         expectedNumParameters++;
     94     }
     95 
     96     WebSocketDeflater::ContextTakeOverMode mode = WebSocketDeflater::TakeOverContext;
     97     parameter = serverParameters.find("no_context_takeover");
     98     if (parameter != serverParameters.end()) {
     99         if (!parameter->value.isNull()) {
    100             m_failureReason = "Received invalid no_context_takeover parameter";
    101             return false;
    102         }
    103         mode = WebSocketDeflater::DoNotTakeOverContext;
    104         expectedNumParameters++;
    105     }
    106 
    107     if (expectedNumParameters != serverParameters.size()) {
    108         m_failureReason = "Received unexpected deflate-frame parameter";
    109         return false;
    110     }
    111 
    112     m_framer->enableDeflate(windowBits, mode);
    113     return true;
    114 }
    115 
    116 DeflateResultHolder::DeflateResultHolder(WebSocketDeflateFramer* framer)
    117     : m_framer(framer)
    118     , m_succeeded(true)
    119 {
    120     ASSERT(m_framer);
    121 }
    122 
    123 DeflateResultHolder::~DeflateResultHolder()
    124 {
    125     m_framer->resetDeflateContext();
    126 }
    127 
    128 void DeflateResultHolder::fail(const String& failureReason)
    129 {
    130     m_succeeded = false;
    131     m_failureReason = failureReason;
    132 }
    133 
    134 InflateResultHolder::InflateResultHolder(WebSocketDeflateFramer* framer)
    135     : m_framer(framer)
    136     , m_succeeded(true)
    137 {
    138     ASSERT(m_framer);
    139 }
    140 
    141 InflateResultHolder::~InflateResultHolder()
    142 {
    143     m_framer->resetInflateContext();
    144 }
    145 
    146 void InflateResultHolder::fail(const String& failureReason)
    147 {
    148     m_succeeded = false;
    149     m_failureReason = failureReason;
    150 }
    151 
    152 WebSocketDeflateFramer::WebSocketDeflateFramer()
    153     : m_enabled(false)
    154 {
    155 }
    156 
    157 PassOwnPtr<WebSocketExtensionProcessor> WebSocketDeflateFramer::createExtensionProcessor()
    158 {
    159     return WebSocketExtensionDeflateFrame::create(this);
    160 }
    161 
    162 void WebSocketDeflateFramer::enableDeflate(int windowBits, WebSocketDeflater::ContextTakeOverMode mode)
    163 {
    164     m_deflater = WebSocketDeflater::create(windowBits, mode);
    165     m_inflater = WebSocketInflater::create();
    166     if (!m_deflater->initialize() || !m_inflater->initialize()) {
    167         m_deflater.clear();
    168         m_inflater.clear();
    169         return;
    170     }
    171     m_enabled = true;
    172 }
    173 
    174 PassOwnPtr<DeflateResultHolder> WebSocketDeflateFramer::deflate(WebSocketFrame& frame)
    175 {
    176     OwnPtr<DeflateResultHolder> result = DeflateResultHolder::create(this);
    177     if (!enabled() || !WebSocketFrame::isNonControlOpCode(frame.opCode) || !frame.payloadLength)
    178         return result.release();
    179     if (!m_deflater->addBytes(frame.payload, frame.payloadLength) || !m_deflater->finish()) {
    180         result->fail("Failed to compress frame");
    181         return result.release();
    182     }
    183     frame.compress = true;
    184     frame.payload = m_deflater->data();
    185     frame.payloadLength = m_deflater->size();
    186     return result.release();
    187 }
    188 
    189 void WebSocketDeflateFramer::resetDeflateContext()
    190 {
    191     if (m_deflater)
    192         m_deflater->reset();
    193 }
    194 
    195 PassOwnPtr<InflateResultHolder> WebSocketDeflateFramer::inflate(WebSocketFrame& frame)
    196 {
    197     OwnPtr<InflateResultHolder> result = InflateResultHolder::create(this);
    198     if (!enabled())
    199         return result.release();
    200     if (!frame.compress)
    201         return result.release();
    202     if (!WebSocketFrame::isNonControlOpCode(frame.opCode)) {
    203         result->fail("Received unexpected compressed frame");
    204         return result.release();
    205     }
    206     if (!m_inflater->addBytes(frame.payload, frame.payloadLength) || !m_inflater->finish()) {
    207         result->fail("Failed to decompress frame");
    208         return result.release();
    209     }
    210     frame.compress = false;
    211     frame.payload = m_inflater->data();
    212     frame.payloadLength = m_inflater->size();
    213     return result.release();
    214 }
    215 
    216 void WebSocketDeflateFramer::resetInflateContext()
    217 {
    218     if (m_inflater)
    219         m_inflater->reset();
    220 }
    221 
    222 void WebSocketDeflateFramer::didFail()
    223 {
    224     resetDeflateContext();
    225     resetInflateContext();
    226 }
    227 
    228 } // namespace WebCore
    229