Title: [120315] trunk/Tools
Revision
120315
Author
[email protected]
Date
2012-06-14 05:40:32 -0700 (Thu, 14 Jun 2012)

Log Message

Update pywebsocket to 0.7.6 from 0.7.4
https://bugs.webkit.org/show_bug.cgi?id=88975

Reviewed by Kent Tamura.

This new version of pywebsocket introduce following features.
 - Allow handlers to send a close frame with empty body in response of
     a client initiated closing handshake
 - Implement perframe compression extension
 - Support client certificate authentication

* Scripts/webkitpy/thirdparty/mod_pywebsocket/COPYING:
* Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py:
(_create_control_frame):
(Stream._receive_frame):
(Stream.send_message):
(Stream.receive_message):
(Stream._send_closing_handshake):
(Stream.close_connection):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py:
(ExtensionParsingException):
(ExtensionParsingException.__init__):
(_parse_extension_param):
(_parse_extension):
(parse_extensions):
(format_extension):
(format_extensions):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py:
(_parse_compression_method):
(_create_accepted_method_desc):
(PerFrameCompressionExtensionProcessor):
(PerFrameCompressionExtensionProcessor.__init__):
(PerFrameCompressionExtensionProcessor._lookup_compression_processor):
(PerFrameCompressionExtensionProcessor._get_compression_processor_response):
(PerFrameCompressionExtensionProcessor.get_extension_response):
(PerFrameCompressionExtensionProcessor.setup_stream_options):
(PerFrameCompressionExtensionProcessor.get_compression_processor):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py:
(parse_token_list):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py:
(Handshaker._parse_extensions):
(Handshaker._send_handshake):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py:
(WebSocketServer._create_sockets):
(_get_logger_from_class):
(_configure_logging):
(_build_option_parser):
(_main.if):
* Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py:
(RepeatedXorMasker.mask):

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (120314 => 120315)


--- trunk/Tools/ChangeLog	2012-06-14 12:18:15 UTC (rev 120314)
+++ trunk/Tools/ChangeLog	2012-06-14 12:40:32 UTC (rev 120315)
@@ -1,3 +1,56 @@
+2012-06-14  Takashi Toyoshima  <[email protected]>
+
+        Update pywebsocket to 0.7.6 from 0.7.4
+        https://bugs.webkit.org/show_bug.cgi?id=88975
+
+        Reviewed by Kent Tamura.
+
+        This new version of pywebsocket introduce following features.
+         - Allow handlers to send a close frame with empty body in response of
+             a client initiated closing handshake
+         - Implement perframe compression extension
+         - Support client certificate authentication
+
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/COPYING:
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py:
+        (_create_control_frame):
+        (Stream._receive_frame):
+        (Stream.send_message):
+        (Stream.receive_message):
+        (Stream._send_closing_handshake):
+        (Stream.close_connection):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py:
+        (ExtensionParsingException):
+        (ExtensionParsingException.__init__):
+        (_parse_extension_param):
+        (_parse_extension):
+        (parse_extensions):
+        (format_extension):
+        (format_extensions):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py:
+        (_parse_compression_method):
+        (_create_accepted_method_desc):
+        (PerFrameCompressionExtensionProcessor):
+        (PerFrameCompressionExtensionProcessor.__init__):
+        (PerFrameCompressionExtensionProcessor._lookup_compression_processor):
+        (PerFrameCompressionExtensionProcessor._get_compression_processor_response):
+        (PerFrameCompressionExtensionProcessor.get_extension_response):
+        (PerFrameCompressionExtensionProcessor.setup_stream_options):
+        (PerFrameCompressionExtensionProcessor.get_compression_processor):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py:
+        (parse_token_list):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py:
+        (Handshaker._parse_extensions):
+        (Handshaker._send_handshake):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py:
+        (WebSocketServer._create_sockets):
+        (_get_logger_from_class):
+        (_configure_logging):
+        (_build_option_parser):
+        (_main.if):
+        * Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py:
+        (RepeatedXorMasker.mask):
+
 2012-06-14  Zoltan Horvath  <[email protected]>
 
         [Qt] Remove USE(QT_IMAGE_DECODER) macro, since we don't use it anymore

Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/COPYING (120314 => 120315)


