testing/mochitest/pywebsocket/mod_pywebsocket/extensions.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 # Copyright 2011, Google Inc.
     2 # All rights reserved.
     3 #
     4 # Redistribution and use in source and binary forms, with or without
     5 # modification, are permitted provided that the following conditions are
     6 # met:
     7 #
     8 #     * Redistributions of source code must retain the above copyright
     9 # notice, this list of conditions and the following disclaimer.
    10 #     * Redistributions in binary form must reproduce the above
    11 # copyright notice, this list of conditions and the following disclaimer
    12 # in the documentation and/or other materials provided with the
    13 # distribution.
    14 #     * Neither the name of Google Inc. nor the names of its
    15 # contributors may be used to endorse or promote products derived from
    16 # this software without specific prior written permission.
    17 #
    18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31 from mod_pywebsocket import common
    32 from mod_pywebsocket import util
    35 _available_processors = {}
    38 class ExtensionProcessorInterface(object):
    40     def get_extension_response(self):
    41         return None
    43     def setup_stream_options(self, stream_options):
    44         pass
    47 class DeflateStreamExtensionProcessor(ExtensionProcessorInterface):
    48     """WebSocket DEFLATE stream extension processor."""
    50     def __init__(self, request):
    51         self._logger = util.get_class_logger(self)
    53         self._request = request
    55     def get_extension_response(self):
    56         if len(self._request.get_parameter_names()) != 0:
    57             return None
    59         self._logger.debug(
    60             'Enable %s extension', common.DEFLATE_STREAM_EXTENSION)
    62         return common.ExtensionParameter(common.DEFLATE_STREAM_EXTENSION)
    64     def setup_stream_options(self, stream_options):
    65         stream_options.deflate_stream = True
    68 _available_processors[common.DEFLATE_STREAM_EXTENSION] = (
    69     DeflateStreamExtensionProcessor)
    72 class DeflateFrameExtensionProcessor(ExtensionProcessorInterface):
    73     """WebSocket Per-frame DEFLATE extension processor."""
    75     _WINDOW_BITS_PARAM = 'max_window_bits'
    76     _NO_CONTEXT_TAKEOVER_PARAM = 'no_context_takeover'
    78     def __init__(self, request):
    79         self._logger = util.get_class_logger(self)
    81         self._request = request
    83         self._response_window_bits = None
    84         self._response_no_context_takeover = False
    86         # Counters for statistics.
    88         # Total number of outgoing bytes supplied to this filter.
    89         self._total_outgoing_payload_bytes = 0
    90         # Total number of bytes sent to the network after applying this filter.
    91         self._total_filtered_outgoing_payload_bytes = 0
    93         # Total number of bytes received from the network.
    94         self._total_incoming_payload_bytes = 0
    95         # Total number of incoming bytes obtained after applying this filter.
    96         self._total_filtered_incoming_payload_bytes = 0
    98     def get_extension_response(self):
    99         # Any unknown parameter will be just ignored.
   101         window_bits = self._request.get_parameter_value(
   102             self._WINDOW_BITS_PARAM)
   103         no_context_takeover = self._request.has_parameter(
   104             self._NO_CONTEXT_TAKEOVER_PARAM)
   105         if (no_context_takeover and
   106             self._request.get_parameter_value(
   107                 self._NO_CONTEXT_TAKEOVER_PARAM) is not None):
   108             return None
   110         if window_bits is not None:
   111             try:
   112                 window_bits = int(window_bits)
   113             except ValueError, e:
   114                 return None
   115             if window_bits < 8 or window_bits > 15:
   116                 return None
   118         self._deflater = util._RFC1979Deflater(
   119             window_bits, no_context_takeover)
   121         self._inflater = util._RFC1979Inflater()
   123         self._compress_outgoing = True
   125         response = common.ExtensionParameter(self._request.name())
   127         if self._response_window_bits is not None:
   128             response.add_parameter(
   129                 self._WINDOW_BITS_PARAM, str(self._response_window_bits))
   130         if self._response_no_context_takeover:
   131             response.add_parameter(
   132                 self._NO_CONTEXT_TAKEOVER_PARAM, None)
   134         self._logger.debug(
   135             'Enable %s extension ('
   136             'request: window_bits=%s; no_context_takeover=%r, '
   137             'response: window_wbits=%s; no_context_takeover=%r)' %
   138             (self._request.name(),
   139              window_bits,
   140              no_context_takeover,
   141              self._response_window_bits,
   142              self._response_no_context_takeover))
   144         return response
   146     def setup_stream_options(self, stream_options):
   148         class _OutgoingFilter(object):
   150             def __init__(self, parent):
   151                 self._parent = parent
   153             def filter(self, frame):
   154                 self._parent._outgoing_filter(frame)
   156         class _IncomingFilter(object):
   158             def __init__(self, parent):
   159                 self._parent = parent
   161             def filter(self, frame):
   162                 self._parent._incoming_filter(frame)
   164         stream_options.outgoing_frame_filters.append(
   165             _OutgoingFilter(self))
   166         stream_options.incoming_frame_filters.insert(
   167             0, _IncomingFilter(self))
   169     def set_response_window_bits(self, value):
   170         self._response_window_bits = value
   172     def set_response_no_context_takeover(self, value):
   173         self._response_no_context_takeover = value
   175     def enable_outgoing_compression(self):
   176         self._compress_outgoing = True
   178     def disable_outgoing_compression(self):
   179         self._compress_outgoing = False
   181     def _outgoing_filter(self, frame):
   182         """Transform outgoing frames. This method is called only by
   183         an _OutgoingFilter instance.
   184         """
   186         original_payload_size = len(frame.payload)
   187         self._total_outgoing_payload_bytes += original_payload_size
   189         if (not self._compress_outgoing or
   190             common.is_control_opcode(frame.opcode)):
   191             self._total_filtered_outgoing_payload_bytes += (
   192                 original_payload_size)
   193             return
   195         frame.payload = self._deflater.filter(frame.payload)
   196         frame.rsv1 = 1
   198         filtered_payload_size = len(frame.payload)
   199         self._total_filtered_outgoing_payload_bytes += filtered_payload_size
   201         # Print inf when ratio is not available.
   202         ratio = float('inf')
   203         average_ratio = float('inf')
   204         if original_payload_size != 0:
   205             ratio = float(filtered_payload_size) / original_payload_size
   206         if self._total_outgoing_payload_bytes != 0:
   207             average_ratio = (
   208                 float(self._total_filtered_outgoing_payload_bytes) /
   209                 self._total_outgoing_payload_bytes)
   210         self._logger.debug(
   211             'Outgoing compress ratio: %f (average: %f)' %
   212             (ratio, average_ratio))
   214     def _incoming_filter(self, frame):
   215         """Transform incoming frames. This method is called only by
   216         an _IncomingFilter instance.
   217         """
   219         received_payload_size = len(frame.payload)
   220         self._total_incoming_payload_bytes += received_payload_size
   222         if frame.rsv1 != 1 or common.is_control_opcode(frame.opcode):
   223             self._total_filtered_incoming_payload_bytes += (
   224                 received_payload_size)
   225             return
   227         frame.payload = self._inflater.filter(frame.payload)
   228         frame.rsv1 = 0
   230         filtered_payload_size = len(frame.payload)
   231         self._total_filtered_incoming_payload_bytes += filtered_payload_size
   233         # Print inf when ratio is not available.
   234         ratio = float('inf')
   235         average_ratio = float('inf')
   236         if received_payload_size != 0:
   237             ratio = float(received_payload_size) / filtered_payload_size
   238         if self._total_filtered_incoming_payload_bytes != 0:
   239             average_ratio = (
   240                 float(self._total_incoming_payload_bytes) /
   241                 self._total_filtered_incoming_payload_bytes)
   242         self._logger.debug(
   243             'Incoming compress ratio: %f (average: %f)' %
   244             (ratio, average_ratio))
   247 _available_processors[common.DEFLATE_FRAME_EXTENSION] = (
   248     DeflateFrameExtensionProcessor)
   251 # Adding vendor-prefixed deflate-frame extension.
   252 # TODO(bashi): Remove this after WebKit stops using vender prefix.
   253 _available_processors[common.X_WEBKIT_DEFLATE_FRAME_EXTENSION] = (
   254     DeflateFrameExtensionProcessor)
   257 def get_extension_processor(extension_request):
   258     global _available_processors
   259     processor_class = _available_processors.get(extension_request.name())
   260     if processor_class is None:
   261         return None
   262     return processor_class(extension_request)
   265 # vi:sts=4 sw=4 et

mercurial