diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst index cb8b5f0df88d6c..539d9394f53e12 100644 --- a/Doc/library/http.server.rst +++ b/Doc/library/http.server.rst @@ -207,6 +207,14 @@ instantiation, of which this module provides three different variants: header (using :meth:`send_header`) in all of its responses to clients. For backwards compatibility, the setting defaults to ``'HTTP/1.0'``. + .. attribute:: default_content_type + + Specifies the Content-Type header value sent when the MIME type + cannot be guessed from the file extension of the requested URL. + By default, it is set to ``'application/octet-stream'``. + + .. versionadded:: next + .. attribute:: MessageClass Specifies an :class:`email.message.Message`\ -like class to parse HTTP @@ -518,6 +526,18 @@ The following options are accepted: .. versionadded:: 3.11 +.. option:: --content-type + + Specifies the Content-Type HTTP header. By default, the server uses the + MIME type ``'application/octet-stream'`` for the ``Content-Type`` header + when the content type cannot be guessed from the URL's extension (if any): + + .. code-block:: bash + + python -m http.server --content-type text/html + + .. versionadded:: next + .. option:: --tls-cert Specifies a TLS certificate chain for HTTPS connections:: diff --git a/Lib/http/server.py b/Lib/http/server.py index 568d3bb38deb6c..31874a5ff8273a 100644 --- a/Lib/http/server.py +++ b/Lib/http/server.py @@ -290,6 +290,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler): # the client gets back when sending a malformed request line. # Most web servers default to HTTP 0.9, i.e. don't send a status line. default_request_version = "HTTP/0.9" + default_content_type = "application/octet-stream" def parse_request(self): """Parse a request (internal). @@ -974,7 +975,7 @@ def guess_type(self, path): guess, _ = mimetypes.guess_file_type(path) if guess: return guess - return 'application/octet-stream' + return self.default_content_type nobody = None @@ -1013,6 +1014,7 @@ def _get_best_family(*address): def test(HandlerClass=BaseHTTPRequestHandler, ServerClass=ThreadingHTTPServer, protocol="HTTP/1.0", port=8000, bind=None, + content_type=BaseHTTPRequestHandler.default_content_type, tls_cert=None, tls_key=None, tls_password=None): """Test the HTTP request handler class. @@ -1021,6 +1023,7 @@ def test(HandlerClass=BaseHTTPRequestHandler, """ ServerClass.address_family, addr = _get_best_family(bind, port) HandlerClass.protocol_version = protocol + HandlerClass.default_content_type = content_type if tls_cert: server = ServerClass(addr, HandlerClass, certfile=tls_cert, @@ -1060,6 +1063,10 @@ def _main(args=None): default='HTTP/1.0', help='conform to this HTTP version ' '(default: %(default)s)') + parser.add_argument('--content-type', + default=BaseHTTPRequestHandler.default_content_type, + help='default content type for unknown extensions ' + '(default: %(default)s)') parser.add_argument('--tls-cert', metavar='PATH', help='path to the TLS certificate chain file') parser.add_argument('--tls-key', metavar='PATH', @@ -1112,6 +1119,7 @@ class HTTPSDualStackServer(DualStackServerMixin, ThreadingHTTPSServer): port=args.port, bind=args.bind, protocol=args.protocol, + content_type=args.content_type, tls_cert=args.tls_cert, tls_key=args.tls_key, tls_password=tls_key_password, diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index d78b94e3a373d4..3b987d0081b454 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -1379,6 +1379,7 @@ class CommandLineTestCase(unittest.TestCase): 'protocol': default_protocol, 'port': default_port, 'bind': default_bind, + 'content_type': 'application/octet-stream', 'tls_cert': None, 'tls_key': None, 'tls_password': None, diff --git a/Misc/NEWS.d/next/Library/2023-12-25-19-14-07.gh-issue-113471.ZQMpbI.rst b/Misc/NEWS.d/next/Library/2023-12-25-19-14-07.gh-issue-113471.ZQMpbI.rst new file mode 100644 index 00000000000000..99ba9bd1820fc1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-12-25-19-14-07.gh-issue-113471.ZQMpbI.rst @@ -0,0 +1,2 @@ +Allow :mod:`http.server` to set a default content-type when serving +files with an unknown or missing extension.