def test_helper_with_binary_message(self):
     msg = os.urandom(16)
     s = Stream()
     m = s.binary_message(msg)
     self.assertIsInstance(m, BinaryMessage)
     self.assertTrue(m.is_binary)
     self.assertFalse(m.is_text)
     self.assertEqual(m.opcode, OPCODE_BINARY)
     self.assertIsInstance(m.data, bytes)
     self.assertEqual(len(m), 16)
     self.assertEqual(len(m.data), 16)
     self.assertEqual(m.data, msg)
class WebSocketBaseClient(object):
    upgrade_header = 'Upgrade'

    def __init__(self, url, protocols=None, version='8'):
        self.stream = Stream()
        self.url = url
        self.protocols = protocols
        self.version = version
        self.key = b64encode(os.urandom(16))
        self.client_terminated = False
        self.server_terminated = False

    @property
    def handshake_headers(self):
        parts = urlsplit(self.url)
        host = parts.netloc
        if ':' in host:
            host, port = parts.netloc.split(':')

        headers = [('Host', host), ('Connection', 'Upgrade'),
                   (self.upgrade_header, 'websocket'),
                   ('Sec-WebSocket-Key', self.key),
                   ('Sec-WebSocket-Origin', self.url),
                   ('Sec-WebSocket-Version', self.version)]

        if self.protocols:
            headers.append(
                ('Sec-WebSocket-Protocol', ','.join(self.protocols)))

        return headers

    @property
    def handshake_request(self):
        parts = urlsplit(self.url)

        headers = self.handshake_headers
        request = ["GET %s HTTP/1.1" % parts.path]
        for header, value in headers:
            request.append("%s: %s" % (header, value))
        request.append('\r\n')

        return '\r\n'.join(request)

    def process_response_line(self, response_line):
        protocol, code, status = response_line.split(' ', 2)
        if code != '101':
            raise HandshakeError("Invalid response status: %s %s" %
                                 (code, status))

    def process_handshake_header(self, headers):
        protocols = []
        extensions = []

        headers = headers.strip()

        for header_line in headers.split('\r\n'):
            header, value = header_line.split(':', 1)
            header = header.strip().lower()
            value = value.strip().lower()

            if header == 'upgrade' and value != 'websocket':
                raise HandshakeError("Invalid Upgrade header: %s" % value)

            elif header == 'connection' and value != 'upgrade':
                raise HandshakeError("Invalid Connection header: %s" % value)

            elif header == 'sec-websocket-accept':
                match = b64encode(sha1(self.key + WS_KEY).digest())
                if value != match.lower():
                    raise HandshakeError("Invalid challenge response: %s" %
                                         value)

            elif header == 'sec-websocket-protocol':
                protocols = ','.join(value)

            elif header == 'sec-websocket-extensions':
                extensions = ','.join(value)

        return protocols, extensions

    def opened(self, protocols, extensions):
        pass

    def received_message(self, m):
        pass

    def closed(self, code, reason=None):
        pass

    @property
    def terminated(self):
        return self.client_terminated is True and self.server_terminated is True

    def close(self, reason='', code=1000):
        if not self.client_terminated:
            self.client_terminated = True
            self.write_to_connection(
                self.stream.close(code=code, reason=reason))

    def connect(self):
        raise NotImplemented()

    def write_to_connection(self, bytes):
        raise NotImplemented()

    def read_from_connection(self, amount):
        raise NotImplemented()

    def close_connection(self):
        raise NotImplemented()

    def send(self, payload, binary=False):
        if isinstance(payload, basestring):
            if not binary:
                self.write_to_connection(
                    self.stream.text_message(payload).single(mask=True))
            else:
                self.write_to_connection(
                    self.stream.binary_message(payload).single(mask=True))

        elif isinstance(payload, dict):
            self.write_to_connection(
                self.stream.text_message(
                    json.dumps(payload)).single(mask=True))

        elif type(payload) == types.GeneratorType:
            bytes = payload.next()
            first = True
            for chunk in payload:
                if not binary:
                    self.write_to_connection(
                        self.stream.text_message(bytes).fragment(first=first,
                                                                 mask=True))
                else:
                    self.write_to_connection(
                        self.stream.binary_message(payload).fragment(
                            first=first, mask=True))
                bytes = chunk
                first = False
            if not binary:
                self.write_to_connection(
                    self.stream.text_message(bytes).fragment(last=True,
                                                             mask=True))
            else:
                self.write_to_connection(
                    self.stream.text_message(bytes).fragment(last=True,
                                                             mask=True))
