Improve connection error handling (especially for SelectIOLoop).
# an error state before the socket becomes writable, so
# in that case a connection failure would be handled by the
# error path in _handle_events instead of here.
- gen_log.warning("Connect error on fd %s: %s",
- self.socket.fileno(), errno.errorcode[err])
+ if self._connect_future is None:
+ gen_log.warning("Connect error on fd %s: %s",
+ self.socket.fileno(), errno.errorcode[err])
self.close()
return
if self._connect_callback is not None:
return super(SSLIOStream, self).connect(address, callback=None)
def _handle_connect(self):
+ # Call the superclass method to check for errors.
+ super(SSLIOStream, self)._handle_connect()
+ if self.closed():
+ return
# When the connection is complete, wrap the socket for SSL
# traffic. Note that we do this by overriding _handle_connect
# instead of by passing a callback to super().connect because
server_hostname=self._server_hostname,
do_handshake_on_connect=False)
self._add_io_state(old_state)
- super(SSLIOStream, self)._handle_connect()
def read_from_fd(self):
if self._ssl_accepting:
host = host[1:-1]
self.parsed_hostname = host # save final host for _on_connect
- if request.allow_ipv6:
- af = socket.AF_UNSPEC
- else:
- # We only try the first IP we get from getaddrinfo,
- # so restrict to ipv4 by default.
+ if request.allow_ipv6 is False:
af = socket.AF_INET
+ else:
+ af = socket.AF_UNSPEC
ssl_options = self._get_ssl_options(self.parsed.scheme)
raise
url = self.get_url("/hello").replace("localhost", "[::1]")
- # ipv6 is currently disabled by default and must be explicitly requested
- self.http_client.fetch(url, self.stop)
+ # ipv6 is currently enabled by default but can be disabled
+ self.http_client.fetch(url, self.stop, allow_ipv6=False)
response = self.wait()
self.assertEqual(response.code, 599)
- self.http_client.fetch(url, self.stop, allow_ipv6=True)
+ self.http_client.fetch(url, self.stop)
response = self.wait()
self.assertEqual(response.body, b"Hello world!")
import socket
from tornado.concurrent import Future
-from tornado.log import gen_log
from tornado.netutil import bind_sockets, Resolver
from tornado.tcpclient import TCPClient, _Connector
from tornado.tcpserver import TCPServer
-from tornado.testing import AsyncTestCase, bind_unused_port, gen_test, ExpectLog
+from tornado.testing import AsyncTestCase, bind_unused_port, gen_test
from tornado.test.util import skipIfNoIPv6, unittest
# Fake address families for testing. Used in place of AF_INET
self.do_test_connect(socket.AF_INET, '127.0.0.1')
def test_connect_ipv4_dual(self):
- with ExpectLog(gen_log, 'Connect error', required=False):
- self.do_test_connect(socket.AF_INET, 'localhost')
+ self.do_test_connect(socket.AF_INET, 'localhost')
@skipIfNoIPv6
def test_connect_ipv6_ipv6(self):
def test_connect_ipv6_dual(self):
if Resolver.configured_class().__name__.endswith('TwistedResolver'):
self.skipTest('TwistedResolver does not support multiple addresses')
- with ExpectLog(gen_log, 'Connect error', required=False):
- self.do_test_connect(socket.AF_INET6, 'localhost')
+ self.do_test_connect(socket.AF_INET6, 'localhost')
def test_connect_unspec_ipv4(self):
self.do_test_connect(socket.AF_UNSPEC, '127.0.0.1')
def test_refused_ipv4(self):
sock, port = bind_unused_port()
sock.close()
- with ExpectLog(gen_log, 'Connect error'):
- with self.assertRaises(IOError):
- yield self.client.connect('127.0.0.1', port)
+ with self.assertRaises(IOError):
+ yield self.client.connect('127.0.0.1', port)
class TestConnectorSplit(unittest.TestCase):