<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[150225] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/150225">150225</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2013-05-16 17:33:55 -0700 (Thu, 16 May 2013)</dd>
</dl>

<h3>Log Message</h3>
<pre>[WebSocket] Update pywebsocket to <a href="http://trac.webkit.org/projects/webkit/changeset/760">r760</a>
https://bugs.webkit.org/show_bug.cgi?id=115863

Patch by Lamarque V. Souza &lt;Lamarque.Souza@basyskom.com&gt; on 2013-05-16
Reviewed by Alexey Proskuryakov.

Tools:

Version <a href="http://trac.webkit.org/projects/webkit/changeset/760">r760</a> supports a newer draft of message compression.
We need this update to finish the permessage compression patch in
bug 98840. This patch also fixes failing unit tests after the update.

* Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_base.py:
(StreamBase._read):
(StreamBase._read.of):
(StreamBase._write):
(StreamBase.receive_bytes):
(StreamBase._read_until):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py:
(parse_frame):
(StreamOptions.__init__):
(Stream.__init__):
(Stream._receive_frame_as_frame_object):
(Stream._get_message_from_frame):
(Stream._process_close_message):
(Stream.close_connection):
(Stream.get_last_received_opcode):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py:
* Scripts/webkitpy/thirdparty/mod_pywebsocket/dispatch.py:
(Dispatcher.do_extra_handshake):
(Dispatcher.transfer_data):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py:
(ExtensionProcessorInterface.__init__):
(ExtensionProcessorInterface.request):
(ExtensionProcessorInterface):
(ExtensionProcessorInterface.name):
(ExtensionProcessorInterface.check_consistency_with_other_processors):
(ExtensionProcessorInterface.set_active):
(ExtensionProcessorInterface.is_active):
(ExtensionProcessorInterface._get_extension_response_internal):
(ExtensionProcessorInterface.get_extension_response):
(ExtensionProcessorInterface._setup_stream_options_internal):
(ExtensionProcessorInterface.setup_stream_options):
(_log_outgoing_compression_ratio):
(_log_incoming_compression_ratio):
(_parse_window_bits):
(_AverageRatioCalculator):
(_AverageRatioCalculator.__init__):
(_AverageRatioCalculator.add_original_bytes):
(_AverageRatioCalculator.add_result_bytes):
(_AverageRatioCalculator.get_average_ratio):
(DeflateFrameExtensionProcessor):
(DeflateFrameExtensionProcessor.__init__):
(DeflateFrameExtensionProcessor._get_extension_response_internal):
(DeflateFrameExtensionProcessor._setup_stream_options_internal):
(DeflateFrameExtensionProcessor._outgoing_filter):
(DeflateFrameExtensionProcessor._incoming_filter):
(CompressionExtensionProcessorBase.for):
(CompressionExtensionProcessorBase.__init__):
(CompressionExtensionProcessorBase._get_extension_response_internal):
(CompressionExtensionProcessorBase._setup_stream_options_internal):
(PerFrameCompressExtensionProcessor):
(PerMessageDeflateExtensionProcessor):
(PerMessageDeflateExtensionProcessor.__init__):
(PerMessageDeflateExtensionProcessor._get_extension_response_internal):
(PerMessageDeflateExtensionProcessor._setup_stream_options_internal):
(PerMessageDeflateExtensionProcessor.set_c2s_max_window_bits):
(PerMessageDeflateExtensionProcessor.set_c2s_max_window_bits.adds):
(PerMessageDeflateExtensionProcessor.set_c2s_no_context_takeover):
(PerMessageDeflateExtensionProcessor.set_c2s_no_context_takeover.adds):
(PerMessageDeflateExtensionProcessor.set_bfinal):
(PerMessageDeflateExtensionProcessor.enable_outgoing_compression):
(PerMessageDeflateExtensionProcessor.disable_outgoing_compression):
(_PerMessageDeflateFramer):
(_PerMessageDeflateFramer.__init__):
(_PerMessageDeflateFramer.set_compress_outgoing_enabled):
(_PerMessageDeflateFramer._process_incoming_message):
(_PerMessageDeflateFramer._process_outgoing_message):
(_PerMessageDeflateFramer.setup_stream_options):
(_PerMessageDeflateFramer.setup_stream_options._OutgoingMessageFilter):
(_PerMessageDeflateFramer.setup_stream_options._OutgoingMessageFilter.__init__):
(_PerMessageDeflateFramer.setup_stream_options._OutgoingMessageFilter.filter):
(_PerMessageDeflateFramer.setup_stream_options._IncomingMessageFilter):
(_PerMessageDeflateFramer.setup_stream_options._IncomingMessageFilter.__init__):
(_PerMessageDeflateFramer.setup_stream_options._IncomingMessageFilter.decompress_next_message):
(_PerMessageDeflateFramer.setup_stream_options._IncomingMessageFilter.filter):
(_PerMessageDeflateFramer.setup_stream_options._OutgoingFrameFilter):
(_PerMessageDeflateFramer.setup_stream_options._OutgoingFrameFilter.__init__):
(_PerMessageDeflateFramer.setup_stream_options._OutgoingFrameFilter.set_compression_bit):
(_PerMessageDeflateFramer.setup_stream_options._OutgoingFrameFilter.filter):
(_PerMessageDeflateFramer.setup_stream_options._IncomingFrameFilter):
(_PerMessageDeflateFramer.setup_stream_options._IncomingFrameFilter.__init__):
(_PerMessageDeflateFramer.setup_stream_options._IncomingFrameFilter.filter):
(PerMessageCompressExtensionProcessor):
(PerMessageCompressExtensionProcessor._lookup_compression_processor):
(MuxExtensionProcessor.__init__):
(MuxExtensionProcessor.check_consistency_with_other_processors):
(MuxExtensionProcessor):
(MuxExtensionProcessor._get_extension_response_internal):
(MuxExtensionProcessor._setup_stream_options_internal):
(MuxExtensionProcessor.set_quota):
(MuxExtensionProcessor.quota):
(MuxExtensionProcessor.set_extensions):
(MuxExtensionProcessor.extensions):
(is_compression_extension):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py:
(validate_subprotocol):
(parse_host_header):
(format_header):
(check_request_line):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py:
(Handshaker.do_handshake):
(Handshaker._create_handshake_response):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi00.py:
(_validate_subprotocol):
(_check_header_lines):
(_build_location):
(Handshaker.do_handshake):
(Handshaker._set_subprotocol):
(Handshaker._set_location):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/headerparserhandler.py:
(_create_dispatcher):
(headerparserhandler):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/mux.py:
(_create_add_channel_response):
(_create_drop_channel):
(_create_flow_control):
(_create_new_channel_slot):
(_create_fallback_new_channel_slot):
(_MuxFramePayloadParser._read_number):
(_MuxFramePayloadParser._read_size_and_contents):
(_MuxFramePayloadParser._read_flow_control):
(_MuxFramePayloadParser._read_new_channel_slot):
(_LogicalConnection.__init__):
(_LogicalConnection.write):
(_LogicalConnection.on_write_data_done):
(_LogicalConnection):
(_LogicalConnection.on_writer_done):
(_InnerMessage):
(_InnerMessage.__init__):
(_InnerMessageBuilder):
(_InnerMessageBuilder.that):
(_InnerMessageBuilder.__init__):
(_InnerMessageBuilder._handle_first):
(_InnerMessageBuilder._process_first_fragmented_control):
(_InnerMessageBuilder._process_first_fragmented_message):
(_InnerMessageBuilder._handle_fragmented_control):
(_InnerMessageBuilder._reassemble_fragmented_control):
(_InnerMessageBuilder._handle_fragmented_message):
(_InnerMessageBuilder._reassemble_fragmented_message):
(_InnerMessageBuilder.build):
(_LogicalStream.__init__):
(_LogicalStream._create_inner_frame):
(_LogicalStream._write_inner_frame):
(_LogicalStream.replenish_send_quota):
(_LogicalStream.send_message):
(_LogicalStream._receive_frame):
(_LogicalStream._get_message_from_frame):
(_LogicalStream.stop_sending):
(_PhysicalConnectionWriter.__init__):
(_PhysicalConnectionWriter._write_data):
(_PhysicalConnectionWriter.run):
(_PhysicalConnectionWriter.stop):
(_Worker.run):
(_MuxHandshaker.__init__):
(_MuxHandshaker._create_stream):
(_MuxHandshaker._create_handshake_response):
(_HandshakeDeltaBase.create_headers):
(_MuxHandler.start):
(_MuxHandler.wait_until_done):
(_MuxHandler.notify_write_data_done):
(_MuxHandler._process_drop_channel):
(_MuxHandler._process_logical_frame):
(_MuxHandler.notify_reader_done):
(_MuxHandler):
(_MuxHandler.notify_writer_done):
(_MuxHandler.fail_physical_connection):
(_MuxHandler.fail_logical_channel):
(use_mux):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py:
(_StandaloneRequest.get_uri):
(_StandaloneRequest.get_unparsed_uri):
(_StandaloneRequest):
(_StandaloneRequest.is_https):
(_import_ssl):
(_import_pyopenssl):
(_StandaloneSSLConnection.for):
(_StandaloneSSLConnection):
(_StandaloneSSLConnection.__getattribute__):
(_StandaloneSSLConnection.__setattr__):
(_StandaloneSSLConnection.makefile):
(_StandaloneSSLConnection.shutdown):
(_StandaloneSSLConnection.recv):
(WebSocketServer.__init__):
(WebSocketServer._create_sockets):
(WebSocketServer.handle_error):
(WebSocketServer.get_request):
(WebSocketServer.get_request.default_callback):
(WebSocketRequestHandler.parse_request):
(_build_option_parser):
(_main):
(_main.if):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py:
(RepeatedXorMasker.__init__):
(RepeatedXorMasker._mask_using_swig):
(RepeatedXorMasker):
(RepeatedXorMasker._mask_using_array):
(_Deflater.compress_and_finish):
(_RFC1979Deflater.filter):
(DeflateSocket.send):

LayoutTests:

Fix failing tests.

