gh-113471: Add custom default Content-Type to http.server (#113475)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Co-authored-by: donBarbos <donbarbos@proton.me>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
This commit is contained in:
John Comeau
2026-04-30 08:00:48 -07:00
committed by GitHub
parent f0e90d78eb
commit cc5f8b5434
5 changed files with 49 additions and 2 deletions
+20
View File
@@ -390,6 +390,14 @@ instantiation, of which this module provides three different variants:
This will be ``"SimpleHTTP/" + __version__``, where ``__version__`` is
defined at the module level.
.. 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:: extensions_map
A dictionary mapping suffixes into MIME types, contains custom overrides
@@ -528,6 +536,18 @@ The following options are accepted:
.. versionadded:: 3.11
.. option:: --content-type <content_type>
Specifies the default Content-Type HTTP header used when the MIME type
cannot be guessed from the URL's file extension. By default, the server
uses ``'application/octet-stream'``:
.. code-block:: bash
python -m http.server --content-type text/html
.. versionadded:: next
.. option:: --tls-cert
Specifies a TLS certificate chain for HTTPS connections:
+6
View File
@@ -964,6 +964,12 @@ http.server
<using-on-controlling-color>`.
(Contributed by Hugo van Kemenade in :gh:`146292`.)
* Added :attr:`~http.server.SimpleHTTPRequestHandler.default_content_type`
and the :option:`--content-type <http.server --content-type>` command-line
option to allow customizing the default ``Content-Type`` header
for files with unknown extensions.
(Contributed by John Comeau and Hugo van Kemenade in :gh:`113471`.)
inspect
-------
+10 -2
View File
@@ -727,6 +727,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
"""
server_version = "SimpleHTTP"
default_content_type = "application/octet-stream"
index_pages = ("index.html", "index.htm")
extensions_map = _encodings_map_default = {
'.gz': 'application/gzip',
@@ -974,7 +975,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
guess, _ = mimetypes.guess_file_type(path)
if guess:
return guess
return 'application/octet-stream'
return self.default_content_type
nobody = None
@@ -1010,9 +1011,10 @@ def _get_best_family(*address):
return family, sockaddr
def test(HandlerClass=BaseHTTPRequestHandler,
def test(HandlerClass=SimpleHTTPRequestHandler,
ServerClass=ThreadingHTTPServer,
protocol="HTTP/1.0", port=8000, bind=None,
content_type=SimpleHTTPRequestHandler.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=SimpleHTTPRequestHandler.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 @@ def _main(args=None):
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,
+11
View File
@@ -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,
@@ -1447,6 +1448,16 @@ class CommandLineTestCase(unittest.TestCase):
mock_func.assert_called_once_with(**call_args)
mock_func.reset_mock()
@mock.patch('http.server.test')
def test_content_type_flag(self, mock_func):
content_types = ['text/html', 'text/plain', 'application/json']
for content_type in content_types:
with self.subTest(content_type=content_type):
self.invoke_httpd('--content-type', content_type)
call_args = self.args | dict(content_type=content_type)
mock_func.assert_called_once_with(**call_args)
mock_func.reset_mock()
@unittest.skipIf(ssl is None, "requires ssl")
@mock.patch('http.server.test')
def test_tls_cert_and_key_flags(self, mock_func):
@@ -0,0 +1,2 @@
Allow :mod:`http.server` to set a default content-type when serving
files with an unknown or missing extension.