Hello community,

here is the log from the commit of package python-eventlet for openSUSE:Factory 
checked in at 2013-09-17 16:18:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-eventlet (Old)
 and      /work/SRC/openSUSE:Factory/.python-eventlet.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-eventlet"

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-eventlet/python-eventlet.changes  
2013-07-04 10:14:21.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python-eventlet.new/python-eventlet.changes     
2013-09-17 16:25:46.000000000 +0200
@@ -1,0 +2,13 @@
+Tue Sep 17 08:56:56 UTC 2013 - [email protected]
+
+- update to 0.14.0:
+  * wsgi: handle connection socket timeouts; Thanks to Paul Oppenheim
+  * wsgi: close timed out client connections
+  * greenio: socket pypy compatibility; Thanks to Alex Gaynor
+  * wsgi: env['wsgi.input'] was returning 1 byte strings; Thanks to Eric Urban
+  * green.ssl: fix NameError; Github #17; Thanks to Jakub Stasiak
+  * websocket: allow "websocket" in lowercase in Upgrade header; Compatibility 
with current Google Chrome; Thanks to Dmitry Orlov
+  * wsgi: allow minimum_chunk_size to be overriden on a per request basis; 
Thanks to David Goetz
+  * wsgi: configurable socket_timeout
+
+-------------------------------------------------------------------

Old:
----
  eventlet-0.13.0.tar.gz

New:
----
  eventlet-0.14.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-eventlet.spec ++++++
--- /var/tmp/diff_new_pack.b5bfbY/_old  2013-09-17 16:25:47.000000000 +0200
+++ /var/tmp/diff_new_pack.b5bfbY/_new  2013-09-17 16:25:47.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           python-eventlet
-Version:        0.13.0
+Version:        0.14.0
 Release:        0
 Url:            http://eventlet.net
 Summary:        Highly concurrent networking library
@@ -68,7 +68,7 @@
 
 %files
 %defattr(-,root,root,-)