class WebSocketHandler(object):
    def __init__(self, sock, protocols, extensions):
        """
        A handler appropriate for servers. This handler
        runs the connection's read and parsing in a thread,
        meaning that incoming messages will be alerted in a different
        thread from the one that created the handler.

        @param sock: opened connection after the websocket upgrade
        @param protocols: list of protocols from the handshake
        @param extensions: list of extensions from the handshake
        """
        self.stream = Stream()
        
        self.protocols = protocols
        self.extensions = extensions

        self.sock = sock
        self.sock.settimeout(30.0)
        
        self.client_terminated = False
        self.server_terminated = False

        self._th = threading.Thread(target=self._receive)

    def opened(self):
        """
        Called by the server when the upgrade handshake
        has succeeeded. Starts the internal loop that
        reads bytes from the connection and hands it over
        to the stream for parsing.
        """
        self._th.start()

    def close(self, code=1000, reason=''):
        """
        Call this method to initiate the websocket connection
        closing by sending a close frame to the connected peer.

        Once this method is called, the server_terminated
        attribute is set. Calling this method several times is
        safe as the closing frame will be sent only the first
        time.

        @param code: status code describing why the connection is closed
        @param reason: a human readable message describing why the connection is closed
        """
        if not self.server_terminated:
            self.server_terminated = True
            self.write_to_connection(self.stream.close(code=code, reason=reason))
            
    def closed(self, code, reason=None):
        """
        Called by the server when the websocket connection
        is finally closed.

        @param code: status code
        @param reason: human readable message of the closing exchange
        """
        pass

    @property
    def terminated(self):
        """
        Returns True if both the client and server have been
        marked as terminated.
        """
        return self.client_terminated is True and self.server_terminated is True
    
    def write_to_connection(self, bytes):
        """
        Writes the provided bytes to the underlying connection.

        @param bytes: data tio send out
        """
        return self.sock.sendall(bytes)

    def read_from_connection(self, amount):
        """
        Reads bytes from the underlying connection.

        @param amount: quantity to read (if possible)
        """
        return self.sock.recv(amount)
        
    def close_connection(self):
        """
        Shutdowns then closes the underlying connection.
        """
        try:
            self.sock.shutdown(socket.SHUT_RDWR)
            self.sock.close()
        except:
            pass

    def ponged(self, pong):
        """
        Pong message received on the stream.

        @param pong: messaging.PongControlMessage instance
        """
        pass

    def received_message(self, m):
        """
        Message received on the stream.

        @param pong: messaging.TextMessage or messaging.BinaryMessage instance
        """
        pass

    def send(self, payload, binary=False):
        """
        Sends the given payload out.

        If payload is some bytes or a bytearray,
        then it is sent as a single message not fragmented.

        If payload is a generator, each chunk is sent as part of
        fragmented message.

        @param payload: string, bytes, bytearray or a generator
        @param binary: if set, handles the payload as a binary message
        """
        if isinstance(payload, basestring) or isinstance(payload, bytearray):
            if not binary:
                self.write_to_connection(self.stream.text_message(payload).single())
            else:
                self.write_to_connection(self.stream.binary_message(payload).single())
                
        elif type(payload) == types.GeneratorType:
            bytes = payload.next()
            first = True
            for chunk in payload:
                if not binary:
                    self.write_to_connection(self.stream.text_message(bytes).fragment(first=first))
                else:
                    self.write_to_connection(self.stream.binary_message(payload).fragment(first=first))
                bytes = chunk
                first = False
            if not binary:
                self.write_to_connection(self.stream.text_message(bytes).fragment(last=True))
            else:
                self.write_to_connection(self.stream.text_message(bytes).fragment(last=True))

    def _receive(self):
        """
        Performs the operation of reading from the underlying
        connection in order to feed the stream of bytes.

        We start with a small size of two bytes to be read
        from the connection so that we can quickly parse an
        incoming frame header. Then the stream indicates
        whatever size must be read from the connection since
        it knows the frame payload length.

        Note that we perform some automatic opererations:

        * On a closing message, we respond with a closing
          message and finally close the connection
        * We respond to pings with pong messages.
        * Whenever an error is raised by the stream parsing,
          we initiate the closing of the connection with the
          appropiate error code.
        """
        next_size = 2
        try:
            self.sock.setblocking(1)
            while not self.terminated:
                bytes = self.read_from_connection(next_size)
                if not bytes and next_size > 0:
                    break

                s = self.stream
                next_size = s.parser.send(bytes)

                if s.closing is not None:
                    if not self.server_terminated:
                        next_size = 2
                        self.close(s.closing.code, s.closing.reason)
                    else:
                        self.client_terminated = True
                        break

                elif s.errors:
                    errors = s.errors[:]
                    for error in errors:
                        self.close(error.code, error.reason)
                        s.errors.remove(error)
                    break

                elif s.has_message:
                    self.received_message(s.message)
                    s.message.data = None
                    s.message = None

                for ping in s.pings:
                    self.write_to_connection(s.pong(str(ping.data)))
                s.pings = []

                for pong in s.pongs:
                    self.ponged(pong)
                s.pongs = []
                    
        except:
            print "".join(traceback.format_exception(*exc_info()))
        finally:
            self.client_terminated = self.server_terminated = True
            self.close_connection()
        if self.stream.closing:
            self.closed(self.stream.closing.code, self.stream.closing.reason)
        else:
            self.closed(1006)