--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/COPYING	2012-06-14 12:18:15 UTC (rev 120314)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/COPYING	2012-06-14 12:40:32 UTC (rev 120315)
@@ -1,4 +1,4 @@
-Copyright 2009, Google Inc.
+Copyright 2012, Google Inc.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without

Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py (120314 => 120315)


--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py	2012-06-14 12:18:15 UTC (rev 120314)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/_stream_hybi.py	2012-06-14 12:40:32 UTC (rev 120315)
@@ -39,6 +39,7 @@
 from collections import deque
 import os
 import struct
+import time
 
 from mod_pywebsocket import common
 from mod_pywebsocket import util
@@ -208,9 +209,19 @@
 def _create_control_frame(opcode, body, mask, frame_filters):
     frame = Frame(opcode=opcode, payload=body)
 
-    return _filter_and_format_frame_object(frame, mask, frame_filters)
+    for frame_filter in frame_filters:
+        frame_filter.filter(frame)
 
+    if len(frame.payload) > 125:
+        raise BadOperationException(
+            'Payload data size of control frames must be 125 bytes or less')
 
+    header = create_header(
+        frame.opcode, len(frame.payload), frame.fin,
+        frame.rsv1, frame.rsv2, frame.rsv3, mask)
+    return _build_frame(header, frame.payload, mask)
+
+
 def create_ping_frame(body, mask=False, frame_filters=[]):
     return _create_control_frame(common.OPCODE_PING, body, mask, frame_filters)
 
@@ -286,6 +297,9 @@
             InvalidFrameException: when the frame contains invalid data.
         """
 
+        self._logger.log(common.LOGLEVEL_FINE,
+                         'Receive the first 2 octets of a frame')
+
         received = self.receive_bytes(2)
 
         first_byte = ord(received[0])
@@ -299,6 +313,11 @@
         mask = (second_byte >> 7) & 1
         payload_length = second_byte & 0x7f
 
+        self._logger.log(common.LOGLEVEL_FINE,
+                         'FIN=%s, RSV1=%s, RSV2=%s, RSV3=%s, opcode=%s, '
+                         'Mask=%s, Payload_length=%s',
+                         fin, rsv1, rsv2, rsv3, opcode, mask, payload_length)
+
         if (mask == 1) != self._options.unmask_receive:
             raise InvalidFrameException(
                 'Mask bit on the received frame did\'nt match masking '
@@ -310,6 +329,9 @@
         valid_length_encoding = True
         length_encoding_bytes = 1
         if payload_length == 127:
+            self._logger.log(common.LOGLEVEL_FINE,
+                             'Receive 8-octet extended payload length')
+
             extended_payload_length = self.receive_bytes(8)
             payload_length = struct.unpack(
                 '!Q', extended_payload_length)[0]
@@ -319,7 +341,13 @@
             if self._request.ws_version >= 13 and payload_length < 0x10000:
                 valid_length_encoding = False
                 length_encoding_bytes = 8
+
+            self._logger.log(common.LOGLEVEL_FINE,
+                             'Decoded_payload_length=%s', payload_length)
         elif payload_length == 126:
+            self._logger.log(common.LOGLEVEL_FINE,
+                             'Receive 2-octet extended payload length')
+
             extended_payload_length = self.receive_bytes(2)
             payload_length = struct.unpack(
                 '!H', extended_payload_length)[0]
@@ -327,6 +355,9 @@
                 valid_length_encoding = False
                 length_encoding_bytes = 2
 
+            self._logger.log(common.LOGLEVEL_FINE,
+                             'Decoded_payload_length=%s', payload_length)
+
         if not valid_length_encoding:
             self._logger.warning(
                 'Payload length is not encoded using the minimal number of '
@@ -335,13 +366,39 @@
                 length_encoding_bytes)
 
         if mask == 1:
+            self._logger.log(common.LOGLEVEL_FINE, 'Receive mask')
+
             masking_nonce = self.receive_bytes(4)
             masker = util.RepeatedXorMasker(masking_nonce)
+
+            self._logger.log(common.LOGLEVEL_FINE, 'Mask=%r', masking_nonce)
         else:
             masker = _NOOP_MASKER
 
-        bytes = masker.mask(self.receive_bytes(payload_length))
+        self._logger.log(common.LOGLEVEL_FINE, 'Receive payload data')
+        if self._logger.isEnabledFor(common.LOGLEVEL_FINE):
+            receive_start = time.time()
 
+        raw_payload_bytes = self.receive_bytes(payload_length)
+
+        if self._logger.isEnabledFor(common.LOGLEVEL_FINE):
+            self._logger.log(
+                common.LOGLEVEL_FINE,
+                'Done receiving payload data at %s MB/s',
+                payload_length / (time.time() - receive_start) / 1000 / 1000)
+        self._logger.log(common.LOGLEVEL_FINE, 'Unmask payload data')
+
+        if self._logger.isEnabledFor(common.LOGLEVEL_FINE):
+            unmask_start = time.time()
+
+        bytes = masker.mask(raw_payload_bytes)
+
+        if self._logger.isEnabledFor(common.LOGLEVEL_FINE):
+            self._logger.log(
+                common.LOGLEVEL_FINE,
+                'Done unmasking payload data at %s MB/s',
+                payload_length / (time.time() - unmask_start) / 1000 / 1000)
+
         return opcode, bytes, fin, rsv1, rsv2, rsv3
 
     def _receive_frame_as_frame_object(self):
@@ -359,8 +416,8 @@
 
         Raises:
             BadOperationException: when called on a server-terminated
-                connection or called with inconsistent message type or binary
-                parameter.
+                connection or called with inconsistent message type or
+                binary parameter.
         """
 
         if self._request.server_terminated:
