Add python-eventlet package to MOS 9.0 repository
[packages/trusty/python-eventlet.git] / python-eventlet / tests / wsgi_test.py
index d5cea188f212505f28bc55b495b7a44a13b70019..37c425077a8101df931a479a78ab8c0d4373740d 100644 (file)
@@ -2,25 +2,25 @@ import cgi
 import collections
 import errno
 import os
 import collections
 import errno
 import os
+import shutil
 import signal
 import socket
 import sys
 import signal
 import socket
 import sys
+import tempfile
 import traceback
 import unittest
 
 import eventlet
 from eventlet import debug
 from eventlet import event
 import traceback
 import unittest
 
 import eventlet
 from eventlet import debug
 from eventlet import event
-from eventlet.green import socket as greensocket
-from eventlet.green import ssl
-from eventlet.green import subprocess
 from eventlet import greenio
 from eventlet import greenthread
 from eventlet import support
 from eventlet import greenio
 from eventlet import greenthread
 from eventlet import support
-from eventlet.support import bytes_to_str, capture_stderr, six
 from eventlet import tpool
 from eventlet import wsgi
 from eventlet import tpool
 from eventlet import wsgi
-
+from eventlet.green import socket as greensocket
+from eventlet.green import ssl
+from eventlet.support import bytes_to_str, capture_stderr, six
 import tests
 
 
 import tests
 
 
@@ -136,24 +136,13 @@ class IterableSite(Site):
 CONTENT_LENGTH = 'content-length'
 
 
 CONTENT_LENGTH = 'content-length'
 
 
-"""
-HTTP/1.1 200 OK
-Date: foo
-Content-length: 11
-
-hello world
-"""
-
-
-def recvall(socket_):
+def recvall(sock):
     result = b''
     while True:
     result = b''
     while True:
-        chunk = socket_.recv()
-        result += chunk
+        chunk = sock.recv(16 << 10)
         if chunk == b'':
         if chunk == b'':
-            break
-
-    return result
+            return result
+        result += chunk
 
 
 class ConnectionClosed(Exception):
 
 
 class ConnectionClosed(Exception):
@@ -244,7 +233,7 @@ class _TestBase(tests.LimitedTestCase):
         """Spawns a new wsgi server with the given arguments using
         :meth:`spawn_thread`.
 
         """Spawns a new wsgi server with the given arguments using
         :meth:`spawn_thread`.
 