Beispiel #4
0
class WebSocketBaseClient(object):
    def __init__(self, url, protocols=None, version='8'):
        self.stream = Stream()
        self.url = url
        self.protocols = protocols
        self.version = version
        self.key = b64encode(os.urandom(16))
        self.client_terminated = False
        self.server_terminated = False
        
    @property
    def handshake_headers(self):
        parts = urlsplit(self.url)
        host = parts.netloc
        if ':' in host:
            host, port = parts.netloc.split(':')
            
        headers = [
            ('Host', host),
            ('Connection', 'Upgrade'),
            ('Upgrade', 'websocket'),
            ('Sec-WebSocket-Key', self.key),
            ('Sec-WebSocket-Origin', self.url),
            ('Sec-WebSocket-Version', self.version)
            ]
        
        if self.protocols:
            headers.append(('Sec-WebSocket-Protocol', ','.join(self.protocols)))

        return headers

    @property
    def handshake_request(self):
        parts = urlsplit(self.url)
        
        headers = self.handshake_headers
        request = ["GET %s HTTP/1.1" % parts.path]
        for header, value in headers:
            request.append("%s: %s" % (header, value))
        request.append('\r\n')

        return '\r\n'.join(request)

    def process_response_line(self, response_line):
        protocol, code, status = response_line.split(' ', 2)
        if code != '101':
            raise HandshakeError("Invalid response status: %s %s" % (code, status))

    def process_handshake_header(self, headers):
        protocols = []
        extensions = []

        headers = headers.strip()
        
        for header_line in headers.split('\r\n'):
            header, value = header_line.split(':', 1)
            header = header.strip().lower()
            value = value.strip().lower()
            
            if header == 'upgrade' and value != 'websocket':
                raise HandshakeError("Invalid Upgrade header: %s" % value)

            elif header == 'connection' and value != 'upgrade':
                raise HandshakeError("Invalid Connection header: %s" % value)

            elif header == 'sec-websocket-accept':
                match = b64encode(sha1(self.key + WS_KEY).digest())
                if value != match.lower():
                    raise HandshakeError("Invalid challenge response: %s" % value)

            elif header == 'sec-websocket-protocol':
                protocols = ','.join(value)

            elif header == 'sec-websocket-extensions':
                extensions = ','.join(value)

        return protocols, extensions

    def opened(self, protocols, extensions):
        pass

    def received_message(self, m):
        pass

    def closed(self, code, reason=None):
        pass

    @property
    def terminated(self):
        return self.client_terminated is True and self.server_terminated is True
    
    def close(self, reason='', code=1000):
        if not self.client_terminated:
            self.client_terminated = True
            self.write_to_connection(self.stream.close(code=code, reason=reason))

    def connect(self):
        raise NotImplemented()

    def write_to_connection(self, bytes):
        raise NotImplemented()

    def read_from_connection(self, amount):
        raise NotImplemented()

    def close_connection(self):
        raise NotImplemented()
               
    def send(self, payload, binary=False):
        if isinstance(payload, basestring):
            if not binary:
                self.write_to_connection(self.stream.text_message(payload).single(mask=True))
            else:
                self.write_to_connection(self.stream.binary_message(payload).single(mask=True))
        
        elif isinstance(payload, dict):
            self.write_to_connection(self.stream.text_message(json.dumps(payload)).single(mask=True))
        
        elif type(payload) == types.GeneratorType:
            bytes = payload.next()
            first = True
            for chunk in payload:
                if not binary:
                    self.write_to_connection(self.stream.text_message(bytes).fragment(first=first, mask=True))
                else:
                    self.write_to_connection(self.stream.binary_message(payload).fragment(first=first, mask=True))
                bytes = chunk
                first = False
            if not binary:
                self.write_to_connection(self.stream.text_message(bytes).fragment(last=True, mask=True))
            else:
                self.write_to_connection(self.stream.text_message(bytes).fragment(last=True, mask=True))