@@ -408,6 +465,15 @@
 
             frame = self._receive_frame_as_frame_object()
 
+            # Check the constraint on the payload size for control frames
+            # before extension processes the frame.
+            # See also http://tools.ietf.org/html/rfc6455#section-5.5
+            if (common.is_control_opcode(frame.opcode) and
+                len(frame.payload) > 125):
+                raise InvalidFrameException(
+                    'Payload data size of control frames must be 125 bytes or '
+                    'less')
+
             for frame_filter in self._options.incoming_frame_filters:
                 frame_filter.filter(frame)
 
@@ -450,12 +516,6 @@
                 if frame.fin:
                     # Unfragmented frame
 
-                    if (common.is_control_opcode(frame.opcode) and
-                        len(frame.payload) > 125):
-                        raise InvalidFrameException(
-                            'Application data size of control frames must be '
-                            '125 bytes or less')
-
                     self._original_opcode = frame.opcode
                     message = frame.payload
                 else:
@@ -488,7 +548,11 @@
                 # - no application data: no code no reason
                 # - 2 octet of application data: has code but no reason
                 # - 3 or more octet of application data: both code and reason
-                if len(message) == 1:
+                if len(message) == 0:
+                    self._logger.debug('Received close frame (empty body)')
+                    self._request.ws_close_code = (
+                        common.STATUS_NO_STATUS_RECEIVED)
+                elif len(message) == 1:
                     raise InvalidFrameException(
                         'If a close frame has status code, the length of '
                         'status code must be 2 octet')
@@ -507,8 +571,7 @@
 
                 if self._request.server_terminated:
                     self._logger.debug(
-                        'Received ack for server-initiated closing '
-                        'handshake')
+                        'Received ack for server-initiated closing handshake')
                     return None
 
                 self._logger.debug(
@@ -520,9 +583,16 @@
                     dispatcher = self._request._dispatcher
                     code, reason = dispatcher.passive_closing_handshake(
                         self._request)
+                    if code is None and reason is not None and len(reason) > 0:
+                        self._logger.warning(
+                            'Handler specified reason despite code being None')
+                        reason = ''
+                    if reason is None:
+                        reason = ''
                 self._send_closing_handshake(code, reason)
                 self._logger.debug(
-                    'Sent ack for client-initiated closing handshake')
+                    'Sent ack for client-initiated closing handshake '
+                    '(code=%r, reason=%r)', code, reason)
                 return None
             elif self._original_opcode == common.OPCODE_PING:
                 try:
@@ -571,17 +641,21 @@
                     'Opcode %d is not supported' % self._original_opcode)
 
     def _send_closing_handshake(self, code, reason):
-        if code >= (1 << 16) or code < 0:
-            raise BadOperationException('Status code is out of range')
+        body = ''
+        if code is not None:
+            if (code > common.STATUS_USER_PRIVATE_MAX or
+                code < common.STATUS_NORMAL_CLOSURE):
+                raise BadOperationException('Status code is out of range')
+            if (code == common.STATUS_NO_STATUS_RECEIVED or
+                code == common.STATUS_ABNORMAL_CLOSURE or
+                code == common.STATUS_TLS_HANDSHAKE):
+                raise BadOperationException('Status code is reserved pseudo '
+                    'code')
+            encoded_reason = reason.encode('utf-8')
+            body = struct.pack('!H', code) + encoded_reason
 
