Skip to content
Open
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
0d02fbe
gh-135056: Add a --cors CLI argument to http.server
aisipos May 27, 2025
1838da7
gh-issue-135056: Fix doc versionchanged and NEWS entries.
aisipos Jun 3, 2025
a3256fd
gh-13056: Allow unspecified response_headers in HTTPServer.
aisipos Jun 3, 2025
77b5fff
gh-135056: Simplifications and cleanups to http cors changes.
aisipos Jun 19, 2025
5f89c97
gh-135056: Add a --header argument to http.server cli.
aisipos Jun 20, 2025
a3243fe
gh-135056: Remove --cors opt from http.server in favor of --header
aisipos Jul 6, 2025
b1026d2
gh-135056: Use response_headers only in SimpleHTTPRequestHandler
aisipos Jul 7, 2025
6f88c13
gh-135056: Add test for http.server cli --header argument
aisipos Jul 10, 2025
7a793f2
gh-135056: Support multiple headers of the same name.
aisipos Jul 10, 2025
9450b86
gh-135056: Remove some commented out and unused code.
aisipos Jul 15, 2025
5a30d91
gh-135056: Capitalize CLI acronym in the docs.
aisipos Jul 15, 2025
d317cc2
gh-135056: Simplify args.header processing.
aisipos Jul 15, 2025
5f1fb94
gh-135056: Factor out a _make_server function from test function.
aisipos Aug 12, 2025
c376a71
gh-135056: Document directory and custom_headers as keyword args.
aisipos Aug 12, 2025
89a89f0
gh-135056: Add whatsnew entries to 3.15.rst for custom headers.
aisipos Aug 12, 2025
9653710
gh-135056: Revert document directory + custom_headers as kwargs
aisipos Oct 6, 2025
f3ae904
gh-135056: Document response_headers as an instance_attribute.
aisipos Oct 6, 2025
44efbed
gh-135056: Revert blank line removal in http.server.rst
aisipos Oct 6, 2025
d47c5a7
gh-135056: Remove incorrect = sign from whatsnew argument entry.
aisipos Oct 6, 2025
8d1286a
gh-135056: Document -H, --header cli params in http.server.rst
aisipos Oct 6, 2025
db9de68
gh-135056: Rename custom headers to extra_response_headers.
aisipos Oct 6, 2025
e149708
gh-135056: Fix alignment of parameters to _make_server.
aisipos Oct 6, 2025
c16f4c9
gh-135056: Remove extraneous newline in docstring for test() method
aisipos Oct 6, 2025
777b5b6
gh-135056: Simplify kwargs to CustomHeaderSimpleHTTPRequestHandler
aisipos Oct 6, 2025
eac5c6a
gh-135056: Note both -H and --header in NEWS entries.
aisipos Oct 6, 2025
c9c8083
gh-135056: Put kwarg on its own line in mock assertion.
aisipos Oct 7, 2025
c2d6bb3
gh-135056: Add tests for bad usage of header arg.
aisipos Oct 7, 2025
3377cf7
gh-135056: Document SimpleHTTPRequestHandler params as keyword only.
aisipos Oct 7, 2025
06a9977
gh-135056: Fix missing renames of extra_response_headers.
aisipos Oct 7, 2025
fae21f9
gh-135056: Merge branch 'main' of github.com:python/cpython
aisipos Oct 9, 2025
be78515
gh-135056: Clarify extra_response_headers is a paramter
aisipos Oct 9, 2025
53965ff
gh-135056: Prefer user-defined to user specified in http.server docs
aisipos Oct 9, 2025
c280ed8
gh-135056: Clarify wording about non-200 response header logic
aisipos Oct 9, 2025
64122df
gh-135056: Keep TLS arguments to _make_server on the same line.
aisipos Oct 9, 2025
f0d1bac
gh-135056: Prefer "specified" to "use" in cli --help text.
aisipos Oct 9, 2025
e99780e
gh-135056: Change new arg to mock.patch.object to positional instead
aisipos Oct 9, 2025
2e829bb
gh-135056: Correct proper 2 line spacing after test class.
aisipos Oct 9, 2025
8baa875
gh-135056: Assert response.status is 200 in new tests.
aisipos Oct 9, 2025
7856d27
gh-135056: Add test_extra_response_headers_missing_on_404
aisipos Oct 9, 2025
303ab5b
gh-135056: Augment header test case to check colons and spaces
aisipos Oct 10, 2025
ed0b0b3
gh-135056: Fix ReST fully qualified ref to SimpleHTTPRequestHandler
aisipos Oct 10, 2025
79c577b
gh-135056: Fix socket closing in test_extra_response_headers_arg
aisipos Oct 10, 2025
526e499
Merge remote-tracking branch 'upstream/main'
aisipos Dec 12, 2025
46c1c91
Merge remote-tracking branch 'upstream/main' into https-server-cors-i…
aisipos Apr 12, 2026
c1fee3b
gh-035056: Minor documentation formating and punctuation fixes.
aisipos Apr 12, 2026
3a4fed6
gh-135056: Don't let extra headers overwrite default headers
aisipos Apr 12, 2026
9f0ed01
gh-135056: Fix attribute access to default_response_headers
aisipos Apr 12, 2026
1036a91
gh-135056: Use proper RST syntax for attribute references.
aisipos Apr 28, 2026
49ffc92
gh-135056: Make more new args and attrs private.
aisipos Apr 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion Doc/library/http.server.rst
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,8 @@ instantiation, of which this module provides three different variants:
delays, it now always returns the IP address.