class WebSocketHandler(object):
    def __init__(self, sock, protocols, extensions):
        """
        A handler appropriate for servers. This handler
        runs the connection's read and parsing in a thread,
        meaning that incoming messages will be alerted in a different
        thread from the one that created the handler.

        @param sock: opened connection after the websocket upgrade
        @param protocols: list of protocols from the handshake
        @param extensions: list of extensions from the handshake
        """
        self.stream = Stream()

        self.protocols = protocols
        self.extensions = extensions

        self.sock = sock
        self.sock.settimeout(30.0)

        self.client_terminated = False
        self.server_terminated = False

        self._lock = threading.Lock()
        self._th = threading.Thread(target=self._receive)

    def opened(self):
        """
        Called by the server when the upgrade handshake
        has succeeeded. Starts the internal loop that
        reads bytes from the connection and hands it over
        to the stream for parsing.
        """
        self._th.start()

    def close(self, code=1000, reason=''):
        """
        Call this method to initiate the websocket connection
        closing by sending a close frame to the connected peer.

        Once this method is called, the server_terminated
        attribute is set. Calling this method several times is
        safe as the closing frame will be sent only the first
        time.

        @param code: status code describing why the connection is closed
        @param reason: a human readable message describing why the connection is closed
        """
        if not self.server_terminated:
            self.server_terminated = True
            self.write_to_connection(
                self.stream.close(code=code, reason=reason))

    def closed(self, code, reason=None):
        """
        Called by the server when the websocket connection
        is finally closed.

        @param code: status code
        @param reason: human readable message of the closing exchange
        """
        pass

    @property
    def terminated(self):
        """
        Returns True if both the client and server have been
        marked as terminated.
        """
        return self.client_terminated is True and self.server_terminated is True

    def write_to_connection(self, bytes):
        """
        Writes the provided bytes to the underlying connection.

        @param bytes: data tio send out
        """
        return self.sock.sendall(bytes)

    def read_from_connection(self, amount):
        """
        Reads bytes from the underlying connection.

        @param amount: quantity to read (if possible)
        """
        return self.sock.recv(amount)

    def close_connection(self):
        """
        Shutdowns then closes the underlying connection.
        """
        try:
            self.sock.shutdown(socket.SHUT_RDWR)
            self.sock.close()
        except:
            pass

    def ponged(self, pong):
        """
        Pong message received on the stream.

        @param pong: messaging.PongControlMessage instance
        """
        pass

    def received_message(self, m):
        """
        Message received on the stream.

        @param pong: messaging.TextMessage or messaging.BinaryMessage instance
        """
        pass

    def send(self, payload, binary=False):
        """
        Sends the given payload out.

        If payload is some bytes or a bytearray,
        then it is sent as a single message not fragmented.

        If payload is a generator, each chunk is sent as part of
        fragmented message.

        @param payload: string, bytes, bytearray or a generator
        @param binary: if set, handles the payload as a binary message
        """
        if isinstance(payload, basestring) or isinstance(payload, bytearray):
            if not binary:
                self.write_to_connection(
                    self.stream.text_message(payload).single())
            else:
                self.write_to_connection(
                    self.stream.binary_message(payload).single())

        elif type(payload) == types.GeneratorType:
            bytes = payload.next()
            first = True
            for chunk in payload:
                if not binary:
                    self.write_to_connection(
                        self.stream.text_message(bytes).fragment(first=first))
                else:
                    self.write_to_connection(
                        self.stream.binary_message(payload).fragment(
                            first=first))
                bytes = chunk
                first = False
            if not binary:
                self.write_to_connection(
                    self.stream.text_message(bytes).fragment(last=True))
            else:
                self.write_to_connection(
                    self.stream.text_message(bytes).fragment(last=True))

    def _receive(self):
        """
        Performs the operation of reading from the underlying
        connection in order to feed the stream of bytes.

        We start with a small size of two bytes to be read
        from the connection so that we can quickly parse an
        incoming frame header. Then the stream indicates
        whatever size must be read from the connection since
        it knows the frame payload length.

        Note that we perform some automatic opererations:

        * On a closing message, we respond with a closing
          message and finally close the connection
        * We respond to pings with pong messages.
        * Whenever an error is raised by the stream parsing,
          we initiate the closing of the connection with the
          appropiate error code.
        """
        next_size = 2
        try:
            self.sock.setblocking(1)
            while not self.terminated:
                bytes = self.read_from_connection(next_size)
                if not bytes and next_size > 0:
                    break

                with self._lock:
                    s = self.stream
                    next_size = s.parser.send(bytes)

                    if s.closing is not None:
                        if not self.server_terminated:
                            next_size = 2
                            self.close(s.closing.code, s.closing.reason)
                        else:
                            self.client_terminated = True
                            break

                    elif s.errors:
                        errors = s.errors[:]
                        for error in s.errors:
                            self.close(error.code, error.reason)
                            s.errors.remove(error)
                        break

                    elif s.has_message:
                        self.received_message(s.message)
                        s.message.data = None
                        s.message = None

                    for ping in s.pings:
                        self.write_to_connection(s.pong(str(ping.data)))
                    s.pings = []

                    for pong in s.pongs:
                        self.ponged(pong)
                    s.pongs = []

        except:
            print "".join(traceback.format_exception(*exc_info()))
        finally:
            self.client_terminated = self.server_terminated = True
            self.close_connection()
            if self.stream.closing:
                self.closed(self.stream.closing.code,
                            self.stream.closing.reason)
            else:
                self.closed(1006)