-        encoded_reason = reason.encode('utf-8')
-        if len(encoded_reason) + 2 > 125:
-            raise BadOperationException(
-                'Application data size of close frames must be 125 bytes or '
-                'less')
-
         frame = create_close_frame(
-            struct.pack('!H', code) + encoded_reason,
+            body,
             self._options.mask_send,
             self._options.outgoing_frame_filters)
 
@@ -590,15 +664,36 @@
         self._write(frame)
 
     def close_connection(self, code=common.STATUS_NORMAL_CLOSURE, reason=''):
-        """Closes a WebSocket connection."""
+        """Closes a WebSocket connection.
 
+        Args:
+            code: Status code for close frame. If code is None, a close
+                frame with empty body will be sent.
+            reason: string representing close reason.
+        Raises:
+            BadOperationException: when reason is specified with code None
+            or reason is not an instance of both str and unicode.
+        """
+
         if self._request.server_terminated:
             self._logger.debug(
                 'Requested close_connection but server is already terminated')
             return
 
+        if code is None:
+            if reason is not None and len(reason) > 0:
+                raise BadOperationException(
+                    'close reason must not be specified if code is None')
+            reason = ''
+        else:
+            if not isinstance(reason, str) and not isinstance(reason, unicode):
+                raise BadOperationException(
+                    'close reason must be an instance of str or unicode')
+
         self._send_closing_handshake(code, reason)
-        self._logger.debug('Sent server-initiated closing handshake')
+        self._logger.debug(
+            'Sent server-initiated closing handshake (code=%r, reason=%r)',
+            code, reason)
 
         if (code == common.STATUS_GOING_AWAY or
             code == common.STATUS_PROTOCOL_ERROR):
@@ -621,10 +716,6 @@
         # note: mod_python Connection (mp_conn) doesn't have close method.
 
     def send_ping(self, body=''):
