Skip to content

Commit

Permalink
bpo-35640: Allow passing PathLike arguments to SimpleHTTPRequestHandl…
Browse files Browse the repository at this point in the history
…er (GH-11398)
  • Loading branch information
geryogam authored and zware committed Sep 11, 2019
1 parent e1d455f commit 781266e
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 24 deletions.
3 changes: 3 additions & 0 deletions Doc/library/http.server.rst
Expand Up @@ -344,6 +344,9 @@ provides three different variants:

If not specified, the directory to serve is the current working directory.

.. versionchanged:: 3.9
Accepts a :term:`path-like object`.

The :class:`SimpleHTTPRequestHandler` class defines the following methods:

.. method:: do_HEAD()
Expand Down
2 changes: 1 addition & 1 deletion Lib/http/server.py
Expand Up @@ -642,7 +642,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def __init__(self, *args, directory=None, **kwargs):
if directory is None:
directory = os.getcwd()
self.directory = directory
self.directory = os.fspath(directory)
super().__init__(*args, **kwargs)

def do_GET(self):
Expand Down
97 changes: 74 additions & 23 deletions Lib/test/test_httpservers.py
Expand Up @@ -14,6 +14,7 @@
import re
import base64
import ntpath
import pathlib
import shutil
import email.message
import email.utils
Expand Down Expand Up @@ -790,10 +791,10 @@ def test_query_with_continuous_slashes(self):


class SocketlessRequestHandler(SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
def __init__(self, directory=None):
request = mock.Mock()
request.makefile.return_value = BytesIO()
super().__init__(request, None, None)
super().__init__(request, None, None, directory=directory)

self.get_called = False
self.protocol_version = "HTTP/1.1"
Expand Down Expand Up @@ -1068,41 +1069,91 @@ def test_date_time_string(self):
class SimpleHTTPRequestHandlerTestCase(unittest.TestCase):
""" Test url parsing """
def setUp(self):
self.translated = os.getcwd()
self.translated = os.path.join(self.translated, 'filename')
self.handler = SocketlessRequestHandler()
self.translated_1 = os.path.join(os.getcwd(), 'filename')
self.translated_2 = os.path.join('foo', 'filename')
self.translated_3 = os.path.join('bar', 'filename')
self.handler_1 = SocketlessRequestHandler()
self.handler_2 = SocketlessRequestHandler(directory='foo')
self.handler_3 = SocketlessRequestHandler(directory=pathlib.PurePath('bar'))

def test_query_arguments(self):
path = self.handler.translate_path('/filename')
self.assertEqual(path, self.translated)
path = self.handler.translate_path('/filename?foo=bar')
self.assertEqual(path, self.translated)
path = self.handler.translate_path('/filename?a=b&spam=eggs#zot')
self.assertEqual(path, self.translated)
path = self.handler_1.translate_path('/filename')
self.assertEqual(path, self.translated_1)
path = self.handler_2.translate_path('/filename')
self.assertEqual(path, self.translated_2)
path = self.handler_3.translate_path('/filename')
self.assertEqual(path, self.translated_3)

path = self.handler_1.translate_path('/filename?foo=bar')
self.assertEqual(path, self.translated_1)
path = self.handler_2.translate_path('/filename?foo=bar')
self.assertEqual(path, self.translated_2)
path = self.handler_3.translate_path('/filename?foo=bar')
self.assertEqual(path, self.translated_3)

path = self.handler_1.translate_path('/filename?a=b&spam=eggs#zot')
self.assertEqual(path, self.translated_1)
path = self.handler_2.translate_path('/filename?a=b&spam=eggs#zot')
self.assertEqual(path, self.translated_2)
path = self.handler_3.translate_path('/filename?a=b&spam=eggs#zot')
self.assertEqual(path, self.translated_3)

def test_start_with_double_slash(self):
path = self.handler.translate_path('//filename')
self.assertEqual(path, self.translated)
path = self.handler.translate_path('//filename?foo=bar')
self.assertEqual(path, self.translated)
path = self.handler_1.translate_path('//filename')
self.assertEqual(path, self.translated_1)
path = self.handler_2.translate_path('//filename')
self.assertEqual(path, self.translated_2)
path = self.handler_3.translate_path('//filename')
self.assertEqual(path, self.translated_3)

path = self.handler_1.translate_path('//filename?foo=bar')
self.assertEqual(path, self.translated_1)
path = self.handler_2.translate_path('//filename?foo=bar')
self.assertEqual(path, self.translated_2)
path = self.handler_3.translate_path('//filename?foo=bar')
self.assertEqual(path, self.translated_3)

def test_windows_colon(self):
with support.swap_attr(server.os, 'path', ntpath):
path = self.handler.translate_path('c:c:c:foo/filename')
path = self.handler_1.translate_path('c:c:c:foo/filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated_1)
path = self.handler_2.translate_path('c:c:c:foo/filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated_2)
path = self.handler_3.translate_path('c:c:c:foo/filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated)
self.assertEqual(path, self.translated_3)

path = self.handler.translate_path('\\c:../filename')
path = self.handler_1.translate_path('\\c:../filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated_1)
path = self.handler_2.translate_path('\\c:../filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated_2)
path = self.handler_3.translate_path('\\c:../filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated)
self.assertEqual(path, self.translated_3)

path = self.handler.translate_path('c:\\c:..\\foo/filename')
path = self.handler_1.translate_path('c:\\c:..\\foo/filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated)
self.assertEqual(path, self.translated_1)
path = self.handler_2.translate_path('c:\\c:..\\foo/filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated_2)
path = self.handler_3.translate_path('c:\\c:..\\foo/filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated_3)

path = self.handler.translate_path('c:c:foo\\c:c:bar/filename')
path = self.handler_1.translate_path('c:c:foo\\c:c:bar/filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated_1)
path = self.handler_2.translate_path('c:c:foo\\c:c:bar/filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated_2)
path = self.handler_3.translate_path('c:c:foo\\c:c:bar/filename')
path = path.replace(ntpath.sep, os.sep)
self.assertEqual(path, self.translated)
self.assertEqual(path, self.translated_3)


class MiscTestCase(unittest.TestCase):
Expand Down
@@ -0,0 +1,2 @@
Allow passing a :term:`path-like object` as ``directory`` argument to the
:class:`http.server.SimpleHTTPRequestHandler` class. Patch by Géry Ogam.

0 comments on commit 781266e

Please sign in to comment.