diff -r a318a5ab91fe Lib/http/server.py --- a/Lib/http/server.py Sat Aug 16 15:44:02 2014 +0200 +++ b/Lib/http/server.py Sat Aug 16 22:23:25 2014 +0300 @@ -747,7 +747,12 @@ return None list.sort(key=lambda a: a.lower()) r = [] - displaypath = html.escape(urllib.parse.unquote(self.path)) + try: + displaypath = urllib.parse.unquote(self.path, + errors='surrogatepass') + except UnicodeDecodeError: + displaypath = urllib.parse.unquote(path) + displaypath = html.escape(displaypath) enc = sys.getfilesystemencoding() title = 'Directory listing for %s' % displaypath r.append('%s' - % (urllib.parse.quote(linkname), html.escape(displayname))) + % (urllib.parse.quote(linkname, + errors='surrogatepass'), + html.escape(displayname))) r.append('\n
\n\n\n') - encoded = '\n'.join(r).encode(enc) + encoded = '\n'.join(r).encode(enc, 'surrogateescape') f = io.BytesIO() f.write(encoded) f.seek(0) @@ -794,7 +801,11 @@ path = path.split('#',1)[0] # Don't forget explicit trailing slash when normalizing. Issue17324 trailing_slash = path.rstrip().endswith('/') - path = posixpath.normpath(urllib.parse.unquote(path)) + try: + path = urllib.parse.unquote(path, errors='surrogatepass') + except UnicodeDecodeError: + path = urllib.parse.unquote(path) + path = posixpath.normpath(path) words = path.split('/') words = filter(None, words) path = os.getcwd() diff -r a318a5ab91fe Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py Sat Aug 16 15:44:02 2014 +0200 +++ b/Lib/test/test_httpservers.py Sat Aug 16 22:23:25 2014 +0300 @@ -14,6 +14,7 @@ import base64 import shutil import urllib.parse +import html import http.client import tempfile from io import BytesIO @@ -266,6 +267,24 @@ self.assertIsNotNone(response.reason) if data: self.assertEqual(data, body) + return body + + @unittest.skipUnless(support.TESTFN_UNDECODABLE, + 'need support.TESTFN_UNDECODABLE') + def test_undecodable_filename(self): + filename = os.fsdecode(support.TESTFN_UNDECODABLE) + '.txt' + with open(os.path.join(self.tempdir, filename), 'wb') as f: + f.write(support.TESTFN_UNDECODABLE) + response = self.request(self.tempdir_name + '/') + body = self.check_status_and_reason(response, 200) + quotedname = urllib.parse.quote(filename, errors='surrogatepass') + self.assertIn(('href="%s"' % quotedname) + .encode('utf-8', 'surrogateescape'), body) + self.assertIn(('>%s<' % html.escape(filename)) + .encode('utf-8', 'surrogateescape'), body) + response = self.request(self.tempdir_name + '/' + quotedname) + self.check_status_and_reason(response, 200, + data=support.TESTFN_UNDECODABLE) def test_get(self): #constructs the path relative to the root directory of the HTTPServer