Commits

Jeffrey Gelens  committed ac89f5b

Removed old files

  • Participants
  • Parent commits b92dfc4

Comments (0)

Files changed (15)

File AUTHORS

-This Websocket library for Gevent is written and maintained by
-
-  Jeffrey Gelens <jeffrey at noppo.pro>

File LICENSE

-Copyright (c) 2010, Noppo (Jeffrey Gelens) <http://www.noppo.pro/>
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-Neither the name of the Noppo nor the names of its contributors may be
-used to endorse or promote products derived from this software without specific
-prior written permission.
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File MANIFEST.in

-recursive-include tests *
-recursive-include examples *
-recursive-include geventwebsocket *
-include LICENSE
-include README.rst
-include MANIFEST.in

File README.rst

-================
-gevent-websocket
-================
-
-`gevent-websocket`_ is a websocket library for the gevent_ networking library
-written written and maintained by `Jeffrey Gelens`_ It is licensed under the BSD license.
-
-Installation
-------------------------
-
-Install Python 2.4 or newer and gevent and its dependencies. The latest release
-can be download from PyPi_ or by cloning the repository_.
-
-Usage
------
-
-Native Gevent
-^^^^^^^^^^^^^
-
-At the moment gevent-websocket has one handler based on the Pywsgi gevent
-server. Set the `handler_class` when creating a pywsgi server instance to make
-use of the Websocket functionality:
-
-::
-
-    from gevent import pywsgi
-    from geventwebsocket.handler import WebSocketHandler
-
-    server = pywsgi.WSGIServer(('127.0.0.1', 8000), websocket_app,
-        handler_class=WebSocketHandler)
-    server.serve_forever()
-
-Afterwards write a WSGI application with a 3rd parameter, namely a websocket instance:
-
-::
-
-    def websocket_app(environ, start_response):
-        if environ["PATH_INFO"] == '/echo':
-            ws = environ["wsgi.websocket"]
-            message = ws.wait()
-            ws.send(message)
-
-Gunicorn
-^^^^^^^^
-
-Using Gunicorn it is even more easy to start a server. Only the
-websocket_app from the previous example is required to start the server.
-Start Gunicorn using the following command and worker class:
-
-::
-
-    gunicorn -k "geventwebsocket.gunicorn.workers.GeventWebSocketWorker" gunicorn_websocket:websocket_app
-
-.. _gevent-websocket: http://www.bitbucket.org/Jeffrey/gevent-websocket/
-.. _gevent: http://www.gevent.org/
-.. _Jeffrey Gelens: http://www.gelens.org/
-.. _PyPi: http://pypi.python.org/pypi/gevent-websocket/
-.. _repository: http://www.bitbucket.org/Jeffrey/gevent-websocket/

File examples/gunicorn_websocket.py

-# -*- coding: utf-8 -
-#
-# gunicorn -k "geventwebsocket.gunicorn.workers.GeventWebSocketWorker" gunicorn_websocket:app
-
-import gevent
-
-# demo app
-import os
-import random
-def app(environ, start_response):
-    if environ['PATH_INFO'] == '/test':
-        start_response("200 OK", [('Content-Type', 'text/plain')])
-        return ["blaat"]
-    elif environ['PATH_INFO'] == "/data":
-        ws = environ['wsgi.websocket']
-        for i in xrange(10000):
-            ws.send("0 %s %s\n" % (i, random.random()))
-            gevent.sleep(1)
-    else:
-        start_response("404 Not Found", [])
-        return []
-

File examples/test.py

-from geventwebsocket.handler import WebSocketHandler
-from gevent import pywsgi
-import gevent
-
-
-# demo app
-import os
-import random
-def handle(ws):
-    """  This is the websocket handler function.  Note that we
-    can dispatch based on path in here, too."""
-    if ws.path == '/echo':
-        while True:
-            m = ws.wait()
-            if m is None:
-                break
-            ws.send(m)
-
-    elif ws.path == '/data':
-        for i in xrange(10000):
-            ws.send("0 %s %s\n" % (i, random.random()))
-            #print "0 %s %s\n" % (i, random.random())
-            gevent.sleep(0.1)
-
-
-def app(environ, start_response):
-    if environ['PATH_INFO'] == '/test':
-        start_response("200 OK", [('Content-Type', 'text/plain')])
-        return ["blaat"]
-    elif environ['PATH_INFO'] == "/data":
-        handle(environ['wsgi.websocket'])
-    else:
-        start_response("404 Not Found", [])
-        return []
-
-
-
-server = pywsgi.WSGIServer(('0.0.0.0', 8000), app,
-        handler_class=WebSocketHandler)
-server.serve_forever()