Beispiel #6
0
class WebSocket(object):
    def __init__(self, sock, environ, protocols=None, extensions=None):
        self.stream = Stream()

        self.protocols = protocols
        self.extensions = extensions
        self.environ = environ

        self.sock = sock
        self.sock.settimeout(30.0)

        self.client_terminated = False
        self.server_terminated = False

        self._lock = Semaphore()

    def close(self, code=1000, reason=''):
        """
        Call this method to initiate the websocket connection
        closing by sending a close frame to the connected peer.

        Once this method is called, the server_terminated
        attribute is set. Calling this method several times is
        safe as the closing frame will be sent only the first
        time.

        @param code: status code describing why the connection is closed
        @param reason: a human readable message describing why the connection is closed
        """
        if not self.server_terminated:
            self.server_terminated = True
            self.write_to_connection(
                self.stream.close(code=code, reason=reason))
        self.close_connection()

    @property
    def terminated(self):
        """
        Returns True if both the client and server have been
        marked as terminated.
        """
        return self.client_terminated is True and self.server_terminated is True

    def write_to_connection(self, bytes):
        """
        Writes the provided bytes to the underlying connection.

        @param bytes: data tio send out
        """
        return self.sock.sendall(bytes)

    def read_from_connection(self, amount):
        """
        Reads bytes from the underlying connection.

        @param amount: quantity to read (if possible)
        """
        return self.sock.recv(amount)

    def close_connection(self):
        """
        Shutdowns then closes the underlying connection.
        """
        try:
            self.sock.shutdown(socket.SHUT_RDWR)
        finally:
            self.sock.close()

    def send(self, payload, binary=False):
        """
        Sends the given payload out.

        If payload is some bytes or a bytearray,
        then it is sent as a single message not fragmented.

        If payload is a generator, each chunk is sent as part of
        fragmented message.

        @param payload: string, bytes, bytearray or a generator
        @param binary: if set, handles the payload as a binary message
        """
        if isinstance(payload, basestring) or isinstance(payload, bytearray):
            if not binary:
                self.write_to_connection(
                    self.stream.text_message(payload).single())
            else:
                self.write_to_connection(
                    self.stream.binary_message(payload).single())

        elif type(payload) == types.GeneratorType:
            bytes = payload.next()
            first = True
            for chunk in payload:
                if not binary:
                    self.write_to_connection(
                        self.stream.text_message(bytes).fragment(first=first))
                else:
                    self.write_to_connection(
                        self.stream.binary_message(payload).fragment(
                            first=first))
                bytes = chunk
                first = False
            if not binary:
                self.write_to_connection(
                    self.stream.text_message(bytes).fragment(last=True))
            else:
                self.write_to_connection(
                    self.stream.text_message(bytes).fragment(last=True))

    def receive(self, message_obj=False):
        """
        Performs the operation of reading from the underlying
        connection in order to feed the stream of bytes.

        We start with a small size of two bytes to be read
        from the connection so that we can quickly parse an
        incoming frame header. Then the stream indicates
        whatever size must be read from the connection since
        it knows the frame payload length.

        Note that we perform some automatic opererations:

        * On a closing message, we respond with a closing
          message and finally close the connection
        * We respond to pings with pong messages.
        * Whenever an error is raised by the stream parsing,
          we initiate the closing of the connection with the
          appropriate error code.
        """
        next_size = 2
        #try:
        while not self.terminated:
            bytes = self.read_from_connection(next_size)
            if not bytes and next_size > 0:
                raise IOError()

            message = None
            with self._lock:
                s = self.stream
                next_size = s.parser.send(bytes)

                if s.closing is not None:
                    if not self.server_terminated:
                        next_size = 2
                        self.close(s.closing.code, s.closing.reason)
                    else:
                        self.client_terminated = True
                    raise IOError()

                elif s.errors:
                    errors = s.errors[:]
                    for error in s.errors:
                        self.close(error.code, error.reason)
                        s.errors.remove(error)
                    raise IOError()

                elif s.has_message:
                    if message_obj:
                        message = s.message
                        s.message = None
                    else:
                        message = str(s.message)
                        s.message.data = None
                        s.message = None

                for ping in s.pings:
                    self.write_to_connection(s.pong(str(ping.data)))
                s.pings = []
                s.pongs = []

                if message is not None:
                    return message
