testing/mochitest/pywebsocket/mod_pywebsocket/msgutil.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/testing/mochitest/pywebsocket/mod_pywebsocket/msgutil.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,219 @@
     1.4 +# Copyright 2011, Google Inc.
     1.5 +# All rights reserved.
     1.6 +#
     1.7 +# Redistribution and use in source and binary forms, with or without
     1.8 +# modification, are permitted provided that the following conditions are
     1.9 +# met:
    1.10 +#
    1.11 +#     * Redistributions of source code must retain the above copyright
    1.12 +# notice, this list of conditions and the following disclaimer.
    1.13 +#     * Redistributions in binary form must reproduce the above
    1.14 +# copyright notice, this list of conditions and the following disclaimer
    1.15 +# in the documentation and/or other materials provided with the
    1.16 +# distribution.
    1.17 +#     * Neither the name of Google Inc. nor the names of its
    1.18 +# contributors may be used to endorse or promote products derived from
    1.19 +# this software without specific prior written permission.
    1.20 +#
    1.21 +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.22 +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.23 +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.24 +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    1.25 +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.26 +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    1.27 +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.28 +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.29 +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.30 +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.31 +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.32 +
    1.33 +
    1.34 +"""Message related utilities.
    1.35 +
    1.36 +Note: request.connection.write/read are used in this module, even though
    1.37 +mod_python document says that they should be used only in connection
    1.38 +handlers. Unfortunately, we have no other options. For example,
    1.39 +request.write/read are not suitable because they don't allow direct raw
    1.40 +bytes writing/reading.
    1.41 +"""
    1.42 +
    1.43 +
    1.44 +import Queue
    1.45 +import threading
    1.46 +
    1.47 +
    1.48 +# Export Exception symbols from msgutil for backward compatibility
    1.49 +from mod_pywebsocket._stream_base import ConnectionTerminatedException
    1.50 +from mod_pywebsocket._stream_base import InvalidFrameException
    1.51 +from mod_pywebsocket._stream_base import BadOperationException
    1.52 +from mod_pywebsocket._stream_base import UnsupportedFrameException
    1.53 +
    1.54 +
    1.55 +# An API for handler to send/receive WebSocket messages.
    1.56 +def close_connection(request):
    1.57 +    """Close connection.
    1.58 +
    1.59 +    Args:
    1.60 +        request: mod_python request.
    1.61 +    """
    1.62 +    request.ws_stream.close_connection()
    1.63 +
    1.64 +
    1.65 +def send_message(request, message, end=True, binary=False):
    1.66 +    """Send message.
    1.67 +
    1.68 +    Args:
    1.69 +        request: mod_python request.
    1.70 +        message: unicode text or str binary to send.
    1.71 +        end: False to send message as a fragment. All messages until the
    1.72 +             first call with end=True (inclusive) will be delivered to the
    1.73 +             client in separate frames but as one WebSocket message.
    1.74 +        binary: send message as binary frame.
    1.75 +    Raises:
    1.76 +        BadOperationException: when server already terminated.
    1.77 +    """
    1.78 +    request.ws_stream.send_message(message, end, binary)
    1.79 +
    1.80 +
    1.81 +def receive_message(request):
    1.82 +    """Receive a WebSocket frame and return its payload as a text in
    1.83 +    unicode or a binary in str.
    1.84 +
    1.85 +    Args:
    1.86 +        request: mod_python request.
    1.87 +    Raises:
    1.88 +        InvalidFrameException:     when client send invalid frame.
    1.89 +        UnsupportedFrameException: when client send unsupported frame e.g. some
    1.90 +                                   of reserved bit is set but no extension can
    1.91 +                                   recognize it.
    1.92 +        InvalidUTF8Exception:      when client send a text frame containing any
    1.93 +                                   invalid UTF-8 string.
    1.94 +        ConnectionTerminatedException: when the connection is closed
    1.95 +                                   unexpectedly.
    1.96 +        BadOperationException:     when client already terminated.
    1.97 +    """
    1.98 +    return request.ws_stream.receive_message()
    1.99 +
   1.100 +
   1.101 +def send_ping(request, body=''):
   1.102 +    request.ws_stream.send_ping(body)
   1.103 +
   1.104 +
   1.105 +class MessageReceiver(threading.Thread):
   1.106 +    """This class receives messages from the client.
   1.107 +
   1.108 +    This class provides three ways to receive messages: blocking,
   1.109 +    non-blocking, and via callback. Callback has the highest precedence.
   1.110 +
   1.111 +    Note: This class should not be used with the standalone server for wss
   1.112 +    because pyOpenSSL used by the server raises a fatal error if the socket
   1.113 +    is accessed from multiple threads.
   1.114 +    """
   1.115 +
   1.116 +    def __init__(self, request, onmessage=None):
   1.117 +        """Construct an instance.
   1.118 +
   1.119 +        Args:
   1.120 +            request: mod_python request.
   1.121 +            onmessage: a function to be called when a message is received.
   1.122 +                       May be None. If not None, the function is called on
   1.123 +                       another thread. In that case, MessageReceiver.receive
   1.124 +                       and MessageReceiver.receive_nowait are useless
   1.125 +                       because they will never return any messages.
   1.126 +        """
   1.127 +
   1.128 +        threading.Thread.__init__(self)
   1.129 +        self._request = request
   1.130 +        self._queue = Queue.Queue()
   1.131 +        self._onmessage = onmessage
   1.132 +        self._stop_requested = False
   1.133 +        self.setDaemon(True)
   1.134 +        self.start()
   1.135 +
   1.136 +    def run(self):
   1.137 +        try:
   1.138 +            while not self._stop_requested:
   1.139 +                message = receive_message(self._request)
   1.140 +                if self._onmessage:
   1.141 +                    self._onmessage(message)
   1.142 +                else:
   1.143 +                    self._queue.put(message)
   1.144 +        finally:
   1.145 +            close_connection(self._request)
   1.146 +
   1.147 +    def receive(self):
   1.148 +        """ Receive a message from the channel, blocking.
   1.149 +
   1.150 +        Returns:
   1.151 +            message as a unicode string.
   1.152 +        """
   1.153 +        return self._queue.get()
   1.154 +
   1.155 +    def receive_nowait(self):
   1.156 +        """ Receive a message from the channel, non-blocking.
   1.157 +
   1.158 +        Returns:
   1.159 +            message as a unicode string if available. None otherwise.
   1.160 +        """
   1.161 +        try:
   1.162 +            message = self._queue.get_nowait()
   1.163 +        except Queue.Empty:
   1.164 +            message = None
   1.165 +        return message
   1.166 +
   1.167 +    def stop(self):
   1.168 +        """Request to stop this instance.
   1.169 +
   1.170 +        The instance will be stopped after receiving the next message.
   1.171 +        This method may not be very useful, but there is no clean way
   1.172 +        in Python to forcefully stop a running thread.
   1.173 +        """
   1.174 +        self._stop_requested = True
   1.175 +
   1.176 +
   1.177 +class MessageSender(threading.Thread):
   1.178 +    """This class sends messages to the client.
   1.179 +
   1.180 +    This class provides both synchronous and asynchronous ways to send
   1.181 +    messages.
   1.182 +
   1.183 +    Note: This class should not be used with the standalone server for wss
   1.184 +    because pyOpenSSL used by the server raises a fatal error if the socket
   1.185 +    is accessed from multiple threads.
   1.186 +    """
   1.187 +
   1.188 +    def __init__(self, request):
   1.189 +        """Construct an instance.
   1.190 +
   1.191 +        Args:
   1.192 +            request: mod_python request.
   1.193 +        """
   1.194 +        threading.Thread.__init__(self)
   1.195 +        self._request = request
   1.196 +        self._queue = Queue.Queue()
   1.197 +        self.setDaemon(True)
   1.198 +        self.start()
   1.199 +
   1.200 +    def run(self):
   1.201 +        while True:
   1.202 +            message, condition = self._queue.get()
   1.203 +            condition.acquire()
   1.204 +            send_message(self._request, message)
   1.205 +            condition.notify()
   1.206 +            condition.release()
   1.207 +
   1.208 +    def send(self, message):
   1.209 +        """Send a message, blocking."""
   1.210 +
   1.211 +        condition = threading.Condition()
   1.212 +        condition.acquire()
   1.213 +        self._queue.put((message, condition))
   1.214 +        condition.wait()
   1.215 +
   1.216 +    def send_nowait(self, message):
   1.217 +        """Send a message, non-blocking."""
   1.218 +
   1.219 +        self._queue.put((message, threading.Condition()))
   1.220 +
   1.221 +
   1.222 +# vi:sts=4 sw=4 et

mercurial