File examples/websocket.html

-<!DOCTYPE html>
-<html>
-<head>
-<!-- idea and code swiped from
-http://assorted.svn.sourceforge.net/viewvc/assorted/real-time-plotter/trunk/src/rtp.html?view=markup -->
-<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
-<script src="http://people.iola.dk/olau/flot/jquery.flot.js"></script>
-<script>
-var iets = "";
-window.onload = function() {
-    var data = {};
-    var s = new WebSocket("ws://localhost:8000/data");
-    s.onopen = function() {
-        //alert('open');
-        s.send('hi');
-    };
-    s.onmessage = function(e) {
-      //alert('got ' + e.data);
-      var lines = e.data.split('\n');
-      for (var i = 0; i < lines.length - 1; i++) {
-        var parts = lines[i].split(' ');
-        var d = parts[0], x = parseFloat(parts[1]), y = parseFloat(parts[2]);
-        if (!(d in data)) data[d] = [];
-        data[d].push([x,y]);
-      }
-      var plots = [];
-      for (var d in data) plots.push( { data: data[d].slice(data[d].length - 200) } );
-      $.plot( $("#holder"), plots,
-              {
-                series: {
-                  lines: { show: true, fill: true },
-                },
-                yaxis: { min: 0 },
-              } );
-
-      s.send('');
-    };
-};
-</script>
-</head>
-<body>
-<h3>Plot</h3>
-<div id="holder" style="width:600px;height:300px"></div>
-</body>
-</html>
-

File geventwebsocket/__init__.py

-
-version_info = (0, 2, 2)
-__version__ =  ".".join(map(str, version_info))
-
-try:
-    from geventwebsocket.websocket import WebSocket
-except ImportError:
-    import traceback
-    traceback.print_exc()

File geventwebsocket/gunicorn/__init__.py

Empty file removed.

File geventwebsocket/gunicorn/workers.py

-from geventwebsocket.handler import WebSocketHandler
-from gunicorn.workers.ggevent import GeventPyWSGIWorker
-
-class GeventWebSocketWorker(GeventPyWSGIWorker):
-    wsgi_handler = WebSocketHandler

File geventwebsocket/handler.py