* http/tests/websocket/tests/handler_map.txt:
* http/tests/websocket/tests/hybi/echo-host_wsh.py: Copied from LayoutTests/http/tests/websocket/tests/hybi/echo-location_wsh.py.
(web_socket_do_extra_handshake):
(web_socket_transfer_data):
* http/tests/websocket/tests/hybi/echo-path_wsh.py: Renamed from LayoutTests/http/tests/websocket/tests/hybi/echo-location_wsh.py.
(web_socket_do_extra_handshake):
(web_socket_transfer_data):
* http/tests/websocket/tests/hybi/url-no-trailing-slash-expected.txt:
* http/tests/websocket/tests/hybi/url-no-trailing-slash.html:
* http/tests/websocket/tests/hybi/url-with-credential-expected.txt:
* http/tests/websocket/tests/hybi/url-with-credential.html:
* http/tests/websocket/tests/hybi/url-with-empty-query-expected.txt:
* http/tests/websocket/tests/hybi/url-with-empty-query.html:
* http/tests/websocket/tests/hybi/url-with-query-expected.txt:
* http/tests/websocket/tests/hybi/url-with-query.html:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshandler_maptxt">trunk/LayoutTests/http/tests/websocket/tests/handler_map.txt</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiurlnotrailingslashexpectedtxt">trunk/LayoutTests/http/tests/websocket/tests/hybi/url-no-trailing-slash-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiurlnotrailingslashhtml">trunk/LayoutTests/http/tests/websocket/tests/hybi/url-no-trailing-slash.html</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiurlwithcredentialexpectedtxt">trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-credential-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiurlwithcredentialhtml">trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-credential.html</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiurlwithemptyqueryexpectedtxt">trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-empty-query-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiurlwithemptyqueryhtml">trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-empty-query.html</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiurlwithqueryexpectedtxt">trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-query-expected.txt</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiurlwithqueryhtml">trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-query.html</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsocket_stream_basepy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_base.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsocket_stream_hybipy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsocketcommonpy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsocketdispatchpy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/dispatch.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsocketextensionspy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsockethandshake_basepy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsockethandshakehybipy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsockethandshakehybi00py">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi00.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsocketheaderparserhandlerpy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/headerparserhandler.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsocketmuxpy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/mux.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsocketstandalonepy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py</a></li>
<li><a href="#trunkToolsScriptswebkitpythirdpartymod_pywebsocketutilpy">trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiechohost_wshpy">trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-host_wsh.py</a></li>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiechopath_wshpy">trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-path_wsh.py</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkLayoutTestshttptestswebsockettestshybiecholocation_wshpy">trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-location_wsh.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/ChangeLog        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -1,3 +1,28 @@
</span><ins>+2013-05-16  Lamarque V. Souza  &lt;Lamarque.Souza@basyskom.com&gt;
+
+        [WebSocket] Update pywebsocket to r760
+        https://bugs.webkit.org/show_bug.cgi?id=115863
+
+        Reviewed by Alexey Proskuryakov.
+
+        Fix failing tests.
+
+        * http/tests/websocket/tests/handler_map.txt:
+        * http/tests/websocket/tests/hybi/echo-host_wsh.py: Copied from LayoutTests/http/tests/websocket/tests/hybi/echo-location_wsh.py.
+        (web_socket_do_extra_handshake):
+        (web_socket_transfer_data):
+        * http/tests/websocket/tests/hybi/echo-path_wsh.py: Renamed from LayoutTests/http/tests/websocket/tests/hybi/echo-location_wsh.py.
+        (web_socket_do_extra_handshake):
+        (web_socket_transfer_data):
+        * http/tests/websocket/tests/hybi/url-no-trailing-slash-expected.txt:
+        * http/tests/websocket/tests/hybi/url-no-trailing-slash.html:
+        * http/tests/websocket/tests/hybi/url-with-credential-expected.txt:
+        * http/tests/websocket/tests/hybi/url-with-credential.html:
+        * http/tests/websocket/tests/hybi/url-with-empty-query-expected.txt:
+        * http/tests/websocket/tests/hybi/url-with-empty-query.html:
+        * http/tests/websocket/tests/hybi/url-with-query-expected.txt:
+        * http/tests/websocket/tests/hybi/url-with-query.html:
+
</ins><span class="cx"> 2013-05-16  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Content disappears when scrolling  http://www.childrenscancer.org/zach/
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshandler_maptxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/handler_map.txt (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/handler_map.txt        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/http/tests/websocket/tests/handler_map.txt        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><span class="cx"> # websocket handler map file.
</span><del>-# request to '/' will be handled by echo-location_wsh.py
</del><ins>+# request to '/' will be handled by echo-host_wsh.py
</ins><span class="cx"> # hybi/echo-location_wsh.py can handle both hixie-76 and hybi-10 protocols.
</span><del>-/ /websocket/tests/hybi/echo-location
</del><ins>+/ /websocket/tests/hybi/echo-host
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiechohost_wshpyfromrev150224trunkLayoutTestshttptestswebsockettestshybiecholocation_wshpy"></a>
<div class="copfile"><h4>Copied: trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-host_wsh.py (from rev 150224, trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-location_wsh.py) (0 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-host_wsh.py                                (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-host_wsh.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -0,0 +1,38 @@
</span><ins>+# Copyright (C) 2013 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
+# &quot;AS IS&quot; 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, msgutil
+
+
+def web_socket_do_extra_handshake(request):
+    pass
+
+
+def web_socket_transfer_data(request):
+    msgutil.send_message(request, request.headers_in.get(common.HOST_HEADER))
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiecholocation_wshpy"></a>
<div class="delfile"><h4>Deleted: trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-location_wsh.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-location_wsh.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-location_wsh.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -1,49 +0,0 @@
</span><del>-# Copyright (C) 2011 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
-# &quot;AS IS&quot; 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 msgutil
-from mod_pywebsocket.handshake._base import build_location
-
-
-def web_socket_do_extra_handshake(request):
-    pass
-
-
-def web_socket_transfer_data(request):
-    if hasattr(request, 'ws_location'):
-        location = request.ws_location
-    else:
-        # When hybi protocol is used, pywebsocket does not provide
-        # ws_location attribute because servers are not required to send
-        # Sec-WebSocket-Location header according to the protocol
-        # specification. If ws_location attribute is not available,
-        # we use pywebsocket's internal function &quot;build_function&quot;
-        # to obtain the identical value.
-        location = build_location(request)
-    msgutil.send_message(request, location)
</del></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiechopath_wshpyfromrev150224trunkLayoutTestshttptestswebsockettestshybiecholocation_wshpy"></a>
<div class="copfile"><h4>Copied: trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-path_wsh.py (from rev 150224, trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-location_wsh.py) (0 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-path_wsh.py                                (rev 0)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/echo-path_wsh.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -0,0 +1,38 @@
</span><ins>+# Copyright (C) 2013 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
+# &quot;AS IS&quot; 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, msgutil
+
+
+def web_socket_do_extra_handshake(request):
+    pass
+
+
+def web_socket_transfer_data(request):
+    msgutil.send_message(request, request.uri)
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiurlnotrailingslashexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/url-no-trailing-slash-expected.txt (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/url-no-trailing-slash-expected.txt        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/url-no-trailing-slash-expected.txt        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -3,10 +3,10 @@
</span><span class="cx"> On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
</span><span class="cx"> 
</span><span class="cx"> WebSocket is open
</span><del>-received:ws://127.0.0.1:8880/
</del><ins>+received:127.0.0.1:8880
</ins><span class="cx"> WebSocket is closed
</span><span class="cx"> PASS handshake_success is true
</span><del>-PASS ws_location is &quot;ws://127.0.0.1:8880/&quot;
</del><ins>+PASS host is &quot;127.0.0.1:8880&quot;
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiurlnotrailingslashhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/url-no-trailing-slash.html (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/url-no-trailing-slash.html        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/url-no-trailing-slash.html        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><del>-&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
</del><ins>+&lt;!DOCTYPE&quot;&gt;
</ins><span class="cx"> &lt;html&gt;
</span><span class="cx"> &lt;head&gt;
</span><del>-&lt;script src=&quot;../../../../js-test-resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
</del><ins>+&lt;script src=&quot;/js-test-resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx"> &lt;/head&gt;
</span><span class="cx"> &lt;body&gt;
</span><span class="cx"> &lt;div id=&quot;description&quot;&gt;&lt;/div&gt;
</span><span class="lines">@@ -13,7 +13,7 @@
</span><span class="cx"> 
</span><span class="cx"> var url = &quot;ws://127.0.0.1:8880&quot;;
</span><span class="cx"> var handshake_success = false;
</span><del>-var ws_location;
</del><ins>+var host
</ins><span class="cx"> 
</span><span class="cx"> var ws = new WebSocket(url);
</span><span class="cx"> ws.onopen = function () {
</span><span class="lines">@@ -21,18 +21,18 @@
</span><span class="cx">     handshake_success = true;
</span><span class="cx"> };
</span><span class="cx"> ws.onmessage = function (evt) {
</span><del>-    ws_location = evt.data;
-    debug(&quot;received:&quot; + ws_location);
</del><ins>+    host = evt.data;
+    debug(&quot;received:&quot; + host);
</ins><span class="cx">     ws.close();
</span><span class="cx"> };
</span><span class="cx"> ws.onclose = function () {
</span><span class="cx">     debug(&quot;WebSocket is closed&quot;);
</span><span class="cx">     shouldBeTrue(&quot;handshake_success&quot;);
</span><del>-    shouldBe(&quot;ws_location&quot;, '&quot;ws://127.0.0.1:8880/&quot;');
</del><ins>+    shouldBe(&quot;host&quot;, '&quot;127.0.0.1:8880&quot;');
</ins><span class="cx">     finishJSTest();
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> &lt;/script&gt;
</span><del>-&lt;script src=&quot;../../../../js-test-resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</del><ins>+&lt;script src=&quot;/js-test-resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx"> &lt;/body&gt;
</span><span class="cx"> &lt;/html&gt;
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiurlwithcredentialexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-credential-expected.txt (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-credential-expected.txt        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-credential-expected.txt        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -2,12 +2,12 @@
</span><span class="cx"> 
</span><span class="cx"> On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
</span><span class="cx"> 
</span><del>-url=ws://user:pass@127.0.0.1:8880/websocket/tests/hybi/echo-location
</del><ins>+url=ws://user:pass@127.0.0.1:8880/websocket/tests/hybi/echo-host
</ins><span class="cx"> WebSocket is open
</span><del>-received:ws://127.0.0.1:8880/websocket/tests/hybi/echo-location
</del><ins>+received:127.0.0.1:8880
</ins><span class="cx"> WebSocket is closed
</span><span class="cx"> PASS handshake_success is true
</span><del>-PASS ws_location is &quot;ws://127.0.0.1:8880/websocket/tests/hybi/echo-location&quot;
</del><ins>+PASS host is &quot;127.0.0.1:8880&quot;
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiurlwithcredentialhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-credential.html (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-credential.html        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-credential.html        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><del>-&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
</del><ins>+&lt;!DOCTYPE&quot;&gt;
</ins><span class="cx"> &lt;html&gt;
</span><span class="cx"> &lt;head&gt;
</span><del>-&lt;script src=&quot;../../../../js-test-resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
</del><ins>+&lt;script src=&quot;/js-test-resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx"> &lt;/head&gt;
</span><span class="cx"> &lt;body&gt;
</span><span class="cx"> &lt;div id=&quot;description&quot;&gt;&lt;/div&gt;
</span><span class="lines">@@ -11,15 +11,15 @@
</span><span class="cx"> 
</span><span class="cx"> window.jsTestIsAsync = true;
</span><span class="cx"> 
</span><del>-var url = &quot;ws://user:pass@127.0.0.1:8880/websocket/tests/hybi/echo-location&quot;;
</del><ins>+var url = &quot;ws://user:pass@127.0.0.1:8880/websocket/tests/hybi/echo-host&quot;;
</ins><span class="cx"> var handshake_success = false;
</span><del>-var ws_location;
</del><ins>+var host;
</ins><span class="cx"> 
</span><span class="cx"> function endTest()
</span><span class="cx"> {
</span><span class="cx">     clearTimeout(timeoutID);
</span><span class="cx">     shouldBeTrue(&quot;handshake_success&quot;);
</span><del>-    shouldBe(&quot;ws_location&quot;, '&quot;ws://127.0.0.1:8880/websocket/tests/hybi/echo-location&quot;');
</del><ins>+    shouldBe(&quot;host&quot;, '&quot;127.0.0.1:8880&quot;');
</ins><span class="cx">     finishJSTest();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -30,8 +30,8 @@
</span><span class="cx">     handshake_success = true;
</span><span class="cx"> };
</span><span class="cx"> ws.onmessage = function (evt) {
</span><del>-    ws_location = evt.data;
-    debug(&quot;received:&quot; + ws_location);
</del><ins>+    host = evt.data;
+    debug(&quot;received:&quot; + host);
</ins><span class="cx">     ws.close();
</span><span class="cx"> };
</span><span class="cx"> ws.onclose = function () {
</span><span class="lines">@@ -41,6 +41,6 @@
</span><span class="cx"> var timeoutID = setTimeout(&quot;endTest()&quot;, 2000);
</span><span class="cx"> 
</span><span class="cx"> &lt;/script&gt;
</span><del>-&lt;script src=&quot;../../../../js-test-resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</del><ins>+&lt;script src=&quot;/js-test-resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx"> &lt;/body&gt;
</span><span class="cx"> &lt;/html&gt;
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiurlwithemptyqueryexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-empty-query-expected.txt (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-empty-query-expected.txt        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-empty-query-expected.txt        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -2,12 +2,12 @@
</span><span class="cx"> 
</span><span class="cx"> On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
</span><span class="cx"> 
</span><del>-url=ws://127.0.0.1:8880/websocket/tests/hybi/echo-location?
</del><ins>+url=ws://127.0.0.1:8880/websocket/tests/hybi/echo-path?
</ins><span class="cx"> WebSocket is open
</span><del>-received:ws://127.0.0.1:8880/websocket/tests/hybi/echo-location?
</del><ins>+received:/websocket/tests/hybi/echo-path?
</ins><span class="cx"> WebSocket is closed
</span><span class="cx"> PASS handshake_success is true
</span><del>-PASS ws_location is url
</del><ins>+PASS path is expected_path
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiurlwithemptyqueryhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-empty-query.html (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-empty-query.html        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-empty-query.html        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><del>-&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
</del><ins>+&lt;!DOCTYPE&quot;&gt;
</ins><span class="cx"> &lt;html&gt;
</span><span class="cx"> &lt;head&gt;
</span><del>-&lt;script src=&quot;../../../../js-test-resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
</del><ins>+&lt;script src=&quot;/js-test-resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx"> &lt;/head&gt;
</span><span class="cx"> &lt;body&gt;
</span><span class="cx"> &lt;div id=&quot;description&quot;&gt;&lt;/div&gt;
</span><span class="lines">@@ -11,15 +11,16 @@
</span><span class="cx"> 
</span><span class="cx"> window.jsTestIsAsync = true;
</span><span class="cx"> 
</span><del>-var url = &quot;ws://127.0.0.1:8880/websocket/tests/hybi/echo-location?&quot;;
</del><ins>+var url = &quot;ws://127.0.0.1:8880/websocket/tests/hybi/echo-path?&quot;;
</ins><span class="cx"> var handshake_success = false;
</span><del>-var ws_location;
</del><ins>+var path;
+var expected_path = &quot;/websocket/tests/hybi/echo-path?&quot;;
</ins><span class="cx"> 
</span><span class="cx"> function endTest()
</span><span class="cx"> {
</span><span class="cx">     clearTimeout(timeoutID);
</span><span class="cx">     shouldBeTrue(&quot;handshake_success&quot;);
</span><del>-    shouldBe(&quot;ws_location&quot;, &quot;url&quot;);
</del><ins>+    shouldBe(&quot;path&quot;, &quot;expected_path&quot;);
</ins><span class="cx">     finishJSTest();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -30,8 +31,8 @@
</span><span class="cx">     handshake_success = true;
</span><span class="cx"> };
</span><span class="cx"> ws.onmessage = function (evt) {
</span><del>-    ws_location = evt.data;
-    debug(&quot;received:&quot; + ws_location);
</del><ins>+    path = evt.data;
+    debug(&quot;received:&quot; + path);
</ins><span class="cx">     ws.close();
</span><span class="cx"> };
</span><span class="cx"> ws.onclose = function () {
</span><span class="lines">@@ -41,6 +42,6 @@
</span><span class="cx"> var timeoutID = setTimeout(&quot;endTest()&quot;, 2000);
</span><span class="cx"> 
</span><span class="cx"> &lt;/script&gt;
</span><del>-&lt;script src=&quot;../../../../js-test-resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</del><ins>+&lt;script src=&quot;/js-test-resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx"> &lt;/body&gt;
</span><span class="cx"> &lt;/html&gt;
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiurlwithqueryexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-query-expected.txt (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-query-expected.txt        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-query-expected.txt        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -2,12 +2,12 @@
</span><span class="cx"> 
</span><span class="cx"> On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
</span><span class="cx"> 
</span><del>-url=ws://127.0.0.1:8880/websocket/tests/hybi/echo-location?q=v
</del><ins>+url=ws://127.0.0.1:8880/websocket/tests/hybi/echo-path?q=v
</ins><span class="cx"> WebSocket is open
</span><del>-received:ws://127.0.0.1:8880/websocket/tests/hybi/echo-location?q=v
</del><ins>+received:/websocket/tests/hybi/echo-path?q=v
</ins><span class="cx"> WebSocket is closed
</span><span class="cx"> PASS handshake_success is true
</span><del>-PASS ws_location is url
</del><ins>+PASS path is expected_path
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestshttptestswebsockettestshybiurlwithqueryhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-query.html (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-query.html        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/LayoutTests/http/tests/websocket/tests/hybi/url-with-query.html        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><del>-&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
</del><ins>+&lt;!DOCTYPE&quot;&gt;
</ins><span class="cx"> &lt;html&gt;
</span><span class="cx"> &lt;head&gt;
</span><del>-&lt;script src=&quot;../../../../js-test-resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
</del><ins>+&lt;script src=&quot;/js-test-resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx"> &lt;/head&gt;
</span><span class="cx"> &lt;body&gt;
</span><span class="cx"> &lt;div id=&quot;description&quot;&gt;&lt;/div&gt;
</span><span class="lines">@@ -11,15 +11,16 @@
</span><span class="cx"> 
</span><span class="cx"> window.jsTestIsAsync = true;
</span><span class="cx"> 
</span><del>-var url = &quot;ws://127.0.0.1:8880/websocket/tests/hybi/echo-location?q=v&quot;;
</del><ins>+var url = &quot;ws://127.0.0.1:8880/websocket/tests/hybi/echo-path?q=v&quot;;
</ins><span class="cx"> var handshake_success = false;
</span><del>-var ws_location;
</del><ins>+var path;
+var expected_path = &quot;/websocket/tests/hybi/echo-path?q=v&quot;;
</ins><span class="cx"> 
</span><span class="cx"> function endTest()
</span><span class="cx"> {
</span><span class="cx">     clearTimeout(timeoutID);
</span><span class="cx">     shouldBeTrue(&quot;handshake_success&quot;);
</span><del>-    shouldBe(&quot;ws_location&quot;, &quot;url&quot;);
</del><ins>+    shouldBe(&quot;path&quot;, &quot;expected_path&quot;);
</ins><span class="cx">     finishJSTest();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -30,8 +31,8 @@
</span><span class="cx">     handshake_success = true;
</span><span class="cx"> };
</span><span class="cx"> ws.onmessage = function (evt) {
</span><del>-    ws_location = evt.data;
-    debug(&quot;received:&quot; + ws_location);
</del><ins>+    path = evt.data;
+    debug(&quot;received:&quot; + path);
</ins><span class="cx">     ws.close();
</span><span class="cx"> };
</span><span class="cx"> ws.onclose = function () {
</span><span class="lines">@@ -41,6 +42,6 @@
</span><span class="cx"> var timeoutID = setTimeout(&quot;endTest()&quot;, 2000);
</span><span class="cx"> 
</span><span class="cx"> &lt;/script&gt;
</span><del>-&lt;script src=&quot;../../../../js-test-resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</del><ins>+&lt;script src=&quot;/js-test-resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx"> &lt;/body&gt;
</span><span class="cx"> &lt;/html&gt;
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/ChangeLog        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -1,3 +1,213 @@
</span><ins>+2013-05-16  Lamarque V. Souza  &lt;Lamarque.Souza@basyskom.com&gt;
+
+        [WebSocket] Update pywebsocket to r760
+        https://bugs.webkit.org/show_bug.cgi?id=115863
+
+        Reviewed by Alexey Proskuryakov.
+
+        Version r760 supports a newer draft of message compression.
+        We need this update to finish the permessage compression patch in
+        bug 98840. This patch also fixes failing unit tests after the update.
+
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_base.py:
+        (StreamBase._read):
+        (StreamBase._read.of):
+        (StreamBase._write):
+        (StreamBase.receive_bytes):
+        (StreamBase._read_until):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py:
+        (parse_frame):
+        (StreamOptions.__init__):
+        (Stream.__init__):
+        (Stream._receive_frame_as_frame_object):
+        (Stream._get_message_from_frame):
+        (Stream._process_close_message):
+        (Stream.close_connection):
+        (Stream.get_last_received_opcode):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py:
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/dispatch.py:
+        (Dispatcher.do_extra_handshake):
+        (Dispatcher.transfer_data):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py:
+        (ExtensionProcessorInterface.__init__):
+        (ExtensionProcessorInterface.request):
+        (ExtensionProcessorInterface):
+        (ExtensionProcessorInterface.name):
+        (ExtensionProcessorInterface.check_consistency_with_other_processors):
+        (ExtensionProcessorInterface.set_active):
+        (ExtensionProcessorInterface.is_active):
+        (ExtensionProcessorInterface._get_extension_response_internal):
+        (ExtensionProcessorInterface.get_extension_response):
+        (ExtensionProcessorInterface._setup_stream_options_internal):
+        (ExtensionProcessorInterface.setup_stream_options):
+        (_log_outgoing_compression_ratio):
+        (_log_incoming_compression_ratio):
+        (_parse_window_bits):
+        (_AverageRatioCalculator):
+        (_AverageRatioCalculator.__init__):
+        (_AverageRatioCalculator.add_original_bytes):
+        (_AverageRatioCalculator.add_result_bytes):
+        (_AverageRatioCalculator.get_average_ratio):
+        (DeflateFrameExtensionProcessor):
+        (DeflateFrameExtensionProcessor.__init__):
+        (DeflateFrameExtensionProcessor._get_extension_response_internal):
+        (DeflateFrameExtensionProcessor._setup_stream_options_internal):
+        (DeflateFrameExtensionProcessor._outgoing_filter):
+        (DeflateFrameExtensionProcessor._incoming_filter):
+        (CompressionExtensionProcessorBase.for):
+        (CompressionExtensionProcessorBase.__init__):
+        (CompressionExtensionProcessorBase._get_extension_response_internal):
+        (CompressionExtensionProcessorBase._setup_stream_options_internal):
+        (PerFrameCompressExtensionProcessor):
+        (PerMessageDeflateExtensionProcessor):
+        (PerMessageDeflateExtensionProcessor.__init__):
+        (PerMessageDeflateExtensionProcessor._get_extension_response_internal):
+        (PerMessageDeflateExtensionProcessor._setup_stream_options_internal):
+        (PerMessageDeflateExtensionProcessor.set_c2s_max_window_bits):
+        (PerMessageDeflateExtensionProcessor.set_c2s_max_window_bits.adds):
+        (PerMessageDeflateExtensionProcessor.set_c2s_no_context_takeover):
+        (PerMessageDeflateExtensionProcessor.set_c2s_no_context_takeover.adds):
+        (PerMessageDeflateExtensionProcessor.set_bfinal):
+        (PerMessageDeflateExtensionProcessor.enable_outgoing_compression):
+        (PerMessageDeflateExtensionProcessor.disable_outgoing_compression):
+        (_PerMessageDeflateFramer):
+        (_PerMessageDeflateFramer.__init__):
+        (_PerMessageDeflateFramer.set_compress_outgoing_enabled):
+        (_PerMessageDeflateFramer._process_incoming_message):
+        (_PerMessageDeflateFramer._process_outgoing_message):
+        (_PerMessageDeflateFramer.setup_stream_options):
+        (_PerMessageDeflateFramer.setup_stream_options._OutgoingMessageFilter):
+        (_PerMessageDeflateFramer.setup_stream_options._OutgoingMessageFilter.__init__):
+        (_PerMessageDeflateFramer.setup_stream_options._OutgoingMessageFilter.filter):
+        (_PerMessageDeflateFramer.setup_stream_options._IncomingMessageFilter):
+        (_PerMessageDeflateFramer.setup_stream_options._IncomingMessageFilter.__init__):
+        (_PerMessageDeflateFramer.setup_stream_options._IncomingMessageFilter.decompress_next_message):
+        (_PerMessageDeflateFramer.setup_stream_options._IncomingMessageFilter.filter):
+        (_PerMessageDeflateFramer.setup_stream_options._OutgoingFrameFilter):
+        (_PerMessageDeflateFramer.setup_stream_options._OutgoingFrameFilter.__init__):
+        (_PerMessageDeflateFramer.setup_stream_options._OutgoingFrameFilter.set_compression_bit):
+        (_PerMessageDeflateFramer.setup_stream_options._OutgoingFrameFilter.filter):
+        (_PerMessageDeflateFramer.setup_stream_options._IncomingFrameFilter):
+        (_PerMessageDeflateFramer.setup_stream_options._IncomingFrameFilter.__init__):
+        (_PerMessageDeflateFramer.setup_stream_options._IncomingFrameFilter.filter):
+        (PerMessageCompressExtensionProcessor):
+        (PerMessageCompressExtensionProcessor._lookup_compression_processor):
+        (MuxExtensionProcessor.__init__):
+        (MuxExtensionProcessor.check_consistency_with_other_processors):
+        (MuxExtensionProcessor):
+        (MuxExtensionProcessor._get_extension_response_internal):
+        (MuxExtensionProcessor._setup_stream_options_internal):
+        (MuxExtensionProcessor.set_quota):
+        (MuxExtensionProcessor.quota):
+        (MuxExtensionProcessor.set_extensions):
+        (MuxExtensionProcessor.extensions):
+        (is_compression_extension):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py:
+        (validate_subprotocol):
+        (parse_host_header):
+        (format_header):
+        (check_request_line):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py:
+        (Handshaker.do_handshake):
+        (Handshaker._create_handshake_response):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi00.py:
+        (_validate_subprotocol):
+        (_check_header_lines):
+        (_build_location):
+        (Handshaker.do_handshake):
+        (Handshaker._set_subprotocol):
+        (Handshaker._set_location):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/headerparserhandler.py:
+        (_create_dispatcher):
+        (headerparserhandler):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/mux.py:
+        (_create_add_channel_response):
+        (_create_drop_channel):
+        (_create_flow_control):
+        (_create_new_channel_slot):
+        (_create_fallback_new_channel_slot):
+        (_MuxFramePayloadParser._read_number):
+        (_MuxFramePayloadParser._read_size_and_contents):
+        (_MuxFramePayloadParser._read_flow_control):
+        (_MuxFramePayloadParser._read_new_channel_slot):
+        (_LogicalConnection.__init__):
+        (_LogicalConnection.write):
+        (_LogicalConnection.on_write_data_done):
+        (_LogicalConnection):
+        (_LogicalConnection.on_writer_done):
+        (_InnerMessage):
+        (_InnerMessage.__init__):
+        (_InnerMessageBuilder):
+        (_InnerMessageBuilder.that):
+        (_InnerMessageBuilder.__init__):
+        (_InnerMessageBuilder._handle_first):
+        (_InnerMessageBuilder._process_first_fragmented_control):
+        (_InnerMessageBuilder._process_first_fragmented_message):
+        (_InnerMessageBuilder._handle_fragmented_control):
+        (_InnerMessageBuilder._reassemble_fragmented_control):
+        (_InnerMessageBuilder._handle_fragmented_message):
+        (_InnerMessageBuilder._reassemble_fragmented_message):
+        (_InnerMessageBuilder.build):
+        (_LogicalStream.__init__):
+        (_LogicalStream._create_inner_frame):
+        (_LogicalStream._write_inner_frame):
+        (_LogicalStream.replenish_send_quota):
+        (_LogicalStream.send_message):
+        (_LogicalStream._receive_frame):
+        (_LogicalStream._get_message_from_frame):
+        (_LogicalStream.stop_sending):
+        (_PhysicalConnectionWriter.__init__):
+        (_PhysicalConnectionWriter._write_data):
+        (_PhysicalConnectionWriter.run):
+        (_PhysicalConnectionWriter.stop):
+        (_Worker.run):
+        (_MuxHandshaker.__init__):
+        (_MuxHandshaker._create_stream):
+        (_MuxHandshaker._create_handshake_response):
+        (_HandshakeDeltaBase.create_headers):
+        (_MuxHandler.start):
+        (_MuxHandler.wait_until_done):
+        (_MuxHandler.notify_write_data_done):
+        (_MuxHandler._process_drop_channel):
+        (_MuxHandler._process_logical_frame):
+        (_MuxHandler.notify_reader_done):
+        (_MuxHandler):
+        (_MuxHandler.notify_writer_done):
+        (_MuxHandler.fail_physical_connection):
+        (_MuxHandler.fail_logical_channel):
+        (use_mux):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py:
+        (_StandaloneRequest.get_uri):
+        (_StandaloneRequest.get_unparsed_uri):
+        (_StandaloneRequest):
+        (_StandaloneRequest.is_https):
+        (_import_ssl):
+        (_import_pyopenssl):
+        (_StandaloneSSLConnection.for):
+        (_StandaloneSSLConnection):
+        (_StandaloneSSLConnection.__getattribute__):
+        (_StandaloneSSLConnection.__setattr__):
+        (_StandaloneSSLConnection.makefile):
+        (_StandaloneSSLConnection.shutdown):
+        (_StandaloneSSLConnection.recv):
+        (WebSocketServer.__init__):
+        (WebSocketServer._create_sockets):
+        (WebSocketServer.handle_error):
+        (WebSocketServer.get_request):
+        (WebSocketServer.get_request.default_callback):
+        (WebSocketRequestHandler.parse_request):
+        (_build_option_parser):
+        (_main):
+        (_main.if):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py:
+        (RepeatedXorMasker.__init__):
+        (RepeatedXorMasker._mask_using_swig):
+        (RepeatedXorMasker):
+        (RepeatedXorMasker._mask_using_array):
+        (_Deflater.compress_and_finish):
+        (_RFC1979Deflater.filter):
+        (DeflateSocket.send):
+
</ins><span class="cx"> 2013-05-16  Jonathan Liu  &lt;net147@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix testing if program exists in PATH
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsocket_stream_basepy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_base.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_base.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_base.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -39,6 +39,8 @@
</span><span class="cx"> # writing/reading.
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+import socket
+
</ins><span class="cx"> from mod_pywebsocket import util
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -109,20 +111,34 @@
</span><span class="cx">             ConnectionTerminatedException: when read returns empty string.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        bytes = self._request.connection.read(length)
-        if not bytes:
</del><ins>+        try:
+            read_bytes = self._request.connection.read(length)
+            if not read_bytes:
+                raise ConnectionTerminatedException(
+                    'Receiving %d byte failed. Peer (%r) closed connection' %
+                    (length, (self._request.connection.remote_addr,)))
+            return read_bytes
+        except socket.error, e:
+            # Catch a socket.error. Because it's not a child class of the
+            # IOError prior to Python 2.6, we cannot omit this except clause.
+            # Use %s rather than %r for the exception to use human friendly
+            # format.
</ins><span class="cx">             raise ConnectionTerminatedException(
</span><del>-                'Receiving %d byte failed. Peer (%r) closed connection' %
-                (length, (self._request.connection.remote_addr,)))
-        return bytes
</del><ins>+                'Receiving %d byte failed. socket.error (%s) occurred' %
+                (length, e))
+        except IOError, e:
+            # Also catch an IOError because mod_python throws it.
+            raise ConnectionTerminatedException(
+                'Receiving %d byte failed. IOError (%s) occurred' %
+                (length, e))
</ins><span class="cx"> 
</span><del>-    def _write(self, bytes):
</del><ins>+    def _write(self, bytes_to_write):
</ins><span class="cx">         &quot;&quot;&quot;Writes given bytes to connection. In case we catch any exception,
</span><span class="cx">         prepends remote address to the exception message and raise again.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         try:
</span><del>-            self._request.connection.write(bytes)
</del><ins>+            self._request.connection.write(bytes_to_write)
</ins><span class="cx">         except Exception, e:
</span><span class="cx">             util.prepend_message_to_exception(
</span><span class="cx">                     'Failed to send message to %r: ' %
</span><span class="lines">@@ -138,12 +154,12 @@
</span><span class="cx">             ConnectionTerminatedException: when read returns empty string.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        bytes = []
</del><ins>+        read_bytes = []
</ins><span class="cx">         while length &gt; 0:
</span><del>-            new_bytes = self._read(length)
-            bytes.append(new_bytes)
-            length -= len(new_bytes)
-        return ''.join(bytes)
</del><ins>+            new_read_bytes = self._read(length)
+            read_bytes.append(new_read_bytes)
+            length -= len(new_read_bytes)
+        return ''.join(read_bytes)
</ins><span class="cx"> 
</span><span class="cx">     def _read_until(self, delim_char):
</span><span class="cx">         &quot;&quot;&quot;Reads bytes until we encounter delim_char. The result will not
</span><span class="lines">@@ -153,13 +169,13 @@
</span><span class="cx">             ConnectionTerminatedException: when read returns empty string.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        bytes = []
</del><ins>+        read_bytes = []
</ins><span class="cx">         while True:
</span><span class="cx">             ch = self._read(1)
</span><span class="cx">             if ch == delim_char:
</span><span class="cx">                 break
</span><del>-            bytes.append(ch)
-        return ''.join(bytes)
</del><ins>+            read_bytes.append(ch)
+        return ''.join(read_bytes)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> # vi:sts=4 sw=4 et
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsocket_stream_hybipy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -280,7 +280,7 @@
</span><span class="cx">     if logger.isEnabledFor(common.LOGLEVEL_FINE):
</span><span class="cx">         unmask_start = time.time()
</span><span class="cx"> 
</span><del>-    bytes = masker.mask(raw_payload_bytes)
</del><ins>+    unmasked_bytes = masker.mask(raw_payload_bytes)
</ins><span class="cx"> 
</span><span class="cx">     if logger.isEnabledFor(common.LOGLEVEL_FINE):
</span><span class="cx">         logger.log(
</span><span class="lines">@@ -288,7 +288,7 @@
</span><span class="cx">             'Done unmasking payload data at %s MB/s',
</span><span class="cx">             payload_length / (time.time() - unmask_start) / 1000 / 1000)
</span><span class="cx"> 
</span><del>-    return opcode, bytes, fin, rsv1, rsv2, rsv3
</del><ins>+    return opcode, unmasked_bytes, fin, rsv1, rsv2, rsv3
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class FragmentedFrameBuilder(object):
</span><span class="lines">@@ -389,9 +389,6 @@
</span><span class="cx">     def __init__(self):
</span><span class="cx">         &quot;&quot;&quot;Constructs StreamOptions.&quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        # Enables deflate-stream extension.
-        self.deflate_stream = False
-
</del><span class="cx">         # Filters applied to frames.
</span><span class="cx">         self.outgoing_frame_filters = []
</span><span class="cx">         self.incoming_frame_filters = []
</span><span class="lines">@@ -403,9 +400,6 @@
</span><span class="cx">         self.encode_text_message_to_utf8 = True
</span><span class="cx">         self.mask_send = False
</span><span class="cx">         self.unmask_receive = True
</span><del>-        # RFC6455 disallows fragmented control frames, but mux extension
-        # relaxes the restriction.
-        self.allow_fragmented_control_frame = False
</del><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class Stream(StreamBase):
</span><span class="lines">@@ -426,10 +420,6 @@
</span><span class="cx"> 
</span><span class="cx">         self._options = options
</span><span class="cx"> 
</span><del>-        if self._options.deflate_stream:
-            self._logger.debug('Setup filter for deflate-stream')
-            self._request = util.DeflateRequest(self._request)
-
</del><span class="cx">         self._request.client_terminated = False
</span><span class="cx">         self._request.server_terminated = False
</span><span class="cx"> 
</span><span class="lines">@@ -463,10 +453,10 @@
</span><span class="cx">                            unmask_receive=self._options.unmask_receive)
</span><span class="cx"> 
</span><span class="cx">     def _receive_frame_as_frame_object(self):
</span><del>-        opcode, bytes, fin, rsv1, rsv2, rsv3 = self._receive_frame()
</del><ins>+        opcode, unmasked_bytes, fin, rsv1, rsv2, rsv3 = self._receive_frame()
</ins><span class="cx"> 
</span><span class="cx">         return Frame(fin=fin, rsv1=rsv1, rsv2=rsv2, rsv3=rsv3,
</span><del>-                     opcode=opcode, payload=bytes)
</del><ins>+                     opcode=opcode, payload=unmasked_bytes)
</ins><span class="cx"> 
</span><span class="cx">     def receive_filtered_frame(self):
</span><span class="cx">         &quot;&quot;&quot;Receives a frame and applies frame filters and message filters.
</span><span class="lines">@@ -602,8 +592,7 @@
</span><span class="cx">             else:
</span><span class="cx">                 # Start of fragmentation frame
</span><span class="cx"> 
</span><del>-                if (not self._options.allow_fragmented_control_frame and
-                    common.is_control_opcode(frame.opcode)):
</del><ins>+                if common.is_control_opcode(frame.opcode):
</ins><span class="cx">                     raise InvalidFrameException(
</span><span class="cx">                         'Control frames must not be fragmented')
</span><span class="cx"> 
</span><span class="lines">@@ -647,8 +636,9 @@
</span><span class="cx">                 self._request.ws_close_code,
</span><span class="cx">                 self._request.ws_close_reason)
</span><span class="cx"> 
</span><del>-        # Drain junk data after the close frame if necessary.
-        self._drain_received_data()
</del><ins>+        # As we've received a close frame, no more data is coming over the
+        # socket. We can now safely close the socket without worrying about
+        # RST sending.
</ins><span class="cx"> 
</span><span class="cx">         if self._request.server_terminated:
</span><span class="cx">             self._logger.debug(
</span><span class="lines">@@ -672,7 +662,7 @@
</span><span class="cx">                 reason = ''
</span><span class="cx">         self._send_closing_handshake(code, reason)
</span><span class="cx">         self._logger.debug(
</span><del>-            'Sent ack for client-initiated closing handshake '
</del><ins>+            'Acknowledged closing handshake initiated by the peer '
</ins><span class="cx">             '(code=%r, reason=%r)', code, reason)
</span><span class="cx"> 
</span><span class="cx">     def _process_ping_message(self, message):
</span><span class="lines">@@ -815,13 +805,15 @@
</span><span class="cx"> 
</span><span class="cx">         self._write(frame)
</span><span class="cx"> 
</span><del>-    def close_connection(self, code=common.STATUS_NORMAL_CLOSURE, reason=''):
</del><ins>+    def close_connection(self, code=common.STATUS_NORMAL_CLOSURE, reason='',
+                         wait_response=True):
</ins><span class="cx">         &quot;&quot;&quot;Closes a WebSocket connection.
</span><span class="cx"> 
</span><span class="cx">         Args:
</span><span class="cx">             code: Status code for close frame. If code is None, a close
</span><span class="cx">                 frame with empty body will be sent.
</span><span class="cx">             reason: string representing close reason.
</span><ins>+            wait_response: True when caller want to wait the response.
</ins><span class="cx">         Raises:
</span><span class="cx">             BadOperationException: when reason is specified with code None
</span><span class="cx">             or reason is not an instance of both str and unicode.
</span><span class="lines">@@ -844,11 +836,11 @@
</span><span class="cx"> 
</span><span class="cx">         self._send_closing_handshake(code, reason)
</span><span class="cx">         self._logger.debug(
</span><del>-            'Sent server-initiated closing handshake (code=%r, reason=%r)',
</del><ins>+            'Initiated closing handshake (code=%r, reason=%r)',
</ins><span class="cx">             code, reason)
</span><span class="cx"> 
</span><span class="cx">         if (code == common.STATUS_GOING_AWAY or
</span><del>-            code == common.STATUS_PROTOCOL_ERROR):
</del><ins>+            code == common.STATUS_PROTOCOL_ERROR) or not wait_response:
</ins><span class="cx">             # It doesn't make sense to wait for a close frame if the reason is
</span><span class="cx">             # protocol error or that the server is going away. For some of
</span><span class="cx">             # other reasons, it might not make sense to wait for a close frame,
</span><span class="lines">@@ -891,25 +883,5 @@
</span><span class="cx"> 
</span><span class="cx">         return self._original_opcode
</span><span class="cx"> 
</span><del>-    def _drain_received_data(self):
-        &quot;&quot;&quot;Drains unread data in the receive buffer to avoid sending out TCP
-        RST packet. This is because when deflate-stream is enabled, some
-        DEFLATE block for flushing data may follow a close frame. If any data
-        remains in the receive buffer of a socket when the socket is closed,
-        it sends out TCP RST packet to the other peer.
</del><span class="cx"> 
</span><del>-        Since mod_python's mp_conn object doesn't support non-blocking read,
-        we perform this only when pywebsocket is running in standalone mode.
-        &quot;&quot;&quot;
-
-        # If self._options.deflate_stream is true, self._request is
-        # DeflateRequest, so we can get wrapped request object by
-        # self._request._request.
-        #
-        # Only _StandaloneRequest has _drain_received_data method.
-        if (self._options.deflate_stream and
-            ('_drain_received_data' in dir(self._request._request))):
-            self._request._request._drain_received_data()
-
-
</del><span class="cx"> # vi:sts=4 sw=4 et
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsocketcommonpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -101,10 +101,10 @@
</span><span class="cx"> SEC_WEBSOCKET_LOCATION_HEADER = 'Sec-WebSocket-Location'
</span><span class="cx"> 
</span><span class="cx"> # Extensions
</span><del>-DEFLATE_STREAM_EXTENSION = 'deflate-stream'
</del><span class="cx"> DEFLATE_FRAME_EXTENSION = 'deflate-frame'
</span><span class="cx"> PERFRAME_COMPRESSION_EXTENSION = 'perframe-compress'
</span><span class="cx"> PERMESSAGE_COMPRESSION_EXTENSION = 'permessage-compress'
</span><ins>+PERMESSAGE_DEFLATE_EXTENSION = 'permessage-deflate'
</ins><span class="cx"> X_WEBKIT_DEFLATE_FRAME_EXTENSION = 'x-webkit-deflate-frame'
</span><span class="cx"> X_WEBKIT_PERMESSAGE_COMPRESSION_EXTENSION = 'x-webkit-permessage-compress'
</span><span class="cx"> MUX_EXTENSION = 'mux_DO_NOT_USE'
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsocketdispatchpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/dispatch.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/dispatch.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/dispatch.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -255,6 +255,9 @@
</span><span class="cx">         try:
</span><span class="cx">             do_extra_handshake_(request)
</span><span class="cx">         except handshake.AbortedByUserException, e:
</span><ins>+            # Re-raise to tell the caller of this function to finish this
+            # connection without sending any error.
+            self._logger.debug('%s', util.get_stack_trace())
</ins><span class="cx">             raise
</span><span class="cx">         except Exception, e:
</span><span class="cx">             util.prepend_message_to_exception(
</span><span class="lines">@@ -294,11 +297,12 @@
</span><span class="cx">                 request.ws_stream.close_connection()
</span><span class="cx">         # Catch non-critical exceptions the handler didn't handle.
</span><span class="cx">         except handshake.AbortedByUserException, e:
</span><del>-            self._logger.debug('%s', e)
</del><ins>+            self._logger.debug('%s', util.get_stack_trace())
</ins><span class="cx">             raise
</span><span class="cx">         except msgutil.BadOperationException, e:
</span><span class="cx">             self._logger.debug('%s', e)
</span><del>-            request.ws_stream.close_connection(common.STATUS_ABNORMAL_CLOSURE)
</del><ins>+            request.ws_stream.close_connection(
+                common.STATUS_INTERNAL_ENDPOINT_ERROR)
</ins><span class="cx">         except msgutil.InvalidFrameException, e:
</span><span class="cx">             # InvalidFrameException must be caught before
</span><span class="cx">             # ConnectionTerminatedException that catches InvalidFrameException.
</span><span class="lines">@@ -314,6 +318,8 @@
</span><span class="cx">         except msgutil.ConnectionTerminatedException, e:
</span><span class="cx">             self._logger.debug('%s', e)
</span><span class="cx">         except Exception, e:
</span><ins>+            # Any other exceptions are forwarded to the caller of this
+            # function.
</ins><span class="cx">             util.prepend_message_to_exception(
</span><span class="cx">                 '%s raised exception for %s: ' % (
</span><span class="cx">                     _TRANSFER_DATA_HANDLER_NAME, request.ws_resource),
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsocketextensionspy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -34,83 +34,114 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> _available_processors = {}
</span><ins>+_compression_extension_names = []
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class ExtensionProcessorInterface(object):
</span><span class="cx"> 
</span><ins>+    def __init__(self, request):
+        self._request = request
+        self._active = True
+
+    def request(self):
+        return self._request
+
</ins><span class="cx">     def name(self):
</span><span class="cx">         return None
</span><span class="cx"> 
</span><del>-    def get_extension_response(self):
-        return None
-
-    def setup_stream_options(self, stream_options):
</del><ins>+    def check_consistency_with_other_processors(self, processors):
</ins><span class="cx">         pass
</span><span class="cx"> 
</span><ins>+    def set_active(self, active):
+        self._active = active
</ins><span class="cx"> 
</span><del>-class DeflateStreamExtensionProcessor(ExtensionProcessorInterface):
-    &quot;&quot;&quot;WebSocket DEFLATE stream extension processor.
</del><ins>+    def is_active(self):
+        return self._active
</ins><span class="cx"> 
</span><del>-    Specification:
-    Section 9.2.1 in
-    http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
-    &quot;&quot;&quot;
</del><ins>+    def _get_extension_response_internal(self):
+        return None
</ins><span class="cx"> 
</span><del>-    def __init__(self, request):
-        self._logger = util.get_class_logger(self)
-
-        self._request = request
-
-    def name(self):
-        return common.DEFLATE_STREAM_EXTENSION
-
</del><span class="cx">     def get_extension_response(self):
</span><del>-        if len(self._request.get_parameter_names()) != 0:
-            return None
</del><ins>+        if self._active:
+            response = self._get_extension_response_internal()
+            if response is None:
+                self._active = False
+            return response
+        return None
</ins><span class="cx"> 
</span><del>-        self._logger.debug(
-            'Enable %s extension', common.DEFLATE_STREAM_EXTENSION)
</del><ins>+    def _setup_stream_options_internal(self, stream_options):
+        pass
</ins><span class="cx"> 
</span><del>-        return common.ExtensionParameter(common.DEFLATE_STREAM_EXTENSION)
-
</del><span class="cx">     def setup_stream_options(self, stream_options):
</span><del>-        stream_options.deflate_stream = True
</del><ins>+        if self._active:
+            self._setup_stream_options_internal(stream_options)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-_available_processors[common.DEFLATE_STREAM_EXTENSION] = (
-    DeflateStreamExtensionProcessor)
-
-
-def _log_compression_ratio(logger, original_bytes, total_original_bytes,
-                           filtered_bytes, total_filtered_bytes):
</del><ins>+def _log_outgoing_compression_ratio(
+        logger, original_bytes, filtered_bytes, average_ratio):
</ins><span class="cx">     # Print inf when ratio is not available.
</span><span class="cx">     ratio = float('inf')
</span><del>-    average_ratio = float('inf')
</del><span class="cx">     if original_bytes != 0:
</span><span class="cx">         ratio = float(filtered_bytes) / original_bytes
</span><del>-    if total_original_bytes != 0:
-        average_ratio = (
-            float(total_filtered_bytes) / total_original_bytes)
-    logger.debug('Outgoing compress ratio: %f (average: %f)' %
-        (ratio, average_ratio))
</del><span class="cx"> 
</span><ins>+    logger.debug('Outgoing compression ratio: %f (average: %f)' %
+            (ratio, average_ratio))
</ins><span class="cx"> 
</span><del>-def _log_decompression_ratio(logger, received_bytes, total_received_bytes,
-                             filtered_bytes, total_filtered_bytes):
</del><ins>+
+def _log_incoming_compression_ratio(
+        logger, received_bytes, filtered_bytes, average_ratio):
</ins><span class="cx">     # Print inf when ratio is not available.
</span><span class="cx">     ratio = float('inf')
</span><del>-    average_ratio = float('inf')
-    if received_bytes != 0:
</del><ins>+    if filtered_bytes != 0:
</ins><span class="cx">         ratio = float(received_bytes) / filtered_bytes
</span><del>-    if total_filtered_bytes != 0:
-        average_ratio = (
-            float(total_received_bytes) / total_filtered_bytes)
-    logger.debug('Incoming compress ratio: %f (average: %f)' %
-        (ratio, average_ratio))
</del><span class="cx"> 
</span><ins>+    logger.debug('Incoming compression ratio: %f (average: %f)' %
+            (ratio, average_ratio))
</ins><span class="cx"> 
</span><ins>+
+def _parse_window_bits(bits):
+    &quot;&quot;&quot;Return parsed integer value iff the given string conforms to the
+    grammar of the window bits extension parameters.
+    &quot;&quot;&quot;
+
+    if bits is None:
+        raise ValueError('Value is required')
+
+    # For non integer values such as &quot;10.0&quot;, ValueError will be raised.
+    int_bits = int(bits)
+
+    # First condition is to drop leading zero case e.g. &quot;08&quot;.
+    if bits != str(int_bits) or int_bits &lt; 8 or int_bits &gt; 15:
+        raise ValueError('Invalid value: %r' % bits)
+
+    return int_bits
+
+
+class _AverageRatioCalculator(object):
+    &quot;&quot;&quot;Stores total bytes of original and result data, and calculates average
+    result / original ratio.
+    &quot;&quot;&quot;
+
+    def __init__(self):
+        self._total_original_bytes = 0
+        self._total_result_bytes = 0
+
+    def add_original_bytes(self, value):
+        self._total_original_bytes += value
+
+    def add_result_bytes(self, value):
+        self._total_result_bytes += value
+
+    def get_average_ratio(self):
+        if self._total_original_bytes != 0:
+            return (float(self._total_result_bytes) /
+                    self._total_original_bytes)
+        else:
+            return float('inf')
+
+
</ins><span class="cx"> class DeflateFrameExtensionProcessor(ExtensionProcessorInterface):
</span><del>-    &quot;&quot;&quot;WebSocket Per-frame DEFLATE extension processor.
</del><ins>+    &quot;&quot;&quot;deflate-frame extension processor.
</ins><span class="cx"> 
</span><span class="cx">     Specification:
</span><span class="cx">     http://tools.ietf.org/html/draft-tyoshino-hybi-websocket-perframe-deflate
</span><span class="lines">@@ -120,34 +151,38 @@
</span><span class="cx">     _NO_CONTEXT_TAKEOVER_PARAM = 'no_context_takeover'
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, request):
</span><ins>+        ExtensionProcessorInterface.__init__(self, request)
</ins><span class="cx">         self._logger = util.get_class_logger(self)
</span><span class="cx"> 
</span><del>-        self._request = request
-
</del><span class="cx">         self._response_window_bits = None
</span><span class="cx">         self._response_no_context_takeover = False
</span><span class="cx">         self._bfinal = False
</span><span class="cx"> 
</span><del>-        # Counters for statistics.
</del><ins>+        # Calculates
+        #     (Total outgoing bytes supplied to this filter) /
+        #     (Total bytes sent to the network after applying this filter)
+        self._outgoing_average_ratio_calculator = _AverageRatioCalculator()
</ins><span class="cx"> 
</span><del>-        # Total number of outgoing bytes supplied to this filter.
-        self._total_outgoing_payload_bytes = 0
-        # Total number of bytes sent to the network after applying this filter.
-        self._total_filtered_outgoing_payload_bytes = 0
</del><ins>+        # Calculates
+        #     (Total bytes received from the network) /
+        #     (Total incoming bytes obtained after applying this filter)
+        self._incoming_average_ratio_calculator = _AverageRatioCalculator()
</ins><span class="cx"> 
</span><del>-        # Total number of bytes received from the network.
-        self._total_incoming_payload_bytes = 0
-        # Total number of incoming bytes obtained after applying this filter.
-        self._total_filtered_incoming_payload_bytes = 0
-
</del><span class="cx">     def name(self):
</span><span class="cx">         return common.DEFLATE_FRAME_EXTENSION
</span><span class="cx"> 
</span><del>-    def get_extension_response(self):
</del><ins>+    def _get_extension_response_internal(self):
</ins><span class="cx">         # Any unknown parameter will be just ignored.
</span><span class="cx"> 
</span><del>-        window_bits = self._request.get_parameter_value(
-            self._WINDOW_BITS_PARAM)
</del><ins>+        window_bits = None
+        if self._request.has_parameter(self._WINDOW_BITS_PARAM):
+            window_bits = self._request.get_parameter_value(
+                self._WINDOW_BITS_PARAM)
+            try:
+                window_bits = _parse_window_bits(window_bits)
+            except ValueError, e:
+                return None
+
</ins><span class="cx">         no_context_takeover = self._request.has_parameter(
</span><span class="cx">             self._NO_CONTEXT_TAKEOVER_PARAM)
</span><span class="cx">         if (no_context_takeover and
</span><span class="lines">@@ -155,18 +190,10 @@
</span><span class="cx">                 self._NO_CONTEXT_TAKEOVER_PARAM) is not None):
</span><span class="cx">             return None
</span><span class="cx"> 
</span><del>-        if window_bits is not None:
-            try:
-                window_bits = int(window_bits)
-            except ValueError, e:
-                return None
-            if window_bits &lt; 8 or window_bits &gt; 15:
-                return None
-
-        self._deflater = util._RFC1979Deflater(
</del><ins>+        self._rfc1979_deflater = util._RFC1979Deflater(
</ins><span class="cx">             window_bits, no_context_takeover)
</span><span class="cx"> 
</span><del>-        self._inflater = util._RFC1979Inflater()
</del><ins>+        self._rfc1979_inflater = util._RFC1979Inflater()
</ins><span class="cx"> 
</span><span class="cx">         self._compress_outgoing = True
</span><span class="cx"> 
</span><span class="lines">@@ -191,7 +218,7 @@
</span><span class="cx"> 
</span><span class="cx">         return response
</span><span class="cx"> 
</span><del>-    def setup_stream_options(self, stream_options):
</del><ins>+    def _setup_stream_options_internal(self, stream_options):
</ins><span class="cx"> 
</span><span class="cx">         class _OutgoingFilter(object):
</span><span class="cx"> 
</span><span class="lines">@@ -235,25 +262,28 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         original_payload_size = len(frame.payload)
</span><del>-        self._total_outgoing_payload_bytes += original_payload_size
</del><ins>+        self._outgoing_average_ratio_calculator.add_original_bytes(
+                original_payload_size)
</ins><span class="cx"> 
</span><span class="cx">         if (not self._compress_outgoing or
</span><span class="cx">             common.is_control_opcode(frame.opcode)):
</span><del>-            self._total_filtered_outgoing_payload_bytes += (
-                original_payload_size)
</del><ins>+            self._outgoing_average_ratio_calculator.add_result_bytes(
+                    original_payload_size)
</ins><span class="cx">             return
</span><span class="cx"> 
</span><del>-        frame.payload = self._deflater.filter(
</del><ins>+        frame.payload = self._rfc1979_deflater.filter(
</ins><span class="cx">             frame.payload, bfinal=self._bfinal)
</span><span class="cx">         frame.rsv1 = 1
</span><span class="cx"> 
</span><span class="cx">         filtered_payload_size = len(frame.payload)
</span><del>-        self._total_filtered_outgoing_payload_bytes += filtered_payload_size
</del><ins>+        self._outgoing_average_ratio_calculator.add_result_bytes(
+                filtered_payload_size)
</ins><span class="cx"> 
</span><del>-        _log_compression_ratio(self._logger, original_payload_size,
-                               self._total_outgoing_payload_bytes,
-                               filtered_payload_size,
-                               self._total_filtered_outgoing_payload_bytes)
</del><ins>+        _log_outgoing_compression_ratio(
+                self._logger,
+                original_payload_size,
+                filtered_payload_size,
+                self._outgoing_average_ratio_calculator.get_average_ratio())
</ins><span class="cx"> 
</span><span class="cx">     def _incoming_filter(self, frame):
</span><span class="cx">         &quot;&quot;&quot;Transform incoming frames. This method is called only by
</span><span class="lines">@@ -261,33 +291,35 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         received_payload_size = len(frame.payload)
</span><del>-        self._total_incoming_payload_bytes += received_payload_size
</del><ins>+        self._incoming_average_ratio_calculator.add_result_bytes(
+                received_payload_size)
</ins><span class="cx"> 
</span><span class="cx">         if frame.rsv1 != 1 or common.is_control_opcode(frame.opcode):
</span><del>-            self._total_filtered_incoming_payload_bytes += (
-                received_payload_size)
</del><ins>+            self._incoming_average_ratio_calculator.add_original_bytes(
+                    received_payload_size)
</ins><span class="cx">             return
</span><span class="cx"> 
</span><del>-        frame.payload = self._inflater.filter(frame.payload)
</del><ins>+        frame.payload = self._rfc1979_inflater.filter(frame.payload)
</ins><span class="cx">         frame.rsv1 = 0
</span><span class="cx"> 
</span><span class="cx">         filtered_payload_size = len(frame.payload)
</span><del>-        self._total_filtered_incoming_payload_bytes += filtered_payload_size
</del><ins>+        self._incoming_average_ratio_calculator.add_original_bytes(
+                filtered_payload_size)
</ins><span class="cx"> 
</span><del>-        _log_decompression_ratio(self._logger, received_payload_size,
-                                 self._total_incoming_payload_bytes,
-                                 filtered_payload_size,
-                                 self._total_filtered_incoming_payload_bytes)
</del><ins>+        _log_incoming_compression_ratio(
+                self._logger,
+                received_payload_size,
+                filtered_payload_size,
+                self._incoming_average_ratio_calculator.get_average_ratio())
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> _available_processors[common.DEFLATE_FRAME_EXTENSION] = (
</span><span class="cx">     DeflateFrameExtensionProcessor)
</span><ins>+_compression_extension_names.append(common.DEFLATE_FRAME_EXTENSION)
</ins><span class="cx"> 
</span><del>-
-# Adding vendor-prefixed deflate-frame extension.
-# TODO(bashi): Remove this after WebKit stops using vendor prefix.
</del><span class="cx"> _available_processors[common.X_WEBKIT_DEFLATE_FRAME_EXTENSION] = (
</span><span class="cx">     DeflateFrameExtensionProcessor)
</span><ins>+_compression_extension_names.append(common.X_WEBKIT_DEFLATE_FRAME_EXTENSION)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> def _parse_compression_method(data):
</span><span class="lines">@@ -306,13 +338,13 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class CompressionExtensionProcessorBase(ExtensionProcessorInterface):
</span><del>-    &quot;&quot;&quot;Base class for Per-frame and Per-message compression extension.&quot;&quot;&quot;
</del><ins>+    &quot;&quot;&quot;Base class for perframe-compress and permessage-compress extension.&quot;&quot;&quot;
</ins><span class="cx"> 
</span><span class="cx">     _METHOD_PARAM = 'method'
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, request):
</span><ins>+        ExtensionProcessorInterface.__init__(self, request)
</ins><span class="cx">         self._logger = util.get_class_logger(self)
</span><del>-        self._request = request
</del><span class="cx">         self._compression_method_name = None
</span><span class="cx">         self._compression_processor = None
</span><span class="cx">         self._compression_processor_hook = None
</span><span class="lines">@@ -357,7 +389,7 @@
</span><span class="cx">         self._compression_processor = compression_processor
</span><span class="cx">         return processor_response
</span><span class="cx"> 
</span><del>-    def get_extension_response(self):
</del><ins>+    def _get_extension_response_internal(self):
</ins><span class="cx">         processor_response = self._get_compression_processor_response()
</span><span class="cx">         if processor_response is None:
</span><span class="cx">             return None
</span><span class="lines">@@ -372,7 +404,7 @@
</span><span class="cx">             (self._request.name(), self._compression_method_name))
</span><span class="cx">         return response
</span><span class="cx"> 
</span><del>-    def setup_stream_options(self, stream_options):
</del><ins>+    def _setup_stream_options_internal(self, stream_options):
</ins><span class="cx">         if self._compression_processor is None:
</span><span class="cx">             return
</span><span class="cx">         self._compression_processor.setup_stream_options(stream_options)
</span><span class="lines">@@ -384,8 +416,8 @@
</span><span class="cx">         return self._compression_processor
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class PerFrameCompressionExtensionProcessor(CompressionExtensionProcessorBase):
-    &quot;&quot;&quot;WebSocket Per-frame compression extension processor.
</del><ins>+class PerFrameCompressExtensionProcessor(CompressionExtensionProcessorBase):
+    &quot;&quot;&quot;perframe-compress processor.
</ins><span class="cx"> 
</span><span class="cx">     Specification:
</span><span class="cx">     http://tools.ietf.org/html/draft-ietf-hybi-websocket-perframe-compression
</span><span class="lines">@@ -406,71 +438,99 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> _available_processors[common.PERFRAME_COMPRESSION_EXTENSION] = (
</span><del>-    PerFrameCompressionExtensionProcessor)
</del><ins>+    PerFrameCompressExtensionProcessor)
+_compression_extension_names.append(common.PERFRAME_COMPRESSION_EXTENSION)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DeflateMessageProcessor(ExtensionProcessorInterface):
-    &quot;&quot;&quot;Per-message deflate processor.&quot;&quot;&quot;
</del><ins>+class PerMessageDeflateExtensionProcessor(ExtensionProcessorInterface):
+    &quot;&quot;&quot;permessage-deflate extension processor. It's also used for
+    permessage-compress extension when the deflate method is chosen.
</ins><span class="cx"> 
</span><ins>+    Specification:
+    http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-08
+    &quot;&quot;&quot;
+
</ins><span class="cx">     _S2C_MAX_WINDOW_BITS_PARAM = 's2c_max_window_bits'
</span><span class="cx">     _S2C_NO_CONTEXT_TAKEOVER_PARAM = 's2c_no_context_takeover'
</span><span class="cx">     _C2S_MAX_WINDOW_BITS_PARAM = 'c2s_max_window_bits'
</span><span class="cx">     _C2S_NO_CONTEXT_TAKEOVER_PARAM = 'c2s_no_context_takeover'
</span><span class="cx"> 
</span><del>-    def __init__(self, request):
-        self._request = request
</del><ins>+    def __init__(self, request, draft08=True):
+        &quot;&quot;&quot;Construct PerMessageDeflateExtensionProcessor
+
+        Args:
+            draft08: Follow the constraints on the parameters that were not
+                specified for permessage-compress but are specified for
+                permessage-deflate as on
+                draft-ietf-hybi-permessage-compression-08.
+        &quot;&quot;&quot;
+
+        ExtensionProcessorInterface.__init__(self, request)
</ins><span class="cx">         self._logger = util.get_class_logger(self)
</span><span class="cx"> 
</span><span class="cx">         self._c2s_max_window_bits = None
</span><span class="cx">         self._c2s_no_context_takeover = False
</span><del>-        self._bfinal = False
</del><span class="cx"> 
</span><del>-        self._compress_outgoing_enabled = False
</del><ins>+        self._draft08 = draft08
</ins><span class="cx"> 
</span><del>-        # True if a message is fragmented and compression is ongoing.
-        self._compress_ongoing = False
-
-        # Counters for statistics.
-
-        # Total number of outgoing bytes supplied to this filter.
-        self._total_outgoing_payload_bytes = 0
-        # Total number of bytes sent to the network after applying this filter.
-        self._total_filtered_outgoing_payload_bytes = 0
-
-        # Total number of bytes received from the network.
-        self._total_incoming_payload_bytes = 0
-        # Total number of incoming bytes obtained after applying this filter.
-        self._total_filtered_incoming_payload_bytes = 0
-
</del><span class="cx">     def name(self):
</span><span class="cx">         return 'deflate'
</span><span class="cx"> 
</span><del>-    def get_extension_response(self):
-        # Any unknown parameter will be just ignored.
</del><ins>+    def _get_extension_response_internal(self):
+        if self._draft08:
+            for name in self._request.get_parameter_names():
+                if name not in [self._S2C_MAX_WINDOW_BITS_PARAM,
+                                self._S2C_NO_CONTEXT_TAKEOVER_PARAM,
+                                self._C2S_MAX_WINDOW_BITS_PARAM]:
+                    self._logger.debug('Unknown parameter: %r', name)
+                    return None
+        else:
+            # Any unknown parameter will be just ignored.
+            pass
</ins><span class="cx"> 
</span><del>-        s2c_max_window_bits = self._request.get_parameter_value(
-            self._S2C_MAX_WINDOW_BITS_PARAM)
-        if s2c_max_window_bits is not None:
</del><ins>+        s2c_max_window_bits = None
+        if self._request.has_parameter(self._S2C_MAX_WINDOW_BITS_PARAM):
+            s2c_max_window_bits = self._request.get_parameter_value(
+                    self._S2C_MAX_WINDOW_BITS_PARAM)
</ins><span class="cx">             try:
</span><del>-                s2c_max_window_bits = int(s2c_max_window_bits)
</del><ins>+                s2c_max_window_bits = _parse_window_bits(s2c_max_window_bits)
</ins><span class="cx">             except ValueError, e:
</span><ins>+                self._logger.debug('Bad %s parameter: %r',
+                                   self._S2C_MAX_WINDOW_BITS_PARAM,
+                                   e)
</ins><span class="cx">                 return None
</span><del>-            if s2c_max_window_bits &lt; 8 or s2c_max_window_bits &gt; 15:
-                return None
</del><span class="cx"> 
</span><span class="cx">         s2c_no_context_takeover = self._request.has_parameter(
</span><span class="cx">             self._S2C_NO_CONTEXT_TAKEOVER_PARAM)
</span><span class="cx">         if (s2c_no_context_takeover and
</span><span class="cx">             self._request.get_parameter_value(
</span><span class="cx">                 self._S2C_NO_CONTEXT_TAKEOVER_PARAM) is not None):
</span><ins>+            self._logger.debug('%s parameter must not have a value: %r',
+                               self._S2C_NO_CONTEXT_TAKEOVER_PARAM,
+                               s2c_no_context_takeover)
</ins><span class="cx">             return None
</span><span class="cx"> 
</span><del>-        self._deflater = util._RFC1979Deflater(
</del><ins>+        c2s_max_window_bits = self._request.has_parameter(
+            self._C2S_MAX_WINDOW_BITS_PARAM)
+        if (self._draft08 and
+            c2s_max_window_bits and
+            self._request.get_parameter_value(
+                self._C2S_MAX_WINDOW_BITS_PARAM) is not None):
+            self._logger.debug('%s parameter must not have a value in a '
+                               'client\'s opening handshake: %r',
+                               self._C2S_MAX_WINDOW_BITS_PARAM,
+                               c2s_max_window_bits)
+            return None
+
+        self._rfc1979_deflater = util._RFC1979Deflater(
</ins><span class="cx">             s2c_max_window_bits, s2c_no_context_takeover)
</span><span class="cx"> 
</span><del>-        self._inflater = util._RFC1979Inflater()
</del><ins>+        self._rfc1979_inflater = util._RFC1979Inflater()
</ins><span class="cx"> 
</span><del>-        self._compress_outgoing_enabled = True
</del><ins>+        self._framer = _PerMessageDeflateFramer(
+            s2c_max_window_bits, s2c_no_context_takeover)
+        self._framer.set_bfinal(False)
+        self._framer.set_compress_outgoing_enabled(True)
</ins><span class="cx"> 
</span><span class="cx">         response = common.ExtensionParameter(self._request.name())
</span><span class="cx"> 
</span><span class="lines">@@ -483,9 +543,15 @@
</span><span class="cx">                 self._S2C_NO_CONTEXT_TAKEOVER_PARAM, None)
</span><span class="cx"> 
</span><span class="cx">         if self._c2s_max_window_bits is not None:
</span><ins>+            if self._draft08 and c2s_max_window_bits:
+                self._logger.debug('Processor is configured to use %s but '
+                                   'the client cannot accept it',
+                                   self._C2S_MAX_WINDOW_BITS_PARAM)
+                return None
</ins><span class="cx">             response.add_parameter(
</span><span class="cx">                 self._C2S_MAX_WINDOW_BITS_PARAM,
</span><span class="cx">                 str(self._c2s_max_window_bits))
</span><ins>+
</ins><span class="cx">         if self._c2s_no_context_takeover:
</span><span class="cx">             response.add_parameter(
</span><span class="cx">                 self._C2S_NO_CONTEXT_TAKEOVER_PARAM, None)
</span><span class="lines">@@ -502,100 +568,99 @@
</span><span class="cx"> 
</span><span class="cx">         return response
</span><span class="cx"> 
</span><del>-    def setup_stream_options(self, stream_options):
-        class _OutgoingMessageFilter(object):
</del><ins>+    def _setup_stream_options_internal(self, stream_options):
+        self._framer.setup_stream_options(stream_options)
</ins><span class="cx"> 
</span><del>-            def __init__(self, parent):
-                self._parent = parent
</del><ins>+    def set_c2s_max_window_bits(self, value):
+        &quot;&quot;&quot;If this option is specified, this class adds the c2s_max_window_bits
+        extension parameter to the handshake response, but doesn't reduce the
+        LZ77 sliding window size of its inflater. I.e., you can use this for
+        testing client implementation but cannot reduce memory usage of this
+        class.
</ins><span class="cx"> 
</span><del>-            def filter(self, message, end=True, binary=False):
-                return self._parent._process_outgoing_message(
-                    message, end, binary)
</del><ins>+        If this method has been called with True and an offer without the
+        c2s_max_window_bits extension parameter is received,
+        - (When processing the permessage-deflate extension) this processor
+          declines the request.
+        - (When processing the permessage-compress extension) this processor
+          accepts the request.
+        &quot;&quot;&quot;
</ins><span class="cx"> 
</span><del>-        class _IncomingMessageFilter(object):
</del><ins>+        self._c2s_max_window_bits = value
</ins><span class="cx"> 
</span><del>-            def __init__(self, parent):
-                self._parent = parent
-                self._decompress_next_message = False
</del><ins>+    def set_c2s_no_context_takeover(self, value):
+        &quot;&quot;&quot;If this option is specified, this class adds the
+        c2s_no_context_takeover extension parameter to the handshake response,
+        but doesn't reset inflater for each message. I.e., you can use this for
+        testing client implementation but cannot reduce memory usage of this
+        class.
+        &quot;&quot;&quot;
</ins><span class="cx"> 
</span><del>-            def decompress_next_message(self):
-                self._decompress_next_message = True
</del><ins>+        self._c2s_no_context_takeover = value
</ins><span class="cx"> 
</span><del>-            def filter(self, message):
-                message = self._parent._process_incoming_message(
-                    message, self._decompress_next_message)
-                self._decompress_next_message = False
-                return message
</del><ins>+    def set_bfinal(self, value):
+        self._framer.set_bfinal(value)
</ins><span class="cx"> 
</span><del>-        self._outgoing_message_filter = _OutgoingMessageFilter(self)
-        self._incoming_message_filter = _IncomingMessageFilter(self)
-        stream_options.outgoing_message_filters.append(
-            self._outgoing_message_filter)
-        stream_options.incoming_message_filters.append(
-            self._incoming_message_filter)
</del><ins>+    def enable_outgoing_compression(self):
+        self._framer.set_compress_outgoing_enabled(True)
</ins><span class="cx"> 
</span><del>-        class _OutgoingFrameFilter(object):
</del><ins>+    def disable_outgoing_compression(self):
+        self._framer.set_compress_outgoing_enabled(False)
</ins><span class="cx"> 
</span><del>-            def __init__(self, parent):
-                self._parent = parent
-                self._set_compression_bit = False
</del><span class="cx"> 
</span><del>-            def set_compression_bit(self):
-                self._set_compression_bit = True
</del><ins>+class _PerMessageDeflateFramer(object):
+    &quot;&quot;&quot;A framer for extensions with per-message DEFLATE feature.&quot;&quot;&quot;
</ins><span class="cx"> 
</span><del>-            def filter(self, frame):
-                self._parent._process_outgoing_frame(
-                    frame, self._set_compression_bit)
-                self._set_compression_bit = False
</del><ins>+    def __init__(self, deflate_max_window_bits, deflate_no_context_takeover):
+        self._logger = util.get_class_logger(self)
</ins><span class="cx"> 
</span><del>-        class _IncomingFrameFilter(object):
</del><ins>+        self._rfc1979_deflater = util._RFC1979Deflater(
+            deflate_max_window_bits, deflate_no_context_takeover)
</ins><span class="cx"> 
</span><del>-            def __init__(self, parent):
-                self._parent = parent
</del><ins>+        self._rfc1979_inflater = util._RFC1979Inflater()
</ins><span class="cx"> 
</span><del>-            def filter(self, frame):
-                self._parent._process_incoming_frame(frame)
</del><ins>+        self._bfinal = False
</ins><span class="cx"> 
</span><del>-        self._outgoing_frame_filter = _OutgoingFrameFilter(self)
-        self._incoming_frame_filter = _IncomingFrameFilter(self)
-        stream_options.outgoing_frame_filters.append(
-            self._outgoing_frame_filter)
-        stream_options.incoming_frame_filters.append(
-            self._incoming_frame_filter)
</del><ins>+        self._compress_outgoing_enabled = False
</ins><span class="cx"> 
</span><del>-        stream_options.encode_text_message_to_utf8 = False
</del><ins>+        # True if a message is fragmented and compression is ongoing.
+        self._compress_ongoing = False
</ins><span class="cx"> 
</span><del>-    def set_c2s_max_window_bits(self, value):
-        self._c2s_max_window_bits = value
</del><ins>+        # Calculates
+        #     (Total outgoing bytes supplied to this filter) /
+        #     (Total bytes sent to the network after applying this filter)
+        self._outgoing_average_ratio_calculator = _AverageRatioCalculator()
</ins><span class="cx"> 
</span><del>-    def set_c2s_no_context_takeover(self, value):
-        self._c2s_no_context_takeover = value
</del><ins>+        # Calculates
+        #     (Total bytes received from the network) /
+        #     (Total incoming bytes obtained after applying this filter)
+        self._incoming_average_ratio_calculator = _AverageRatioCalculator()
</ins><span class="cx"> 
</span><span class="cx">     def set_bfinal(self, value):
</span><span class="cx">         self._bfinal = value
</span><span class="cx"> 
</span><del>-    def enable_outgoing_compression(self):
-        self._compress_outgoing_enabled = True
</del><ins>+    def set_compress_outgoing_enabled(self, value):
+        self._compress_outgoing_enabled = value
</ins><span class="cx"> 
</span><del>-    def disable_outgoing_compression(self):
-        self._compress_outgoing_enabled = False
-
</del><span class="cx">     def _process_incoming_message(self, message, decompress):
</span><span class="cx">         if not decompress:
</span><span class="cx">             return message
</span><span class="cx"> 
</span><span class="cx">         received_payload_size = len(message)
</span><del>-        self._total_incoming_payload_bytes += received_payload_size
</del><ins>+        self._incoming_average_ratio_calculator.add_result_bytes(
+                received_payload_size)
</ins><span class="cx"> 
</span><del>-        message = self._inflater.filter(message)
</del><ins>+        message = self._rfc1979_inflater.filter(message)
</ins><span class="cx"> 
</span><span class="cx">         filtered_payload_size = len(message)
</span><del>-        self._total_filtered_incoming_payload_bytes += filtered_payload_size
</del><ins>+        self._incoming_average_ratio_calculator.add_original_bytes(
+                filtered_payload_size)
</ins><span class="cx"> 
</span><del>-        _log_decompression_ratio(self._logger, received_payload_size,
-                                 self._total_incoming_payload_bytes,
-                                 filtered_payload_size,
-                                 self._total_filtered_incoming_payload_bytes)
</del><ins>+        _log_incoming_compression_ratio(
+                self._logger,
+                received_payload_size,
+                filtered_payload_size,
+                self._incoming_average_ratio_calculator.get_average_ratio())
</ins><span class="cx"> 
</span><span class="cx">         return message
</span><span class="cx"> 
</span><span class="lines">@@ -607,18 +672,21 @@
</span><span class="cx">             return message
</span><span class="cx"> 
</span><span class="cx">         original_payload_size = len(message)
</span><del>-        self._total_outgoing_payload_bytes += original_payload_size
</del><ins>+        self._outgoing_average_ratio_calculator.add_original_bytes(
+            original_payload_size)
</ins><span class="cx"> 
</span><del>-        message = self._deflater.filter(
</del><ins>+        message = self._rfc1979_deflater.filter(
</ins><span class="cx">             message, flush=end, bfinal=self._bfinal)
</span><span class="cx"> 
</span><span class="cx">         filtered_payload_size = len(message)
</span><del>-        self._total_filtered_outgoing_payload_bytes += filtered_payload_size
</del><ins>+        self._outgoing_average_ratio_calculator.add_result_bytes(
+            filtered_payload_size)
</ins><span class="cx"> 
</span><del>-        _log_compression_ratio(self._logger, original_payload_size,
-                               self._total_outgoing_payload_bytes,
-                               filtered_payload_size,
-                               self._total_filtered_outgoing_payload_bytes)
</del><ins>+        _log_outgoing_compression_ratio(
+                self._logger,
+                original_payload_size,
+                filtered_payload_size,
+                self._outgoing_average_ratio_calculator.get_average_ratio())
</ins><span class="cx"> 
</span><span class="cx">         if not self._compress_ongoing:
</span><span class="cx">             self._outgoing_frame_filter.set_compression_bit()
</span><span class="lines">@@ -637,10 +705,81 @@
</span><span class="cx"> 
</span><span class="cx">         frame.rsv1 = 1
</span><span class="cx"> 
</span><ins>+    def setup_stream_options(self, stream_options):
+        &quot;&quot;&quot;Creates filters and sets them to the StreamOptions.&quot;&quot;&quot;
</ins><span class="cx"> 
</span><del>-class PerMessageCompressionExtensionProcessor(
</del><ins>+        class _OutgoingMessageFilter(object):
+
+            def __init__(self, parent):
+                self._parent = parent
+
+            def filter(self, message, end=True, binary=False):
+                return self._parent._process_outgoing_message(
+                    message, end, binary)
+
+        class _IncomingMessageFilter(object):
+
+            def __init__(self, parent):
+                self._parent = parent
+                self._decompress_next_message = False
+
+            def decompress_next_message(self):
+                self._decompress_next_message = True
+
+            def filter(self, message):
+                message = self._parent._process_incoming_message(
+                    message, self._decompress_next_message)
+                self._decompress_next_message = False
+                return message
+
+        self._outgoing_message_filter = _OutgoingMessageFilter(self)
+        self._incoming_message_filter = _IncomingMessageFilter(self)
+        stream_options.outgoing_message_filters.append(
+            self._outgoing_message_filter)
+        stream_options.incoming_message_filters.append(
+            self._incoming_message_filter)
+
+        class _OutgoingFrameFilter(object):
+
+            def __init__(self, parent):
+                self._parent = parent
+                self._set_compression_bit = False
+
+            def set_compression_bit(self):
+                self._set_compression_bit = True
+
+            def filter(self, frame):
+                self._parent._process_outgoing_frame(
+                    frame, self._set_compression_bit)
+                self._set_compression_bit = False
+
+        class _IncomingFrameFilter(object):
+
+            def __init__(self, parent):
+                self._parent = parent
+
+            def filter(self, frame):
+                self._parent._process_incoming_frame(frame)
+
+        self._outgoing_frame_filter = _OutgoingFrameFilter(self)
+        self._incoming_frame_filter = _IncomingFrameFilter(self)
+        stream_options.outgoing_frame_filters.append(
+            self._outgoing_frame_filter)
+        stream_options.incoming_frame_filters.append(
+            self._incoming_frame_filter)
+
+        stream_options.encode_text_message_to_utf8 = False
+
+
+_available_processors[common.PERMESSAGE_DEFLATE_EXTENSION] = (
+        PerMessageDeflateExtensionProcessor)
+# TODO(tyoshino): Reorganize class names.
+_compression_extension_names.append('deflate')
+
+
+class PerMessageCompressExtensionProcessor(
</ins><span class="cx">     CompressionExtensionProcessorBase):
</span><del>-    &quot;&quot;&quot;WebSocket Per-message compression extension processor.
</del><ins>+    &quot;&quot;&quot;permessage-compress extension processor.
</ins><span class="cx"> 
</span><span class="cx">     Specification:
</span><span class="cx">     http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression
</span><span class="lines">@@ -656,72 +795,100 @@
</span><span class="cx"> 
</span><span class="cx">     def _lookup_compression_processor(self, method_desc):
</span><span class="cx">         if method_desc.name() == self._DEFLATE_METHOD:
</span><del>-            return DeflateMessageProcessor(method_desc)
</del><ins>+            return PerMessageDeflateExtensionProcessor(method_desc, False)
</ins><span class="cx">         return None
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> _available_processors[common.PERMESSAGE_COMPRESSION_EXTENSION] = (
</span><del>-    PerMessageCompressionExtensionProcessor)
</del><ins>+    PerMessageCompressExtensionProcessor)
+_compression_extension_names.append(common.PERMESSAGE_COMPRESSION_EXTENSION)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-# Adding vendor-prefixed permessage-compress extension.
-# TODO(bashi): Remove this after WebKit stops using vendor prefix.
-_available_processors[common.X_WEBKIT_PERMESSAGE_COMPRESSION_EXTENSION] = (
-    PerMessageCompressionExtensionProcessor)
-
-
</del><span class="cx"> class MuxExtensionProcessor(ExtensionProcessorInterface):
</span><span class="cx">     &quot;&quot;&quot;WebSocket multiplexing extension processor.&quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     _QUOTA_PARAM = 'quota'
</span><span class="cx"> 
</span><span class="cx">     def __init__(self, request):
</span><del>-        self._request = request
</del><ins>+        ExtensionProcessorInterface.__init__(self, request)
+        self._quota = 0
+        self._extensions = []
</ins><span class="cx"> 
</span><span class="cx">     def name(self):
</span><span class="cx">         return common.MUX_EXTENSION
</span><span class="cx"> 
</span><del>-    def get_extension_response(self, ws_request,
-                               logical_channel_extensions):
-        # Mux extension cannot be used after extensions that depend on
-        # frame boundary, extension data field, or any reserved bits
-        # which are attributed to each frame.
-        for extension in logical_channel_extensions:
-            name = extension.name()
-            if (name == common.PERFRAME_COMPRESSION_EXTENSION or
-                name == common.DEFLATE_FRAME_EXTENSION or
-                name == common.X_WEBKIT_DEFLATE_FRAME_EXTENSION):
-                return None
</del><ins>+    def check_consistency_with_other_processors(self, processors):
+        before_mux = True
+        for processor in processors:
+            name = processor.name()
+            if name == self.name():
+                before_mux = False
+                continue
+            if not processor.is_active():
+                continue
+            if before_mux:
+                # Mux extension cannot be used after extensions
+                # that depend on frame boundary, extension data field, or any
+                # reserved bits which are attributed to each frame.
+                if (name == common.PERFRAME_COMPRESSION_EXTENSION or
+                    name == common.DEFLATE_FRAME_EXTENSION or
+                    name == common.X_WEBKIT_DEFLATE_FRAME_EXTENSION):
+                    self.set_active(False)
+                    return
+            else:
+                # Mux extension should not be applied before any history-based
+                # compression extension.
+                if (name == common.PERFRAME_COMPRESSION_EXTENSION or
+                    name == common.DEFLATE_FRAME_EXTENSION or
+                    name == common.X_WEBKIT_DEFLATE_FRAME_EXTENSION or
+                    name == common.PERMESSAGE_COMPRESSION_EXTENSION or
+                    name == common.X_WEBKIT_PERMESSAGE_COMPRESSION_EXTENSION):
+                    self.set_active(False)
+                    return
</ins><span class="cx"> 
</span><ins>+    def _get_extension_response_internal(self):
+        self._active = False
</ins><span class="cx">         quota = self._request.get_parameter_value(self._QUOTA_PARAM)
</span><del>-        if quota is None:
-            ws_request.mux_quota = 0
-        else:
</del><ins>+        if quota is not None:
</ins><span class="cx">             try:
</span><span class="cx">                 quota = int(quota)
</span><span class="cx">             except ValueError, e:
</span><span class="cx">                 return None
</span><span class="cx">             if quota &lt; 0 or quota &gt;= 2 ** 32:
</span><span class="cx">                 return None
</span><del>-            ws_request.mux_quota = quota
</del><ins>+            self._quota = quota
</ins><span class="cx"> 
</span><del>-        ws_request.mux = True
-        ws_request.mux_extensions = logical_channel_extensions
</del><ins>+        self._active = True
</ins><span class="cx">         return common.ExtensionParameter(common.MUX_EXTENSION)
</span><span class="cx"> 
</span><del>-    def setup_stream_options(self, stream_options):
</del><ins>+    def _setup_stream_options_internal(self, stream_options):
</ins><span class="cx">         pass
</span><span class="cx"> 
</span><ins>+    def set_quota(self, quota):
+        self._quota = quota
</ins><span class="cx"> 
</span><ins>+    def quota(self):
+        return self._quota
+
+    def set_extensions(self, extensions):
+        self._extensions = extensions
+
+    def extensions(self):
+        return self._extensions
+
+
</ins><span class="cx"> _available_processors[common.MUX_EXTENSION] = MuxExtensionProcessor
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> def get_extension_processor(extension_request):
</span><del>-    global _available_processors
</del><span class="cx">     processor_class = _available_processors.get(extension_request.name())
</span><span class="cx">     if processor_class is None:
</span><span class="cx">         return None
</span><span class="cx">     return processor_class(extension_request)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+def is_compression_extension(extension_name):
+    return extension_name in _compression_extension_names
+
+
</ins><span class="cx"> # vi:sts=4 sw=4 et
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsockethandshake_basepy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -84,42 +84,29 @@
</span><span class="cx">         return common.DEFAULT_WEB_SOCKET_PORT
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-def validate_subprotocol(subprotocol, hixie):
</del><ins>+def validate_subprotocol(subprotocol):
</ins><span class="cx">     &quot;&quot;&quot;Validate a value in the Sec-WebSocket-Protocol field.
</span><span class="cx"> 
</span><del>-    See
-    - RFC 6455: Section 4.1., 4.2.2., and 4.3.
-    - HyBi 00: Section 4.1. Opening handshake
-
-    Args:
-         hixie: if True, checks if characters in subprotocol are in range
-                between U+0020 and U+007E. It's required by HyBi 00 but not by
-                RFC 6455.
</del><ins>+    See the Section 4.1., 4.2.2., and 4.3. of RFC 6455.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">     if not subprotocol:
</span><span class="cx">         raise HandshakeException('Invalid subprotocol name: empty')
</span><del>-    if hixie:
-        # Parameter should be in the range U+0020 to U+007E.
-        for c in subprotocol:
-            if not 0x20 &lt;= ord(c) &lt;= 0x7e:
-                raise HandshakeException(
-                    'Illegal character in subprotocol name: %r' % c)
-    else:
-        # Parameter should be encoded HTTP token.
-        state = http_header_util.ParsingState(subprotocol)
-        token = http_header_util.consume_token(state)
-        rest = http_header_util.peek(state)
-        # If |rest| is not None, |subprotocol| is not one token or invalid. If
-        # |rest| is None, |token| must not be None because |subprotocol| is
-        # concatenation of |token| and |rest| and is not None.
-        if rest is not None:
-            raise HandshakeException('Invalid non-token string in subprotocol '
-                                     'name: %r' % rest)
</del><span class="cx"> 
</span><ins>+    # Parameter should be encoded HTTP token.
+    state = http_header_util.ParsingState(subprotocol)
+    token = http_header_util.consume_token(state)
+    rest = http_header_util.peek(state)
+    # If |rest| is not None, |subprotocol| is not one token or invalid. If
+    # |rest| is None, |token| must not be None because |subprotocol| is
+    # concatenation of |token| and |rest| and is not None.
+    if rest is not None:
+        raise HandshakeException('Invalid non-token string in subprotocol '
+                                 'name: %r' % rest)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def parse_host_header(request):
</span><del>-    fields = request.headers_in['Host'].split(':', 1)
</del><ins>+    fields = request.headers_in[common.HOST_HEADER].split(':', 1)
</ins><span class="cx">     if len(fields) == 1:
</span><span class="cx">         return fields[0], get_default_port(request.is_https())
</span><span class="cx">     try:
</span><span class="lines">@@ -132,27 +119,6 @@
</span><span class="cx">     return '%s: %s\r\n' % (name, value)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-def build_location(request):
-    &quot;&quot;&quot;Build WebSocket location for request.&quot;&quot;&quot;
-    location_parts = []
-    if request.is_https():
-        location_parts.append(common.WEB_SOCKET_SECURE_SCHEME)
-    else:
-        location_parts.append(common.WEB_SOCKET_SCHEME)
-    location_parts.append('://')
-    host, port = parse_host_header(request)
-    connection_port = request.connection.local_addr[1]
-    if port != connection_port:
-        raise HandshakeException('Header/connection port mismatch: %d/%d' %
-                                 (port, connection_port))
-    location_parts.append(host)
-    if (port != get_default_port(request.is_https())):
-        location_parts.append(':')
-        location_parts.append(str(port))
-    location_parts.append(request.uri)
-    return ''.join(location_parts)
-
-
</del><span class="cx"> def get_mandatory_header(request, key):
</span><span class="cx">     value = request.headers_in.get(key)
</span><span class="cx">     if value is None:
</span><span class="lines">@@ -180,16 +146,6 @@
</span><span class="cx">                                  request.protocol)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-def check_header_lines(request, mandatory_headers):
-    check_request_line(request)
-
-    # The expected field names, and the meaning of their corresponding
-    # values, are as follows.
-    #  |Upgrade| and |Connection|
-    for key, expected_value in mandatory_headers:
-        validate_mandatory_header(request, key, expected_value)
-
-
</del><span class="cx"> def parse_token_list(data):
</span><span class="cx">     &quot;&quot;&quot;Parses a header value which follows 1#token and returns parsed elements
</span><span class="cx">     as a list of strings.
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsockethandshakehybipy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -49,6 +49,7 @@
</span><span class="cx"> 
</span><span class="cx"> from mod_pywebsocket import common
</span><span class="cx"> from mod_pywebsocket.extensions import get_extension_processor
</span><ins>+from mod_pywebsocket.extensions import is_compression_extension
</ins><span class="cx"> from mod_pywebsocket.handshake._base import check_request_line
</span><span class="cx"> from mod_pywebsocket.handshake._base import format_header
</span><span class="cx"> from mod_pywebsocket.handshake._base import get_mandatory_header
</span><span class="lines">@@ -180,43 +181,59 @@
</span><span class="cx">                         processors.append(processor)
</span><span class="cx">             self._request.ws_extension_processors = processors
</span><span class="cx"> 
</span><ins>+            # List of extra headers. The extra handshake handler may add header
+            # data as name/value pairs to this list and pywebsocket appends
+            # them to the WebSocket handshake.
+            self._request.extra_headers = []
+
</ins><span class="cx">             # Extra handshake handler may modify/remove processors.
</span><span class="cx">             self._dispatcher.do_extra_handshake(self._request)
</span><span class="cx">             processors = filter(lambda processor: processor is not None,
</span><span class="cx">                                 self._request.ws_extension_processors)
</span><span class="cx"> 
</span><ins>+            # Ask each processor if there are extensions on the request which
+            # cannot co-exist. When processor decided other processors cannot
+            # co-exist with it, the processor marks them (or itself) as
+            # &quot;inactive&quot;. The first extension processor has the right to
+            # make the final call.
+            for processor in reversed(processors):
+                if processor.is_active():
+                    processor.check_consistency_with_other_processors(
+                        processors)
+            processors = filter(lambda processor: processor.is_active(),
+                                processors)
+
</ins><span class="cx">             accepted_extensions = []
</span><span class="cx"> 
</span><del>-            # We need to take care of mux extension here. Extensions that
-            # are placed before mux should be applied to logical channels.
</del><ins>+            # We need to take into account of mux extension here.
+            # If mux extension exists:
+            # - Remove processors of extensions for logical channel,
+            #   which are processors located before the mux processor
+            # - Pass extension requests for logical channel to mux processor
+            # - Attach the mux processor to the request. It will be referred
+            #   by dispatcher to see whether the dispatcher should use mux
+            #   handler or not.
</ins><span class="cx">             mux_index = -1
</span><span class="cx">             for i, processor in enumerate(processors):
</span><span class="cx">                 if processor.name() == common.MUX_EXTENSION:
</span><span class="cx">                     mux_index = i
</span><span class="cx">                     break
</span><span class="cx">             if mux_index &gt;= 0:
</span><del>-                mux_processor = processors[mux_index]
-                logical_channel_processors = processors[:mux_index]
-                processors = processors[mux_index+1:]
</del><ins>+                logical_channel_extensions = []
+                for processor in processors[:mux_index]:
+                    logical_channel_extensions.append(processor.request())
+                    processor.set_active(False)
+                self._request.mux_processor = processors[mux_index]
+                self._request.mux_processor.set_extensions(
+                    logical_channel_extensions)
+                processors = filter(lambda processor: processor.is_active(),
+                                    processors)
</ins><span class="cx"> 
</span><del>-                for processor in logical_channel_processors:
-                    extension_response = processor.get_extension_response()
-                    if extension_response is None:
-                        # Rejected.
-                        continue
-                    accepted_extensions.append(extension_response)
-                # Pass a shallow copy of accepted_extensions as extensions for
-                # logical channels.
-                mux_response = mux_processor.get_extension_response(
-                    self._request, accepted_extensions[:])
-                if mux_response is not None:
-                    accepted_extensions.append(mux_response)
-
</del><span class="cx">             stream_options = StreamOptions()
</span><span class="cx"> 
</span><del>-            # When there is mux extension, here, |processors| contain only
-            # prosessors for extensions placed after mux.
-            for processor in processors:
</del><ins>+            for index, processor in enumerate(processors):
+                if not processor.is_active():
+                    continue
</ins><span class="cx"> 
</span><span class="cx">                 extension_response = processor.get_extension_response()
</span><span class="cx">                 if extension_response is None:
</span><span class="lines">@@ -227,6 +244,14 @@
</span><span class="cx"> 
</span><span class="cx">                 processor.setup_stream_options(stream_options)
</span><span class="cx"> 
</span><ins>+                if not is_compression_extension(processor.name()):
+                    continue
+
+                # Inactivate all of the following compression extensions.
+                for j in xrange(index + 1, len(processors)):
+                    if is_compression_extension(processors[j].name()):
+                        processors[j].set_active(False)
+
</ins><span class="cx">             if len(accepted_extensions) &gt; 0:
</span><span class="cx">                 self._request.ws_extensions = accepted_extensions
</span><span class="cx">                 self._logger.debug(
</span><span class="lines">@@ -242,7 +267,7 @@
</span><span class="cx">                     raise HandshakeException(
</span><span class="cx">                         'do_extra_handshake must choose one subprotocol from '
</span><span class="cx">                         'ws_requested_protocols and set it to ws_protocol')
</span><del>-                validate_subprotocol(self._request.ws_protocol, hixie=False)
</del><ins>+                validate_subprotocol(self._request.ws_protocol)
</ins><span class="cx"> 
</span><span class="cx">                 self._logger.debug(
</span><span class="cx">                     'Subprotocol accepted: %r',
</span><span class="lines">@@ -375,6 +400,7 @@
</span><span class="cx"> 
</span><span class="cx">         response.append('HTTP/1.1 101 Switching Protocols\r\n')
</span><span class="cx"> 
</span><ins>+        # WebSocket headers
</ins><span class="cx">         response.append(format_header(
</span><span class="cx">             common.UPGRADE_HEADER, common.WEBSOCKET_UPGRADE_TYPE))
</span><span class="cx">         response.append(format_header(
</span><span class="lines">@@ -390,6 +416,11 @@
</span><span class="cx">             response.append(format_header(
</span><span class="cx">                 common.SEC_WEBSOCKET_EXTENSIONS_HEADER,
</span><span class="cx">                 common.format_extensions(self._request.ws_extensions)))
</span><ins>+
+        # Headers not specific for WebSocket
+        for name, value in self._request.extra_headers:
+            response.append(format_header(name, value))
+
</ins><span class="cx">         response.append('\r\n')
</span><span class="cx"> 
</span><span class="cx">         return ''.join(response)
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsockethandshakehybi00py"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi00.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi00.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi00.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -51,11 +51,12 @@
</span><span class="cx"> from mod_pywebsocket.stream import StreamHixie75
</span><span class="cx"> from mod_pywebsocket import util
</span><span class="cx"> from mod_pywebsocket.handshake._base import HandshakeException
</span><del>-from mod_pywebsocket.handshake._base import build_location
-from mod_pywebsocket.handshake._base import check_header_lines
</del><ins>+from mod_pywebsocket.handshake._base import check_request_line
</ins><span class="cx"> from mod_pywebsocket.handshake._base import format_header
</span><ins>+from mod_pywebsocket.handshake._base import get_default_port
</ins><span class="cx"> from mod_pywebsocket.handshake._base import get_mandatory_header
</span><del>-from mod_pywebsocket.handshake._base import validate_subprotocol
</del><ins>+from mod_pywebsocket.handshake._base import parse_host_header
+from mod_pywebsocket.handshake._base import validate_mandatory_header
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> _MANDATORY_HEADERS = [
</span><span class="lines">@@ -65,6 +66,56 @@
</span><span class="cx"> ]
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+def _validate_subprotocol(subprotocol):
+    &quot;&quot;&quot;Checks if characters in subprotocol are in range between U+0020 and
+    U+007E. A value in the Sec-WebSocket-Protocol field need to satisfy this
+    requirement.
+
+    See the Section 4.1. Opening handshake of the spec.
+    &quot;&quot;&quot;
+
+    if not subprotocol:
+        raise HandshakeException('Invalid subprotocol name: empty')
+
+    # Parameter should be in the range U+0020 to U+007E.
+    for c in subprotocol:
+        if not 0x20 &lt;= ord(c) &lt;= 0x7e:
+            raise HandshakeException(
+                'Illegal character in subprotocol name: %r' % c)
+
+
+def _check_header_lines(request, mandatory_headers):
+    check_request_line(request)
+
+    # The expected field names, and the meaning of their corresponding
+    # values, are as follows.
+    #  |Upgrade| and |Connection|
+    for key, expected_value in mandatory_headers:
+        validate_mandatory_header(request, key, expected_value)
+
+
+def _build_location(request):
+    &quot;&quot;&quot;Build WebSocket location for request.&quot;&quot;&quot;
+
+    location_parts = []
+    if request.is_https():
+        location_parts.append(common.WEB_SOCKET_SECURE_SCHEME)
+    else:
+        location_parts.append(common.WEB_SOCKET_SCHEME)
+    location_parts.append('://')
+    host, port = parse_host_header(request)
+    connection_port = request.connection.local_addr[1]
+    if port != connection_port:
+        raise HandshakeException('Header/connection port mismatch: %d/%d' %
+                                 (port, connection_port))
+    location_parts.append(host)
+    if (port != get_default_port(request.is_https())):
+        location_parts.append(':')
+        location_parts.append(str(port))
+    location_parts.append(request.unparsed_uri)
+    return ''.join(location_parts)
+
+
</ins><span class="cx"> class Handshaker(object):
</span><span class="cx">     &quot;&quot;&quot;Opening handshake processor for the WebSocket protocol version HyBi 00.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="lines">@@ -101,7 +152,7 @@
</span><span class="cx"> 
</span><span class="cx">         # 5.1 Reading the client's opening handshake.
</span><span class="cx">         # dispatcher sets it in self._request.
</span><del>-        check_header_lines(self._request, _MANDATORY_HEADERS)
</del><ins>+        _check_header_lines(self._request, _MANDATORY_HEADERS)
</ins><span class="cx">         self._set_resource()
</span><span class="cx">         self._set_subprotocol()
</span><span class="cx">         self._set_location()
</span><span class="lines">@@ -121,14 +172,14 @@
</span><span class="cx">         subprotocol = self._request.headers_in.get(
</span><span class="cx">             common.SEC_WEBSOCKET_PROTOCOL_HEADER)
</span><span class="cx">         if subprotocol is not None:
</span><del>-            validate_subprotocol(subprotocol, hixie=True)
</del><ins>+            _validate_subprotocol(subprotocol)
</ins><span class="cx">         self._request.ws_protocol = subprotocol
</span><span class="cx"> 
</span><span class="cx">     def _set_location(self):
</span><span class="cx">         # |Host|
</span><span class="cx">         host = self._request.headers_in.get(common.HOST_HEADER)
</span><span class="cx">         if host is not None:
</span><del>-            self._request.ws_location = build_location(self._request)
</del><ins>+            self._request.ws_location = _build_location(self._request)
</ins><span class="cx">         # TODO(ukai): check host is this host.
</span><span class="cx"> 
</span><span class="cx">     def _set_origin(self):
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsocketheaderparserhandlerpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/headerparserhandler.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/headerparserhandler.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/headerparserhandler.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -167,7 +167,9 @@
</span><span class="cx">         handler_root, handler_scan, allow_handlers_outside_root)
</span><span class="cx"> 
</span><span class="cx">     for warning in dispatcher.source_warnings():
</span><del>-        apache.log_error('mod_pywebsocket: %s' % warning, apache.APLOG_WARNING)
</del><ins>+        apache.log_error(
+            'mod_pywebsocket: Warning in source loading: %s' % warning,
+            apache.APLOG_WARNING)
</ins><span class="cx"> 
</span><span class="cx">     return dispatcher
</span><span class="cx"> 
</span><span class="lines">@@ -191,12 +193,16 @@
</span><span class="cx">         # Fallback to default http handler for request paths for which
</span><span class="cx">         # we don't have request handlers.
</span><span class="cx">         if not _dispatcher.get_handler_suite(request.uri):
</span><del>-            request.log_error('No handler for resource: %r' % request.uri,
-                              apache.APLOG_INFO)
-            request.log_error('Fallback to Apache', apache.APLOG_INFO)
</del><ins>+            request.log_error(
+                'mod_pywebsocket: No handler for resource: %r' % request.uri,
+                apache.APLOG_INFO)
+            request.log_error(
+                'mod_pywebsocket: Fallback to Apache', apache.APLOG_INFO)
</ins><span class="cx">             return apache.DECLINED
</span><span class="cx">     except dispatch.DispatchException, e:
</span><del>-        request.log_error('mod_pywebsocket: %s' % e, apache.APLOG_INFO)
</del><ins>+        request.log_error(
+            'mod_pywebsocket: Dispatch failed for error: %s' % e,
+            apache.APLOG_INFO)
</ins><span class="cx">         if not handshake_is_done:
</span><span class="cx">             return e.status
</span><span class="cx"> 
</span><span class="lines">@@ -210,26 +216,30 @@
</span><span class="cx">             handshake.do_handshake(
</span><span class="cx">                 request, _dispatcher, allowDraft75=allow_draft75)
</span><span class="cx">         except handshake.VersionException, e:
</span><del>-            request.log_error('mod_pywebsocket: %s' % e, apache.APLOG_INFO)
</del><ins>+            request.log_error(
+                'mod_pywebsocket: Handshake failed for version error: %s' % e,
+                apache.APLOG_INFO)
</ins><span class="cx">             request.err_headers_out.add(common.SEC_WEBSOCKET_VERSION_HEADER,
</span><span class="cx">                                         e.supported_versions)
</span><span class="cx">             return apache.HTTP_BAD_REQUEST
</span><span class="cx">         except handshake.HandshakeException, e:
</span><span class="cx">             # Handshake for ws/wss failed.
</span><span class="cx">             # Send http response with error status.
</span><del>-            request.log_error('mod_pywebsocket: %s' % e, apache.APLOG_INFO)
</del><ins>+            request.log_error(
+                'mod_pywebsocket: Handshake failed for error: %s' % e,
+                apache.APLOG_INFO)
</ins><span class="cx">             return e.status
</span><span class="cx"> 
</span><span class="cx">         handshake_is_done = True
</span><span class="cx">         request._dispatcher = _dispatcher
</span><span class="cx">         _dispatcher.transfer_data(request)
</span><span class="cx">     except handshake.AbortedByUserException, e:
</span><del>-        request.log_error('mod_pywebsocket: %s' % e, apache.APLOG_INFO)
</del><ins>+        request.log_error('mod_pywebsocket: Aborted: %s' % e, apache.APLOG_INFO)
</ins><span class="cx">     except Exception, e:
</span><span class="cx">         # DispatchException can also be thrown if something is wrong in
</span><span class="cx">         # pywebsocket code. It's caught here, then.
</span><span class="cx"> 
</span><del>-        request.log_error('mod_pywebsocket: %s\n%s' %
</del><ins>+        request.log_error('mod_pywebsocket: Exception occurred: %s\n%s' %
</ins><span class="cx">                           (e, util.get_stack_trace()),
</span><span class="cx">                           apache.APLOG_ERR)
</span><span class="cx">         # Unknown exceptions before handshake mean Apache must handle its
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsocketmuxpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/mux.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/mux.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/mux.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx"> from mod_pywebsocket import util
</span><span class="cx"> from mod_pywebsocket._stream_base import BadOperationException
</span><span class="cx"> from mod_pywebsocket._stream_base import ConnectionTerminatedException
</span><ins>+from mod_pywebsocket._stream_base import InvalidFrameException
</ins><span class="cx"> from mod_pywebsocket._stream_hybi import Frame
</span><span class="cx"> from mod_pywebsocket._stream_hybi import Stream
</span><span class="cx"> from mod_pywebsocket._stream_hybi import StreamOptions
</span><span class="lines">@@ -94,10 +95,12 @@
</span><span class="cx"> _DROP_CODE_INVALID_MUX_CONTROL_BLOCK = 2005
</span><span class="cx"> _DROP_CODE_CHANNEL_ALREADY_EXISTS = 2006
</span><span class="cx"> _DROP_CODE_NEW_CHANNEL_SLOT_VIOLATION = 2007
</span><ins>+_DROP_CODE_UNKNOWN_REQUEST_ENCODING = 2010
</ins><span class="cx"> 
</span><del>-_DROP_CODE_UNKNOWN_REQUEST_ENCODING = 3002
</del><span class="cx"> _DROP_CODE_SEND_QUOTA_VIOLATION = 3005
</span><ins>+_DROP_CODE_SEND_QUOTA_OVERFLOW = 3006
</ins><span class="cx"> _DROP_CODE_ACKNOWLEDGED = 3008
</span><ins>+_DROP_CODE_BAD_FRAGMENTATION = 3009
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class MuxUnexpectedException(Exception):
</span><span class="lines">@@ -158,8 +161,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> def _create_add_channel_response(channel_id, encoded_handshake,
</span><del>-                                 encoding=0, rejected=False,
-                                 outer_frame_mask=False):
</del><ins>+                                 encoding=0, rejected=False):
</ins><span class="cx">     if encoding != 0 and encoding != 1:
</span><span class="cx">         raise ValueError('Invalid encoding %d' % encoding)
</span><span class="cx"> 
</span><span class="lines">@@ -169,12 +171,10 @@
</span><span class="cx">              _encode_channel_id(channel_id) +
</span><span class="cx">              _encode_number(len(encoded_handshake)) +
</span><span class="cx">              encoded_handshake)
</span><del>-    payload = _encode_channel_id(_CONTROL_CHANNEL_ID) + block
-    return create_binary_frame(payload, mask=outer_frame_mask)
</del><ins>+    return block
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-def _create_drop_channel(channel_id, code=None, message='',
-                         outer_frame_mask=False):
</del><ins>+def _create_drop_channel(channel_id, code=None, message=''):
</ins><span class="cx">     if len(message) &gt; 0 and code is None:
</span><span class="cx">         raise ValueError('Code must be specified if message is specified')
</span><span class="cx"> 
</span><span class="lines">@@ -187,36 +187,31 @@
</span><span class="cx">         reason_size = _encode_number(len(reason))
</span><span class="cx">         block += reason_size + reason
</span><span class="cx"> 
</span><del>-    payload = _encode_channel_id(_CONTROL_CHANNEL_ID) + block
-    return create_binary_frame(payload, mask=outer_frame_mask)
</del><ins>+    return block
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-def _create_flow_control(channel_id, replenished_quota,
-                         outer_frame_mask=False):
</del><ins>+def _create_flow_control(channel_id, replenished_quota):
</ins><span class="cx">     first_byte = _MUX_OPCODE_FLOW_CONTROL &lt;&lt; 5
</span><span class="cx">     block = (chr(first_byte) +
</span><span class="cx">              _encode_channel_id(channel_id) +
</span><span class="cx">              _encode_number(replenished_quota))
</span><del>-    payload = _encode_channel_id(_CONTROL_CHANNEL_ID) + block
-    return create_binary_frame(payload, mask=outer_frame_mask)
</del><ins>+    return block
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-def _create_new_channel_slot(slots, send_quota, outer_frame_mask=False):
</del><ins>+def _create_new_channel_slot(slots, send_quota):
</ins><span class="cx">     if slots &lt; 0 or send_quota &lt; 0:
</span><span class="cx">         raise ValueError('slots and send_quota must be non-negative.')
</span><span class="cx">     first_byte = _MUX_OPCODE_NEW_CHANNEL_SLOT &lt;&lt; 5
</span><span class="cx">     block = (chr(first_byte) +
</span><span class="cx">              _encode_number(slots) +
</span><span class="cx">              _encode_number(send_quota))
</span><del>-    payload = _encode_channel_id(_CONTROL_CHANNEL_ID) + block
-    return create_binary_frame(payload, mask=outer_frame_mask)
</del><ins>+    return block
</ins><span class="cx"> 
</span><span class="cx"> 
</span><del>-def _create_fallback_new_channel_slot(outer_frame_mask=False):
</del><ins>+def _create_fallback_new_channel_slot():
</ins><span class="cx">     first_byte = (_MUX_OPCODE_NEW_CHANNEL_SLOT &lt;&lt; 5) | 1 # Set the F flag
</span><span class="cx">     block = (chr(first_byte) + _encode_number(0) + _encode_number(0))
</span><del>-    payload = _encode_channel_id(_CONTROL_CHANNEL_ID) + block
-    return create_binary_frame(payload, mask=outer_frame_mask)
</del><ins>+    return block
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> def _parse_request_text(request_text):
</span><span class="lines">@@ -318,44 +313,34 @@
</span><span class="cx"> 
</span><span class="cx">     def _read_number(self):
</span><span class="cx">         if self._read_position + 1 &gt; len(self._data):
</span><del>-            raise PhysicalConnectionError(
-                _DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
</del><ins>+            raise ValueError(
</ins><span class="cx">                 'Cannot read the first byte of number field')
</span><span class="cx"> 
</span><span class="cx">         number = ord(self._data[self._read_position])
</span><span class="cx">         if number &amp; 0x80 == 0x80:
</span><del>-            raise PhysicalConnectionError(
-                _DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
</del><ins>+            raise ValueError(
</ins><span class="cx">                 'The most significant bit of the first byte of number should '
</span><span class="cx">                 'be unset')
</span><span class="cx">         self._read_position += 1
</span><span class="cx">         pos = self._read_position
</span><span class="cx">         if number == 127:
</span><span class="cx">             if pos + 8 &gt; len(self._data):
</span><del>-                raise PhysicalConnectionError(
-                    _DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
-                    'Invalid number field')
</del><ins>+                raise ValueError('Invalid number field')
</ins><span class="cx">             self._read_position += 8
</span><span class="cx">             number = struct.unpack('!Q', self._data[pos:pos+8])[0]
</span><span class="cx">             if number &gt; 0x7FFFFFFFFFFFFFFF:
</span><del>-                raise PhysicalConnectionError(
-                    _DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
-                    'Encoded number &gt;= 2^63')
</del><ins>+                raise ValueError('Encoded number(%d) &gt;= 2^63' % number)
</ins><span class="cx">             if number &lt;= 0xFFFF:
</span><del>-                raise PhysicalConnectionError(
-                    _DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
</del><ins>+                raise ValueError(
</ins><span class="cx">                     '%d should not be encoded by 9 bytes encoding' % number)
</span><span class="cx">             return number
</span><span class="cx">         if number == 126:
</span><span class="cx">             if pos + 2 &gt; len(self._data):
</span><del>-                raise PhysicalConnectionError(
-                    _DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
-                    'Invalid number field')
</del><ins>+                raise ValueError('Invalid number field')
</ins><span class="cx">             self._read_position += 2
</span><span class="cx">             number = struct.unpack('!H', self._data[pos:pos+2])[0]
</span><span class="cx">             if number &lt;= 125:
</span><del>-                raise PhysicalConnectionError(
-                    _DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
</del><ins>+                raise ValueError(
</ins><span class="cx">                     '%d should not be encoded by 3 bytes encoding' % number)
</span><span class="cx">         return number
</span><span class="cx"> 
</span><span class="lines">@@ -366,7 +351,11 @@
</span><span class="cx">             - the contents.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        size = self._read_number()
</del><ins>+        try:
+            size = self._read_number()
+        except ValueError, e:
+            raise PhysicalConnectionError(_DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
+                                          str(e))
</ins><span class="cx">         pos = self._read_position
</span><span class="cx">         if pos + size &gt; len(self._data):
</span><span class="cx">             raise PhysicalConnectionError(
</span><span class="lines">@@ -419,9 +408,11 @@
</span><span class="cx"> 
</span><span class="cx">         try:
</span><span class="cx">             control_block.channel_id = self.read_channel_id()
</span><ins>+            control_block.send_quota = self._read_number()
</ins><span class="cx">         except ValueError, e:
</span><del>-            raise PhysicalConnectionError(_DROP_CODE_INVALID_MUX_CONTROL_BLOCK)
-        control_block.send_quota = self._read_number()
</del><ins>+            raise PhysicalConnectionError(_DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
+                                          str(e))
+
</ins><span class="cx">         return control_block
</span><span class="cx"> 
</span><span class="cx">     def _read_drop_channel(self, first_byte, control_block):
</span><span class="lines">@@ -455,8 +446,12 @@
</span><span class="cx">                 _DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
</span><span class="cx">                 'Reserved bits must be unset')
</span><span class="cx">         control_block.fallback = first_byte &amp; 1
</span><del>-        control_block.slots = self._read_number()
-        control_block.send_quota = self._read_number()
</del><ins>+        try:
+            control_block.slots = self._read_number()
+            control_block.send_quota = self._read_number()
+        except ValueError, e:
+            raise PhysicalConnectionError(_DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
+                                          str(e))
</ins><span class="cx">         return control_block
</span><span class="cx"> 
</span><span class="cx">     def read_control_blocks(self):
</span><span class="lines">@@ -549,8 +544,12 @@
</span><span class="cx">         self._mux_handler = mux_handler
</span><span class="cx">         self._channel_id = channel_id
</span><span class="cx">         self._incoming_data = ''
</span><ins>+
+        # - Protects _waiting_write_completion
+        # - Signals the thread waiting for completion of write by mux handler
</ins><span class="cx">         self._write_condition = threading.Condition()
</span><span class="cx">         self._waiting_write_completion = False
</span><ins>+
</ins><span class="cx">         self._read_condition = threading.Condition()
</span><span class="cx">         self._read_state = self.STATE_ACTIVE
</span><span class="cx"> 
</span><span class="lines">@@ -594,6 +593,7 @@
</span><span class="cx">             self._waiting_write_completion = True
</span><span class="cx">             self._mux_handler.send_data(self._channel_id, data)
</span><span class="cx">             self._write_condition.wait()
</span><ins>+            # TODO(tyoshino): Raise an exception if woke up by on_writer_done.
</ins><span class="cx">         finally:
</span><span class="cx">             self._write_condition.release()
</span><span class="cx"> 
</span><span class="lines">@@ -607,20 +607,31 @@
</span><span class="cx"> 
</span><span class="cx">         self._mux_handler.send_control_data(data)
</span><span class="cx"> 
</span><del>-    def notify_write_done(self):
</del><ins>+    def on_write_data_done(self):
</ins><span class="cx">         &quot;&quot;&quot;Called when sending data is completed.&quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         try:
</span><span class="cx">             self._write_condition.acquire()
</span><span class="cx">             if not self._waiting_write_completion:
</span><span class="cx">                 raise MuxUnexpectedException(
</span><del>-                    'Invalid call of notify_write_done for logical connection'
-                    ' %d' % self._channel_id)
</del><ins>+                    'Invalid call of on_write_data_done for logical '
+                    'connection %d' % self._channel_id)
</ins><span class="cx">             self._waiting_write_completion = False
</span><span class="cx">             self._write_condition.notify()
</span><span class="cx">         finally:
</span><span class="cx">             self._write_condition.release()
</span><span class="cx"> 
</span><ins>+    def on_writer_done(self):
+        &quot;&quot;&quot;Called by the mux handler when the writer thread has finished.&quot;&quot;&quot;
+
+        try:
+            self._write_condition.acquire()
+            self._waiting_write_completion = False
+            self._write_condition.notify()
+        finally:
+            self._write_condition.release()
+
+
</ins><span class="cx">     def append_frame_data(self, frame_data):
</span><span class="cx">         &quot;&quot;&quot;Appends incoming frame data. Called when mux_handler dispatches
</span><span class="cx">         frame data to the corresponding application.
</span><span class="lines">@@ -686,38 +697,163 @@
</span><span class="cx">         self._read_condition.release()
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+class _InnerMessage(object):
+    &quot;&quot;&quot;Holds the result of _InnerMessageBuilder.build().
+    &quot;&quot;&quot;
+
+    def __init__(self, opcode, payload):
+        self.opcode = opcode
+        self.payload = payload
+
+
+class _InnerMessageBuilder(object):
+    &quot;&quot;&quot;A class that holds the context of inner message fragmentation and
+    builds a message from fragmented inner frame(s).
+    &quot;&quot;&quot;
+
+    def __init__(self):
+        self._control_opcode = None
+        self._pending_control_fragments = []
+        self._message_opcode = None
+        self._pending_message_fragments = []
+        self._frame_handler = self._handle_first
+
+    def _handle_first(self, frame):
+        if frame.opcode == common.OPCODE_CONTINUATION:
+            raise InvalidFrameException('Sending invalid continuation opcode')
+
+        if common.is_control_opcode(frame.opcode):
+            return self._process_first_fragmented_control(frame)
+        else:
+            return self._process_first_fragmented_message(frame)
+
+    def _process_first_fragmented_control(self, frame):
+        self._control_opcode = frame.opcode
+        self._pending_control_fragments.append(frame.payload)
+        if not frame.fin:
+            self._frame_handler = self._handle_fragmented_control
+            return None
+        return self._reassemble_fragmented_control()
+
+    def _process_first_fragmented_message(self, frame):
+        self._message_opcode = frame.opcode
+        self._pending_message_fragments.append(frame.payload)
+        if not frame.fin:
+            self._frame_handler = self._handle_fragmented_message
+            return None
+        return self._reassemble_fragmented_message()
+
+    def _handle_fragmented_control(self, frame):
+        if frame.opcode != common.OPCODE_CONTINUATION:
+            raise InvalidFrameException(
+                'Sending invalid opcode %d while sending fragmented control '
+                'message' % frame.opcode)
+        self._pending_control_fragments.append(frame.payload)
+        if not frame.fin:
+            return None
+        return self._reassemble_fragmented_control()
+
+    def _reassemble_fragmented_control(self):
+        opcode = self._control_opcode
+        payload = ''.join(self._pending_control_fragments)
+        self._control_opcode = None
+        self._pending_control_fragments = []
+        if self._message_opcode is not None:
+            self._frame_handler = self._handle_fragmented_message
+        else:
+            self._frame_handler = self._handle_first
+        return _InnerMessage(opcode, payload)
+
+    def _handle_fragmented_message(self, frame):
+        # Sender can interleave a control message while sending fragmented
+        # messages.
+        if common.is_control_opcode(frame.opcode):
+            if self._control_opcode is not None:
+                raise MuxUnexpectedException(
+                    'Should not reach here(Bug in builder)')
+            return self._process_first_fragmented_control(frame)
+
+        if frame.opcode != common.OPCODE_CONTINUATION:
+            raise InvalidFrameException(
+                'Sending invalid opcode %d while sending fragmented message' %
+                frame.opcode)
+        self._pending_message_fragments.append(frame.payload)
+        if not frame.fin:
+            return None
+        return self._reassemble_fragmented_message()
+
+    def _reassemble_fragmented_message(self):
+        opcode = self._message_opcode
+        payload = ''.join(self._pending_message_fragments)
+        self._message_opcode = None
+        self._pending_message_fragments = []
+        self._frame_handler = self._handle_first
+        return _InnerMessage(opcode, payload)
+
+    def build(self, frame):
+        &quot;&quot;&quot;Build an inner message. Returns an _InnerMessage instance when
+        the given frame is the last fragmented frame. Returns None otherwise.
+
+        Args:
+            frame: an inner frame.
+        Raises:
+            InvalidFrameException: when received invalid opcode. (e.g.
+                receiving non continuation data opcode but the fin flag of
+                the previous inner frame was not set.)
+        &quot;&quot;&quot;
+
+        return self._frame_handler(frame)
+
+
</ins><span class="cx"> class _LogicalStream(Stream):
</span><span class="cx">     &quot;&quot;&quot;Mimics the Stream class. This class interprets multiplexed WebSocket
</span><span class="cx">     frames.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def __init__(self, request, send_quota, receive_quota):
</del><ins>+    def __init__(self, request, stream_options, send_quota, receive_quota):
</ins><span class="cx">         &quot;&quot;&quot;Constructs an instance.
</span><span class="cx"> 
</span><span class="cx">         Args:
</span><span class="cx">             request: _LogicalRequest instance.
</span><ins>+            stream_options: StreamOptions instance.
</ins><span class="cx">             send_quota: Initial send quota.
</span><span class="cx">             receive_quota: Initial receive quota.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        # TODO(bashi): Support frame filters.
-        stream_options = StreamOptions()
</del><span class="cx">         # Physical stream is responsible for masking.
</span><span class="cx">         stream_options.unmask_receive = False
</span><del>-        # Control frames can be fragmented on logical channel.
-        stream_options.allow_fragmented_control_frame = True
</del><span class="cx">         Stream.__init__(self, request, stream_options)
</span><ins>+
+        self._send_closed = False
</ins><span class="cx">         self._send_quota = send_quota
</span><del>-        self._send_quota_condition = threading.Condition()
</del><ins>+        # - Protects _send_closed and _send_quota
+        # - Signals the thread waiting for send quota replenished
+        self._send_condition = threading.Condition()
+
+        # The opcode of the first frame in messages.
+        self._message_opcode = common.OPCODE_TEXT
+        # True when the last message was fragmented.
+        self._last_message_was_fragmented = False
+
</ins><span class="cx">         self._receive_quota = receive_quota
</span><span class="cx">         self._write_inner_frame_semaphore = threading.Semaphore()
</span><span class="cx"> 
</span><ins>+        self._inner_message_builder = _InnerMessageBuilder()
+
</ins><span class="cx">     def _create_inner_frame(self, opcode, payload, end=True):
</span><del>-        # TODO(bashi): Support extensions that use reserved bits.
-        first_byte = (end &lt;&lt; 7) | opcode
-        return (_encode_channel_id(self._request.channel_id) +
-                chr(first_byte) + payload)
</del><ins>+        frame = Frame(fin=end, opcode=opcode, payload=payload)
+        for frame_filter in self._options.outgoing_frame_filters:
+            frame_filter.filter(frame)
</ins><span class="cx"> 
</span><ins>+        if len(payload) != len(frame.payload):
+            raise MuxUnexpectedException(
+                'Mux extension must not be used after extensions which change '
+                ' frame boundary')
+
+        first_byte = ((frame.fin &lt;&lt; 7) | (frame.rsv1 &lt;&lt; 6) |
+                      (frame.rsv2 &lt;&lt; 5) | (frame.rsv3 &lt;&lt; 4) | frame.opcode)
+        return chr(first_byte) + frame.payload
+
</ins><span class="cx">     def _write_inner_frame(self, opcode, payload, end=True):
</span><span class="cx">         payload_length = len(payload)
</span><span class="cx">         write_position = 0
</span><span class="lines">@@ -730,15 +866,37 @@
</span><span class="cx">             # multiplexing control blocks can be inserted between fragmented
</span><span class="cx">             # inner frames on the physical channel.
</span><span class="cx">             self._write_inner_frame_semaphore.acquire()
</span><ins>+
+            # Consume an octet quota when this is the first fragmented frame.
+            if opcode != common.OPCODE_CONTINUATION:
+                try:
+                    self._send_condition.acquire()
+                    while (not self._send_closed) and self._send_quota == 0:
+                        self._send_condition.wait()
+
+                    if self._send_closed:
+                        raise BadOperationException(
+                            'Logical connection %d is closed' %
+                            self._request.channel_id)
+
+                    self._send_quota -= 1
+                finally:
+                    self._send_condition.release()
+
</ins><span class="cx">             while write_position &lt; payload_length:
</span><span class="cx">                 try:
</span><del>-                    self._send_quota_condition.acquire()
-                    while self._send_quota == 0:
</del><ins>+                    self._send_condition.acquire()
+                    while (not self._send_closed) and self._send_quota == 0:
</ins><span class="cx">                         self._logger.debug(
</span><span class="cx">                             'No quota. Waiting FlowControl message for %d.' %
</span><span class="cx">                             self._request.channel_id)
</span><del>-                        self._send_quota_condition.wait()
</del><ins>+                        self._send_condition.wait()
</ins><span class="cx"> 
</span><ins>+                    if self._send_closed:
+                        raise BadOperationException(
+                            'Logical connection %d is closed' %
+                            self.request._channel_id)
+
</ins><span class="cx">                     remaining = payload_length - write_position
</span><span class="cx">                     write_length = min(self._send_quota, remaining)
</span><span class="cx">                     inner_frame_end = (
</span><span class="lines">@@ -749,18 +907,16 @@
</span><span class="cx">                         opcode,
</span><span class="cx">                         payload[write_position:write_position+write_length],
</span><span class="cx">                         inner_frame_end)
</span><del>-                    frame_data = self._writer.build(
-                        inner_frame, end=True, binary=True)
</del><span class="cx">                     self._send_quota -= write_length
</span><span class="cx">                     self._logger.debug('Consumed quota=%d, remaining=%d' %
</span><span class="cx">                                        (write_length, self._send_quota))
</span><span class="cx">                 finally:
</span><del>-                    self._send_quota_condition.release()
</del><ins>+                    self._send_condition.release()
</ins><span class="cx"> 
</span><span class="cx">                 # Writing data will block the worker so we need to release
</span><del>-                # _send_quota_condition before writing.
-                self._logger.debug('Sending inner frame: %r' % frame_data)
-                self._request.connection.write(frame_data)
</del><ins>+                # _send_condition before writing.
+                self._logger.debug('Sending inner frame: %r' % inner_frame)
+                self._request.connection.write(inner_frame)
</ins><span class="cx">                 write_position += write_length
</span><span class="cx"> 
</span><span class="cx">                 opcode = common.OPCODE_CONTINUATION
</span><span class="lines">@@ -773,12 +929,18 @@
</span><span class="cx">     def replenish_send_quota(self, send_quota):
</span><span class="cx">         &quot;&quot;&quot;Replenish send quota.&quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        self._send_quota_condition.acquire()
-        self._send_quota += send_quota
-        self._logger.debug('Replenished send quota for channel id %d: %d' %
-                           (self._request.channel_id, self._send_quota))
-        self._send_quota_condition.notify()
-        self._send_quota_condition.release()
</del><ins>+        try:
+            self._send_condition.acquire()
+            if self._send_quota + send_quota &gt; 0x7FFFFFFFFFFFFFFF:
+                self._send_quota = 0
+                raise LogicalChannelError(
+                    self._request.channel_id, _DROP_CODE_SEND_QUOTA_OVERFLOW)
+            self._send_quota += send_quota
+            self._logger.debug('Replenished send quota for channel id %d: %d' %
+                               (self._request.channel_id, self._send_quota))
+        finally:
+            self._send_condition.notify()
+            self._send_condition.release()
</ins><span class="cx"> 
</span><span class="cx">     def consume_receive_quota(self, amount):
</span><span class="cx">         &quot;&quot;&quot;Consumes receive quota. Returns False on failure.&quot;&quot;&quot;
</span><span class="lines">@@ -808,7 +970,19 @@
</span><span class="cx">             opcode = common.OPCODE_TEXT
</span><span class="cx">             message = message.encode('utf-8')
</span><span class="cx"> 
</span><ins>+        for message_filter in self._options.outgoing_message_filters:
+            message = message_filter.filter(message, end, binary)
+
+        if self._last_message_was_fragmented:
+            if opcode != self._message_opcode:
+                raise BadOperationException('Message types are different in '
+                                            'frames for the same message')
+            opcode = common.OPCODE_CONTINUATION
+        else:
+            self._message_opcode = opcode
+
</ins><span class="cx">         self._write_inner_frame(opcode, message, end)
</span><ins>+        self._last_message_was_fragmented = not end
</ins><span class="cx"> 
</span><span class="cx">     def _receive_frame(self):
</span><span class="cx">         &quot;&quot;&quot;Overrides Stream._receive_frame.
</span><span class="lines">@@ -821,6 +995,9 @@
</span><span class="cx"> 
</span><span class="cx">         opcode, payload, fin, rsv1, rsv2, rsv3 = Stream._receive_frame(self)
</span><span class="cx">         amount = len(payload)
</span><ins>+        # Replenish extra one octet when receiving the first fragmented frame.
+        if opcode != common.OPCODE_CONTINUATION:
+            amount += 1
</ins><span class="cx">         self._receive_quota += amount
</span><span class="cx">         frame_data = _create_flow_control(self._request.channel_id,
</span><span class="cx">                                           amount)
</span><span class="lines">@@ -829,6 +1006,21 @@
</span><span class="cx">         self._request.connection.write_control_data(frame_data)
</span><span class="cx">         return opcode, payload, fin, rsv1, rsv2, rsv3
</span><span class="cx"> 
</span><ins>+    def _get_message_from_frame(self, frame):
+        &quot;&quot;&quot;Overrides Stream._get_message_from_frame.
+        &quot;&quot;&quot;
+
+        try:
+            inner_message = self._inner_message_builder.build(frame)
+        except InvalidFrameException:
+            raise LogicalChannelError(
+                self._request.channel_id, _DROP_CODE_BAD_FRAGMENTATION)
+
+        if inner_message is None:
+            return None
+        self._original_opcode = inner_message.opcode
+        return inner_message.payload
+
</ins><span class="cx">     def receive_message(self):
</span><span class="cx">         &quot;&quot;&quot;Overrides Stream.receive_message.&quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -875,12 +1067,13 @@
</span><span class="cx">                            self._request.channel_id)
</span><span class="cx">         self._request.server_terminated = True
</span><span class="cx"> 
</span><del>-    def _drain_received_data(self):
-        &quot;&quot;&quot;Overrides Stream._drain_received_data. Nothing need to be done for
-        logical channel.
-        &quot;&quot;&quot;
</del><ins>+    def stop_sending(self):
+        &quot;&quot;&quot;Stops accepting new send operation (_write_inner_frame).&quot;&quot;&quot;
</ins><span class="cx"> 
</span><del>-        pass
</del><ins>+        self._send_condition.acquire()
+        self._send_closed = True
+        self._send_condition.notify()
+        self._send_condition.release()
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> class _OutgoingData(object):
</span><span class="lines">@@ -911,8 +1104,17 @@
</span><span class="cx">         self._logger = util.get_class_logger(self)
</span><span class="cx">         self._mux_handler = mux_handler
</span><span class="cx">         self.setDaemon(True)
</span><ins>+
+        # When set, make this thread stop accepting new data, flush pending
+        # data and exit.
</ins><span class="cx">         self._stop_requested = False
</span><ins>+        # The close code of the physical connection.
+        self._close_code = common.STATUS_NORMAL_CLOSURE
+        # Deque for passing write data. It's protected by _deque_condition
+        # until _stop_requested is set.
</ins><span class="cx">         self._deque = collections.deque()
</span><ins>+        # - Protects _deque, _stop_requested and _close_code
+        # - Signals threads waiting for them to be available
</ins><span class="cx">         self._deque_condition = threading.Condition()
</span><span class="cx"> 
</span><span class="cx">     def put_outgoing_data(self, data):
</span><span class="lines">@@ -937,8 +1139,11 @@
</span><span class="cx">             self._deque_condition.release()
</span><span class="cx"> 
</span><span class="cx">     def _write_data(self, outgoing_data):
</span><ins>+        message = (_encode_channel_id(outgoing_data.channel_id) +
+                   outgoing_data.data)
</ins><span class="cx">         try:
</span><del>-            self._mux_handler.physical_connection.write(outgoing_data.data)
</del><ins>+            self._mux_handler.physical_stream.send_message(
+                message=message, end=True, binary=True)
</ins><span class="cx">         except Exception, e:
</span><span class="cx">             util.prepend_message_to_exception(
</span><span class="cx">                 'Failed to send message to %r: ' %
</span><span class="lines">@@ -948,33 +1153,51 @@
</span><span class="cx">         # TODO(bashi): It would be better to block the thread that sends
</span><span class="cx">         # control data as well.
</span><span class="cx">         if outgoing_data.channel_id != _CONTROL_CHANNEL_ID:
</span><del>-            self._mux_handler.notify_write_done(outgoing_data.channel_id)
</del><ins>+            self._mux_handler.notify_write_data_done(outgoing_data.channel_id)
</ins><span class="cx"> 
</span><span class="cx">     def run(self):
</span><del>-        self._deque_condition.acquire()
-        while not self._stop_requested:
-            if len(self._deque) == 0:
-                self._deque_condition.wait()
-                continue
-
-            outgoing_data = self._deque.popleft()
-            self._deque_condition.release()
-            self._write_data(outgoing_data)
</del><ins>+        try:
</ins><span class="cx">             self._deque_condition.acquire()
</span><ins>+            while not self._stop_requested:
+                if len(self._deque) == 0:
+                    self._deque_condition.wait()
+                    continue
</ins><span class="cx"> 
</span><del>-        # Flush deque
-        try:
-            while len(self._deque) &gt; 0:
</del><span class="cx">                 outgoing_data = self._deque.popleft()
</span><ins>+
+                self._deque_condition.release()
</ins><span class="cx">                 self._write_data(outgoing_data)
</span><ins>+                self._deque_condition.acquire()
+
+            # Flush deque.
+            #
+            # At this point, self._deque_condition is always acquired.
+            try:
+                while len(self._deque) &gt; 0:
+                    outgoing_data = self._deque.popleft()
+                    self._write_data(outgoing_data)
+            finally:
+                self._deque_condition.release()
+
+            # Close physical connection.
+            try:
+                # Don't wait the response here. The response will be read
+                # by the reader thread.
+                self._mux_handler.physical_stream.close_connection(
+                    self._close_code, wait_response=False)
+            except Exception, e:
+                util.prepend_message_to_exception(
+                    'Failed to close the physical connection: %r' % e)
+                raise
</ins><span class="cx">         finally:
</span><del>-            self._deque_condition.release()
</del><ins>+            self._mux_handler.notify_writer_done()
</ins><span class="cx"> 
</span><del>-    def stop(self):
</del><ins>+    def stop(self, close_code=common.STATUS_NORMAL_CLOSURE):
</ins><span class="cx">         &quot;&quot;&quot;Stops the writer thread.&quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         self._deque_condition.acquire()
</span><span class="cx">         self._stop_requested = True
</span><ins>+        self._close_code = close_code
</ins><span class="cx">         self._deque_condition.notify()
</span><span class="cx">         self._deque_condition.release()
</span><span class="cx"> 
</span><span class="lines">@@ -1055,6 +1278,9 @@
</span><span class="cx">         try:
</span><span class="cx">             # Non-critical exceptions will be handled by dispatcher.
</span><span class="cx">             self._mux_handler.dispatcher.transfer_data(self._request)
</span><ins>+        except LogicalChannelError, e:
+            self._mux_handler.fail_logical_channel(
+                e.channel_id, e.drop_code, e.message)
</ins><span class="cx">         finally:
</span><span class="cx">             self._mux_handler.notify_worker_done(self._request.channel_id)
</span><span class="cx"> 
</span><span class="lines">@@ -1083,8 +1309,6 @@
</span><span class="cx">         #     these headers are included already.
</span><span class="cx">         request.headers_in[common.UPGRADE_HEADER] = (
</span><span class="cx">             common.WEBSOCKET_UPGRADE_TYPE)
</span><del>-        request.headers_in[common.CONNECTION_HEADER] = (
-            common.UPGRADE_CONNECTION_TYPE)
</del><span class="cx">         request.headers_in[common.SEC_WEBSOCKET_VERSION_HEADER] = (
</span><span class="cx">             str(common.VERSION_HYBI_LATEST))
</span><span class="cx">         request.headers_in[common.SEC_WEBSOCKET_KEY_HEADER] = (
</span><span class="lines">@@ -1095,8 +1319,9 @@
</span><span class="cx"> 
</span><span class="cx">         self._logger.debug('Creating logical stream for %d' %
</span><span class="cx">                            self._request.channel_id)
</span><del>-        return _LogicalStream(self._request, self._send_quota,
-                              self._receive_quota)
</del><ins>+        return _LogicalStream(
+            self._request, stream_options, self._send_quota,
+            self._receive_quota)
</ins><span class="cx"> 
</span><span class="cx">     def _create_handshake_response(self, accept):
</span><span class="cx">         &quot;&quot;&quot;Override hybi._create_handshake_response.&quot;&quot;&quot;
</span><span class="lines">@@ -1105,7 +1330,9 @@
</span><span class="cx"> 
</span><span class="cx">         response.append('HTTP/1.1 101 Switching Protocols\r\n')
</span><span class="cx"> 
</span><del>-        # Upgrade, Connection and Sec-WebSocket-Accept should be excluded.
</del><ins>+        # Upgrade and Sec-WebSocket-Accept should be excluded.
+        response.append('%s: %s\r\n' % (
+            common.CONNECTION_HEADER, common.UPGRADE_CONNECTION_TYPE))
</ins><span class="cx">         if self._request.ws_protocol is not None:
</span><span class="cx">             response.append('%s: %s\r\n' % (
</span><span class="cx">                 common.SEC_WEBSOCKET_PROTOCOL_HEADER,
</span><span class="lines">@@ -1169,8 +1396,6 @@
</span><span class="cx">                     del headers[key]
</span><span class="cx">                 else:
</span><span class="cx">                     headers[key] = value
</span><del>-        # TODO(bashi): Support extensions
-        headers['Sec-WebSocket-Extensions'] = ''
</del><span class="cx">         return headers
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1232,8 +1457,12 @@
</span><span class="cx"> 
</span><span class="cx">         # Create &quot;Implicitly Opened Connection&quot;.
</span><span class="cx">         logical_connection = _LogicalConnection(self, _DEFAULT_CHANNEL_ID)
</span><del>-        self._handshake_base = _HandshakeDeltaBase(
-            self.original_request.headers_in)
</del><ins>+        headers = copy.copy(self.original_request.headers_in)
+        # Add extensions for logical channel.
+        headers[common.SEC_WEBSOCKET_EXTENSIONS_HEADER] = (
+            common.format_extensions(
+                self.original_request.mux_processor.extensions()))
+        self._handshake_base = _HandshakeDeltaBase(headers)
</ins><span class="cx">         logical_request = _LogicalRequest(
</span><span class="cx">             _DEFAULT_CHANNEL_ID,
</span><span class="cx">             self.original_request.method,
</span><span class="lines">@@ -1245,8 +1474,9 @@
</span><span class="cx">         # but we will send FlowControl later so set the initial quota to
</span><span class="cx">         # _INITIAL_QUOTA_FOR_CLIENT.
</span><span class="cx">         self._channel_slots.append(_INITIAL_QUOTA_FOR_CLIENT)
</span><ins>+        send_quota = self.original_request.mux_processor.quota()
</ins><span class="cx">         if not self._do_handshake_for_logical_request(
</span><del>-            logical_request, send_quota=self.original_request.mux_quota):
</del><ins>+            logical_request, send_quota=send_quota):
</ins><span class="cx">             raise MuxUnexpectedException(
</span><span class="cx">                 'Failed handshake on the default channel id')
</span><span class="cx">         self._add_logical_channel(logical_request)
</span><span class="lines">@@ -1287,7 +1517,6 @@
</span><span class="cx">                 if not self._worker_done_notify_received:
</span><span class="cx">                     self._logger.debug('Waiting worker(s) timed out')
</span><span class="cx">                     return False
</span><del>-
</del><span class="cx">         finally:
</span><span class="cx">             self._logical_channels_condition.release()
</span><span class="cx"> 
</span><span class="lines">@@ -1297,7 +1526,7 @@
</span><span class="cx"> 
</span><span class="cx">         return True
</span><span class="cx"> 
</span><del>-    def notify_write_done(self, channel_id):
</del><ins>+    def notify_write_data_done(self, channel_id):
</ins><span class="cx">         &quot;&quot;&quot;Called by the writer thread when a write operation has done.
</span><span class="cx"> 
</span><span class="cx">         Args:
</span><span class="lines">@@ -1308,7 +1537,7 @@
</span><span class="cx">             self._logical_channels_condition.acquire()
</span><span class="cx">             if channel_id in self._logical_channels:
</span><span class="cx">                 channel_data = self._logical_channels[channel_id]
</span><del>-                channel_data.request.connection.notify_write_done()
</del><ins>+                channel_data.request.connection.on_write_data_done()
</ins><span class="cx">             else:
</span><span class="cx">                 self._logger.debug('Seems that logical channel for %d has gone'
</span><span class="cx">                                    % channel_id)
</span><span class="lines">@@ -1469,9 +1698,11 @@
</span><span class="cx">                 return
</span><span class="cx">             channel_data = self._logical_channels[block.channel_id]
</span><span class="cx">             channel_data.drop_code = _DROP_CODE_ACKNOWLEDGED
</span><ins>+
</ins><span class="cx">             # Close the logical channel
</span><span class="cx">             channel_data.request.connection.set_read_state(
</span><span class="cx">                 _LogicalConnection.STATE_TERMINATED)
</span><ins>+            channel_data.request.ws_stream.stop_sending()
</ins><span class="cx">         finally:
</span><span class="cx">             self._logical_channels_condition.release()
</span><span class="cx"> 
</span><span class="lines">@@ -1506,8 +1737,11 @@
</span><span class="cx">                 return
</span><span class="cx">             channel_data = self._logical_channels[channel_id]
</span><span class="cx">             fin, rsv1, rsv2, rsv3, opcode, payload = parser.read_inner_frame()
</span><ins>+            consuming_byte = len(payload)
+            if opcode != common.OPCODE_CONTINUATION:
+                consuming_byte += 1
</ins><span class="cx">             if not channel_data.request.ws_stream.consume_receive_quota(
</span><del>-                len(payload)):
</del><ins>+                consuming_byte):
</ins><span class="cx">                 # The client violates quota. Close logical channel.
</span><span class="cx">                 raise LogicalChannelError(
</span><span class="cx">                     channel_id, _DROP_CODE_SEND_QUOTA_VIOLATION)
</span><span class="lines">@@ -1569,17 +1803,34 @@
</span><span class="cx">         finished.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        # Terminate all logical connections
-        self._logger.debug('termiating all logical connections...')
</del><ins>+        self._logger.debug(
+            'Termiating all logical connections waiting for incoming data '
+            '...')
</ins><span class="cx">         self._logical_channels_condition.acquire()
</span><span class="cx">         for channel_data in self._logical_channels.values():
</span><span class="cx">             try:
</span><span class="cx">                 channel_data.request.connection.set_read_state(
</span><span class="cx">                     _LogicalConnection.STATE_TERMINATED)
</span><span class="cx">             except Exception:
</span><del>-                pass
</del><ins>+                self._logger.debug(traceback.format_exc())
</ins><span class="cx">         self._logical_channels_condition.release()
</span><span class="cx"> 
</span><ins>+    def notify_writer_done(self):
+        &quot;&quot;&quot;This method is called by the writer thread when the writer has
+        finished.
+        &quot;&quot;&quot;
+
+        self._logger.debug(
+            'Termiating all logical connections waiting for write '
+            'completion ...')
+        self._logical_channels_condition.acquire()
+        for channel_data in self._logical_channels.values():
+            try:
+                channel_data.request.connection.on_writer_done()
+            except Exception:
+                self._logger.debug(traceback.format_exc())
+        self._logical_channels_condition.release()
+
</ins><span class="cx">     def fail_physical_connection(self, code, message):
</span><span class="cx">         &quot;&quot;&quot;Fail the physical connection.
</span><span class="cx"> 
</span><span class="lines">@@ -1590,8 +1841,7 @@
</span><span class="cx"> 
</span><span class="cx">         self._logger.debug('Failing the physical connection...')
</span><span class="cx">         self._send_drop_channel(_CONTROL_CHANNEL_ID, code, message)
</span><del>-        self.physical_stream.close_connection(
-            common.STATUS_INTERNAL_ENDPOINT_ERROR)
</del><ins>+        self._writer.stop(common.STATUS_INTERNAL_ENDPOINT_ERROR)
</ins><span class="cx"> 
</span><span class="cx">     def fail_logical_channel(self, channel_id, code, message):
</span><span class="cx">         &quot;&quot;&quot;Fail a logical channel.
</span><span class="lines">@@ -1611,8 +1861,10 @@
</span><span class="cx">                 # called later and it will send DropChannel.
</span><span class="cx">                 channel_data.drop_code = code
</span><span class="cx">                 channel_data.drop_message = message
</span><ins>+
</ins><span class="cx">                 channel_data.request.connection.set_read_state(
</span><span class="cx">                     _LogicalConnection.STATE_TERMINATED)
</span><ins>+                channel_data.request.ws_stream.stop_sending()
</ins><span class="cx">             else:
</span><span class="cx">                 self._send_drop_channel(channel_id, code, message)
</span><span class="cx">         finally:
</span><span class="lines">@@ -1620,7 +1872,8 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> def use_mux(request):
</span><del>-    return hasattr(request, 'mux') and request.mux
</del><ins>+    return hasattr(request, 'mux_processor') and (
+        request.mux_processor.is_active())
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> def start(request, dispatcher):
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsocketstandalonepy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -76,7 +76,10 @@
</span><span class="cx"> 
</span><span class="cx"> To support TLS, run standalone.py with -t, -k, and -c options.
</span><span class="cx"> 
</span><ins>+Note that when ssl module is used and the key/cert location is incorrect,
+TLS connection silently fails while pyOpenSSL fails on startup.
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx"> SUPPORTING CLIENT AUTHENTICATION
</span><span class="cx"> 
</span><span class="cx"> To support client authentication with TLS, run standalone.py with -t, -k, -c,
</span><span class="lines">@@ -140,18 +143,6 @@
</span><span class="cx"> import threading
</span><span class="cx"> import time
</span><span class="cx"> 
</span><del>-_HAS_SSL = False
-_HAS_OPEN_SSL = False
-try:
-    import ssl
-    _HAS_SSL = True
-except ImportError:
-    try:
-        import OpenSSL.SSL
-        _HAS_OPEN_SSL = True
-    except ImportError:
-        pass
-
</del><span class="cx"> from mod_pywebsocket import common
</span><span class="cx"> from mod_pywebsocket import dispatch
</span><span class="cx"> from mod_pywebsocket import handshake
</span><span class="lines">@@ -168,7 +159,11 @@
</span><span class="cx"> # 1024 is practically large enough to contain WebSocket handshake lines.
</span><span class="cx"> _MAX_MEMORIZED_LINES = 1024
</span><span class="cx"> 
</span><ins>+# Constants for the --tls_module flag.
+_TLS_BY_STANDARD_MODULE = 'ssl'
+_TLS_BY_PYOPENSSL = 'pyopenssl'
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class _StandaloneConnection(object):
</span><span class="cx">     &quot;&quot;&quot;Mimic mod_python mp_conn.&quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -231,11 +226,23 @@
</span><span class="cx">         self.headers_in = request_handler.headers
</span><span class="cx"> 
</span><span class="cx">     def get_uri(self):
</span><del>-        &quot;&quot;&quot;Getter to mimic request.uri.&quot;&quot;&quot;
</del><ins>+        &quot;&quot;&quot;Getter to mimic request.uri.
</ins><span class="cx"> 
</span><ins>+        This method returns the raw data at the Request-URI part of the
+        Request-Line, while the uri method on the request object of mod_python
+        returns the path portion after parsing the raw data. This behavior is
+        kept for compatibility.
+        &quot;&quot;&quot;
+
</ins><span class="cx">         return self._request_handler.path
</span><span class="cx">     uri = property(get_uri)
</span><span class="cx"> 
</span><ins>+    def get_unparsed_uri(self):
+        &quot;&quot;&quot;Getter to mimic request.unparsed_uri.&quot;&quot;&quot;
+
+        return self._request_handler.path
+    unparsed_uri = property(get_unparsed_uri)
+
</ins><span class="cx">     def get_method(self):
</span><span class="cx">         &quot;&quot;&quot;Getter to mimic request.method.&quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -253,41 +260,70 @@
</span><span class="cx"> 
</span><span class="cx">         return self._use_tls
</span><span class="cx"> 
</span><del>-    def _drain_received_data(self):
-        &quot;&quot;&quot;Don't use this method from WebSocket handler. Drains unread data
-        in the receive buffer.
-        &quot;&quot;&quot;
</del><span class="cx"> 
</span><del>-        raw_socket = self._request_handler.connection
-        drained_data = util.drain_received_data(raw_socket)
</del><ins>+def _import_ssl():
+    global ssl
+    try:
+        import ssl
+        return True
+    except ImportError:
+        return False
</ins><span class="cx"> 
</span><del>-        if drained_data:
-            self._logger.debug(
-                'Drained data following close frame: %r', drained_data)
</del><span class="cx"> 
</span><ins>+def _import_pyopenssl():
+    global OpenSSL
+    try:
+        import OpenSSL.SSL
+        return True
+    except ImportError:
+        return False
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class _StandaloneSSLConnection(object):
</span><del>-    &quot;&quot;&quot;A wrapper class for OpenSSL.SSL.Connection to provide makefile method
-    which is not supported by the class.
</del><ins>+    &quot;&quot;&quot;A wrapper class for OpenSSL.SSL.Connection to
+    - provide makefile method which is not supported by the class
+    - tweak shutdown method since OpenSSL.SSL.Connection.shutdown doesn't
+      accept the &quot;how&quot; argument.
+    - convert SysCallError exceptions that its recv method may raise into a
+      return value of '', meaning EOF. We cannot overwrite the recv method on
+      self._connection since it's immutable.
</ins><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><ins>+    _OVERRIDDEN_ATTRIBUTES = ['_connection', 'makefile', 'shutdown', 'recv']
+
</ins><span class="cx">     def __init__(self, connection):
</span><span class="cx">         self._connection = connection
</span><span class="cx"> 
</span><span class="cx">     def __getattribute__(self, name):
</span><del>-        if name in ('_connection', 'makefile'):
</del><ins>+        if name in _StandaloneSSLConnection._OVERRIDDEN_ATTRIBUTES:
</ins><span class="cx">             return object.__getattribute__(self, name)
</span><span class="cx">         return self._connection.__getattribute__(name)
</span><span class="cx"> 
</span><span class="cx">     def __setattr__(self, name, value):
</span><del>-        if name in ('_connection', 'makefile'):
</del><ins>+        if name in _StandaloneSSLConnection._OVERRIDDEN_ATTRIBUTES:
</ins><span class="cx">             return object.__setattr__(self, name, value)
</span><span class="cx">         return self._connection.__setattr__(name, value)
</span><span class="cx"> 
</span><span class="cx">     def makefile(self, mode='r', bufsize=-1):
</span><del>-        return socket._fileobject(self._connection, mode, bufsize)
</del><ins>+        return socket._fileobject(self, mode, bufsize)
</ins><span class="cx"> 
</span><ins>+    def shutdown(self, unused_how):
+        self._connection.shutdown()
</ins><span class="cx"> 
</span><ins>+    def recv(self, bufsize, flags=0):
+        if flags != 0:
+            raise ValueError('Non-zero flags not allowed')
+
+        try:
+            return self._connection.recv(bufsize)
+        except OpenSSL.SSL.SysCallError, (err, message):
+            if err == -1:
+                # Suppress &quot;unexpected EOF&quot; exception. See the OpenSSL document
+                # for SSL_get_error.
+                return ''
+            raise
+
+
</ins><span class="cx"> def _alias_handlers(dispatcher, websock_handlers_map_file):
</span><span class="cx">     &quot;&quot;&quot;Set aliases specified in websock_handler_map_file in dispatcher.
</span><span class="cx"> 
</span><span class="lines">@@ -340,7 +376,7 @@
</span><span class="cx">         warnings = options.dispatcher.source_warnings()
</span><span class="cx">         if warnings:
</span><span class="cx">             for warning in warnings:
</span><del>-                logging.warning('mod_pywebsocket: %s' % warning)
</del><ins>+                logging.warning('Warning in source loading: %s' % warning)
</ins><span class="cx"> 
</span><span class="cx">         self._logger = util.get_class_logger(self)
</span><span class="cx"> 
</span><span class="lines">@@ -387,25 +423,25 @@
</span><span class="cx">             except Exception, e:
</span><span class="cx">                 self._logger.info('Skip by failure: %r', e)
</span><span class="cx">                 continue
</span><del>-            if self.websocket_server_options.use_tls:
-                if _HAS_SSL:
-                    if self.websocket_server_options.tls_client_auth:
-                        client_cert_ = ssl.CERT_REQUIRED
</del><ins>+            server_options = self.websocket_server_options
+            if server_options.use_tls:
+                # For the case of _HAS_OPEN_SSL, we do wrapper setup after
+                # accept.
+                if server_options.tls_module == _TLS_BY_STANDARD_MODULE:
+                    if server_options.tls_client_auth:
+                        if server_options.tls_client_cert_optional:
+                            client_cert_ = ssl.CERT_OPTIONAL
+                        else:
+                            client_cert_ = ssl.CERT_REQUIRED
</ins><span class="cx">                     else:
</span><span class="cx">                         client_cert_ = ssl.CERT_NONE
</span><span class="cx">                     socket_ = ssl.wrap_socket(socket_,
</span><del>-                        keyfile=self.websocket_server_options.private_key,
-                        certfile=self.websocket_server_options.certificate,
</del><ins>+                        keyfile=server_options.private_key,
+                        certfile=server_options.certificate,
</ins><span class="cx">                         ssl_version=ssl.PROTOCOL_SSLv23,
</span><del>-                        ca_certs=self.websocket_server_options.tls_client_ca,
-                        cert_reqs=client_cert_)
-                if _HAS_OPEN_SSL:
-                    ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
-                    ctx.use_privatekey_file(
-                        self.websocket_server_options.private_key)
-                    ctx.use_certificate_file(
-                        self.websocket_server_options.certificate)
-                    socket_ = OpenSSL.SSL.Connection(ctx, socket_)
</del><ins>+                        ca_certs=server_options.tls_client_ca,
+                        cert_reqs=client_cert_,
+                        do_handshake_on_connect=False)
</ins><span class="cx">             self._sockets.append((socket_, addrinfo))
</span><span class="cx"> 
</span><span class="cx">     def server_bind(self):
</span><span class="lines">@@ -479,7 +515,7 @@
</span><span class="cx">         self._logger.critical('Not supported: fileno')
</span><span class="cx">         return self._sockets[0][0].fileno()
</span><span class="cx"> 
</span><del>-    def handle_error(self, rquest, client_address):
</del><ins>+    def handle_error(self, request, client_address):
</ins><span class="cx">         &quot;&quot;&quot;Override SocketServer.handle_error.&quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         self._logger.error(
</span><span class="lines">@@ -496,8 +532,63 @@
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><span class="cx">         accepted_socket, client_address = self.socket.accept()
</span><del>-        if self.websocket_server_options.use_tls and _HAS_OPEN_SSL:
-            accepted_socket = _StandaloneSSLConnection(accepted_socket)
</del><ins>+
+        server_options = self.websocket_server_options
+        if server_options.use_tls:
+            if server_options.tls_module == _TLS_BY_STANDARD_MODULE:
+                try:
+                    accepted_socket.do_handshake()
+                except ssl.SSLError, e:
+                    self._logger.debug('%r', e)
+                    raise
+
+                # Print cipher in use. Handshake is done on accept.
+                self._logger.debug('Cipher: %s', accepted_socket.cipher())
+                self._logger.debug('Client cert: %r',
+                                   accepted_socket.getpeercert())
+            elif server_options.tls_module == _TLS_BY_PYOPENSSL:
+                # We cannot print the cipher in use. pyOpenSSL doesn't provide
+                # any method to fetch that.
+
+                ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
+                ctx.use_privatekey_file(server_options.private_key)
+                ctx.use_certificate_file(server_options.certificate)
+
+                def default_callback(conn, cert, errnum, errdepth, ok):
+                    return ok == 1
+
+                # See the OpenSSL document for SSL_CTX_set_verify.
+                if server_options.tls_client_auth:
+                    verify_mode = OpenSSL.SSL.VERIFY_PEER
+                    if not server_options.tls_client_cert_optional:
+                        verify_mode |= OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT
+                    ctx.set_verify(verify_mode, default_callback)
+                    ctx.load_verify_locations(server_options.tls_client_ca,
+                                              None)
+                else:
+                    ctx.set_verify(OpenSSL.SSL.VERIFY_NONE, default_callback)
+
+                accepted_socket = OpenSSL.SSL.Connection(ctx, accepted_socket)
+                accepted_socket.set_accept_state()
+
+                # Convert SSL related error into socket.error so that
+                # SocketServer ignores them and keeps running.
+                #
+                # TODO(tyoshino): Convert all kinds of errors.
+                try:
+                    accepted_socket.do_handshake()
+                except OpenSSL.SSL.Error, e:
+                    # Set errno part to 1 (SSL_ERROR_SSL) like the ssl module
+                    # does.
+                    self._logger.debug('%r', e)
+                    raise socket.error(1, '%r' % e)
+                cert = accepted_socket.get_peer_certificate()
+                self._logger.debug('Client cert subject: %r',
+                                   cert.get_subject().get_components())
+                accepted_socket = _StandaloneSSLConnection(accepted_socket)
+            else:
+                raise ValueError('No TLS support module is available')
+
</ins><span class="cx">         return accepted_socket, client_address
</span><span class="cx"> 
</span><span class="cx">     def serve_forever(self, poll_interval=0.5):
</span><span class="lines">@@ -636,7 +727,7 @@
</span><span class="cx">                 self._logger.info('Fallback to CGIHTTPRequestHandler')
</span><span class="cx">                 return True
</span><span class="cx">         except dispatch.DispatchException, e:
</span><del>-            self._logger.info('%s', e)
</del><ins>+            self._logger.info('Dispatch failed for error: %s', e)
</ins><span class="cx">             self.send_error(e.status)
</span><span class="cx">             return False
</span><span class="cx"> 
</span><span class="lines">@@ -652,7 +743,7 @@
</span><span class="cx">                     allowDraft75=self._options.allow_draft75,
</span><span class="cx">                     strict=self._options.strict)
</span><span class="cx">             except handshake.VersionException, e:
</span><del>-                self._logger.info('%s', e)
</del><ins>+                self._logger.info('Handshake failed for version error: %s', e)
</ins><span class="cx">                 self.send_response(common.HTTP_STATUS_BAD_REQUEST)
</span><span class="cx">                 self.send_header(common.SEC_WEBSOCKET_VERSION_HEADER,
</span><span class="cx">                                  e.supported_versions)
</span><span class="lines">@@ -660,14 +751,14 @@
</span><span class="cx">                 return False
</span><span class="cx">             except handshake.HandshakeException, e:
</span><span class="cx">                 # Handshake for ws(s) failed.
</span><del>-                self._logger.info('%s', e)
</del><ins>+                self._logger.info('Handshake failed for error: %s', e)
</ins><span class="cx">                 self.send_error(e.status)
</span><span class="cx">                 return False
</span><span class="cx"> 
</span><span class="cx">             request._dispatcher = self._options.dispatcher
</span><span class="cx">             self._options.dispatcher.transfer_data(request)
</span><span class="cx">         except handshake.AbortedByUserException, e:
</span><del>-            self._logger.info('%s', e)
</del><ins>+            self._logger.info('Aborted: %s', e)
</ins><span class="cx">         return False
</span><span class="cx"> 
</span><span class="cx">     def log_request(self, code='-', size='-'):
</span><span class="lines">@@ -799,6 +890,12 @@
</span><span class="cx">                             'as CGI programs. Must be executable.'))
</span><span class="cx">     parser.add_option('-t', '--tls', dest='use_tls', action='store_true',
</span><span class="cx">                       default=False, help='use TLS (wss://)')
</span><ins>+    parser.add_option('--tls-module', '--tls_module', dest='tls_module',
+                      type='choice',
+                      choices = [_TLS_BY_STANDARD_MODULE, _TLS_BY_PYOPENSSL],
+                      help='Use ssl module if &quot;%s&quot; is specified. '
+                      'Use pyOpenSSL module if &quot;%s&quot; is specified' %
+                      (_TLS_BY_STANDARD_MODULE, _TLS_BY_PYOPENSSL))
</ins><span class="cx">     parser.add_option('-k', '--private-key', '--private_key',
</span><span class="cx">                       dest='private_key',
</span><span class="cx">                       default='', help='TLS private key file.')
</span><span class="lines">@@ -806,7 +903,12 @@
</span><span class="cx">                       default='', help='TLS certificate file.')
</span><span class="cx">     parser.add_option('--tls-client-auth', dest='tls_client_auth',
</span><span class="cx">                       action='store_true', default=False,
</span><del>-                      help='Requires TLS client auth on every connection.')
</del><ins>+                      help='Requests TLS client auth on every connection.')
+    parser.add_option('--tls-client-cert-optional',
+                      dest='tls_client_cert_optional',
+                      action='store_true', default=False,
+                      help=('Makes client certificate optional even though '
+                            'TLS client auth is enabled.'))
</ins><span class="cx">     parser.add_option('--tls-client-ca', dest='tls_client_ca', default='',
</span><span class="cx">                       help=('Specifies a pem file which contains a set of '
</span><span class="cx">                             'concatenated CA certificates which are used to '
</span><span class="lines">@@ -933,6 +1035,12 @@
</span><span class="cx"> 
</span><span class="cx">     _configure_logging(options)
</span><span class="cx"> 
</span><ins>+    if options.allow_draft75:
+        logging.warning('--allow_draft75 option is obsolete.')
+
+    if options.strict:
+        logging.warning('--strict option is obsolete.')
+
</ins><span class="cx">     # TODO(tyoshino): Clean up initialization of CGI related values. Move some
</span><span class="cx">     # of code here to WebSocketRequestHandler class if it's better.
</span><span class="cx">     options.cgi_directories = []
</span><span class="lines">@@ -955,21 +1063,54 @@
</span><span class="cx">             options.is_executable_method = __check_script
</span><span class="cx"> 
</span><span class="cx">     if options.use_tls:
</span><del>-        if not (_HAS_SSL or _HAS_OPEN_SSL):
-            logging.critical('TLS support requires ssl or pyOpenSSL module.')
</del><ins>+        if options.tls_module is None:
+            if _import_ssl():
+                options.tls_module = _TLS_BY_STANDARD_MODULE
+                logging.debug('Using ssl module')
+            elif _import_pyopenssl():
+                options.tls_module = _TLS_BY_PYOPENSSL
+                logging.debug('Using pyOpenSSL module')
+            else:
+                logging.critical(
+                        'TLS support requires ssl or pyOpenSSL module.')
+                sys.exit(1)
+        elif options.tls_module == _TLS_BY_STANDARD_MODULE:
+            if not _import_ssl():
+                logging.critical('ssl module is not available')
+                sys.exit(1)
+        elif options.tls_module == _TLS_BY_PYOPENSSL:
+            if not _import_pyopenssl():
+                logging.critical('pyOpenSSL module is not available')
+                sys.exit(1)
+        else:
+            logging.critical('Invalid --tls-module option: %r',
+                             options.tls_module)
</ins><span class="cx">             sys.exit(1)
</span><ins>+
</ins><span class="cx">         if not options.private_key or not options.certificate:
</span><span class="cx">             logging.critical(
</span><span class="cx">                     'To use TLS, specify private_key and certificate.')
</span><span class="cx">             sys.exit(1)
</span><span class="cx"> 
</span><del>-    if options.tls_client_auth:
-        if not options.use_tls:
</del><ins>+        if (options.tls_client_cert_optional and
+            not options.tls_client_auth):
+            logging.critical('Client authentication must be enabled to '
+                             'specify tls_client_cert_optional')
+            sys.exit(1)
+    else:
+        if options.tls_module is not None:
+            logging.critical('Use --tls-module option only together with '
+                             '--use-tls option.')
+            sys.exit(1)
+
+        if options.tls_client_auth:
</ins><span class="cx">             logging.critical('TLS must be enabled for client authentication.')
</span><span class="cx">             sys.exit(1)
</span><del>-        if not _HAS_SSL:
-            logging.critical('Client authentication requires ssl module.')
</del><span class="cx"> 
</span><ins>+        if options.tls_client_cert_optional:
+            logging.critical('TLS must be enabled for client authentication.')
+            sys.exit(1)
+
</ins><span class="cx">     if not options.scan_dir:
</span><span class="cx">         options.scan_dir = options.websock_handlers
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsScriptswebkitpythirdpartymod_pywebsocketutilpy"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py (150224 => 150225)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py        2013-05-17 00:30:52 UTC (rev 150224)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py        2013-05-17 00:33:55 UTC (rev 150225)
</span><span class="lines">@@ -56,7 +56,12 @@
</span><span class="cx"> import traceback
</span><span class="cx"> import zlib
</span><span class="cx"> 
</span><ins>+try:
+    from mod_pywebsocket import fast_masking
+except ImportError:
+    pass
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx"> def get_stack_trace():
</span><span class="cx">     &quot;&quot;&quot;Get the current stack trace as string.
</span><span class="cx"> 
</span><span class="lines">@@ -169,47 +174,41 @@
</span><span class="cx">     ended and resumes from that point on the next mask method call.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    def __init__(self, mask):
-        self._mask = map(ord, mask)
-        self._mask_size = len(self._mask)
-        self._count = 0
</del><ins>+    def __init__(self, masking_key):
+        self._masking_key = masking_key
+        self._masking_key_index = 0
</ins><span class="cx"> 
</span><del>-    def mask(self, s):
</del><ins>+    def _mask_using_swig(self, s):
+        masked_data = fast_masking.mask(
+                s, self._masking_key, self._masking_key_index)
+        self._masking_key_index = (
+                (self._masking_key_index + len(s)) % len(self._masking_key))
+        return masked_data
+
+    def _mask_using_array(self, s):
</ins><span class="cx">         result = array.array('B')
</span><span class="cx">         result.fromstring(s)
</span><ins>+
</ins><span class="cx">         # Use temporary local variables to eliminate the cost to access
</span><span class="cx">         # attributes
</span><del>-        count = self._count
-        mask = self._mask
-        mask_size = self._mask_size
</del><ins>+        masking_key = map(ord, self._masking_key)
+        masking_key_size = len(masking_key)
+        masking_key_index = self._masking_key_index
+
</ins><span class="cx">         for i in xrange(len(result)):
</span><del>-            result[i] ^= mask[count]
-            count = (count + 1) % mask_size
-        self._count = count
</del><ins>+            result[i] ^= masking_key[masking_key_index]
+            masking_key_index = (masking_key_index + 1) % masking_key_size
</ins><span class="cx"> 
</span><ins>+        self._masking_key_index = masking_key_index
+
</ins><span class="cx">         return result.tostring()
</span><span class="cx"> 
</span><ins>+    if 'fast_masking' in globals():
+        mask = _mask_using_swig
+    else:
+        mask = _mask_using_array
</ins><span class="cx"> 
</span><del>-class DeflateRequest(object):
-    &quot;&quot;&quot;A wrapper class for request object to intercept send and recv to perform
-    deflate compression and decompression transparently.
-    &quot;&quot;&quot;
</del><span class="cx"> 
</span><del>-    def __init__(self, request):
-        self._request = request
-        self.connection = DeflateConnection(request.connection)
-
-    def __getattribute__(self, name):
-        if name in ('_request', 'connection'):
-            return object.__getattribute__(self, name)
-        return self._request.__getattribute__(name)
-
-    def __setattr__(self, name, value):
-        if name in ('_request', 'connection'):
-            return object.__setattr__(self, name, value)
-        return self._request.__setattr__(name, value)
-
-
</del><span class="cx"> # By making wbits option negative, we can suppress CMF/FLG (2 octet) and
</span><span class="cx"> # ADLER32 (4 octet) fields of zlib so that we can use zlib module just as
</span><span class="cx"> # deflate library. DICTID won't be added as far as we don't set dictionary.
</span><span class="lines">@@ -252,6 +251,7 @@
</span><span class="cx">         self._logger.debug('Compress result %r', compressed_bytes)
</span><span class="cx">         return compressed_bytes
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class _Inflater(object):
</span><span class="cx"> 
</span><span class="cx">     def __init__(self):
</span><span class="lines">@@ -346,6 +346,7 @@
</span><span class="cx">             return self._deflater.compress_and_flush(bytes)[:-4]
</span><span class="cx">         return self._deflater.compress(bytes)
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> class _RFC1979Inflater(object):
</span><span class="cx">     &quot;&quot;&quot;A decompressor class for byte sequence compressed and flushed following
</span><span class="cx">     the algorithm described in the RFC1979 section 2.1.
</span><span class="lines">@@ -405,111 +406,4 @@
</span><span class="cx">         return len(bytes)
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-class DeflateConnection(object):
-    &quot;&quot;&quot;A wrapper class for request object to intercept write and read to
-    perform deflate compression and decompression transparently.
-    &quot;&quot;&quot;
-
-    def __init__(self, connection):
-        self._connection = connection
-
-        self._logger = get_class_logger(self)
-
-        self._deflater = _Deflater(zlib.MAX_WBITS)
-        self._inflater = _Inflater()
-
-    def get_remote_addr(self):
-        return self._connection.remote_addr
-    remote_addr = property(get_remote_addr)
-
-    def put_bytes(self, bytes):
-        self.write(bytes)
-
-    def read(self, size=-1):
-        &quot;&quot;&quot;Reads at most size bytes. Blocks until there's at least one byte
-        available.
-        &quot;&quot;&quot;
-
-        # TODO(tyoshino): Allow call with size=0.
-        if not (size == -1 or size &gt; 0):
-            raise Exception('size must be -1 or positive')
-
-        data = ''
-        while True:
-            if size == -1:
-                data += self._inflater.decompress(-1)
-            else:
-                data += self._inflater.decompress(size - len(data))
-
-            if size &gt;= 0 and len(data) != 0:
-                break
-
-            # TODO(tyoshino): Make this read efficient by some workaround.
-            #
-            # In 3.0.3 and prior of mod_python, read blocks until length bytes
-            # was read. We don't know the exact size to read while using
-            # deflate, so read byte-by-byte.
-            #
-            # _StandaloneRequest.read that ultimately performs
-            # socket._fileobject.read also blocks until length bytes was read
-            read_data = self._connection.read(1)
-            if not read_data:
-                break
-            self._inflater.append(read_data)
-        return data
-
-    def write(self, bytes):
-        self._connection.write(self._deflater.compress_and_flush(bytes))
-
-
-def _is_ewouldblock_errno(error_number):
-    &quot;&quot;&quot;Returns True iff error_number indicates that receive operation would
-    block. To make this portable, we check availability of errno and then
-    compare them.
-    &quot;&quot;&quot;
-
-    for error_name in ['WSAEWOULDBLOCK', 'EWOULDBLOCK', 'EAGAIN']:
-        if (error_name in dir(errno) and
-            error_number == getattr(errno, error_name)):
-            return True
-    return False
-
-
-def drain_received_data(raw_socket):
-    # Set the socket non-blocking.
-    original_timeout = raw_socket.gettimeout()
-    raw_socket.settimeout(0.0)
-
-    drained_data = []
-
-    # Drain until the socket is closed or no data is immediately
-    # available for read.
-    while True:
-        try:
-            data = raw_socket.recv(1)
-            if not data:
-                break
-            drained_data.append(data)
-        except socket.error, e:
-            # e can be either a pair (errno, string) or just a string (or
-            # something else) telling what went wrong. We suppress only
-            # the errors that indicates that the socket blocks. Those
-            # exceptions can be parsed as a pair (errno, string).
-            try:
-                error_number, message = e
-            except:
-                # Failed to parse socket.error.
-                raise e
-
-            if _is_ewouldblock_errno(error_number):
-                break
-            else:
-                raise e
-
-    # Rollback timeout value.
-    raw_socket.settimeout(original_timeout)
-
-    return ''.join(drained_data)
-
-
</del><span class="cx"> # vi:sts=4 sw=4 et
</span></span></pre>
</div>
</div>

</body>
</html>