[3.14] gh-133889: Improve tests for SimpleHTTPRequestHandler (GH-134102) (GH-134121)

(cherry picked from commit fcaf009907)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
Miss Islington (bot) 2025-05-17 09:27:38 +02:00 committed by GitHub
parent f89323236f
commit 5cdad8c90c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -522,34 +522,111 @@ class SimpleHTTPServerTestCase(BaseTestCase):
reader.close()
return body
def check_list_dir_dirname(self, dirname, quotedname=None):
fullpath = os.path.join(self.tempdir, dirname)
try:
os.mkdir(os.path.join(self.tempdir, dirname))
except (OSError, UnicodeEncodeError):
self.skipTest(f'Can not create directory {dirname!a} '
f'on current file system')
if quotedname is None:
quotedname = urllib.parse.quote(dirname, errors='surrogatepass')
response = self.request(self.base_url + '/' + quotedname + '/')
body = self.check_status_and_reason(response, HTTPStatus.OK)
displaypath = html.escape(f'{self.base_url}/{dirname}/', quote=False)
enc = sys.getfilesystemencoding()
prefix = f'listing for {displaypath}</'.encode(enc, 'surrogateescape')
self.assertIn(prefix + b'title>', body)
self.assertIn(prefix + b'h1>', body)
def check_list_dir_filename(self, filename):
fullpath = os.path.join(self.tempdir, filename)
content = ascii(fullpath).encode() + (os_helper.TESTFN_UNDECODABLE or b'\xff')
try:
with open(fullpath, 'wb') as f:
f.write(content)
except OSError:
self.skipTest(f'Can not create file {filename!a} '
f'on current file system')
response = self.request(self.base_url + '/')
body = self.check_status_and_reason(response, HTTPStatus.OK)
quotedname = urllib.parse.quote(filename, errors='surrogatepass')
enc = response.headers.get_content_charset()
self.assertIsNotNone(enc)
self.assertIn((f'href="{quotedname}"').encode('ascii'), body)
displayname = html.escape(filename, quote=False)
self.assertIn(f'>{displayname}<'.encode(enc, 'surrogateescape'), body)
response = self.request(self.base_url + '/' + quotedname)
self.check_status_and_reason(response, HTTPStatus.OK, data=content)
@unittest.skipUnless(os_helper.TESTFN_NONASCII,
'need os_helper.TESTFN_NONASCII')
def test_list_dir_nonascii_dirname(self):
dirname = os_helper.TESTFN_NONASCII + '.dir'
self.check_list_dir_dirname(dirname)
@unittest.skipUnless(os_helper.TESTFN_NONASCII,
'need os_helper.TESTFN_NONASCII')
def test_list_dir_nonascii_filename(self):
filename = os_helper.TESTFN_NONASCII + '.txt'
self.check_list_dir_filename(filename)
@unittest.skipIf(is_apple,
'undecodable name cannot always be decoded on Apple platforms')
@unittest.skipIf(sys.platform == 'win32',
'undecodable name cannot be decoded on win32')
@unittest.skipUnless(os_helper.TESTFN_UNDECODABLE,
'need os_helper.TESTFN_UNDECODABLE')
def test_undecodable_filename(self):
enc = sys.getfilesystemencoding()
def test_list_dir_undecodable_dirname(self):
dirname = os.fsdecode(os_helper.TESTFN_UNDECODABLE) + '.dir'
self.check_list_dir_dirname(dirname)
@unittest.skipIf(is_apple,
'undecodable name cannot always be decoded on Apple platforms')
@unittest.skipIf(sys.platform == 'win32',
'undecodable name cannot be decoded on win32')
@unittest.skipUnless(os_helper.TESTFN_UNDECODABLE,
'need os_helper.TESTFN_UNDECODABLE')
def test_list_dir_undecodable_filename(self):
filename = os.fsdecode(os_helper.TESTFN_UNDECODABLE) + '.txt'
with open(os.path.join(self.tempdir, filename), 'wb') as f:
f.write(os_helper.TESTFN_UNDECODABLE)
response = self.request(self.base_url + '/')
if is_apple:
# On Apple platforms the HFS+ filesystem replaces bytes that
# aren't valid UTF-8 into a percent-encoded value.
for name in os.listdir(self.tempdir):
if name != 'test': # Ignore a filename created in setUp().
filename = name
break
body = self.check_status_and_reason(response, HTTPStatus.OK)
quotedname = urllib.parse.quote(filename, errors='surrogatepass')
self.assertIn(('href="%s"' % quotedname)
.encode(enc, 'surrogateescape'), body)
self.assertIn(('>%s<' % html.escape(filename, quote=False))
.encode(enc, 'surrogateescape'), body)
response = self.request(self.base_url + '/' + quotedname)
self.check_status_and_reason(response, HTTPStatus.OK,
data=os_helper.TESTFN_UNDECODABLE)
self.check_list_dir_filename(filename)
def test_list_dir_undecodable_dirname2(self):
dirname = '\ufffd.dir'
self.check_list_dir_dirname(dirname, quotedname='%ff.dir')
@unittest.skipUnless(os_helper.TESTFN_UNENCODABLE,
'need os_helper.TESTFN_UNENCODABLE')
def test_list_dir_unencodable_dirname(self):
dirname = os_helper.TESTFN_UNENCODABLE + '.dir'
self.check_list_dir_dirname(dirname)
@unittest.skipUnless(os_helper.TESTFN_UNENCODABLE,
'need os_helper.TESTFN_UNENCODABLE')
def test_list_dir_unencodable_filename(self):
filename = os_helper.TESTFN_UNENCODABLE + '.txt'
self.check_list_dir_filename(filename)
def test_list_dir_escape_dirname(self):
# Characters that need special treating in URL or HTML.
for name in ('q?', 'f#', '&amp;', '&amp', '<i>', '"dq"', "'sq'",
'%A4', '%E2%82%AC'):
with self.subTest(name=name):
dirname = name + '.dir'
self.check_list_dir_dirname(dirname,
quotedname=urllib.parse.quote(dirname, safe='&<>\'"'))
def test_list_dir_escape_filename(self):
# Characters that need special treating in URL or HTML.
for name in ('q?', 'f#', '&amp;', '&amp', '<i>', '"dq"', "'sq'",
'%A4', '%E2%82%AC'):
with self.subTest(name=name):
filename = name + '.txt'
self.check_list_dir_filename(filename)
os_helper.unlink(os.path.join(self.tempdir, filename))
def test_undecodable_parameter(self):
# sanity check using a valid parameter
@ -731,27 +808,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
self.assertEqual(response.getheader("Location"),
self.tempdir_name + "/?hi=1")
def test_html_escape_filename(self):
filename = '<test&>.txt'
fullpath = os.path.join(self.tempdir, filename)
try:
open(fullpath, 'wb').close()
except OSError:
raise unittest.SkipTest('Can not create file %s on current file '
'system' % filename)
try:
response = self.request(self.base_url + '/')
body = self.check_status_and_reason(response, HTTPStatus.OK)
enc = response.headers.get_content_charset()
finally:
os.unlink(fullpath) # avoid affecting test_undecodable_filename
self.assertIsNotNone(enc)
html_text = '>%s<' % html.escape(filename, quote=False)
self.assertIn(html_text.encode(enc), body)
cgi_file1 = """\
#!%s