2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #include "modules/websockets/WebSocketDeflateFramer.h"
35 #include "wtf/HashMap.h"
36 #include "wtf/text/StringHash.h"
37 #include "wtf/text/WTFString.h"
41 class WebSocketExtensionDeflateFrame FINAL : public WebSocketExtensionProcessor {
42 WTF_MAKE_FAST_ALLOCATED;
44 static PassOwnPtr<WebSocketExtensionDeflateFrame> create(WebSocketDeflateFramer* framer)
46 return adoptPtr(new WebSocketExtensionDeflateFrame(framer));
48 virtual ~WebSocketExtensionDeflateFrame() { }
50 virtual String handshakeString() OVERRIDE;
51 virtual bool processResponse(const HashMap<String, String>&) OVERRIDE;
52 virtual String failureReason() OVERRIDE { return m_failureReason; }
55 WebSocketExtensionDeflateFrame(WebSocketDeflateFramer*);
57 WebSocketDeflateFramer* m_framer;
58 bool m_responseProcessed;
59 String m_failureReason;
62 // FXIME: Remove vendor prefix after the specification matured.
63 WebSocketExtensionDeflateFrame::WebSocketExtensionDeflateFrame(WebSocketDeflateFramer* framer)
64 : WebSocketExtensionProcessor("x-webkit-deflate-frame")
66 , m_responseProcessed(false)
71 String WebSocketExtensionDeflateFrame::handshakeString()
73 return extensionToken(); // No parameter
76 bool WebSocketExtensionDeflateFrame::processResponse(const HashMap<String, String>& serverParameters)
78 if (m_responseProcessed) {
79 m_failureReason = "Received duplicate deflate-frame response";
82 m_responseProcessed = true;
84 unsigned expectedNumParameters = 0;
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";
93 expectedNumParameters++;
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";
103 mode = WebSocketDeflater::DoNotTakeOverContext;
104 expectedNumParameters++;
107 if (expectedNumParameters != serverParameters.size()) {
108 m_failureReason = "Received unexpected deflate-frame parameter";
112 m_framer->enableDeflate(windowBits, mode);
116 DeflateResultHolder::DeflateResultHolder(WebSocketDeflateFramer* framer)
123 DeflateResultHolder::~DeflateResultHolder()
125 m_framer->resetDeflateContext();
128 void DeflateResultHolder::fail(const String& failureReason)
131 m_failureReason = failureReason;
134 InflateResultHolder::InflateResultHolder(WebSocketDeflateFramer* framer)
141 InflateResultHolder::~InflateResultHolder()
143 m_framer->resetInflateContext();
146 void InflateResultHolder::fail(const String& failureReason)
149 m_failureReason = failureReason;
152 WebSocketDeflateFramer::WebSocketDeflateFramer()
157 PassOwnPtr<WebSocketExtensionProcessor> WebSocketDeflateFramer::createExtensionProcessor()
159 return WebSocketExtensionDeflateFrame::create(this);
162 void WebSocketDeflateFramer::enableDeflate(int windowBits, WebSocketDeflater::ContextTakeOverMode mode)
164 m_deflater = WebSocketDeflater::create(windowBits, mode);
165 m_inflater = WebSocketInflater::create();
166 if (!m_deflater->initialize() || !m_inflater->initialize()) {
174 PassOwnPtr<DeflateResultHolder> WebSocketDeflateFramer::deflate(WebSocketFrame& frame)
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();
183 frame.compress = true;
184 frame.payload = m_deflater->data();
185 frame.payloadLength = m_deflater->size();
186 return result.release();
189 void WebSocketDeflateFramer::resetDeflateContext()
195 PassOwnPtr<InflateResultHolder> WebSocketDeflateFramer::inflate(WebSocketFrame& frame)
197 OwnPtr<InflateResultHolder> result = InflateResultHolder::create(this);
199 return result.release();
201 return result.release();
202 if (!WebSocketFrame::isNonControlOpCode(frame.opCode)) {
203 result->fail("Received unexpected compressed frame");
204 return result.release();
206 if (!m_inflater->addBytes(frame.payload, frame.payloadLength) || !m_inflater->finish()) {
207 result->fail("Failed to decompress frame");
208 return result.release();
210 frame.compress = false;
211 frame.payload = m_inflater->data();
212 frame.payloadLength = m_inflater->size();
213 return result.release();
216 void WebSocketDeflateFramer::resetInflateContext()
222 void WebSocketDeflateFramer::didFail()
224 resetDeflateContext();
225 resetInflateContext();