Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 6 additions & 2 deletions Doc/library/http.server.rst
Original file line number Diff line number Diff line change
Expand Up @@ -410,14 +410,18 @@ the previous example, this serves files relative to the current directory::
python -m http.server 8000

By default, server binds itself to all interfaces. The option ``-b/--bind``
specifies a specific address to which it should bind. For example, the
following command causes the server to bind to localhost only::
specifies a specific address to which it should bind. Both IPv4 and IPv6
addresses are supported. For example, the following command causes the server
to bind to localhost only::

python -m http.server 8000 --bind 127.0.0.1

.. versionadded:: 3.4
``--bind`` argument was introduced.

.. versionadded:: 3.8
``--bind`` argument enhanced to support IPv6

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::
Expand Down
3 changes: 3 additions & 0 deletions Lib/http/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,9 @@ def test(HandlerClass=BaseHTTPRequestHandler,
"""
server_address = (bind, port)

if ':' in bind:

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.

Although : is sufficient to indicate that the family should be INET6, it's not necessary. For example, one could specify localhost, which may resolve to 127.0.0.1 or ::1 or both. Or one may bind to '' or None, which will resolve to all interfaces. In that case, INET6 or AF_UNSPEC might be more appropriate.

Plus, I'd prefer that the default behavior should be to bind to IPv6, which in many cases also supports binding to IPv4 (at least for ::, all interfaces), and only fall back to the older IPv4 standard when necessary or directed. I do say though, with as few people familiar with IPv6, it's probably a hard sell to make it the default, even if that's eventually where the code should end up and it's been more than a decade in the transition.

ServerClass.address_family = socket.AF_INET6

HandlerClass.protocol_version = protocol
with ServerClass(server_address, HandlerClass) as httpd:
sa = httpd.socket.getsockname()
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_httpservers.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from http import server, HTTPStatus

import os
import socket
import sys
import re
import base64
Expand Down Expand Up @@ -1116,6 +1117,24 @@ def test_all(self):
self.assertCountEqual(server.__all__, expected)


class ScriptTestCase(unittest.TestCase):
@mock.patch('builtins.print')
def test_server_test_ipv6(self, _):
mock_server = mock.MagicMock()
server.test(ServerClass=mock_server, bind="::")
self.assertEqual(mock_server.address_family, socket.AF_INET6)

mock_server.reset_mock()
server.test(ServerClass=mock_server,
bind="2001:0db8:85a3:0000:0000:8a2e:0370:7334")
self.assertEqual(mock_server.address_family, socket.AF_INET6)

mock_server.reset_mock()
server.test(ServerClass=mock_server,
bind="::1")
self.assertEqual(mock_server.address_family, socket.AF_INET6)


def test_main(verbose=None):
cwd = os.getcwd()
try:
Expand All @@ -1127,6 +1146,7 @@ def test_main(verbose=None):
CGIHTTPServerTestCase,
SimpleHTTPRequestHandlerTestCase,
MiscTestCase,
ScriptTestCase
)
finally:
os.chdir(cwd)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Adds IPv6 support when invoking http.server directly.