.. class:: SimpleHTTPRequestHandler(request, client_address, server, directory=None)
.. class:: SimpleHTTPRequestHandler(request, client_address, server, \
*, directory=None, extra_response_headers=None)

This class serves files from the directory *directory* and below,
or the current directory if *directory* is not provided, directly
Expand All @@ -378,6 +379,9 @@ instantiation, of which this module provides three different variants:
.. versionchanged:: 3.9
The *directory* parameter accepts a :term:`path-like object`.

.. versionchanged:: next
Added *extra_response_headers* parameter.

A lot of the work, such as parsing the request, is done by the base class
:class:`BaseHTTPRequestHandler`. This class implements the :func:`do_GET`
and :func:`do_HEAD` functions.
Expand All @@ -400,6 +404,15 @@ instantiation, of which this module provides three different variants:
This dictionary is no longer filled with the default system mappings,
but only contains overrides.

.. attribute:: extra_response_headers

A sequence of ``(name, value)`` pairs containing user-defined extra HTTP
response headers to add to each successful HTTP status 200 response. These
headers are not included in other status code responses.

Headers that the server sends automatically (for instance Content-Type)
will not be overwritten by extra_response_headers.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Headers that the server sends automatically (for instance Content-Type)
will not be overwritten by extra_response_headers.
Headers that the server sends automatically such as ``Content-Type``
will not be overwritten by :attr:`!extra_response_headers`.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1036a91


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

.. method:: do_HEAD()
Expand Down Expand Up @@ -432,6 +445,9 @@ instantiation, of which this module provides three different variants:
followed by a ``'Content-Length:'`` header with the file's size and a
``'Last-Modified:'`` header with the file's modification time.

The instance attribute ``extra_response_headers`` is a sequence of
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The instance attribute ``extra_response_headers`` is a sequence of
The instance attribute :attr:`extra_response_headers` is a sequence of

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1036a91

``(name, value)`` pairs containing user-defined extra response headers.

Then follows a blank line signifying the end of the headers, and then the
contents of the file are output.

Expand Down Expand Up @@ -547,6 +563,15 @@ The following options are accepted:

.. versionadded:: 3.14

.. option:: -H, --header <header> <value>
Comment thread
picnixz marked this conversation as resolved.

Specify an additional extra HTTP Response Header to send on successful HTTP
200 responses. Can be used multiple times to send additional custom response
headers. Headers that are sent automatically by the server (for instance
Content-Type) will not be overwritten by the server.

.. versionadded:: next


Comment thread
picnixz marked this conversation as resolved.
.. _http.server-security:

