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