-import re
-import struct
-from hashlib import md5
-from socket import error
-
-from gevent.pywsgi import WSGIHandler
-from geventwebsocket import WebSocket
-
-
-class WebSocketError(error):
-    pass
-
-
-class BadRequest(WebSocketError):
-    """
-    This error will be raised by meth:`do_handshake` when encountering an invalid request.
-    If left unhandled, it will cause :class:`WebSocketHandler` to log the error and to issue 400 reply.
-    It will also be raised by :meth:`connect` if remote server has replied with 4xx error.
-    """
-
-
-class WebSocketHandler(WSGIHandler):
-    """ Automatically upgrades the connection to websockets. """
-    def __init__(self, *args, **kwargs):
-        self.allowed_paths = []
-
-        for expression in kwargs.pop('allowed_paths', []):
-            if isinstance(expression, basestring):
-                self.allowed_paths.append(re.compile(expression))
-            else:
-                self.allowed_paths.append(expression)
-
-        super(WebSocketHandler, self).__init__(*args, **kwargs)
-
-    def run_application(self):
-        if self.websocket:
-            return self.application(self.environ, self.start_response)
-        else:
-            return super(WebSocketHandler, self).run_application()
-
-    def handle_one_response(self):
-        # TODO: refactor to run under run_application
-        # In case the client doesn't want to initialize a WebSocket connection
-        # we will proceed with the default PyWSGI functionality.
-        if self.environ.get("HTTP_CONNECTION") != "Upgrade" or \
-           self.environ.get("HTTP_UPGRADE") != "WebSocket" or \
-           not self.environ.get("HTTP_ORIGIN") or \
-           not self.accept_upgrade():
-            return super(WebSocketHandler, self).handle_one_response()
-
-        self.websocket = WebSocket(self.socket, self.rfile, self.environ)
-        self.environ['wsgi.websocket'] = self.websocket
-
-        headers = [
-            ("Upgrade", "WebSocket"),
-            ("Connection", "Upgrade"),
-        ]
-
-        # Detect the Websocket protocol
-        if "HTTP_SEC_WEBSOCKET_KEY1" in self.environ:
-            version = 76
-        else:
-            version = 75
-
-        if version == 75:
-            headers.extend([
-                ("WebSocket-Origin", self.websocket.origin),
-                ("WebSocket-Protocol", self.websocket.protocol),
-                ("WebSocket-Location", "ws://" + self.environ.get('HTTP_HOST') + self.websocket.path),
-            ])
-            self.start_response("101 Web Socket Protocol Handshake", headers)
-        elif version == 76:
-            challenge = self._get_challenge()
-            headers.extend([
-                ("Sec-WebSocket-Origin", self.websocket.origin),
-                ("Sec-WebSocket-Protocol", self.websocket.protocol),
-                ("Sec-WebSocket-Location", "ws://" + self.environ.get('HTTP_HOST') + self.websocket.path),
-            ])
-
-            self.start_response("101 Web Socket Protocol Handshake", headers)
-            self.write(challenge)
-        else:
-            raise Exception("WebSocket version not supported")
-
-        return self.run_application()
-
-    def accept_upgrade(self):
-        """
-        Returns True if request is allowed to be upgraded.
-        If self.allowed_paths is non-empty, self.environ['PATH_INFO'] will
-        be matched against each of the regular expressions.
-        """
-
-        if self.allowed_paths:
-            path_info = self.environ.get('PATH_INFO', '')
-
-            for regexps in self.allowed_paths:
-                return regexps.match(path_info)
-        else:
-            return True
-
-    def write(self, data):
-        if self.websocket:
-            self.socket.sendall(data)
-        else:
-            super(WebSocketHandler, self).write(data)
-
-    def start_response(self, status, headers, exc_info=None):
-        if self.websocket_connection:
-            self.status = status
-
-            towrite = []
-            towrite.append('%s %s\r\n' % (self.request_version, self.status))
-
-            for header in headers:
-                towrite.append("%s: %s\r\n" % header)
-
-            towrite.append("\r\n")
-            self.socket.sendall(towrite)
-            self.headers_sent = True
-        else:
-            super(WebSocketHandler, self).start_response(status, headers, exc_info)
-
-    def _get_key_value(self, key_value):
-        key_number = int(re.sub("\\D", "", key_value))
-        spaces = re.subn(" ", "", key_value)[1]
-
-        if key_number % spaces != 0:
-            raise WebSocketHandler("key_number %d is not an intergral multiple of"
-                                 " spaces %d" % (key_number, spaces))
-
-        return key_number / spaces
-
-    def _get_challenge(self):
-        key1 = self.environ.get('HTTP_SEC_WEBSOCKET_KEY1')
-        key2 = self.environ.get('HTTP_SEC_WEBSOCKET_KEY2')
-
-        if not key1:
-            raise BadRequest("SEC-WEBSOCKET-KEY1 header is missing")
-        if not key2:
-            raise BadRequest("SEC-WEBSOCKET-KEY2 header is missing")
-
-        part1 = self._get_key_value(self.environ['HTTP_SEC_WEBSOCKET_KEY1'])
-        part2 = self._get_key_value(self.environ['HTTP_SEC_WEBSOCKET_KEY2'])
-
-        # This request should have 8 bytes of data in the body
-        key3 = self.rfile.read(8)
-
-        return md5(struct.pack("!II", part1, part2) + key3).digest()
-
-    def wait(self):
-        return self.websocket.wait()
-
-    def send(self, message):
-        return self.websocket.send(message)

File geventwebsocket/websocket.py

