[Python-checkins] cpython (merge 3.4 -> default): Issue #22165: SimpleHTTPRequestHandler now supports undecodable file names.

serhiy.storchaka python-checkins at python.org
Sun Aug 17 07:25:54 CEST 2014


http://hg.python.org/cpython/rev/3153a400b739
changeset:   92126:3153a400b739
parent:      92124:6219aa966a5f
parent:      92125:f180a9156cc8
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Sun Aug 17 08:24:49 2014 +0300
summary:
  Issue #22165: SimpleHTTPRequestHandler now supports undecodable file names.

files:
  Lib/http/server.py           |  19 +++++++++++++++----
  Lib/test/test_httpservers.py |  19 +++++++++++++++++++
  Misc/NEWS                    |   2 ++
  3 files changed, 36 insertions(+), 4 deletions(-)


diff --git a/Lib/http/server.py b/Lib/http/server.py
--- a/Lib/http/server.py
+++ b/Lib/http/server.py
@@ -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('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" '
@@ -769,9 +774,11 @@
                 displayname = name + "@"
                 # Note: a link to a directory displays with @ and links with /
             r.append('<li><a href="%s">%s</a></li>'
-                    % (urllib.parse.quote(linkname), html.escape(displayname)))
+                    % (urllib.parse.quote(linkname,
+                                          errors='surrogatepass'),
+                       html.escape(displayname)))
         r.append('</ul>\n<hr>\n</body>\n</html>\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 --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -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
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -118,6 +118,8 @@
 Library
 -------
 
+- Issue #22165: SimpleHTTPRequestHandler now supports undecodable file names.
+
 - Issue #15381: Optimized line reading in io.BytesIO.
 
 - Issue #20729: Restored the use of lazy iterkeys()/itervalues()/iteritems()

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list