class WebSocket(object):
    def __init__(self, sock, environ, protocols=None, extensions=None):
        self.stream = Stream()

        self.protocols = protocols
        self.extensions = extensions
        self.environ = environ

        self.sock = sock
        self.sock.settimeout(30.0)

        self.client_terminated = False
        self.server_terminated = False

        self._lock = Semaphore()

    def close(self, code=1000, reason=''):
        """
        Call this method to initiate the websocket connection
        closing by sending a close frame to the connected peer.

        Once this method is called, the server_terminated
        attribute is set. Calling this method several times is
        safe as the closing frame will be sent only the first
        time.

        @param code: status code describing why the connection is closed
        @param reason: a human readable message describing why the connection is closed
        """
        if not self.server_terminated:
            self.server_terminated = True
            self.write_to_connection(self.stream.close(code=code, reason=reason))
        self.close_connection()

    @property
    def terminated(self):
        """
        Returns True if both the client and server have been
        marked as terminated.
        """
        return self.client_terminated is True and self.server_terminated is True

    def write_to_connection(self, bytes):
        """
        Writes the provided bytes to the underlying connection.

        @param bytes: data tio send out
        """
        return self.sock.sendall(bytes)

    def read_from_connection(self, amount):
        """
        Reads bytes from the underlying connection.

        @param amount: quantity to read (if possible)
        """
        return self.sock.recv(amount)

    def close_connection(self):
        """
        Shutdowns then closes the underlying connection.
        """
        try:
            self.sock.shutdown(socket.SHUT_RDWR)
        finally:
            self.sock.close()

    def send(self, payload, binary=False):
        """
        Sends the given payload out.

        If payload is some bytes or a bytearray,
        then it is sent as a single message not fragmented.

        If payload is a generator, each chunk is sent as part of
        fragmented message.

        @param payload: string, bytes, bytearray or a generator
        @param binary: if set, handles the payload as a binary message
        """
        if isinstance(payload, basestring) or isinstance(payload, bytearray):
            if not binary:
                self.write_to_connection(self.stream.text_message(payload).single())
            else:
                self.write_to_connection(self.stream.binary_message(payload).single())

        elif type(payload) == types.GeneratorType:
            bytes = payload.next()
            first = True
            for chunk in payload:
                if not binary:
                    self.write_to_connection(self.stream.text_message(bytes).fragment(first=first))
                else:
                    self.write_to_connection(self.stream.binary_message(payload).fragment(first=first))
                bytes = chunk
                first = False
            if not binary:
                self.write_to_connection(self.stream.text_message(bytes).fragment(last=True))
            else:
                self.write_to_connection(self.stream.text_message(bytes).fragment(last=True))

    def receive(self, message_obj=False):
        """
        Performs the operation of reading from the underlying
        connection in order to feed the stream of bytes.

        We start with a small size of two bytes to be read
        from the connection so that we can quickly parse an
        incoming frame header. Then the stream indicates
        whatever size must be read from the connection since
        it knows the frame payload length.

        Note that we perform some automatic opererations:

        * On a closing message, we respond with a closing
          message and finally close the connection
        * We respond to pings with pong messages.
        * Whenever an error is raised by the stream parsing,
          we initiate the closing of the connection with the
          appropriate error code.
        """
        next_size = 2
        #try:
        while not self.terminated:
            bytes = self.read_from_connection(next_size)
            if not bytes and next_size > 0:
                raise IOError()

            message = None
            with self._lock:
                s = self.stream
                next_size = s.parser.send(bytes)

                if s.closing is not None:
                    if not self.server_terminated:
                        next_size = 2
                        self.close(s.closing.code, s.closing.reason)
                    else:
                        self.client_terminated = True
                    raise IOError()

                elif s.errors:
                    errors = s.errors[:]
                    for error in s.errors:
                        self.close(error.code, error.reason)
                        s.errors.remove(error)
                    raise IOError()

                elif s.has_message:
                    if message_obj:
                        message = s.message
                        s.message = None
                    else:
                        message = str(s.message)
                        s.message.data = None
                        s.message = None

                for ping in s.pings:
                    self.write_to_connection(s.pong(str(ping.data)))
                s.pings = []
                s.pongs = []

                if message is not None:
                    return message