-        if len(body) > 125:
-            raise ValueError(
-                'Application data size of control frames must be 125 bytes or '
-                'less')
         frame = create_ping_frame(
             body,
             self._options.mask_send,
@@ -634,10 +725,6 @@
         self._ping_queue.append(body)
 
     def _send_pong(self, body):
-        if len(body) > 125:
-            raise ValueError(
-                'Application data size of control frames must be 125 bytes or '
-                'less')
         frame = create_pong_frame(
             body,
             self._options.mask_send,

Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py (120314 => 120315)


--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py	2012-06-14 12:18:15 UTC (rev 120314)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/common.py	2012-06-14 12:40:32 UTC (rev 120315)
@@ -28,6 +28,16 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
+"""This file must not depend on any module specific to the WebSocket protocol.
+"""
+
+
+from mod_pywebsocket import http_header_util
+
+
+# Additional log level definitions.
+LOGLEVEL_FINE = 9
+
 # Constants indicating WebSocket protocol version.
 VERSION_HIXIE75 = -1
 VERSION_HYBI00 = 0
@@ -93,6 +103,7 @@
 # Extensions
 DEFLATE_STREAM_EXTENSION = 'deflate-stream'
 DEFLATE_FRAME_EXTENSION = 'deflate-frame'
+PERFRAME_COMPRESSION_EXTENSION = 'perframe-compress'
 X_WEBKIT_DEFLATE_FRAME_EXTENSION = 'x-webkit-deflate-frame'
 
 # Status codes
@@ -176,4 +187,118 @@
                 return param_value
 
 
+class ExtensionParsingException(Exception):
+    def __init__(self, name):
+        super(ExtensionParsingException, self).__init__(name)
+
+
+def _parse_extension_param(state, definition, allow_quoted_string):
+    param_name = http_header_util.consume_token(state)
+
+    if param_name is None:
+        raise ExtensionParsingException('No valid parameter name found')
+
+    http_header_util.consume_lwses(state)
+
+    if not http_header_util.consume_string(state, '='):
+        definition.add_parameter(param_name, None)
+        return
+
+    http_header_util.consume_lwses(state)
+
+    if allow_quoted_string:
+        # TODO(toyoshim): Add code to validate that parsed param_value is token
+        param_value = http_header_util.consume_token_or_quoted_string(state)
+    else:
+        param_value = http_header_util.consume_token(state)
+    if param_value is None:
+        raise ExtensionParsingException(
+            'No valid parameter value found on the right-hand side of '
+            'parameter %r' % param_name)
+
+    definition.add_parameter(param_name, param_value)
+
+
+def _parse_extension(state, allow_quoted_string):
+    extension_token = http_header_util.consume_token(state)
+    if extension_token is None:
+        return None
+
+    extension = ExtensionParameter(extension_token)
+
+    while True:
+        http_header_util.consume_lwses(state)
+
+        if not http_header_util.consume_string(state, ';'):
+            break
+
+        http_header_util.consume_lwses(state)
+
+        try:
+            _parse_extension_param(state, extension, allow_quoted_string)
+        except ExtensionParsingException, e:
+            raise ExtensionParsingException(
+                'Failed to parse parameter for %r (%r)' %
+                (extension_token, e))
+
+    return extension
+
+
+def parse_extensions(data, allow_quoted_string=False):
+    """Parses Sec-WebSocket-Extensions header value returns a list of
+    ExtensionParameter objects.
+
+    Leading LWSes must be trimmed.
+    """
+
+    state = http_header_util.ParsingState(data)
+
+    extension_list = []
+    while True:
+        extension = _parse_extension(state, allow_quoted_string)
+        if extension is not None:
+            extension_list.append(extension)
+
+        http_header_util.consume_lwses(state)
+
+        if http_header_util.peek(state) is None:
+            break
+
+        if not http_header_util.consume_string(state, ','):
+            raise ExtensionParsingException(
+                'Failed to parse Sec-WebSocket-Extensions header: '
+                'Expected a comma but found %r' %
+                http_header_util.peek(state))
+
+        http_header_util.consume_lwses(state)
+
+    if len(extension_list) == 0:
+        raise ExtensionParsingException(
+            'No valid extension entry found')
+
+    return extension_list
+
+
+def format_extension(extension):
+    """Formats an ExtensionParameter object."""
+
+    formatted_params = [extension.name()]
+    for param_name, param_value in extension.get_parameters():
+        if param_value is None:
+            formatted_params.append(param_name)
+        else:
+            quoted_value = http_header_util.quote_if_necessary(param_value)
+            formatted_params.append('%s=%s' % (param_name, quoted_value))
+    return '; '.join(formatted_params)
+
+
+def format_extensions(extension_list):
+    """Formats a list of ExtensionParameter objects."""
+
+    formatted_extension_list = []
+    for extension in extension_list:
+        formatted_extension_list.append(format_extension(extension))
+    return ', '.join(formatted_extension_list)
+
+
 # vi:sts=4 sw=4 et

Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py (120314 => 120315)


--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py	2012-06-14 12:18:15 UTC (rev 120314)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/extensions.py	2012-06-14 12:40:32 UTC (rev 120315)
@@ -1,4 +1,4 @@
-# Copyright 2011, Google Inc.
+# Copyright 2012, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,7 @@
 
 from mod_pywebsocket import common
 from mod_pywebsocket import util
+from mod_pywebsocket.http_header_util import quote_if_necessary
 
 
 _available_processors = {}
@@ -254,6 +255,96 @@
     DeflateFrameExtensionProcessor)
 
 
+def _parse_compression_method(data):
+    """Parses the value of "method" extension parameter."""
+
+    return common.parse_extensions(data, allow_quoted_string=True)
+
+
+def _create_accepted_method_desc(method_name, method_params):
+    """Creates accepted-method-desc from given method name and parameters"""
+
+    extension = common.ExtensionParameter(method_name)
+    for name, value in method_params:
+        extension.add_parameter(name, value)
+    return common.format_extension(extension)
+
+
+class PerFrameCompressionExtensionProcessor(ExtensionProcessorInterface):
+    """WebSocket Per-frame compression extension processor."""
+
+    _METHOD_PARAM = 'method'
+    _DEFLATE_METHOD = 'deflate'
+
+    def __init__(self, request):
+        self._logger = util.get_class_logger(self)
+        self._request = request
+        self._compression_method_name = None
+        self._compression_processor = None
+
+    def _lookup_compression_processor(self, method_desc):
+        if method_desc.name() == self._DEFLATE_METHOD:
+            return DeflateFrameExtensionProcessor(method_desc)
+        return None
+
+    def _get_compression_processor_response(self):
+        """Looks up the compression processor based on the self._request and
+           returns the compression processor's response.
+        """
+
+        method_list = self._request.get_parameter_value(self._METHOD_PARAM)
+        if method_list is None:
+            return None
+        methods = _parse_compression_method(method_list)
+        if methods is None:
+            return None
+        comression_processor = None
+        # The current implementation tries only the first method that matches
+        # supported algorithm. Following methods aren't tried even if the
+        # first one is rejected.
+        # TODO(bashi): Need to clarify this behavior.
+        for method_desc in methods:
+            compression_processor = self._lookup_compression_processor(
+                method_desc)
+            if compression_processor is not None:
+                self._compression_method_name = method_desc.name()
+                break
+        if compression_processor is None:
+            return None
+        processor_response = compression_processor.get_extension_response()
+        if processor_response is None:
+            return None
+        self._compression_processor = compression_processor
+        return processor_response
+
+    def get_extension_response(self):
+        processor_response = self._get_compression_processor_response()
+        if processor_response is None:
+            return None
+
+        response = common.ExtensionParameter(self._request.name())
+        accepted_method_desc = _create_accepted_method_desc(
+                                   self._compression_method_name,
+                                   processor_response.get_parameters())
+        response.add_parameter(self._METHOD_PARAM, accepted_method_desc)
+        self._logger.debug(
+            'Enable %s extension (method: %s)' %
+            (self._request.name(), self._compression_method_name))
+        return response
+
+    def setup_stream_options(self, stream_options):
+        if self._compression_processor is None:
+            return
+        self._compression_processor.setup_stream_options(stream_options)
+
+    def get_compression_processor(self):
+        return self._compression_processor
+
+
+_available_processors[common.PERFRAME_COMPRESSION_EXTENSION] = (
+    PerFrameCompressionExtensionProcessor)
+
+
 def get_extension_processor(extension_request):
     global _available_processors
     processor_class = _available_processors.get(extension_request.name())

Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py (120314 => 120315)


--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py	2012-06-14 12:18:15 UTC (rev 120314)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/_base.py	2012-06-14 12:40:32 UTC (rev 120315)
@@ -1,4 +1,4 @@
-# Copyright 2011, Google Inc.
+# Copyright 2012, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -216,108 +216,4 @@
     return token_list
 
 
-def _parse_extension_param(state, definition, allow_quoted_string):
-    param_name = http_header_util.consume_token(state)
-
-    if param_name is None:
-        raise HandshakeException('No valid parameter name found')
-
-    http_header_util.consume_lwses(state)
-
-    if not http_header_util.consume_string(state, '='):
-        definition.add_parameter(param_name, None)
-        return
-
-    http_header_util.consume_lwses(state)
-
-    if allow_quoted_string:
-        # TODO(toyoshim): Add code to validate that parsed param_value is token
-        param_value = http_header_util.consume_token_or_quoted_string(state)
-    else:
-        param_value = http_header_util.consume_token(state)
-    if param_value is None:
-        raise HandshakeException(
-            'No valid parameter value found on the right-hand side of '
-            'parameter %r' % param_name)
-
-    definition.add_parameter(param_name, param_value)
-
-
-def _parse_extension(state, allow_quoted_string):
-    extension_token = http_header_util.consume_token(state)
-    if extension_token is None:
-        return None
-
-    extension = common.ExtensionParameter(extension_token)
-
-    while True:
-        http_header_util.consume_lwses(state)
-
-        if not http_header_util.consume_string(state, ';'):
-            break
-
-        http_header_util.consume_lwses(state)
-
-        try:
-            _parse_extension_param(state, extension, allow_quoted_string)
-        except HandshakeException, e:
-            raise HandshakeException(
-                'Failed to parse Sec-WebSocket-Extensions header: '
-                'Failed to parse parameter for %r (%r)' %
-                (extension_token, e))
-
-    return extension
-
-
-def parse_extensions(data, allow_quoted_string=False):
-    """Parses Sec-WebSocket-Extensions header value returns a list of
-    common.ExtensionParameter objects.
-
-    Leading LWSes must be trimmed.
-    """
-
-    state = http_header_util.ParsingState(data)
-
-    extension_list = []
-    while True:
-        extension = _parse_extension(state, allow_quoted_string)
-        if extension is not None:
-            extension_list.append(extension)
-
-        http_header_util.consume_lwses(state)
-
-        if http_header_util.peek(state) is None:
-            break
-
-        if not http_header_util.consume_string(state, ','):
-            raise HandshakeException(
-                'Failed to parse Sec-WebSocket-Extensions header: '
-                'Expected a comma but found %r' %
-                http_header_util.peek(state))
-
-        http_header_util.consume_lwses(state)
-
-    if len(extension_list) == 0:
-        raise HandshakeException(
-            'Sec-WebSocket-Extensions header contains no valid extension')
-
-    return extension_list
-
-
-def format_extensions(extension_list):
-    formatted_extension_list = []
-    for extension in extension_list:
-        formatted_params = [extension.name()]
-        for param_name, param_value in extension.get_parameters():
-            if param_value is None:
-                formatted_params.append(param_name)
-            else:
-                quoted_value = http_header_util.quote_if_necessary(param_value)
-                formatted_params.append('%s=%s' % (param_name, quoted_value))
-
-        formatted_extension_list.append('; '.join(formatted_params))
-
-    return ', '.join(formatted_extension_list)
-
-
 # vi:sts=4 sw=4 et

Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py (120314 => 120315)


--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py	2012-06-14 12:18:15 UTC (rev 120314)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/handshake/hybi.py	2012-06-14 12:40:32 UTC (rev 120315)
@@ -1,4 +1,4 @@
-# Copyright 2011, Google Inc.
+# Copyright 2012, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -50,11 +50,9 @@
 from mod_pywebsocket import common
 from mod_pywebsocket.extensions import get_extension_processor
 from mod_pywebsocket.handshake._base import check_request_line
-from mod_pywebsocket.handshake._base import format_extensions
 from mod_pywebsocket.handshake._base import format_header
 from mod_pywebsocket.handshake._base import get_mandatory_header
 from mod_pywebsocket.handshake._base import HandshakeException
-from mod_pywebsocket.handshake._base import parse_extensions
 from mod_pywebsocket.handshake._base import parse_token_list
 from mod_pywebsocket.handshake._base import validate_mandatory_header
 from mod_pywebsocket.handshake._base import validate_subprotocol
@@ -290,8 +288,12 @@
             allow_quoted_string=False
         else:
             allow_quoted_string=True
-        self._request.ws_requested_extensions = parse_extensions(
-            extensions_header, allow_quoted_string=allow_quoted_string)
+        try:
+            self._request.ws_requested_extensions = common.parse_extensions(
+                extensions_header, allow_quoted_string=allow_quoted_string)
+        except common.ExtensionParsingException, e:
+            raise HandshakeException(
+                'Failed to parse Sec-WebSocket-Extensions header: %r' % e)
 
         self._logger.debug(
             'Extensions requested: %r',
@@ -358,7 +360,7 @@
             len(self._request.ws_extensions) != 0):
             response.append(format_header(
                 common.SEC_WEBSOCKET_EXTENSIONS_HEADER,
-                format_extensions(self._request.ws_extensions)))
+                common.format_extensions(self._request.ws_extensions)))
         response.append('\r\n')
 
         raw_response = ''.join(response)

Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py (120314 => 120315)


