]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Count SSL_ERROR_EOF as a kind of connection reset.
authorBen Darnell <ben@bendarnell.com>
Thu, 5 Mar 2015 04:25:59 +0000 (23:25 -0500)
committerBen Darnell <ben@bendarnell.com>
Thu, 5 Mar 2015 04:25:59 +0000 (23:25 -0500)
This reduces log spam and lets us remove an old (and timing-sensitive)
test workaround.

Closes #1362.

tornado/iostream.py
tornado/test/simple_httpclient_test.py

index 8c7675c0dd5b38bb12019ade691e578f7d010122..089d413b76776062bdbd1fed1dcf6b67f338a7da 100644 (file)
@@ -438,8 +438,7 @@ class BaseIOStream(object):
                 futures.append(self._connect_future)
                 self._connect_future = None
             for future in futures:
-                if (isinstance(self.error, (socket.error, IOError)) and
-                        errno_from_exception(self.error) in _ERRNO_CONNRESET):
+                if self._is_connreset(self.error):
                     # Treat connection resets as closed connections so
                     # clients only have to catch one kind of exception
                     # to avoid logging.
@@ -719,7 +718,7 @@ class BaseIOStream(object):
             chunk = self.read_from_fd()
         except (socket.error, IOError, OSError) as e:
             # ssl.SSLError is a subclass of socket.error
-            if e.args[0] in _ERRNO_CONNRESET:
+            if self._is_connreset(e):
                 # Treat ECONNRESET as a connection close rather than
                 # an error to minimize log spam  (the exception will
                 # be available on self.error for apps that care).
@@ -841,7 +840,7 @@ class BaseIOStream(object):
                     self._write_buffer_frozen = True
                     break
                 else:
-                    if e.args[0] not in _ERRNO_CONNRESET:
+                    if not self._is_connreset(e):
                         # Broken pipe errors are usually caused by connection
                         # reset, and its better to not log EPIPE errors to
                         # minimize log spam
@@ -919,6 +918,14 @@ class BaseIOStream(object):
             self._state = self._state | state
             self.io_loop.update_handler(self.fileno(), self._state)
 
+    def _is_connreset(self, exc):
+        """Return true if exc is ECONNRESET or equivalent.
+
+        May be overridden in subclasses.
+        """
+        return (isinstance(exc, (socket.error, IOError)) and
+                errno_from_exception(exc) in _ERRNO_CONNRESET)
+
 
 class IOStream(BaseIOStream):
     r"""Socket-based `IOStream` implementation.
@@ -1175,7 +1182,7 @@ class IOStream(BaseIOStream):
                 # Sometimes setsockopt will fail if the socket is closed
                 # at the wrong time.  This can happen with HTTPServer
                 # resetting the value to false between requests.
-                if e.errno not in (errno.EINVAL, errno.ECONNRESET):
+                if e.errno != errno.EINVAL and not self._is_connreset(e):
                     raise
 
 
@@ -1250,8 +1257,7 @@ class SSLIOStream(IOStream):
             # to cause do_handshake to raise EBADF, so make that error
             # quiet as well.
             # https://groups.google.com/forum/?fromgroups#!topic/python-tornado/ApucKJat1_0
-            if (err.args[0] in _ERRNO_CONNRESET or
-                    err.args[0] == errno.EBADF):
+            if self._is_connreset(err) or err.args[0] == errno.EBADF:
                 return self.close(exc_info=True)
             raise
         except AttributeError:
@@ -1385,6 +1391,11 @@ class SSLIOStream(IOStream):
             return None
         return chunk
 
+    def _is_connreset(self, e):
+        if isinstance(e, ssl.SSLError) and e.args[0] == ssl.SSL_ERROR_EOF:
+            return True
+        return super(SSLIOStream, self)._is_connreset(e)
+
 
 class PipeIOStream(BaseIOStream):
     """Pipe-based `IOStream` implementation.
index 2d72992e004a5c1263a135e9dffc09733f19d03a..088010586026bf8346147782a495c2ab3b52361c 100644 (file)
@@ -446,10 +446,6 @@ class SimpleHTTPSClientTestCase(SimpleHTTPClientTestMixin, AsyncHTTPSTestCase):
                        required=False):
             resp = self.fetch(
                 "/hello", ssl_options=dict(cert_reqs=ssl.CERT_REQUIRED))
-            # On python 2.6, the server logs an exception a little after
-            # the client finishes ("unexpected EOF")
-            self.io_loop.add_timeout(self.io_loop.time() + 0.01, self.stop)
-            self.wait()
         self.assertRaises(ssl.SSLError, resp.rethrow)
 
     @unittest.skipIf(not hasattr(ssl, 'SSLContext'),