@@ -411,34 +411,111 @@ def close_conn():
411
411
reader .close ()
412
412
return body
413
413
414
+ def check_list_dir_dirname (self , dirname , quotedname = None ):
415
+ fullpath = os .path .join (self .tempdir , dirname )
416
+ try :
417
+ os .mkdir (os .path .join (self .tempdir , dirname ))
418
+ except (OSError , UnicodeEncodeError ):
419
+ self .skipTest (f'Can not create directory { dirname !a} '
420
+ f'on current file system' )
421
+
422
+ if quotedname is None :
423
+ quotedname = urllib .parse .quote (dirname , errors = 'surrogatepass' )
424
+ response = self .request (self .base_url + '/' + quotedname + '/' )
425
+ body = self .check_status_and_reason (response , HTTPStatus .OK )
426
+ displaypath = html .escape (f'{ self .base_url } /{ dirname } /' , quote = False )
427
+ enc = sys .getfilesystemencoding ()
428
+ prefix = f'listing for { displaypath } </' .encode (enc , 'surrogateescape' )
429
+ self .assertIn (prefix + b'title>' , body )
430
+ self .assertIn (prefix + b'h1>' , body )
431
+
432
+ def check_list_dir_filename (self , filename ):
433
+ fullpath = os .path .join (self .tempdir , filename )
434
+ content = ascii (fullpath ).encode () + (os_helper .TESTFN_UNDECODABLE or b'\xff ' )
435
+ try :
436
+ with open (fullpath , 'wb' ) as f :
437
+ f .write (content )
438
+ except OSError :
439
+ self .skipTest (f'Can not create file { filename !a} '
440
+ f'on current file system' )
441
+
442
+ response = self .request (self .base_url + '/' )
443
+ body = self .check_status_and_reason (response , HTTPStatus .OK )
444
+ quotedname = urllib .parse .quote (filename , errors = 'surrogatepass' )
445
+ enc = response .headers .get_content_charset ()
446
+ self .assertIsNotNone (enc )
447
+ self .assertIn ((f'href="{ quotedname } "' ).encode ('ascii' ), body )
448
+ displayname = html .escape (filename , quote = False )
449
+ self .assertIn (f'>{ displayname } <' .encode (enc , 'surrogateescape' ), body )
450
+
451
+ response = self .request (self .base_url + '/' + quotedname )
452
+ self .check_status_and_reason (response , HTTPStatus .OK , data = content )
453
+
454
+ @unittest .skipUnless (os_helper .TESTFN_NONASCII ,
455
+ 'need os_helper.TESTFN_NONASCII' )
456
+ def test_list_dir_nonascii_dirname (self ):
457
+ dirname = os_helper .TESTFN_NONASCII + '.dir'
458
+ self .check_list_dir_dirname (dirname )
459
+
460
+ @unittest .skipUnless (os_helper .TESTFN_NONASCII ,
461
+ 'need os_helper.TESTFN_NONASCII' )
462
+ def test_list_dir_nonascii_filename (self ):
463
+ filename = os_helper .TESTFN_NONASCII + '.txt'
464
+ self .check_list_dir_filename (filename )
465
+
414
466
@unittest .skipIf (is_apple ,
415
467
'undecodable name cannot always be decoded on Apple platforms' )
416
468
@unittest .skipIf (sys .platform == 'win32' ,
417
469
'undecodable name cannot be decoded on win32' )
418
470
@unittest .skipUnless (os_helper .TESTFN_UNDECODABLE ,
419
471
'need os_helper.TESTFN_UNDECODABLE' )
420
- def test_undecodable_filename (self ):
421
- enc = sys .getfilesystemencoding ()
472
+ def test_list_dir_undecodable_dirname (self ):
473
+ dirname = os .fsdecode (os_helper .TESTFN_UNDECODABLE ) + '.dir'
474
+ self .check_list_dir_dirname (dirname )
475
+
476
+ @unittest .skipIf (is_apple ,
477
+ 'undecodable name cannot always be decoded on Apple platforms' )
478
+ @unittest .skipIf (sys .platform == 'win32' ,
479
+ 'undecodable name cannot be decoded on win32' )
480
+ @unittest .skipUnless (os_helper .TESTFN_UNDECODABLE ,
481
+ 'need os_helper.TESTFN_UNDECODABLE' )
482
+ def test_list_dir_undecodable_filename (self ):
422
483
filename = os .fsdecode (os_helper .TESTFN_UNDECODABLE ) + '.txt'
423
- with open (os .path .join (self .tempdir , filename ), 'wb' ) as f :
424
- f .write (os_helper .TESTFN_UNDECODABLE )
425
- response = self .request (self .base_url + '/' )
426
- if is_apple :
427
- # On Apple platforms the HFS+ filesystem replaces bytes that
428
- # aren't valid UTF-8 into a percent-encoded value.
429
- for name in os .listdir (self .tempdir ):
430
- if name != 'test' : # Ignore a filename created in setUp().
431
- filename = name
432
- break
433
- body = self .check_status_and_reason (response , HTTPStatus .OK )
434
- quotedname = urllib .parse .quote (filename , errors = 'surrogatepass' )
435
- self .assertIn (('href="%s"' % quotedname )
436
- .encode (enc , 'surrogateescape' ), body )
437
- self .assertIn (('>%s<' % html .escape (filename , quote = False ))
438
- .encode (enc , 'surrogateescape' ), body )
439
- response = self .request (self .base_url + '/' + quotedname )
440
- self .check_status_and_reason (response , HTTPStatus .OK ,
441
- data = os_helper .TESTFN_UNDECODABLE )
484
+ self .check_list_dir_filename (filename )
485
+
486
+ def test_list_dir_undecodable_dirname2 (self ):
487
+ dirname = '\ufffd .dir'
488
+ self .check_list_dir_dirname (dirname , quotedname = '%ff.dir' )
489
+
490
+ @unittest .skipUnless (os_helper .TESTFN_UNENCODABLE ,
491
+ 'need os_helper.TESTFN_UNENCODABLE' )
492
+ def test_list_dir_unencodable_dirname (self ):
493
+ dirname = os_helper .TESTFN_UNENCODABLE + '.dir'
494
+ self .check_list_dir_dirname (dirname )
495
+
496
+ @unittest .skipUnless (os_helper .TESTFN_UNENCODABLE ,
497
+ 'need os_helper.TESTFN_UNENCODABLE' )
498
+ def test_list_dir_unencodable_filename (self ):
499
+ filename = os_helper .TESTFN_UNENCODABLE + '.txt'
500
+ self .check_list_dir_filename (filename )
501
+
502
+ def test_list_dir_escape_dirname (self ):
503
+ # Characters that need special treating in URL or HTML.
504
+ for name in ('q?' , 'f#' , '&' , '&' , '<i>' , '"dq"' , "'sq'" ,
505
+ '%A4' , '%E2%82%AC' ):
506
+ with self .subTest (name = name ):
507
+ dirname = name + '.dir'
508
+ self .check_list_dir_dirname (dirname ,
509
+ quotedname = urllib .parse .quote (dirname , safe = '&<>\' "' ))
510
+
511
+ def test_list_dir_escape_filename (self ):
512
+ # Characters that need special treating in URL or HTML.
513
+ for name in ('q?' , 'f#' , '&' , '&' , '<i>' , '"dq"' , "'sq'" ,
514
+ '%A4' , '%E2%82%AC' ):
515
+ with self .subTest (name = name ):
516
+ filename = name + '.txt'
517
+ self .check_list_dir_filename (filename )
518
+ os_helper .unlink (os .path .join (self .tempdir , filename ))
442
519
443
520
def test_undecodable_parameter (self ):
444
521
# sanity check using a valid parameter
@@ -620,27 +697,6 @@ def test_path_without_leading_slash(self):
620
697
self .assertEqual (response .getheader ("Location" ),
621
698
self .tempdir_name + "/?hi=1" )
622
699
623
- def test_html_escape_filename (self ):
624
- filename = '<test&>.txt'
625
- fullpath = os .path .join (self .tempdir , filename )
626
-
627
- try :
628
- open (fullpath , 'wb' ).close ()
629
- except OSError :
630
- raise unittest .SkipTest ('Can not create file %s on current file '
631
- 'system' % filename )
632
-
633
- try :
634
- response = self .request (self .base_url + '/' )
635
- body = self .check_status_and_reason (response , HTTPStatus .OK )
636
- enc = response .headers .get_content_charset ()
637
- finally :
638
- os .unlink (fullpath ) # avoid affecting test_undecodable_filename
639
-
640
- self .assertIsNotNone (enc )
641
- html_text = '>%s<' % html .escape (filename , quote = False )
642
- self .assertIn (html_text .encode (enc ), body )
643
-
644
700
645
701
cgi_file1 = """\
646
702
#!%s
0 commit comments