[Python-checkins] bpo-39259: smtp.SMTP/SMTP_SSL now reject timeout = 0 (GH-17958)

Victor Stinner webhook-mailer at python.org
Tue Jan 14 02:50:06 EST 2020


https://github.com/python/cpython/commit/62e3973395fb9fab2eb8f651bcd0fea4e695e1cf
commit: 62e3973395fb9fab2eb8f651bcd0fea4e695e1cf
branch: master
author: Dong-hee Na <donghee.na92 at gmail.com>
committer: Victor Stinner <vstinner at python.org>
date: 2020-01-14T08:49:59+01:00
summary:

bpo-39259: smtp.SMTP/SMTP_SSL now reject timeout = 0 (GH-17958)

files:
A Misc/NEWS.d/next/Library/2020-01-12-16-34-28.bpo-39259.J_yBVq.rst
M Doc/library/smtplib.rst
M Doc/whatsnew/3.9.rst
M Lib/smtplib.py
M Lib/test/test_smtplib.py

diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst
index 6176c35a0e4a5..f6ac123823b69 100644
--- a/Doc/library/smtplib.rst
+++ b/Doc/library/smtplib.rst
@@ -70,6 +70,9 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions).
    .. versionadded:: 3.5
       The SMTPUTF8 extension (:rfc:`6531`) is now supported.
 
+   .. versionchanged:: 3.9
+      If the *timeout* parameter is set to be zero, it will raise a
+      :class:`ValueError` to prevent the creation of a non-blocking socket
 
 .. class:: SMTP_SSL(host='', port=0, local_hostname=None, keyfile=None, \
                     certfile=None [, timeout], context=None, \
@@ -108,6 +111,9 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions).
        :func:`ssl.create_default_context` select the system's trusted CA
        certificates for you.
 
+   .. versionchanged:: 3.9
+      If the *timeout* parameter is set to be zero, it will raise a
+      :class:`ValueError` to prevent the creation of a non-blocking socket
 
 .. class:: LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None)
 
diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst
index 859bf440f89af..00409af4387d8 100644
--- a/Doc/whatsnew/3.9.rst
+++ b/Doc/whatsnew/3.9.rst
@@ -259,6 +259,13 @@ now raises :exc:`ImportError` instead of :exc:`ValueError` for invalid relative
 import attempts.
 (Contributed by Ngalim Siregar in :issue:`37444`.)
 
+smtplib
+-------
+
+:class:`~smtplib.SMTP` and :class:`~smtplib.SMTP_SSL` now raise a :class:`ValueError`
+if the given timeout for their constructor is zero to prevent the creation of
+a non-blocking socket. (Contributed by Dong-hee Na in :issue:`39259`.)
+
 signal
 ------
 
diff --git a/Lib/smtplib.py b/Lib/smtplib.py
index 6513842eb6c61..4d5cdb5ac0ad9 100755
--- a/Lib/smtplib.py
+++ b/Lib/smtplib.py
@@ -303,6 +303,8 @@ def _print_debug(self, *args):
     def _get_socket(self, host, port, timeout):
         # This makes it simpler for SMTP_SSL to use the SMTP connect code
         # and just alter the socket connection bit.
+        if timeout is not None and not timeout:
+            raise ValueError('Non-blocking socket (timeout=0) is not supported')
         if self.debuglevel > 0:
             self._print_debug('connect: to', (host, port), self.source_address)
         return socket.create_connection((host, port), timeout,
@@ -1030,13 +1032,12 @@ def __init__(self, host='', port=0, local_hostname=None,
                                                      keyfile=keyfile)
             self.context = context
             SMTP.__init__(self, host, port, local_hostname, timeout,
-                    source_address)
+                          source_address)
 
         def _get_socket(self, host, port, timeout):
             if self.debuglevel > 0:
                 self._print_debug('connect:', (host, port))
-            new_socket = socket.create_connection((host, port), timeout,
-                    self.source_address)
+            new_socket = super()._get_socket(host, port, timeout)
             new_socket = self.context.wrap_socket(new_socket,
                                                   server_hostname=self._host)
             return new_socket
@@ -1065,15 +1066,15 @@ class LMTP(SMTP):
     ehlo_msg = "lhlo"
 
     def __init__(self, host='', port=LMTP_PORT, local_hostname=None,
-            source_address=None):
+                 source_address=None):
         """Initialize a new instance."""
-        SMTP.__init__(self, host, port, local_hostname=local_hostname,
-                      source_address=source_address)
+        super().__init__(host, port, local_hostname=local_hostname,
+                         source_address=source_address)
 
     def connect(self, host='localhost', port=0, source_address=None):
         """Connect to the LMTP daemon, on either a Unix or a TCP socket."""
         if host[0] != '/':
-            return SMTP.connect(self, host, port, source_address=source_address)
+            return super().connect(host, port, source_address=source_address)
 
         # Handle Unix-domain sockets.
         try:
diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py
index faf013ac9a66e..cc5c4b1346488 100644
--- a/Lib/test/test_smtplib.py
+++ b/Lib/test/test_smtplib.py
@@ -122,6 +122,11 @@ def testTimeoutNone(self):
         self.assertIsNone(smtp.sock.gettimeout())
         smtp.close()
 
+    def testTimeoutZero(self):
+        mock_socket.reply_with(b"220 Hola mundo")
+        with self.assertRaises(ValueError):
+            smtplib.SMTP(HOST, self.port, timeout=0)
+
     def testTimeoutValue(self):
         mock_socket.reply_with(b"220 Hola mundo")
         smtp = smtplib.SMTP(HOST, self.port, timeout=30)
diff --git a/Misc/NEWS.d/next/Library/2020-01-12-16-34-28.bpo-39259.J_yBVq.rst b/Misc/NEWS.d/next/Library/2020-01-12-16-34-28.bpo-39259.J_yBVq.rst
new file mode 100644
index 0000000000000..6cc490eb35e6e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-01-12-16-34-28.bpo-39259.J_yBVq.rst
@@ -0,0 +1,3 @@
+:class:`~smtplib.SMTP` and :class:`~smtplib.SMTP_SSL` now raise a
+:class:`ValueError` if the given timeout for their constructor is zero to
+prevent the creation of a non-blocking socket. Patch by Dong-hee Na.



More information about the Python-checkins mailing list