From b09e617464284de3603caedfc78d1c5aaea0a89a Mon Sep 17 00:00:00 2001 From: Ross Rhodes Date: Sun, 27 Dec 2020 21:08:56 +0000 Subject: [PATCH 1/4] LMTP Unix-domain socket assumes global default timeout when timeout not provided --- Lib/smtplib.py | 6 ++++-- Lib/test/mock_socket.py | 10 ++++++---- Lib/test/test_smtplib.py | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py index e2dbbbcf2e6d16..be87acb3c8a219 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -1070,7 +1070,7 @@ def __init__(self, host='', port=LMTP_PORT, local_hostname=None, """Initialize a new instance.""" super().__init__(host, port, local_hostname=local_hostname, source_address=source_address, timeout=timeout) - + 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] != '/': @@ -1082,7 +1082,9 @@ def connect(self, host='localhost', port=0, source_address=None): # Handle Unix-domain sockets. try: self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.sock.settimeout(self.timeout) + + if self.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: + self.sock.settimeout(self.timeout) self.file = None self.sock.connect(host) except OSError: diff --git a/Lib/test/mock_socket.py b/Lib/test/mock_socket.py index cda4db25cba594..ed4891c8c000a1 100644 --- a/Lib/test/mock_socket.py +++ b/Lib/test/mock_socket.py @@ -107,16 +107,16 @@ def getpeername(self): def close(self): pass + def connect(self, host): + pass + def socket(family=None, type=None, proto=None): return MockSocket(family) + def create_connection(address, timeout=socket_module._GLOBAL_DEFAULT_TIMEOUT, source_address=None): - try: - int_port = int(address[1]) - except ValueError: - raise error ms = MockSocket() if timeout is socket_module._GLOBAL_DEFAULT_TIMEOUT: timeout = getdefaulttimeout() @@ -152,8 +152,10 @@ def getaddrinfo(*args, **kw): # Constants +_GLOBAL_DEFAULT_TIMEOUT = socket_module._GLOBAL_DEFAULT_TIMEOUT AF_INET = socket_module.AF_INET AF_INET6 = socket_module.AF_INET6 +AF_UNIX = socket_module.AF_UNIX SOCK_STREAM = socket_module.SOCK_STREAM SOL_SOCKET = None SO_REUSEADDR = None diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 91985384ec7ff9..f3046e1b8a917a 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -165,12 +165,26 @@ class LMTPGeneralTests(GeneralTests, unittest.TestCase): client = smtplib.LMTP + def testTimeoutDefault(self): + super().testTimeoutDefault() + local_host = '/some/local/lmtp/delivery/program' + mock_socket.reply_with(b"220 Hello world") + + try: + client = self.client(local_host, self.port) + finally: + mock_socket.setdefaulttimeout(None) + + self.assertIsNone(client.sock.gettimeout()) + client.close() + def testTimeoutZero(self): super().testTimeoutZero() local_host = '/some/local/lmtp/delivery/program' with self.assertRaises(ValueError): self.client(local_host, timeout=0) + # Test server thread using the specified SMTP server class def debugging_server(serv, serv_evt, client_evt): serv_evt.set() From 5097ec0d700f321a6f1248c8622fea80c69959b9 Mon Sep 17 00:00:00 2001 From: Ross Rhodes Date: Sun, 27 Dec 2020 21:56:43 +0000 Subject: [PATCH 2/4] Rectify mock socket setup for Windows; add news entry --- Lib/smtplib.py | 2 +- Lib/test/mock_socket.py | 4 +++- Lib/test/test_smtplib.py | 6 ++++-- .../next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst | 2 ++ 4 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst diff --git a/Lib/smtplib.py b/Lib/smtplib.py index be87acb3c8a219..9bc2c6f5051a56 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -1070,7 +1070,7 @@ def __init__(self, host='', port=LMTP_PORT, local_hostname=None, """Initialize a new instance.""" super().__init__(host, port, local_hostname=local_hostname, source_address=source_address, timeout=timeout) - + 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] != '/': diff --git a/Lib/test/mock_socket.py b/Lib/test/mock_socket.py index ed4891c8c000a1..1daf8e1b73c49c 100644 --- a/Lib/test/mock_socket.py +++ b/Lib/test/mock_socket.py @@ -155,7 +155,9 @@ def getaddrinfo(*args, **kw): _GLOBAL_DEFAULT_TIMEOUT = socket_module._GLOBAL_DEFAULT_TIMEOUT AF_INET = socket_module.AF_INET AF_INET6 = socket_module.AF_INET6 -AF_UNIX = socket_module.AF_UNIX SOCK_STREAM = socket_module.SOCK_STREAM SOL_SOCKET = None SO_REUSEADDR = None + +if hasattr(socket_module, 'AF_UNIX'): + AF_UNIX = socket_module.AF_UNIX diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index f3046e1b8a917a..6d3368e9b61a82 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -165,8 +165,10 @@ class LMTPGeneralTests(GeneralTests, unittest.TestCase): client = smtplib.LMTP - def testTimeoutDefault(self): - super().testTimeoutDefault() + def testUnixDomainSocketTimeoutDefault(self): + if not hasattr(socket, "AF_UNIX"): + self.skipTest("requires Unix domain socket") + local_host = '/some/local/lmtp/delivery/program' mock_socket.reply_with(b"220 Hello world") diff --git a/Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst b/Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst new file mode 100644 index 00000000000000..93a0bb010df2bb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-27-21-22-01.bpo-42756.dHMPJ9.rst @@ -0,0 +1,2 @@ +Configure LMTP Unix-domain socket to use socket global default timeout when +a timeout is not explicitly provided. From 4960091003f18be599dd07e1b478bf76041ca0a8 Mon Sep 17 00:00:00 2001 From: Ross Rhodes Date: Fri, 1 Jan 2021 16:51:15 +0000 Subject: [PATCH 3/4] Apply skipUnless decorator and reduce whitespace --- Lib/smtplib.py | 1 - Lib/test/mock_socket.py | 5 ++++- Lib/test/test_smtplib.py | 7 +------ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 9bc2c6f5051a56..e81a9f05d60c4e 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -1082,7 +1082,6 @@ def connect(self, host='localhost', port=0, source_address=None): # Handle Unix-domain sockets. try: self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - if self.timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: self.sock.settimeout(self.timeout) self.file = None diff --git a/Lib/test/mock_socket.py b/Lib/test/mock_socket.py index 1daf8e1b73c49c..0cbe4745de7838 100644 --- a/Lib/test/mock_socket.py +++ b/Lib/test/mock_socket.py @@ -114,9 +114,12 @@ def connect(self, host): def socket(family=None, type=None, proto=None): return MockSocket(family) - def create_connection(address, timeout=socket_module._GLOBAL_DEFAULT_TIMEOUT, source_address=None): + try: + int_port = int(address[1]) + except ValueError: + raise ms = MockSocket() if timeout is socket_module._GLOBAL_DEFAULT_TIMEOUT: timeout = getdefaulttimeout() diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py index 6d3368e9b61a82..1ad45d8c780d17 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py @@ -165,18 +165,14 @@ class LMTPGeneralTests(GeneralTests, unittest.TestCase): client = smtplib.LMTP + @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), "test requires Unix domain socket") def testUnixDomainSocketTimeoutDefault(self): - if not hasattr(socket, "AF_UNIX"): - self.skipTest("requires Unix domain socket") - local_host = '/some/local/lmtp/delivery/program' mock_socket.reply_with(b"220 Hello world") - try: client = self.client(local_host, self.port) finally: mock_socket.setdefaulttimeout(None) - self.assertIsNone(client.sock.gettimeout()) client.close() @@ -186,7 +182,6 @@ def testTimeoutZero(self): with self.assertRaises(ValueError): self.client(local_host, timeout=0) - # Test server thread using the specified SMTP server class def debugging_server(serv, serv_evt, client_evt): serv_evt.set() From 4ba315fd77faff7d7142876e10752f703e65f6a8 Mon Sep 17 00:00:00 2001 From: Ross Rhodes Date: Fri, 1 Jan 2021 16:53:40 +0000 Subject: [PATCH 4/4] Raise value error if invalid connection port provided --- Lib/test/mock_socket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/mock_socket.py b/Lib/test/mock_socket.py index 0cbe4745de7838..c7abddcf5fafd3 100644 --- a/Lib/test/mock_socket.py +++ b/Lib/test/mock_socket.py @@ -119,7 +119,7 @@ def create_connection(address, timeout=socket_module._GLOBAL_DEFAULT_TIMEOUT, try: int_port = int(address[1]) except ValueError: - raise + raise error ms = MockSocket() if timeout is socket_module._GLOBAL_DEFAULT_TIMEOUT: timeout = getdefaulttimeout()