~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Tools/Scripts/webkitpy/thirdparty/mod_pywebsocket/msgutil.py

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2011, Google Inc.
 
2
# All rights reserved.
 
3
#
 
4
# Redistribution and use in source and binary forms, with or without
 
5
# modification, are permitted provided that the following conditions are
 
6
# met:
 
7
#
 
8
#     * Redistributions of source code must retain the above copyright
 
9
# notice, this list of conditions and the following disclaimer.
 
10
#     * Redistributions in binary form must reproduce the above
 
11
# copyright notice, this list of conditions and the following disclaimer
 
12
# in the documentation and/or other materials provided with the
 
13
# distribution.
 
14
#     * Neither the name of Google Inc. nor the names of its
 
15
# contributors may be used to endorse or promote products derived from
 
16
# this software without specific prior written permission.
 
17
#
 
18
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 
19
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 
20
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 
21
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 
22
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
23
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 
24
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
25
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
26
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
27
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
28
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
29
 
 
30
 
 
31
"""Message related utilities.
 
32
 
 
33
Note: request.connection.write/read are used in this module, even though
 
34
mod_python document says that they should be used only in connection
 
35
handlers. Unfortunately, we have no other options. For example,
 
36
request.write/read are not suitable because they don't allow direct raw
 
37
bytes writing/reading.
 
38
"""
 
39
 
 
40
 
 
41
import Queue
 
42
import threading
 
43
 
 
44
 
 
45
# Export Exception symbols from msgutil for backward compatibility
 
46
from mod_pywebsocket._stream_base import ConnectionTerminatedException
 
47
from mod_pywebsocket._stream_base import InvalidFrameException
 
48
from mod_pywebsocket._stream_base import BadOperationException
 
49
from mod_pywebsocket._stream_base import UnsupportedFrameException
 
50
 
 
51
 
 
52
# An API for handler to send/receive WebSocket messages.
 
53
def close_connection(request):
 
54
    """Close connection.
 
55
 
 
56
    Args:
 
57
        request: mod_python request.
 
58
    """
 
59
    request.ws_stream.close_connection()
 
60
 
 
61
 
 
62
def send_message(request, payload_data, end=True, binary=False):
 
63
    """Send a message (or part of a message).
 
64
 
 
65
    Args:
 
66
        request: mod_python request.
 
67
        payload_data: unicode text or str binary to send.
 
68
        end: True to terminate a message.
 
69
             False to send payload_data as part of a message that is to be
 
70
             terminated by next or later send_message call with end=True.
 
71
        binary: send payload_data as binary frame(s).
 
72
    Raises:
 
73
        BadOperationException: when server already terminated.
 
74
    """
 
75
    request.ws_stream.send_message(payload_data, end, binary)
 
76
 
 
77
 
 
78
def receive_message(request):
 
79
    """Receive a WebSocket frame and return its payload as a text in
 
80
    unicode or a binary in str.
 
81
 
 
82
    Args:
 
83
        request: mod_python request.
 
84
    Raises:
 
85
        InvalidFrameException:     when client send invalid frame.
 
86
        UnsupportedFrameException: when client send unsupported frame e.g. some
 
87
                                   of reserved bit is set but no extension can
 
88
                                   recognize it.
 
89
        InvalidUTF8Exception:      when client send a text frame containing any
 
90
                                   invalid UTF-8 string.
 
91
        ConnectionTerminatedException: when the connection is closed
 
92
                                   unexpectedly.
 
93
        BadOperationException:     when client already terminated.
 
94
    """
 
95
    return request.ws_stream.receive_message()
 
96
 
 
97
 
 
98
def send_ping(request, body=''):
 
99
    request.ws_stream.send_ping(body)
 
100
 
 
101
 
 
102
class MessageReceiver(threading.Thread):
 