-from gevent.coros import Semaphore
-
-# This class implements the Websocket protocol draft version as of May 23, 2010
-# The version as of August 6, 2010 will be implementend once Firefox or
-# Webkit-trunk support this version.
-
-class WebSocket(object):
-    def __init__(self, sock, rfile, environ):
-        self.rfile = rfile
-        self.socket = sock
-        self.origin = environ.get('HTTP_ORIGIN')
-        self.protocol = environ.get('HTTP_SEC_WEBSOCKET_PROTOCOL', 'unknown')
-        self.path = environ.get('PATH_INFO')
-        self._writelock = Semaphore(1)
-
-    def send(self, message):
-        if isinstance(message, unicode):
-            message = message.encode('utf-8')
-        elif isinstance(message, str):
-            message = unicode(message).encode('utf-8')
-        else:
-            raise Exception("Invalid message encoding")
-
-        with self._writelock:
-            self.socket.sendall("\x00" + message + "\xFF")
-
-    def detach(self):
-        self.socket = None
-        self.rfile = None
-        self.handler = None
-
-    def close(self):
-        # TODO implement graceful close with 0xFF frame
-        if self.socket is not None:
-            try:
-                self.socket.close()
-            except Exception:
-                pass
-            self.detach()
-
-
-    def _message_length(self):
-        # TODO: buildin security agains lengths greater than 2**31 or 2**32
-        length = 0
-
-        while True:
-            byte_str = self.rfile.read(1)
-
-            if not byte_str:
-                return 0
-            else:
-                byte = ord(byte_str)
-
-            if byte != 0x00:
-                length = length * 128 + (byte & 0x7f)
-                if (byte & 0x80) != 0x80:
-                    break
-
-        return length
-
-    def _read_until(self):
-        bytes = []
-
-        while True:
-            byte = self.rfile.read(1)
-            if ord(byte) != 0xff:
-                bytes.append(byte)
-            else:
-                break
-
-        return ''.join(bytes)
-
-    def receive(self):
-        while self.socket is not None:
-            frame_str = self.rfile.read(1)
-            if not frame_str:
-                # Connection lost?
-                self.close()
-                break
-            else:
-                frame_type = ord(frame_str)
-
-
-            if (frame_type & 0x80) == 0x00: # most significant byte is not set
-                if frame_type == 0x00:
-                    bytes = self._read_until()
-                    return bytes.decode("utf-8", "replace")
-                else:
-                    self.close()
-            elif (frame_type & 0x80) == 0x80: # most significant byte is set
-                # Read binary data (forward-compatibility)
-                if frame_type != 0xff:
-                    self.close()
-                    break
-                else:
-                    length = self._message_length()
-                    if length == 0:
-                        self.close()
-                        break
-                    else:
-                        self.rfile.read(length) # discard the bytes
-            else:
-                raise IOError("Reveiced an invalid message")

File setup.py

-from setuptools import setup, find_packages
-
-setup(
-    name="gevent-websocket",
-    version="0.2.2",
-    description="Websocket handler for the gevent pywsgi server, a Python network library",
-    long_description=open("README.rst").read(),
-    author="Jeffrey Gelens",
-    author_email="jeffrey@noppo.pro",
-    license="BSD",
-    url="http://www.gelens.org/code/gevent-websocket/",
-    download_url="http://www.gelens.org/code/gevent-websocket/",
-    install_requires=("gevent", "greenlet"),
-    packages=find_packages(exclude=["examples","tests"]),
-    classifiers=[
-        "Development Status :: 4 - Beta",
-        "License :: OSI Approved :: BSD License",
-        "Programming Language :: Python",
-        "Operating System :: MacOS :: MacOS X",
-        "Operating System :: POSIX",
-        "Topic :: Internet",
-        "Topic :: Software Development :: Libraries :: Python Modules",
-        "Intended Audience :: Developers",
-    ],
-)

File tests/greentest.py

