17db96d56Sopenharmony_ci"""Unittests for the various HTTPServer modules.
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ciWritten by Cody A.W. Somerville <cody-somerville@ubuntu.com>,
47db96d56Sopenharmony_ciJosip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest.
57db96d56Sopenharmony_ci"""
67db96d56Sopenharmony_cifrom collections import OrderedDict
77db96d56Sopenharmony_cifrom http.server import BaseHTTPRequestHandler, HTTPServer, \
87db96d56Sopenharmony_ci     SimpleHTTPRequestHandler, CGIHTTPRequestHandler
97db96d56Sopenharmony_cifrom http import server, HTTPStatus
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ciimport os
127db96d56Sopenharmony_ciimport socket
137db96d56Sopenharmony_ciimport sys
147db96d56Sopenharmony_ciimport re
157db96d56Sopenharmony_ciimport base64
167db96d56Sopenharmony_ciimport ntpath
177db96d56Sopenharmony_ciimport pathlib
187db96d56Sopenharmony_ciimport shutil
197db96d56Sopenharmony_ciimport email.message
207db96d56Sopenharmony_ciimport email.utils
217db96d56Sopenharmony_ciimport html
227db96d56Sopenharmony_ciimport http, http.client
237db96d56Sopenharmony_ciimport urllib.parse
247db96d56Sopenharmony_ciimport tempfile
257db96d56Sopenharmony_ciimport time
267db96d56Sopenharmony_ciimport datetime
277db96d56Sopenharmony_ciimport threading
287db96d56Sopenharmony_cifrom unittest import mock
297db96d56Sopenharmony_cifrom io import BytesIO, StringIO
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ciimport unittest
327db96d56Sopenharmony_cifrom test import support
337db96d56Sopenharmony_cifrom test.support import os_helper
347db96d56Sopenharmony_cifrom test.support import threading_helper
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_cisupport.requires_working_socket(module=True)
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ciclass NoLogRequestHandler:
397db96d56Sopenharmony_ci    def log_message(self, *args):
407db96d56Sopenharmony_ci        # don't write log messages to stderr
417db96d56Sopenharmony_ci        pass
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_ci    def read(self, n=None):
447db96d56Sopenharmony_ci        return ''
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ciclass TestServerThread(threading.Thread):
487db96d56Sopenharmony_ci    def __init__(self, test_object, request_handler):
497db96d56Sopenharmony_ci        threading.Thread.__init__(self)
507db96d56Sopenharmony_ci        self.request_handler = request_handler
517db96d56Sopenharmony_ci        self.test_object = test_object
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_ci    def run(self):
547db96d56Sopenharmony_ci        self.server = HTTPServer(('localhost', 0), self.request_handler)
557db96d56Sopenharmony_ci        self.test_object.HOST, self.test_object.PORT = self.server.socket.getsockname()
567db96d56Sopenharmony_ci        self.test_object.server_started.set()
577db96d56Sopenharmony_ci        self.test_object = None
587db96d56Sopenharmony_ci        try:
597db96d56Sopenharmony_ci            self.server.serve_forever(0.05)
607db96d56Sopenharmony_ci        finally:
617db96d56Sopenharmony_ci            self.server.server_close()
627db96d56Sopenharmony_ci
637db96d56Sopenharmony_ci    def stop(self):
647db96d56Sopenharmony_ci        self.server.shutdown()
657db96d56Sopenharmony_ci        self.join()
667db96d56Sopenharmony_ci
677db96d56Sopenharmony_ci
687db96d56Sopenharmony_ciclass BaseTestCase(unittest.TestCase):
697db96d56Sopenharmony_ci    def setUp(self):
707db96d56Sopenharmony_ci        self._threads = threading_helper.threading_setup()
717db96d56Sopenharmony_ci        os.environ = os_helper.EnvironmentVarGuard()
727db96d56Sopenharmony_ci        self.server_started = threading.Event()
737db96d56Sopenharmony_ci        self.thread = TestServerThread(self, self.request_handler)
747db96d56Sopenharmony_ci        self.thread.start()
757db96d56Sopenharmony_ci        self.server_started.wait()
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_ci    def tearDown(self):
787db96d56Sopenharmony_ci        self.thread.stop()
797db96d56Sopenharmony_ci        self.thread = None
807db96d56Sopenharmony_ci        os.environ.__exit__()
817db96d56Sopenharmony_ci        threading_helper.threading_cleanup(*self._threads)
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_ci    def request(self, uri, method='GET', body=None, headers={}):
847db96d56Sopenharmony_ci        self.connection = http.client.HTTPConnection(self.HOST, self.PORT)
857db96d56Sopenharmony_ci        self.connection.request(method, uri, body, headers)
867db96d56Sopenharmony_ci        return self.connection.getresponse()
877db96d56Sopenharmony_ci
887db96d56Sopenharmony_ci
897db96d56Sopenharmony_ciclass BaseHTTPServerTestCase(BaseTestCase):
907db96d56Sopenharmony_ci    class request_handler(NoLogRequestHandler, BaseHTTPRequestHandler):
917db96d56Sopenharmony_ci        protocol_version = 'HTTP/1.1'
927db96d56Sopenharmony_ci        default_request_version = 'HTTP/1.1'
937db96d56Sopenharmony_ci
947db96d56Sopenharmony_ci        def do_TEST(self):
957db96d56Sopenharmony_ci            self.send_response(HTTPStatus.NO_CONTENT)
967db96d56Sopenharmony_ci            self.send_header('Content-Type', 'text/html')
977db96d56Sopenharmony_ci            self.send_header('Connection', 'close')
987db96d56Sopenharmony_ci            self.end_headers()
997db96d56Sopenharmony_ci
1007db96d56Sopenharmony_ci        def do_KEEP(self):
1017db96d56Sopenharmony_ci            self.send_response(HTTPStatus.NO_CONTENT)
1027db96d56Sopenharmony_ci            self.send_header('Content-Type', 'text/html')
1037db96d56Sopenharmony_ci            self.send_header('Connection', 'keep-alive')
1047db96d56Sopenharmony_ci            self.end_headers()
1057db96d56Sopenharmony_ci
1067db96d56Sopenharmony_ci        def do_KEYERROR(self):
1077db96d56Sopenharmony_ci            self.send_error(999)
1087db96d56Sopenharmony_ci
1097db96d56Sopenharmony_ci        def do_NOTFOUND(self):
1107db96d56Sopenharmony_ci            self.send_error(HTTPStatus.NOT_FOUND)
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_ci        def do_EXPLAINERROR(self):
1137db96d56Sopenharmony_ci            self.send_error(999, "Short Message",
1147db96d56Sopenharmony_ci                            "This is a long \n explanation")
1157db96d56Sopenharmony_ci
1167db96d56Sopenharmony_ci        def do_CUSTOM(self):
1177db96d56Sopenharmony_ci            self.send_response(999)
1187db96d56Sopenharmony_ci            self.send_header('Content-Type', 'text/html')
1197db96d56Sopenharmony_ci            self.send_header('Connection', 'close')
1207db96d56Sopenharmony_ci            self.end_headers()
1217db96d56Sopenharmony_ci
1227db96d56Sopenharmony_ci        def do_LATINONEHEADER(self):
1237db96d56Sopenharmony_ci            self.send_response(999)
1247db96d56Sopenharmony_ci            self.send_header('X-Special', 'Dängerous Mind')
1257db96d56Sopenharmony_ci            self.send_header('Connection', 'close')
1267db96d56Sopenharmony_ci            self.end_headers()
1277db96d56Sopenharmony_ci            body = self.headers['x-special-incoming'].encode('utf-8')
1287db96d56Sopenharmony_ci            self.wfile.write(body)
1297db96d56Sopenharmony_ci
1307db96d56Sopenharmony_ci        def do_SEND_ERROR(self):
1317db96d56Sopenharmony_ci            self.send_error(int(self.path[1:]))
1327db96d56Sopenharmony_ci
1337db96d56Sopenharmony_ci        def do_HEAD(self):
1347db96d56Sopenharmony_ci            self.send_error(int(self.path[1:]))
1357db96d56Sopenharmony_ci
1367db96d56Sopenharmony_ci    def setUp(self):
1377db96d56Sopenharmony_ci        BaseTestCase.setUp(self)
1387db96d56Sopenharmony_ci        self.con = http.client.HTTPConnection(self.HOST, self.PORT)
1397db96d56Sopenharmony_ci        self.con.connect()
1407db96d56Sopenharmony_ci
1417db96d56Sopenharmony_ci    def test_command(self):
1427db96d56Sopenharmony_ci        self.con.request('GET', '/')
1437db96d56Sopenharmony_ci        res = self.con.getresponse()
1447db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.NOT_IMPLEMENTED)
1457db96d56Sopenharmony_ci
1467db96d56Sopenharmony_ci    def test_request_line_trimming(self):
1477db96d56Sopenharmony_ci        self.con._http_vsn_str = 'HTTP/1.1\n'
1487db96d56Sopenharmony_ci        self.con.putrequest('XYZBOGUS', '/')
1497db96d56Sopenharmony_ci        self.con.endheaders()
1507db96d56Sopenharmony_ci        res = self.con.getresponse()
1517db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.NOT_IMPLEMENTED)
1527db96d56Sopenharmony_ci
1537db96d56Sopenharmony_ci    def test_version_bogus(self):
1547db96d56Sopenharmony_ci        self.con._http_vsn_str = 'FUBAR'
1557db96d56Sopenharmony_ci        self.con.putrequest('GET', '/')
1567db96d56Sopenharmony_ci        self.con.endheaders()
1577db96d56Sopenharmony_ci        res = self.con.getresponse()
1587db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_ci    def test_version_digits(self):
1617db96d56Sopenharmony_ci        self.con._http_vsn_str = 'HTTP/9.9.9'
1627db96d56Sopenharmony_ci        self.con.putrequest('GET', '/')
1637db96d56Sopenharmony_ci        self.con.endheaders()
1647db96d56Sopenharmony_ci        res = self.con.getresponse()
1657db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
1667db96d56Sopenharmony_ci
1677db96d56Sopenharmony_ci    def test_version_signs_and_underscores(self):
1687db96d56Sopenharmony_ci        self.con._http_vsn_str = 'HTTP/-9_9_9.+9_9_9'
1697db96d56Sopenharmony_ci        self.con.putrequest('GET', '/')
1707db96d56Sopenharmony_ci        self.con.endheaders()
1717db96d56Sopenharmony_ci        res = self.con.getresponse()
1727db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
1737db96d56Sopenharmony_ci
1747db96d56Sopenharmony_ci    def test_major_version_number_too_long(self):
1757db96d56Sopenharmony_ci        self.con._http_vsn_str = 'HTTP/909876543210.0'
1767db96d56Sopenharmony_ci        self.con.putrequest('GET', '/')
1777db96d56Sopenharmony_ci        self.con.endheaders()
1787db96d56Sopenharmony_ci        res = self.con.getresponse()
1797db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
1807db96d56Sopenharmony_ci
1817db96d56Sopenharmony_ci    def test_minor_version_number_too_long(self):
1827db96d56Sopenharmony_ci        self.con._http_vsn_str = 'HTTP/1.909876543210'
1837db96d56Sopenharmony_ci        self.con.putrequest('GET', '/')
1847db96d56Sopenharmony_ci        self.con.endheaders()
1857db96d56Sopenharmony_ci        res = self.con.getresponse()
1867db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
1877db96d56Sopenharmony_ci
1887db96d56Sopenharmony_ci    def test_version_none_get(self):
1897db96d56Sopenharmony_ci        self.con._http_vsn_str = ''
1907db96d56Sopenharmony_ci        self.con.putrequest('GET', '/')
1917db96d56Sopenharmony_ci        self.con.endheaders()
1927db96d56Sopenharmony_ci        res = self.con.getresponse()
1937db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.NOT_IMPLEMENTED)
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci    def test_version_none(self):
1967db96d56Sopenharmony_ci        # Test that a valid method is rejected when not HTTP/1.x
1977db96d56Sopenharmony_ci        self.con._http_vsn_str = ''
1987db96d56Sopenharmony_ci        self.con.putrequest('CUSTOM', '/')
1997db96d56Sopenharmony_ci        self.con.endheaders()
2007db96d56Sopenharmony_ci        res = self.con.getresponse()
2017db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ci    def test_version_invalid(self):
2047db96d56Sopenharmony_ci        self.con._http_vsn = 99
2057db96d56Sopenharmony_ci        self.con._http_vsn_str = 'HTTP/9.9'
2067db96d56Sopenharmony_ci        self.con.putrequest('GET', '/')
2077db96d56Sopenharmony_ci        self.con.endheaders()
2087db96d56Sopenharmony_ci        res = self.con.getresponse()
2097db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.HTTP_VERSION_NOT_SUPPORTED)
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ci    def test_send_blank(self):
2127db96d56Sopenharmony_ci        self.con._http_vsn_str = ''
2137db96d56Sopenharmony_ci        self.con.putrequest('', '')
2147db96d56Sopenharmony_ci        self.con.endheaders()
2157db96d56Sopenharmony_ci        res = self.con.getresponse()
2167db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ci    def test_header_close(self):
2197db96d56Sopenharmony_ci        self.con.putrequest('GET', '/')
2207db96d56Sopenharmony_ci        self.con.putheader('Connection', 'close')
2217db96d56Sopenharmony_ci        self.con.endheaders()
2227db96d56Sopenharmony_ci        res = self.con.getresponse()
2237db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.NOT_IMPLEMENTED)
2247db96d56Sopenharmony_ci
2257db96d56Sopenharmony_ci    def test_header_keep_alive(self):
2267db96d56Sopenharmony_ci        self.con._http_vsn_str = 'HTTP/1.1'
2277db96d56Sopenharmony_ci        self.con.putrequest('GET', '/')
2287db96d56Sopenharmony_ci        self.con.putheader('Connection', 'keep-alive')
2297db96d56Sopenharmony_ci        self.con.endheaders()
2307db96d56Sopenharmony_ci        res = self.con.getresponse()
2317db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.NOT_IMPLEMENTED)
2327db96d56Sopenharmony_ci
2337db96d56Sopenharmony_ci    def test_handler(self):
2347db96d56Sopenharmony_ci        self.con.request('TEST', '/')
2357db96d56Sopenharmony_ci        res = self.con.getresponse()
2367db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.NO_CONTENT)
2377db96d56Sopenharmony_ci
2387db96d56Sopenharmony_ci    def test_return_header_keep_alive(self):
2397db96d56Sopenharmony_ci        self.con.request('KEEP', '/')
2407db96d56Sopenharmony_ci        res = self.con.getresponse()
2417db96d56Sopenharmony_ci        self.assertEqual(res.getheader('Connection'), 'keep-alive')
2427db96d56Sopenharmony_ci        self.con.request('TEST', '/')
2437db96d56Sopenharmony_ci        self.addCleanup(self.con.close)
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_ci    def test_internal_key_error(self):
2467db96d56Sopenharmony_ci        self.con.request('KEYERROR', '/')
2477db96d56Sopenharmony_ci        res = self.con.getresponse()
2487db96d56Sopenharmony_ci        self.assertEqual(res.status, 999)
2497db96d56Sopenharmony_ci
2507db96d56Sopenharmony_ci    def test_return_custom_status(self):
2517db96d56Sopenharmony_ci        self.con.request('CUSTOM', '/')
2527db96d56Sopenharmony_ci        res = self.con.getresponse()
2537db96d56Sopenharmony_ci        self.assertEqual(res.status, 999)
2547db96d56Sopenharmony_ci
2557db96d56Sopenharmony_ci    def test_return_explain_error(self):
2567db96d56Sopenharmony_ci        self.con.request('EXPLAINERROR', '/')
2577db96d56Sopenharmony_ci        res = self.con.getresponse()
2587db96d56Sopenharmony_ci        self.assertEqual(res.status, 999)
2597db96d56Sopenharmony_ci        self.assertTrue(int(res.getheader('Content-Length')))
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci    def test_latin1_header(self):
2627db96d56Sopenharmony_ci        self.con.request('LATINONEHEADER', '/', headers={
2637db96d56Sopenharmony_ci            'X-Special-Incoming':       'Ärger mit Unicode'
2647db96d56Sopenharmony_ci        })
2657db96d56Sopenharmony_ci        res = self.con.getresponse()
2667db96d56Sopenharmony_ci        self.assertEqual(res.getheader('X-Special'), 'Dängerous Mind')
2677db96d56Sopenharmony_ci        self.assertEqual(res.read(), 'Ärger mit Unicode'.encode('utf-8'))
2687db96d56Sopenharmony_ci
2697db96d56Sopenharmony_ci    def test_error_content_length(self):
2707db96d56Sopenharmony_ci        # Issue #16088: standard error responses should have a content-length
2717db96d56Sopenharmony_ci        self.con.request('NOTFOUND', '/')
2727db96d56Sopenharmony_ci        res = self.con.getresponse()
2737db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.NOT_FOUND)
2747db96d56Sopenharmony_ci
2757db96d56Sopenharmony_ci        data = res.read()
2767db96d56Sopenharmony_ci        self.assertEqual(int(res.getheader('Content-Length')), len(data))
2777db96d56Sopenharmony_ci
2787db96d56Sopenharmony_ci    def test_send_error(self):
2797db96d56Sopenharmony_ci        allow_transfer_encoding_codes = (HTTPStatus.NOT_MODIFIED,
2807db96d56Sopenharmony_ci                                         HTTPStatus.RESET_CONTENT)
2817db96d56Sopenharmony_ci        for code in (HTTPStatus.NO_CONTENT, HTTPStatus.NOT_MODIFIED,
2827db96d56Sopenharmony_ci                     HTTPStatus.PROCESSING, HTTPStatus.RESET_CONTENT,
2837db96d56Sopenharmony_ci                     HTTPStatus.SWITCHING_PROTOCOLS):
2847db96d56Sopenharmony_ci            self.con.request('SEND_ERROR', '/{}'.format(code))
2857db96d56Sopenharmony_ci            res = self.con.getresponse()
2867db96d56Sopenharmony_ci            self.assertEqual(code, res.status)
2877db96d56Sopenharmony_ci            self.assertEqual(None, res.getheader('Content-Length'))
2887db96d56Sopenharmony_ci            self.assertEqual(None, res.getheader('Content-Type'))
2897db96d56Sopenharmony_ci            if code not in allow_transfer_encoding_codes:
2907db96d56Sopenharmony_ci                self.assertEqual(None, res.getheader('Transfer-Encoding'))
2917db96d56Sopenharmony_ci
2927db96d56Sopenharmony_ci            data = res.read()
2937db96d56Sopenharmony_ci            self.assertEqual(b'', data)
2947db96d56Sopenharmony_ci
2957db96d56Sopenharmony_ci    def test_head_via_send_error(self):
2967db96d56Sopenharmony_ci        allow_transfer_encoding_codes = (HTTPStatus.NOT_MODIFIED,
2977db96d56Sopenharmony_ci                                         HTTPStatus.RESET_CONTENT)
2987db96d56Sopenharmony_ci        for code in (HTTPStatus.OK, HTTPStatus.NO_CONTENT,
2997db96d56Sopenharmony_ci                     HTTPStatus.NOT_MODIFIED, HTTPStatus.RESET_CONTENT,
3007db96d56Sopenharmony_ci                     HTTPStatus.SWITCHING_PROTOCOLS):
3017db96d56Sopenharmony_ci            self.con.request('HEAD', '/{}'.format(code))
3027db96d56Sopenharmony_ci            res = self.con.getresponse()
3037db96d56Sopenharmony_ci            self.assertEqual(code, res.status)
3047db96d56Sopenharmony_ci            if code == HTTPStatus.OK:
3057db96d56Sopenharmony_ci                self.assertTrue(int(res.getheader('Content-Length')) > 0)
3067db96d56Sopenharmony_ci                self.assertIn('text/html', res.getheader('Content-Type'))
3077db96d56Sopenharmony_ci            else:
3087db96d56Sopenharmony_ci                self.assertEqual(None, res.getheader('Content-Length'))
3097db96d56Sopenharmony_ci                self.assertEqual(None, res.getheader('Content-Type'))
3107db96d56Sopenharmony_ci            if code not in allow_transfer_encoding_codes:
3117db96d56Sopenharmony_ci                self.assertEqual(None, res.getheader('Transfer-Encoding'))
3127db96d56Sopenharmony_ci
3137db96d56Sopenharmony_ci            data = res.read()
3147db96d56Sopenharmony_ci            self.assertEqual(b'', data)
3157db96d56Sopenharmony_ci
3167db96d56Sopenharmony_ci
3177db96d56Sopenharmony_ciclass RequestHandlerLoggingTestCase(BaseTestCase):
3187db96d56Sopenharmony_ci    class request_handler(BaseHTTPRequestHandler):
3197db96d56Sopenharmony_ci        protocol_version = 'HTTP/1.1'
3207db96d56Sopenharmony_ci        default_request_version = 'HTTP/1.1'
3217db96d56Sopenharmony_ci
3227db96d56Sopenharmony_ci        def do_GET(self):
3237db96d56Sopenharmony_ci            self.send_response(HTTPStatus.OK)
3247db96d56Sopenharmony_ci            self.end_headers()
3257db96d56Sopenharmony_ci
3267db96d56Sopenharmony_ci        def do_ERROR(self):
3277db96d56Sopenharmony_ci            self.send_error(HTTPStatus.NOT_FOUND, 'File not found')
3287db96d56Sopenharmony_ci
3297db96d56Sopenharmony_ci    def test_get(self):
3307db96d56Sopenharmony_ci        self.con = http.client.HTTPConnection(self.HOST, self.PORT)
3317db96d56Sopenharmony_ci        self.con.connect()
3327db96d56Sopenharmony_ci
3337db96d56Sopenharmony_ci        with support.captured_stderr() as err:
3347db96d56Sopenharmony_ci            self.con.request('GET', '/')
3357db96d56Sopenharmony_ci            self.con.getresponse()
3367db96d56Sopenharmony_ci
3377db96d56Sopenharmony_ci        self.assertTrue(
3387db96d56Sopenharmony_ci            err.getvalue().endswith('"GET / HTTP/1.1" 200 -\n'))
3397db96d56Sopenharmony_ci
3407db96d56Sopenharmony_ci    def test_err(self):
3417db96d56Sopenharmony_ci        self.con = http.client.HTTPConnection(self.HOST, self.PORT)
3427db96d56Sopenharmony_ci        self.con.connect()
3437db96d56Sopenharmony_ci
3447db96d56Sopenharmony_ci        with support.captured_stderr() as err:
3457db96d56Sopenharmony_ci            self.con.request('ERROR', '/')
3467db96d56Sopenharmony_ci            self.con.getresponse()
3477db96d56Sopenharmony_ci
3487db96d56Sopenharmony_ci        lines = err.getvalue().split('\n')
3497db96d56Sopenharmony_ci        self.assertTrue(lines[0].endswith('code 404, message File not found'))
3507db96d56Sopenharmony_ci        self.assertTrue(lines[1].endswith('"ERROR / HTTP/1.1" 404 -'))
3517db96d56Sopenharmony_ci
3527db96d56Sopenharmony_ci
3537db96d56Sopenharmony_ciclass SimpleHTTPServerTestCase(BaseTestCase):
3547db96d56Sopenharmony_ci    class request_handler(NoLogRequestHandler, SimpleHTTPRequestHandler):
3557db96d56Sopenharmony_ci        pass
3567db96d56Sopenharmony_ci
3577db96d56Sopenharmony_ci    def setUp(self):
3587db96d56Sopenharmony_ci        super().setUp()
3597db96d56Sopenharmony_ci        self.cwd = os.getcwd()
3607db96d56Sopenharmony_ci        basetempdir = tempfile.gettempdir()
3617db96d56Sopenharmony_ci        os.chdir(basetempdir)
3627db96d56Sopenharmony_ci        self.data = b'We are the knights who say Ni!'
3637db96d56Sopenharmony_ci        self.tempdir = tempfile.mkdtemp(dir=basetempdir)
3647db96d56Sopenharmony_ci        self.tempdir_name = os.path.basename(self.tempdir)
3657db96d56Sopenharmony_ci        self.base_url = '/' + self.tempdir_name
3667db96d56Sopenharmony_ci        tempname = os.path.join(self.tempdir, 'test')
3677db96d56Sopenharmony_ci        with open(tempname, 'wb') as temp:
3687db96d56Sopenharmony_ci            temp.write(self.data)
3697db96d56Sopenharmony_ci            temp.flush()
3707db96d56Sopenharmony_ci        mtime = os.stat(tempname).st_mtime
3717db96d56Sopenharmony_ci        # compute last modification datetime for browser cache tests
3727db96d56Sopenharmony_ci        last_modif = datetime.datetime.fromtimestamp(mtime,
3737db96d56Sopenharmony_ci            datetime.timezone.utc)
3747db96d56Sopenharmony_ci        self.last_modif_datetime = last_modif.replace(microsecond=0)
3757db96d56Sopenharmony_ci        self.last_modif_header = email.utils.formatdate(
3767db96d56Sopenharmony_ci            last_modif.timestamp(), usegmt=True)
3777db96d56Sopenharmony_ci
3787db96d56Sopenharmony_ci    def tearDown(self):
3797db96d56Sopenharmony_ci        try:
3807db96d56Sopenharmony_ci            os.chdir(self.cwd)
3817db96d56Sopenharmony_ci            try:
3827db96d56Sopenharmony_ci                shutil.rmtree(self.tempdir)
3837db96d56Sopenharmony_ci            except:
3847db96d56Sopenharmony_ci                pass
3857db96d56Sopenharmony_ci        finally:
3867db96d56Sopenharmony_ci            super().tearDown()
3877db96d56Sopenharmony_ci
3887db96d56Sopenharmony_ci    def check_status_and_reason(self, response, status, data=None):
3897db96d56Sopenharmony_ci        def close_conn():
3907db96d56Sopenharmony_ci            """Don't close reader yet so we can check if there was leftover
3917db96d56Sopenharmony_ci            buffered input"""
3927db96d56Sopenharmony_ci            nonlocal reader
3937db96d56Sopenharmony_ci            reader = response.fp
3947db96d56Sopenharmony_ci            response.fp = None
3957db96d56Sopenharmony_ci        reader = None
3967db96d56Sopenharmony_ci        response._close_conn = close_conn
3977db96d56Sopenharmony_ci
3987db96d56Sopenharmony_ci        body = response.read()
3997db96d56Sopenharmony_ci        self.assertTrue(response)
4007db96d56Sopenharmony_ci        self.assertEqual(response.status, status)
4017db96d56Sopenharmony_ci        self.assertIsNotNone(response.reason)
4027db96d56Sopenharmony_ci        if data:
4037db96d56Sopenharmony_ci            self.assertEqual(data, body)
4047db96d56Sopenharmony_ci        # Ensure the server has not set up a persistent connection, and has
4057db96d56Sopenharmony_ci        # not sent any extra data
4067db96d56Sopenharmony_ci        self.assertEqual(response.version, 10)
4077db96d56Sopenharmony_ci        self.assertEqual(response.msg.get("Connection", "close"), "close")
4087db96d56Sopenharmony_ci        self.assertEqual(reader.read(30), b'', 'Connection should be closed')
4097db96d56Sopenharmony_ci
4107db96d56Sopenharmony_ci        reader.close()
4117db96d56Sopenharmony_ci        return body
4127db96d56Sopenharmony_ci
4137db96d56Sopenharmony_ci    @unittest.skipIf(sys.platform == 'darwin',
4147db96d56Sopenharmony_ci                     'undecodable name cannot always be decoded on macOS')
4157db96d56Sopenharmony_ci    @unittest.skipIf(sys.platform == 'win32',
4167db96d56Sopenharmony_ci                     'undecodable name cannot be decoded on win32')
4177db96d56Sopenharmony_ci    @unittest.skipUnless(os_helper.TESTFN_UNDECODABLE,
4187db96d56Sopenharmony_ci                         'need os_helper.TESTFN_UNDECODABLE')
4197db96d56Sopenharmony_ci    def test_undecodable_filename(self):
4207db96d56Sopenharmony_ci        enc = sys.getfilesystemencoding()
4217db96d56Sopenharmony_ci        filename = os.fsdecode(os_helper.TESTFN_UNDECODABLE) + '.txt'
4227db96d56Sopenharmony_ci        with open(os.path.join(self.tempdir, filename), 'wb') as f:
4237db96d56Sopenharmony_ci            f.write(os_helper.TESTFN_UNDECODABLE)
4247db96d56Sopenharmony_ci        response = self.request(self.base_url + '/')
4257db96d56Sopenharmony_ci        if sys.platform == 'darwin':
4267db96d56Sopenharmony_ci            # On Mac OS the HFS+ filesystem replaces bytes that aren't valid
4277db96d56Sopenharmony_ci            # UTF-8 into a percent-encoded value.
4287db96d56Sopenharmony_ci            for name in os.listdir(self.tempdir):
4297db96d56Sopenharmony_ci                if name != 'test': # Ignore a filename created in setUp().
4307db96d56Sopenharmony_ci                    filename = name
4317db96d56Sopenharmony_ci                    break
4327db96d56Sopenharmony_ci        body = self.check_status_and_reason(response, HTTPStatus.OK)
4337db96d56Sopenharmony_ci        quotedname = urllib.parse.quote(filename, errors='surrogatepass')
4347db96d56Sopenharmony_ci        self.assertIn(('href="%s"' % quotedname)
4357db96d56Sopenharmony_ci                      .encode(enc, 'surrogateescape'), body)
4367db96d56Sopenharmony_ci        self.assertIn(('>%s<' % html.escape(filename, quote=False))
4377db96d56Sopenharmony_ci                      .encode(enc, 'surrogateescape'), body)
4387db96d56Sopenharmony_ci        response = self.request(self.base_url + '/' + quotedname)
4397db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK,
4407db96d56Sopenharmony_ci                                     data=os_helper.TESTFN_UNDECODABLE)
4417db96d56Sopenharmony_ci
4427db96d56Sopenharmony_ci    def test_undecodable_parameter(self):
4437db96d56Sopenharmony_ci        # sanity check using a valid parameter
4447db96d56Sopenharmony_ci        response = self.request(self.base_url + '/?x=123').read()
4457db96d56Sopenharmony_ci        self.assertRegex(response, f'listing for {self.base_url}/\?x=123'.encode('latin1'))
4467db96d56Sopenharmony_ci        # now the bogus encoding
4477db96d56Sopenharmony_ci        response = self.request(self.base_url + '/?x=%bb').read()
4487db96d56Sopenharmony_ci        self.assertRegex(response, f'listing for {self.base_url}/\?x=\xef\xbf\xbd'.encode('latin1'))
4497db96d56Sopenharmony_ci
4507db96d56Sopenharmony_ci    def test_get_dir_redirect_location_domain_injection_bug(self):
4517db96d56Sopenharmony_ci        """Ensure //evil.co/..%2f../../X does not put //evil.co/ in Location.
4527db96d56Sopenharmony_ci
4537db96d56Sopenharmony_ci        //netloc/ in a Location header is a redirect to a new host.
4547db96d56Sopenharmony_ci        https://github.com/python/cpython/issues/87389
4557db96d56Sopenharmony_ci
4567db96d56Sopenharmony_ci        This checks that a path resolving to a directory on our server cannot
4577db96d56Sopenharmony_ci        resolve into a redirect to another server.
4587db96d56Sopenharmony_ci        """
4597db96d56Sopenharmony_ci        os.mkdir(os.path.join(self.tempdir, 'existing_directory'))
4607db96d56Sopenharmony_ci        url = f'/python.org/..%2f..%2f..%2f..%2f..%2f../%0a%0d/../{self.tempdir_name}/existing_directory'
4617db96d56Sopenharmony_ci        expected_location = f'{url}/'  # /python.org.../ single slash single prefix, trailing slash
4627db96d56Sopenharmony_ci        # Canonicalizes to /tmp/tempdir_name/existing_directory which does
4637db96d56Sopenharmony_ci        # exist and is a dir, triggering the 301 redirect logic.
4647db96d56Sopenharmony_ci        response = self.request(url)
4657db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
4667db96d56Sopenharmony_ci        location = response.getheader('Location')
4677db96d56Sopenharmony_ci        self.assertEqual(location, expected_location, msg='non-attack failed!')
4687db96d56Sopenharmony_ci
4697db96d56Sopenharmony_ci        # //python.org... multi-slash prefix, no trailing slash
4707db96d56Sopenharmony_ci        attack_url = f'/{url}'
4717db96d56Sopenharmony_ci        response = self.request(attack_url)
4727db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
4737db96d56Sopenharmony_ci        location = response.getheader('Location')
4747db96d56Sopenharmony_ci        self.assertFalse(location.startswith('//'), msg=location)
4757db96d56Sopenharmony_ci        self.assertEqual(location, expected_location,
4767db96d56Sopenharmony_ci                msg='Expected Location header to start with a single / and '
4777db96d56Sopenharmony_ci                'end with a / as this is a directory redirect.')
4787db96d56Sopenharmony_ci
4797db96d56Sopenharmony_ci        # ///python.org... triple-slash prefix, no trailing slash
4807db96d56Sopenharmony_ci        attack3_url = f'//{url}'
4817db96d56Sopenharmony_ci        response = self.request(attack3_url)
4827db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
4837db96d56Sopenharmony_ci        self.assertEqual(response.getheader('Location'), expected_location)
4847db96d56Sopenharmony_ci
4857db96d56Sopenharmony_ci        # If the second word in the http request (Request-URI for the http
4867db96d56Sopenharmony_ci        # method) is a full URI, we don't worry about it, as that'll be parsed
4877db96d56Sopenharmony_ci        # and reassembled as a full URI within BaseHTTPRequestHandler.send_head
4887db96d56Sopenharmony_ci        # so no errant scheme-less //netloc//evil.co/ domain mixup can happen.
4897db96d56Sopenharmony_ci        attack_scheme_netloc_2slash_url = f'https://pypi.org/{url}'
4907db96d56Sopenharmony_ci        expected_scheme_netloc_location = f'{attack_scheme_netloc_2slash_url}/'
4917db96d56Sopenharmony_ci        response = self.request(attack_scheme_netloc_2slash_url)
4927db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
4937db96d56Sopenharmony_ci        location = response.getheader('Location')
4947db96d56Sopenharmony_ci        # We're just ensuring that the scheme and domain make it through, if
4957db96d56Sopenharmony_ci        # there are or aren't multiple slashes at the start of the path that
4967db96d56Sopenharmony_ci        # follows that isn't important in this Location: header.
4977db96d56Sopenharmony_ci        self.assertTrue(location.startswith('https://pypi.org/'), msg=location)
4987db96d56Sopenharmony_ci
4997db96d56Sopenharmony_ci    def test_get(self):
5007db96d56Sopenharmony_ci        #constructs the path relative to the root directory of the HTTPServer
5017db96d56Sopenharmony_ci        response = self.request(self.base_url + '/test')
5027db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK, data=self.data)
5037db96d56Sopenharmony_ci        # check for trailing "/" which should return 404. See Issue17324
5047db96d56Sopenharmony_ci        response = self.request(self.base_url + '/test/')
5057db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.NOT_FOUND)
5067db96d56Sopenharmony_ci        response = self.request(self.base_url + '/')
5077db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK)
5087db96d56Sopenharmony_ci        response = self.request(self.base_url)
5097db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
5107db96d56Sopenharmony_ci        self.assertEqual(response.getheader("Content-Length"), "0")
5117db96d56Sopenharmony_ci        response = self.request(self.base_url + '/?hi=2')
5127db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK)
5137db96d56Sopenharmony_ci        response = self.request(self.base_url + '?hi=1')
5147db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
5157db96d56Sopenharmony_ci        self.assertEqual(response.getheader("Location"),
5167db96d56Sopenharmony_ci                         self.base_url + "/?hi=1")
5177db96d56Sopenharmony_ci        response = self.request('/ThisDoesNotExist')
5187db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.NOT_FOUND)
5197db96d56Sopenharmony_ci        response = self.request('/' + 'ThisDoesNotExist' + '/')
5207db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.NOT_FOUND)
5217db96d56Sopenharmony_ci        os.makedirs(os.path.join(self.tempdir, 'spam', 'index.html'))
5227db96d56Sopenharmony_ci        response = self.request(self.base_url + '/spam/')
5237db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK)
5247db96d56Sopenharmony_ci
5257db96d56Sopenharmony_ci        data = b"Dummy index file\r\n"
5267db96d56Sopenharmony_ci        with open(os.path.join(self.tempdir_name, 'index.html'), 'wb') as f:
5277db96d56Sopenharmony_ci            f.write(data)
5287db96d56Sopenharmony_ci        response = self.request(self.base_url + '/')
5297db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK, data)
5307db96d56Sopenharmony_ci
5317db96d56Sopenharmony_ci        # chmod() doesn't work as expected on Windows, and filesystem
5327db96d56Sopenharmony_ci        # permissions are ignored by root on Unix.
5337db96d56Sopenharmony_ci        if os.name == 'posix' and os.geteuid() != 0:
5347db96d56Sopenharmony_ci            os.chmod(self.tempdir, 0)
5357db96d56Sopenharmony_ci            try:
5367db96d56Sopenharmony_ci                response = self.request(self.base_url + '/')
5377db96d56Sopenharmony_ci                self.check_status_and_reason(response, HTTPStatus.NOT_FOUND)
5387db96d56Sopenharmony_ci            finally:
5397db96d56Sopenharmony_ci                os.chmod(self.tempdir, 0o755)
5407db96d56Sopenharmony_ci
5417db96d56Sopenharmony_ci    def test_head(self):
5427db96d56Sopenharmony_ci        response = self.request(
5437db96d56Sopenharmony_ci            self.base_url + '/test', method='HEAD')
5447db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK)
5457db96d56Sopenharmony_ci        self.assertEqual(response.getheader('content-length'),
5467db96d56Sopenharmony_ci                         str(len(self.data)))
5477db96d56Sopenharmony_ci        self.assertEqual(response.getheader('content-type'),
5487db96d56Sopenharmony_ci                         'application/octet-stream')
5497db96d56Sopenharmony_ci
5507db96d56Sopenharmony_ci    def test_browser_cache(self):
5517db96d56Sopenharmony_ci        """Check that when a request to /test is sent with the request header
5527db96d56Sopenharmony_ci        If-Modified-Since set to date of last modification, the server returns
5537db96d56Sopenharmony_ci        status code 304, not 200
5547db96d56Sopenharmony_ci        """
5557db96d56Sopenharmony_ci        headers = email.message.Message()
5567db96d56Sopenharmony_ci        headers['If-Modified-Since'] = self.last_modif_header
5577db96d56Sopenharmony_ci        response = self.request(self.base_url + '/test', headers=headers)
5587db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.NOT_MODIFIED)
5597db96d56Sopenharmony_ci
5607db96d56Sopenharmony_ci        # one hour after last modification : must return 304
5617db96d56Sopenharmony_ci        new_dt = self.last_modif_datetime + datetime.timedelta(hours=1)
5627db96d56Sopenharmony_ci        headers = email.message.Message()
5637db96d56Sopenharmony_ci        headers['If-Modified-Since'] = email.utils.format_datetime(new_dt,
5647db96d56Sopenharmony_ci            usegmt=True)
5657db96d56Sopenharmony_ci        response = self.request(self.base_url + '/test', headers=headers)
5667db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.NOT_MODIFIED)
5677db96d56Sopenharmony_ci
5687db96d56Sopenharmony_ci    def test_browser_cache_file_changed(self):
5697db96d56Sopenharmony_ci        # with If-Modified-Since earlier than Last-Modified, must return 200
5707db96d56Sopenharmony_ci        dt = self.last_modif_datetime
5717db96d56Sopenharmony_ci        # build datetime object : 365 days before last modification
5727db96d56Sopenharmony_ci        old_dt = dt - datetime.timedelta(days=365)
5737db96d56Sopenharmony_ci        headers = email.message.Message()
5747db96d56Sopenharmony_ci        headers['If-Modified-Since'] = email.utils.format_datetime(old_dt,
5757db96d56Sopenharmony_ci            usegmt=True)
5767db96d56Sopenharmony_ci        response = self.request(self.base_url + '/test', headers=headers)
5777db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK)
5787db96d56Sopenharmony_ci
5797db96d56Sopenharmony_ci    def test_browser_cache_with_If_None_Match_header(self):
5807db96d56Sopenharmony_ci        # if If-None-Match header is present, ignore If-Modified-Since
5817db96d56Sopenharmony_ci
5827db96d56Sopenharmony_ci        headers = email.message.Message()
5837db96d56Sopenharmony_ci        headers['If-Modified-Since'] = self.last_modif_header
5847db96d56Sopenharmony_ci        headers['If-None-Match'] = "*"
5857db96d56Sopenharmony_ci        response = self.request(self.base_url + '/test', headers=headers)
5867db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK)
5877db96d56Sopenharmony_ci
5887db96d56Sopenharmony_ci    def test_invalid_requests(self):
5897db96d56Sopenharmony_ci        response = self.request('/', method='FOO')
5907db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.NOT_IMPLEMENTED)
5917db96d56Sopenharmony_ci        # requests must be case sensitive,so this should fail too
5927db96d56Sopenharmony_ci        response = self.request('/', method='custom')
5937db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.NOT_IMPLEMENTED)
5947db96d56Sopenharmony_ci        response = self.request('/', method='GETs')
5957db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.NOT_IMPLEMENTED)
5967db96d56Sopenharmony_ci
5977db96d56Sopenharmony_ci    def test_last_modified(self):
5987db96d56Sopenharmony_ci        """Checks that the datetime returned in Last-Modified response header
5997db96d56Sopenharmony_ci        is the actual datetime of last modification, rounded to the second
6007db96d56Sopenharmony_ci        """
6017db96d56Sopenharmony_ci        response = self.request(self.base_url + '/test')
6027db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK, data=self.data)
6037db96d56Sopenharmony_ci        last_modif_header = response.headers['Last-modified']
6047db96d56Sopenharmony_ci        self.assertEqual(last_modif_header, self.last_modif_header)
6057db96d56Sopenharmony_ci
6067db96d56Sopenharmony_ci    def test_path_without_leading_slash(self):
6077db96d56Sopenharmony_ci        response = self.request(self.tempdir_name + '/test')
6087db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK, data=self.data)
6097db96d56Sopenharmony_ci        response = self.request(self.tempdir_name + '/test/')
6107db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.NOT_FOUND)
6117db96d56Sopenharmony_ci        response = self.request(self.tempdir_name + '/')
6127db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK)
6137db96d56Sopenharmony_ci        response = self.request(self.tempdir_name)
6147db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
6157db96d56Sopenharmony_ci        response = self.request(self.tempdir_name + '/?hi=2')
6167db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.OK)
6177db96d56Sopenharmony_ci        response = self.request(self.tempdir_name + '?hi=1')
6187db96d56Sopenharmony_ci        self.check_status_and_reason(response, HTTPStatus.MOVED_PERMANENTLY)
6197db96d56Sopenharmony_ci        self.assertEqual(response.getheader("Location"),
6207db96d56Sopenharmony_ci                         self.tempdir_name + "/?hi=1")
6217db96d56Sopenharmony_ci
6227db96d56Sopenharmony_ci    def test_html_escape_filename(self):
6237db96d56Sopenharmony_ci        filename = '<test&>.txt'
6247db96d56Sopenharmony_ci        fullpath = os.path.join(self.tempdir, filename)
6257db96d56Sopenharmony_ci
6267db96d56Sopenharmony_ci        try:
6277db96d56Sopenharmony_ci            open(fullpath, 'wb').close()
6287db96d56Sopenharmony_ci        except OSError:
6297db96d56Sopenharmony_ci            raise unittest.SkipTest('Can not create file %s on current file '
6307db96d56Sopenharmony_ci                                    'system' % filename)
6317db96d56Sopenharmony_ci
6327db96d56Sopenharmony_ci        try:
6337db96d56Sopenharmony_ci            response = self.request(self.base_url + '/')
6347db96d56Sopenharmony_ci            body = self.check_status_and_reason(response, HTTPStatus.OK)
6357db96d56Sopenharmony_ci            enc = response.headers.get_content_charset()
6367db96d56Sopenharmony_ci        finally:
6377db96d56Sopenharmony_ci            os.unlink(fullpath)  # avoid affecting test_undecodable_filename
6387db96d56Sopenharmony_ci
6397db96d56Sopenharmony_ci        self.assertIsNotNone(enc)
6407db96d56Sopenharmony_ci        html_text = '>%s<' % html.escape(filename, quote=False)
6417db96d56Sopenharmony_ci        self.assertIn(html_text.encode(enc), body)
6427db96d56Sopenharmony_ci
6437db96d56Sopenharmony_ci
6447db96d56Sopenharmony_cicgi_file1 = """\
6457db96d56Sopenharmony_ci#!%s
6467db96d56Sopenharmony_ci
6477db96d56Sopenharmony_ciprint("Content-type: text/html")
6487db96d56Sopenharmony_ciprint()
6497db96d56Sopenharmony_ciprint("Hello World")
6507db96d56Sopenharmony_ci"""
6517db96d56Sopenharmony_ci
6527db96d56Sopenharmony_cicgi_file2 = """\
6537db96d56Sopenharmony_ci#!%s
6547db96d56Sopenharmony_ciimport os
6557db96d56Sopenharmony_ciimport sys
6567db96d56Sopenharmony_ciimport urllib.parse
6577db96d56Sopenharmony_ci
6587db96d56Sopenharmony_ciprint("Content-type: text/html")
6597db96d56Sopenharmony_ciprint()
6607db96d56Sopenharmony_ci
6617db96d56Sopenharmony_cicontent_length = int(os.environ["CONTENT_LENGTH"])
6627db96d56Sopenharmony_ciquery_string = sys.stdin.buffer.read(content_length)
6637db96d56Sopenharmony_ciparams = {key.decode("utf-8"): val.decode("utf-8")
6647db96d56Sopenharmony_ci            for key, val in urllib.parse.parse_qsl(query_string)}
6657db96d56Sopenharmony_ci
6667db96d56Sopenharmony_ciprint("%%s, %%s, %%s" %% (params["spam"], params["eggs"], params["bacon"]))
6677db96d56Sopenharmony_ci"""
6687db96d56Sopenharmony_ci
6697db96d56Sopenharmony_cicgi_file4 = """\
6707db96d56Sopenharmony_ci#!%s
6717db96d56Sopenharmony_ciimport os
6727db96d56Sopenharmony_ci
6737db96d56Sopenharmony_ciprint("Content-type: text/html")
6747db96d56Sopenharmony_ciprint()
6757db96d56Sopenharmony_ci
6767db96d56Sopenharmony_ciprint(os.environ["%s"])
6777db96d56Sopenharmony_ci"""
6787db96d56Sopenharmony_ci
6797db96d56Sopenharmony_cicgi_file6 = """\
6807db96d56Sopenharmony_ci#!%s
6817db96d56Sopenharmony_ciimport os
6827db96d56Sopenharmony_ci
6837db96d56Sopenharmony_ciprint("X-ambv: was here")
6847db96d56Sopenharmony_ciprint("Content-type: text/html")
6857db96d56Sopenharmony_ciprint()
6867db96d56Sopenharmony_ciprint("<pre>")
6877db96d56Sopenharmony_cifor k, v in os.environ.items():
6887db96d56Sopenharmony_ci    try:
6897db96d56Sopenharmony_ci        k.encode('ascii')
6907db96d56Sopenharmony_ci        v.encode('ascii')
6917db96d56Sopenharmony_ci    except UnicodeEncodeError:
6927db96d56Sopenharmony_ci        continue  # see: BPO-44647
6937db96d56Sopenharmony_ci    print(f"{k}={v}")
6947db96d56Sopenharmony_ciprint("</pre>")
6957db96d56Sopenharmony_ci"""
6967db96d56Sopenharmony_ci
6977db96d56Sopenharmony_ci
6987db96d56Sopenharmony_ci@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
6997db96d56Sopenharmony_ci        "This test can't be run reliably as root (issue #13308).")
7007db96d56Sopenharmony_ciclass CGIHTTPServerTestCase(BaseTestCase):
7017db96d56Sopenharmony_ci    class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler):
7027db96d56Sopenharmony_ci        pass
7037db96d56Sopenharmony_ci
7047db96d56Sopenharmony_ci    linesep = os.linesep.encode('ascii')
7057db96d56Sopenharmony_ci
7067db96d56Sopenharmony_ci    def setUp(self):
7077db96d56Sopenharmony_ci        BaseTestCase.setUp(self)
7087db96d56Sopenharmony_ci        self.cwd = os.getcwd()
7097db96d56Sopenharmony_ci        self.parent_dir = tempfile.mkdtemp()
7107db96d56Sopenharmony_ci        self.cgi_dir = os.path.join(self.parent_dir, 'cgi-bin')
7117db96d56Sopenharmony_ci        self.cgi_child_dir = os.path.join(self.cgi_dir, 'child-dir')
7127db96d56Sopenharmony_ci        self.sub_dir_1 = os.path.join(self.parent_dir, 'sub')
7137db96d56Sopenharmony_ci        self.sub_dir_2 = os.path.join(self.sub_dir_1, 'dir')
7147db96d56Sopenharmony_ci        self.cgi_dir_in_sub_dir = os.path.join(self.sub_dir_2, 'cgi-bin')
7157db96d56Sopenharmony_ci        os.mkdir(self.cgi_dir)
7167db96d56Sopenharmony_ci        os.mkdir(self.cgi_child_dir)
7177db96d56Sopenharmony_ci        os.mkdir(self.sub_dir_1)
7187db96d56Sopenharmony_ci        os.mkdir(self.sub_dir_2)
7197db96d56Sopenharmony_ci        os.mkdir(self.cgi_dir_in_sub_dir)
7207db96d56Sopenharmony_ci        self.nocgi_path = None
7217db96d56Sopenharmony_ci        self.file1_path = None
7227db96d56Sopenharmony_ci        self.file2_path = None
7237db96d56Sopenharmony_ci        self.file3_path = None
7247db96d56Sopenharmony_ci        self.file4_path = None
7257db96d56Sopenharmony_ci        self.file5_path = None
7267db96d56Sopenharmony_ci
7277db96d56Sopenharmony_ci        # The shebang line should be pure ASCII: use symlink if possible.
7287db96d56Sopenharmony_ci        # See issue #7668.
7297db96d56Sopenharmony_ci        self._pythonexe_symlink = None
7307db96d56Sopenharmony_ci        if os_helper.can_symlink():
7317db96d56Sopenharmony_ci            self.pythonexe = os.path.join(self.parent_dir, 'python')
7327db96d56Sopenharmony_ci            self._pythonexe_symlink = support.PythonSymlink(self.pythonexe).__enter__()
7337db96d56Sopenharmony_ci        else:
7347db96d56Sopenharmony_ci            self.pythonexe = sys.executable
7357db96d56Sopenharmony_ci
7367db96d56Sopenharmony_ci        try:
7377db96d56Sopenharmony_ci            # The python executable path is written as the first line of the
7387db96d56Sopenharmony_ci            # CGI Python script. The encoding cookie cannot be used, and so the
7397db96d56Sopenharmony_ci            # path should be encodable to the default script encoding (utf-8)
7407db96d56Sopenharmony_ci            self.pythonexe.encode('utf-8')
7417db96d56Sopenharmony_ci        except UnicodeEncodeError:
7427db96d56Sopenharmony_ci            self.tearDown()
7437db96d56Sopenharmony_ci            self.skipTest("Python executable path is not encodable to utf-8")
7447db96d56Sopenharmony_ci
7457db96d56Sopenharmony_ci        self.nocgi_path = os.path.join(self.parent_dir, 'nocgi.py')
7467db96d56Sopenharmony_ci        with open(self.nocgi_path, 'w', encoding='utf-8') as fp:
7477db96d56Sopenharmony_ci            fp.write(cgi_file1 % self.pythonexe)
7487db96d56Sopenharmony_ci        os.chmod(self.nocgi_path, 0o777)
7497db96d56Sopenharmony_ci
7507db96d56Sopenharmony_ci        self.file1_path = os.path.join(self.cgi_dir, 'file1.py')
7517db96d56Sopenharmony_ci        with open(self.file1_path, 'w', encoding='utf-8') as file1:
7527db96d56Sopenharmony_ci            file1.write(cgi_file1 % self.pythonexe)
7537db96d56Sopenharmony_ci        os.chmod(self.file1_path, 0o777)
7547db96d56Sopenharmony_ci
7557db96d56Sopenharmony_ci        self.file2_path = os.path.join(self.cgi_dir, 'file2.py')
7567db96d56Sopenharmony_ci        with open(self.file2_path, 'w', encoding='utf-8') as file2:
7577db96d56Sopenharmony_ci            file2.write(cgi_file2 % self.pythonexe)
7587db96d56Sopenharmony_ci        os.chmod(self.file2_path, 0o777)
7597db96d56Sopenharmony_ci
7607db96d56Sopenharmony_ci        self.file3_path = os.path.join(self.cgi_child_dir, 'file3.py')
7617db96d56Sopenharmony_ci        with open(self.file3_path, 'w', encoding='utf-8') as file3:
7627db96d56Sopenharmony_ci            file3.write(cgi_file1 % self.pythonexe)
7637db96d56Sopenharmony_ci        os.chmod(self.file3_path, 0o777)
7647db96d56Sopenharmony_ci
7657db96d56Sopenharmony_ci        self.file4_path = os.path.join(self.cgi_dir, 'file4.py')
7667db96d56Sopenharmony_ci        with open(self.file4_path, 'w', encoding='utf-8') as file4:
7677db96d56Sopenharmony_ci            file4.write(cgi_file4 % (self.pythonexe, 'QUERY_STRING'))
7687db96d56Sopenharmony_ci        os.chmod(self.file4_path, 0o777)
7697db96d56Sopenharmony_ci
7707db96d56Sopenharmony_ci        self.file5_path = os.path.join(self.cgi_dir_in_sub_dir, 'file5.py')
7717db96d56Sopenharmony_ci        with open(self.file5_path, 'w', encoding='utf-8') as file5:
7727db96d56Sopenharmony_ci            file5.write(cgi_file1 % self.pythonexe)
7737db96d56Sopenharmony_ci        os.chmod(self.file5_path, 0o777)
7747db96d56Sopenharmony_ci
7757db96d56Sopenharmony_ci        self.file6_path = os.path.join(self.cgi_dir, 'file6.py')
7767db96d56Sopenharmony_ci        with open(self.file6_path, 'w', encoding='utf-8') as file6:
7777db96d56Sopenharmony_ci            file6.write(cgi_file6 % self.pythonexe)
7787db96d56Sopenharmony_ci        os.chmod(self.file6_path, 0o777)
7797db96d56Sopenharmony_ci
7807db96d56Sopenharmony_ci        os.chdir(self.parent_dir)
7817db96d56Sopenharmony_ci
7827db96d56Sopenharmony_ci    def tearDown(self):
7837db96d56Sopenharmony_ci        try:
7847db96d56Sopenharmony_ci            os.chdir(self.cwd)
7857db96d56Sopenharmony_ci            if self._pythonexe_symlink:
7867db96d56Sopenharmony_ci                self._pythonexe_symlink.__exit__(None, None, None)
7877db96d56Sopenharmony_ci            if self.nocgi_path:
7887db96d56Sopenharmony_ci                os.remove(self.nocgi_path)
7897db96d56Sopenharmony_ci            if self.file1_path:
7907db96d56Sopenharmony_ci                os.remove(self.file1_path)
7917db96d56Sopenharmony_ci            if self.file2_path:
7927db96d56Sopenharmony_ci                os.remove(self.file2_path)
7937db96d56Sopenharmony_ci            if self.file3_path:
7947db96d56Sopenharmony_ci                os.remove(self.file3_path)
7957db96d56Sopenharmony_ci            if self.file4_path:
7967db96d56Sopenharmony_ci                os.remove(self.file4_path)
7977db96d56Sopenharmony_ci            if self.file5_path:
7987db96d56Sopenharmony_ci                os.remove(self.file5_path)
7997db96d56Sopenharmony_ci            if self.file6_path:
8007db96d56Sopenharmony_ci                os.remove(self.file6_path)
8017db96d56Sopenharmony_ci            os.rmdir(self.cgi_child_dir)
8027db96d56Sopenharmony_ci            os.rmdir(self.cgi_dir)
8037db96d56Sopenharmony_ci            os.rmdir(self.cgi_dir_in_sub_dir)
8047db96d56Sopenharmony_ci            os.rmdir(self.sub_dir_2)
8057db96d56Sopenharmony_ci            os.rmdir(self.sub_dir_1)
8067db96d56Sopenharmony_ci            os.rmdir(self.parent_dir)
8077db96d56Sopenharmony_ci        finally:
8087db96d56Sopenharmony_ci            BaseTestCase.tearDown(self)
8097db96d56Sopenharmony_ci
8107db96d56Sopenharmony_ci    def test_url_collapse_path(self):
8117db96d56Sopenharmony_ci        # verify tail is the last portion and head is the rest on proper urls
8127db96d56Sopenharmony_ci        test_vectors = {
8137db96d56Sopenharmony_ci            '': '//',
8147db96d56Sopenharmony_ci            '..': IndexError,
8157db96d56Sopenharmony_ci            '/.//..': IndexError,
8167db96d56Sopenharmony_ci            '/': '//',
8177db96d56Sopenharmony_ci            '//': '//',
8187db96d56Sopenharmony_ci            '/\\': '//\\',
8197db96d56Sopenharmony_ci            '/.//': '//',
8207db96d56Sopenharmony_ci            'cgi-bin/file1.py': '/cgi-bin/file1.py',
8217db96d56Sopenharmony_ci            '/cgi-bin/file1.py': '/cgi-bin/file1.py',
8227db96d56Sopenharmony_ci            'a': '//a',
8237db96d56Sopenharmony_ci            '/a': '//a',
8247db96d56Sopenharmony_ci            '//a': '//a',
8257db96d56Sopenharmony_ci            './a': '//a',
8267db96d56Sopenharmony_ci            './C:/': '/C:/',
8277db96d56Sopenharmony_ci            '/a/b': '/a/b',
8287db96d56Sopenharmony_ci            '/a/b/': '/a/b/',
8297db96d56Sopenharmony_ci            '/a/b/.': '/a/b/',
8307db96d56Sopenharmony_ci            '/a/b/c/..': '/a/b/',
8317db96d56Sopenharmony_ci            '/a/b/c/../d': '/a/b/d',
8327db96d56Sopenharmony_ci            '/a/b/c/../d/e/../f': '/a/b/d/f',
8337db96d56Sopenharmony_ci            '/a/b/c/../d/e/../../f': '/a/b/f',
8347db96d56Sopenharmony_ci            '/a/b/c/../d/e/.././././..//f': '/a/b/f',
8357db96d56Sopenharmony_ci            '../a/b/c/../d/e/.././././..//f': IndexError,
8367db96d56Sopenharmony_ci            '/a/b/c/../d/e/../../../f': '/a/f',
8377db96d56Sopenharmony_ci            '/a/b/c/../d/e/../../../../f': '//f',
8387db96d56Sopenharmony_ci            '/a/b/c/../d/e/../../../../../f': IndexError,
8397db96d56Sopenharmony_ci            '/a/b/c/../d/e/../../../../f/..': '//',
8407db96d56Sopenharmony_ci            '/a/b/c/../d/e/../../../../f/../.': '//',
8417db96d56Sopenharmony_ci        }
8427db96d56Sopenharmony_ci        for path, expected in test_vectors.items():
8437db96d56Sopenharmony_ci            if isinstance(expected, type) and issubclass(expected, Exception):
8447db96d56Sopenharmony_ci                self.assertRaises(expected,
8457db96d56Sopenharmony_ci                                  server._url_collapse_path, path)
8467db96d56Sopenharmony_ci            else:
8477db96d56Sopenharmony_ci                actual = server._url_collapse_path(path)
8487db96d56Sopenharmony_ci                self.assertEqual(expected, actual,
8497db96d56Sopenharmony_ci                                 msg='path = %r\nGot:    %r\nWanted: %r' %
8507db96d56Sopenharmony_ci                                 (path, actual, expected))
8517db96d56Sopenharmony_ci
8527db96d56Sopenharmony_ci    def test_headers_and_content(self):
8537db96d56Sopenharmony_ci        res = self.request('/cgi-bin/file1.py')
8547db96d56Sopenharmony_ci        self.assertEqual(
8557db96d56Sopenharmony_ci            (res.read(), res.getheader('Content-type'), res.status),
8567db96d56Sopenharmony_ci            (b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK))
8577db96d56Sopenharmony_ci
8587db96d56Sopenharmony_ci    def test_issue19435(self):
8597db96d56Sopenharmony_ci        res = self.request('///////////nocgi.py/../cgi-bin/nothere.sh')
8607db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.NOT_FOUND)
8617db96d56Sopenharmony_ci
8627db96d56Sopenharmony_ci    def test_post(self):
8637db96d56Sopenharmony_ci        params = urllib.parse.urlencode(
8647db96d56Sopenharmony_ci            {'spam' : 1, 'eggs' : 'python', 'bacon' : 123456})
8657db96d56Sopenharmony_ci        headers = {'Content-type' : 'application/x-www-form-urlencoded'}
8667db96d56Sopenharmony_ci        res = self.request('/cgi-bin/file2.py', 'POST', params, headers)
8677db96d56Sopenharmony_ci
8687db96d56Sopenharmony_ci        self.assertEqual(res.read(), b'1, python, 123456' + self.linesep)
8697db96d56Sopenharmony_ci
8707db96d56Sopenharmony_ci    def test_invaliduri(self):
8717db96d56Sopenharmony_ci        res = self.request('/cgi-bin/invalid')
8727db96d56Sopenharmony_ci        res.read()
8737db96d56Sopenharmony_ci        self.assertEqual(res.status, HTTPStatus.NOT_FOUND)
8747db96d56Sopenharmony_ci
8757db96d56Sopenharmony_ci    def test_authorization(self):
8767db96d56Sopenharmony_ci        headers = {b'Authorization' : b'Basic ' +
8777db96d56Sopenharmony_ci                   base64.b64encode(b'username:pass')}
8787db96d56Sopenharmony_ci        res = self.request('/cgi-bin/file1.py', 'GET', headers=headers)
8797db96d56Sopenharmony_ci        self.assertEqual(
8807db96d56Sopenharmony_ci            (b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
8817db96d56Sopenharmony_ci            (res.read(), res.getheader('Content-type'), res.status))
8827db96d56Sopenharmony_ci
8837db96d56Sopenharmony_ci    def test_no_leading_slash(self):
8847db96d56Sopenharmony_ci        # http://bugs.python.org/issue2254
8857db96d56Sopenharmony_ci        res = self.request('cgi-bin/file1.py')
8867db96d56Sopenharmony_ci        self.assertEqual(
8877db96d56Sopenharmony_ci            (b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
8887db96d56Sopenharmony_ci            (res.read(), res.getheader('Content-type'), res.status))
8897db96d56Sopenharmony_ci
8907db96d56Sopenharmony_ci    def test_os_environ_is_not_altered(self):
8917db96d56Sopenharmony_ci        signature = "Test CGI Server"
8927db96d56Sopenharmony_ci        os.environ['SERVER_SOFTWARE'] = signature
8937db96d56Sopenharmony_ci        res = self.request('/cgi-bin/file1.py')
8947db96d56Sopenharmony_ci        self.assertEqual(
8957db96d56Sopenharmony_ci            (b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
8967db96d56Sopenharmony_ci            (res.read(), res.getheader('Content-type'), res.status))
8977db96d56Sopenharmony_ci        self.assertEqual(os.environ['SERVER_SOFTWARE'], signature)
8987db96d56Sopenharmony_ci
8997db96d56Sopenharmony_ci    def test_urlquote_decoding_in_cgi_check(self):
9007db96d56Sopenharmony_ci        res = self.request('/cgi-bin%2ffile1.py')
9017db96d56Sopenharmony_ci        self.assertEqual(
9027db96d56Sopenharmony_ci            (b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
9037db96d56Sopenharmony_ci            (res.read(), res.getheader('Content-type'), res.status))
9047db96d56Sopenharmony_ci
9057db96d56Sopenharmony_ci    def test_nested_cgi_path_issue21323(self):
9067db96d56Sopenharmony_ci        res = self.request('/cgi-bin/child-dir/file3.py')
9077db96d56Sopenharmony_ci        self.assertEqual(
9087db96d56Sopenharmony_ci            (b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
9097db96d56Sopenharmony_ci            (res.read(), res.getheader('Content-type'), res.status))
9107db96d56Sopenharmony_ci
9117db96d56Sopenharmony_ci    def test_query_with_multiple_question_mark(self):
9127db96d56Sopenharmony_ci        res = self.request('/cgi-bin/file4.py?a=b?c=d')
9137db96d56Sopenharmony_ci        self.assertEqual(
9147db96d56Sopenharmony_ci            (b'a=b?c=d' + self.linesep, 'text/html', HTTPStatus.OK),
9157db96d56Sopenharmony_ci            (res.read(), res.getheader('Content-type'), res.status))
9167db96d56Sopenharmony_ci
9177db96d56Sopenharmony_ci    def test_query_with_continuous_slashes(self):
9187db96d56Sopenharmony_ci        res = self.request('/cgi-bin/file4.py?k=aa%2F%2Fbb&//q//p//=//a//b//')
9197db96d56Sopenharmony_ci        self.assertEqual(
9207db96d56Sopenharmony_ci            (b'k=aa%2F%2Fbb&//q//p//=//a//b//' + self.linesep,
9217db96d56Sopenharmony_ci             'text/html', HTTPStatus.OK),
9227db96d56Sopenharmony_ci            (res.read(), res.getheader('Content-type'), res.status))
9237db96d56Sopenharmony_ci
9247db96d56Sopenharmony_ci    def test_cgi_path_in_sub_directories(self):
9257db96d56Sopenharmony_ci        try:
9267db96d56Sopenharmony_ci            CGIHTTPRequestHandler.cgi_directories.append('/sub/dir/cgi-bin')
9277db96d56Sopenharmony_ci            res = self.request('/sub/dir/cgi-bin/file5.py')
9287db96d56Sopenharmony_ci            self.assertEqual(
9297db96d56Sopenharmony_ci                (b'Hello World' + self.linesep, 'text/html', HTTPStatus.OK),
9307db96d56Sopenharmony_ci                (res.read(), res.getheader('Content-type'), res.status))
9317db96d56Sopenharmony_ci        finally:
9327db96d56Sopenharmony_ci            CGIHTTPRequestHandler.cgi_directories.remove('/sub/dir/cgi-bin')
9337db96d56Sopenharmony_ci
9347db96d56Sopenharmony_ci    def test_accept(self):
9357db96d56Sopenharmony_ci        browser_accept = \
9367db96d56Sopenharmony_ci                    'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
9377db96d56Sopenharmony_ci        tests = (
9387db96d56Sopenharmony_ci            ((('Accept', browser_accept),), browser_accept),
9397db96d56Sopenharmony_ci            ((), ''),
9407db96d56Sopenharmony_ci            # Hack case to get two values for the one header
9417db96d56Sopenharmony_ci            ((('Accept', 'text/html'), ('ACCEPT', 'text/plain')),
9427db96d56Sopenharmony_ci               'text/html,text/plain'),
9437db96d56Sopenharmony_ci        )
9447db96d56Sopenharmony_ci        for headers, expected in tests:
9457db96d56Sopenharmony_ci            headers = OrderedDict(headers)
9467db96d56Sopenharmony_ci            with self.subTest(headers):
9477db96d56Sopenharmony_ci                res = self.request('/cgi-bin/file6.py', 'GET', headers=headers)
9487db96d56Sopenharmony_ci                self.assertEqual(http.HTTPStatus.OK, res.status)
9497db96d56Sopenharmony_ci                expected = f"HTTP_ACCEPT={expected}".encode('ascii')
9507db96d56Sopenharmony_ci                self.assertIn(expected, res.read())
9517db96d56Sopenharmony_ci
9527db96d56Sopenharmony_ci
9537db96d56Sopenharmony_ciclass SocketlessRequestHandler(SimpleHTTPRequestHandler):
9547db96d56Sopenharmony_ci    def __init__(self, directory=None):
9557db96d56Sopenharmony_ci        request = mock.Mock()
9567db96d56Sopenharmony_ci        request.makefile.return_value = BytesIO()
9577db96d56Sopenharmony_ci        super().__init__(request, None, None, directory=directory)
9587db96d56Sopenharmony_ci
9597db96d56Sopenharmony_ci        self.get_called = False
9607db96d56Sopenharmony_ci        self.protocol_version = "HTTP/1.1"
9617db96d56Sopenharmony_ci
9627db96d56Sopenharmony_ci    def do_GET(self):
9637db96d56Sopenharmony_ci        self.get_called = True
9647db96d56Sopenharmony_ci        self.send_response(HTTPStatus.OK)
9657db96d56Sopenharmony_ci        self.send_header('Content-Type', 'text/html')
9667db96d56Sopenharmony_ci        self.end_headers()
9677db96d56Sopenharmony_ci        self.wfile.write(b'<html><body>Data</body></html>\r\n')
9687db96d56Sopenharmony_ci
9697db96d56Sopenharmony_ci    def log_message(self, format, *args):
9707db96d56Sopenharmony_ci        pass
9717db96d56Sopenharmony_ci
9727db96d56Sopenharmony_ciclass RejectingSocketlessRequestHandler(SocketlessRequestHandler):
9737db96d56Sopenharmony_ci    def handle_expect_100(self):
9747db96d56Sopenharmony_ci        self.send_error(HTTPStatus.EXPECTATION_FAILED)
9757db96d56Sopenharmony_ci        return False
9767db96d56Sopenharmony_ci
9777db96d56Sopenharmony_ci
9787db96d56Sopenharmony_ciclass AuditableBytesIO:
9797db96d56Sopenharmony_ci
9807db96d56Sopenharmony_ci    def __init__(self):
9817db96d56Sopenharmony_ci        self.datas = []
9827db96d56Sopenharmony_ci
9837db96d56Sopenharmony_ci    def write(self, data):
9847db96d56Sopenharmony_ci        self.datas.append(data)
9857db96d56Sopenharmony_ci
9867db96d56Sopenharmony_ci    def getData(self):
9877db96d56Sopenharmony_ci        return b''.join(self.datas)
9887db96d56Sopenharmony_ci
9897db96d56Sopenharmony_ci    @property
9907db96d56Sopenharmony_ci    def numWrites(self):
9917db96d56Sopenharmony_ci        return len(self.datas)
9927db96d56Sopenharmony_ci
9937db96d56Sopenharmony_ci
9947db96d56Sopenharmony_ciclass BaseHTTPRequestHandlerTestCase(unittest.TestCase):
9957db96d56Sopenharmony_ci    """Test the functionality of the BaseHTTPServer.
9967db96d56Sopenharmony_ci
9977db96d56Sopenharmony_ci       Test the support for the Expect 100-continue header.
9987db96d56Sopenharmony_ci       """
9997db96d56Sopenharmony_ci
10007db96d56Sopenharmony_ci    HTTPResponseMatch = re.compile(b'HTTP/1.[0-9]+ 200 OK')
10017db96d56Sopenharmony_ci
10027db96d56Sopenharmony_ci    def setUp (self):
10037db96d56Sopenharmony_ci        self.handler = SocketlessRequestHandler()
10047db96d56Sopenharmony_ci
10057db96d56Sopenharmony_ci    def send_typical_request(self, message):
10067db96d56Sopenharmony_ci        input = BytesIO(message)
10077db96d56Sopenharmony_ci        output = BytesIO()
10087db96d56Sopenharmony_ci        self.handler.rfile = input
10097db96d56Sopenharmony_ci        self.handler.wfile = output
10107db96d56Sopenharmony_ci        self.handler.handle_one_request()
10117db96d56Sopenharmony_ci        output.seek(0)
10127db96d56Sopenharmony_ci        return output.readlines()
10137db96d56Sopenharmony_ci
10147db96d56Sopenharmony_ci    def verify_get_called(self):
10157db96d56Sopenharmony_ci        self.assertTrue(self.handler.get_called)
10167db96d56Sopenharmony_ci
10177db96d56Sopenharmony_ci    def verify_expected_headers(self, headers):
10187db96d56Sopenharmony_ci        for fieldName in b'Server: ', b'Date: ', b'Content-Type: ':
10197db96d56Sopenharmony_ci            self.assertEqual(sum(h.startswith(fieldName) for h in headers), 1)
10207db96d56Sopenharmony_ci
10217db96d56Sopenharmony_ci    def verify_http_server_response(self, response):
10227db96d56Sopenharmony_ci        match = self.HTTPResponseMatch.search(response)
10237db96d56Sopenharmony_ci        self.assertIsNotNone(match)
10247db96d56Sopenharmony_ci
10257db96d56Sopenharmony_ci    def test_unprintable_not_logged(self):
10267db96d56Sopenharmony_ci        # We call the method from the class directly as our Socketless
10277db96d56Sopenharmony_ci        # Handler subclass overrode it... nice for everything BUT this test.
10287db96d56Sopenharmony_ci        self.handler.client_address = ('127.0.0.1', 1337)
10297db96d56Sopenharmony_ci        log_message = BaseHTTPRequestHandler.log_message
10307db96d56Sopenharmony_ci        with mock.patch.object(sys, 'stderr', StringIO()) as fake_stderr:
10317db96d56Sopenharmony_ci            log_message(self.handler, '/foo')
10327db96d56Sopenharmony_ci            log_message(self.handler, '/\033bar\000\033')
10337db96d56Sopenharmony_ci            log_message(self.handler, '/spam %s.', 'a')
10347db96d56Sopenharmony_ci            log_message(self.handler, '/spam %s.', '\033\x7f\x9f\xa0beans')
10357db96d56Sopenharmony_ci            log_message(self.handler, '"GET /foo\\b"ar\007 HTTP/1.0"')
10367db96d56Sopenharmony_ci        stderr = fake_stderr.getvalue()
10377db96d56Sopenharmony_ci        self.assertNotIn('\033', stderr)  # non-printable chars are caught.
10387db96d56Sopenharmony_ci        self.assertNotIn('\000', stderr)  # non-printable chars are caught.
10397db96d56Sopenharmony_ci        lines = stderr.splitlines()
10407db96d56Sopenharmony_ci        self.assertIn('/foo', lines[0])
10417db96d56Sopenharmony_ci        self.assertIn(r'/\x1bbar\x00\x1b', lines[1])
10427db96d56Sopenharmony_ci        self.assertIn('/spam a.', lines[2])
10437db96d56Sopenharmony_ci        self.assertIn('/spam \\x1b\\x7f\\x9f\xa0beans.', lines[3])
10447db96d56Sopenharmony_ci        self.assertIn(r'"GET /foo\\b"ar\x07 HTTP/1.0"', lines[4])
10457db96d56Sopenharmony_ci
10467db96d56Sopenharmony_ci    def test_http_1_1(self):
10477db96d56Sopenharmony_ci        result = self.send_typical_request(b'GET / HTTP/1.1\r\n\r\n')
10487db96d56Sopenharmony_ci        self.verify_http_server_response(result[0])
10497db96d56Sopenharmony_ci        self.verify_expected_headers(result[1:-1])
10507db96d56Sopenharmony_ci        self.verify_get_called()
10517db96d56Sopenharmony_ci        self.assertEqual(result[-1], b'<html><body>Data</body></html>\r\n')
10527db96d56Sopenharmony_ci        self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1')
10537db96d56Sopenharmony_ci        self.assertEqual(self.handler.command, 'GET')
10547db96d56Sopenharmony_ci        self.assertEqual(self.handler.path, '/')
10557db96d56Sopenharmony_ci        self.assertEqual(self.handler.request_version, 'HTTP/1.1')
10567db96d56Sopenharmony_ci        self.assertSequenceEqual(self.handler.headers.items(), ())
10577db96d56Sopenharmony_ci
10587db96d56Sopenharmony_ci    def test_http_1_0(self):
10597db96d56Sopenharmony_ci        result = self.send_typical_request(b'GET / HTTP/1.0\r\n\r\n')
10607db96d56Sopenharmony_ci        self.verify_http_server_response(result[0])
10617db96d56Sopenharmony_ci        self.verify_expected_headers(result[1:-1])
10627db96d56Sopenharmony_ci        self.verify_get_called()
10637db96d56Sopenharmony_ci        self.assertEqual(result[-1], b'<html><body>Data</body></html>\r\n')
10647db96d56Sopenharmony_ci        self.assertEqual(self.handler.requestline, 'GET / HTTP/1.0')
10657db96d56Sopenharmony_ci        self.assertEqual(self.handler.command, 'GET')
10667db96d56Sopenharmony_ci        self.assertEqual(self.handler.path, '/')
10677db96d56Sopenharmony_ci        self.assertEqual(self.handler.request_version, 'HTTP/1.0')
10687db96d56Sopenharmony_ci        self.assertSequenceEqual(self.handler.headers.items(), ())
10697db96d56Sopenharmony_ci
10707db96d56Sopenharmony_ci    def test_http_0_9(self):
10717db96d56Sopenharmony_ci        result = self.send_typical_request(b'GET / HTTP/0.9\r\n\r\n')
10727db96d56Sopenharmony_ci        self.assertEqual(len(result), 1)
10737db96d56Sopenharmony_ci        self.assertEqual(result[0], b'<html><body>Data</body></html>\r\n')
10747db96d56Sopenharmony_ci        self.verify_get_called()
10757db96d56Sopenharmony_ci
10767db96d56Sopenharmony_ci    def test_extra_space(self):
10777db96d56Sopenharmony_ci        result = self.send_typical_request(
10787db96d56Sopenharmony_ci            b'GET /spaced out HTTP/1.1\r\n'
10797db96d56Sopenharmony_ci            b'Host: dummy\r\n'
10807db96d56Sopenharmony_ci            b'\r\n'
10817db96d56Sopenharmony_ci        )
10827db96d56Sopenharmony_ci        self.assertTrue(result[0].startswith(b'HTTP/1.1 400 '))
10837db96d56Sopenharmony_ci        self.verify_expected_headers(result[1:result.index(b'\r\n')])
10847db96d56Sopenharmony_ci        self.assertFalse(self.handler.get_called)
10857db96d56Sopenharmony_ci
10867db96d56Sopenharmony_ci    def test_with_continue_1_0(self):
10877db96d56Sopenharmony_ci        result = self.send_typical_request(b'GET / HTTP/1.0\r\nExpect: 100-continue\r\n\r\n')
10887db96d56Sopenharmony_ci        self.verify_http_server_response(result[0])
10897db96d56Sopenharmony_ci        self.verify_expected_headers(result[1:-1])
10907db96d56Sopenharmony_ci        self.verify_get_called()
10917db96d56Sopenharmony_ci        self.assertEqual(result[-1], b'<html><body>Data</body></html>\r\n')
10927db96d56Sopenharmony_ci        self.assertEqual(self.handler.requestline, 'GET / HTTP/1.0')
10937db96d56Sopenharmony_ci        self.assertEqual(self.handler.command, 'GET')
10947db96d56Sopenharmony_ci        self.assertEqual(self.handler.path, '/')
10957db96d56Sopenharmony_ci        self.assertEqual(self.handler.request_version, 'HTTP/1.0')
10967db96d56Sopenharmony_ci        headers = (("Expect", "100-continue"),)
10977db96d56Sopenharmony_ci        self.assertSequenceEqual(self.handler.headers.items(), headers)
10987db96d56Sopenharmony_ci
10997db96d56Sopenharmony_ci    def test_with_continue_1_1(self):
11007db96d56Sopenharmony_ci        result = self.send_typical_request(b'GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n')
11017db96d56Sopenharmony_ci        self.assertEqual(result[0], b'HTTP/1.1 100 Continue\r\n')
11027db96d56Sopenharmony_ci        self.assertEqual(result[1], b'\r\n')
11037db96d56Sopenharmony_ci        self.assertEqual(result[2], b'HTTP/1.1 200 OK\r\n')
11047db96d56Sopenharmony_ci        self.verify_expected_headers(result[2:-1])
11057db96d56Sopenharmony_ci        self.verify_get_called()
11067db96d56Sopenharmony_ci        self.assertEqual(result[-1], b'<html><body>Data</body></html>\r\n')
11077db96d56Sopenharmony_ci        self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1')
11087db96d56Sopenharmony_ci        self.assertEqual(self.handler.command, 'GET')
11097db96d56Sopenharmony_ci        self.assertEqual(self.handler.path, '/')
11107db96d56Sopenharmony_ci        self.assertEqual(self.handler.request_version, 'HTTP/1.1')
11117db96d56Sopenharmony_ci        headers = (("Expect", "100-continue"),)
11127db96d56Sopenharmony_ci        self.assertSequenceEqual(self.handler.headers.items(), headers)
11137db96d56Sopenharmony_ci
11147db96d56Sopenharmony_ci    def test_header_buffering_of_send_error(self):
11157db96d56Sopenharmony_ci
11167db96d56Sopenharmony_ci        input = BytesIO(b'GET / HTTP/1.1\r\n\r\n')
11177db96d56Sopenharmony_ci        output = AuditableBytesIO()
11187db96d56Sopenharmony_ci        handler = SocketlessRequestHandler()
11197db96d56Sopenharmony_ci        handler.rfile = input
11207db96d56Sopenharmony_ci        handler.wfile = output
11217db96d56Sopenharmony_ci        handler.request_version = 'HTTP/1.1'
11227db96d56Sopenharmony_ci        handler.requestline = ''
11237db96d56Sopenharmony_ci        handler.command = None
11247db96d56Sopenharmony_ci
11257db96d56Sopenharmony_ci        handler.send_error(418)
11267db96d56Sopenharmony_ci        self.assertEqual(output.numWrites, 2)
11277db96d56Sopenharmony_ci
11287db96d56Sopenharmony_ci    def test_header_buffering_of_send_response_only(self):
11297db96d56Sopenharmony_ci
11307db96d56Sopenharmony_ci        input = BytesIO(b'GET / HTTP/1.1\r\n\r\n')
11317db96d56Sopenharmony_ci        output = AuditableBytesIO()
11327db96d56Sopenharmony_ci        handler = SocketlessRequestHandler()
11337db96d56Sopenharmony_ci        handler.rfile = input
11347db96d56Sopenharmony_ci        handler.wfile = output
11357db96d56Sopenharmony_ci        handler.request_version = 'HTTP/1.1'
11367db96d56Sopenharmony_ci
11377db96d56Sopenharmony_ci        handler.send_response_only(418)
11387db96d56Sopenharmony_ci        self.assertEqual(output.numWrites, 0)
11397db96d56Sopenharmony_ci        handler.end_headers()
11407db96d56Sopenharmony_ci        self.assertEqual(output.numWrites, 1)
11417db96d56Sopenharmony_ci
11427db96d56Sopenharmony_ci    def test_header_buffering_of_send_header(self):
11437db96d56Sopenharmony_ci
11447db96d56Sopenharmony_ci        input = BytesIO(b'GET / HTTP/1.1\r\n\r\n')
11457db96d56Sopenharmony_ci        output = AuditableBytesIO()
11467db96d56Sopenharmony_ci        handler = SocketlessRequestHandler()
11477db96d56Sopenharmony_ci        handler.rfile = input
11487db96d56Sopenharmony_ci        handler.wfile = output
11497db96d56Sopenharmony_ci        handler.request_version = 'HTTP/1.1'
11507db96d56Sopenharmony_ci
11517db96d56Sopenharmony_ci        handler.send_header('Foo', 'foo')
11527db96d56Sopenharmony_ci        handler.send_header('bar', 'bar')
11537db96d56Sopenharmony_ci        self.assertEqual(output.numWrites, 0)
11547db96d56Sopenharmony_ci        handler.end_headers()
11557db96d56Sopenharmony_ci        self.assertEqual(output.getData(), b'Foo: foo\r\nbar: bar\r\n\r\n')
11567db96d56Sopenharmony_ci        self.assertEqual(output.numWrites, 1)
11577db96d56Sopenharmony_ci
11587db96d56Sopenharmony_ci    def test_header_unbuffered_when_continue(self):
11597db96d56Sopenharmony_ci
11607db96d56Sopenharmony_ci        def _readAndReseek(f):
11617db96d56Sopenharmony_ci            pos = f.tell()
11627db96d56Sopenharmony_ci            f.seek(0)
11637db96d56Sopenharmony_ci            data = f.read()
11647db96d56Sopenharmony_ci            f.seek(pos)
11657db96d56Sopenharmony_ci            return data
11667db96d56Sopenharmony_ci
11677db96d56Sopenharmony_ci        input = BytesIO(b'GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n')
11687db96d56Sopenharmony_ci        output = BytesIO()
11697db96d56Sopenharmony_ci        self.handler.rfile = input
11707db96d56Sopenharmony_ci        self.handler.wfile = output
11717db96d56Sopenharmony_ci        self.handler.request_version = 'HTTP/1.1'
11727db96d56Sopenharmony_ci
11737db96d56Sopenharmony_ci        self.handler.handle_one_request()
11747db96d56Sopenharmony_ci        self.assertNotEqual(_readAndReseek(output), b'')
11757db96d56Sopenharmony_ci        result = _readAndReseek(output).split(b'\r\n')
11767db96d56Sopenharmony_ci        self.assertEqual(result[0], b'HTTP/1.1 100 Continue')
11777db96d56Sopenharmony_ci        self.assertEqual(result[1], b'')
11787db96d56Sopenharmony_ci        self.assertEqual(result[2], b'HTTP/1.1 200 OK')
11797db96d56Sopenharmony_ci
11807db96d56Sopenharmony_ci    def test_with_continue_rejected(self):
11817db96d56Sopenharmony_ci        usual_handler = self.handler        # Save to avoid breaking any subsequent tests.
11827db96d56Sopenharmony_ci        self.handler = RejectingSocketlessRequestHandler()
11837db96d56Sopenharmony_ci        result = self.send_typical_request(b'GET / HTTP/1.1\r\nExpect: 100-continue\r\n\r\n')
11847db96d56Sopenharmony_ci        self.assertEqual(result[0], b'HTTP/1.1 417 Expectation Failed\r\n')
11857db96d56Sopenharmony_ci        self.verify_expected_headers(result[1:-1])
11867db96d56Sopenharmony_ci        # The expect handler should short circuit the usual get method by
11877db96d56Sopenharmony_ci        # returning false here, so get_called should be false
11887db96d56Sopenharmony_ci        self.assertFalse(self.handler.get_called)
11897db96d56Sopenharmony_ci        self.assertEqual(sum(r == b'Connection: close\r\n' for r in result[1:-1]), 1)
11907db96d56Sopenharmony_ci        self.handler = usual_handler        # Restore to avoid breaking any subsequent tests.
11917db96d56Sopenharmony_ci
11927db96d56Sopenharmony_ci    def test_request_length(self):
11937db96d56Sopenharmony_ci        # Issue #10714: huge request lines are discarded, to avoid Denial
11947db96d56Sopenharmony_ci        # of Service attacks.
11957db96d56Sopenharmony_ci        result = self.send_typical_request(b'GET ' + b'x' * 65537)
11967db96d56Sopenharmony_ci        self.assertEqual(result[0], b'HTTP/1.1 414 Request-URI Too Long\r\n')
11977db96d56Sopenharmony_ci        self.assertFalse(self.handler.get_called)
11987db96d56Sopenharmony_ci        self.assertIsInstance(self.handler.requestline, str)
11997db96d56Sopenharmony_ci
12007db96d56Sopenharmony_ci    def test_header_length(self):
12017db96d56Sopenharmony_ci        # Issue #6791: same for headers
12027db96d56Sopenharmony_ci        result = self.send_typical_request(
12037db96d56Sopenharmony_ci            b'GET / HTTP/1.1\r\nX-Foo: bar' + b'r' * 65537 + b'\r\n\r\n')
12047db96d56Sopenharmony_ci        self.assertEqual(result[0], b'HTTP/1.1 431 Line too long\r\n')
12057db96d56Sopenharmony_ci        self.assertFalse(self.handler.get_called)
12067db96d56Sopenharmony_ci        self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1')
12077db96d56Sopenharmony_ci
12087db96d56Sopenharmony_ci    def test_too_many_headers(self):
12097db96d56Sopenharmony_ci        result = self.send_typical_request(
12107db96d56Sopenharmony_ci            b'GET / HTTP/1.1\r\n' + b'X-Foo: bar\r\n' * 101 + b'\r\n')
12117db96d56Sopenharmony_ci        self.assertEqual(result[0], b'HTTP/1.1 431 Too many headers\r\n')
12127db96d56Sopenharmony_ci        self.assertFalse(self.handler.get_called)
12137db96d56Sopenharmony_ci        self.assertEqual(self.handler.requestline, 'GET / HTTP/1.1')
12147db96d56Sopenharmony_ci
12157db96d56Sopenharmony_ci    def test_html_escape_on_error(self):
12167db96d56Sopenharmony_ci        result = self.send_typical_request(
12177db96d56Sopenharmony_ci            b'<script>alert("hello")</script> / HTTP/1.1')
12187db96d56Sopenharmony_ci        result = b''.join(result)
12197db96d56Sopenharmony_ci        text = '<script>alert("hello")</script>'
12207db96d56Sopenharmony_ci        self.assertIn(html.escape(text, quote=False).encode('ascii'), result)
12217db96d56Sopenharmony_ci
12227db96d56Sopenharmony_ci    def test_close_connection(self):
12237db96d56Sopenharmony_ci        # handle_one_request() should be repeatedly called until
12247db96d56Sopenharmony_ci        # it sets close_connection
12257db96d56Sopenharmony_ci        def handle_one_request():
12267db96d56Sopenharmony_ci            self.handler.close_connection = next(close_values)
12277db96d56Sopenharmony_ci        self.handler.handle_one_request = handle_one_request
12287db96d56Sopenharmony_ci
12297db96d56Sopenharmony_ci        close_values = iter((True,))
12307db96d56Sopenharmony_ci        self.handler.handle()
12317db96d56Sopenharmony_ci        self.assertRaises(StopIteration, next, close_values)
12327db96d56Sopenharmony_ci
12337db96d56Sopenharmony_ci        close_values = iter((False, False, True))
12347db96d56Sopenharmony_ci        self.handler.handle()
12357db96d56Sopenharmony_ci        self.assertRaises(StopIteration, next, close_values)
12367db96d56Sopenharmony_ci
12377db96d56Sopenharmony_ci    def test_date_time_string(self):
12387db96d56Sopenharmony_ci        now = time.time()
12397db96d56Sopenharmony_ci        # this is the old code that formats the timestamp
12407db96d56Sopenharmony_ci        year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now)
12417db96d56Sopenharmony_ci        expected = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
12427db96d56Sopenharmony_ci            self.handler.weekdayname[wd],
12437db96d56Sopenharmony_ci            day,
12447db96d56Sopenharmony_ci            self.handler.monthname[month],
12457db96d56Sopenharmony_ci            year, hh, mm, ss
12467db96d56Sopenharmony_ci        )
12477db96d56Sopenharmony_ci        self.assertEqual(self.handler.date_time_string(timestamp=now), expected)
12487db96d56Sopenharmony_ci
12497db96d56Sopenharmony_ci
12507db96d56Sopenharmony_ciclass SimpleHTTPRequestHandlerTestCase(unittest.TestCase):
12517db96d56Sopenharmony_ci    """ Test url parsing """
12527db96d56Sopenharmony_ci    def setUp(self):
12537db96d56Sopenharmony_ci        self.translated_1 = os.path.join(os.getcwd(), 'filename')
12547db96d56Sopenharmony_ci        self.translated_2 = os.path.join('foo', 'filename')
12557db96d56Sopenharmony_ci        self.translated_3 = os.path.join('bar', 'filename')
12567db96d56Sopenharmony_ci        self.handler_1 = SocketlessRequestHandler()
12577db96d56Sopenharmony_ci        self.handler_2 = SocketlessRequestHandler(directory='foo')
12587db96d56Sopenharmony_ci        self.handler_3 = SocketlessRequestHandler(directory=pathlib.PurePath('bar'))
12597db96d56Sopenharmony_ci
12607db96d56Sopenharmony_ci    def test_query_arguments(self):
12617db96d56Sopenharmony_ci        path = self.handler_1.translate_path('/filename')
12627db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_1)
12637db96d56Sopenharmony_ci        path = self.handler_2.translate_path('/filename')
12647db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_2)
12657db96d56Sopenharmony_ci        path = self.handler_3.translate_path('/filename')
12667db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_3)
12677db96d56Sopenharmony_ci
12687db96d56Sopenharmony_ci        path = self.handler_1.translate_path('/filename?foo=bar')
12697db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_1)
12707db96d56Sopenharmony_ci        path = self.handler_2.translate_path('/filename?foo=bar')
12717db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_2)
12727db96d56Sopenharmony_ci        path = self.handler_3.translate_path('/filename?foo=bar')
12737db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_3)
12747db96d56Sopenharmony_ci
12757db96d56Sopenharmony_ci        path = self.handler_1.translate_path('/filename?a=b&spam=eggs#zot')
12767db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_1)
12777db96d56Sopenharmony_ci        path = self.handler_2.translate_path('/filename?a=b&spam=eggs#zot')
12787db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_2)
12797db96d56Sopenharmony_ci        path = self.handler_3.translate_path('/filename?a=b&spam=eggs#zot')
12807db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_3)
12817db96d56Sopenharmony_ci
12827db96d56Sopenharmony_ci    def test_start_with_double_slash(self):
12837db96d56Sopenharmony_ci        path = self.handler_1.translate_path('//filename')
12847db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_1)
12857db96d56Sopenharmony_ci        path = self.handler_2.translate_path('//filename')
12867db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_2)
12877db96d56Sopenharmony_ci        path = self.handler_3.translate_path('//filename')
12887db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_3)
12897db96d56Sopenharmony_ci
12907db96d56Sopenharmony_ci        path = self.handler_1.translate_path('//filename?foo=bar')
12917db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_1)
12927db96d56Sopenharmony_ci        path = self.handler_2.translate_path('//filename?foo=bar')
12937db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_2)
12947db96d56Sopenharmony_ci        path = self.handler_3.translate_path('//filename?foo=bar')
12957db96d56Sopenharmony_ci        self.assertEqual(path, self.translated_3)
12967db96d56Sopenharmony_ci
12977db96d56Sopenharmony_ci    def test_windows_colon(self):
12987db96d56Sopenharmony_ci        with support.swap_attr(server.os, 'path', ntpath):
12997db96d56Sopenharmony_ci            path = self.handler_1.translate_path('c:c:c:foo/filename')
13007db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13017db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_1)
13027db96d56Sopenharmony_ci            path = self.handler_2.translate_path('c:c:c:foo/filename')
13037db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13047db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_2)
13057db96d56Sopenharmony_ci            path = self.handler_3.translate_path('c:c:c:foo/filename')
13067db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13077db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_3)
13087db96d56Sopenharmony_ci
13097db96d56Sopenharmony_ci            path = self.handler_1.translate_path('\\c:../filename')
13107db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13117db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_1)
13127db96d56Sopenharmony_ci            path = self.handler_2.translate_path('\\c:../filename')
13137db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13147db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_2)
13157db96d56Sopenharmony_ci            path = self.handler_3.translate_path('\\c:../filename')
13167db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13177db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_3)
13187db96d56Sopenharmony_ci
13197db96d56Sopenharmony_ci            path = self.handler_1.translate_path('c:\\c:..\\foo/filename')
13207db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13217db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_1)
13227db96d56Sopenharmony_ci            path = self.handler_2.translate_path('c:\\c:..\\foo/filename')
13237db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13247db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_2)
13257db96d56Sopenharmony_ci            path = self.handler_3.translate_path('c:\\c:..\\foo/filename')
13267db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13277db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_3)
13287db96d56Sopenharmony_ci
13297db96d56Sopenharmony_ci            path = self.handler_1.translate_path('c:c:foo\\c:c:bar/filename')
13307db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13317db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_1)
13327db96d56Sopenharmony_ci            path = self.handler_2.translate_path('c:c:foo\\c:c:bar/filename')
13337db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13347db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_2)
13357db96d56Sopenharmony_ci            path = self.handler_3.translate_path('c:c:foo\\c:c:bar/filename')
13367db96d56Sopenharmony_ci            path = path.replace(ntpath.sep, os.sep)
13377db96d56Sopenharmony_ci            self.assertEqual(path, self.translated_3)
13387db96d56Sopenharmony_ci
13397db96d56Sopenharmony_ci
13407db96d56Sopenharmony_ciclass MiscTestCase(unittest.TestCase):
13417db96d56Sopenharmony_ci    def test_all(self):
13427db96d56Sopenharmony_ci        expected = []
13437db96d56Sopenharmony_ci        denylist = {'executable', 'nobody_uid', 'test'}
13447db96d56Sopenharmony_ci        for name in dir(server):
13457db96d56Sopenharmony_ci            if name.startswith('_') or name in denylist:
13467db96d56Sopenharmony_ci                continue
13477db96d56Sopenharmony_ci            module_object = getattr(server, name)
13487db96d56Sopenharmony_ci            if getattr(module_object, '__module__', None) == 'http.server':
13497db96d56Sopenharmony_ci                expected.append(name)
13507db96d56Sopenharmony_ci        self.assertCountEqual(server.__all__, expected)
13517db96d56Sopenharmony_ci
13527db96d56Sopenharmony_ci
13537db96d56Sopenharmony_ciclass ScriptTestCase(unittest.TestCase):
13547db96d56Sopenharmony_ci
13557db96d56Sopenharmony_ci    def mock_server_class(self):
13567db96d56Sopenharmony_ci        return mock.MagicMock(
13577db96d56Sopenharmony_ci            return_value=mock.MagicMock(
13587db96d56Sopenharmony_ci                __enter__=mock.MagicMock(
13597db96d56Sopenharmony_ci                    return_value=mock.MagicMock(
13607db96d56Sopenharmony_ci                        socket=mock.MagicMock(
13617db96d56Sopenharmony_ci                            getsockname=lambda: ('', 0),
13627db96d56Sopenharmony_ci                        ),
13637db96d56Sopenharmony_ci                    ),
13647db96d56Sopenharmony_ci                ),
13657db96d56Sopenharmony_ci            ),
13667db96d56Sopenharmony_ci        )
13677db96d56Sopenharmony_ci
13687db96d56Sopenharmony_ci    @mock.patch('builtins.print')
13697db96d56Sopenharmony_ci    def test_server_test_unspec(self, _):
13707db96d56Sopenharmony_ci        mock_server = self.mock_server_class()
13717db96d56Sopenharmony_ci        server.test(ServerClass=mock_server, bind=None)
13727db96d56Sopenharmony_ci        self.assertIn(
13737db96d56Sopenharmony_ci            mock_server.address_family,
13747db96d56Sopenharmony_ci            (socket.AF_INET6, socket.AF_INET),
13757db96d56Sopenharmony_ci        )
13767db96d56Sopenharmony_ci
13777db96d56Sopenharmony_ci    @mock.patch('builtins.print')
13787db96d56Sopenharmony_ci    def test_server_test_localhost(self, _):
13797db96d56Sopenharmony_ci        mock_server = self.mock_server_class()
13807db96d56Sopenharmony_ci        server.test(ServerClass=mock_server, bind="localhost")
13817db96d56Sopenharmony_ci        self.assertIn(
13827db96d56Sopenharmony_ci            mock_server.address_family,
13837db96d56Sopenharmony_ci            (socket.AF_INET6, socket.AF_INET),
13847db96d56Sopenharmony_ci        )
13857db96d56Sopenharmony_ci
13867db96d56Sopenharmony_ci    ipv6_addrs = (
13877db96d56Sopenharmony_ci        "::",
13887db96d56Sopenharmony_ci        "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
13897db96d56Sopenharmony_ci        "::1",
13907db96d56Sopenharmony_ci    )
13917db96d56Sopenharmony_ci
13927db96d56Sopenharmony_ci    ipv4_addrs = (
13937db96d56Sopenharmony_ci        "0.0.0.0",
13947db96d56Sopenharmony_ci        "8.8.8.8",
13957db96d56Sopenharmony_ci        "127.0.0.1",
13967db96d56Sopenharmony_ci    )
13977db96d56Sopenharmony_ci
13987db96d56Sopenharmony_ci    @mock.patch('builtins.print')
13997db96d56Sopenharmony_ci    def test_server_test_ipv6(self, _):
14007db96d56Sopenharmony_ci        for bind in self.ipv6_addrs:
14017db96d56Sopenharmony_ci            mock_server = self.mock_server_class()
14027db96d56Sopenharmony_ci            server.test(ServerClass=mock_server, bind=bind)
14037db96d56Sopenharmony_ci            self.assertEqual(mock_server.address_family, socket.AF_INET6)
14047db96d56Sopenharmony_ci
14057db96d56Sopenharmony_ci    @mock.patch('builtins.print')
14067db96d56Sopenharmony_ci    def test_server_test_ipv4(self, _):
14077db96d56Sopenharmony_ci        for bind in self.ipv4_addrs:
14087db96d56Sopenharmony_ci            mock_server = self.mock_server_class()
14097db96d56Sopenharmony_ci            server.test(ServerClass=mock_server, bind=bind)
14107db96d56Sopenharmony_ci            self.assertEqual(mock_server.address_family, socket.AF_INET)
14117db96d56Sopenharmony_ci
14127db96d56Sopenharmony_ci
14137db96d56Sopenharmony_cidef setUpModule():
14147db96d56Sopenharmony_ci    unittest.addModuleCleanup(os.chdir, os.getcwd())
14157db96d56Sopenharmony_ci
14167db96d56Sopenharmony_ci
14177db96d56Sopenharmony_ciif __name__ == '__main__':
14187db96d56Sopenharmony_ci    unittest.main()
1419