[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[WebKit-https.git] / Source / WebCore / Modules / websockets / WebSocketDeflateFramer.cpp
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 #include "WebSocketDeflateFramer.h"
33
34 #include <wtf/HashMap.h>
35 #include <wtf/text/StringHash.h>
36 #include <wtf/text/WTFString.h>
37
38 namespace WebCore {
39
40 class WebSocketExtensionDeflateFrame : public WebSocketExtensionProcessor {
41     WTF_MAKE_FAST_ALLOCATED;
42 public:
43     explicit WebSocketExtensionDeflateFrame(WebSocketDeflateFramer*);
44     virtual ~WebSocketExtensionDeflateFrame() = default;
45
46     String handshakeString() override;
47     bool processResponse(const HashMap<String, String>&) override;
48     String failureReason() override { return m_failureReason; }
49
50 private:
51     WebSocketDeflateFramer* m_framer;
52     bool m_responseProcessed;
53     String m_failureReason;
54 };
55
56 // FXIME: Remove vendor prefix after the specification matured.
57 WebSocketExtensionDeflateFrame::WebSocketExtensionDeflateFrame(WebSocketDeflateFramer* framer)
58     : WebSocketExtensionProcessor("x-webkit-deflate-frame")
59     , m_framer(framer)
60     , m_responseProcessed(false)
61 {
62     ASSERT(m_framer);
63 }
64
65 String WebSocketExtensionDeflateFrame::handshakeString()
66 {
67     return extensionToken(); // No parameter
68 }
69
70 bool WebSocketExtensionDeflateFrame::processResponse(const HashMap<String, String>& serverParameters)
71 {
72 #if USE(ZLIB)
73     if (m_responseProcessed) {
74         m_failureReason = "Received duplicate deflate-frame response";
75         return false;
76     }
77     m_responseProcessed = true;
78
79     unsigned expectedNumParameters = 0;
80     int windowBits = 15;
81     HashMap<String, String>::const_iterator parameter = serverParameters.find("max_window_bits");
82     if (parameter != serverParameters.end()) {
83         windowBits = parameter->value.toInt();
84         if (windowBits < 8 || windowBits > 15) {
85             m_failureReason = "Received invalid max_window_bits parameter";
86             return false;
87         }
88         expectedNumParameters++;
89     }
90
91     WebSocketDeflater::ContextTakeOverMode mode = WebSocketDeflater::TakeOverContext;
92     parameter = serverParameters.find("no_context_takeover");
93     if (parameter != serverParameters.end()) {
94         if (!parameter->value.isNull()) {
95             m_failureReason = "Received invalid no_context_takeover parameter";
96             return false;
97         }
98         mode = WebSocketDeflater::DoNotTakeOverContext;
99         expectedNumParameters++;
100     }
101
102     if (expectedNumParameters != serverParameters.size()) {
103         m_failureReason = "Received unexpected deflate-frame parameter";
104         return false;
105     }
106
107     m_framer->enableDeflate(windowBits, mode);
108     return true;
109 #else
110     ASSERT_NOT_REACHED();
111     return false;
112 #endif
113 }
114
115 DeflateResultHolder::DeflateResultHolder(WebSocketDeflateFramer* framer)
116     : m_framer(framer)
117     , m_succeeded(true)
118 {
119     ASSERT(m_framer);
120 }
121
122 DeflateResultHolder::~DeflateResultHolder()
123 {
124     m_framer->resetDeflateContext();
125 }
126
127 void DeflateResultHolder::fail(const String& failureReason)
128 {
129     m_succeeded = false;
130     m_failureReason = failureReason;
131 }
132
133 InflateResultHolder::InflateResultHolder(WebSocketDeflateFramer* framer)
134     : m_framer(framer)
135     , m_succeeded(true)
136 {
137     ASSERT(m_framer);
138 }
139
140 InflateResultHolder::~InflateResultHolder()
141 {
142     m_framer->resetInflateContext();
143 }
144
145 void InflateResultHolder::fail(const String& failureReason)
146 {
147     m_succeeded = false;
148     m_failureReason = failureReason;
149 }
150
151 WebSocketDeflateFramer::WebSocketDeflateFramer()
152     : m_enabled(false)
153 {
154 }
155
156 std::unique_ptr<WebSocketExtensionProcessor> WebSocketDeflateFramer::createExtensionProcessor()
157 {
158     return makeUnique<WebSocketExtensionDeflateFrame>(this);
159 }
160
161 bool WebSocketDeflateFramer::canDeflate() const
162 {
163 #if USE(ZLIB)
164     return true;
165 #else
166     return false;
167 #endif
168 }
169
170 #if USE(ZLIB)
171 void WebSocketDeflateFramer::enableDeflate(int windowBits, WebSocketDeflater::ContextTakeOverMode mode)
172 {
173     m_deflater = makeUnique<WebSocketDeflater>(windowBits, mode);
174     m_inflater = makeUnique<WebSocketInflater>();
175     if (!m_deflater->initialize() || !m_inflater->initialize()) {
176         m_deflater = nullptr;
177         m_inflater = nullptr;
178         return;
179     }
180     m_enabled = true;
181 }
182 #endif
183
184 std::unique_ptr<DeflateResultHolder> WebSocketDeflateFramer::deflate(WebSocketFrame& frame)
185 {
186 #if USE(ZLIB)
187     auto result = makeUnique<DeflateResultHolder>(this);
188     if (!enabled() || !WebSocketFrame::isNonControlOpCode(frame.opCode) || !frame.payloadLength)
189         return result;
190     if (!m_deflater->addBytes(frame.payload, frame.payloadLength) || !m_deflater->finish()) {
191         result->fail("Failed to compress frame");
192         return result;
193     }
194     frame.compress = true;
195     frame.payload = m_deflater->data();
196     frame.payloadLength = m_deflater->size();
197     return result;
198 #else
199     return makeUnique<DeflateResultHolder>(this);
200 #endif
201 }
202
203 void WebSocketDeflateFramer::resetDeflateContext()
204 {
205 #if USE(ZLIB)
206     if (m_deflater)
207         m_deflater->reset();
208 #endif
209 }
210
211 std::unique_ptr<InflateResultHolder> WebSocketDeflateFramer::inflate(WebSocketFrame& frame)
212 {
213     auto result = makeUnique<InflateResultHolder>(this);
214     if (!enabled() && frame.compress) {
215         result->fail("Compressed bit must be 0 if no negotiated deflate-frame extension");
216         return result;
217     }
218 #if USE(ZLIB)
219     if (!frame.compress)
220         return result;
221     if (!WebSocketFrame::isNonControlOpCode(frame.opCode)) {
222         result->fail("Received unexpected compressed frame");
223         return result;
224     }
225     if (!m_inflater->addBytes(frame.payload, frame.payloadLength) || !m_inflater->finish()) {
226         result->fail("Failed to decompress frame");
227         return result;
228     }
229     frame.compress = false;
230     frame.payload = m_inflater->data();
231     frame.payloadLength = m_inflater->size();
232     return result;
233 #else
234     return result;
235 #endif
236 }
237
238 void WebSocketDeflateFramer::resetInflateContext()
239 {
240 #if USE(ZLIB)
241     if (m_inflater)
242         m_inflater->reset();
243 #endif
244 }
245
246 void WebSocketDeflateFramer::didFail()
247 {
248     resetDeflateContext();
249     resetInflateContext();
250 }
251
252 } // namespace WebCore