Fix TLS accept loop stalls

This commit is contained in:
Hermes Agent committed 2026-06-23 00:31:42 +02:00
1 parent 80d6514c9d
commit 8fdbb23bc9
2 files changed
+66 -2

No files matched your search

+32 -2
View File
@@ -8,6 +8,7 @@ import os
import re
import signal
import socket
import ssl
import sys
import threading
import time
@@ -157,6 +158,7 @@ class QuietHTTPServer(ThreadingHTTPServer):
server_address = args[0] if args else kwargs.get('server_address', None)
if server_address and ':' in server_address[0]:
self.address_family = socket.AF_INET6
self.ssl_context: object | None = None
super().__init__(*args, **kwargs)
self.accept_loop_requests_total = 0
self.accept_loop_last_request_at = 0.0
@@ -185,6 +187,31 @@ class QuietHTTPServer(ThreadingHTTPServer):
else:
super().server_bind()
def get_request(self):
"""Accept a connection without letting TLS handshakes block the loop.
``ssl.wrap_socket(listening_socket)`` performs the TLS handshake inside
``accept()``. A browser/network probe that opens TCP but never sends a
ClientHello can then freeze the one accept loop, leaving the process
alive but unable to serve any later clients. Accept the raw socket here
and wrap the accepted connection with ``do_handshake_on_connect=False``
so any slow/broken handshake times out in its own request thread.
"""
request, client_address = self.socket.accept()
ssl_context = getattr(self, "ssl_context", None)
if ssl_context is None:
return request, client_address
try:
tls_request = ssl_context.wrap_socket(
request,
server_side=True,
do_handshake_on_connect=False,
)
except Exception:
request.close()
raise
return tls_request, client_address
def _handle_request_noblock(self):
"""Record accept-loop progress before dispatching a request handler.
@@ -207,7 +234,10 @@ class QuietHTTPServer(ThreadingHTTPServer):
exc_type, exc_value, _ = sys.exc_info()
# Silently ignore common connection errors caused by client disconnects
if exc_type in (ConnectionResetError, BrokenPipeError, ConnectionAbortedError, TimeoutError):
if exc_type in (
ConnectionResetError, BrokenPipeError, ConnectionAbortedError,
TimeoutError, ssl.SSLError, ssl.SSLEOFError,
):
return
# Also handle socket errors that indicate client disconnect
@@ -648,7 +678,7 @@ def main() -> None:
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
ctx.load_cert_chain(TLS_CERT, TLS_KEY)
httpd.socket = ctx.wrap_socket(httpd.socket, server_side=True)
httpd.ssl_context = ctx
print(f' TLS enabled: cert={TLS_CERT}, key={TLS_KEY}', flush=True)
except Exception as e:
print(f'[!!] WARNING: TLS setup failed ({e}), falling back to HTTP', flush=True)