-%doc AUTHORS LICENSE NEWS README README.twisted
+%doc AUTHORS LICENSE NEWS README.rst README.twisted
 %{python_sitelib}/*
 
 %files doc

++++++ eventlet-0.13.0.tar.gz -> eventlet-0.14.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/AUTHORS new/eventlet-0.14.0/AUTHORS
--- old/eventlet-0.13.0/AUTHORS 2013-07-02 18:25:04.000000000 +0200
+++ new/eventlet-0.14.0/AUTHORS 2013-09-13 18:36:48.000000000 +0200
@@ -33,6 +33,8 @@
 * Geoff Salmon
 * Edward George
 * Floris Bruynooghe
+* Paul Oppenheim
+* Jakub Stasiak
 
 Linden Lab Contributors
 -----------------------
@@ -84,6 +86,7 @@
 * Peter Portante, save syscalls in socket.dup(), environ[REMOTE_PORT] in wsgi
 * Peter Skirko, fixing socket.settimeout(0) bug
 * Derk Tegeler, Pre-cache proxied GreenSocket methods (Bitbucket #136)
-* Jakub Stasiak, Travis integration, wsgi fix
-* Paul Oppenheim, bug reports
 * David Malcolm, optional "timeout" argument to the subprocess module 
(Bitbucket #89)
+* Eric Urban, fix wsgi.input 1-byte (Bitbucket #150)
+* David Goetz, wsgi: Allow minimum_chunk_size to be overriden on a per request 
basis
+* Dmitry Orlov, websocket: accept Upgrade: websocket (lowercase)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/MANIFEST.in 
new/eventlet-0.14.0/MANIFEST.in
--- old/eventlet-0.13.0/MANIFEST.in     2013-07-02 18:25:04.000000000 +0200
+++ new/eventlet-0.14.0/MANIFEST.in     2013-09-13 15:50:20.000000000 +0200
@@ -1,4 +1,4 @@
 recursive-include tests *.py *.crt *.key
 recursive-include doc *.rst *.txt *.py Makefile *.png
 recursive-include examples *.py *.html
-include MANIFEST.in README.twisted NEWS AUTHORS LICENSE README
+include MANIFEST.in README.twisted NEWS AUTHORS LICENSE README.rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/NEWS new/eventlet-0.14.0/NEWS
--- old/eventlet-0.13.0/NEWS    2013-07-02 18:25:04.000000000 +0200
+++ new/eventlet-0.14.0/NEWS    2013-09-13 18:34:13.000000000 +0200
@@ -1,3 +1,14 @@
+0.14
+====
+* wsgi: handle connection socket timeouts; Thanks to Paul Oppenheim
+* wsgi: close timed out client connections
+* greenio: socket pypy compatibility; Thanks to Alex Gaynor
+* wsgi: env['wsgi.input'] was returning 1 byte strings; Thanks to Eric Urban
+* green.ssl: fix NameError; Github #17; Thanks to Jakub Stasiak
+* websocket: allow "websocket" in lowercase in Upgrade header; Compatibility 
with current Google Chrome; Thanks to Dmitry Orlov
+* wsgi: allow minimum_chunk_size to be overriden on a per request basis; 
Thanks to David Goetz
+* wsgi: configurable socket_timeout
+
 0.13
 ====
 * hubs: kqueue support! Thanks to YAMAMOTO Takashi, Edward George
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/PKG-INFO new/eventlet-0.14.0/PKG-INFO
--- old/eventlet-0.13.0/PKG-INFO        2013-07-02 18:38:04.000000000 +0200
+++ new/eventlet-0.14.0/PKG-INFO        2013-09-13 18:43:21.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: eventlet
-Version: 0.13.0
+Version: 0.14.0
 Summary: Highly concurrent networking library
 Home-page: http://eventlet.net
 Author: Linden Lab
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/README new/eventlet-0.14.0/README
--- old/eventlet-0.13.0/README  2013-07-02 18:25:04.000000000 +0200
+++ new/eventlet-0.14.0/README  1970-01-01 01:00:00.000000000 +0100
@@ -1,50 +0,0 @@
-Eventlet is a concurrent networking library for Python that allows you to 
change how you run your code, not how you write it.
-
-It uses epoll or libevent for highly scalable non-blocking I/O.  Coroutines 
ensure that the developer uses a blocking style of programming that is similar 
to threading, but provide the benefits of non-blocking I/O.  The event dispatch 
is implicit, which means you can easily use Eventlet from the Python 
interpreter, or as a small part of a larger application.
-
-It's easy to get started using Eventlet, and easy to convert existing 
-applications to use it.  Start off by looking at the `examples`_, 
-`common design patterns`_, and the list of `basic API primitives`_.
-
-.. _examples: http://eventlet.net/doc/examples.html
-.. _common design patterns: http://eventlet.net/doc/design_patterns.html
-.. _basic API primitives: http://eventlet.net/doc/basic_usage.html
-
-Quick Example
-===============
-
-Here's something you can try right on the command line::
-
-    % python
-    >>> import eventlet 
-    >>> from eventlet.green import urllib2
-    >>> gt = eventlet.spawn(urllib2.urlopen, 'http://eventlet.net')
-    >>> gt2 = eventlet.spawn(urllib2.urlopen, 'http://secondlife.com')
-    >>> gt2.wait()
-    >>> gt.wait()
-
-
-Getting Eventlet
-==================
-
-The easiest way to get Eventlet is to use easy_install or pip::
-
-  easy_install eventlet
-  pip install eventlet
-
-The development `tip`_ is available via easy_install as well::
-
-  easy_install 'eventlet==dev'
-  pip install 'eventlet==dev'
-
-.. _tip: http://bitbucket.org/eventlet/eventlet/get/tip.zip#egg=eventlet-dev
-
-Building the Docs Locally
-=========================
-
-To build a complete set of HTML documentation, you must have Sphinx, which can 
be found at http://sphinx.pocoo.org/ (or installed with `easy_install sphinx`)
-
-  cd doc
-  make html
-  
-The built html files can be found in doc/_build/html afterward.
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/README.rst 
new/eventlet-0.14.0/README.rst
--- old/eventlet-0.13.0/README.rst      1970-01-01 01:00:00.000000000 +0100
+++ new/eventlet-0.14.0/README.rst      2013-09-13 15:50:20.000000000 +0200
@@ -0,0 +1,50 @@
+Eventlet is a concurrent networking library for Python that allows you to 
change how you run your code, not how you write it.
+
+It uses epoll or libevent for highly scalable non-blocking I/O.  Coroutines 
ensure that the developer uses a blocking style of programming that is similar 
to threading, but provide the benefits of non-blocking I/O.  The event dispatch 
is implicit, which means you can easily use Eventlet from the Python 
interpreter, or as a small part of a larger application.
+
+It's easy to get started using Eventlet, and easy to convert existing 
+applications to use it.  Start off by looking at the `examples`_, 
+`common design patterns`_, and the list of `basic API primitives`_.
+
+.. _examples: http://eventlet.net/doc/examples.html
+.. _common design patterns: http://eventlet.net/doc/design_patterns.html
+.. _basic API primitives: http://eventlet.net/doc/basic_usage.html
+
+Quick Example
+===============
+
+Here's something you can try right on the command line::
+
+    % python
+    >>> import eventlet 
+    >>> from eventlet.green import urllib2
+    >>> gt = eventlet.spawn(urllib2.urlopen, 'http://eventlet.net')
+    >>> gt2 = eventlet.spawn(urllib2.urlopen, 'http://secondlife.com')
+    >>> gt2.wait()
+    >>> gt.wait()
+
+
+Getting Eventlet
+==================
+
+The easiest way to get Eventlet is to use easy_install or pip::
+
+  easy_install eventlet
+  pip install eventlet
+
+The development `tip`_ is available via easy_install as well::
+
+  easy_install 'eventlet==dev'
+  pip install 'eventlet==dev'
+
+.. _tip: http://bitbucket.org/eventlet/eventlet/get/tip.zip#egg=eventlet-dev
+
+Building the Docs Locally
+=========================
+
+To build a complete set of HTML documentation, you must have Sphinx, which can 
be found at http://sphinx.pocoo.org/ (or installed with `easy_install sphinx`)
+
+  cd doc
+  make html
+  
+The built html files can be found in doc/_build/html afterward.
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/eventlet/__init__.py 
new/eventlet-0.14.0/eventlet/__init__.py
--- old/eventlet-0.13.0/eventlet/__init__.py    2013-07-02 18:29:16.000000000 
+0200
+++ new/eventlet-0.14.0/eventlet/__init__.py    2013-09-13 18:34:47.000000000 
+0200
@@ -1,4 +1,4 @@
-version_info = (0, 13, 0)
+version_info = (0, 14, 0)
 __version__ = ".".join(map(str, version_info))
 
 try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/eventlet/green/ssl.py 
new/eventlet-0.14.0/eventlet/green/ssl.py
--- old/eventlet-0.13.0/eventlet/green/ssl.py   2013-07-02 18:25:04.000000000 
+0200
+++ new/eventlet-0.14.0/eventlet/green/ssl.py   2013-08-20 14:50:45.000000000 
+0200
@@ -136,7 +136,7 @@
         else:
             while True:
                 try:
-                    return socket.sendall(self, buflen, flags)
+                    return socket.sendall(self, data, flags)
                 except orig_socket.error, e:
                     if self.act_non_blocking:
                         raise
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/eventlet/greenio.py 
new/eventlet-0.14.0/eventlet/greenio.py
--- old/eventlet-0.13.0/eventlet/greenio.py     2013-07-02 18:25:04.000000000 
+0200
+++ new/eventlet-0.14.0/eventlet/greenio.py     2013-08-20 14:50:45.000000000 
+0200
@@ -127,8 +127,6 @@
             fd = _original_socket(family_or_realsock, *args, **kwargs)
         else:
             fd = family_or_realsock
-            assert not args, args
-            assert not kwargs, kwargs
 
         # import timeout from other socket, if it was there
         try:
@@ -235,7 +233,11 @@
         return newsock
 
     def makefile(self, *args, **kw):
-        return _fileobject(self.dup(), *args, **kw)
+        dupped = self.dup()
+        res = _fileobject(dupped, *args, **kw)
+        if hasattr(dupped, "_drop"):
+            dupped._drop()
+        return res
 
     def makeGreenFile(self, *args, **kw):
         warnings.warn("makeGreenFile has been deprecated, please use "
@@ -342,6 +344,13 @@
     def gettimeout(self):
         return self._timeout
 
+    if "__pypy__" in sys.builtin_module_names:
+        def _reuse(self):
+            self.fd._sock._reuse()
+
+        def _drop(self):
+            self.fd._sock._drop()
+
 
 class _SocketDuckForFd(object):
     """ Class implementing all socket method used by _fileobject in 
cooperative manner using low level os I/O calls."""
@@ -393,6 +402,13 @@
     def __repr__(self):
         return "%s:%d" % (self.__class__.__name__, self._fileno)
 
+    if "__pypy__" in sys.builtin_module_names:
+        def _reuse(self):
+            pass
+
+        def _drop(self):
+            pass
+
 
 def _operationOnClosedFile(*args, **kwargs):
     raise ValueError("I/O operation on closed file")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/eventlet/support/greendns.py 
new/eventlet-0.14.0/eventlet/support/greendns.py
--- old/eventlet-0.13.0/eventlet/support/greendns.py    2013-07-02 
18:25:04.000000000 +0200
+++ new/eventlet-0.14.0/eventlet/support/greendns.py    2013-08-20 
14:50:45.000000000 +0200
@@ -40,13 +40,13 @@
 from eventlet.green import time
 from eventlet.green import select
 
-dns = patcher.import_patched('dns', 
+dns = patcher.import_patched('dns',
                              socket=_socket_nodns,
                              time=time,
                              select=select)
-for pkg in ('dns.query', 'dns.exception', 'dns.inet', 'dns.message', 
+for pkg in ('dns.query', 'dns.exception', 'dns.inet', 'dns.message',
             'dns.rdatatype','dns.resolver', 'dns.reversename'):
-   setattr(dns, pkg.split('.')[1], patcher.import_patched(pkg, 
+   setattr(dns, pkg.split('.')[1], patcher.import_patched(pkg,
                                                           socket=_socket_nodns,
                                                           time=time,
                                                           select=select))
@@ -252,12 +252,13 @@
             raise socket.gaierror(
                 (socket.EAI_NODATA, 'No address associated with hostname'))
 
-        if not (flags & socket.NI_NUMERICSERV):
-            proto = (flags & socket.NI_DGRAM) and 'udp' or 'tcp'
-            port = socket.getservbyport(port, proto)
+    if not (flags & socket.NI_NUMERICSERV):
+        proto = (flags & socket.NI_DGRAM) and 'udp' or 'tcp'
+        port = socket.getservbyport(port, proto)
 
     return (host, port)
 
+
 def is_ipv4_addr(host):
     """is_ipv4_addr returns true if host is a valid IPv4 address in
     dotted quad notation.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/eventlet/websocket.py 
new/eventlet-0.14.0/eventlet/websocket.py
--- old/eventlet-0.13.0/eventlet/websocket.py   2013-07-02 18:25:04.000000000 
+0200
+++ new/eventlet-0.14.0/eventlet/websocket.py   2013-09-13 15:53:28.000000000 
+0200
@@ -40,7 +40,7 @@
 
     def __call__(self, environ, start_response):
         if not (environ.get('HTTP_CONNECTION') == 'Upgrade' and
-                environ.get('HTTP_UPGRADE') == 'WebSocket'):
+                environ.get('HTTP_UPGRADE').lower() == 'websocket'):
             # need to check a few more things here for true compliance
             start_response('400 Bad Request', [('Connection','close')])
             return []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/eventlet/wsgi.py 
new/eventlet-0.14.0/eventlet/wsgi.py
--- old/eventlet-0.13.0/eventlet/wsgi.py        2013-07-02 18:25:04.000000000 
+0200
+++ new/eventlet-0.14.0/eventlet/wsgi.py        2013-09-13 15:50:20.000000000 
+0200
@@ -31,6 +31,7 @@
               "Jan", "Feb", "Mar", "Apr", "May", "Jun",
               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
 
+
 def format_date_time(timestamp):
     """Formats a unix timestamp into an HTTP standard string."""
     year, month, day, hh, mm, ss, wd, _y, _z = time.gmtime(timestamp)
@@ -38,11 +39,13 @@
         _weekdayname[wd], day, _monthname[month], year, hh, mm, ss
     )
 
+
 # Collections of error codes to compare against.  Not all attributes are set
 # on errno module on all platforms, so some are literals :(
 BAD_SOCK = set((errno.EBADF, 10053))
 BROKEN_SOCK = set((errno.EPIPE, errno.ECONNRESET))
 
+
 # special flag return value for apps
 class _AlreadyHandled(object):
 
@@ -54,7 +57,9 @@
 
 ALREADY_HANDLED = _AlreadyHandled()
 
+
 class Input(object):
+
     def __init__(self,
                  rfile,
                  content_length,
@@ -161,7 +166,7 @@
         return self._do_read(self.rfile.readlines, hint)
 
     def __iter__(self):
-        return iter(self.read())
+        return iter(self.read, '')
 
     def get_socket(self):
         return self.rfile._sock
@@ -392,10 +397,12 @@
                 towrite = []
                 towrite_size = 0
                 just_written_size = 0
+                minimum_write_chunk_size = int(self.environ.get(
+                    'eventlet.minimum_write_chunk_size', 
self.minimum_chunk_size))
                 for data in result:
                     towrite.append(data)
                     towrite_size += len(data)
-                    if towrite_size >= self.minimum_chunk_size:
+                    if towrite_size >= minimum_write_chunk_size:
                         write(''.join(towrite))
                         towrite = []
                         just_written_size = towrite_size
@@ -519,8 +526,8 @@
         self.connection.close()
 
 
-
 class Server(BaseHTTPServer.HTTPServer):
+
     def __init__(self,
                  socket,
                  address,
@@ -535,7 +542,8 @@
                  log_output=True,
                  log_format=DEFAULT_LOG_FORMAT,
                  url_length_limit=MAX_REQUEST_LINE,
-                 debug=True):
+                 debug=True,
+                 socket_timeout=None):
 
         self.outstanding_requests = 0
         self.socket = socket
@@ -556,6 +564,7 @@
         self.log_format = log_format
         self.url_length_limit = url_length_limit
         self.debug = debug
+        self.socket_timeout = socket_timeout
 
     def get_environ(self):
         d = {
@@ -574,18 +583,26 @@
             d.update(self.environ)
         return d
 
-    def process_request(self, (socket, address)):
+    def process_request(self, (sock, address)):
         # The actual request handling takes place in __init__, so we need to
         # set minimum_chunk_size before __init__ executes and we don't want to 
modify
         # class variable
         proto = types.InstanceType(self.protocol)
         if self.minimum_chunk_size is not None:
             proto.minimum_chunk_size = self.minimum_chunk_size
-        proto.__init__(socket, address, self)
+        try:
+            proto.__init__(sock, address, self)
+        except socket.timeout:
+            # Expected exceptions are not exceptional
+            sock.close()
+            if self.debug:
+                # similar to logging "accepted" in server()
+                self.log_message('(%s) timed out %r' % (self.pid, address))
 
     def log_message(self, message):
         self.log.write(message + '\n')
 
+
 try:
     import ssl
     ACCEPT_EXCEPTIONS = (socket.error, ssl.SSLError)
@@ -595,6 +612,7 @@
     ACCEPT_EXCEPTIONS = (socket.error,)
     ACCEPT_ERRNO = set((errno.EPIPE, errno.EBADF, errno.ECONNRESET))
 
+
 def server(sock, site,
            log=None,
            environ=None,
@@ -609,8 +627,9 @@
            log_output=True,
            log_format=DEFAULT_LOG_FORMAT,
            url_length_limit=MAX_REQUEST_LINE,
-           debug=True):
-    """  Start up a wsgi server handling requests from the supplied server
+           debug=True,
+           socket_timeout=None):
+    """Start up a WSGI server handling requests from the supplied server
     socket.  This function loops forever.  The *sock* object will be closed 
after server exits,
     but the underlying file descriptor will remain open, so if you have a 
dup() of *sock*,
     it will remain usable.
@@ -623,7 +642,7 @@
     :param max_http_version: Set to "HTTP/1.0" to make the server pretend it 
only supports HTTP 1.0.  This can help with applications or clients that don't 
behave properly using HTTP 1.1.
     :param protocol: Protocol class.  Deprecated.
     :param server_event: Used to collect the Server object.  Deprecated.
-    :param minimum_chunk_size: Minimum size in bytes for http chunks.  This  
can be used to improve performance of applications which yield many small 
strings, though using it technically violates the WSGI spec.
+    :param minimum_chunk_size: Minimum size in bytes for http chunks.  This  
can be used to improve performance of applications which yield many small 
strings, though using it technically violates the WSGI spec. This can be 
overridden on a per request basis by setting 
environ['eventlet.minimum_write_chunk_size'].
     :param log_x_forwarded_for: If True (the default), logs the contents of 
the x-forwarded-for header in addition to the actual client ip address in the 
'client_ip' field of the log line.
     :param custom_pool: A custom GreenPool instance which is used to spawn 
client green threads.  If this is supplied, max_size is ignored.
     :param keepalive: If set to False, disables keepalives on the server; all 
connections will be closed after serving one request.
@@ -631,6 +650,7 @@
     :param log_format: A python format string that is used as the template to 
generate log lines.  The following values can be formatted into it: client_ip, 
date_time, request_line, status_code, body_length, wall_seconds.  The default 
is a good example of how to use it.
     :param url_length_limit: A maximum allowed length of the request url. If 
exceeded, 414 error is returned.
     :param debug: True if the server should send exception tracebacks to the 
clients on 500 errors.  If False, the server will respond with empty bodies.
+    :param socket_timeout: Timeout for client connections' socket operations. 
Default None means wait forever.
     """
     serv = Server(sock, sock.getsockname(),
                   site, log,
@@ -643,7 +663,9 @@
                   log_output=log_output,
                   log_format=log_format,
                   url_length_limit=url_length_limit,
-                  debug=debug)
+                  debug=debug,
+                  socket_timeout=socket_timeout,
+                  )
     if server_event is not None:
         server_event.send(serv)
     if max_size is None:
@@ -669,6 +691,7 @@
         while True:
             try:
                 client_socket = sock.accept()
+                client_socket[0].settimeout(serv.socket_timeout)
                 if debug:
                     serv.log.write("(%s) accepted %r\n" % (
                         serv.pid, client_socket[1]))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/eventlet.egg-info/PKG-INFO 
new/eventlet-0.14.0/eventlet.egg-info/PKG-INFO
--- old/eventlet-0.13.0/eventlet.egg-info/PKG-INFO      2013-07-02 
18:37:51.000000000 +0200
+++ new/eventlet-0.14.0/eventlet.egg-info/PKG-INFO      2013-09-13 
18:43:17.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: eventlet
-Version: 0.13.0
+Version: 0.14.0
 Summary: Highly concurrent networking library
 Home-page: http://eventlet.net
 Author: Linden Lab
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/eventlet.egg-info/SOURCES.txt 
new/eventlet-0.14.0/eventlet.egg-info/SOURCES.txt
--- old/eventlet-0.13.0/eventlet.egg-info/SOURCES.txt   2013-07-02 
18:37:51.000000000 +0200
+++ new/eventlet-0.14.0/eventlet.egg-info/SOURCES.txt   2013-09-13 
18:43:18.000000000 +0200
@@ -2,7 +2,7 @@
 LICENSE
 MANIFEST.in
 NEWS
-README
+README.rst
 README.twisted
 setup.py
 doc/Makefile
@@ -153,6 +153,7 @@
 tests/env_test.py
 tests/event_test.py
 tests/fork_test.py
+tests/greendns_test.py
 tests/greenio_test.py
 tests/greenpipe_test_with_statement.py
 tests/greenpool_test.py
@@ -189,6 +190,7 @@
 tests/tpool_test.py
 tests/websocket_test.py
 tests/wsgi_test.py
+tests/wsgi_test_conntimeout.py
 tests/zmq_test.py
 tests/stdlib/all.py
 tests/stdlib/all_modules.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/setup.py new/eventlet-0.14.0/setup.py
--- old/eventlet-0.13.0/setup.py        2013-07-02 18:25:04.000000000 +0200
+++ new/eventlet-0.14.0/setup.py        2013-09-13 15:50:20.000000000 +0200
@@ -19,7 +19,7 @@
     long_description=open(
         path.join(
             path.dirname(__file__),
-            'README'
+            'README.rst'
         )
     ).read(),
     test_suite='nose.collector',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/tests/__init__.py 
new/eventlet-0.14.0/tests/__init__.py
--- old/eventlet-0.13.0/tests/__init__.py       2013-07-02 18:25:04.000000000 
+0200
+++ new/eventlet-0.14.0/tests/__init__.py       2013-09-13 15:52:46.000000000 
+0200
@@ -1,13 +1,18 @@
 # package is named tests, not test, so it won't be confused with test in stdlib
 import errno
 import os
-import resource
+try:
+    import resource
+except ImportError:
+    resource = None
 import signal
+import subprocess
+import sys
 import unittest
 import warnings
 
 import eventlet
-from eventlet import debug, hubs
+from eventlet import debug, hubs, tpool
 
 
 # convenience for importers
@@ -173,15 +178,8 @@
             signal.signal(signal.SIGALRM, self.previous_alarm[0])
             signal.alarm(self.previous_alarm[1])
 
-        try:
-            hub = hubs.get_hub()
-            num_readers = len(hub.get_readers())
-            num_writers = len(hub.get_writers())
-            assert num_readers == num_writers == 0
-        except AssertionError:
-            print "ERROR: Hub not empty"
-            print debug.format_hub_timers()
-            print debug.format_hub_listeners()
+        tpool.killall()
+        verify_hub_empty()
 
     def assert_less_than(self, a,b,msg=None):
         if msg:
@@ -201,6 +199,11 @@
 
 
 def check_idle_cpu_usage(duration, allowed_part):
+    if resource is None:
+        # TODO: use https://code.google.com/p/psutil/
+        from nose.plugins.skip import SkipTest
+        raise SkipTest('CPU usage testing not supported (`import resource` 
failed)')
+
     r1 = resource.getrusage(resource.RUSAGE_SELF)
     eventlet.sleep(duration)
     r2 = resource.getrusage(resource.RUSAGE_SELF)
@@ -282,5 +285,24 @@
             pass
     return retval
 
+
+def run_python(path):
+    if not path.endswith('.py'):
+        path += '.py'
+    path = os.path.abspath(path)
+    dir_ = os.path.dirname(path)
+    new_env = os.environ.copy()
+    new_env['PYTHONPATH'] = os.pathsep.join(sys.path + [dir_])
+    p = subprocess.Popen(
+        [sys.executable, path],
+        env=new_env,
+        stderr=subprocess.STDOUT,
+        stdin=subprocess.PIPE,
+        stdout=subprocess.PIPE,
+    )
+    output, _ = p.communicate()
+    return output
+
+
 certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
 private_key_file = os.path.join(os.path.dirname(__file__), 'test_server.key')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/tests/greendns_test.py 
new/eventlet-0.14.0/tests/greendns_test.py
--- old/eventlet-0.13.0/tests/greendns_test.py  1970-01-01 01:00:00.000000000 
+0100
+++ new/eventlet-0.14.0/tests/greendns_test.py  2013-08-20 14:50:45.000000000 
+0200
@@ -0,0 +1,13 @@
+from nose.plugins.skip import SkipTest
+
+
+def test_greendns_getnameinfo_resolve_port():
+    try:
+        from eventlet.support import greendns
+    except ImportError:
+        raise SkipTest('greendns requires package dnspython')
+
+    # https://bitbucket.org/eventlet/eventlet/issue/152
+    _, port1 = greendns.getnameinfo(('127.0.0.1', 80), 0)
+    _, port2 = greendns.getnameinfo(('localhost', 80), 0)
+    assert port1 == port2 == 'http'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/tests/mysqldb_test.py 
new/eventlet-0.14.0/tests/mysqldb_test.py
--- old/eventlet-0.13.0/tests/mysqldb_test.py   2013-07-02 18:25:04.000000000 
+0200
+++ new/eventlet-0.14.0/tests/mysqldb_test.py   2013-08-20 14:50:45.000000000 
+0200
@@ -34,6 +34,8 @@
 
 class MySQLdbTester(LimitedTestCase):
     def setUp(self):
+        super(MySQLdbTester, self).setUp()
+
         self._auth = get_database_auth()['MySQLdb']
         self.create_db()
         self.connection = None
@@ -51,6 +53,8 @@
             self.connection.close()
         self.drop_db()
 
+        super(MySQLdbTester, self).tearDown()
+
     @skip_unless(mysql_requirement)    
     def create_db(self):
         auth = self._auth.copy()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/tests/patcher_test.py 
new/eventlet-0.14.0/tests/patcher_test.py
--- old/eventlet-0.13.0/tests/patcher_test.py   2013-07-02 18:25:04.000000000 
+0200
+++ new/eventlet-0.14.0/tests/patcher_test.py   2013-08-20 14:50:45.000000000 
+0200
@@ -4,7 +4,8 @@
 import sys
 import tempfile
 
-from tests import LimitedTestCase, main, skip_with_pyevent
+from tests import LimitedTestCase, main, run_python, skip_with_pyevent
+
 
 base_module_contents = """
 import socket
@@ -27,32 +28,31 @@
 print "importing", patching, socket, patching.socket, patching.urllib
 """
 
+
 class ProcessBase(LimitedTestCase):
-    TEST_TIMEOUT=3 # starting processes is time-consuming
+    TEST_TIMEOUT = 3  # starting processes is time-consuming
+
     def setUp(self):
+        super(ProcessBase, self).setUp()
         self._saved_syspath = sys.path
         self.tempdir = tempfile.mkdtemp('_patcher_test')
-        
+
     def tearDown(self):
+        super(ProcessBase, self).tearDown()
         sys.path = self._saved_syspath
         shutil.rmtree(self.tempdir)
-        
+
     def write_to_tempfile(self, name, contents):
-        filename = os.path.join(self.tempdir, name + '.py')
-        fd = open(filename, "w")
+        filename = os.path.join(self.tempdir, name)
+        if not filename.endswith('.py'):
+            filename = filename + '.py'
+        fd = open(filename, "wb")
         fd.write(contents)
         fd.close()
-        
+
     def launch_subprocess(self, filename):
-        python_path = os.pathsep.join(sys.path + [self.tempdir])
-        new_env = os.environ.copy()
-        new_env['PYTHONPATH'] = python_path
-        if not filename.endswith('.py'):
-            filename = filename + '.py'
-        p = subprocess.Popen([sys.executable, 
-                              os.path.join(self.tempdir, filename)],
-                stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=new_env)
-        output, _ = p.communicate()
+        path = os.path.join(self.tempdir, filename)
+        output = run_python(path)
         lines = output.split("\n")
         return output, lines
 
@@ -77,7 +77,7 @@
         self.assert_('eventlet.green.socket' in lines[2], repr(output))
         self.assert_('eventlet.green.urllib' in lines[2], repr(output))
         self.assert_('eventlet.green.httplib' not in lines[2], repr(output))
-        
+
     def test_import_patched_defaults(self):
         self.write_to_tempfile("base", base_module_contents)
         new_mod = """
@@ -93,7 +93,7 @@
         self.assert_('GreenSocket' in lines[1], repr(output))
 
 
-class MonkeyPatch(ProcessBase):        
+class MonkeyPatch(ProcessBase):
     def test_patched_modules(self):
         new_mod = """
 from eventlet import patcher
@@ -106,7 +106,7 @@
         output, lines = self.launch_subprocess('newmod.py')
         self.assert_(lines[0].startswith('newmod'), repr(output))
         self.assertEqual(lines[0].count('GreenSocket'), 2, repr(output))
-        
+
     def test_early_patching(self):
         new_mod = """
 from eventlet import patcher
@@ -133,7 +133,7 @@
         output, lines = self.launch_subprocess('newmod.py')
         self.assertEqual(len(lines), 2, repr(output))
         self.assert_(lines[0].startswith('newmod'), repr(output))
-        
+
 
     def test_typeerror(self):
         new_mod = """
@@ -144,7 +144,7 @@
         output, lines = self.launch_subprocess('newmod.py')
         self.assert_(lines[-2].startswith('TypeError'), repr(output))
         self.assert_('finagle' in lines[-2], repr(output))
-        
+
 
     def assert_boolean_logic(self, call, expected, not_expected=''):
         expected_list = ", ".join(['"%s"' % x for x in expected.split(',') if 
len(x)])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/tests/ssl_test.py 
new/eventlet-0.14.0/tests/ssl_test.py
--- old/eventlet-0.13.0/tests/ssl_test.py       2013-07-02 18:25:04.000000000 
+0200
+++ new/eventlet-0.14.0/tests/ssl_test.py       2013-08-20 14:50:45.000000000 
+0200
@@ -1,9 +1,17 @@
-from tests import LimitedTestCase, certificate_file, private_key_file, 
check_idle_cpu_usage
-from tests import skip_if_no_ssl
+import socket
+import warnings
 from unittest import main
+
 import eventlet
 from eventlet import util, greenio
-import socket
+try:
+    from eventlet.green.socket import ssl
+except ImportError:
+    pass
+from tests import (
+    LimitedTestCase, certificate_file, private_key_file, check_idle_cpu_usage,
+    skip_if_no_ssl
+)
 
 
 def listen_ssl_socket(address=('127.0.0.1', 0)):
@@ -16,6 +24,15 @@
 
 
 class SSLTest(LimitedTestCase):
+    def setUp(self):
+        # disabling socket.ssl warnings because we're testing it here
+        warnings.filterwarnings(
+            action='ignore',
+            message='.*socket.ssl.*',
+            category=DeprecationWarning)
+
+        super(SSLTest, self).setUp()
+
     @skip_if_no_ssl
     def test_duplex_response(self):
         def serve(listener):
@@ -133,16 +150,8 @@
         check_idle_cpu_usage(0.2, 0.1)
         server_coro.kill()
 
-
-class SocketSSLTest(LimitedTestCase):
     @skip_if_no_ssl
     def test_greensslobject(self):
-        import warnings
-        # disabling socket.ssl warnings because we're testing it here
-        warnings.filterwarnings(action = 'ignore',
-                        message='.*socket.ssl.*',
-                        category=DeprecationWarning)
-
         def serve(listener):
             sock, addr = listener.accept()
             sock.write('content')
@@ -150,11 +159,24 @@
             sock.close()
         listener = listen_ssl_socket(('', 0))
         killer = eventlet.spawn(serve, listener)
-        from eventlet.green.socket import ssl
         client = ssl(eventlet.connect(('localhost', 
listener.getsockname()[1])))
         self.assertEquals(client.read(1024), 'content')
         self.assertEquals(client.read(1024), '')
 
+    @skip_if_no_ssl
+    def test_regression_gh_17(self):
+        def serve(listener):
+            sock, addr = listener.accept()
+
+            # to simulate condition mentioned in GH-17
+            sock._sslobj = None
+            sock.sendall('some data')
+            greenio.shutdown_safe(sock)
+            sock.close()
+
+        listener = listen_ssl_socket(('', 0))
+        killer = eventlet.spawn(serve, listener)
+        client = ssl(eventlet.connect(('localhost', 
listener.getsockname()[1])))
 
 if __name__ == '__main__':
     main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/tests/wsgi_test.py 
new/eventlet-0.14.0/tests/wsgi_test.py
--- old/eventlet-0.13.0/tests/wsgi_test.py      2013-07-02 18:25:04.000000000 
+0200
+++ new/eventlet-0.14.0/tests/wsgi_test.py      2013-09-13 15:50:20.000000000 
+0200
@@ -14,7 +14,7 @@
 from eventlet import wsgi
 from eventlet.support import get_errno
 
-from tests import find_command
+from tests import find_command, run_python
 
 httplib = eventlet.import_patched('httplib')
 
@@ -195,15 +195,10 @@
         super(_TestBase, self).tearDown()
 
     def spawn_server(self, **kwargs):
-        """Spawns a new wsgi server with the given arguments.
-        Sets self.port to the port of the server, and self.killer is the 
greenlet
-        running it.
-
-        Kills any previously-running server."""
-        eventlet.sleep(0) # give previous server a chance to start
-        if self.killer:
-            greenthread.kill(self.killer)
+        """Spawns a new wsgi server with the given arguments using
+        :meth:`spawn_thread`.
 
+        Sets self.port to the port of the server"""
         new_kwargs = dict(max_size=128,
                           log=self.logfile,
                           site=self.site)
@@ -213,9 +208,19 @@
             new_kwargs['sock'] = eventlet.listen(('localhost', 0))
 
         self.port = new_kwargs['sock'].getsockname()[1]
-        self.killer = eventlet.spawn_n(
-            wsgi.server,
-            **new_kwargs)
+        self.spawn_thread(wsgi.server, **new_kwargs)
+
+    def spawn_thread(self, target, **kwargs):
+        """Spawns a new greenthread using specified target and arguments.
+
+        Kills any previously-running server and sets self.killer to the
+        greenthread running the target.
+        """
+        eventlet.sleep(0)  # give previous server a chance to start
+        if self.killer:
+            greenthread.kill(self.killer)
+
+        self.killer = eventlet.spawn_n(target, **kwargs)
 
     def set_site(self):
         raise NotImplementedError
@@ -956,6 +961,34 @@
             'HTTP/1.0 400 Headers Too Large\r\n')
         fd.close()
 
+    def test_032_wsgi_input_as_iterable(self):
+        # https://bitbucket.org/eventlet/eventlet/issue/150
+        # env['wsgi.input'] returns a single byte at a time
+        # when used as an iterator
+        g = [0]
+
+        def echo_by_iterating(env, start_response):
+            start_response('200 OK', [('Content-type', 'text/plain')])
+            for chunk in env['wsgi.input']:
+                g[0] += 1
+                yield chunk
+
+        self.site.application = echo_by_iterating
+        upload_data = '123456789abcdef' * 100
+        request = (
+            'POST / HTTP/1.0\r\n'
+            'Host: localhost\r\n'
+            'Content-Length: %i\r\n\r\n%s'
+        ) % (len(upload_data), upload_data)
+        sock = eventlet.connect(('localhost', self.port))
+        fd = sock.makefile('rw')
+        fd.write(request)
+        fd.flush()
+        response_line, headers, body = read_http(sock)
+        self.assertEquals(body, upload_data)
+        fd.close()
+        self.assertEquals(g[0], 1)
+
     def test_zero_length_chunked_response(self):
         def zero_chunked_app(env, start_response):
             start_response('200 OK', [('Content-type', 'text/plain')])
@@ -1076,12 +1109,15 @@
             return
         log = StringIO()
         # first thing the server does is try to log the IP it's bound to
+
         def run_server():
             try:
-                server = wsgi.server(sock=sock, log=log, site=Site())
+                wsgi.server(sock=sock, log=log, site=Site())
             except ValueError:
                 log.write('broked')
-        eventlet.spawn_n(run_server)
+
+        self.spawn_thread(run_server)
+
         logval = log.getvalue()
         while not logval:
             eventlet.sleep(0.0)
@@ -1144,6 +1180,38 @@
         request_thread.wait()
         server_sock.close()
 
+    def test_server_connection_timeout_exception(self):
+        # Handle connection socket timeouts
+        # https://bitbucket.org/eventlet/eventlet/issue/143/
+        # Runs tests.wsgi_test_conntimeout in a separate process.
+        testcode_path = os.path.join(
+            os.path.dirname(os.path.abspath(__file__)),
+            'wsgi_test_conntimeout.py')
+        output = run_python(testcode_path)
+        sections = output.split("SEPERATOR_SENTINEL")
+        # first section is empty
+        self.assertEqual(3, len(sections), output)
+        # if the "BOOM" check fails, it's because our timeout didn't happen
+        # (if eventlet stops using file.readline() to read HTTP headers,
+        # for instance)
+        for runlog in sections[1:]:
+            debug = False if "debug set to: False" in runlog else True
+            if debug:
+                self.assertTrue("timed out" in runlog)
+            self.assertTrue("BOOM" in runlog)
+            self.assertFalse("Traceback" in runlog)
+
+    def test_server_socket_timeout(self):
+        self.spawn_server(socket_timeout=0.1)
+        sock = eventlet.connect(('localhost', self.port))
+        sock.send('GET / HTTP/1.1\r\n')
+        eventlet.sleep(0.1)
+        try:
+            read_http(sock)
+            assert False, 'Expected ConnectionClosed exception'
+        except ConnectionClosed:
+            pass
+
 
 def read_headers(sock):
     fd = sock.makefile()
@@ -1173,6 +1241,7 @@
         headers[key.lower()] = value
     return response_line, headers
 
+
 class IterableAlreadyHandledTest(_TestBase):
     def set_site(self):
         self.site = IterableSite()
@@ -1199,6 +1268,7 @@
         self.assertEqual(headers.get('transfer-encoding'), 'chunked')
         self.assertEqual(body, '0\r\n\r\n') # Still coming back chunked
 
+
 class ProxiedIterableAlreadyHandledTest(IterableAlreadyHandledTest):
     # same thing as the previous test but ensuring that it works with tpooled
     # results as well as regular ones
@@ -1212,6 +1282,7 @@
         tpool.killall()
         super(ProxiedIterableAlreadyHandledTest, self).tearDown()
 
+
 class TestChunkedInput(_TestBase):
     dirt = ""
     validator = None
@@ -1230,6 +1301,24 @@
         elif pi=="/ping":
             input.read()
             response.append("pong")
+        elif pi.startswith("/yield_spaces"):
+            if pi.endswith('override_min'):
+                env['eventlet.minimum_write_chunk_size'] = 1
+            self.yield_next_space = False
+
+            def response_iter():
+                yield ' '
+                num_sleeps = 0
+                while not self.yield_next_space and num_sleeps < 200:
+                    eventlet.sleep(.01)
+                    num_sleeps += 1
+
+                yield ' '
+
+            start_response('200 OK',
+                           [('Content-Type', 'text/plain'),
+                            ('Content-Length', '2')])
+            return response_iter()
         else:
             raise RuntimeError("bad path")
 
@@ -1306,6 +1395,50 @@
         fd.sendall(req)
         self.assertEquals(read_http(fd)[-1], 'this is chunked\nline 2\nline3')
 
+    def test_chunked_readline_wsgi_override_minimum_chunk_size(self):
+
+        fd = self.connect()
+        fd.sendall("POST /yield_spaces/override_min 
HTTP/1.1\r\nContent-Length: 0\r\n\r\n")
+
+        resp_so_far = ''
+        with eventlet.Timeout(.1):
+            while True:
+                one_byte = fd.recv(1)
+                resp_so_far += one_byte
+                if resp_so_far.endswith('\r\n\r\n'):
+                    break
+            self.assertEquals(fd.recv(1), ' ')
+        try:
+            with eventlet.Timeout(.1):
+                fd.recv(1)
+        except eventlet.Timeout:
+            pass
+        else:
+            self.assert_(False)
+        self.yield_next_space = True
+
+        with eventlet.Timeout(.1):
+            self.assertEquals(fd.recv(1), ' ')
+
+    def test_chunked_readline_wsgi_not_override_minimum_chunk_size(self):
+
+        fd = self.connect()
+        fd.sendall("POST /yield_spaces HTTP/1.1\r\nContent-Length: 0\r\n\r\n")
+
+        resp_so_far = ''
+        try:
+            with eventlet.Timeout(.1):
+                while True:
+                    one_byte = fd.recv(1)
+                    resp_so_far += one_byte
+                    if resp_so_far.endswith('\r\n\r\n'):
+                        break
+                self.assertEquals(fd.recv(1), ' ')
+        except eventlet.Timeout:
+            pass
+        else:
+            self.assert_(False)
+
     def test_close_before_finished(self):
         import signal
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/eventlet-0.13.0/tests/wsgi_test_conntimeout.py 
new/eventlet-0.14.0/tests/wsgi_test_conntimeout.py
--- old/eventlet-0.13.0/tests/wsgi_test_conntimeout.py  1970-01-01 
01:00:00.000000000 +0100
+++ new/eventlet-0.14.0/tests/wsgi_test_conntimeout.py  2013-08-20 
14:50:45.000000000 +0200
@@ -0,0 +1,163 @@
+"""Issue #143 - Socket timeouts in wsgi server not caught.
+https://bitbucket.org/eventlet/eventlet/issue/143/
+
+This file intentionally ignored by nose.
+Caller process (tests.wsgi_test.TestWsgiConnTimeout) handles success / failure
+
+
+Simulate server connection socket timeout without actually waiting.
+Logs 'timed out' if server debug=True (similar to 'accepted' logging)
+
+FAIL: if log (ie, _spawn_n_impl 'except:' catches timeout, logs TB)
+NOTE: timeouts are NOT on server_sock, but on the conn sockets produced
+by the socket.accept() call
+
+server's socket.listen() sock - NaughtySocketAcceptWrap
+    /  |  \
+    |  |  |   (1 - many)
+    V  V  V
+server / client accept() conn - ExplodingConnectionWrap
+    /  |  \
+    |  |  |   (1 - many)
+    V  V  V
+connection makefile() file objects - ExplodingSocketFile <-- these raise
+"""
+
+import eventlet
+
+import socket
+import sys
+
+import tests.wsgi_test
+
+
+# no standard tests in this file, ignore
+__test__ = False
+
+
+# This test might make you wince
+class NaughtySocketAcceptWrap(object):
+    # server's socket.accept(); patches resulting connection sockets
+
+    def __init__(self, sock):
+        self.sock = sock
+        self.sock._really_accept = self.sock.accept
+        self.sock.accept = self
+        self.conn_reg = []
+
+    def unwrap(self):
+        self.sock.accept = self.sock._really_accept
+        del self.sock._really_accept
+        for conn_wrap in self.conn_reg:
+            conn_wrap.unwrap()
+
+    def arm(self):
+        print "ca-click"
+        for i in self.conn_reg:
+            i.arm()
+
+    def __call__(self):
+        print self.__class__.__name__ + ".__call__"
+        conn, addr = self.sock._really_accept()
+        self.conn_reg.append(ExplodingConnectionWrap(conn))
+        return conn, addr
+
+
+class ExplodingConnectionWrap(object):
+    # new connection's socket.makefile
+    # eventlet *tends* to use socket.makefile, not raw socket methods.
+    # need to patch file operations
+
+    def __init__(self, conn):
+        self.conn = conn
+        self.conn._really_makefile = self.conn.makefile
+        self.conn.makefile = self
+        self.armed = False
+        self.file_reg = []
+
+    def unwrap(self):
+        self.conn.makefile = self.conn._really_makefile
+        del self.conn._really_makefile
+
+    def arm(self):
+        print "tick"
+        for i in self.file_reg:
+            i.arm()
+
+    def __call__(self, mode='r', bufsize=-1):
+        print self.__class__.__name__ + ".__call__"
+        # file_obj = self.conn._really_makefile(*args, **kwargs)
+        file_obj = ExplodingSocketFile(self.conn._sock, mode, bufsize)
+        self.file_reg.append(file_obj)
+        return file_obj
+
+
+class ExplodingSocketFile(socket._fileobject):
+
+    def __init__(self, sock, mode='rb', bufsize=-1, close=False):
+        super(self.__class__, self).__init__(sock, mode, bufsize, close)
+        self.armed = False
+
+    def arm(self):
+        print "beep"
+        self.armed = True
+
+    def _fuse(self):
+        if self.armed:
+            print "=== ~* BOOM *~ ==="
+            raise socket.timeout("timed out")
+
+    def readline(self, *args, **kwargs):
+        print self.__class__.__name__ + ".readline"
+        self._fuse()
+        return super(self.__class__, self).readline(*args, **kwargs)
+
+
+if __name__ == '__main__':
+    for debug in (False, True):
+        print "SEPERATOR_SENTINEL"
+        print "debug set to: %s" % debug
+
+        server_sock = eventlet.listen(('localhost', 0))
+        server_addr = server_sock.getsockname()
+        sock_wrap = NaughtySocketAcceptWrap(server_sock)
+
+        eventlet.spawn_n(
+            eventlet.wsgi.server,
+            debug=debug,
+            log=sys.stdout,
+            max_size=128,
+            site=tests.wsgi_test.Site(),
+            sock=server_sock,
+        )
+
+        try:
+            # req #1 - normal
+            sock1 = eventlet.connect(server_addr)
+            sock1.settimeout(0.1)
+            fd1 = sock1.makefile('rw')
+            fd1.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
+            fd1.flush()
+            tests.wsgi_test.read_http(sock1)
+
+            # let the server socket ops catch up, set bomb
+            eventlet.sleep(0)
+            print "arming..."
+            sock_wrap.arm()
+
+            # req #2 - old conn, post-arm - timeout
+            fd1.write('GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
+            fd1.flush()
+            try:
+                tests.wsgi_test.read_http(sock1)
+                assert False, 'Expected ConnectionClosed exception'
+            except tests.wsgi_test.ConnectionClosed:
+                pass
+
+            fd1.close()
+            sock1.close()
+        finally:
+            # reset streams, then output trapped tracebacks
+            sock_wrap.unwrap()
+        # check output asserts in tests.wsgi_test.TestHttpd
+        # test_143_server_connection_timeout_exception

-- 
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to