We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent 5a4ad6b commit f4b84c2Copy full SHA for f4b84c2
src/rfc3986/misc.py
@@ -58,6 +58,7 @@
58
abnf_regexp.PORT_RE))
59
60
61
+HOST_MATCHER = re.compile('^' + abnf_regexp.HOST_RE + '$')
62
IPv4_MATCHER = re.compile('^' + abnf_regexp.IPv4_RE + '$')
63
IPv6_MATCHER = re.compile(r'^\[' + abnf_regexp.IPv6_ADDRZ_RFC4007_RE + r'\]$')
64
src/rfc3986/uri.py
@@ -171,12 +171,6 @@ def authority_info(self):
171
# valid bytes, it is an InvalidAuthority.
172
raise exc.InvalidAuthority(self.authority.encode(self.encoding))
173
174
- if (host and misc.IPv6_MATCHER.match(host) and not
175
- misc.IPv6_NO_RFC4007_MATCHER.match(host)):
176
- # If it's an IPv6 address that has RFC 4007 IPv6
177
- # Zone IDs then it's invalid.
178
- raise exc.InvalidAuthority(self.authority.encode(self.encoding))
179
-
180
return matches
181
182
@property
src/rfc3986/validators.py
@@ -304,6 +304,24 @@ def authority_is_valid(authority, host=None, require=False):
304
bool
305
"""
306
validated = is_valid(authority, misc.SUBAUTHORITY_MATCHER, require)
307
+ if validated and host is not None:
308
+ return host_is_valid(host, require)
309
+ return validated
310
+
311
312
+def host_is_valid(host, require=False):
313
+ """Determine if the host string is valid.
314
315
+ :param str host:
316
+ The host to validate.
317
+ :param bool require:
318
+ (optional) Specify if host must not be None.
319
+ :returns:
320
+ ``True`` if valid, ``False`` otherwise
321
+ :rtype:
322
+ bool
323
+ """
324
+ validated = is_valid(host, misc.HOST_MATCHER, require)
325
if validated and host is not None and misc.IPv4_MATCHER.match(host):
326
return valid_ipv4_host_address(host)
327
elif validated and host is not None and misc.IPv6_MATCHER.match(host):
@@ -397,7 +415,9 @@ def subauthority_component_is_valid(uri, component):
397
415
398
416
# If we can parse the authority into sub-components and we're not
399
417
# validating the port, we can assume it's valid.
400
- if component != 'port':
418
+ if component == 'host':
419
+ return host_is_valid(subauthority_dict['host'], require=True)
420
+ elif component != 'port':
401
421
return True
402
422
403
423
try:
tests/conftest.py
@@ -32,9 +32,7 @@
32
'[FF02::3::5]', # IPv6 can only have one ::
33
'[FADF:01]', # Not properly compacted (missing a :)
34
'[FADF:01%en0]', # Not properly compacted (missing a :), Invalid ZoneID
35
- '[FADF::01%en0]', # ZoneID is per RFC 4007
36
- '[FADF::01%]', # Invalid ZoneID separator and no ZoneID
37
- '[FADF::01%25]', # Missing ZoneID in RFC 6974, is 25 in RFC 4007
+ '[FADF::01%]', # Empty Zone ID
38
'localhost:80:80:80', # Too many ports
39
'256.256.256.256', # Invalid IPv4 Address
40
SNOWMAN.decode('utf-8')
tests/test_builder.py
@@ -67,16 +67,22 @@ def test_add_credentials_requires_username():
67
builder.URIBuilder().add_credentials(None, None)
68
69
70
-@pytest.mark.parametrize('hostname', [
71
- 'google.com',
72
- 'GOOGLE.COM',
73
- 'gOOgLe.COM',
74
- 'goOgLE.com',
75
-])
76
-def test_add_host(hostname):
+@pytest.mark.parametrize(
+ ['hostname', 'expected_hostname'],
+ [
+ ('google.com', 'google.com'),
+ ('GOOGLE.COM', 'google.com'),
+ ('gOOgLe.COM', 'google.com'),
+ ('goOgLE.com', 'google.com'),
77
+ ('[::ff%etH0]', '[::ff%25etH0]'),
78
+ ('[::ff%25etH0]', '[::ff%25etH0]'),
79
+ ('[::FF%etH0]', '[::ff%25etH0]'),
80
+ ]
81
+)
82
+def test_add_host(hostname, expected_hostname):
83
"""Verify we normalize hostnames in add_host."""
84
uribuilder = builder.URIBuilder().add_host(hostname)
- assert uribuilder.host == 'google.com'
85
+ assert uribuilder.host == expected_hostname
86
87
88
@pytest.mark.parametrize('port', [
tests/test_normalizers.py
@@ -67,10 +67,17 @@ def test_hostname_normalization():
URIReference(None, 'example.com', None, None, None))
-def test_authority_normalization():
+ ['authority', 'expected_authority'],
+ ('user%[email protected]', 'user%[email protected]'),
+ ('[::1%eth0]', '[::1%25eth0]')
+def test_authority_normalization(authority, expected_authority):
uri = URIReference(
- None, 'user%[email protected]', None, None, None).normalize()
- assert uri.authority == 'user%[email protected]'
+ None, authority, None, None, None).normalize()
+ assert uri.authority == expected_authority
def test_fragment_normalization():
tests/test_validators.py
@@ -235,3 +235,21 @@ def test_invalid_uri_with_invalid_path(invalid_uri):
235
validators.Validator().check_validity_of(
236
'host', 'path',
237
).validate(uri)
238
239
240
+def test_validating_rfc_4007_ipv6_zone_ids():
241
+ """Verify that RFC 4007 IPv6 Zone IDs are invalid
242
+ host/authority but after normalization are valid
243
244
+ uri = rfc3986.uri_reference("http://[::1%eth0]")
245
+ with pytest.raises(exceptions.InvalidComponentsError):
246
+ validators.Validator().check_validity_of(
247
+ 'host'
248
+ ).validate(uri)
249
250
+ uri = uri.normalize()
251
+ assert uri.host == '[::1%25eth0]'
252
253
254
255
0 commit comments