Expand Down
9 changes: 9 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,15 @@ http.server
<using-on-controlling-color>`.
(Contributed by Hugo van Kemenade in :gh:`146292`.)

* Add a new ``extra_response_headers`` keyword argument to
:class:`~http.server.SimpleHTTPRequestHandler` to support custom headers in
HTTP responses.
(Contributed by Anton I. Sipos in :gh:`135057`.)

* Add a ``-H/--header`` option to the :program:`python -m http.server`
command-line interface to support custom headers in HTTP responses.
(Contributed by Anton I. Sipos in :gh:`135057`.)


inspect
-------
Expand Down
55 changes: 41 additions & 14 deletions Lib/http/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ def handle_one_request(self):
def handle(self):
"""Handle multiple requests if necessary."""
self.close_connection = True
self.default_response_headers = []
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm always worried about creating new public attributes because we had a breakage of that with threading. See #132578. I think this attribute should still be private but at the same time, I'm worried about people overriding this class and having their own default_response_headers (it may not be far-fetched to assume that this attribute exists in customer classes). Can you make a quick search on GH for that?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good point. Looking at this Github code search , at least at this simple of a search I only see some projects that are defining a new function _send_default_response_headers, which won't conflict with any of our new names.


self.handle_one_request()
while not self.close_connection:
Expand Down Expand Up @@ -551,13 +552,15 @@ def send_response_only(self, code, message=None):
(self.protocol_version, code, message)).encode(
'latin-1', 'strict'))

def send_header(self, keyword, value):
def send_header(self, keyword, value, is_extra=False):
"""Send a MIME header to the headers buffer."""
if self.request_version != 'HTTP/0.9':
if not hasattr(self, '_headers_buffer'):
self._headers_buffer = []
self._headers_buffer.append(
("%s: %s\r\n" % (keyword, value)).encode('latin-1', 'strict'))
if not is_extra and hasattr(self, 'default_response_headers'):
self.default_response_headers.append((keyword, value))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def send_header(self, keyword, value, is_extra=False):
"""Send a MIME header to the headers buffer."""
if self.request_version != 'HTTP/0.9':
if not hasattr(self, '_headers_buffer'):
self._headers_buffer = []
self._headers_buffer.append(
("%s: %s\r\n" % (keyword, value)).encode('latin-1', 'strict'))
if not is_extra and hasattr(self, 'default_response_headers'):
self.default_response_headers.append((keyword, value))
def send_header(self, keyword, value, *, _is_extra=False):
"""Send a MIME header to the headers buffer."""
if self.request_version != 'HTTP/0.9':
if not hasattr(self, '_headers_buffer'):
self._headers_buffer = []
self._headers_buffer.append(
("%s: %s\r\n" % (keyword, value)).encode('latin-1', 'strict'))
if not _is_extra and hasattr(self, '_default_response_headers'):
self._default_response_headers.append((keyword, value))

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 49ffc92


if keyword.lower() == 'connection':
if value.lower() == 'close':
Expand Down Expand Up @@ -735,10 +738,11 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
'.xz': 'application/x-xz',
}

def __init__(self, *args, directory=None, **kwargs):
def __init__(self, *args, directory=None, extra_response_headers=None, **kwargs):
Comment thread
picnixz marked this conversation as resolved.
if directory is None:
directory = os.getcwd()
self.directory = os.fspath(directory)
self.extra_response_headers = extra_response_headers
super().__init__(*args, **kwargs)

def do_GET(self):
Expand All @@ -756,6 +760,14 @@ def do_HEAD(self):
if f:
f.close()

def _send_extra_response_headers(self):
"""Send the headers stored in self.extra_response_headers"""
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Send the headers stored in self.extra_response_headers"""
"""Send the headers stored in self.extra_response_headers."""

if self.extra_response_headers is not None:
for header, value in self.extra_response_headers:
# Don't send the header if it's already sent as part of the default response headers
if header.lower() not in (h.lower() for h, _ in self.default_response_headers):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for header, value in self.extra_response_headers:
# Don't send the header if it's already sent as part of the default response headers
if header.lower() not in (h.lower() for h, _ in self.default_response_headers):
default_headers = {h.lower() for h, _ in self.default_response_headers}
for header, value in self.extra_response_headers:
# Don't send the header if it's already sent
# as part of the default response headers
if header not in default_headers:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 49ffc92

self.send_header(header, value, is_extra=True)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.send_header(header, value, is_extra=True)
self.send_header(header, value, _is_extra=True)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 49ffc92


def send_head(self):
"""Common code for GET and HEAD commands.

Expand Down Expand Up @@ -838,6 +850,7 @@ def send_head(self):
self.send_header("Content-Length", str(fs[6]))
self.send_header("Last-Modified",
self.date_time_string(fs.st_mtime))
self._send_extra_response_headers()
self.end_headers()
return f
except:
Expand Down Expand Up @@ -902,6 +915,7 @@ def list_directory(self, path):
self.send_response(HTTPStatus.OK)
self.send_header("Content-type", "text/html; charset=%s" % enc)
self.send_header("Content-Length", str(len(encoded)))
self._send_extra_response_headers()
self.end_headers()
return f

Expand Down Expand Up @@ -1010,25 +1024,33 @@ def _get_best_family(*address):
return family, sockaddr


def _make_server(HandlerClass=BaseHTTPRequestHandler,
Comment thread
picnixz marked this conversation as resolved.
ServerClass=ThreadingHTTPServer,
protocol="HTTP/1.0", port=8000, bind=None,
tls_cert=None, tls_key=None, tls_password=None):
ServerClass.address_family, addr = _get_best_family(bind, port)
HandlerClass.protocol_version = protocol

if tls_cert:
return ServerClass(addr, HandlerClass, certfile=tls_cert,
keyfile=tls_key, password=tls_password)
else:
return ServerClass(addr, HandlerClass)


def test(HandlerClass=BaseHTTPRequestHandler,
ServerClass=ThreadingHTTPServer,
protocol="HTTP/1.0", port=8000, bind=None,
tls_cert=None, tls_key=None, tls_password=None):
"""Test the HTTP request handler class.

This runs an HTTP server on port 8000 (or the port argument).

"""
ServerClass.address_family, addr = _get_best_family(bind, port)
HandlerClass.protocol_version = protocol

if tls_cert:
server = ServerClass(addr, HandlerClass, certfile=tls_cert,
keyfile=tls_key, password=tls_password)
else:
server = ServerClass(addr, HandlerClass)

with server as httpd:
with _make_server(
HandlerClass=HandlerClass, ServerClass=ServerClass,
protocol=protocol, port=port, bind=bind,
tls_cert=tls_cert, tls_key=tls_key, tls_password=tls_password
) as httpd:
host, port = httpd.socket.getsockname()[:2]
url_host = f'[{host}]' if ':' in host else host
protocol = 'HTTPS' if tls_cert else 'HTTP'
Expand Down Expand Up @@ -1069,6 +1091,10 @@ def _main(args=None):
parser.add_argument('port', default=8000, type=int, nargs='?',
help='bind to this port '
'(default: %(default)s)')
parser.add_argument('-H', '--header', nargs=2, action='append',
metavar=('HEADER', 'VALUE'),
help='Add a custom response header '
'(can be specified multiple times)')
args = parser.parse_args(args)

if not args.tls_cert and args.tls_key:
Expand Down Expand Up @@ -1097,7 +1123,8 @@ def server_bind(self):

def finish_request(self, request, client_address):
self.RequestHandlerClass(request, client_address, self,
directory=args.directory)
directory=args.directory,
extra_response_headers=args.header)

class HTTPDualStackServer(DualStackServerMixin, ThreadingHTTPServer):
pass
Expand Down
104 changes: 103 additions & 1 deletion Lib/test/test_httpservers.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,8 +540,16 @@ def test_err(self):
self.assertIn(f"{t.status_client_error}404", lines[1])


class CustomHeaderSimpleHTTPRequestHandler(SimpleHTTPRequestHandler):
extra_response_headers = None

def __init__(self, *args, **kwargs):
kwargs.setdefault('extra_response_headers', self.extra_response_headers)
super().__init__(*args, **kwargs)

Comment on lines +543 to +549
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class CustomHeaderSimpleHTTPRequestHandler(SimpleHTTPRequestHandler):
custom_headers = None
def __init__(self, *args, directory=None, response_headers=None, **kwargs):
super().__init__(*args, response_headers=self.custom_headers, **kwargs)
class CustomHeaderSimpleHTTPRequestHandler(SimpleHTTPRequestHandler):
custom_headers = None
def __init__(self, *args, **kwargs):
kwargs.setdefault('response_headers', self.custom_headers)
super().__init__(*args, **kwargs)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 777b5b6


class SimpleHTTPServerTestCase(BaseTestCase):
class request_handler(NoLogRequestHandler, SimpleHTTPRequestHandler):
class request_handler(NoLogRequestHandler, CustomHeaderSimpleHTTPRequestHandler):
pass

def setUp(self):
Expand Down Expand Up @@ -898,6 +906,55 @@ def test_path_without_leading_slash(self):
self.assertEqual(response.getheader("Location"),
self.tempdir_name + "/?hi=1")

def test_extra_response_headers_list_dir(self):
with mock.patch.object(self.request_handler, 'extra_response_headers', [
('X-Test1', 'test1'),
('X-Test2', 'test2'),
]):
response = self.request(self.base_url + '/')
self.assertEqual(response.status, 200)
self.assertEqual(response.getheader("X-Test1"), 'test1')
self.assertEqual(response.getheader("X-Test2"), 'test2')

def test_extra_response_headers_get_file(self):
with mock.patch.object(self.request_handler, 'extra_response_headers', [
('Set-Cookie', 'test1=value1'),
('Set-Cookie', 'test2=value2'),
('X-Test1', 'value3'),
]):
data = b"Dummy index file\r\n"
with open(os.path.join(self.tempdir_name, 'index.html'), 'wb') as f:
f.write(data)
response = self.request(self.base_url + '/')
self.assertEqual(response.status, 200)
self.assertEqual(response.getheader("Set-Cookie"),
'test1=value1, test2=value2')
self.assertEqual(response.getheader("X-Test1"), 'value3')
Comment thread
hugovk marked this conversation as resolved.

def test_extra_response_headers_missing_on_404(self):
with mock.patch.object(self.request_handler, 'extra_response_headers', [
('X-Test1', 'value'),
]):
response = self.request(self.base_url + '/missing.html')
self.assertEqual(response.status, 404)
self.assertEqual(response.getheader("X-Test1"), None)

def test_extra_response_headers_dont_overwrite_default_headers(self):
with mock.patch.object(self.request_handler, 'extra_response_headers', [
('Content-Type', 'test/not_allowed'),
('Server', 'not_allowed'),
('Set-Cookie', 'test=allowed'),
]):
# The Content-Type header should not be overwritten by the extra_response_headers
# But cookies in the extra_allowed_duplicate_headers are allowed,
# including Set-Cookie
response = self.request(self.base_url + '/')
self.assertEqual(response.status, 200)
self.assertNotEqual(response.getheader("Content-Type"), 'test/not_allowed')
self.assertNotEqual(response.getheader("Server"), 'not_allowed')
self.assertEqual(response.getheader("Set-Cookie"), 'test=allowed')



class SocketlessRequestHandler(SimpleHTTPRequestHandler):
def __init__(self, directory=None):
Expand Down Expand Up @@ -1447,6 +1504,21 @@ def test_protocol_flag(self, mock_func):
mock_func.assert_called_once_with(**call_args)
mock_func.reset_mock()

@mock.patch('http.server.test')
def test_header_flag(self, mock_func):
call_args = self.args
self.invoke_httpd('--header', 'h1', 'v1', '-H', 'h2', 'v2')
mock_func.assert_called_once_with(**call_args)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to check this as --header is only used by the handler and not the server test server itself. Ideally, we should also extract the logic of making the parser to check that the parsed arguments are of the expected form (namely a sequence of pairs).

You can however check bad usages of --header (e.g., --header h1 should raise, and --header h1 h2 h3 as well).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some new tests to verify exceptions with incorrect header CLI usage in c2d6bb3.

I agree that test_header_flag doesn't quite do what we want. I only put it there to ensure all the argument parsing and logic in _main() doesn't raise in the presence of the new arguments before calling test(). I agree that refactoring out the parser logic would allow us to test this properly. However, I've been trying to keep the changes in this PR relatively small. If you feel though that a refactor is the better choice, I'm happy to do that.

mock_func.reset_mock()

def test_extra_header_flag_too_few_args(self):
with self.assertRaises(SystemExit):
self.invoke_httpd('--header', 'h1')

def test_extra_header_flag_too_many_args(self):
with self.assertRaises(SystemExit):
self.invoke_httpd('--header', 'h1', 'v1', 'h2')

@unittest.skipIf(ssl is None, "requires ssl")
@mock.patch('http.server.test')
def test_tls_cert_and_key_flags(self, mock_func):
Expand Down Expand Up @@ -1530,6 +1602,36 @@ def test_unknown_flag(self, _):
self.assertEqual(stdout.getvalue(), '')
self.assertIn('error', stderr.getvalue())

@mock.patch('http.server._make_server', wraps=server._make_server)
@mock.patch.object(HTTPServer, 'serve_forever')
def test_extra_response_headers_arg(self, _, mock_make_server):
server._main(
['-H', 'Set-Cookie', 'k=v', '-H', 'Set-Cookie', 'k2=v2:v3 v4', '8080']
)
# Get an instance of the server / RequestHandler by using
# the spied call args, then calling _make_server with them.
args, kwargs = mock_make_server.call_args
httpd = server._make_server(*args, **kwargs)
self.addCleanup(httpd.server_close)

# Ensure the RequestHandler class is passed the correct response
# headers
request_handler_class = httpd.RequestHandlerClass
with mock.patch.object(
request_handler_class, '__init__'
) as mock_handler_init:
mock_handler_init.return_value = None
# finish_request instantiates a request handler class,
# ensure extra_response_headers are passed to it
httpd.finish_request(mock.Mock(), '127.0.0.1')
mock_handler_init.assert_called_once_with(
mock.ANY, mock.ANY, mock.ANY,
directory=mock.ANY,
extra_response_headers=[
['Set-Cookie', 'k=v'], ['Set-Cookie', 'k2=v2:v3 v4']
]
)


class CommandLineRunTimeTestCase(unittest.TestCase):
served_data = os.urandom(32)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add a ``-H`` or ``--header`` CLI option to :program:`python -m http.server`. Contributed by
Anton I. Sipos.
Loading