103
    """This class receives messages from the client.
 
104
 
 
105
    This class provides three ways to receive messages: blocking,
 
106
    non-blocking, and via callback. Callback has the highest precedence.
 
107
 
 
108
    Note: This class should not be used with the standalone server for wss
 
109
    because pyOpenSSL used by the server raises a fatal error if the socket
 
110
    is accessed from multiple threads.
 
111
    """
 
112
 
 
113
    def __init__(self, request, onmessage=None):
 
114
        """Construct an instance.
 
115
 
 
116
        Args:
 
117
            request: mod_python request.
 
118
            onmessage: a function to be called when a message is received.
 
119
                       May be None. If not None, the function is called on
 
120
                       another thread. In that case, MessageReceiver.receive
 
121
                       and MessageReceiver.receive_nowait are useless
 
122
                       because they will never return any messages.
 
123
        """
 
124
 
 
125
        threading.Thread.__init__(self)
 
126
        self._request = request
 
127
        self._queue = Queue.Queue()
 
128
        self._onmessage = onmessage
 
129
        self._stop_requested = False
 
130
        self.setDaemon(True)
 
131
        self.start()
 
132
 
 
133
    def run(self):
 
134
        try:
 
135
            while not self._stop_requested:
 
136
                message = receive_message(self._request)
 
137
                if self._onmessage:
 
138
                    self._onmessage(message)
 
139
                else:
 
140
                    self._queue.put(message)
 
141
        finally:
 
142
            close_connection(self._request)
 
143
 
 
144
    def receive(self):
 
145
        """ Receive a message from the channel, blocking.
 
146
 
 
147
        Returns:
 
148
            message as a unicode string.
 
149
        """
 
150
        return self._queue.get()
 
151
 
 
152
    def receive_nowait(self):
 
153
        """ Receive a message from the channel, non-blocking.
 
154
 
 
155
        Returns:
 
156
            message as a unicode string if available. None otherwise.
 
157
        """
 
158
        try:
 
159
            message = self._queue.get_nowait()
 
160
        except Queue.Empty:
 
161
            message = None
 
162
        return message
 
163
 
 
164
    def stop(self):
 
165
        """Request to stop this instance.
 
166
 
 
167
        The instance will be stopped after receiving the next message.
 
168
        This method may not be very useful, but there is no clean way
 
169
        in Python to forcefully stop a running thread.
 
170
        """
 
171
        self._stop_requested = True
 
172
 
 
173
 
 
174
class MessageSender(threading.Thread):
 
175
    """This class sends messages to the client.
 
176
 
 
177
    This class provides both synchronous and asynchronous ways to send
 
178
    messages.
 
179
 
 
180
    Note: This class should not be used with the standalone server for wss
 
181
    because pyOpenSSL used by the server raises a fatal error if the socket
 
182
    is accessed from multiple threads.
 
183
    """
 
184
 
 
185
    def __init__(self, request):
 
186
        """Construct an instance.
 
187
 
 
188
        Args:
 
189
            request: mod_python request.
 
190
        """
 
191
        threading.Thread.__init__(self)
 
192
        self._request = request
 
193
        self._queue = Queue.Queue()
 
194
        self.setDaemon(True)
 
195
        self.start()
 
196
 
 
197
    def run(self):
 
198
        while True:
 
199
            message, condition = self._queue.get()
 
200
            condition.acquire()
 
201
            send_message(self._request, message)
 
202
            condition.notify()
 
203
            condition.release()
 
204
 
 
205
    def send(self, message):
 
206
        """Send a message, blocking."""
 
207
 
 
208
        condition = threading.Condition()
 
209
        condition.acquire()
 
210
        self._queue.put((message, condition))
 
211
        condition.wait()
 
212
 
 
213
    def send_nowait(self, message):
 
214
        """Send a message, non-blocking."""
 
215
 
 
216
        self._queue.put((message, threading.Condition()))
 
217
 
 
218
 
 
219
# vi:sts=4 sw=4 et