summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/pywebsocket/src/mod_pywebsocket/util.py
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/pywebsocket/src/mod_pywebsocket/util.py')
-rw-r--r--chromium/third_party/pywebsocket/src/mod_pywebsocket/util.py208
1 files changed, 61 insertions, 147 deletions
diff --git a/chromium/third_party/pywebsocket/src/mod_pywebsocket/util.py b/chromium/third_party/pywebsocket/src/mod_pywebsocket/util.py
index 6146e052fbc..109d0492365 100644
--- a/chromium/third_party/pywebsocket/src/mod_pywebsocket/util.py
+++ b/chromium/third_party/pywebsocket/src/mod_pywebsocket/util.py
@@ -56,6 +56,11 @@ import socket
import traceback
import zlib
+try:
+ from mod_pywebsocket import fast_masking
+except ImportError:
+ pass
+
def get_stack_trace():
"""Get the current stack trace as string.
@@ -169,45 +174,39 @@ class RepeatedXorMasker(object):
ended and resumes from that point on the next mask method call.
"""
- def __init__(self, mask):
- self._mask = map(ord, mask)
- self._mask_size = len(self._mask)
- self._count = 0
+ def __init__(self, masking_key):
+ self._masking_key = masking_key
+ self._masking_key_index = 0
- def mask(self, s):
+ 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):
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] ^= mask[count]
- count = (count + 1) % mask_size
- self._count = count
-
- return result.tostring()
+ masking_key = map(ord, self._masking_key)
+ masking_key_size = len(masking_key)
+ masking_key_index = self._masking_key_index
+ for i in xrange(len(result)):
+ result[i] ^= masking_key[masking_key_index]
+ masking_key_index = (masking_key_index + 1) % masking_key_size
-class DeflateRequest(object):
- """A wrapper class for request object to intercept send and recv to perform
- deflate compression and decompression transparently.
- """
-
- def __init__(self, request):
- self._request = request
- self.connection = DeflateConnection(request.connection)
+ self._masking_key_index = masking_key_index
- def __getattribute__(self, name):
- if name in ('_request', 'connection'):
- return object.__getattribute__(self, name)
- return self._request.__getattribute__(name)
+ return result.tostring()
- def __setattr__(self, name, value):
- if name in ('_request', 'connection'):
- return object.__setattr__(self, name, value)
- return self._request.__setattr__(name, value)
+ if 'fast_masking' in globals():
+ mask = _mask_using_swig
+ else:
+ mask = _mask_using_array
# By making wbits option negative, we can suppress CMF/FLG (2 octet) and
@@ -232,6 +231,12 @@ class _Deflater(object):
self._compress = zlib.compressobj(
zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -window_bits)
+ def compress(self, bytes):
+ compressed_bytes = self._compress.compress(bytes)
+ self._logger.debug('Compress input %r', bytes)
+ self._logger.debug('Compress result %r', compressed_bytes)
+ return compressed_bytes
+
def compress_and_flush(self, bytes):
compressed_bytes = self._compress.compress(bytes)
compressed_bytes += self._compress.flush(zlib.Z_SYNC_FLUSH)
@@ -239,11 +244,19 @@ class _Deflater(object):
self._logger.debug('Compress result %r', compressed_bytes)
return compressed_bytes
+ def compress_and_finish(self, bytes):
+ compressed_bytes = self._compress.compress(bytes)
+ compressed_bytes += self._compress.flush(zlib.Z_FINISH)
+ self._logger.debug('Compress input %r', bytes)
+ self._logger.debug('Compress result %r', compressed_bytes)
+ return compressed_bytes
+
class _Inflater(object):
- def __init__(self):
+ def __init__(self, window_bits):
self._logger = get_class_logger(self)
+ self._window_bits = window_bits
self._unconsumed = ''
@@ -300,7 +313,7 @@ class _Inflater(object):
def reset(self):
self._logger.debug('Reset')
- self._decompress = zlib.decompressobj(-zlib.MAX_WBITS)
+ self._decompress = zlib.decompressobj(-self._window_bits)
# Compresses/decompresses given octets using the method introduced in RFC1979.
@@ -318,13 +331,21 @@ class _RFC1979Deflater(object):
self._window_bits = window_bits
self._no_context_takeover = no_context_takeover
- def filter(self, bytes):
- if self._deflater is None or self._no_context_takeover:
+ def filter(self, bytes, flush=True, bfinal=False):
+ if self._deflater is None or (self._no_context_takeover and flush):
self._deflater = _Deflater(self._window_bits)
- # Strip last 4 octets which is LEN and NLEN field of a non-compressed
- # block added for Z_SYNC_FLUSH.
- return self._deflater.compress_and_flush(bytes)[:-4]
+ if bfinal:
+ result = self._deflater.compress_and_finish(bytes)
+ # Add a padding block with BFINAL = 0 and BTYPE = 0.
+ result = result + chr(0)
+ self._deflater = None
+ return result
+ if flush:
+ # Strip last 4 octets which is LEN and NLEN field of a
+ # non-compressed block added for Z_SYNC_FLUSH.
+ return self._deflater.compress_and_flush(bytes)[:-4]
+ return self._deflater.compress(bytes)
class _RFC1979Inflater(object):
@@ -332,8 +353,8 @@ class _RFC1979Inflater(object):
the algorithm described in the RFC1979 section 2.1.
"""
- def __init__(self):
- self._inflater = _Inflater()
+ def __init__(self, window_bits=zlib.MAX_WBITS):
+ self._inflater = _Inflater(window_bits)
def filter(self, bytes):
# Restore stripped LEN and NLEN field of a non-compressed block added
@@ -356,7 +377,7 @@ class DeflateSocket(object):
self._logger = get_class_logger(self)
self._deflater = _Deflater(zlib.MAX_WBITS)
- self._inflater = _Inflater()
+ self._inflater = _Inflater(zlib.MAX_WBITS)
def recv(self, size):
"""Receives data from the socket specified on the construction up
@@ -386,111 +407,4 @@ class DeflateSocket(object):
return len(bytes)
-class DeflateConnection(object):
- """A wrapper class for request object to intercept write and read to
- perform deflate compression and decompression transparently.
- """
-
- 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):
- """Reads at most size bytes. Blocks until there's at least one byte
- available.
- """
-
- # TODO(tyoshino): Allow call with size=0.
- if not (size == -1 or size > 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 >= 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):
- """Returns True iff error_number indicates that receive operation would
- block. To make this portable, we check availability of errno and then
- compare them.
- """
-
- 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)
-
-
# vi:sts=4 sw=4 et