Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f289084

Browse filesBrowse files
authored
bpo-24209: In http.server script, rely on getaddrinfo to bind to preferred address based on the bind parameter. (#11767)
In http.server script, rely on getaddrinfo to bind to preferred address based on the bind parameter. As a result, now IPv6 is used as the default (including IPv4 on dual-stack systems). Enhanced tests.
1 parent 2848d9d commit f289084
Copy full SHA for f289084

File tree

Expand file treeCollapse file tree

3 files changed

+76
-23
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+76
-23
lines changed

‎Lib/http/server.py

Copy file name to clipboardExpand all lines: Lib/http/server.py
+20-10Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,24 +1224,34 @@ def run_cgi(self):
12241224
self.log_message("CGI script exited OK")
12251225

12261226

1227+
def _get_best_family(*address):
1228+
infos = socket.getaddrinfo(
1229+
*address,
1230+
type=socket.SOCK_STREAM,
1231+
flags=socket.AI_PASSIVE,
1232+
)
1233+
family, type, proto, canonname, sockaddr = next(iter(infos))
1234+
return family, sockaddr
1235+
1236+
12271237
def test(HandlerClass=BaseHTTPRequestHandler,
12281238
ServerClass=ThreadingHTTPServer,
1229-
protocol="HTTP/1.0", port=8000, bind=""):
1239+
protocol="HTTP/1.0", port=8000, bind=None):
12301240
"""Test the HTTP request handler class.
12311241
12321242
This runs an HTTP server on port 8000 (or the port argument).
12331243
12341244
"""
1235-
server_address = (bind, port)
1236-
1237-
if ':' in bind:
1238-
ServerClass.address_family = socket.AF_INET6
1245+
ServerClass.address_family, addr = _get_best_family(bind, port)
12391246

12401247
HandlerClass.protocol_version = protocol
1241-
with ServerClass(server_address, HandlerClass) as httpd:
1242-
sa = httpd.socket.getsockname()
1243-
serve_message = "Serving HTTP on {host} port {port} (http://{host}:{port}/) ..."
1244-
print(serve_message.format(host=sa[0], port=sa[1]))
1248+
with ServerClass(addr, HandlerClass) as httpd:
1249+
host, port = httpd.socket.getsockname()[:2]
1250+
url_host = f'[{host}]' if ':' in host else host
1251+
print(
1252+
f"Serving HTTP on {host} port {port} "
1253+
f"(http://{url_host}:{port}/) ..."
1254+
)
12451255
try:
12461256
httpd.serve_forever()
12471257
except KeyboardInterrupt:
@@ -1254,7 +1264,7 @@ def test(HandlerClass=BaseHTTPRequestHandler,
12541264
parser = argparse.ArgumentParser()
12551265
parser.add_argument('--cgi', action='store_true',
12561266
help='Run as CGI Server')
1257-
parser.add_argument('--bind', '-b', default='', metavar='ADDRESS',
1267+
parser.add_argument('--bind', '-b', metavar='ADDRESS',
12581268
help='Specify alternate bind address '
12591269
'[default: all interfaces]')
12601270
parser.add_argument('--directory', '-d', default=os.getcwd(),

‎Lib/test/test_httpservers.py

Copy file name to clipboardExpand all lines: Lib/test/test_httpservers.py
+55-13Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,21 +1118,63 @@ def test_all(self):
11181118

11191119

11201120
class ScriptTestCase(unittest.TestCase):
1121+
1122+
def mock_server_class(self):
1123+
return mock.MagicMock(
1124+
return_value=mock.MagicMock(
1125+
__enter__=mock.MagicMock(
1126+
return_value=mock.MagicMock(
1127+
socket=mock.MagicMock(
1128+
getsockname=lambda: ('', 0),
1129+
),
1130+
),
1131+
),
1132+
),
1133+
)
1134+
1135+
@mock.patch('builtins.print')
1136+
def test_server_test_unspec(self, _):
1137+
mock_server = self.mock_server_class()
1138+
server.test(ServerClass=mock_server, bind=None)
1139+
self.assertIn(
1140+
mock_server.address_family,
1141+
(socket.AF_INET6, socket.AF_INET),
1142+
)
1143+
1144+
@mock.patch('builtins.print')
1145+
def test_server_test_localhost(self, _):
1146+
mock_server = self.mock_server_class()
1147+
server.test(ServerClass=mock_server, bind="localhost")
1148+
self.assertIn(
1149+
mock_server.address_family,
1150+
(socket.AF_INET6, socket.AF_INET),
1151+
)
1152+
1153+
ipv6_addrs = (
1154+
"::",
1155+
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
1156+
"::1",
1157+
)
1158+
1159+
ipv4_addrs = (
1160+
"0.0.0.0",
1161+
"8.8.8.8",
1162+
"127.0.0.1",
1163+
)
1164+
11211165
@mock.patch('builtins.print')
11221166
def test_server_test_ipv6(self, _):
1123-
mock_server = mock.MagicMock()
1124-
server.test(ServerClass=mock_server, bind="::")
1125-
self.assertEqual(mock_server.address_family, socket.AF_INET6)
1126-
1127-
mock_server.reset_mock()
1128-
server.test(ServerClass=mock_server,
1129-
bind="2001:0db8:85a3:0000:0000:8a2e:0370:7334")
1130-
self.assertEqual(mock_server.address_family, socket.AF_INET6)
1131-
1132-
mock_server.reset_mock()
1133-
server.test(ServerClass=mock_server,
1134-
bind="::1")
1135-
self.assertEqual(mock_server.address_family, socket.AF_INET6)
1167+
for bind in self.ipv6_addrs:
1168+
mock_server = self.mock_server_class()
1169+
server.test(ServerClass=mock_server, bind=bind)
1170+
self.assertEqual(mock_server.address_family, socket.AF_INET6)
1171+
1172+
@mock.patch('builtins.print')
1173+
def test_server_test_ipv4(self, _):
1174+
for bind in self.ipv4_addrs:
1175+
mock_server = self.mock_server_class()
1176+
server.test(ServerClass=mock_server, bind=bind)
1177+
self.assertEqual(mock_server.address_family, socket.AF_INET)
11361178

11371179

11381180
def test_main(verbose=None):
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
In http.server script, rely on getaddrinfo to bind to preferred address based on the bind parameter. Now default bind or binding to a name may bind to IPv6 or dual-stack, depending on the environment.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.