12da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#!/usr/bin/env python
22da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#
32da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Copyright 2012, Google Inc.
42da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# All rights reserved.
52da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#
62da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# Redistribution and use in source and binary forms, with or without
72da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# modification, are permitted provided that the following conditions are
82da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# met:
92da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#
102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#     * Redistributions of source code must retain the above copyright
112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# notice, this list of conditions and the following disclaimer.
122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#     * Redistributions in binary form must reproduce the above
132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# copyright notice, this list of conditions and the following disclaimer
142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# in the documentation and/or other materials provided with the
152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# distribution.
162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#     * Neither the name of Google Inc. nor the names of its
172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# contributors may be used to endorse or promote products derived from
182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# this software without specific prior written permission.
192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis#
202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis"""Tests for msgutil module."""
342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
362da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport array
372da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport Queue
382da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport struct
392da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport unittest
402da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport zlib
412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
422da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport set_sys_path  # Update sys.path to locate mod_pywebsocket module.
432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
442da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom mod_pywebsocket import common
452da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom mod_pywebsocket.extensions import DeflateFrameExtensionProcessor
462da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom mod_pywebsocket.extensions import PerFrameCompressionExtensionProcessor
472da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom mod_pywebsocket.extensions import PerMessageCompressionExtensionProcessor
482da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom mod_pywebsocket import msgutil
492da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom mod_pywebsocket.stream import InvalidUTF8Exception
502da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom mod_pywebsocket.stream import Stream
512da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom mod_pywebsocket.stream import StreamHixie75
522da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom mod_pywebsocket.stream import StreamOptions
532da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom mod_pywebsocket import util
542da489cd246702bee5938545b18a6f710ed214bcJamie Gennisfrom test import mock
552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# We use one fixed nonce for testing instead of cryptographically secure PRNG.
582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis_MASKING_NONCE = 'ABCD'
592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
612da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _mask_hybi(frame):
622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    frame_key = map(ord, _MASKING_NONCE)
632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    frame_key_len = len(frame_key)
642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    result = array.array('B')
652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    result.fromstring(frame)
662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    count = 0
672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    for i in xrange(len(result)):
682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        result[i] ^= frame_key[count]
692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        count = (count + 1) % frame_key_len
702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return _MASKING_NONCE + result.tostring()
712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
732da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _install_extension_processor(processor, request, stream_options):
742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    response = processor.get_extension_response()
752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if response is not None:
762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor.setup_stream_options(stream_options)
772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request.ws_extension_processors.append(processor)
782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
802da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _create_request_from_rawdata(
812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    read_data, deflate_stream=False, deflate_frame_request=None,
822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    perframe_compression_request=None, permessage_compression_request=None):
832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req = mock.MockRequest(connection=mock.MockConn(''.join(read_data)))
842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req.ws_version = common.VERSION_HYBI_LATEST
852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    stream_options = StreamOptions()
862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    stream_options.deflate_stream = deflate_stream
872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req.ws_extension_processors = []
882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    if deflate_frame_request is not None:
892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor = DeflateFrameExtensionProcessor(deflate_frame_request)
902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        _install_extension_processor(processor, req, stream_options)
912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    elif perframe_compression_request is not None:
922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor = PerFrameCompressionExtensionProcessor(
932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            perframe_compression_request)
942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        _install_extension_processor(processor, req, stream_options)
952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    elif permessage_compression_request is not None:
962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor = PerMessageCompressionExtensionProcessor(
972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            permessage_compression_request)
982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        _install_extension_processor(processor, req, stream_options)
992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req.ws_stream = Stream(req, stream_options)
1012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return req
1022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1042da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _create_request(*frames):
1052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    """Creates MockRequest using data given as frames.
1062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    frames will be returned on calling request.connection.read() where request
1082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    is MockRequest returned by this function.
1092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    """
1102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    read_data = []
1122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    for (header, body) in frames:
1132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        read_data.append(header + _mask_hybi(body))
1142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return _create_request_from_rawdata(read_data)
1162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1182da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _create_blocking_request():
1192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    """Creates MockRequest.
1202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    Data written to a MockRequest can be read out by calling
1222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    request.connection.written_data().
1232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    """
1242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req = mock.MockRequest(connection=mock.MockBlockingConn())
1262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req.ws_version = common.VERSION_HYBI_LATEST
1272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    stream_options = StreamOptions()
1282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req.ws_stream = Stream(req, stream_options)
1292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return req
1302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1322da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _create_request_hixie75(read_data=''):
1332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req = mock.MockRequest(connection=mock.MockConn(read_data))
1342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req.ws_stream = StreamHixie75(req)
1352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return req
1362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1382da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef _create_blocking_request_hixie75():
1392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req = mock.MockRequest(connection=mock.MockBlockingConn())
1402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    req.ws_stream = StreamHixie75(req)
1412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return req
1422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1442da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass MessageTest(unittest.TestCase):
1452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    # Tests for Stream
1462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message(self):
1482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
1492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello')
1502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x81\x05Hello', request.connection.written_data())
1512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        payload = 'a' * 125
1532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
1542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, payload)
1552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x81\x7d' + payload,
1562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
1572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_medium_message(self):
1592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        payload = 'a' * 126
1602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
1612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, payload)
1622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x81\x7e\x00\x7e' + payload,
1632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
1642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        payload = 'a' * ((1 << 16) - 1)
1662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
1672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, payload)
1682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x81\x7e\xff\xff' + payload,
1692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
1702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_large_message(self):
1722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        payload = 'a' * (1 << 16)
1732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
1742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, payload)
1752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x81\x7f\x00\x00\x00\x00\x00\x01\x00\x00' + payload,
1762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
1772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message_unicode(self):
1792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
1802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, u'\u65e5')
1812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # U+65e5 is encoded as e6,97,a5 in UTF-8
1822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x81\x03\xe6\x97\xa5',
1832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
1842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message_fragments(self):
1862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
1872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello', False)
1882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, ' ', False)
1892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'World', False)
1902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, '!', True)
1912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x01\x05Hello\x00\x01 \x00\x05World\x80\x01!',
1922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
1932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_fragments_immediate_zero_termination(self):
1952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
1962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello World!', False)
1972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, '', True)
1982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x01\x0cHello World!\x80\x00',
1992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
2002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message_deflate_stream(self):
2022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
2032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
2042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata('', deflate_stream=True)
2062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello')
2072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected = compress.compress('\x81\x05Hello')
2082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += compress.flush(zlib.Z_SYNC_FLUSH)
2092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(expected, request.connection.written_data())
2102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message_deflate_frame(self):
2122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
2132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
2142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
2162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(
2172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            '', deflate_frame_request=extension)
2182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello')
2192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'World')
2202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected = ''
2222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compress.compress('Hello')
2242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello += compress.flush(zlib.Z_SYNC_FLUSH)
2252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compressed_hello[:-4]
2262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += '\xc1%c' % len(compressed_hello)
2272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += compressed_hello
2282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compress.compress('World')
2302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world += compress.flush(zlib.Z_SYNC_FLUSH)
2312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compressed_world[:-4]
2322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += '\xc1%c' % len(compressed_world)
2332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += compressed_world
2342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(expected, request.connection.written_data())
2362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message_deflate_frame_comp_bit(self):
2382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
2392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
2402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
2422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(
2432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            '', deflate_frame_request=extension)
2442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEquals(1, len(request.ws_extension_processors))
2452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        deflate_frame_processor = request.ws_extension_processors[0]
2462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello')
2472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        deflate_frame_processor.disable_outgoing_compression()
2482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello')
2492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        deflate_frame_processor.enable_outgoing_compression()
2502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello')
2512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected = ''
2532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compress.compress('Hello')
2552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello += compress.flush(zlib.Z_SYNC_FLUSH)
2562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compressed_hello[:-4]
2572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += '\xc1%c' % len(compressed_hello)
2582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += compressed_hello
2592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += '\x81\x05Hello'
2612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_2nd_hello = compress.compress('Hello')
2632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_2nd_hello += compress.flush(zlib.Z_SYNC_FLUSH)
2642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_2nd_hello = compressed_2nd_hello[:-4]
2652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += '\xc1%c' % len(compressed_2nd_hello)
2662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += compressed_2nd_hello
2672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(expected, request.connection.written_data())
2692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message_deflate_frame_no_context_takeover_parameter(self):
2712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
2722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
2732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
2752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension.add_parameter('no_context_takeover', None)
2762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(
2772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            '', deflate_frame_request=extension)
2782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        for i in xrange(3):
2792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            msgutil.send_message(request, 'Hello')
2802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_message = compress.compress('Hello')
2822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_message += compress.flush(zlib.Z_SYNC_FLUSH)
2832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_message = compressed_message[:-4]
2842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected = '\xc1%c' % len(compressed_message)
2852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += compressed_message
2862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(
2882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            expected + expected + expected, request.connection.written_data())
2892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_deflate_frame_bad_request_parameters(self):
2912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        """Tests that if there's anything wrong with deflate-frame extension
2922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request, deflate-frame is rejected.
2932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        """
2942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
2962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # max_window_bits less than 8 is illegal.
2972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension.add_parameter('max_window_bits', '7')
2982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor = DeflateFrameExtensionProcessor(extension)
2992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, processor.get_extension_response())
3002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
3022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # max_window_bits greater than 15 is illegal.
3032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension.add_parameter('max_window_bits', '16')
3042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor = DeflateFrameExtensionProcessor(extension)
3052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, processor.get_extension_response())
3062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
3082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Non integer max_window_bits is illegal.
3092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension.add_parameter('max_window_bits', 'foobar')
3102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor = DeflateFrameExtensionProcessor(extension)
3112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, processor.get_extension_response())
3122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
3142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # no_context_takeover must not have any value.
3152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension.add_parameter('no_context_takeover', 'foobar')
3162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor = DeflateFrameExtensionProcessor(extension)
3172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, processor.get_extension_response())
3182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_deflate_frame_response_parameters(self):
3202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
3212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor = DeflateFrameExtensionProcessor(extension)
3222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor.set_response_window_bits(8)
3232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        response = processor.get_extension_response()
3242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertTrue(response.has_parameter('max_window_bits'))
3252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('8', response.get_parameter_value('max_window_bits'))
3262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
3282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor = DeflateFrameExtensionProcessor(extension)
3292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        processor.set_response_no_context_takeover(True)
3302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        response = processor.get_extension_response()
3312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertTrue(response.has_parameter('no_context_takeover'))
3322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertTrue(
3332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            response.get_parameter_value('no_context_takeover') is None)
3342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message_perframe_compress_deflate(self):
3362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
3372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
3382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(
3392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            common.PERFRAME_COMPRESSION_EXTENSION)
3402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension.add_parameter('method', 'deflate')
3412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(
3422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                      '', perframe_compression_request=extension)
3432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello')
3442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'World')
3452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected = ''
3472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compress.compress('Hello')
3492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello += compress.flush(zlib.Z_SYNC_FLUSH)
3502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compressed_hello[:-4]
3512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += '\xc1%c' % len(compressed_hello)
3522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += compressed_hello
3532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compress.compress('World')
3552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world += compress.flush(zlib.Z_SYNC_FLUSH)
3562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compressed_world[:-4]
3572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += '\xc1%c' % len(compressed_world)
3582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += compressed_world
3592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(expected, request.connection.written_data())
3612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message_permessage_compress_deflate(self):
3632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
3642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
3652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(
3662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            common.PERMESSAGE_COMPRESSION_EXTENSION)
3672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension.add_parameter('method', 'deflate')
3682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(
3692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                      '', permessage_compression_request=extension)
3702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello')
3712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'World')
3722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected = ''
3742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compress.compress('Hello')
3762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello += compress.flush(zlib.Z_SYNC_FLUSH)
3772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compressed_hello[:-4]
3782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += '\xc1%c' % len(compressed_hello)
3792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += compressed_hello
3802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compress.compress('World')
3822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world += compress.flush(zlib.Z_SYNC_FLUSH)
3832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compressed_world[:-4]
3842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += '\xc1%c' % len(compressed_world)
3852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        expected += compressed_world
3862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(expected, request.connection.written_data())
3882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message(self):
3902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
3912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x81\x85', 'Hello'), ('\x81\x86', 'World!'))
3922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello', msgutil.receive_message(request))
3932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World!', msgutil.receive_message(request))
3942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        payload = 'a' * 125
3962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(('\x81\xfd', payload))
3972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(payload, msgutil.receive_message(request))
3982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
3992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_medium_message(self):
4002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        payload = 'a' * 126
4012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(('\x81\xfe\x00\x7e', payload))
4022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(payload, msgutil.receive_message(request))
4032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        payload = 'a' * ((1 << 16) - 1)
4052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(('\x81\xfe\xff\xff', payload))
4062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(payload, msgutil.receive_message(request))
4072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_large_message(self):
4092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        payload = 'a' * (1 << 16)
4102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
4112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x81\xff\x00\x00\x00\x00\x00\x01\x00\x00', payload))
4122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(payload, msgutil.receive_message(request))
4132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_length_not_encoded_using_minimal_number_of_bytes(self):
4152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Log warning on receiving bad payload length field that doesn't use
4162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # minimal number of bytes but continue processing.
4172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        payload = 'a'
4192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # 1 byte can be represented without extended payload length field.
4202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
4212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x81\xff\x00\x00\x00\x00\x00\x00\x00\x01', payload))
4222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(payload, msgutil.receive_message(request))
4232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_unicode(self):
4252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(('\x81\x83', '\xe6\x9c\xac'))
4262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # U+672c is encoded as e6,9c,ac in UTF-8
4272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(u'\u672c', msgutil.receive_message(request))
4282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_erroneous_unicode(self):
4302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # \x80 and \x81 are invalid as UTF-8.
4312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(('\x81\x82', '\x80\x81'))
4322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Invalid characters should raise InvalidUTF8Exception
4332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(InvalidUTF8Exception,
4342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          msgutil.receive_message,
4352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          request)
4362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_fragments(self):
4382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
4392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x01\x85', 'Hello'),
4402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x00\x81', ' '),
4412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x00\x85', 'World'),
4422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x80\x81', '!'))
4432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello World!', msgutil.receive_message(request))
4442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_fragments_unicode(self):
4462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # UTF-8 encodes U+6f22 into e6bca2 and U+5b57 into e5ad97.
4472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
4482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x01\x82', '\xe6\xbc'),
4492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x00\x82', '\xa2\xe5'),
4502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x80\x82', '\xad\x97'))
4512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(u'\u6f22\u5b57', msgutil.receive_message(request))
4522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_fragments_immediate_zero_termination(self):
4542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
4552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x01\x8c', 'Hello World!'), ('\x80\x80', ''))
4562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello World!', msgutil.receive_message(request))
4572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_fragments_duplicate_start(self):
4592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
4602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x01\x85', 'Hello'), ('\x01\x85', 'World'))
4612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.InvalidFrameException,
4622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          msgutil.receive_message,
4632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          request)
4642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_fragments_intermediate_but_not_started(self):
4662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(('\x00\x85', 'Hello'))
4672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.InvalidFrameException,
4682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          msgutil.receive_message,
4692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          request)
4702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_fragments_end_but_not_started(self):
4722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(('\x80\x85', 'Hello'))
4732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.InvalidFrameException,
4742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          msgutil.receive_message,
4752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          request)
4762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_discard(self):
4782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
4792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x8f\x86', 'IGNORE'), ('\x81\x85', 'Hello'),
4802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x8f\x89', 'DISREGARD'), ('\x81\x86', 'World!'))
4812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.UnsupportedFrameException,
4822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          msgutil.receive_message, request)
4832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello', msgutil.receive_message(request))
4842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.UnsupportedFrameException,
4852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          msgutil.receive_message, request)
4862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World!', msgutil.receive_message(request))
4872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_close(self):
4892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
4902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x88\x8a', struct.pack('!H', 1000) + 'Good bye'))
4912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, msgutil.receive_message(request))
4922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(1000, request.ws_close_code)
4932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Good bye', request.ws_close_reason)
4942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_deflate_stream(self):
4962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
4972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
4982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
4992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data = compress.compress('\x81\x85' + _mask_hybi('Hello'))
5002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += compress.flush(zlib.Z_SYNC_FLUSH)
5012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += compress.compress('\x81\x89' + _mask_hybi('WebSocket'))
5022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += compress.flush(zlib.Z_FINISH)
5032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
5052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
5062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += compress.compress('\x81\x85' + _mask_hybi('World'))
5082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += compress.flush(zlib.Z_SYNC_FLUSH)
5092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Close frame
5102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += compress.compress(
5112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            '\x88\x8a' + _mask_hybi(struct.pack('!H', 1000) + 'Good bye'))
5122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += compress.flush(zlib.Z_SYNC_FLUSH)
5132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(data, deflate_stream=True)
5152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello', msgutil.receive_message(request))
5162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('WebSocket', msgutil.receive_message(request))
5172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World', msgutil.receive_message(request))
5182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertFalse(request.drain_received_data_called)
5202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, msgutil.receive_message(request))
5222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertTrue(request.drain_received_data_called)
5242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_deflate_frame(self):
5262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
5272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
5282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data = ''
5302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compress.compress('Hello')
5322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello += compress.flush(zlib.Z_SYNC_FLUSH)
5332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compressed_hello[:-4]
5342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\xc1%c' % (len(compressed_hello) | 0x80)
5352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_hello)
5362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_websocket = compress.compress('WebSocket')
5382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_websocket += compress.flush(zlib.Z_FINISH)
5392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_websocket += '\x00'
5402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\xc1%c' % (len(compressed_websocket) | 0x80)
5412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_websocket)
5422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
5442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
5452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compress.compress('World')
5472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world += compress.flush(zlib.Z_SYNC_FLUSH)
5482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compressed_world[:-4]
5492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\xc1%c' % (len(compressed_world) | 0x80)
5502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_world)
5512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Close frame
5532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\x88\x8a' + _mask_hybi(struct.pack('!H', 1000) + 'Good bye')
5542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
5562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(
5572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            data, deflate_frame_request=extension)
5582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello', msgutil.receive_message(request))
5592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('WebSocket', msgutil.receive_message(request))
5602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World', msgutil.receive_message(request))
5612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, msgutil.receive_message(request))
5632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_deflate_frame_client_using_smaller_window(self):
5652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        """Test that frames coming from a client which is using smaller window
5662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        size that the server are correctly received.
5672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        """
5682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Using the smallest window bits of 8 for generating input frames.
5702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
5712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -8)
5722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data = ''
5742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Use a frame whose content is bigger than the clients' DEFLATE window
5762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # size before compression. The content mainly consists of 'a' but
5772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # repetition of 'b' is put at the head and tail so that if the window
5782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # size is big, the head is back-referenced but if small, not.
5792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        payload = 'b' * 64 + 'a' * 1024 + 'b' * 64
5802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compress.compress(payload)
5812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello += compress.flush(zlib.Z_SYNC_FLUSH)
5822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compressed_hello[:-4]
5832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\xc1%c' % (len(compressed_hello) | 0x80)
5842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_hello)
5852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Close frame
5872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\x88\x8a' + _mask_hybi(struct.pack('!H', 1000) + 'Good bye')
5882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
5902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(
5912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            data, deflate_frame_request=extension)
5922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(payload, msgutil.receive_message(request))
5932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, msgutil.receive_message(request))
5952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
5962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_deflate_frame_comp_bit(self):
5972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
5982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
5992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data = ''
6012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compress.compress('Hello')
6032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello += compress.flush(zlib.Z_SYNC_FLUSH)
6042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compressed_hello[:-4]
6052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\xc1%c' % (len(compressed_hello) | 0x80)
6062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_hello)
6072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\x81\x85' + _mask_hybi('Hello')
6092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
6112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
6122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_2nd_hello = compress.compress('Hello')
6142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_2nd_hello += compress.flush(zlib.Z_SYNC_FLUSH)
6152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_2nd_hello = compressed_2nd_hello[:-4]
6162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\xc1%c' % (len(compressed_2nd_hello) | 0x80)
6172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_2nd_hello)
6182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(common.DEFLATE_FRAME_EXTENSION)
6202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(
6212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            data, deflate_frame_request=extension)
6222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        for i in xrange(3):
6232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            self.assertEqual('Hello', msgutil.receive_message(request))
6242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_perframe_compression_frame(self):
6262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
6272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
6282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data = ''
6302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compress.compress('Hello')
6322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello += compress.flush(zlib.Z_SYNC_FLUSH)
6332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compressed_hello[:-4]
6342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\xc1%c' % (len(compressed_hello) | 0x80)
6352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_hello)
6362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_websocket = compress.compress('WebSocket')
6382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_websocket += compress.flush(zlib.Z_FINISH)
6392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_websocket += '\x00'
6402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\xc1%c' % (len(compressed_websocket) | 0x80)
6412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_websocket)
6422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
6442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
6452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compress.compress('World')
6472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world += compress.flush(zlib.Z_SYNC_FLUSH)
6482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compressed_world[:-4]
6492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\xc1%c' % (len(compressed_world) | 0x80)
6502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_world)
6512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Close frame
6532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\x88\x8a' + _mask_hybi(struct.pack('!H', 1000) + 'Good bye')
6542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(
6562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            common.PERFRAME_COMPRESSION_EXTENSION)
6572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension.add_parameter('method', 'deflate')
6582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(
6592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            data, perframe_compression_request=extension)
6602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello', msgutil.receive_message(request))
6612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('WebSocket', msgutil.receive_message(request))
6622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World', msgutil.receive_message(request))
6632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, msgutil.receive_message(request))
6652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_permessage_deflate_compression(self):
6672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
6682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
6692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data = ''
6712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compress.compress('HelloWebSocket')
6732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello += compress.flush(zlib.Z_SYNC_FLUSH)
6742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_hello = compressed_hello[:-4]
6752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        split_position = len(compressed_hello) / 2
6762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\x41%c' % (split_position | 0x80)
6772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_hello[:split_position])
6782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\x80%c' % ((len(compressed_hello) - split_position) | 0x80)
6802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_hello[split_position:])
6812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compress = zlib.compressobj(
6832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -zlib.MAX_WBITS)
6842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compress.compress('World')
6862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world += compress.flush(zlib.Z_SYNC_FLUSH)
6872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        compressed_world = compressed_world[:-4]
6882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\xc1%c' % (len(compressed_world) | 0x80)
6892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += _mask_hybi(compressed_world)
6902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Close frame
6922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        data += '\x88\x8a' + _mask_hybi(struct.pack('!H', 1000) + 'Good bye')
6932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
6942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension = common.ExtensionParameter(
6952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            common.PERMESSAGE_COMPRESSION_EXTENSION)
6962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        extension.add_parameter('method', 'deflate')
6972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_from_rawdata(
6982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            data, permessage_compression_request=extension)
6992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('HelloWebSocket', msgutil.receive_message(request))
7002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World', msgutil.receive_message(request))
7012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, msgutil.receive_message(request))
7032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_longest_close(self):
7052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        reason = 'a' * 123
7062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
7072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x88\xfd',
7082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis             struct.pack('!H', common.STATUS_NORMAL_CLOSURE) + reason))
7092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request.ws_stream.close_connection(common.STATUS_NORMAL_CLOSURE,
7102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                           reason)
7112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(request.ws_close_code, common.STATUS_NORMAL_CLOSURE)
7122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(request.ws_close_reason, reason)
7132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_close_too_long(self):
7152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
7162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.BadOperationException,
7172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          Stream.close_connection,
7182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          request.ws_stream,
7192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          common.STATUS_NORMAL_CLOSURE,
7202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          'a' * 124)
7212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_close_inconsistent_code_and_reason(self):
7232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
7242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # reason parameter must not be specified when code is None.
7252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.BadOperationException,
7262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          Stream.close_connection,
7272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          request.ws_stream,
7282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          None,
7292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          'a')
7302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_ping(self):
7322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
7332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_ping(request, 'Hello World!')
7342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x89\x0cHello World!',
7352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
7362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_longest_ping(self):
7382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
7392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_ping(request, 'a' * 125)
7402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x89\x7d' + 'a' * 125,
7412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
7422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_ping_too_long(self):
7442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request()
7452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.BadOperationException,
7462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          msgutil.send_ping,
7472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          request,
7482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          'a' * 126)
7492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_ping(self):
7512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        """Tests receiving a ping control frame."""
7522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        def handler(request, message):
7542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            request.called = True
7552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Stream automatically respond to ping with pong without any action
7572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # by application layer.
7582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
7592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x89\x85', 'Hello'), ('\x81\x85', 'World'))
7602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World', msgutil.receive_message(request))
7612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x8a\x05Hello',
7622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
7632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
7652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x89\x85', 'Hello'), ('\x81\x85', 'World'))
7662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request.on_ping_handler = handler
7672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World', msgutil.receive_message(request))
7682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertTrue(request.called)
7692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_longest_ping(self):
7712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
7722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x89\xfd', 'a' * 125), ('\x81\x85', 'World'))
7732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World', msgutil.receive_message(request))
7742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x8a\x7d' + 'a' * 125,
7752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
7762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_ping_too_long(self):
7782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(('\x89\xfe\x00\x7e', 'a' * 126))
7792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.InvalidFrameException,
7802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          msgutil.receive_message,
7812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          request)
7822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_pong(self):
7842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        """Tests receiving a pong control frame."""
7852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        def handler(request, message):
7872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            request.called = True
7882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
7892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
7902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x8a\x85', 'Hello'), ('\x81\x85', 'World'))
7912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request.on_pong_handler = handler
7922da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_ping(request, 'Hello')
7932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x89\x05Hello',
7942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
7952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Valid pong is received, but receive_message won't return for it.
7962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World', msgutil.receive_message(request))
7972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Check that nothing was written after receive_message call.
7982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x89\x05Hello',
7992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
8002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertTrue(request.called)
8022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_unsolicited_pong(self):
8042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Unsolicited pong is allowed from HyBi 07.
8052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
8062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x8a\x85', 'Hello'), ('\x81\x85', 'World'))
8072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.receive_message(request)
8082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(
8102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            ('\x8a\x85', 'Hello'), ('\x81\x85', 'World'))
8112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_ping(request, 'Jumbo')
8122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Body mismatch.
8132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.receive_message(request)
8142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_ping_cannot_be_fragmented(self):
8162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(('\x09\x85', 'Hello'))
8172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.InvalidFrameException,
8182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          msgutil.receive_message,
8192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          request)
8202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_ping_with_too_long_payload(self):
8222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request(('\x89\xfe\x01\x00', 'a' * 256))
8232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertRaises(msgutil.InvalidFrameException,
8242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          msgutil.receive_message,
8252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                          request)
8262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8282da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass MessageTestHixie75(unittest.TestCase):
8292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    """Tests for draft-hixie-thewebsocketprotocol-76 stream class."""
8302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message(self):
8322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_hixie75()
8332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, 'Hello')
8342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x00Hello\xff', request.connection.written_data())
8352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_message_unicode(self):
8372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_hixie75()
8382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        msgutil.send_message(request, u'\u65e5')
8392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # U+65e5 is encoded as e6,97,a5 in UTF-8
8402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x00\xe6\x97\xa5\xff',
8412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                         request.connection.written_data())
8422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message(self):
8442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_hixie75('\x00Hello\xff\x00World!\xff')
8452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello', msgutil.receive_message(request))
8462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World!', msgutil.receive_message(request))
8472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_unicode(self):
8492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_hixie75('\x00\xe6\x9c\xac\xff')
8502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # U+672c is encoded as e6,9c,ac in UTF-8
8512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(u'\u672c', msgutil.receive_message(request))
8522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_erroneous_unicode(self):
8542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # \x80 and \x81 are invalid as UTF-8.
8552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_hixie75('\x00\x80\x81\xff')
8562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Invalid characters should be replaced with
8572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # U+fffd REPLACEMENT CHARACTER
8582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(u'\ufffd\ufffd', msgutil.receive_message(request))
8592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_receive_message_discard(self):
8612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_request_hixie75('\x80\x06IGNORE\x00Hello\xff'
8622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                                          '\x01DISREGARD\xff\x00World!\xff')
8632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello', msgutil.receive_message(request))
8642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('World!', msgutil.receive_message(request))
8652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8672da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass MessageReceiverTest(unittest.TestCase):
8682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    """Tests the Stream class using MessageReceiver."""
8692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_queue(self):
8712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_blocking_request()
8722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        receiver = msgutil.MessageReceiver(request)
8732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, receiver.receive_nowait())
8752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request.connection.put_bytes('\x81\x86' + _mask_hybi('Hello!'))
8772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello!', receiver.receive())
8782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_onmessage(self):
8802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        onmessage_queue = Queue.Queue()
8812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8822da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        def onmessage_handler(message):
8832da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            onmessage_queue.put(message)
8842da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8852da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_blocking_request()
8862da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        receiver = msgutil.MessageReceiver(request, onmessage_handler)
8872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request.connection.put_bytes('\x81\x86' + _mask_hybi('Hello!'))
8892da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello!', onmessage_queue.get())
8902da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8912da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8922da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass MessageReceiverHixie75Test(unittest.TestCase):
8932da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    """Tests the StreamHixie75 class using MessageReceiver."""
8942da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_queue(self):
8962da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_blocking_request_hixie75()
8972da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        receiver = msgutil.MessageReceiver(request)
8982da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
8992da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual(None, receiver.receive_nowait())
9002da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9012da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request.connection.put_bytes('\x00Hello!\xff')
9022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello!', receiver.receive())
9032da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9042da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_onmessage(self):
9052da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        onmessage_queue = Queue.Queue()
9062da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9072da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        def onmessage_handler(message):
9082da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            onmessage_queue.put(message)
9092da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9102da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_blocking_request_hixie75()
9112da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        receiver = msgutil.MessageReceiver(request, onmessage_handler)
9122da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9132da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request.connection.put_bytes('\x00Hello!\xff')
9142da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('Hello!', onmessage_queue.get())
9152da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9162da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9172da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass MessageSenderTest(unittest.TestCase):
9182da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    """Tests the Stream class using MessageSender."""
9192da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9202da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send(self):
9212da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_blocking_request()
9222da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        sender = msgutil.MessageSender(request)
9232da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9242da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        sender.send('World')
9252da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x81\x05World', request.connection.written_data())
9262da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9272da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_nowait(self):
9282da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Use a queue to check the bytes written by MessageSender.
9292da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # request.connection.written_data() cannot be used here because
9302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # MessageSender runs in a separate thread.
9312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        send_queue = Queue.Queue()
9322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        def write(bytes):
9342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            send_queue.put(bytes)
9352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_blocking_request()
9372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request.connection.write = write
9382da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        sender = msgutil.MessageSender(request)
9402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        sender.send_nowait('Hello')
9422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        sender.send_nowait('World')
9432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x81\x05Hello', send_queue.get())
9442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x81\x05World', send_queue.get())
9452da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9472da489cd246702bee5938545b18a6f710ed214bcJamie Gennisclass MessageSenderHixie75Test(unittest.TestCase):
9482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    """Tests the StreamHixie75 class using MessageSender."""
9492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send(self):
9512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_blocking_request_hixie75()
9522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        sender = msgutil.MessageSender(request)
9532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        sender.send('World')
9552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x00World\xff', request.connection.written_data())
9562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    def test_send_nowait(self):
9582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # Use a queue to check the bytes written by MessageSender.
9592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # request.connection.written_data() cannot be used here because
9602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        # MessageSender runs in a separate thread.
9612da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        send_queue = Queue.Queue()
9622da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9632da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        def write(bytes):
9642da489cd246702bee5938545b18a6f710ed214bcJamie Gennis            send_queue.put(bytes)
9652da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9662da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request = _create_blocking_request_hixie75()
9672da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        request.connection.write = write
9682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9692da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        sender = msgutil.MessageSender(request)
9702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        sender.send_nowait('Hello')
9722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        sender.send_nowait('World')
9732da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x00Hello\xff', send_queue.get())
9742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis        self.assertEqual('\x00World\xff', send_queue.get())
9752da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9772da489cd246702bee5938545b18a6f710ed214bcJamie Gennisif __name__ == '__main__':
9782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    unittest.main()
9792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
9812da489cd246702bee5938545b18a6f710ed214bcJamie Gennis# vi:sts=4 sw=4 et
982