-        Sets self.port to the port of the server
+        Sets `self.server_addr` to (host, port) tuple suitable for `socket.connect`.
         """
         new_kwargs = dict(max_size=128,
                           log=self.logfile,
         """
         new_kwargs = dict(max_size=128,
                           log=self.logfile,
@@ -254,7 +243,7 @@ class _TestBase(tests.LimitedTestCase):
         if 'sock' not in new_kwargs:
             new_kwargs['sock'] = eventlet.listen(('localhost', 0))
 
         if 'sock' not in new_kwargs:
             new_kwargs['sock'] = eventlet.listen(('localhost', 0))
 
-        self.port = new_kwargs['sock'].getsockname()[1]
+        self.server_addr = new_kwargs['sock'].getsockname()
         self.spawn_thread(wsgi.server, **new_kwargs)
 
     def spawn_thread(self, target, **kwargs):
         self.spawn_thread(wsgi.server, **new_kwargs)
 
     def spawn_thread(self, target, **kwargs):
@@ -278,72 +267,37 @@ class TestHttpd(_TestBase):
         self.site = Site()
 
     def test_001_server(self):
         self.site = Site()
 
     def test_001_server(self):
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
 
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
-        fd.flush()
-        result = fd.read()
-        fd.close()
+        sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+        result = recvall(sock)
         # The server responds with the maximum version it supports
         assert result.startswith(b'HTTP'), result
         assert result.endswith(b'hello world'), result
 
     def test_002_keepalive(self):
         # The server responds with the maximum version it supports
         assert result.startswith(b'HTTP'), result
         assert result.endswith(b'hello world'), result
 
     def test_002_keepalive(self):
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
 
-        fd = sock.makefile('wb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         read_http(sock)
         read_http(sock)
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         read_http(sock)
         read_http(sock)
-        fd.close()
-        sock.close()
-
-    def test_003_passing_non_int_to_read(self):
-        # This should go in greenio_test
-        sock = eventlet.connect(
-            ('localhost', self.port))
-
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
-        cancel = eventlet.Timeout(1, RuntimeError)
-        self.assertRaises(TypeError, fd.read, "This shouldn't work")
-        cancel.cancel()
-        fd.close()
 
     def test_004_close_keepalive(self):
 
     def test_004_close_keepalive(self):
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
 
-        fd = sock.makefile('wb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
-        read_http(sock)
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
-        fd.flush()
-        read_http(sock)
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
+        result1 = read_http(sock)
+        assert result1.status == 'HTTP/1.1 200 OK'
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+        result2 = read_http(sock)
+        assert result2.status == 'HTTP/1.1 200 OK'
+        assert result2.headers_lower['connection'] == 'close'
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         self.assertRaises(ConnectionClosed, read_http, sock)
         self.assertRaises(ConnectionClosed, read_http, sock)
-        fd.close()
-
-    @tests.skipped
-    def test_005_run_apachebench(self):
-        url = 'http://localhost:12346/'
-        # ab is apachebench
-        subprocess.call(
-            [tests.find_command('ab'), '-c', '64', '-n', '1024', '-k', url],
-            stdout=subprocess.PIPE)
 
     def test_006_reject_long_urls(self):
 
     def test_006_reject_long_urls(self):
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         path_parts = []
         for ii in range(3000):
             path_parts.append('path')
         path_parts = []
         for ii in range(3000):
             path_parts.append('path')
@@ -368,65 +322,48 @@ class TestHttpd(_TestBase):
             return [six.b('a is %s, body is %s' % (a, body))]
 
         self.site.application = new_app
             return [six.b('a is %s, body is %s' % (a, body))]
 
         self.site.application = new_app
-        sock = eventlet.connect(
-            ('localhost', self.port))
-        request = '\r\n'.join((
-            'POST / HTTP/1.0',
-            'Host: localhost',
-            'Content-Length: 3',
-            '',
-            'a=a'))
-        fd = sock.makefile('wb')
-        fd.write(request.encode())
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
+        request = b'\r\n'.join((
+            b'POST / HTTP/1.0',
+            b'Host: localhost',
+            b'Content-Length: 3',
+            b'',
+            b'a=a'))
+        sock.sendall(request)
 
         # send some junk after the actual request
 
         # send some junk after the actual request
-        fd.write(b'01234567890123456789')
+        sock.sendall(b'01234567890123456789')
         result = read_http(sock)
         self.assertEqual(result.body, b'a is a, body is a=a')
         result = read_http(sock)
         self.assertEqual(result.body, b'a is a, body is a=a')
-        fd.close()
 
     def test_008_correctresponse(self):
 
     def test_008_correctresponse(self):
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
 
-        fd = sock.makefile('wb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         result_200 = read_http(sock)
         result_200 = read_http(sock)
-        fd.write(b'GET /notexist HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
+        sock.sendall(b'GET /notexist HTTP/1.1\r\nHost: localhost\r\n\r\n')
         read_http(sock)
         read_http(sock)
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         result_test = read_http(sock)
         self.assertEqual(result_200.status, result_test.status)
         result_test = read_http(sock)
         self.assertEqual(result_200.status, result_test.status)
-        fd.close()
-        sock.close()
 
     def test_009_chunked_response(self):
         self.site.application = chunked_app
 
     def test_009_chunked_response(self):
         self.site.application = chunked_app
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
 
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
-        fd.flush()
-        assert b'Transfer-Encoding: chunked' in fd.read()
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+        assert b'Transfer-Encoding: chunked' in recvall(sock)
 
     def test_010_no_chunked_http_1_0(self):
         self.site.application = chunked_app
 
     def test_010_no_chunked_http_1_0(self):
         self.site.application = chunked_app
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
 
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
-        fd.flush()
-        assert b'Transfer-Encoding: chunked' not in fd.read()
+        sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+        assert b'Transfer-Encoding: chunked' not in recvall(sock)
 
     def test_011_multiple_chunks(self):
         self.site.application = big_chunks
 
     def test_011_multiple_chunks(self):
         self.site.application = big_chunks
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
         fd = sock.makefile('rwb')
         fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
 
         fd = sock.makefile('rwb')
         fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
@@ -451,6 +388,54 @@ class TestHttpd(_TestBase):
         # Require a CRLF to close the message body
         self.assertEqual(response, b'\r\n')
 
         # Require a CRLF to close the message body
         self.assertEqual(response, b'\r\n')
 
+    def test_partial_writes_are_handled(self):
+        # https://github.com/eventlet/eventlet/issues/295
+        # Eventlet issue: "Python 3: wsgi doesn't handle correctly partial
+        # write of socket send() when using writelines()".
+        #
+        # The bug was caused by the default writelines() implementaiton
+        # (used by the wsgi module) which doesn't check if write()
+        # successfully completed sending *all* data therefore data could be
+        # lost and the client could be left hanging forever.
+        #
+        # Switching wsgi wfile to buffered mode fixes the issue.
+        #
+        # Related CPython issue: "Raw I/O writelines() broken",
+        # http://bugs.python.org/issue26292
+        #
+        # Custom accept() and send() in order to simulate a connection that
+        # only sends one byte at a time so that any code that doesn't handle
+        # partial writes correctly has to fail.
+        listen_socket = eventlet.listen(('localhost', 0))
+        original_accept = listen_socket.accept
+
+        def accept():
+            connection, address = original_accept()
+            original_send = connection.send
+
+            def send(b, *args):
+                b = b[:1]
+                return original_send(b, *args)
+
+            connection.send = send
+            return connection, address
+
+        listen_socket.accept = accept
+
+        def application(env, start_response):
+            # Sending content-length is important here so that the client knows
+            # exactly how many bytes does it need to wait for.
+            start_response('200 OK', [('Content-length', 3)])
+            yield 'asd'
+
+        self.spawn_server(sock=listen_socket)
+        self.site.application = application
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
+        # This would previously hang forever
+        result = read_http(sock)
+        assert result.body == b'asd'
+
     @tests.skip_if_no_ssl
     def test_012_ssl_server(self):
         def wsgi_app(environ, start_response):
     @tests.skip_if_no_ssl
     def test_012_ssl_server(self):
         def wsgi_app(environ, start_response):
@@ -466,7 +451,7 @@ class TestHttpd(_TestBase):
                                         server_side=True)
         self.spawn_server(sock=server_sock, site=wsgi_app)
 
                                         server_side=True)
         self.spawn_server(sock=server_sock, site=wsgi_app)
 
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         sock = eventlet.wrap_ssl(sock)
         sock.write(
             b'POST /foo HTTP/1.1\r\nHost: localhost\r\n'
         sock = eventlet.wrap_ssl(sock)
         sock.write(
             b'POST /foo HTTP/1.1\r\nHost: localhost\r\n'
@@ -496,7 +481,7 @@ class TestHttpd(_TestBase):
 
     def test_014_chunked_post(self):
         self.site.application = chunked_post
 
     def test_014_chunked_post(self):
         self.site.application = chunked_post
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         fd = sock.makefile('rwb')
         fd.write('PUT /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
                  'Transfer-Encoding: chunked\r\n\r\n'
         fd = sock.makefile('rwb')
         fd.write('PUT /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
                  'Transfer-Encoding: chunked\r\n\r\n'
@@ -508,7 +493,7 @@ class TestHttpd(_TestBase):
         response = fd.read()
         assert response == b'oh hai', 'invalid response %s' % response
 
         response = fd.read()
         assert response == b'oh hai', 'invalid response %s' % response
 
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         fd = sock.makefile('rwb')
         fd.write('PUT /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
                  'Transfer-Encoding: chunked\r\n\r\n'
         fd = sock.makefile('rwb')
         fd.write('PUT /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
                  'Transfer-Encoding: chunked\r\n\r\n'
@@ -520,7 +505,7 @@ class TestHttpd(_TestBase):
         response = fd.read()
         assert response == b'oh hai', 'invalid response %s' % response
 
         response = fd.read()
         assert response == b'oh hai', 'invalid response %s' % response
 
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         fd = sock.makefile('rwb')
         fd.write('PUT /c HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
                  'Transfer-Encoding: chunked\r\n\r\n'
         fd = sock.makefile('rwb')
         fd.write('PUT /c HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n'
                  'Transfer-Encoding: chunked\r\n\r\n'
@@ -534,17 +519,13 @@ class TestHttpd(_TestBase):
 
     def test_015_write(self):
         self.site.application = use_write
 
     def test_015_write(self):
         self.site.application = use_write
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('wb')
-        fd.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
         result1 = read_http(sock)
         assert 'content-length' in result1.headers_lower
 
         result1 = read_http(sock)
         assert 'content-length' in result1.headers_lower
 
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('wb')
-        fd.write(b'GET /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET /b HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
         result2 = read_http(sock)
         assert 'transfer-encoding' in result2.headers_lower
         assert result2.headers_lower['transfer-encoding'] == 'chunked'
         result2 = read_http(sock)
         assert 'transfer-encoding' in result2.headers_lower
         assert result2.headers_lower['transfer-encoding'] == 'chunked'
@@ -557,7 +538,7 @@ class TestHttpd(_TestBase):
             start_response('200 OK', [('Content-Length', '7')])
             return [b'testing']
         self.site.application = wsgi_app
             start_response('200 OK', [('Content-Length', '7')])
             return [b'testing']
         self.site.application = wsgi_app
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         fd = sock.makefile('rwb')
         fd.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
         fd.flush()
         fd = sock.makefile('rwb')
         fd.write(b'GET /a HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
         fd.flush()
@@ -609,19 +590,15 @@ class TestHttpd(_TestBase):
     def test_018_http_10_keepalive(self):
         # verify that if an http/1.0 client sends connection: keep-alive
         # that we don't close the connection
     def test_018_http_10_keepalive(self):
         # verify that if an http/1.0 client sends connection: keep-alive
         # that we don't close the connection
-        sock = eventlet.connect(
-            ('localhost', self.port))
-
-        fd = sock.makefile('wb')
-        fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
 
 
+        sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
         result1 = read_http(sock)
         assert 'connection' in result1.headers_lower
         self.assertEqual('keep-alive', result1.headers_lower['connection'])
         result1 = read_http(sock)
         assert 'connection' in result1.headers_lower
         self.assertEqual('keep-alive', result1.headers_lower['connection'])
+
         # repeat request to verify connection is actually still open
         # repeat request to verify connection is actually still open
-        fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
-        fd.flush()
+        sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
         result2 = read_http(sock)
         assert 'connection' in result2.headers_lower
         self.assertEqual('keep-alive', result2.headers_lower['connection'])
         result2 = read_http(sock)
         assert 'connection' in result2.headers_lower
         self.assertEqual('keep-alive', result2.headers_lower['connection'])
@@ -634,18 +611,15 @@ class TestHttpd(_TestBase):
             return [b'hello!']
 
         self.site.application = use_fieldstorage
             return [b'hello!']
 
         self.site.application = use_fieldstorage
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
 
-        fd = sock.makefile('rwb')
-        fd.write('POST / HTTP/1.1\r\n'
-                 'Host: localhost\r\n'
-                 'Connection: close\r\n'
-                 'Transfer-Encoding: chunked\r\n\r\n'
-                 '2\r\noh\r\n'
-                 '4\r\n hai\r\n0\r\n\r\n'.encode())
-        fd.flush()
-        assert b'hello!' in fd.read()
+        sock.sendall(b'POST / HTTP/1.1\r\n'
+                     b'Host: localhost\r\n'
+                     b'Connection: close\r\n'
+                     b'Transfer-Encoding: chunked\r\n\r\n'
+                     b'2\r\noh\r\n'
+                     b'4\r\n hai\r\n0\r\n\r\n')
+        assert b'hello!' in recvall(sock)
 
     def test_020_x_forwarded_for(self):
         request_bytes = (
 
     def test_020_x_forwarded_for(self):
         request_bytes = (
@@ -653,7 +627,7 @@ class TestHttpd(_TestBase):
             + b'X-Forwarded-For: 1.2.3.4, 5.6.7.8\r\n\r\n'
         )
 
             + b'X-Forwarded-For: 1.2.3.4, 5.6.7.8\r\n\r\n'
         )
 
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         sock.sendall(request_bytes)
         sock.recv(1024)
         sock.close()
         sock.sendall(request_bytes)
         sock.recv(1024)
         sock.close()
@@ -663,7 +637,7 @@ class TestHttpd(_TestBase):
         self.logfile = six.StringIO()
         self.spawn_server(log_x_forwarded_for=False)
 
         self.logfile = six.StringIO()
         self.spawn_server(log_x_forwarded_for=False)
 
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         sock.sendall(request_bytes)
         sock.recv(1024)
         sock.close()
         sock.sendall(request_bytes)
         sock.recv(1024)
         sock.close()
@@ -677,12 +651,9 @@ class TestHttpd(_TestBase):
         server_sock_2 = server_sock.dup()
         self.spawn_server(sock=server_sock_2)
         # do a single req/response to verify it's up
         server_sock_2 = server_sock.dup()
         self.spawn_server(sock=server_sock_2)
         # do a single req/response to verify it's up
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
-        fd.flush()
-        result = fd.read(1024)
-        fd.close()
+        sock = eventlet.connect(server_sock.getsockname())
+        sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+        result = sock.recv(1024)
         assert result.startswith(b'HTTP'), result
         assert result.endswith(b'hello world'), result
 
         assert result.startswith(b'HTTP'), result
         assert result.endswith(b'hello world'), result
 
@@ -696,12 +667,9 @@ class TestHttpd(_TestBase):
         except socket.error as exc:
             self.assertEqual(support.get_errno(exc), errno.EBADF)
         self.spawn_server(sock=server_sock)
         except socket.error as exc:
             self.assertEqual(support.get_errno(exc), errno.EBADF)
         self.spawn_server(sock=server_sock)
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
-        fd.flush()
-        result = fd.read(1024)
-        fd.close()
+        sock = eventlet.connect(server_sock.getsockname())
+        sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+        result = sock.recv(1024)
         assert result.startswith(b'HTTP'), result
         assert result.endswith(b'hello world'), result
 
         assert result.startswith(b'HTTP'), result
         assert result.endswith(b'hello world'), result
 
@@ -718,14 +686,12 @@ class TestHttpd(_TestBase):
             start_response('200 OK', [('Content-type', 'text/plain')])
             return []
         self.site.application = clobberin_time
             start_response('200 OK', [('Content-type', 'text/plain')])
             return []
         self.site.application = clobberin_time
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('rwb')
-        fd.write('GET / HTTP/1.1\r\n'
-                 'Host: localhost\r\n'
-                 'Connection: close\r\n'
-                 '\r\n\r\n'.encode())
-        fd.flush()
-        assert b'200 OK' in fd.read()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET / HTTP/1.1\r\n'
+                     b'Host: localhost\r\n'
+                     b'Connection: close\r\n'
+                     b'\r\n\r\n')
+        assert b'200 OK' in recvall(sock)
 
     def test_022_custom_pool(self):
         # just test that it accepts the parameter for now
 
     def test_022_custom_pool(self):
         # just test that it accepts the parameter for now
@@ -735,24 +701,16 @@ class TestHttpd(_TestBase):
         self.spawn_server(custom_pool=p)
 
         # this stuff is copied from test_001_server, could be better factored
         self.spawn_server(custom_pool=p)
 
         # this stuff is copied from test_001_server, could be better factored
-        sock = eventlet.connect(
-            ('localhost', self.port))
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
-        fd.flush()
-        result = fd.read()
-        fd.close()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
+        result = recvall(sock)
         assert result.startswith(b'HTTP'), result
         assert result.endswith(b'hello world'), result
 
     def test_023_bad_content_length(self):
         assert result.startswith(b'HTTP'), result
         assert result.endswith(b'hello world'), result
 
     def test_023_bad_content_length(self):
-        sock = eventlet.connect(
-            ('localhost', self.port))
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n')
-        fd.flush()
-        result = fd.read()
-        fd.close()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nContent-length: argh\r\n\r\n')
+        result = recvall(sock)
         assert result.startswith(b'HTTP'), result
         assert b'400 Bad Request' in result, result
         assert b'500' not in result, result
         assert result.startswith(b'HTTP'), result
         assert b'400 Bad Request' in result, result
         assert b'500' not in result, result
@@ -767,7 +725,7 @@ class TestHttpd(_TestBase):
                 start_response('200 OK', [('Content-Length', str(len(text)))])
                 return [text]
         self.site.application = wsgi_app
                 start_response('200 OK', [('Content-Length', str(len(text)))])
                 return [text]
         self.site.application = wsgi_app
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         fd = sock.makefile('rwb')
         fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n'
                  b'Expect: 100-continue\r\n\r\n')
         fd = sock.makefile('rwb')
         fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n'
                  b'Expect: 100-continue\r\n\r\n')
@@ -813,7 +771,7 @@ class TestHttpd(_TestBase):
                 start_response('200 OK', [('Content-Length', str(len(text)))])
                 return [text]
         self.site.application = wsgi_app
                 start_response('200 OK', [('Content-Length', str(len(text)))])
                 return [text]
         self.site.application = wsgi_app
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         fd = sock.makefile('rwb')
         fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n'
                  b'Expect: 100-continue\r\n\r\n')
         fd = sock.makefile('rwb')
         fd.write(b'PUT / HTTP/1.1\r\nHost: localhost\r\nContent-length: 1025\r\n'
                  b'Expect: 100-continue\r\n\r\n')
@@ -868,7 +826,7 @@ class TestHttpd(_TestBase):
             start_response('200 OK', [('Content-Length', str(len(text)))])
             return [text]
         self.site.application = wsgi_app
             start_response('200 OK', [('Content-Length', str(len(text)))])
             return [text]
         self.site.application = wsgi_app
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         fd = sock.makefile('rwb')
         fd.write(b'PUT /a HTTP/1.1\r\n'
                  b'Host: localhost\r\nConnection: close\r\n'
         fd = sock.makefile('rwb')
         fd.write(b'PUT /a HTTP/1.1\r\n'
                  b'Host: localhost\r\nConnection: close\r\n'
@@ -946,7 +904,7 @@ class TestHttpd(_TestBase):
             return [text]
 
         self.site.application = wsgi_app
             return [text]
 
         self.site.application = wsgi_app
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         fd = sock.makefile('rwb')
         fd.write(b'PUT /a HTTP/1.1\r\n'
                  b'Host: localhost\r\nConnection: close\r\n'
         fd = sock.makefile('rwb')
         fd.write(b'PUT /a HTTP/1.1\r\n'
                  b'Host: localhost\r\nConnection: close\r\n'
@@ -1015,7 +973,7 @@ class TestHttpd(_TestBase):
             self.spawn_server(sock=listener)
             eventlet.sleep(0)  # need to enter server loop
             try:
             self.spawn_server(sock=listener)
             eventlet.sleep(0)  # need to enter server loop
             try:
-                eventlet.connect(('localhost', self.port))
+                eventlet.connect(self.server_addr)
                 self.fail("Didn't expect to connect")
             except socket.error as exc:
                 self.assertEqual(support.get_errno(exc), errno.ECONNREFUSED)
                 self.fail("Didn't expect to connect")
             except socket.error as exc:
                 self.assertEqual(support.get_errno(exc), errno.ECONNREFUSED)
@@ -1026,7 +984,7 @@ class TestHttpd(_TestBase):
 
     def test_026_log_format(self):
         self.spawn_server(log_format="HI %(request_line)s HI")
 
     def test_026_log_format(self):
         self.spawn_server(log_format="HI %(request_line)s HI")
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         sock.sendall(b'GET /yo! HTTP/1.1\r\nHost: localhost\r\n\r\n')
         sock.recv(1024)
         sock.close()
         sock.sendall(b'GET /yo! HTTP/1.1\r\nHost: localhost\r\n\r\n')
         sock.recv(1024)
         sock.close()
@@ -1037,7 +995,7 @@ class TestHttpd(_TestBase):
         # and we're not speaking with a 1.1 client, that we
         # close the connection
         self.site.application = chunked_app
         # and we're not speaking with a 1.1 client, that we
         # close the connection
         self.site.application = chunked_app
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
         sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
 
 
         sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
 
@@ -1046,11 +1004,26 @@ class TestHttpd(_TestBase):
         self.assertNotEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
         self.assertEqual(result.body, b"thisischunked")
 
         self.assertNotEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
         self.assertEqual(result.body, b"thisischunked")
 
+    def test_chunked_response_when_app_yields_empty_string(self):
+        def empty_string_chunked_app(env, start_response):
+            env['eventlet.minimum_write_chunk_size'] = 0  # no buffering
+            start_response('200 OK', [('Content-type', 'text/plain')])
+            return iter([b"stuff", b"", b"more stuff"])
+
+        self.site.application = empty_string_chunked_app
+        sock = eventlet.connect(self.server_addr)
+
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+
+        result = read_http(sock)
+        self.assertEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
+        self.assertEqual(result.body, b"5\r\nstuff\r\na\r\nmore stuff\r\n0\r\n\r\n")
+
     def test_minimum_chunk_size_parameter_leaves_httpprotocol_class_member_intact(self):
         start_size = wsgi.HttpProtocol.minimum_chunk_size
 
         self.spawn_server(minimum_chunk_size=start_size * 2)
     def test_minimum_chunk_size_parameter_leaves_httpprotocol_class_member_intact(self):
         start_size = wsgi.HttpProtocol.minimum_chunk_size
 
         self.spawn_server(minimum_chunk_size=start_size * 2)
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         read_http(sock)
 
         sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         read_http(sock)
 
@@ -1062,7 +1035,7 @@ class TestHttpd(_TestBase):
         self.spawn_server(minimum_chunk_size=1)
 
         self.site.application = chunked_fail_app
         self.spawn_server(minimum_chunk_size=1)
 
         self.site.application = chunked_fail_app
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
         sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
 
 
         sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
 
@@ -1081,8 +1054,7 @@ class TestHttpd(_TestBase):
         # verify that if an http/1.0 client sends connection: keep-alive
         # and the server doesn't accept keep-alives, we close the connection
         self.spawn_server(keepalive=False)
         # verify that if an http/1.0 client sends connection: keep-alive
         # and the server doesn't accept keep-alives, we close the connection
         self.spawn_server(keepalive=False)
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
         sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
         result = read_http(sock)
 
         sock.sendall(b'GET / HTTP/1.0\r\nHost: localhost\r\nConnection: keep-alive\r\n\r\n')
         result = read_http(sock)
@@ -1090,22 +1062,17 @@ class TestHttpd(_TestBase):
 
     def test_027_keepalive_chunked(self):
         self.site.application = chunked_post
 
     def test_027_keepalive_chunked(self):
         self.site.application = chunked_post
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('wb')
+        sock = eventlet.connect(self.server_addr)
         common_suffix = (
             b'Host: localhost\r\nTransfer-Encoding: chunked\r\n\r\n' +
             b'10\r\n0123456789abcdef\r\n0\r\n\r\n')
         common_suffix = (
             b'Host: localhost\r\nTransfer-Encoding: chunked\r\n\r\n' +
             b'10\r\n0123456789abcdef\r\n0\r\n\r\n')
-        fd.write(b'PUT /a HTTP/1.1\r\n' + common_suffix)
-        fd.flush()
+        sock.sendall(b'PUT /a HTTP/1.1\r\n' + common_suffix)
         read_http(sock)
         read_http(sock)
-        fd.write(b'PUT /b HTTP/1.1\r\n' + common_suffix)
-        fd.flush()
+        sock.sendall(b'PUT /b HTTP/1.1\r\n' + common_suffix)
         read_http(sock)
         read_http(sock)
-        fd.write(b'PUT /c HTTP/1.1\r\n' + common_suffix)
-        fd.flush()
+        sock.sendall(b'PUT /c HTTP/1.1\r\n' + common_suffix)
         read_http(sock)
         read_http(sock)
-        fd.write(b'PUT /a HTTP/1.1\r\n' + common_suffix)
-        fd.flush()
+        sock.sendall(b'PUT /a HTTP/1.1\r\n' + common_suffix)
         read_http(sock)
         sock.close()
 
         read_http(sock)
         sock.close()
 
@@ -1127,9 +1094,9 @@ class TestHttpd(_TestBase):
                 eventlet.listen(('localhost', 0)),
                 certfile=certificate_file, keyfile=private_key_file,
                 server_side=True)
                 eventlet.listen(('localhost', 0)),
                 certfile=certificate_file, keyfile=private_key_file,
                 server_side=True)
-            port = srv_sock.getsockname()[1]
+            addr = srv_sock.getsockname()
             g = eventlet.spawn_n(server, srv_sock)
             g = eventlet.spawn_n(server, srv_sock)
-            client = eventlet.connect(('localhost', port))
+            client = eventlet.connect(addr)
             if data:  # send non-ssl request
                 client.sendall(data.encode())
             else:  # close sock prematurely
             if data:  # send non-ssl request
                 client.sendall(data.encode())
             else:  # close sock prematurely
@@ -1138,7 +1105,7 @@ class TestHttpd(_TestBase):
             assert not errored[0], errored[0]
             # make another request to ensure the server's still alive
             try:
             assert not errored[0], errored[0]
             # make another request to ensure the server's still alive
             try:
-                client = ssl.wrap_socket(eventlet.connect(('localhost', port)))
+                client = ssl.wrap_socket(eventlet.connect(addr))
                 client.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
                 result = recvall(client)
                 assert result.startswith(b'HTTP'), result
                 client.write(b'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n')
                 result = recvall(client)
                 assert result.startswith(b'HTTP'), result
@@ -1170,7 +1137,7 @@ class TestHttpd(_TestBase):
                 start_response('200 OK', [('Content-Type', 'text/plain')])
             yield b''
         self.site.application = one_posthook_app
                 start_response('200 OK', [('Content-Type', 'text/plain')])
             yield b''
         self.site.application = one_posthook_app
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         fp = sock.makefile('rwb')
         fp.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         fp.flush()
         fp = sock.makefile('rwb')
         fp.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         fp.flush()
@@ -1193,7 +1160,7 @@ class TestHttpd(_TestBase):
                 start_response('200 OK', [('Content-Type', 'text/plain')])
             yield b''
         self.site.application = two_posthook_app
                 start_response('200 OK', [('Content-Type', 'text/plain')])
             yield b''
         self.site.application = two_posthook_app
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         fp = sock.makefile('rwb')
         fp.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         fp.flush()
         fp = sock.makefile('rwb')
         fp.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         fp.flush()
@@ -1204,7 +1171,7 @@ class TestHttpd(_TestBase):
         self.assertEqual(posthook2_count[0], 25)
 
     def test_030_reject_long_header_lines(self):
         self.assertEqual(posthook2_count[0], 25)
 
     def test_030_reject_long_header_lines(self):
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         request = 'GET / HTTP/1.0\r\nHost: localhost\r\nLong: %s\r\n\r\n' % \
             ('a' * 10000)
         send_expect_close(sock, request.encode())
         request = 'GET / HTTP/1.0\r\nHost: localhost\r\nLong: %s\r\n\r\n' % \
             ('a' * 10000)
         send_expect_close(sock, request.encode())
@@ -1212,7 +1179,7 @@ class TestHttpd(_TestBase):
         self.assertEqual(result.status, 'HTTP/1.0 400 Header Line Too Long')
 
     def test_031_reject_large_headers(self):
         self.assertEqual(result.status, 'HTTP/1.0 400 Header Line Too Long')
 
     def test_031_reject_large_headers(self):
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         headers = ('Name: %s\r\n' % ('a' * 7000,)) * 20
         request = 'GET / HTTP/1.0\r\nHost: localhost\r\n%s\r\n\r\n' % headers
         send_expect_close(sock, request.encode())
         headers = ('Name: %s\r\n' % ('a' * 7000,)) * 20
         request = 'GET / HTTP/1.0\r\nHost: localhost\r\n%s\r\n\r\n' % headers
         send_expect_close(sock, request.encode())
@@ -1238,13 +1205,10 @@ class TestHttpd(_TestBase):
             'Host: localhost\r\n'
             'Content-Length: %i\r\n\r\n%s'
         ) % (len(upload_data), bytes_to_str(upload_data))
             'Host: localhost\r\n'
             'Content-Length: %i\r\n\r\n%s'
         ) % (len(upload_data), bytes_to_str(upload_data))
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('rwb')
-        fd.write(request.encode())
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(request.encode())
         result = read_http(sock)
         self.assertEqual(result.body, upload_data)
         result = read_http(sock)
         self.assertEqual(result.body, upload_data)
-        fd.close()
         self.assertEqual(g[0], 1)
 
     def test_zero_length_chunked_response(self):
         self.assertEqual(g[0], 1)
 
     def test_zero_length_chunked_response(self):
@@ -1253,13 +1217,10 @@ class TestHttpd(_TestBase):
             yield b""
 
         self.site.application = zero_chunked_app
             yield b""
 
         self.site.application = zero_chunked_app
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
 
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
-        fd.flush()
-        response = fd.read().split(b'\r\n')
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
+        response = recvall(sock).split(b'\r\n')
         headers = []
         while True:
             h = response.pop(0)
         headers = []
         while True:
             h = response.pop(0)
@@ -1273,8 +1234,7 @@ class TestHttpd(_TestBase):
 
     def test_configurable_url_length_limit(self):
         self.spawn_server(url_length_limit=20000)
 
     def test_configurable_url_length_limit(self):
         self.spawn_server(url_length_limit=20000)
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         path = 'x' * 15000
         request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path
         fd = sock.makefile('rwb')
         path = 'x' * 15000
         request = 'GET /%s HTTP/1.0\r\nHost: localhost\r\n\r\n' % path
         fd = sock.makefile('rwb')
@@ -1301,6 +1261,7 @@ class TestHttpd(_TestBase):
             read_content.send(content)
             start_response('200 OK', [('Content-Type', 'text/plain')])
             return [content]
             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',
         self.site.application = chunk_reader
         expected_body = 'a bunch of stuff'
         data = "\r\n".join(['PUT /somefile HTTP/1.0',
@@ -1309,7 +1270,71 @@ class TestHttpd(_TestBase):
                             'def',
                             expected_body])
         # start PUT-ing some chunked data but close prematurely
                             'def',
                             expected_body])
         # start PUT-ing some chunked data but close prematurely
-        sock = eventlet.connect(('127.0.0.1', self.port))
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(data.encode())
+        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(), b'ok')
+        assert blew_up[0]
+
+    def test_aborted_chunked_post_between_chunks(self):
+        read_content = event.Event()
+        blew_up = [False]
+
+        def chunk_reader(env, start_response):
+            try:
+                content = env['wsgi.input'].read(1024)
+            except wsgi.ChunkReadError:
+                blew_up[0] = True
+                content = b'ok'
+            except Exception as err:
+                blew_up[0] = True
+                content = b'wrong exception: ' + str(err).encode()
+            read_content.send(content)
+            start_response('200 OK', [('Content-Type', 'text/plain')])
+            return [content]
+        self.site.application = chunk_reader
+        expected_body = 'A' * 0xdb
+        data = "\r\n".join(['PUT /somefile HTTP/1.0',
+                            'Transfer-Encoding: chunked',
+                            '',
+                            'db',
+                            expected_body])
+        # start PUT-ing some chunked data but close prematurely
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(data.encode())
+        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(), b'ok')
+        assert blew_up[0]
+
+    def test_aborted_chunked_post_bad_chunks(self):
+        read_content = event.Event()
+        blew_up = [False]
+
+        def chunk_reader(env, start_response):
+            try:
+                content = env['wsgi.input'].read(1024)
+            except wsgi.ChunkReadError:
+                blew_up[0] = True
+                content = b'ok'
+            except Exception as err:
+                blew_up[0] = True
+                content = b'wrong exception: ' + str(err).encode()
+            read_content.send(content)
+            start_response('200 OK', [('Content-Type', 'text/plain')])
+            return [content]
+        self.site.application = chunk_reader
+        expected_body = 'look here is some data for you'
+        data = "\r\n".join(['PUT /somefile HTTP/1.0',
+                            'Transfer-Encoding: chunked',
+                            '',
+                            'cats',
+                            expected_body])
+        # start PUT-ing some garbage
+        sock = eventlet.connect(self.server_addr)
         sock.sendall(data.encode())
         sock.close()
         # the test passes if we successfully get here, and read all the data
         sock.sendall(data.encode())
         sock.close()
         # the test passes if we successfully get here, and read all the data
@@ -1321,10 +1346,8 @@ class TestHttpd(_TestBase):
         def wsgi_app(environ, start_response):
             raise RuntimeError("intentional error")
         self.site.application = wsgi_app
         def wsgi_app(environ, start_response):
             raise RuntimeError("intentional error")
         self.site.application = wsgi_app
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         result = read_http(sock)
         self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error')
         self.assertEqual(result.headers_lower['connection'], 'close')
         result = read_http(sock)
         self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error')
         self.assertEqual(result.headers_lower['connection'], 'close')
@@ -1336,10 +1359,8 @@ class TestHttpd(_TestBase):
             yield b"oh hai, "
             yield u"xxx"
         self.site.application = wsgi_app
             yield b"oh hai, "
             yield u"xxx"
         self.site.application = wsgi_app
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
         result = read_http(sock)
         assert b'xxx' in result.body
 
         result = read_http(sock)
         assert b'xxx' in result.body
 
@@ -1349,10 +1370,8 @@ class TestHttpd(_TestBase):
             yield b"oh hai, "
             yield u"xxx \u0230"
         self.site.application = wsgi_app
             yield b"oh hai, "
             yield u"xxx \u0230"
         self.site.application = wsgi_app
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
         result = read_http(sock)
         self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error')
         self.assertEqual(result.headers_lower['connection'], 'close')
         result = read_http(sock)
         self.assertEqual(result.status, 'HTTP/1.1 500 Internal Server Error')
         self.assertEqual(result.headers_lower['connection'], 'close')
@@ -1363,10 +1382,8 @@ class TestHttpd(_TestBase):
             yield six.b("decoded: %s" % environ['PATH_INFO'])
             yield six.b("raw: %s" % environ['RAW_PATH_INFO'])
         self.site.application = wsgi_app
             yield six.b("decoded: %s" % environ['PATH_INFO'])
             yield six.b("raw: %s" % environ['RAW_PATH_INFO'])
         self.site.application = wsgi_app
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('rwb')
-        fd.write(b'GET /a*b@%40%233 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET /a*b@%40%233 HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
         result = read_http(sock)
         self.assertEqual(result.status, 'HTTP/1.1 200 OK')
         assert b'decoded: /a*b@@#3' in result.body
         result = read_http(sock)
         self.assertEqual(result.status, 'HTTP/1.1 200 OK')
         assert b'decoded: /a*b@@#3' in result.body
@@ -1402,10 +1419,8 @@ class TestHttpd(_TestBase):
             raise RuntimeError("intentional crash")
         self.site.application = crasher
 
             raise RuntimeError("intentional crash")
         self.site.application = crasher
 
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('wb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         result1 = read_http(sock)
         self.assertEqual(result1.status, 'HTTP/1.1 500 Internal Server Error')
         self.assertEqual(result1.body, b'')
         result1 = read_http(sock)
         self.assertEqual(result1.status, 'HTTP/1.1 500 Internal Server Error')
         self.assertEqual(result1.body, b'')
@@ -1415,10 +1430,8 @@ class TestHttpd(_TestBase):
         # verify traceback when debugging enabled
         self.spawn_server(debug=True)
         self.site.application = crasher
         # verify traceback when debugging enabled
         self.spawn_server(debug=True)
         self.site.application = crasher
-        sock = eventlet.connect(('localhost', self.port))
-        fd = sock.makefile('wb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-        fd.flush()
+        sock = eventlet.connect(self.server_addr)
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         result2 = read_http(sock)
         self.assertEqual(result2.status, 'HTTP/1.1 500 Internal Server Error')
         assert b'intentional crash' in result2.body, result2.body
         result2 = read_http(sock)
         self.assertEqual(result2.status, 'HTTP/1.1 500 Internal Server Error')
         assert b'intentional crash' in result2.body, result2.body
@@ -1435,7 +1448,7 @@ class TestHttpd(_TestBase):
             yield b'a' * 9876
 
         server_sock = eventlet.listen(('localhost', 0))
             yield b'a' * 9876
 
         server_sock = eventlet.listen(('localhost', 0))
-        self.port = server_sock.getsockname()[1]
+        self.server_addr = server_sock.getsockname()
         server = wsgi.Server(server_sock, server_sock.getsockname(), long_response,
                              log=self.logfile)
 
         server = wsgi.Server(server_sock, server_sock.getsockname(), long_response,
                              log=self.logfile)
 
@@ -1459,7 +1472,7 @@ class TestHttpd(_TestBase):
 
     def test_server_socket_timeout(self):
         self.spawn_server(socket_timeout=0.1)
 
     def test_server_socket_timeout(self):
         self.spawn_server(socket_timeout=0.1)
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         sock.send(b'GET / HTTP/1.1\r\n')
         eventlet.sleep(0.1)
         try:
         sock.send(b'GET / HTTP/1.1\r\n')
         eventlet.sleep(0.1)
         try:
@@ -1480,7 +1493,7 @@ class TestHttpd(_TestBase):
 
         self.spawn_server(site=wsgi_app, capitalize_response_headers=False)
 
 
         self.spawn_server(site=wsgi_app, capitalize_response_headers=False)
 
-        sock = eventlet.connect(('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
         sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         result = read_http(sock)
         sock.close()
         sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         result = read_http(sock)
         sock.close()
@@ -1488,6 +1501,20 @@ class TestHttpd(_TestBase):
         self.assertEqual(result.headers_lower[random_case_header[0].lower()], random_case_header[1])
         self.assertEqual(result.headers_original[random_case_header[0]], random_case_header[1])
 
         self.assertEqual(result.headers_lower[random_case_header[0].lower()], random_case_header[1])
         self.assertEqual(result.headers_original[random_case_header[0]], random_case_header[1])
 
+    def test_log_unix_address(self):
+        tempdir = tempfile.mkdtemp('eventlet_test_log_unix_address')
+        path = ''
+        try:
+            sock = eventlet.listen(tempdir + '/socket', socket.AF_UNIX)
+            path = sock.getsockname()
+
+            log = six.StringIO()
+            self.spawn_server(sock=sock, log=log)
+            eventlet.sleep(0)  # need to enter server loop
+            assert 'http:' + path in log.getvalue()
+        finally:
+            shutil.rmtree(tempdir)
+
 
 def read_headers(sock):
     fd = sock.makefile('rb')
 
 def read_headers(sock):
     fd = sock.makefile('rb')
@@ -1527,18 +1554,14 @@ class IterableAlreadyHandledTest(_TestBase):
 
     def test_iterable_app_keeps_socket_open_unless_connection_close_sent(self):
         self.site.application = self.get_app()
 
     def test_iterable_app_keeps_socket_open_unless_connection_close_sent(self):
         self.site.application = self.get_app()
-        sock = eventlet.connect(
-            ('localhost', self.port))
+        sock = eventlet.connect(self.server_addr)
 
 
-        fd = sock.makefile('rwb')
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
-
-        fd.flush()
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n')
         response_line, headers = read_headers(sock)
         self.assertEqual(response_line, 'HTTP/1.1 200 OK\r\n')
         assert 'connection' not in headers
         response_line, headers = read_headers(sock)
         self.assertEqual(response_line, 'HTTP/1.1 200 OK\r\n')
         assert 'connection' not in headers
-        fd.write(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
-        fd.flush()
+
+        sock.sendall(b'GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n')
         result = read_http(sock)
         self.assertEqual(result.status, 'HTTP/1.1 200 OK')
         self.assertEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
         result = read_http(sock)
         self.assertEqual(result.status, 'HTTP/1.1 200 OK')
         self.assertEqual(result.headers_lower.get('transfer-encoding'), 'chunked')
@@ -1558,7 +1581,6 @@ class ProxiedIterableAlreadyHandledTest(IterableAlreadyHandledTest):
 
 
 class TestChunkedInput(_TestBase):
 
 
 class TestChunkedInput(_TestBase):
-    dirt = ""
     validator = None
 
     def application(self, env, start_response):
     validator = None
 
     def application(self, env, start_response):
@@ -1601,22 +1623,19 @@ class TestChunkedInput(_TestBase):
         return response
 
     def connect(self):
         return response
 
     def connect(self):
-        return eventlet.connect(('localhost', self.port))
+        return eventlet.connect(self.server_addr)
 
     def set_site(self):
         self.site = Site()
         self.site.application = self.application
 
 
     def set_site(self):
         self.site = Site()
         self.site.application = self.application
 
-    def chunk_encode(self, chunks, dirt=None):
-        if dirt is None:
-            dirt = self.dirt
-
+    def chunk_encode(self, chunks, dirt=""):
         b = ""
         for c in chunks:
             b += "%x%s\r\n%s\r\n" % (len(c), dirt, c)
         return b
 
         b = ""
         for c in chunks:
             b += "%x%s\r\n%s\r\n" % (len(c), dirt, c)
         return b
 
-    def body(self, dirt=None):
+    def body(self, dirt=""):
         return self.chunk_encode(["this", " is ", "chunked", "\nline",
                                   " 2", "\n", "line3", ""], dirt=dirt)
 
         return self.chunk_encode(["this", " is ", "chunked", "\nline",
                                   " 2", "\n", "line3", ""], dirt=dirt)