Skip to content

Commit 8f1721d

Browse files
juangjAutomatedTester
authored andcommitted
Fix some more IPv6 stuff.
utils.is_connectable() will try every IP to which the 'host' parameter resolves, so on dual-stack hosts it should still find the target server even if the target is only listening on one of IPv4 and IPv6.
1 parent 5e6de50 commit 8f1721d

File tree

3 files changed

+57
-56
lines changed

3 files changed

+57
-56
lines changed

py/selenium/webdriver/common/service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def service_url(self):
4141
"""
4242
Gets the url of the Service
4343
"""
44-
return "http://localhost:%d" % self.port
44+
return "http://%s" % utils.join_host_port('localhost', self.port)
4545

4646
def command_line_args(self):
4747
raise NotImplemented("This method needs to be implemented in a sub class")
@@ -100,7 +100,7 @@ def send_remote_shutdown_command(self):
100100
URLError = urllib2.URLError
101101

102102
try:
103-
url_request.urlopen("http://127.0.0.1:%d/shutdown" % self.port)
103+
url_request.urlopen("%s/shutdown" % self.service_url)
104104
except URLError:
105105
return
106106
count = 0

py/selenium/webdriver/common/utils.py

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
"""
1919
The Utils methods.
2020
"""
21-
2221
import socket
2322
from selenium.webdriver.common.keys import Keys
2423

@@ -40,22 +39,68 @@ def free_port():
4039
free_socket.close()
4140
return port
4241

43-
def is_connectable(port):
42+
def resolve_ip(host):
43+
"""Resolve a hostname to an IP, preferring IPv4 addresses.
44+
45+
We prefer IPv4 so that we don't change behavior from previous IPv4-only
46+
implementations, and because some drivers (e.g., FirefoxDriver) do not
47+
support IPv6 connections.
48+
49+
:Args:
50+
- host - A hostname.
51+
52+
:Returns:
53+
A single IP address, as a string. If any IPv4 address is found, one is
54+
returned. Otherwise, if any IPv6 address is found, one is returned. If
55+
neither, then None is returned.
56+
57+
"""
58+
try:
59+
addrinfos = socket.getaddrinfo(host, None)
60+
except socket.gaierror:
61+
return None
62+
63+
ip = None
64+
for family, _, _, _, sockaddr in addrinfos:
65+
if family == socket.AF_INET:
66+
return sockaddr[0]
67+
if not ip and family == socket.AF_INET6:
68+
ip = sockaddr[0]
69+
return ip
70+
71+
72+
def join_host_port(host, port):
73+
"""Joins a hostname and port together.
74+
75+
This is a minimal implementation intended to cope with IPv6 literals. For
76+
example, _join_host_port('::1', 80) == '[::1]:80'.
77+
78+
:Args:
79+
- host - A hostname.
80+
- port - An integer port.
81+
82+
"""
83+
if ':' in host and not host.startswith('['):
84+
return '[%s]:%d' % (host, port)
85+
return '%s:%d' % (host, port)
86+
87+
88+
def is_connectable(port, host="localhost"):
4489
"""
4590
Tries to connect to the server at port to see if it is running.
4691
4792
:Args:
4893
- port: The port to connect.
4994
"""
95+
socket_ = None
5096
try:
51-
socket_ = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
52-
socket_.settimeout(1)
53-
socket_.connect(("127.0.0.1", port))
97+
socket_ = socket.create_connection((host, port), 1)
5498
result = True
5599
except socket.error:
56100
result = False
57101
finally:
58-
socket_.close()
102+
if socket_:
103+
socket_.close()
59104
return result
60105

61106
def is_url_connectable(port):

py/selenium/webdriver/remote/remote_connection.py

Lines changed: 4 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -29,59 +29,14 @@
2929
import urllib2 as url_request
3030
import urlparse as parse
3131

32+
from selenium.webdriver.common import utils as common_utils
3233
from .command import Command
3334
from .errorhandler import ErrorCode
3435
from . import utils
3536

3637
LOGGER = logging.getLogger(__name__)
3738

3839

39-
def _resolve_ip(host):
40-
"""Resolve a hostname to an IP, preferring IPv4 addresses.
41-
42-
We prefer IPv4 so that we don't change behavior from previous IPv4-only
43-
implementations, and because some drivers (e.g., FirefoxDriver) do not support
44-
IPv6 connections.
45-
46-
:Args:
47-
- host - A hostname.
48-
49-
:Returns:
50-
A single IP address, as a string. If any IPv4 address is found, one is
51-
returned. Otherwise, if any IPv6 address is found, one is returned. If
52-
neither, then None is returned.
53-
54-
"""
55-
try:
56-
addrinfos = socket.getaddrinfo(host, None)
57-
except socket.gaierror:
58-
return None
59-
60-
ip = None
61-
for family, _, _, _, sockaddr in addrinfos:
62-
if family == socket.AF_INET:
63-
return sockaddr[0]
64-
if not ip and family == socket.AF_INET6:
65-
ip = sockaddr[0]
66-
return ip
67-
68-
69-
def _join_host_port(host, port):
70-
"""Joins a hostname and port together.
71-
72-
This is a minimal implementation intended to cope with IPv6 literals. For
73-
example, _join_host_port('::1', 80) == '[::1]:80'.
74-
75-
:Args:
76-
- host - A hostname.
77-
- port - An integer port.
78-
79-
"""
80-
if ':' in host and not host.startswith('['):
81-
return '[%s]:%d' % (host, port)
82-
return '%s:%d' % (host, port)
83-
84-
8540
class Request(url_request.Request):
8641
"""
8742
Extends the url_request.Request to support all HTTP request types.
@@ -213,12 +168,13 @@ def __init__(self, remote_server_addr, keep_alive=False, resolve_ip=True):
213168
parsed_url = parse.urlparse(remote_server_addr)
214169
addr = ""
215170
if parsed_url.hostname and resolve_ip:
216-
ip = _resolve_ip(parsed_url.hostname)
171+
ip = common_utils.resolve_ip(parsed_url.hostname)
217172
if ip:
218173
netloc = ip
219174
addr = netloc
220175
if parsed_url.port:
221-
netloc = _join_host_port(netloc, parsed_url.port)
176+
netloc = common_utils.join_host_port(netloc,
177+
parsed_url.port)
222178
if parsed_url.username:
223179
auth = parsed_url.username
224180
if parsed_url.password:

0 commit comments

Comments
 (0)