Skip to content

Commit aee80cd

Browse files
[3.12] gh-126500: test_ssl: Don't stop ThreadedEchoServer on OSError in ConnectionHandler; rely on __exit__ (GH-126503) (GH-126572)
gh-126500: test_ssl: Don't stop ThreadedEchoServer on OSError in ConnectionHandler; rely on __exit__ (GH-126503) If `read()` in the ConnectionHandler thread raises `OSError` (except `ConnectionError`), the ConnectionHandler shuts down the entire ThreadedEchoServer, preventing further connections. It also does that for `EPROTOTYPE` in `wrap_conn`. As far as I can see, this is done to avoid the server thread getting stuck, forgotten, in its accept loop. However, since 2011 (5b95eb9) the server is used as a context manager, and its `__exit__` does `stop()` and `join()`. (I'm not sure if we *always* used `with` since that commit, but currently we do.) Make sure that the context manager *is* used, and remove the `server.stop()` calls from ConnectionHandler. (cherry picked from commit c9cda16) Co-authored-by: Petr Viktorin <[email protected]>
1 parent d62f100 commit aee80cd

File tree

1 file changed

+12
-5
lines changed

1 file changed

+12
-5
lines changed

Lib/test/test_ssl.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -2300,7 +2300,6 @@ def wrap_conn(self):
23002300
# See also http://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/
23012301
if e.errno != errno.EPROTOTYPE and sys.platform != "darwin":
23022302
self.running = False
2303-
self.server.stop()
23042303
self.close()
23052304
return False
23062305
else:
@@ -2435,10 +2434,6 @@ def run(self):
24352434
self.close()
24362435
self.running = False
24372436

2438-
# normally, we'd just stop here, but for the test
2439-
# harness, we want to stop the server
2440-
self.server.stop()
2441-
24422437
def __init__(self, certificate=None, ssl_version=None,
24432438
certreqs=None, cacerts=None,
24442439
chatty=True, connectionchatty=False, starttls_server=False,
@@ -2472,21 +2467,33 @@ def __init__(self, certificate=None, ssl_version=None,
24722467
self.conn_errors = []
24732468
threading.Thread.__init__(self)
24742469
self.daemon = True
2470+
self._in_context = False
24752471

24762472
def __enter__(self):
2473+
if self._in_context:
2474+
raise ValueError('Re-entering ThreadedEchoServer context')
2475+
self._in_context = True
24772476
self.start(threading.Event())
24782477
self.flag.wait()
24792478
return self
24802479

24812480
def __exit__(self, *args):
2481+
assert self._in_context
2482+
self._in_context = False
24822483
self.stop()
24832484
self.join()
24842485

24852486
def start(self, flag=None):
2487+
if not self._in_context:
2488+
raise ValueError(
2489+
'ThreadedEchoServer must be used as a context manager')
24862490
self.flag = flag
24872491
threading.Thread.start(self)
24882492

24892493
def run(self):
2494+
if not self._in_context:
2495+
raise ValueError(
2496+
'ThreadedEchoServer must be used as a context manager')
24902497
self.sock.settimeout(1.0)
24912498
self.sock.listen(5)
24922499
self.active = True

0 commit comments

Comments
 (0)