--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py	2012-06-14 12:18:15 UTC (rev 120314)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/standalone.py	2012-06-14 12:40:32 UTC (rev 120315)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-# Copyright 2011, Google Inc.
+# Copyright 2012, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -55,6 +55,20 @@
 handlers under scan_dir are scanned. This is useful in saving scan time.
 
 
+SUPPORTING TLS
+
+To support TLS, run standalone.py with -t, -k, and -c options.
+
+
+SUPPORTING CLIENT AUTHENTICATION
+
+To support client authentication with TLS, run standalone.py with -t, -k, -c,
+and --ca-certificate options.
+
+E.g., $./standalone.py -d ../example -p 10443 -t -c ../test/cert/cert.pem -k
+../test/cert/key.pem --ca-certificate=../test/cert/cacert.pem
+
+
 CONFIGURATION FILE
 
 You can also write a configuration file and use it by specifying the path to
@@ -311,10 +325,16 @@
                 continue
             if self.websocket_server_options.use_tls:
                 if _HAS_SSL:
+                    if self.websocket_server_options.ca_certificate:
+                        client_cert_ = ssl.CERT_REQUIRED
+                    else:
+                        client_cert_ = ssl.CERT_NONE
                     socket_ = ssl.wrap_socket(socket_,
                         keyfile=self.websocket_server_options.private_key,
                         certfile=self.websocket_server_options.certificate,
-                        ssl_version=ssl.PROTOCOL_SSLv23)
+                        ssl_version=ssl.PROTOCOL_SSLv23,
+                        ca_certs=self.websocket_server_options.ca_certificate,
+                        cert_reqs=client_cert_)
                 if _HAS_OPEN_SSL:
                     ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
                     ctx.use_privatekey_file(
@@ -601,7 +621,13 @@
         return False
 
 
+def _get_logger_from_class(c):
+    return logging.getLogger('%s.%s' % (c.__module__, c.__name__))
+
+
 def _configure_logging(options):
+    logging.addLevelName(common.LOGLEVEL_FINE, 'FINE')
+
     logger = logging.getLogger()
     logger.setLevel(logging.getLevelName(options.log_level.upper()))
     if options.log_file:
@@ -614,7 +640,14 @@
     handler.setFormatter(formatter)
     logger.addHandler(handler)
 
+    deflate_log_level_name = logging.getLevelName(
+        options.deflate_log_level.upper())
+    _get_logger_from_class(util._Deflater).setLevel(
+        deflate_log_level_name)
+    _get_logger_from_class(util._Inflater).setLevel(
+        deflate_log_level_name)
 
+
 def _alias_handlers(dispatcher, websock_handlers_map_file):
     """Set aliases specified in websock_handler_map_file in dispatcher.
 
@@ -702,13 +735,25 @@
                       default='', help='TLS private key file.')
     parser.add_option('-c', '--certificate', dest='certificate',
                       default='', help='TLS certificate file.')
+    parser.add_option('--ca-certificate', dest='ca_certificate', default='',
+                      help=('TLS CA certificate file for client '
+                            'authentication.'))
     parser.add_option('-l', '--log-file', '--log_file', dest='log_file',
                       default='', help='Log file.')
+    # Custom log level:
+    # - FINE: Prints status of each frame processing step
     parser.add_option('--log-level', '--log_level', type='choice',
                       dest='log_level', default='warn',
+                      choices=['fine',
+                               'debug', 'info', 'warning', 'warn', 'error',
+                               'critical'],
+                      help='Log level.')
+    parser.add_option('--deflate-log-level', '--deflate_log_level',
+                      type='choice',
+                      dest='deflate_log_level', default='warn',
                       choices=['debug', 'info', 'warning', 'warn', 'error',
                                'critical'],
-                      help='Log level.')
+                      help='Log level for _Deflater and _Inflater.')
     parser.add_option('--thread-monitor-interval-in-sec',
                       '--thread_monitor_interval_in_sec',
                       dest='thread_monitor_interval_in_sec',
@@ -825,13 +870,20 @@
 
     if options.use_tls:
         if not (_HAS_SSL or _HAS_OPEN_SSL):
-            logging.critical('TLS support requires ssl or pyOpenSSL.')
+            logging.critical('TLS support requires ssl or pyOpenSSL module.')
             sys.exit(1)
         if not options.private_key or not options.certificate:
             logging.critical(
                     'To use TLS, specify private_key and certificate.')
             sys.exit(1)
 
+    if options.ca_certificate:
+        if not options.use_tls:
+            logging.critical('TLS must be enabled for client authentication.')
+            sys.exit(1)
+        if not _HAS_SSL:
+            logging.critical('Client authentication requires ssl module.')
+
     if not options.scan_dir:
         options.scan_dir = options.websock_handlers
 

Modified: trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py (120314 => 120315)


--- trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py	2012-06-14 12:18:15 UTC (rev 120314)
+++ trunk/Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/util.py	2012-06-14 12:40:32 UTC (rev 120315)
@@ -177,9 +177,16 @@
     def mask(self, s):
         result = array.array('B')
         result.fromstring(s)
+        # Use temporary local variables to eliminate the cost to access
+        # attributes
+        count = self._count
+        mask = self._mask
+        mask_size = self._mask_size
         for i in xrange(len(result)):
-            result[i] ^= self._mask[self._count]
-            self._count = (self._count + 1) % self._mask_size
+            result[i] ^= mask[count]
+            count = (count + 1) % mask_size
+        self._count = count
+
         return result.tostring()
 
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to