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 39namespace WebCore { 40 41class WebSocketExtensionDeflateFrame FINAL : public WebSocketExtensionProcessor { 42 WTF_MAKE_FAST_ALLOCATED; 43public: 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 54private: 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. 63WebSocketExtensionDeflateFrame::WebSocketExtensionDeflateFrame(WebSocketDeflateFramer* framer) 64 : WebSocketExtensionProcessor("x-webkit-deflate-frame") 65 , m_framer(framer) 66 , m_responseProcessed(false) 67{ 68 ASSERT(m_framer); 69} 70 71String WebSocketExtensionDeflateFrame::handshakeString() 72{ 73 return extensionToken(); // No parameter 74} 75 76bool 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 116DeflateResultHolder::DeflateResultHolder(WebSocketDeflateFramer* framer) 117 : m_framer(framer) 118 , m_succeeded(true) 119{ 120 ASSERT(m_framer); 121} 122 123DeflateResultHolder::~DeflateResultHolder() 124{ 125 m_framer->resetDeflateContext(); 126} 127 128void DeflateResultHolder::fail(const String& failureReason) 129{ 130 m_succeeded = false; 131 m_failureReason = failureReason; 132} 133 134InflateResultHolder::InflateResultHolder(WebSocketDeflateFramer* framer) 135 : m_framer(framer) 136 , m_succeeded(true) 137{ 138 ASSERT(m_framer); 139} 140 141InflateResultHolder::~InflateResultHolder() 142{ 143 m_framer->resetInflateContext(); 144} 145 146void InflateResultHolder::fail(const String& failureReason) 147{ 148 m_succeeded = false; 149 m_failureReason = failureReason; 150} 151 152WebSocketDeflateFramer::WebSocketDeflateFramer() 153 : m_enabled(false) 154{ 155} 156 157PassOwnPtr<WebSocketExtensionProcessor> WebSocketDeflateFramer::createExtensionProcessor() 158{ 159 return WebSocketExtensionDeflateFrame::create(this); 160} 161 162void 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 174PassOwnPtr<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 189void WebSocketDeflateFramer::resetDeflateContext() 190{ 191 if (m_deflater) 192 m_deflater->reset(); 193} 194 195PassOwnPtr<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 216void WebSocketDeflateFramer::resetInflateContext() 217{ 218 if (m_inflater) 219 m_inflater->reset(); 220} 221 222void WebSocketDeflateFramer::didFail() 223{ 224 resetDeflateContext(); 225 resetInflateContext(); 226} 227 228} // namespace WebCore 229