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.
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.vcproj/WebCore.vcproj: Ditto.
* 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: https://svn.webkit.org/repository/webkit/trunk@108468
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-02-22 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-22 Yanbin Zhang <yanbin.zhang@intel.com>
[GTK] fast/mediastream/peerconnection-argument-types.html fails
--- /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-22 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-22 Hojong Han <hojong.han@samsung.com>
Short circuit fixed for a 16 bt pattern character and an 8 bit string.
#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-22 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.
+
+ 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.vcproj/WebCore.vcproj: Ditto.
+ * 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-22 Yuta Kitamura <yutak@chromium.org>
Unreviewed, rolling out r108453.
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 \
'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