-# Copyright (c) 2008-2009 AG Projects
-# Author: Denis Bilenko
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-
-# package is named greentest, not test, so it won't be confused with test in stdlib
-import sys
-import unittest
-import time
-import traceback
-import re
-
-import gevent
-
-disabled_marker = '-*-*-*-*-*- disabled -*-*-*-*-*-'
-def exit_disabled():
-    sys.exit(disabled_marker)
-
-def exit_unless_25():
-    if sys.version_info[:2] < (2, 5):
-        exit_disabled()
-
-VERBOSE = sys.argv.count('-v') > 1
-
-if '--debug-greentest' in sys.argv:
-    sys.argv.remove('--debug-greentest')
-    DEBUG = True
-else:
-    DEBUG = False
-
-
-class TestCase(unittest.TestCase):
-
-    __timeout__ = 1
-    switch_expected = True
-    _switch_count = None
-
-    def setUp(self):
-        gevent.sleep(0) # switch at least once to setup signal handlers
-        if hasattr(gevent.core, '_event_count'):
-            self._event_count = (gevent.core._event_count(), gevent.core._event_count_active())
-        hub = gevent.hub.get_hub()
-        if hasattr(hub, 'switch_count'):
-            self._switch_count = hub.switch_count
-        self._timer = gevent.Timeout.start_new(self.__timeout__, RuntimeError('test is taking too long'))
-
-    def tearDown(self):
-        try:
-            if not hasattr(self, 'stderr'):
-                self.unhook_stderr()
-            if hasattr(self, 'stderr'):
-                sys.__stderr__.write(self.stderr)
-        except:
-            traceback.print_exc()
-        if hasattr(self, '_timer'):
-            self._timer.cancel()
-            hub = gevent.hub.get_hub()
-            if self._switch_count is not None and hasattr(hub, 'switch_count'):
-                msg = ''
-                if hub.switch_count < self._switch_count:
-                    msg = 'hub.switch_count decreased?\n'
-                elif hub.switch_count == self._switch_count:
-                    if self.switch_expected:
-                        msg = '%s.%s did not switch\n' % (type(self).__name__, self.testname)
-                elif hub.switch_count > self._switch_count:
-                    if not self.switch_expected:
-                        msg = '%s.%s switched but expected not to\n' % (type(self).__name__, self.testname)
-                if msg:
-                    print >> sys.stderr, 'WARNING: ' + msg
-
-            if hasattr(gevent.core, '_event_count'):
-                event_count = (gevent.core._event_count(), gevent.core._event_count_active())
-                if event_count > self._event_count:
-                    args = (type(self).__name__, self.testname, self._event_count, event_count)
-                    sys.stderr.write('WARNING: %s.%s event count was %s, now %s\n' % args)
-                    gevent.sleep(0.1)
-        else:
-            sys.stderr.write('WARNING: %s.setUp does not call base class setUp\n' % (type(self).__name__, ))
-
-    @property
-    def testname(self):
-        return getattr(self, '_testMethodName', '') or getattr(self, '_TestCase__testMethodName')
-
-    @property
-    def testcasename(self):
-        return self.__class__.__name__ + '.' + self.testname
-
-    def hook_stderr(self):
-        if VERBOSE:
-            return
-        from cStringIO import StringIO
-        self.new_stderr = StringIO()
-        self.old_stderr = sys.stderr
-        sys.stderr = self.new_stderr
-
-    def unhook_stderr(self):
-        if VERBOSE:
-            return
-        try:
-            value = self.new_stderr.getvalue()
-        except AttributeError:
-            return None
-        sys.stderr = self.old_stderr
-        self.stderr = value
-        return value
-
-    def assert_no_stderr(self):
-        stderr = self.unhook_stderr()
-        assert not stderr, 'Expected no stderr, got:\n__________\n%s\n^^^^^^^^^^\n\n' % (stderr, )
-
-    def assert_stderr_traceback(self, typ, value=None):
-        if VERBOSE:
-            return
-        if isinstance(typ, Exception):
-            if value is None:
-                value = str(typ)
-            typ = typ.__class__.__name__
-        else:
-            typ = getattr(typ, '__name__', typ)
-        stderr = self.unhook_stderr()
-        assert stderr is not None, repr(stderr)
-        traceback_re = '^Traceback \\(most recent call last\\):\n( +.*?\n)+^(?P<type>\w+): (?P<value>.*?)$'
-        self.extract_re(traceback_re, type=typ, value=value)
-
-    def assert_stderr(self, message):
-        if VERBOSE:
-            return
-        exact_re = '^' + message + '.*?\n$.*'
-        if re.match(exact_re, self.stderr):
-            self.extract_re(exact_re)
-        else:
-            words_re = '^' + '.*?'.join(message.split()) + '.*?\n$'
-            if re.match(words_re, self.stderr):
-                self.extract_re(words_re)
-            else:
-                if message.endswith('...'):
-                    another_re = '^' + '.*?'.join(message.split()) + '.*?(\n +.*?$){2,5}\n\n'
-                    self.extract_re(another_re)
-                else:
-                    raise AssertionError('%r did not match:\n%r' % (message, self.stderr))
-
-    def assert_mainloop_assertion(self, message=None):
-        self.assert_stderr_traceback('AssertionError', 'Cannot switch to MAINLOOP from MAINLOOP')
-        if message is not None:
-            self.assert_stderr(message)
-
-    def extract_re(self, regex, **kwargs):
-        assert self.stderr is not None
-        m = re.search(regex, self.stderr, re.DOTALL|re.M)
-        if m is None:
-            raise AssertionError('%r did not match:\n%r' % (regex, self.stderr))
-        for key, expected_value in kwargs.items():
-            real_value = m.group(key)
-            if expected_value is not None:
-                try:
-                    self.assertEqual(real_value, expected_value)
-                except AssertionError:
-                    print 'failed to process: %s' % self.stderr
-                    raise
-        if DEBUG:
-            ate = '\n#ATE#: ' + self.stderr[m.start(0):m.end(0)].replace('\n', '\n#ATE#: ') + '\n'
-            sys.__stderr__.write(ate)
-        self.stderr = self.stderr[:m.start(0)] + self.stderr[m.end(0)+1:]
-
-
-main = unittest.main
-
-_original_Hub = gevent.hub.Hub
-
-class CountingHub(_original_Hub):
-
-    switch_count = 0
-
-    def switch(self):
-        self.switch_count += 1
-        return _original_Hub.switch(self)
-
-gevent.hub.Hub = CountingHub
-
-
-def test_outer_timeout_is_not_lost(self):
-    timeout = gevent.Timeout.start_new(0.01)
-    try:
-        self.wait(timeout=0.02)
-    except gevent.Timeout, ex:
-        assert ex is timeout, (ex, timeout)
-    else:
-        raise AssertionError('must raise Timeout')
-    gevent.sleep(0.02)
-
-
-class GenericWaitTestCase(TestCase):
-
-    def wait(self, timeout):
-        raise NotImplementedError('override me in subclass')
-
-    test_outer_timeout_is_not_lost = test_outer_timeout_is_not_lost
-
-    def test_returns_none_after_timeout(self):
-        start = time.time()
-        result = self.wait(timeout=0.01)
-        # join and wait simply returns after timeout expires
-        delay = time.time() - start
-        assert 0.01 - 0.001 <= delay < 0.01 + 0.01 + 0.1, delay
-        assert result is None, repr(result)
-
-
-class GenericGetTestCase(TestCase):
-
-    def wait(self, timeout):
-        raise NotImplementedError('override me in subclass')
-
-    test_outer_timeout_is_not_lost = test_outer_timeout_is_not_lost
-
-    def test_raises_timeout_number(self):
-        start = time.time()
-        self.assertRaises(gevent.Timeout, self.wait, timeout=0.01)
-        # get raises Timeout after timeout expired
-        delay = time.time() - start
-        assert 0.01 - 0.001 <= delay < 0.01 + 0.01 + 0.1, delay
-
-    def test_raises_timeout_Timeout(self):
-        start = time.time()
-        timeout = gevent.Timeout(0.01)
-        try:
-            self.wait(timeout=timeout)
-        except gevent.Timeout, ex:
-            assert ex is timeout, (ex, timeout)
-        delay = time.time() - start
-        assert 0.01 - 0.001 <= delay < 0.01 + 0.01 + 0.1, delay
-
-    def test_raises_timeout_Timeout_exc_customized(self):
-        start = time.time()
-        error = RuntimeError('expected error')
-        timeout = gevent.Timeout(0.01, exception=error)
-        try:
-            self.wait(timeout=timeout)
-        except RuntimeError, ex:
-            assert ex is error, (ex, error)
-        delay = time.time() - start
-        assert 0.01 - 0.001 <= delay < 0.01 + 0.01 + 0.1, delay
-
-
-class ExpectedException(Exception):
-    """An exception whose traceback should be ignored"""

