diff --git a/eventlet/__init__.py b/eventlet/__init__.py index 7361da2..dda5923 100644 --- a/eventlet/__init__.py +++ b/eventlet/__init__.py @@ -1,4 +1,4 @@ -version_info = (0, 9, 7, "dev1") +version_info = (0, 9, 8, "dev1") __version__ = ".".join(map(str, version_info)) try: diff --git a/eventlet/support/psycopg2_patcher.py b/eventlet/support/psycopg2_patcher.py index 7d9c1d5..29af65d 100644 --- a/eventlet/support/psycopg2_patcher.py +++ b/eventlet/support/psycopg2_patcher.py @@ -38,15 +38,20 @@ def make_psycopg_green(): extensions.set_wait_callback(eventlet_wait_callback) -def eventlet_wait_callback(conn, timeout=-1): +def eventlet_wait_callback(conn, timeout=-1, + # access these objects with LOAD_FAST instead of LOAD_GLOBAL lookup + POLL_OK=extensions.POLL_OK, + POLL_READ=extensions.POLL_READ, + POLL_WRITE=extensions.POLL_WRITE, + trampoline=trampoline): """A wait callback useful to allow eventlet to work with Psycopg.""" while 1: state = conn.poll() - if state == extensions.POLL_OK: + if state == POLL_OK: break - elif state == extensions.POLL_READ: + elif state == POLL_READ: trampoline(conn.fileno(), read=True) - elif state == extensions.POLL_WRITE: + elif state == POLL_WRITE: trampoline(conn.fileno(), write=True) else: raise psycopg2.OperationalError( diff --git a/eventlet/tpool.py b/eventlet/tpool.py index 7e9dd45..0db26fd 100644 --- a/eventlet/tpool.py +++ b/eventlet/tpool.py @@ -231,7 +231,7 @@ def setup(): _rpipe, _wpipe = os.pipe() _wfile = greenio.GreenPipe(_wpipe, 'wb', 0) _rfile = greenio.GreenPipe(_rpipe, 'rb', 0) - except ImportError: + except (ImportError, NotImplementedError): # This is Windows compatibility -- use a socket instead of a pipe because # pipes don't really exist on Windows. import socket diff --git a/eventlet/wsgi.py b/eventlet/wsgi.py index 1b46395..e490e1a 100644 --- a/eventlet/wsgi.py +++ b/eventlet/wsgi.py @@ -111,8 +111,11 @@ class Input(object): if self.chunk_length > self.position: response.append(rfile.read( min(self.chunk_length - self.position, length))) - length -= len(response[-1]) - self.position += len(response[-1]) + last_read = len(response[-1]) + if last_read == 0: + break + length -= last_read + self.position += last_read if self.chunk_length == self.position: rfile.readline() else: diff --git a/tests/wsgi_test.py b/tests/wsgi_test.py index 5e79def..e4de67e 100644 --- a/tests/wsgi_test.py +++ b/tests/wsgi_test.py @@ -11,6 +11,7 @@ from unittest import main from eventlet import api from eventlet import util from eventlet import greenio +from eventlet import event from eventlet.green import socket as greensocket from eventlet import wsgi from eventlet.support import get_errno @@ -833,6 +834,28 @@ class TestHttpd(_TestBase): # (one terminates the chunk, one terminates the body) self.assertEqual(response, ['0', '', '']) + def test_aborted_chunked_post(self): + read_content = event.Event() + def chunk_reader(env, start_response): + content = env['wsgi.input'].read(1024) + read_content.send(content) + start_response('200 OK', [('Content-Type', 'text/plain')]) + return [content] + self.site.application = chunk_reader + expected_body = 'a bunch of stuff' + data = "\r\n".join(['PUT /somefile HTTP/1.0', + 'Transfer-Encoding: chunked', + '', + 'def', + expected_body]) + # start PUT-ing some chunked data but close prematurely + sock = eventlet.connect(('127.0.0.1', self.port)) + sock.sendall(data) + sock.close() + # the test passes if we successfully get here, and read all the data + # in spite of the early close + self.assertEqual(read_content.wait(), expected_body) + def read_headers(sock): fd = sock.makefile() try: