https://bugs.webkit.org/show_bug.cgi?id=77522
Source/JavaScriptCore:
Added USE(ZLIB) flag.
Reviewed by Kent Tamura.
* wtf/Platform.h:
Source/WebCore:
Add WebSocketDeflateFramer class which handles deflate-frame extension.
This class encapsulates WebSocketDeflater and WebSocketInflater classes,
which depend on zlib, so that WebSocketChannel is not necessary to aware
zlib dependency.
This is the second patch to land. The previous patch broke Chromium Win
release build. r108600 should fix the build failure. I also added
zlib entry to |export_dependent_settings| of |webcore_prerequisites|
target.
Reviewed by Kent Tamura.
Tests: http/tests/websocket/tests/hybi/compressed-control-frame.html
http/tests/websocket/tests/hybi/deflate-frame-comp-bit-onoff.html
http/tests/websocket/tests/hybi/deflate-frame-invalid-parameter.html
http/tests/websocket/tests/hybi/deflate-frame-parameter.html
* CMakeLists.txt: Added WebSocketDeflateFramer.(cpp|h)
* GNUmakefile.list.am: Ditto.
* Target.pri: Ditto.
* WebCore.gypi: Ditto.
* WebCore.gyp/WebCore.gyp: Added zlib dependency.
* WebCore.vcproj/WebCore.vcproj: Added WebSocketDeflateFramer.(cpp|h)
* WebCore.xcodeproj/project.pbxproj: Ditto.
* websockets/WebSocket.cpp:
(WebCore::WebSocket::didConnect): Set m_extensions.
* websockets/WebSocketChannel.cpp:
(WebCore::WebSocketChannel::connect): Add deflate-frame extension processor to WebSocketHanshake if deflate can use.
(WebCore::WebSocketChannel::fail): Call m_deflateFramer.didFail().
(WebCore::WebSocketChannel::processFrame): Decompress frames if needed.
(WebCore::WebSocketChannel::sendFrame): Compress frames if possible.
* websockets/WebSocketChannel.h:
* websockets/WebSocketDeflateFramer.cpp: Added.
(WebCore):
(WebSocketExtensionDeflateFrame):
(WebCore::WebSocketExtensionDeflateFrame::create):
(WebCore::WebSocketExtensionDeflateFrame::~WebSocketExtensionDeflateFrame):
(WebCore::WebSocketExtensionDeflateFrame::WebSocketExtensionDeflateFrame):
(WebCore::WebSocketExtensionDeflateFrame::handshakeString):
(WebCore::WebSocketExtensionDeflateFrame::processResponse):
(WebCore::DeflateResultHolder::DeflateResultHolder):
(WebCore::DeflateResultHolder::~DeflateResultHolder):
(WebCore::DeflateResultHolder::fail):
(WebCore::InflateResultHolder::InflateResultHolder):
(WebCore::InflateResultHolder::~InflateResultHolder):
(WebCore::InflateResultHolder::fail):
(WebCore::WebSocketDeflateFramer::WebSocketDeflateFramer):
(WebCore::WebSocketDeflateFramer::createExtensionProcessor):
(WebCore::WebSocketDeflateFramer::canDeflate):
(WebCore::WebSocketDeflateFramer::enableDeflate):
(WebCore::WebSocketDeflateFramer::deflate):
(WebCore::WebSocketDeflateFramer::resetDeflateContext):
(WebCore::WebSocketDeflateFramer::inflate):
(WebCore::WebSocketDeflateFramer::resetInflateContext):
(WebCore::WebSocketDeflateFramer::didFail):
* websockets/WebSocketDeflateFramer.h: Added.
(WebCore):
(DeflateResultHolder):
(WebCore::DeflateResultHolder::succeeded):
(WebCore::DeflateResultHolder::failureReason):
(InflateResultHolder):
(WebCore::InflateResultHolder::succeeded):
(WebCore::InflateResultHolder::failureReason):
(WebSocketDeflateFramer):
(WebCore::WebSocketDeflateFramer::enabled):
LayoutTests:
Added tests for WebSocket deflate-frame extension. Also updated some
tests to follow the change.
Reviewed by Kent Tamura.
* http/tests/websocket/tests/hybi/compressed-control-frame-expected.txt: Added.
* http/tests/websocket/tests/hybi/compressed-control-frame.html: Added.
* http/tests/websocket/tests/hybi/compressed-control-frame_wsh.py: Added.
(web_socket_do_extra_handshake):
(web_socket_transfer_data):
* http/tests/websocket/tests/hybi/deflate-frame-comp-bit-onoff-expected.txt: Added.
* http/tests/websocket/tests/hybi/deflate-frame-comp-bit-onoff.html: Added.
* http/tests/websocket/tests/hybi/deflate-frame-invalid-parameter-expected.txt: Added.
* http/tests/websocket/tests/hybi/deflate-frame-invalid-parameter.html: Added.
* http/tests/websocket/tests/hybi/deflate-frame-invalid-parameter_wsh.py: Added.
(web_socket_do_extra_handshake):
(web_socket_transfer_data):
* http/tests/websocket/tests/hybi/deflate-frame-parameter-expected.txt: Added.
* http/tests/websocket/tests/hybi/deflate-frame-parameter.html: Added.
* http/tests/websocket/tests/hybi/deflate-frame_wsh.py: Added.
(_get_deflate_frame_extension_processor):
(web_socket_do_extra_handshake):
(web_socket_transfer_data):
* http/tests/websocket/tests/hybi/handshake-fail-by-extensions-header-expected.txt:
* http/tests/websocket/tests/hybi/send-file-blob_wsh.py:
(_retrieve_frame):
(web_socket_transfer_data):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@108731
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-02-23 Kenichi Ishibashi <bashi@chromium.org>
+
+ Adding WebSocket per-frame DEFLATE extension
+ https://bugs.webkit.org/show_bug.cgi?id=77522
+
+ Added tests for WebSocket deflate-frame extension. Also updated some
+ tests to follow the change.
+
+ Reviewed by Kent Tamura.
+
+ * http/tests/websocket/tests/hybi/compressed-control-frame-expected.txt: Added.
+ * http/tests/websocket/tests/hybi/compressed-control-frame.html: Added.
+ * http/tests/websocket/tests/hybi/compressed-control-frame_wsh.py: Added.
+ (web_socket_do_extra_handshake):
+ (web_socket_transfer_data):
+ * http/tests/websocket/tests/hybi/deflate-frame-comp-bit-onoff-expected.txt: Added.
+ * http/tests/websocket/tests/hybi/deflate-frame-comp-bit-onoff.html: Added.
+ * http/tests/websocket/tests/hybi/deflate-frame-invalid-parameter-expected.txt: Added.
+ * http/tests/websocket/tests/hybi/deflate-frame-invalid-parameter.html: Added.
+ * http/tests/websocket/tests/hybi/deflate-frame-invalid-parameter_wsh.py: Added.
+ (web_socket_do_extra_handshake):
+ (web_socket_transfer_data):
+ * http/tests/websocket/tests/hybi/deflate-frame-parameter-expected.txt: Added.
+ * http/tests/websocket/tests/hybi/deflate-frame-parameter.html: Added.
+ * http/tests/websocket/tests/hybi/deflate-frame_wsh.py: Added.
+ (_get_deflate_frame_extension_processor):
+ (web_socket_do_extra_handshake):
+ (web_socket_transfer_data):
+ * http/tests/websocket/tests/hybi/handshake-fail-by-extensions-header-expected.txt:
+ * http/tests/websocket/tests/hybi/send-file-blob_wsh.py:
+ (_retrieve_frame):
+ (web_socket_transfer_data):
+
2012-02-23 Erik Arvidsson <arv@chromium.org>
Rename DOMWindow to Window in the bindings
--- /dev/null
+CONSOLE MESSAGE: Received unexpected compressed frame
+Test whether a compressed control frame is rejected
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+onopen() was called.
+onclose() was called.
+PASS closeEvent.wasClean is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../../js-test-resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script type="text/javascript">
+description("Test whether a compressed control frame is rejected");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+ layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+var ws = new WebSocket("ws://127.0.0.1:8880/websocket/tests/hybi/compressed-control-frame");
+var closeEvent;
+
+ws.onopen = function()
+{
+ debug("onopen() was called.");
+};
+
+ws.onmessage = function(event)
+{
+ var message = event.data;
+ testFailed("onmessage() was called. (message = \"" + message + "\")");
+};
+
+ws.onclose = function(event)
+{
+ debug("onclose() was called.");
+ closeEvent = event;
+ shouldBeFalse("closeEvent.wasClean");
+ finishJSTest();
+};
+
+</script>
+<script src="../../../../js-test-resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+# Copyright 2012, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+from mod_pywebsocket import common
+from mod_pywebsocket import stream
+import zlib
+
+
+def web_socket_do_extra_handshake(request):
+ pass
+
+
+def web_socket_transfer_data(request):
+ compress = zlib.compressobj(
+ zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
+ compressed_message = compress.compress('close message')
+ compressed_message += compress.flush(zlib.Z_SYNC_FLUSH)
+ compressed_message = compressed_message[:-4]
+ header = stream.create_header(
+ opcode=common.OPCODE_CLOSE, payload_length=len(compressed_message),
+ fin=1, rsv1=1, rsv2=0, rsv3=0, mask=False)
+ request.connection.write(header + compressed_message)
--- /dev/null
+Test compression enabled/disabled frame receiving.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+Sending message: "Hello"
+PASS event.data is 'Hello'
+Sending message: "DisableCompression"
+PASS event.data is 'DisableCompression'
+Sending message: "World"
+PASS event.data is 'World'
+Sending message: "EnableCompression"
+PASS event.data is 'EnableCompression'
+Sending message: "Goodbye"
+PASS event.data is 'Goodbye'
+onclose() was called.
+PASS closeEvent.wasClean is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../../js-test-resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+description("Test compression enabled/disabled frame receiving.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+ layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+var closeEvent;
+var ws;
+var messageIndex;
+
+var messages = [
+ "Hello",
+ "DisableCompression", // This disables compression
+ "World",
+ "EnableCompression", // This enables compression
+ "Goodbye"
+];
+
+ws = new WebSocket("ws://localhost:8880/websocket/tests/hybi/deflate-frame");
+
+ws.onopen = function(event)
+{
+ messageIndex = 0;
+ debug("Sending message: \"" + messages[messageIndex] + "\"");
+ ws.send(messages[messageIndex]);
+};
+
+ws.onmessage = function(event)
+{
+ shouldBe("event.data", "'" + messages[messageIndex] + "'");
+ if (messageIndex === messages.length - 1)
+ ws.close();
+ else {
+ messageIndex += 1;
+ debug("Sending message: \"" + messages[messageIndex] + "\"");
+ ws.send(messages[messageIndex]);
+ }
+};
+
+ws.onclose = function(event)
+{
+ debug("onclose() was called.");
+ closeEvent = event;
+ shouldBeTrue("closeEvent.wasClean");
+ finishJSTest();
+};
+
+</script>
+<script src="../../../../js-test-resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+CONSOLE MESSAGE: Received unexpected deflate-frame parameter
+CONSOLE MESSAGE: Received invalid max_window_bits parameter
+CONSOLE MESSAGE: Received invalid max_window_bits parameter
+CONSOLE MESSAGE: Received invalid no_context_takeover parameter
+CONSOLE MESSAGE: Received unexpected deflate-frame parameter
+Test whether WebSocket rejects invalid deflate-frame parameters.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+Testing parameter: "x-foo"
+onclose() was called.
+PASS closeEvent.wasClean is false
+Testing parameter: "max_window_bits=7"
+onclose() was called.
+PASS closeEvent.wasClean is false
+Testing parameter: "max_window_bits=16"
+onclose() was called.
+PASS closeEvent.wasClean is false
+Testing parameter: "no_context_takeover=foo"
+onclose() was called.
+PASS closeEvent.wasClean is false
+Testing parameter: "max_window_bits=8; no_context_takeover; x-foo"
+onclose() was called.
+PASS closeEvent.wasClean is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../../js-test-resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+description("Test whether WebSocket rejects invalid deflate-frame parameters.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+ layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+var closeEvent;
+
+var testCase = [
+ "x-foo",
+ "max_window_bits=7",
+ "max_window_bits=16",
+ "no_context_takeover=foo",
+ "max_window_bits=8; no_context_takeover; x-foo"
+];
+
+function doTest(index)
+{
+ var parameter = testCase[index];
+ var url = "ws://localhost:8880/websocket/tests/hybi/deflate-frame-invalid-parameter?" + encodeURI(parameter);
+ var ws = new WebSocket(url);
+
+ debug("Testing parameter: \"" + parameter + "\"");
+
+ ws.onmessage = function(event)
+ {
+ var message = event.data;
+ testFailed("onmessage() was called. (message = \"" + message + "\")");
+ };
+
+ ws.onclose = function(event)
+ {
+ debug("onclose() was called.");
+ closeEvent = event;
+ shouldBeFalse("closeEvent.wasClean");
+ if (index === testCase.length - 1)
+ finishJSTest();
+ else
+ doTest(index + 1);
+ };
+}
+
+doTest(0);
+
+</script>
+<script src="../../../../js-test-resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+# Copyright 2012, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import urllib
+from mod_pywebsocket import handshake
+from mod_pywebsocket.handshake.hybi import compute_accept
+
+
+def web_socket_do_extra_handshake(request):
+ resources = request.ws_resource.split('?', 1)
+ parameters = None
+ if len(resources) == 2:
+ parameters = urllib.unquote(resources[1])
+
+ message = 'HTTP/1.1 101 Switching Protocols\r\n'
+ message += 'Upgrade: websocket\r\n'
+ message += 'Connection: Upgrade\r\n'
+ message += 'Sec-WebSocket-Accept: %s\r\n' % compute_accept(request.headers_in['Sec-WebSocket-Key'])[0]
+ message += 'Sec-WebSocket-Extensions: x-webkit-deflate-frame'
+ if parameters:
+ message += '; %s\r\n' % parameters
+ else:
+ message += '\r\n'
+ message += '\r\n'
+ request.connection.write(message)
+ raise handshake.AbortedByUserException('Abort the connection') # Prevents pywebsocket from sending its own handshake message.
+
+
+def web_socket_transfer_data(request):
+ pass
--- /dev/null
+Test WebSocket deflate-frame extension.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+Testing query: "max_window_bits=8"
+PASS ws.extensions.search('x-webkit-deflate-frame') != -1 is true
+PASS ws.extensions.search('max_window_bits=8') != -1 is true
+PASS event.data is firstMessage
+PASS event.data is secondMessage
+onclose() was called.
+PASS closeEvent.wasClean is true
+Testing query: "no_context_takeover"
+PASS ws.extensions.search('x-webkit-deflate-frame') != -1 is true
+PASS ws.extensions.search('no_context_takeover') != -1 is true
+PASS event.data is firstMessage
+PASS event.data is secondMessage
+onclose() was called.
+PASS closeEvent.wasClean is true
+Testing query: "max_window_bits=8&no_context_takeover"
+PASS ws.extensions.search('x-webkit-deflate-frame') != -1 is true
+PASS ws.extensions.search('max_window_bits=8') != -1 is true
+PASS ws.extensions.search('no_context_takeover') != -1 is true
+PASS event.data is firstMessage
+PASS event.data is secondMessage
+onclose() was called.
+PASS closeEvent.wasClean is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE HTML>
+<html>
+<head>
+<script src="../../../../js-test-resources/js-test-pre.js"></script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+description("Test WebSocket deflate-frame extension.");
+
+window.jsTestIsAsync = true;
+if (window.layoutTestController)
+ layoutTestController.overridePreference("WebKitHixie76WebSocketProtocolEnabled", 0);
+
+var closeEvent;
+var ws;
+var messageIndex;
+
+var queries = [
+ "max_window_bits=8",
+ "no_context_takeover",
+ "max_window_bits=8&no_context_takeover"
+];
+
+// The first message consists of a lot of 'b' and a few 'a' at the head and
+// the tail, while the second one consists of 'a'.
+var firstMessage = '';
+var secondMessage = '';
+for (var i = 0; i < 16; ++i) {
+ firstMessage += 'a';
+ secondMessage += 'a';
+}
+for (var i = 0; i < 1024; ++i) {
+ firstMessage += 'b';
+ secondMessage += 'a';
+}
+for (var i = 0; i < 16; ++i) {
+ firstMessage += 'a';
+ secondMessage += 'a';
+}
+
+function doTest(queryIndex)
+{
+ var query = queries[queryIndex];
+ debug("Testing query: \"" + query + "\"");
+
+ var url = "ws://localhost:8880/websocket/tests/hybi/deflate-frame?" + query;
+ ws = new WebSocket(url);
+ messageIndex = 0;
+
+ ws.onopen = function(event)
+ {
+ shouldBeTrue("ws.extensions.search('x-webkit-deflate-frame') != -1");
+ parameters = query.split('&');
+ for (var i = 0; i < parameters.length; ++i)
+ shouldBeTrue("ws.extensions.search('" + parameters[i] + "') != -1");
+ ws.send(firstMessage);
+ };
+
+ ws.onmessage = function(event)
+ {
+ if (messageIndex === 0) {
+ shouldBe("event.data", "firstMessage");
+ messageIndex += 1
+ ws.send(secondMessage);
+ } else {
+ shouldBe("event.data", "secondMessage");
+ ws.close();
+ }
+ };
+
+ ws.onclose = function(event)
+ {
+ debug("onclose() was called.");
+ closeEvent = event;
+ shouldBeTrue("closeEvent.wasClean");
+ if (queryIndex === queries.length - 1)
+ finishJSTest();
+ else
+ doTest(queryIndex + 1);
+ };
+}
+
+doTest(0);
+
+</script>
+<script src="../../../../js-test-resources/js-test-post.js"></script>
+</body>
+</html>
--- /dev/null
+# Copyright 2012, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import urlparse
+from mod_pywebsocket.extensions import DeflateFrameExtensionProcessor
+from mod_pywebsocket.extensions import ExtensionProcessorInterface
+from mod_pywebsocket.common import ExtensionParameter
+
+
+_GOODBYE_MESSAGE = u'Goodbye'
+_ENABLE_MESSAGE = u'EnableCompression'
+_DISABLE_MESSAGE = u'DisableCompression'
+
+
+def _get_deflate_frame_extension_processor(request):
+ for extension_processor in request.ws_extension_processors:
+ if isinstance(extension_processor, DeflateFrameExtensionProcessor):
+ return extension_processor
+ return None
+
+
+def web_socket_do_extra_handshake(request):
+ processor = _get_deflate_frame_extension_processor(request)
+ if not processor:
+ return
+ r = request.ws_resource.split('?', 1)
+ if len(r) == 1:
+ return
+ parameters = urlparse.parse_qs(r[1], keep_blank_values=True)
+ if 'max_window_bits' in parameters:
+ window_bits = int(parameters['max_window_bits'][0])
+ processor.set_response_window_bits(window_bits)
+ if 'no_context_takeover' in parameters:
+ processor.set_response_no_context_takeover(True)
+
+
+def web_socket_transfer_data(request):
+ processor = _get_deflate_frame_extension_processor(request)
+ while True:
+ line = request.ws_stream.receive_message()
+ if line is None:
+ return
+ if isinstance(line, unicode):
+ if processor:
+ if line == _ENABLE_MESSAGE:
+ processor.enable_outgoing_compression()
+ elif line == _DISABLE_MESSAGE:
+ processor.disable_outgoing_compression()
+ request.ws_stream.send_message(line, binary=False)
+ if line == _GOODBYE_MESSAGE:
+ return
+ else:
+ request.ws_stream.send_message(line, binary=True)
+
+
+# vi:sts=4 sw=4 et
-CONSOLE MESSAGE: Received unexpected Sec-WebSocket-Extensions header
+CONSOLE MESSAGE: Received unexpected extension: x-foo
Test whether WebSocket handshake fails if the server sends Sec-WebSocket-Extensions header.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
from mod_pywebsocket import msgutil
+def _retrieve_frame(stream):
+ # FIXME: Use better API.
+ frame = stream._receive_frame_as_frame_object()
+ for frame_filter in stream._options.incoming_frame_filters:
+ frame_filter.filter(frame)
+ return frame
+
+
def web_socket_do_extra_handshake(request):
pass # Always accept.
expected_messages = ['Hello, world!']
for test_number, expected_message in enumerate(expected_messages):
- # FIXME: Use better API.
- opcode, payload, final, unused_reserved1, unused_reserved2, unused_reserved3 = request.ws_stream._receive_frame()
- if opcode == common.OPCODE_BINARY and payload == expected_message and final:
+ frame = _retrieve_frame(request.ws_stream)
+ if frame.opcode == common.OPCODE_BINARY and frame.payload == expected_message and frame.fin:
msgutil.send_message(request, 'PASS: Message #%d.' % test_number)
else:
- msgutil.send_message(request, 'FAIL: Message #%d: Received unexpected frame: opcode = %r, payload = %r, final = %r' % (test_number, opcode, payload, final))
+ msgutil.send_message(request, 'FAIL: Message #%d: Received unexpected frame: opcode = %r, payload = %r, final = %r' % (test_number, frame.opcode, frame.payload, frame.fin))
def all_distinct_bytes():
+2012-02-23 Kenichi Ishibashi <bashi@chromium.org>
+
+ Adding WebSocket per-frame DEFLATE extension
+ https://bugs.webkit.org/show_bug.cgi?id=77522
+
+ Added USE(ZLIB) flag.
+
+ Reviewed by Kent Tamura.
+
+ * wtf/Platform.h:
+
2012-02-23 Mark Hahnenberg <mhahnenberg@apple.com>
Zero out CopiedBlocks on initialization
#define WTF_USE_WTFURL 0
#endif
+#if !PLATFORM(QT) && !PLATFORM(EFL)
+#define WTF_USE_ZLIB 1
+#endif
+
#endif /* WTF_Platform_h */
websockets/ThreadableWebSocketChannelClientWrapper.cpp
websockets/WebSocket.cpp
websockets/WebSocketChannel.cpp
+ websockets/WebSocketDeflateFramer.cpp
websockets/WebSocketExtensionDispatcher.cpp
websockets/WebSocketHandshake.cpp
websockets/WebSocketHandshakeRequest.cpp
+2012-02-23 Kenichi Ishibashi <bashi@chromium.org>
+
+ Adding WebSocket per-frame DEFLATE extension
+ https://bugs.webkit.org/show_bug.cgi?id=77522
+
+ Add WebSocketDeflateFramer class which handles deflate-frame extension.
+ This class encapsulates WebSocketDeflater and WebSocketInflater classes,
+ which depend on zlib, so that WebSocketChannel is not necessary to aware
+ zlib dependency.
+
+ This is the second patch to land. The previous patch broke Chromium Win
+ release build. r108600 should fix the build failure. I also added
+ zlib entry to |export_dependent_settings| of |webcore_prerequisites|
+ target.
+
+ Reviewed by Kent Tamura.
+
+ Tests: http/tests/websocket/tests/hybi/compressed-control-frame.html
+ http/tests/websocket/tests/hybi/deflate-frame-comp-bit-onoff.html
+ http/tests/websocket/tests/hybi/deflate-frame-invalid-parameter.html
+ http/tests/websocket/tests/hybi/deflate-frame-parameter.html
+
+ * CMakeLists.txt: Added WebSocketDeflateFramer.(cpp|h)
+ * GNUmakefile.list.am: Ditto.
+ * Target.pri: Ditto.
+ * WebCore.gypi: Ditto.
+ * WebCore.gyp/WebCore.gyp: Added zlib dependency.
+ * WebCore.vcproj/WebCore.vcproj: Added WebSocketDeflateFramer.(cpp|h)
+ * WebCore.xcodeproj/project.pbxproj: Ditto.
+ * websockets/WebSocket.cpp:
+ (WebCore::WebSocket::didConnect): Set m_extensions.
+ * websockets/WebSocketChannel.cpp:
+ (WebCore::WebSocketChannel::connect): Add deflate-frame extension processor to WebSocketHanshake if deflate can use.
+ (WebCore::WebSocketChannel::fail): Call m_deflateFramer.didFail().
+ (WebCore::WebSocketChannel::processFrame): Decompress frames if needed.
+ (WebCore::WebSocketChannel::sendFrame): Compress frames if possible.
+ * websockets/WebSocketChannel.h:
+ * websockets/WebSocketDeflateFramer.cpp: Added.
+ (WebCore):
+ (WebSocketExtensionDeflateFrame):
+ (WebCore::WebSocketExtensionDeflateFrame::create):
+ (WebCore::WebSocketExtensionDeflateFrame::~WebSocketExtensionDeflateFrame):
+ (WebCore::WebSocketExtensionDeflateFrame::WebSocketExtensionDeflateFrame):
+ (WebCore::WebSocketExtensionDeflateFrame::handshakeString):
+ (WebCore::WebSocketExtensionDeflateFrame::processResponse):
+ (WebCore::DeflateResultHolder::DeflateResultHolder):
+ (WebCore::DeflateResultHolder::~DeflateResultHolder):
+ (WebCore::DeflateResultHolder::fail):
+ (WebCore::InflateResultHolder::InflateResultHolder):
+ (WebCore::InflateResultHolder::~InflateResultHolder):
+ (WebCore::InflateResultHolder::fail):
+ (WebCore::WebSocketDeflateFramer::WebSocketDeflateFramer):
+ (WebCore::WebSocketDeflateFramer::createExtensionProcessor):
+ (WebCore::WebSocketDeflateFramer::canDeflate):
+ (WebCore::WebSocketDeflateFramer::enableDeflate):
+ (WebCore::WebSocketDeflateFramer::deflate):
+ (WebCore::WebSocketDeflateFramer::resetDeflateContext):
+ (WebCore::WebSocketDeflateFramer::inflate):
+ (WebCore::WebSocketDeflateFramer::resetInflateContext):
+ (WebCore::WebSocketDeflateFramer::didFail):
+ * websockets/WebSocketDeflateFramer.h: Added.
+ (WebCore):
+ (DeflateResultHolder):
+ (WebCore::DeflateResultHolder::succeeded):
+ (WebCore::DeflateResultHolder::failureReason):
+ (InflateResultHolder):
+ (WebCore::InflateResultHolder::succeeded):
+ (WebCore::InflateResultHolder::failureReason):
+ (WebSocketDeflateFramer):
+ (WebCore::WebSocketDeflateFramer::enabled):
+
2012-02-23 Andy Estes <aestes@apple.com>
Rename [setS|s]uppressIncrementalRendering to [setS|s]uppressesIncrementalRendering and make it WebPreferences API.
Source/WebCore/websockets/WebSocketChannel.h \
Source/WebCore/websockets/WebSocket.cpp \
Source/WebCore/websockets/WebSocket.h \
+ Source/WebCore/websockets/WebSocketDeflateFramer.cpp \
+ Source/WebCore/websockets/WebSocketDeflateFramer.h \
Source/WebCore/websockets/WebSocketDeflater.cpp \
Source/WebCore/websockets/WebSocketDeflater.h \
Source/WebCore/websockets/WebSocketExtensionDispatcher.cpp \
websockets/WebSocket.h \
websockets/WebSocketChannel.h \
websockets/WebSocketChannelClient.h \
+ websockets/WebSocketDeflateFramer.h \
websockets/WebSocketExtensionDispatcher.h \
websockets/WebSocketExtensionProcessor.h \
websockets/WebSocketFrame.h \
SOURCES += \
websockets/WebSocket.cpp \
websockets/WebSocketChannel.cpp \
+ websockets/WebSocketDeflateFramer.cpp \
websockets/WebSocketExtensionDispatcher.cpp \
websockets/WebSocketHandshake.cpp \
websockets/WebSocketHandshakeRequest.cpp \
'<(chromium_src_dir)/third_party/ots/ots.gyp:ots',
'<(chromium_src_dir)/third_party/sqlite/sqlite.gyp:sqlite',
'<(chromium_src_dir)/third_party/angle/src/build_angle.gyp:translator_glsl',
+ '<(chromium_src_dir)/third_party/zlib/zlib.gyp:zlib',
'<(chromium_src_dir)/v8/tools/gyp/v8.gyp:v8',
'<(libjpeg_gyp_path):libjpeg',
],
'websockets/WebSocketChannel.cpp',
'websockets/WebSocketChannel.h',
'websockets/WebSocketChannelClient.h',
+ 'websockets/WebSocketDeflateFramer.cpp',
+ 'websockets/WebSocketDeflateFramer.h',
'websockets/WebSocketDeflater.cpp',
'websockets/WebSocketDeflater.h',
'websockets/WebSocketExtensionDispatcher.cpp',
>
</File>
<File
+ RelativePath="..\websockets\WebSocketDeflateFramer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\websockets\WebSocketDeflateFramer.h"
+ >
+ </File>
+ <File
RelativePath="..\websockets\WebSocketDeflater.cpp"
>
</File>
4A1E719614E101F900626F9D /* JSHTMLShadowElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A1E719414E101F900626F9D /* JSHTMLShadowElement.h */; };
4A1E71A514E106AC00626F9D /* JSShadowRoot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A1E71A314E106AC00626F9D /* JSShadowRoot.cpp */; };
4A1E71A614E106AC00626F9D /* JSShadowRoot.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A1E71A414E106AC00626F9D /* JSShadowRoot.h */; };
+ 4A29222B14F468BA0021F77E /* WebSocketDeflateFramer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A29222914F468BA0021F77E /* WebSocketDeflateFramer.cpp */; };
+ 4A29222C14F468BA0021F77E /* WebSocketDeflateFramer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A29222A14F468BA0021F77E /* WebSocketDeflateFramer.h */; };
4A4A234614F1E1440046FBF1 /* WebSocketFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A4A234514F1E1440046FBF1 /* WebSocketFrame.h */; };
4A6E9FC313C17D1D0046A7F8 /* FontFeatureValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4A6E9FC113C17D1D0046A7F8 /* FontFeatureValue.cpp */; };
4A6E9FC413C17D1D0046A7F8 /* FontFeatureValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A6E9FC213C17D1D0046A7F8 /* FontFeatureValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
4A1E719414E101F900626F9D /* JSHTMLShadowElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSHTMLShadowElement.h; sourceTree = "<group>"; };
4A1E71A314E106AC00626F9D /* JSShadowRoot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSShadowRoot.cpp; sourceTree = "<group>"; };
4A1E71A414E106AC00626F9D /* JSShadowRoot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSShadowRoot.h; sourceTree = "<group>"; };
+ 4A29222914F468BA0021F77E /* WebSocketDeflateFramer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSocketDeflateFramer.cpp; sourceTree = "<group>"; };
+ 4A29222A14F468BA0021F77E /* WebSocketDeflateFramer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketDeflateFramer.h; sourceTree = "<group>"; };
4A4A234514F1E1440046FBF1 /* WebSocketFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSocketFrame.h; sourceTree = "<group>"; };
4A6E9FC113C17D1D0046A7F8 /* FontFeatureValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FontFeatureValue.cpp; sourceTree = "<group>"; };
4A6E9FC213C17D1D0046A7F8 /* FontFeatureValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontFeatureValue.h; sourceTree = "<group>"; };
510D4A47103177A20049EA54 /* WebSocketChannel.cpp */,
510D4A48103177A20049EA54 /* WebSocketChannel.h */,
510D4A49103177A20049EA54 /* WebSocketChannelClient.h */,
+ 4A29222914F468BA0021F77E /* WebSocketDeflateFramer.cpp */,
+ 4A29222A14F468BA0021F77E /* WebSocketDeflateFramer.h */,
4AE02ABB14E8A9D200BC3BA7 /* WebSocketDeflater.cpp */,
4AE02ABC14E8A9D200BC3BA7 /* WebSocketDeflater.h */,
4A957F0314E241100049DBFB /* WebSocketExtensionDispatcher.cpp */,
518A34C21026C831001B6896 /* WebSocket.h in Headers */,
510D4A4F103177A20049EA54 /* WebSocketChannel.h in Headers */,
510D4A50103177A20049EA54 /* WebSocketChannelClient.h in Headers */,
+ 4A29222C14F468BA0021F77E /* WebSocketDeflateFramer.h in Headers */,
4AE02ABE14E8A9D200BC3BA7 /* WebSocketDeflater.h in Headers */,
4A957F0714E241300049DBFB /* WebSocketExtensionDispatcher.h in Headers */,
4ADE25FA14E3BB4C004C2213 /* WebSocketExtensionProcessor.h in Headers */,
1CAF34820A6C405200ABE06E /* WebScriptObject.mm in Sources */,
518A34C11026C831001B6896 /* WebSocket.cpp in Sources */,
510D4A4E103177A20049EA54 /* WebSocketChannel.cpp in Sources */,
+ 4A29222B14F468BA0021F77E /* WebSocketDeflateFramer.cpp in Sources */,
4AE02ABD14E8A9D200BC3BA7 /* WebSocketDeflater.cpp in Sources */,
4A957F0614E2412A0049DBFB /* WebSocketExtensionDispatcher.cpp in Sources */,
51ABAE441043AB4A008C5260 /* WebSocketHandshake.cpp in Sources */,
ASSERT(scriptExecutionContext());
m_state = OPEN;
m_subprotocol = m_channel->subprotocol();
+ m_extensions = m_channel->extensions();
dispatchEvent(Event::create(eventNames().openEvent, false, false));
}
ASSERT(!m_suspended);
m_handshake = adoptPtr(new WebSocketHandshake(url, protocol, m_document, m_useHixie76Protocol));
m_handshake->reset();
+ if (!m_useHixie76Protocol && m_deflateFramer.canDeflate())
+ m_handshake->addExtensionProcessor(m_deflateFramer.createExtensionProcessor());
if (m_identifier)
InspectorInstrumentation::didCreateWebSocket(m_document, m_identifier, url, m_document->url());
ref();
m_shouldDiscardReceivedData = true;
if (m_buffer)
skipBuffer(m_bufferSize); // Save memory.
+ m_deflateFramer.didFail();
m_hasContinuousFrame = false;
m_continuousFrameData.clear();
}
ASSERT(m_buffer < frameEnd);
ASSERT(frameEnd <= m_buffer + m_bufferSize);
+ InflateResultHolder inflateResult = m_deflateFramer.inflate(frame);
+ if (!inflateResult.succeeded()) {
+ fail(inflateResult.failureReason());
+ return false;
+ }
+
// Validate the frame data.
if (WebSocketFrame::isReservedOpCode(frame.opCode)) {
fail("Unrecognized frame opcode: " + String::number(frame.opCode));
ASSERT(!(opCode & ~opCodeMask)); // Checks whether "opCode" fits in the range of opCodes.
WebSocketFrame frame(opCode, true, false, true, data, dataLength);
+
+ DeflateResultHolder deflateResult = m_deflateFramer.deflate(frame);
+ if (!deflateResult.succeeded()) {
+ fail(deflateResult.failureReason());
+ return false;
+ }
+
Vector<char> frameData;
makeFrameData(frame, frameData);
#include "SocketStreamHandleClient.h"
#include "ThreadableWebSocketChannel.h"
#include "Timer.h"
+#include "WebSocketDeflateFramer.h"
#include "WebSocketFrame.h"
#include "WebSocketHandshake.h"
#include <wtf/Deque.h>
OwnPtr<FileReaderLoader> m_blobLoader;
BlobLoaderStatus m_blobLoaderStatus;
#endif
+
+ WebSocketDeflateFramer m_deflateFramer;
};
} // namespace WebCore
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEB_SOCKETS)
+
+#include "WebSocketDeflateFramer.h"
+
+#include <wtf/HashMap.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class WebSocketExtensionDeflateFrame : public WebSocketExtensionProcessor {
+public:
+ static PassOwnPtr<WebSocketExtensionDeflateFrame> create(WebSocketDeflateFramer* framer)
+ {
+ return adoptPtr(new WebSocketExtensionDeflateFrame(framer));
+ }
+ virtual ~WebSocketExtensionDeflateFrame() { }
+
+ virtual String handshakeString() OVERRIDE;
+ virtual bool processResponse(const HashMap<String, String>&) OVERRIDE;
+ virtual String failureReason() OVERRIDE { return m_failureReason; }
+
+private:
+ WebSocketExtensionDeflateFrame(WebSocketDeflateFramer*);
+
+ WebSocketDeflateFramer* m_framer;
+ bool m_responseProcessed;
+ String m_failureReason;
+};
+
+// FXIME: Remove vendor prefix after the specification matured.
+WebSocketExtensionDeflateFrame::WebSocketExtensionDeflateFrame(WebSocketDeflateFramer* framer)
+ : WebSocketExtensionProcessor("x-webkit-deflate-frame")
+ , m_framer(framer)
+ , m_responseProcessed(false)
+{
+ ASSERT(m_framer);
+}
+
+String WebSocketExtensionDeflateFrame::handshakeString()
+{
+ return extensionToken(); // No parameter
+}
+
+bool WebSocketExtensionDeflateFrame::processResponse(const HashMap<String, String>& serverParameters)
+{
+#if USE(ZLIB)
+ if (m_responseProcessed) {
+ m_failureReason = "Received duplicate deflate-frame response";
+ return false;
+ }
+ m_responseProcessed = true;
+
+ int expectedNumParameters = 0;
+ int windowBits = 15;
+ HashMap<String, String>::const_iterator parameter = serverParameters.find("max_window_bits");
+ if (parameter != serverParameters.end()) {
+ windowBits = parameter->second.toInt();
+ if (windowBits < 8 || windowBits > 15) {
+ m_failureReason = "Received invalid max_window_bits parameter";
+ return false;
+ }
+ expectedNumParameters++;
+ }
+
+ WebSocketDeflater::ContextTakeOverMode mode = WebSocketDeflater::TakeOverContext;
+ parameter = serverParameters.find("no_context_takeover");
+ if (parameter != serverParameters.end()) {
+ if (!parameter->second.isNull()) {
+ m_failureReason = "Received invalid no_context_takeover parameter";
+ return false;
+ }
+ mode = WebSocketDeflater::DoNotTakeOverContext;
+ expectedNumParameters++;
+ }
+
+ if (expectedNumParameters != serverParameters.size()) {
+ m_failureReason = "Received unexpected deflate-frame parameter";
+ return false;
+ }
+
+ m_framer->enableDeflate(windowBits, mode);
+ return true;
+#else
+ ASSERT_NOT_REACHED();
+ return false;
+#endif
+}
+
+DeflateResultHolder::DeflateResultHolder(WebSocketDeflateFramer* framer)
+ : m_framer(framer)
+ , m_succeeded(true)
+{
+ ASSERT(m_framer);
+}
+
+DeflateResultHolder::~DeflateResultHolder()
+{
+ m_framer->resetDeflateContext();
+}
+
+void DeflateResultHolder::fail(const String& failureReason)
+{
+ m_succeeded = false;
+ m_failureReason = failureReason;
+}
+
+InflateResultHolder::InflateResultHolder(WebSocketDeflateFramer* framer)
+ : m_framer(framer)
+ , m_succeeded(true)
+{
+ ASSERT(m_framer);
+}
+
+InflateResultHolder::~InflateResultHolder()
+{
+ m_framer->resetInflateContext();
+}
+
+void InflateResultHolder::fail(const String& failureReason)
+{
+ m_succeeded = false;
+ m_failureReason = failureReason;
+}
+
+WebSocketDeflateFramer::WebSocketDeflateFramer()
+ : m_enabled(false)
+{
+}
+
+PassOwnPtr<WebSocketExtensionProcessor> WebSocketDeflateFramer::createExtensionProcessor()
+{
+ return WebSocketExtensionDeflateFrame::create(this);
+}
+
+bool WebSocketDeflateFramer::canDeflate() const
+{
+#if USE(ZLIB)
+ return true;
+#else
+ return false;
+#endif
+}
+
+#if USE(ZLIB)
+void WebSocketDeflateFramer::enableDeflate(int windowBits, WebSocketDeflater::ContextTakeOverMode mode)
+{
+ m_deflater = WebSocketDeflater::create(windowBits, mode);
+ m_inflater = WebSocketInflater::create();
+ if (!m_deflater || !m_inflater) {
+ m_deflater.clear();
+ m_inflater.clear();
+ return;
+ }
+ if (!m_deflater->initialize() || !m_inflater->initialize()) {
+ m_deflater.clear();
+ m_inflater.clear();
+ return;
+ }
+ m_enabled = true;
+}
+#endif
+
+DeflateResultHolder WebSocketDeflateFramer::deflate(WebSocketFrame& frame)
+{
+#if USE(ZLIB)
+ DeflateResultHolder result(this);
+ if (!enabled() || !WebSocketFrame::isNonControlOpCode(frame.opCode) || !frame.payloadLength)
+ return result;
+ if (!m_deflater->addBytes(frame.payload, frame.payloadLength) || !m_deflater->finish()) {
+ result.fail("Failed to compress frame");
+ return result;
+ }
+ frame.compress = true;
+ frame.payload = m_deflater->data();
+ frame.payloadLength = m_deflater->size();
+ return result;
+#else
+ return DeflateResultHolder(this);
+#endif
+}
+
+void WebSocketDeflateFramer::resetDeflateContext()
+{
+#if USE(ZLIB)
+ if (m_deflater)
+ m_deflater->reset();
+#endif
+}
+
+InflateResultHolder WebSocketDeflateFramer::inflate(WebSocketFrame& frame)
+{
+#if USE(ZLIB)
+ InflateResultHolder result(this);
+ if (!frame.compress)
+ return result;
+ if (!enabled() || !WebSocketFrame::isNonControlOpCode(frame.opCode)) {
+ result.fail("Received unexpected compressed frame");
+ return result;
+ }
+ if (!m_inflater->addBytes(frame.payload, frame.payloadLength) || !m_inflater->finish()) {
+ result.fail("Failed to decompress frame");
+ return result;
+ }
+ frame.compress = false;
+ frame.payload = m_inflater->data();
+ frame.payloadLength = m_inflater->size();
+ return result;
+#else
+ return InflateResultHolder(this);
+#endif
+}
+
+void WebSocketDeflateFramer::resetInflateContext()
+{
+#if USE(ZLIB)
+ if (m_inflater)
+ m_inflater->reset();
+#endif
+}
+
+void WebSocketDeflateFramer::didFail()
+{
+ resetDeflateContext();
+ resetInflateContext();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEB_SOCKETS)
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebSocketDeflateFramer_h
+#define WebSocketDeflateFramer_h
+
+#if ENABLE(WEB_SOCKETS)
+
+#if USE(ZLIB)
+#include "WebSocketDeflater.h"
+#endif
+#include "WebSocketExtensionProcessor.h"
+#include "WebSocketFrame.h"
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebCore {
+
+class WebSocketDeflateFramer;
+
+class DeflateResultHolder {
+public:
+ explicit DeflateResultHolder(WebSocketDeflateFramer*);
+ ~DeflateResultHolder();
+
+ bool succeeded() const { return m_succeeded; }
+ String failureReason() const { return m_failureReason; }
+
+ void fail(const String& failureReason);
+
+private:
+ WebSocketDeflateFramer* m_framer;
+ bool m_succeeded;
+ String m_failureReason;
+};
+
+class InflateResultHolder {
+public:
+ explicit InflateResultHolder(WebSocketDeflateFramer*);
+ ~InflateResultHolder();
+
+ bool succeeded() const { return m_succeeded; }
+ String failureReason() const { return m_failureReason; }
+
+ void fail(const String& failureReason);
+
+private:
+ WebSocketDeflateFramer* m_framer;
+ bool m_succeeded;
+ String m_failureReason;
+};
+
+class WebSocketDeflateFramer {
+public:
+ WebSocketDeflateFramer();
+
+ PassOwnPtr<WebSocketExtensionProcessor> createExtensionProcessor();
+
+ bool canDeflate() const;
+ bool enabled() const { return m_enabled; }
+
+ DeflateResultHolder deflate(WebSocketFrame&);
+ void resetDeflateContext();
+ InflateResultHolder inflate(WebSocketFrame&);
+ void resetInflateContext();
+
+ void didFail();
+
+#if USE(ZLIB)
+ void enableDeflate(int windowBits, WebSocketDeflater::ContextTakeOverMode);
+#endif
+
+private:
+ bool m_enabled;
+#if USE(ZLIB)
+ OwnPtr<WebSocketDeflater> m_deflater;
+ OwnPtr<WebSocketInflater> m_inflater;
+#endif
+};
+
+}
+
+#endif // ENABLE(WEB_SOCKETS)
+
+#endif // WebSocketDeflateFramer_h