File tests/test__websocket.py

-# Websocket tests by Jeffrey Gelens, Copyright 2010, Noppo.pro
-# Socket related functions by:
-#
-# @author Donovan Preston
-#
-# Copyright (c) 2007, Linden Research, Inc.
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-from gevent import monkey
-monkey.patch_all(thread=False)
-
-import sys
-import greentest
-import gevent
-from gevent import socket
-from geventwebsocket.handler import WebSocketHandler
-
-
-CONTENT_LENGTH = 'Content-Length'
-CONN_ABORTED_ERRORS = []
-DEBUG = '-v' in sys.argv
-
-try:
-    from errno import WSAECONNABORTED
-    CONN_ABORTED_ERRORS.append(WSAECONNABORTED)
-except ImportError:
-    pass
-
-
-class ConnectionClosed(Exception):
-    pass
-
-
-def read_headers(fd):
-    response_line = fd.readline()
-    if not response_line:
-        raise ConnectionClosed
-    headers = {}
-    while True:
-        line = fd.readline().strip()
-        if not line:
-            break
-        try:
-            key, value = line.split(': ', 1)
-        except:
-            print 'Failed to split: %r' % (line, )
-            raise
-        assert key.lower() not in [x.lower() for x in headers.keys()], 'Header %r:%r sent more than once: %r' % (key, value, headers)
-        headers[key] = value
-    return response_line, headers
-
-
-def iread_chunks(fd):
-    while True:
-        line = fd.readline()
-        chunk_size = line.strip()
-        try:
-            chunk_size = int(chunk_size, 16)
-        except:
-            print 'Failed to parse chunk size: %r' % line
-            raise
-        if chunk_size == 0:
-            crlf = fd.read(2)
-            assert crlf == '\r\n', repr(crlf)
-            break
-        data = fd.read(chunk_size)
-        yield data
-        crlf = fd.read(2)
-        assert crlf == '\r\n', repr(crlf)
-
-
-class Response(object):
-
-    def __init__(self, status_line, headers, body=None, chunks=None):
-        self.status_line = status_line
-        self.headers = headers
-        self.body = body
-        self.chunks = chunks
-        try:
-            version, code, self.reason = status_line[:-2].split(' ', 2)
-        except Exception:
-            print 'Error: %r' % status_line
-            raise
-        self.code = int(code)
-        HTTP, self.version = version.split('/')
-        assert HTTP == 'HTTP', repr(HTTP)
-        assert self.version in ('1.0', '1.1'), repr(self.version)
-
-    def __iter__(self):
-        yield self.status_line
-        yield self.headers
-        yield self.body
-
-    def __str__(self):
-        args = (self.__class__.__name__, self.status_line, self.headers, self.body, self.chunks)
-        return '<%s status_line=%r headers=%r body=%r chunks=%r>' % args
-
-    def assertCode(self, code):
-        if hasattr(code, '__contains__'):
-            assert self.code in code, 'Unexpected code: %r (expected %r)\n%s' % (self.code, code, self)
-        else:
-            assert self.code == code, 'Unexpected code: %r (expected %r)\n%s' % (self.code, code, self)
-
-    def assertReason(self, reason):
-        assert self.reason == reason, 'Unexpected reason: %r (expected %r)\n%s' % (self.reason, reason, self)
-
-    def assertVersion(self, version):
-        assert self.version == version, 'Unexpected version: %r (expected %r)\n%s' % (self.version, version, self)
-
-    def assertHeader(self, header, value):
-        real_value = self.headers.get(header)
-        assert real_value == value, \
-               'Unexpected header %r: %r (expected %r)\n%s' % (header, real_value, value, self)
-
-    def assertBody(self, body):
-        assert self.body == body, \
-               'Unexpected body: %r (expected %r)\n%s' % (self.body, body, self)
-
-    @classmethod
-    def read(cls, fd, code=200, reason='default', version='1.1', body=None):
-        _status_line, headers = read_headers(fd)
-        self = cls(_status_line, headers)
-        if code is not None:
-            self.assertCode(code)
-        if reason == 'default':
-            reason = {200: 'OK'}.get(code)
-        if reason is not None:
-            self.assertReason(reason)
-        if version is not None:
-            self.assertVersion(version)
-        if self.code == 100:
-            return self
-        try:
-            if 'chunked' in headers.get('Transfer-Encoding', ''):
-                if CONTENT_LENGTH in headers:
-                    print "WARNING: server used chunked transfer-encoding despite having Content-Length header (libevent 1.x's bug)"
-                self.chunks = list(iread_chunks(fd))
-                self.body = ''.join(self.chunks)
-            elif CONTENT_LENGTH in headers:
-                num = int(headers[CONTENT_LENGTH])
-                self.body = fd.read(num)
-            #else:
-            #    self.body = fd.read(16)
-        except:
-            print 'Response.read failed to read the body:\n%s' % self
-            raise
-        if body is not None:
-            self.assertBody(body)
-        return self
-
-read_http = Response.read
-
-
-class DebugFileObject(object):
-
-    def __init__(self, obj):
-        self.obj = obj
-
-    def read(self, *args):
-        result = self.obj.read(*args)
-        if DEBUG:
-            print repr(result)
-        return result
-
-    def readline(self, *args):
-        result = self.obj.readline(*args)
-        if DEBUG:
-            print repr(result)
-        return result
-
-    def __getattr__(self, item):
-        assert item != 'obj'
-        return getattr(self.obj, item)
-
-
-def makefile(self, mode='r', bufsize=-1):
-    return DebugFileObject(socket._fileobject(self.dup(), mode, bufsize))
-
-socket.socket.makefile = makefile
-
-class TestCase(greentest.TestCase):
-    __timeout__ = 5
-
-    def get_wsgi_module(self):
-        from gevent import pywsgi
-        return pywsgi
-
-    def init_server(self, application):
-        self.server = self.get_wsgi_module().WSGIServer(('127.0.0.1', 0),
-            application, handler_class=WebSocketHandler)
-
-    def setUp(self):
-        application = self.application
-        self.init_server(application)
-        self.server.start()
-        self.port = self.server.server_port
-        greentest.TestCase.setUp(self)
-
-
-    def tearDown(self):
-        greentest.TestCase.tearDown(self)
-        timeout = gevent.Timeout.start_new(0.5)
-        try:
-            self.server.stop()
-        finally:
-            timeout.cancel()
-
-    def connect(self):
-        return socket.create_connection(('127.0.0.1', self.port))
-
-
-class TestWebSocket(TestCase):
-    message = "\x00Hello world\xff"
-
-    def application(self, environ, start_response):
-        if environ['PATH_INFO'] == "/echo":
-            try:
-                ws = environ['wsgi.websocket']
-            except KeyError:
-                start_response("400 Bad Request", [])
-                return []
-
-            while True:
-                message = ws.wait()
-                if message is None:
-                    break
-                ws.send(message)
-
-            return []
-
-    def test_basic(self):
-        fd = self.connect().makefile(bufsize=1)
-        headers = "" \
-        "GET /echo HTTP/1.1\r\n" \
-        "Host: localhost\r\n" \
-        "Connection: Upgrade\r\n" \
-        "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n" \
-        "Sec-WebSocket-Protocol: test\r\n" \
-        "Upgrade: WebSocket\r\n" \
-        "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n" \
-        "Origin: http://localhost\r\n\r\n" \
-        "^n:ds[4U"
-
-        fd.write(headers)
-
-        response = read_http(fd, code=101, reason="Web Socket Protocol Handshake")
-        response.assertHeader("Upgrade", "WebSocket")
-        response.assertHeader("Connection", "Upgrade")
-        response.assertHeader("Sec-WebSocket-Origin", "http://localhost")
-        response.assertHeader("Sec-WebSocket-Location", "ws://localhost/echo")
-        response.assertHeader("Sec-WebSocket-Protocol", "test")
-        assert fd.read(16) == "8jKS'y:G*Co,Wxa-"
-
-        fd.write(self.message)
-        message = fd.read(len(self.message))
-        assert message == self.message, \
-               'Unexpected message: %r (expected %r)\n%s' % (message, self.message, self)
-
-        fd.close()
-
-    def test_10000_messages(self):
-        fd = self.connect().makefile(bufsize=1)
-        headers = "" \
-        "GET /echo HTTP/1.1\r\n" \
-        "Host: localhost\r\n" \
-        "Connection: Upgrade\r\n" \
-        "Sec-WebSocket-Key2: 12998 5 Y3 1  .P00\r\n" \
-        "Sec-WebSocket-Protocol: test\r\n" \
-        "Upgrade: WebSocket\r\n" \
-        "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n" \
-        "Origin: http://localhost\r\n\r\n" \
-        "^n:ds[4U"
-
-        fd.write(headers)
-
-        response = read_http(fd, code=101, reason="Web Socket Protocol Handshake")
-        response.assertHeader("Upgrade", "WebSocket")
-        response.assertHeader("Connection", "Upgrade")
-        response.assertHeader("Sec-WebSocket-Origin", "http://localhost")
-        response.assertHeader("Sec-WebSocket-Location", "ws://localhost/echo")
-        response.assertHeader("Sec-WebSocket-Protocol", "test")
-        assert fd.read(16) == "8jKS'y:G*Co,Wxa-"
-
-        for i in xrange(10000):
-            fd.write(self.message)
-            message = fd.read(len(self.message))
-
-            assert message == self.message, \
-                   'Unexpected message: %r (expected %r)\n%s' % (message, self.message, self)
-
-
-        fd.close()
-
-    def test_badrequest(self):
-        fd = self.connect().makefile(bufsize=1)
-        fd.write('GET /echo HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        read_http(fd, code=400, reason='Bad Request')
-        fd.close()
-
-    def test_oldprotocol_version(self):
-        fd = self.connect().makefile(bufsize=1)
-        headers = "" \
-        "GET /echo HTTP/1.1\r\n" \
-        "Host: localhost\r\n" \
-        "Connection: Upgrade\r\n" \
-        "Sec-WebSocket-Protocol: test\r\n" \
-        "Upgrade: WebSocket\r\n" \
-        "Sec-WebSocket-Key1: 4 @1  46546xW%0l 1 5\r\n" \
-        "Origin: http://localhost\r\n\r\n" \
-        "^n:ds[4U"
-
-        fd.write(headers)
-        read_http(fd, code=400, reason='Bad Request',
-            body='Client using old/invalid protocol implementation')
-
-        fd.close()
-
-    def test_protocol_version75(self):
-        fd = self.connect().makefile(bufsize=1)
-        headers = "" \
-        "GET /echo HTTP/1.1\r\n" \
-        "Host: localhost\r\n" \
-        "Connection: Upgrade\r\n" \
-        "WebSocket-Protocol: sample\r\n" \
-        "Upgrade: WebSocket\r\n" \
-        "Origin: http://example.com\r\n\r\n"
-
-        fd.write(headers)
-        response = read_http(fd, code=101, reason="Web Socket Protocol Handshake")
-
-        fd.write(self.message)
-        message = fd.read(len(self.message))
-        assert message == self.message, \
-               'Unexpected message: %r (expected %r)\n%s' % (message, self.message, self)
-
-        fd.close()
-
-if __name__ == '__main__':
-    greentest.main()