From a17a2f52c4c3b37414da95a152fc8669978c7c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Wirtel?= Date: Wed, 24 May 2017 09:29:06 +0200 Subject: [PATCH] bpo-28707: Add the directory parameter to http.server.SimpleHTTPRequestHandler and http.server module (#1776) * bpo-28707: call the constructor of SimpleHTTPRequestHandler in the test with a mock object * bpo-28707: Add the directory parameter to http.server.SimpleHTTPRequestHandler and http.server module --- Doc/library/http.server.rst | 15 +++++++++++++-- Doc/whatsnew/3.7.rst | 5 +++++ Lib/http/server.py | 15 +++++++++++++-- Lib/test/test_httpservers.py | 7 ++++++- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index ee1c37c6319..323ee9f5d36 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -299,7 +299,7 @@ of which this module provides three different variants: delays, it now always returns the IP address. -.. class:: SimpleHTTPRequestHandler(request, client_address, server) +.. class:: SimpleHTTPRequestHandler(request, client_address, server, directory=None) This class serves files from the current directory and below, directly mapping the directory structure to HTTP requests. @@ -323,6 +323,10 @@ of which this module provides three different variants: ``application/octet-stream``. The mapping is used case-insensitively, and so should contain only lower-cased keys. + .. attribute:: directory + + If not specified, the directory to serve is the current working directory. + The :class:`SimpleHTTPRequestHandler` class defines the following methods: .. method:: do_HEAD() @@ -397,6 +401,14 @@ following command causes the server to bind to localhost only:: .. versionadded:: 3.4 ``--bind`` argument was introduced. +By default, server uses the current directory. The option ``-d/--directory`` +specifies a directory to which it should serve the files. For example, +the following command uses a specific directory:: + + python -m http.server --directory /tmp/ + +.. versionadded:: 3.7 + ``--directory`` specify alternate directory .. class:: CGIHTTPRequestHandler(request, client_address, server) @@ -442,4 +454,3 @@ following command causes the server to bind to localhost only:: the ``--cgi`` option:: python -m http.server --cgi 8000 - diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index c305e5a94cb..3195d9022ee 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -139,6 +139,11 @@ If-Modified-Since header. The server returns the 304 response status if the target file was not modified after the time specified in the header. (Contributed by Pierre Quentel in :issue:`29654`.) +Add the parameter ``directory`` to the :class:`~http.server.SimpleHTTPRequestHandler` +and the ``--directory`` to the command line of the module :mod:`~http.server`. +With this parameter, the server serves the specified directory, by default it uses the current working directory. +(Contributed by Stéphane Wirtel and Julien Palard in :issue:`28707`.) + locale ------ diff --git a/Lib/http/server.py b/Lib/http/server.py index 7b3e701fb7a..b1151a2b654 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -103,6 +103,7 @@ import socketserver import sys import time import urllib.parse +from functools import partial from http import HTTPStatus @@ -634,6 +635,12 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): server_version = "SimpleHTTP/" + __version__ + def __init__(self, *args, directory=None, **kwargs): + if directory is None: + directory = os.getcwd() + self.directory = directory + super().__init__(*args, **kwargs) + def do_GET(self): """Serve a GET request.""" f = self.send_head() @@ -806,7 +813,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): path = posixpath.normpath(path) words = path.split('/') words = filter(None, words) - path = os.getcwd() + path = self.directory for word in words: if os.path.dirname(word) or word in (os.curdir, os.pardir): # Ignore components that are not a simple file/directory name @@ -1234,6 +1241,9 @@ if __name__ == '__main__': parser.add_argument('--bind', '-b', default='', metavar='ADDRESS', help='Specify alternate bind address ' '[default: all interfaces]') + parser.add_argument('--directory', '-d', default=os.getcwd(), + help='Specify alternative directory ' + '[default:current directory]') parser.add_argument('port', action='store', default=8000, type=int, nargs='?', @@ -1242,5 +1252,6 @@ if __name__ == '__main__': if args.cgi: handler_class = CGIHTTPRequestHandler else: - handler_class = SimpleHTTPRequestHandler + handler_class = partial(SimpleHTTPRequestHandler, + directory=args.directory) test(HandlerClass=handler_class, port=args.port, bind=args.bind) diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index dafcb0cbd56..cdc52021013 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -22,6 +22,7 @@ import urllib.parse import tempfile import time import datetime +from unittest import mock from io import BytesIO import unittest @@ -782,7 +783,11 @@ class CGIHTTPServerTestCase(BaseTestCase): class SocketlessRequestHandler(SimpleHTTPRequestHandler): - def __init__(self): + def __init__(self, *args, **kwargs): + request = mock.Mock() + request.makefile.return_value = BytesIO() + super().__init__(request, None, None) + self.get_called = False self.protocol_version = "HTTP/1.1"