17db96d56Sopenharmony_ci"""
27db96d56Sopenharmony_ciTest suite for socketserver.
37db96d56Sopenharmony_ci"""
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ciimport contextlib
67db96d56Sopenharmony_ciimport io
77db96d56Sopenharmony_ciimport os
87db96d56Sopenharmony_ciimport select
97db96d56Sopenharmony_ciimport signal
107db96d56Sopenharmony_ciimport socket
117db96d56Sopenharmony_ciimport tempfile
127db96d56Sopenharmony_ciimport threading
137db96d56Sopenharmony_ciimport unittest
147db96d56Sopenharmony_ciimport socketserver
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ciimport test.support
177db96d56Sopenharmony_cifrom test.support import reap_children, verbose
187db96d56Sopenharmony_cifrom test.support import os_helper
197db96d56Sopenharmony_cifrom test.support import socket_helper
207db96d56Sopenharmony_cifrom test.support import threading_helper
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_citest.support.requires("network")
247db96d56Sopenharmony_citest.support.requires_working_socket(module=True)
257db96d56Sopenharmony_ci
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ciTEST_STR = b"hello world\n"
287db96d56Sopenharmony_ciHOST = socket_helper.HOST
297db96d56Sopenharmony_ci
307db96d56Sopenharmony_ciHAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX")
317db96d56Sopenharmony_cirequires_unix_sockets = unittest.skipUnless(HAVE_UNIX_SOCKETS,
327db96d56Sopenharmony_ci                                            'requires Unix sockets')
337db96d56Sopenharmony_ciHAVE_FORKING = test.support.has_fork_support
347db96d56Sopenharmony_cirequires_forking = unittest.skipUnless(HAVE_FORKING, 'requires forking')
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_cidef signal_alarm(n):
377db96d56Sopenharmony_ci    """Call signal.alarm when it exists (i.e. not on Windows)."""
387db96d56Sopenharmony_ci    if hasattr(signal, 'alarm'):
397db96d56Sopenharmony_ci        signal.alarm(n)
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci# Remember real select() to avoid interferences with mocking
427db96d56Sopenharmony_ci_real_select = select.select
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_cidef receive(sock, n, timeout=test.support.SHORT_TIMEOUT):
457db96d56Sopenharmony_ci    r, w, x = _real_select([sock], [], [], timeout)
467db96d56Sopenharmony_ci    if sock in r:
477db96d56Sopenharmony_ci        return sock.recv(n)
487db96d56Sopenharmony_ci    else:
497db96d56Sopenharmony_ci        raise RuntimeError("timed out on %r" % (sock,))
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ciif HAVE_UNIX_SOCKETS and HAVE_FORKING:
527db96d56Sopenharmony_ci    class ForkingUnixStreamServer(socketserver.ForkingMixIn,
537db96d56Sopenharmony_ci                                  socketserver.UnixStreamServer):
547db96d56Sopenharmony_ci        pass
557db96d56Sopenharmony_ci
567db96d56Sopenharmony_ci    class ForkingUnixDatagramServer(socketserver.ForkingMixIn,
577db96d56Sopenharmony_ci                                    socketserver.UnixDatagramServer):
587db96d56Sopenharmony_ci        pass
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci
617db96d56Sopenharmony_ci@contextlib.contextmanager
627db96d56Sopenharmony_cidef simple_subprocess(testcase):
637db96d56Sopenharmony_ci    """Tests that a custom child process is not waited on (Issue 1540386)"""
647db96d56Sopenharmony_ci    pid = os.fork()
657db96d56Sopenharmony_ci    if pid == 0:
667db96d56Sopenharmony_ci        # Don't raise an exception; it would be caught by the test harness.
677db96d56Sopenharmony_ci        os._exit(72)
687db96d56Sopenharmony_ci    try:
697db96d56Sopenharmony_ci        yield None
707db96d56Sopenharmony_ci    except:
717db96d56Sopenharmony_ci        raise
727db96d56Sopenharmony_ci    finally:
737db96d56Sopenharmony_ci        test.support.wait_process(pid, exitcode=72)
747db96d56Sopenharmony_ci
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_ciclass SocketServerTest(unittest.TestCase):
777db96d56Sopenharmony_ci    """Test all socket servers."""
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci    def setUp(self):
807db96d56Sopenharmony_ci        signal_alarm(60)  # Kill deadlocks after 60 seconds.
817db96d56Sopenharmony_ci        self.port_seed = 0
827db96d56Sopenharmony_ci        self.test_files = []
837db96d56Sopenharmony_ci
847db96d56Sopenharmony_ci    def tearDown(self):
857db96d56Sopenharmony_ci        signal_alarm(0)  # Didn't deadlock.
867db96d56Sopenharmony_ci        reap_children()
877db96d56Sopenharmony_ci
887db96d56Sopenharmony_ci        for fn in self.test_files:
897db96d56Sopenharmony_ci            try:
907db96d56Sopenharmony_ci                os.remove(fn)
917db96d56Sopenharmony_ci            except OSError:
927db96d56Sopenharmony_ci                pass
937db96d56Sopenharmony_ci        self.test_files[:] = []
947db96d56Sopenharmony_ci
957db96d56Sopenharmony_ci    def pickaddr(self, proto):
967db96d56Sopenharmony_ci        if proto == socket.AF_INET:
977db96d56Sopenharmony_ci            return (HOST, 0)
987db96d56Sopenharmony_ci        else:
997db96d56Sopenharmony_ci            # XXX: We need a way to tell AF_UNIX to pick its own name
1007db96d56Sopenharmony_ci            # like AF_INET provides port==0.
1017db96d56Sopenharmony_ci            dir = None
1027db96d56Sopenharmony_ci            fn = tempfile.mktemp(prefix='unix_socket.', dir=dir)
1037db96d56Sopenharmony_ci            self.test_files.append(fn)
1047db96d56Sopenharmony_ci            return fn
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_ci    def make_server(self, addr, svrcls, hdlrbase):
1077db96d56Sopenharmony_ci        class MyServer(svrcls):
1087db96d56Sopenharmony_ci            def handle_error(self, request, client_address):
1097db96d56Sopenharmony_ci                self.close_request(request)
1107db96d56Sopenharmony_ci                raise
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_ci        class MyHandler(hdlrbase):
1137db96d56Sopenharmony_ci            def handle(self):
1147db96d56Sopenharmony_ci                line = self.rfile.readline()
1157db96d56Sopenharmony_ci                self.wfile.write(line)
1167db96d56Sopenharmony_ci
1177db96d56Sopenharmony_ci        if verbose: print("creating server")
1187db96d56Sopenharmony_ci        try:
1197db96d56Sopenharmony_ci            server = MyServer(addr, MyHandler)
1207db96d56Sopenharmony_ci        except PermissionError as e:
1217db96d56Sopenharmony_ci            # Issue 29184: cannot bind() a Unix socket on Android.
1227db96d56Sopenharmony_ci            self.skipTest('Cannot create server (%s, %s): %s' %
1237db96d56Sopenharmony_ci                          (svrcls, addr, e))
1247db96d56Sopenharmony_ci        self.assertEqual(server.server_address, server.socket.getsockname())
1257db96d56Sopenharmony_ci        return server
1267db96d56Sopenharmony_ci
1277db96d56Sopenharmony_ci    @threading_helper.reap_threads
1287db96d56Sopenharmony_ci    def run_server(self, svrcls, hdlrbase, testfunc):
1297db96d56Sopenharmony_ci        server = self.make_server(self.pickaddr(svrcls.address_family),
1307db96d56Sopenharmony_ci                                  svrcls, hdlrbase)
1317db96d56Sopenharmony_ci        # We had the OS pick a port, so pull the real address out of
1327db96d56Sopenharmony_ci        # the server.
1337db96d56Sopenharmony_ci        addr = server.server_address
1347db96d56Sopenharmony_ci        if verbose:
1357db96d56Sopenharmony_ci            print("ADDR =", addr)
1367db96d56Sopenharmony_ci            print("CLASS =", svrcls)
1377db96d56Sopenharmony_ci
1387db96d56Sopenharmony_ci        t = threading.Thread(
1397db96d56Sopenharmony_ci            name='%s serving' % svrcls,
1407db96d56Sopenharmony_ci            target=server.serve_forever,
1417db96d56Sopenharmony_ci            # Short poll interval to make the test finish quickly.
1427db96d56Sopenharmony_ci            # Time between requests is short enough that we won't wake
1437db96d56Sopenharmony_ci            # up spuriously too many times.
1447db96d56Sopenharmony_ci            kwargs={'poll_interval':0.01})
1457db96d56Sopenharmony_ci        t.daemon = True  # In case this function raises.
1467db96d56Sopenharmony_ci        t.start()
1477db96d56Sopenharmony_ci        if verbose: print("server running")
1487db96d56Sopenharmony_ci        for i in range(3):
1497db96d56Sopenharmony_ci            if verbose: print("test client", i)
1507db96d56Sopenharmony_ci            testfunc(svrcls.address_family, addr)
1517db96d56Sopenharmony_ci        if verbose: print("waiting for server")
1527db96d56Sopenharmony_ci        server.shutdown()
1537db96d56Sopenharmony_ci        t.join()
1547db96d56Sopenharmony_ci        server.server_close()
1557db96d56Sopenharmony_ci        self.assertEqual(-1, server.socket.fileno())
1567db96d56Sopenharmony_ci        if HAVE_FORKING and isinstance(server, socketserver.ForkingMixIn):
1577db96d56Sopenharmony_ci            # bpo-31151: Check that ForkingMixIn.server_close() waits until
1587db96d56Sopenharmony_ci            # all children completed
1597db96d56Sopenharmony_ci            self.assertFalse(server.active_children)
1607db96d56Sopenharmony_ci        if verbose: print("done")
1617db96d56Sopenharmony_ci
1627db96d56Sopenharmony_ci    def stream_examine(self, proto, addr):
1637db96d56Sopenharmony_ci        with socket.socket(proto, socket.SOCK_STREAM) as s:
1647db96d56Sopenharmony_ci            s.connect(addr)
1657db96d56Sopenharmony_ci            s.sendall(TEST_STR)
1667db96d56Sopenharmony_ci            buf = data = receive(s, 100)
1677db96d56Sopenharmony_ci            while data and b'\n' not in buf:
1687db96d56Sopenharmony_ci                data = receive(s, 100)
1697db96d56Sopenharmony_ci                buf += data
1707db96d56Sopenharmony_ci            self.assertEqual(buf, TEST_STR)
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_ci    def dgram_examine(self, proto, addr):
1737db96d56Sopenharmony_ci        with socket.socket(proto, socket.SOCK_DGRAM) as s:
1747db96d56Sopenharmony_ci            if HAVE_UNIX_SOCKETS and proto == socket.AF_UNIX:
1757db96d56Sopenharmony_ci                s.bind(self.pickaddr(proto))
1767db96d56Sopenharmony_ci            s.sendto(TEST_STR, addr)
1777db96d56Sopenharmony_ci            buf = data = receive(s, 100)
1787db96d56Sopenharmony_ci            while data and b'\n' not in buf:
1797db96d56Sopenharmony_ci                data = receive(s, 100)
1807db96d56Sopenharmony_ci                buf += data
1817db96d56Sopenharmony_ci            self.assertEqual(buf, TEST_STR)
1827db96d56Sopenharmony_ci
1837db96d56Sopenharmony_ci    def test_TCPServer(self):
1847db96d56Sopenharmony_ci        self.run_server(socketserver.TCPServer,
1857db96d56Sopenharmony_ci                        socketserver.StreamRequestHandler,
1867db96d56Sopenharmony_ci                        self.stream_examine)
1877db96d56Sopenharmony_ci
1887db96d56Sopenharmony_ci    def test_ThreadingTCPServer(self):
1897db96d56Sopenharmony_ci        self.run_server(socketserver.ThreadingTCPServer,
1907db96d56Sopenharmony_ci                        socketserver.StreamRequestHandler,
1917db96d56Sopenharmony_ci                        self.stream_examine)
1927db96d56Sopenharmony_ci
1937db96d56Sopenharmony_ci    @requires_forking
1947db96d56Sopenharmony_ci    def test_ForkingTCPServer(self):
1957db96d56Sopenharmony_ci        with simple_subprocess(self):
1967db96d56Sopenharmony_ci            self.run_server(socketserver.ForkingTCPServer,
1977db96d56Sopenharmony_ci                            socketserver.StreamRequestHandler,
1987db96d56Sopenharmony_ci                            self.stream_examine)
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_ci    @requires_unix_sockets
2017db96d56Sopenharmony_ci    def test_UnixStreamServer(self):
2027db96d56Sopenharmony_ci        self.run_server(socketserver.UnixStreamServer,
2037db96d56Sopenharmony_ci                        socketserver.StreamRequestHandler,
2047db96d56Sopenharmony_ci                        self.stream_examine)
2057db96d56Sopenharmony_ci
2067db96d56Sopenharmony_ci    @requires_unix_sockets
2077db96d56Sopenharmony_ci    def test_ThreadingUnixStreamServer(self):
2087db96d56Sopenharmony_ci        self.run_server(socketserver.ThreadingUnixStreamServer,
2097db96d56Sopenharmony_ci                        socketserver.StreamRequestHandler,
2107db96d56Sopenharmony_ci                        self.stream_examine)
2117db96d56Sopenharmony_ci
2127db96d56Sopenharmony_ci    @requires_unix_sockets
2137db96d56Sopenharmony_ci    @requires_forking
2147db96d56Sopenharmony_ci    def test_ForkingUnixStreamServer(self):
2157db96d56Sopenharmony_ci        with simple_subprocess(self):
2167db96d56Sopenharmony_ci            self.run_server(ForkingUnixStreamServer,
2177db96d56Sopenharmony_ci                            socketserver.StreamRequestHandler,
2187db96d56Sopenharmony_ci                            self.stream_examine)
2197db96d56Sopenharmony_ci
2207db96d56Sopenharmony_ci    def test_UDPServer(self):
2217db96d56Sopenharmony_ci        self.run_server(socketserver.UDPServer,
2227db96d56Sopenharmony_ci                        socketserver.DatagramRequestHandler,
2237db96d56Sopenharmony_ci                        self.dgram_examine)
2247db96d56Sopenharmony_ci
2257db96d56Sopenharmony_ci    def test_ThreadingUDPServer(self):
2267db96d56Sopenharmony_ci        self.run_server(socketserver.ThreadingUDPServer,
2277db96d56Sopenharmony_ci                        socketserver.DatagramRequestHandler,
2287db96d56Sopenharmony_ci                        self.dgram_examine)
2297db96d56Sopenharmony_ci
2307db96d56Sopenharmony_ci    @requires_forking
2317db96d56Sopenharmony_ci    def test_ForkingUDPServer(self):
2327db96d56Sopenharmony_ci        with simple_subprocess(self):
2337db96d56Sopenharmony_ci            self.run_server(socketserver.ForkingUDPServer,
2347db96d56Sopenharmony_ci                            socketserver.DatagramRequestHandler,
2357db96d56Sopenharmony_ci                            self.dgram_examine)
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_ci    @requires_unix_sockets
2387db96d56Sopenharmony_ci    def test_UnixDatagramServer(self):
2397db96d56Sopenharmony_ci        self.run_server(socketserver.UnixDatagramServer,
2407db96d56Sopenharmony_ci                        socketserver.DatagramRequestHandler,
2417db96d56Sopenharmony_ci                        self.dgram_examine)
2427db96d56Sopenharmony_ci
2437db96d56Sopenharmony_ci    @requires_unix_sockets
2447db96d56Sopenharmony_ci    def test_ThreadingUnixDatagramServer(self):
2457db96d56Sopenharmony_ci        self.run_server(socketserver.ThreadingUnixDatagramServer,
2467db96d56Sopenharmony_ci                        socketserver.DatagramRequestHandler,
2477db96d56Sopenharmony_ci                        self.dgram_examine)
2487db96d56Sopenharmony_ci
2497db96d56Sopenharmony_ci    @requires_unix_sockets
2507db96d56Sopenharmony_ci    @requires_forking
2517db96d56Sopenharmony_ci    def test_ForkingUnixDatagramServer(self):
2527db96d56Sopenharmony_ci        self.run_server(ForkingUnixDatagramServer,
2537db96d56Sopenharmony_ci                        socketserver.DatagramRequestHandler,
2547db96d56Sopenharmony_ci                        self.dgram_examine)
2557db96d56Sopenharmony_ci
2567db96d56Sopenharmony_ci    @threading_helper.reap_threads
2577db96d56Sopenharmony_ci    def test_shutdown(self):
2587db96d56Sopenharmony_ci        # Issue #2302: shutdown() should always succeed in making an
2597db96d56Sopenharmony_ci        # other thread leave serve_forever().
2607db96d56Sopenharmony_ci        class MyServer(socketserver.TCPServer):
2617db96d56Sopenharmony_ci            pass
2627db96d56Sopenharmony_ci
2637db96d56Sopenharmony_ci        class MyHandler(socketserver.StreamRequestHandler):
2647db96d56Sopenharmony_ci            pass
2657db96d56Sopenharmony_ci
2667db96d56Sopenharmony_ci        threads = []
2677db96d56Sopenharmony_ci        for i in range(20):
2687db96d56Sopenharmony_ci            s = MyServer((HOST, 0), MyHandler)
2697db96d56Sopenharmony_ci            t = threading.Thread(
2707db96d56Sopenharmony_ci                name='MyServer serving',
2717db96d56Sopenharmony_ci                target=s.serve_forever,
2727db96d56Sopenharmony_ci                kwargs={'poll_interval':0.01})
2737db96d56Sopenharmony_ci            t.daemon = True  # In case this function raises.
2747db96d56Sopenharmony_ci            threads.append((t, s))
2757db96d56Sopenharmony_ci        for t, s in threads:
2767db96d56Sopenharmony_ci            t.start()
2777db96d56Sopenharmony_ci            s.shutdown()
2787db96d56Sopenharmony_ci        for t, s in threads:
2797db96d56Sopenharmony_ci            t.join()
2807db96d56Sopenharmony_ci            s.server_close()
2817db96d56Sopenharmony_ci
2827db96d56Sopenharmony_ci    def test_close_immediately(self):
2837db96d56Sopenharmony_ci        class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
2847db96d56Sopenharmony_ci            pass
2857db96d56Sopenharmony_ci
2867db96d56Sopenharmony_ci        server = MyServer((HOST, 0), lambda: None)
2877db96d56Sopenharmony_ci        server.server_close()
2887db96d56Sopenharmony_ci
2897db96d56Sopenharmony_ci    def test_tcpserver_bind_leak(self):
2907db96d56Sopenharmony_ci        # Issue #22435: the server socket wouldn't be closed if bind()/listen()
2917db96d56Sopenharmony_ci        # failed.
2927db96d56Sopenharmony_ci        # Create many servers for which bind() will fail, to see if this result
2937db96d56Sopenharmony_ci        # in FD exhaustion.
2947db96d56Sopenharmony_ci        for i in range(1024):
2957db96d56Sopenharmony_ci            with self.assertRaises(OverflowError):
2967db96d56Sopenharmony_ci                socketserver.TCPServer((HOST, -1),
2977db96d56Sopenharmony_ci                                       socketserver.StreamRequestHandler)
2987db96d56Sopenharmony_ci
2997db96d56Sopenharmony_ci    def test_context_manager(self):
3007db96d56Sopenharmony_ci        with socketserver.TCPServer((HOST, 0),
3017db96d56Sopenharmony_ci                                    socketserver.StreamRequestHandler) as server:
3027db96d56Sopenharmony_ci            pass
3037db96d56Sopenharmony_ci        self.assertEqual(-1, server.socket.fileno())
3047db96d56Sopenharmony_ci
3057db96d56Sopenharmony_ci
3067db96d56Sopenharmony_ciclass ErrorHandlerTest(unittest.TestCase):
3077db96d56Sopenharmony_ci    """Test that the servers pass normal exceptions from the handler to
3087db96d56Sopenharmony_ci    handle_error(), and that exiting exceptions like SystemExit and
3097db96d56Sopenharmony_ci    KeyboardInterrupt are not passed."""
3107db96d56Sopenharmony_ci
3117db96d56Sopenharmony_ci    def tearDown(self):
3127db96d56Sopenharmony_ci        os_helper.unlink(os_helper.TESTFN)
3137db96d56Sopenharmony_ci
3147db96d56Sopenharmony_ci    def test_sync_handled(self):
3157db96d56Sopenharmony_ci        BaseErrorTestServer(ValueError)
3167db96d56Sopenharmony_ci        self.check_result(handled=True)
3177db96d56Sopenharmony_ci
3187db96d56Sopenharmony_ci    def test_sync_not_handled(self):
3197db96d56Sopenharmony_ci        with self.assertRaises(SystemExit):
3207db96d56Sopenharmony_ci            BaseErrorTestServer(SystemExit)
3217db96d56Sopenharmony_ci        self.check_result(handled=False)
3227db96d56Sopenharmony_ci
3237db96d56Sopenharmony_ci    def test_threading_handled(self):
3247db96d56Sopenharmony_ci        ThreadingErrorTestServer(ValueError)
3257db96d56Sopenharmony_ci        self.check_result(handled=True)
3267db96d56Sopenharmony_ci
3277db96d56Sopenharmony_ci    def test_threading_not_handled(self):
3287db96d56Sopenharmony_ci        with threading_helper.catch_threading_exception() as cm:
3297db96d56Sopenharmony_ci            ThreadingErrorTestServer(SystemExit)
3307db96d56Sopenharmony_ci            self.check_result(handled=False)
3317db96d56Sopenharmony_ci
3327db96d56Sopenharmony_ci            self.assertIs(cm.exc_type, SystemExit)
3337db96d56Sopenharmony_ci
3347db96d56Sopenharmony_ci    @requires_forking
3357db96d56Sopenharmony_ci    def test_forking_handled(self):
3367db96d56Sopenharmony_ci        ForkingErrorTestServer(ValueError)
3377db96d56Sopenharmony_ci        self.check_result(handled=True)
3387db96d56Sopenharmony_ci
3397db96d56Sopenharmony_ci    @requires_forking
3407db96d56Sopenharmony_ci    def test_forking_not_handled(self):
3417db96d56Sopenharmony_ci        ForkingErrorTestServer(SystemExit)
3427db96d56Sopenharmony_ci        self.check_result(handled=False)
3437db96d56Sopenharmony_ci
3447db96d56Sopenharmony_ci    def check_result(self, handled):
3457db96d56Sopenharmony_ci        with open(os_helper.TESTFN) as log:
3467db96d56Sopenharmony_ci            expected = 'Handler called\n' + 'Error handled\n' * handled
3477db96d56Sopenharmony_ci            self.assertEqual(log.read(), expected)
3487db96d56Sopenharmony_ci
3497db96d56Sopenharmony_ci
3507db96d56Sopenharmony_ciclass BaseErrorTestServer(socketserver.TCPServer):
3517db96d56Sopenharmony_ci    def __init__(self, exception):
3527db96d56Sopenharmony_ci        self.exception = exception
3537db96d56Sopenharmony_ci        super().__init__((HOST, 0), BadHandler)
3547db96d56Sopenharmony_ci        with socket.create_connection(self.server_address):
3557db96d56Sopenharmony_ci            pass
3567db96d56Sopenharmony_ci        try:
3577db96d56Sopenharmony_ci            self.handle_request()
3587db96d56Sopenharmony_ci        finally:
3597db96d56Sopenharmony_ci            self.server_close()
3607db96d56Sopenharmony_ci        self.wait_done()
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ci    def handle_error(self, request, client_address):
3637db96d56Sopenharmony_ci        with open(os_helper.TESTFN, 'a') as log:
3647db96d56Sopenharmony_ci            log.write('Error handled\n')
3657db96d56Sopenharmony_ci
3667db96d56Sopenharmony_ci    def wait_done(self):
3677db96d56Sopenharmony_ci        pass
3687db96d56Sopenharmony_ci
3697db96d56Sopenharmony_ci
3707db96d56Sopenharmony_ciclass BadHandler(socketserver.BaseRequestHandler):
3717db96d56Sopenharmony_ci    def handle(self):
3727db96d56Sopenharmony_ci        with open(os_helper.TESTFN, 'a') as log:
3737db96d56Sopenharmony_ci            log.write('Handler called\n')
3747db96d56Sopenharmony_ci        raise self.server.exception('Test error')
3757db96d56Sopenharmony_ci
3767db96d56Sopenharmony_ci
3777db96d56Sopenharmony_ciclass ThreadingErrorTestServer(socketserver.ThreadingMixIn,
3787db96d56Sopenharmony_ci        BaseErrorTestServer):
3797db96d56Sopenharmony_ci    def __init__(self, *pos, **kw):
3807db96d56Sopenharmony_ci        self.done = threading.Event()
3817db96d56Sopenharmony_ci        super().__init__(*pos, **kw)
3827db96d56Sopenharmony_ci
3837db96d56Sopenharmony_ci    def shutdown_request(self, *pos, **kw):
3847db96d56Sopenharmony_ci        super().shutdown_request(*pos, **kw)
3857db96d56Sopenharmony_ci        self.done.set()
3867db96d56Sopenharmony_ci
3877db96d56Sopenharmony_ci    def wait_done(self):
3887db96d56Sopenharmony_ci        self.done.wait()
3897db96d56Sopenharmony_ci
3907db96d56Sopenharmony_ci
3917db96d56Sopenharmony_ciif HAVE_FORKING:
3927db96d56Sopenharmony_ci    class ForkingErrorTestServer(socketserver.ForkingMixIn, BaseErrorTestServer):
3937db96d56Sopenharmony_ci        pass
3947db96d56Sopenharmony_ci
3957db96d56Sopenharmony_ci
3967db96d56Sopenharmony_ciclass SocketWriterTest(unittest.TestCase):
3977db96d56Sopenharmony_ci    def test_basics(self):
3987db96d56Sopenharmony_ci        class Handler(socketserver.StreamRequestHandler):
3997db96d56Sopenharmony_ci            def handle(self):
4007db96d56Sopenharmony_ci                self.server.wfile = self.wfile
4017db96d56Sopenharmony_ci                self.server.wfile_fileno = self.wfile.fileno()
4027db96d56Sopenharmony_ci                self.server.request_fileno = self.request.fileno()
4037db96d56Sopenharmony_ci
4047db96d56Sopenharmony_ci        server = socketserver.TCPServer((HOST, 0), Handler)
4057db96d56Sopenharmony_ci        self.addCleanup(server.server_close)
4067db96d56Sopenharmony_ci        s = socket.socket(
4077db96d56Sopenharmony_ci            server.address_family, socket.SOCK_STREAM, socket.IPPROTO_TCP)
4087db96d56Sopenharmony_ci        with s:
4097db96d56Sopenharmony_ci            s.connect(server.server_address)
4107db96d56Sopenharmony_ci        server.handle_request()
4117db96d56Sopenharmony_ci        self.assertIsInstance(server.wfile, io.BufferedIOBase)
4127db96d56Sopenharmony_ci        self.assertEqual(server.wfile_fileno, server.request_fileno)
4137db96d56Sopenharmony_ci
4147db96d56Sopenharmony_ci    def test_write(self):
4157db96d56Sopenharmony_ci        # Test that wfile.write() sends data immediately, and that it does
4167db96d56Sopenharmony_ci        # not truncate sends when interrupted by a Unix signal
4177db96d56Sopenharmony_ci        pthread_kill = test.support.get_attribute(signal, 'pthread_kill')
4187db96d56Sopenharmony_ci
4197db96d56Sopenharmony_ci        class Handler(socketserver.StreamRequestHandler):
4207db96d56Sopenharmony_ci            def handle(self):
4217db96d56Sopenharmony_ci                self.server.sent1 = self.wfile.write(b'write data\n')
4227db96d56Sopenharmony_ci                # Should be sent immediately, without requiring flush()
4237db96d56Sopenharmony_ci                self.server.received = self.rfile.readline()
4247db96d56Sopenharmony_ci                big_chunk = b'\0' * test.support.SOCK_MAX_SIZE
4257db96d56Sopenharmony_ci                self.server.sent2 = self.wfile.write(big_chunk)
4267db96d56Sopenharmony_ci
4277db96d56Sopenharmony_ci        server = socketserver.TCPServer((HOST, 0), Handler)
4287db96d56Sopenharmony_ci        self.addCleanup(server.server_close)
4297db96d56Sopenharmony_ci        interrupted = threading.Event()
4307db96d56Sopenharmony_ci
4317db96d56Sopenharmony_ci        def signal_handler(signum, frame):
4327db96d56Sopenharmony_ci            interrupted.set()
4337db96d56Sopenharmony_ci
4347db96d56Sopenharmony_ci        original = signal.signal(signal.SIGUSR1, signal_handler)
4357db96d56Sopenharmony_ci        self.addCleanup(signal.signal, signal.SIGUSR1, original)
4367db96d56Sopenharmony_ci        response1 = None
4377db96d56Sopenharmony_ci        received2 = None
4387db96d56Sopenharmony_ci        main_thread = threading.get_ident()
4397db96d56Sopenharmony_ci
4407db96d56Sopenharmony_ci        def run_client():
4417db96d56Sopenharmony_ci            s = socket.socket(server.address_family, socket.SOCK_STREAM,
4427db96d56Sopenharmony_ci                socket.IPPROTO_TCP)
4437db96d56Sopenharmony_ci            with s, s.makefile('rb') as reader:
4447db96d56Sopenharmony_ci                s.connect(server.server_address)
4457db96d56Sopenharmony_ci                nonlocal response1
4467db96d56Sopenharmony_ci                response1 = reader.readline()
4477db96d56Sopenharmony_ci                s.sendall(b'client response\n')
4487db96d56Sopenharmony_ci
4497db96d56Sopenharmony_ci                reader.read(100)
4507db96d56Sopenharmony_ci                # The main thread should now be blocking in a send() syscall.
4517db96d56Sopenharmony_ci                # But in theory, it could get interrupted by other signals,
4527db96d56Sopenharmony_ci                # and then retried. So keep sending the signal in a loop, in
4537db96d56Sopenharmony_ci                # case an earlier signal happens to be delivered at an
4547db96d56Sopenharmony_ci                # inconvenient moment.
4557db96d56Sopenharmony_ci                while True:
4567db96d56Sopenharmony_ci                    pthread_kill(main_thread, signal.SIGUSR1)
4577db96d56Sopenharmony_ci                    if interrupted.wait(timeout=float(1)):
4587db96d56Sopenharmony_ci                        break
4597db96d56Sopenharmony_ci                nonlocal received2
4607db96d56Sopenharmony_ci                received2 = len(reader.read())
4617db96d56Sopenharmony_ci
4627db96d56Sopenharmony_ci        background = threading.Thread(target=run_client)
4637db96d56Sopenharmony_ci        background.start()
4647db96d56Sopenharmony_ci        server.handle_request()
4657db96d56Sopenharmony_ci        background.join()
4667db96d56Sopenharmony_ci        self.assertEqual(server.sent1, len(response1))
4677db96d56Sopenharmony_ci        self.assertEqual(response1, b'write data\n')
4687db96d56Sopenharmony_ci        self.assertEqual(server.received, b'client response\n')
4697db96d56Sopenharmony_ci        self.assertEqual(server.sent2, test.support.SOCK_MAX_SIZE)
4707db96d56Sopenharmony_ci        self.assertEqual(received2, test.support.SOCK_MAX_SIZE - 100)
4717db96d56Sopenharmony_ci
4727db96d56Sopenharmony_ci
4737db96d56Sopenharmony_ciclass MiscTestCase(unittest.TestCase):
4747db96d56Sopenharmony_ci
4757db96d56Sopenharmony_ci    def test_all(self):
4767db96d56Sopenharmony_ci        # objects defined in the module should be in __all__
4777db96d56Sopenharmony_ci        expected = []
4787db96d56Sopenharmony_ci        for name in dir(socketserver):
4797db96d56Sopenharmony_ci            if not name.startswith('_'):
4807db96d56Sopenharmony_ci                mod_object = getattr(socketserver, name)
4817db96d56Sopenharmony_ci                if getattr(mod_object, '__module__', None) == 'socketserver':
4827db96d56Sopenharmony_ci                    expected.append(name)
4837db96d56Sopenharmony_ci        self.assertCountEqual(socketserver.__all__, expected)
4847db96d56Sopenharmony_ci
4857db96d56Sopenharmony_ci    def test_shutdown_request_called_if_verify_request_false(self):
4867db96d56Sopenharmony_ci        # Issue #26309: BaseServer should call shutdown_request even if
4877db96d56Sopenharmony_ci        # verify_request is False
4887db96d56Sopenharmony_ci
4897db96d56Sopenharmony_ci        class MyServer(socketserver.TCPServer):
4907db96d56Sopenharmony_ci            def verify_request(self, request, client_address):
4917db96d56Sopenharmony_ci                return False
4927db96d56Sopenharmony_ci
4937db96d56Sopenharmony_ci            shutdown_called = 0
4947db96d56Sopenharmony_ci            def shutdown_request(self, request):
4957db96d56Sopenharmony_ci                self.shutdown_called += 1
4967db96d56Sopenharmony_ci                socketserver.TCPServer.shutdown_request(self, request)
4977db96d56Sopenharmony_ci
4987db96d56Sopenharmony_ci        server = MyServer((HOST, 0), socketserver.StreamRequestHandler)
4997db96d56Sopenharmony_ci        s = socket.socket(server.address_family, socket.SOCK_STREAM)
5007db96d56Sopenharmony_ci        s.connect(server.server_address)
5017db96d56Sopenharmony_ci        s.close()
5027db96d56Sopenharmony_ci        server.handle_request()
5037db96d56Sopenharmony_ci        self.assertEqual(server.shutdown_called, 1)
5047db96d56Sopenharmony_ci        server.server_close()
5057db96d56Sopenharmony_ci
5067db96d56Sopenharmony_ci    def test_threads_reaped(self):
5077db96d56Sopenharmony_ci        """
5087db96d56Sopenharmony_ci        In #37193, users reported a memory leak
5097db96d56Sopenharmony_ci        due to the saving of every request thread. Ensure that
5107db96d56Sopenharmony_ci        not all threads are kept forever.
5117db96d56Sopenharmony_ci        """
5127db96d56Sopenharmony_ci        class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
5137db96d56Sopenharmony_ci            pass
5147db96d56Sopenharmony_ci
5157db96d56Sopenharmony_ci        server = MyServer((HOST, 0), socketserver.StreamRequestHandler)
5167db96d56Sopenharmony_ci        for n in range(10):
5177db96d56Sopenharmony_ci            with socket.create_connection(server.server_address):
5187db96d56Sopenharmony_ci                server.handle_request()
5197db96d56Sopenharmony_ci        self.assertLess(len(server._threads), 10)
5207db96d56Sopenharmony_ci        server.server_close()
5217db96d56Sopenharmony_ci
5227db96d56Sopenharmony_ci
5237db96d56Sopenharmony_ciif __name__ == "__main__":
5247db96d56Sopenharmony_ci    unittest.main()
525