diff --git a/src/validators/hostname.py b/src/validators/hostname.py index bdf6bdb0..25dc53dd 100644 --- a/src/validators/hostname.py +++ b/src/validators/hostname.py @@ -29,6 +29,20 @@ def _simple_hostname_regex(): return re.compile(r"^(?!-)[a-z0-9](?:[a-z0-9-]{0,59}[a-z0-9])?(? 1: + value = value[:-1] + return _simple_hostname_regex().match(value) + + def _port_validator(value: str): """Returns host segment if port is valid.""" if value.count("]:") == 1: @@ -115,14 +129,14 @@ def hostname( if may_have_port and (host_seg := _port_validator(value)): return ( - (_simple_hostname_regex().match(host_seg) if maybe_simple else False) + (_simple_hostname_match(host_seg, rfc_1034) if maybe_simple else False) or domain(host_seg, consider_tld=consider_tld, rfc_1034=rfc_1034, rfc_2782=rfc_2782) or (False if skip_ipv4_addr else ipv4(host_seg, cidr=False, private=private)) or (False if skip_ipv6_addr else ipv6(host_seg, cidr=False)) ) return ( - (_simple_hostname_regex().match(value) if maybe_simple else False) + (_simple_hostname_match(value, rfc_1034) if maybe_simple else False) or domain(value, consider_tld=consider_tld, rfc_1034=rfc_1034, rfc_2782=rfc_2782) or (False if skip_ipv4_addr else ipv4(value, cidr=False, private=private)) or (False if skip_ipv6_addr else ipv6(value, cidr=False)) diff --git a/tests/test_hostname.py b/tests/test_hostname.py index 6ff40406..382b5b9b 100644 --- a/tests/test_hostname.py +++ b/tests/test_hostname.py @@ -30,6 +30,9 @@ ("[dead:beef:0:0:0:0000:42:1]:5731", False, False), ("[0:0:0:0:0:ffff:1.2.3.4]:80", False, False), ("[0:a:b:c:d:e:f::]:53", False, False), + # bare single-label name with the RFC 1034 trailing dot, GH-442 + ("yu.", True, False), + ("yu.:443", True, False), ], ) def test_returns_true_on_valid_hostname(value: str, rfc_1034: bool, rfc_2782: bool): @@ -60,6 +63,10 @@ def test_returns_true_on_valid_hostname(value: str, rfc_1034: bool, rfc_2782: bo ("[dead:beef:0:-:0:-:42:1]:5731", False, False), ("[0:0:0:0:0:ffff:1.2.3.4]:-65538", False, False), ("[0:&:b:c:@:e:f:::9999", False, False), + # bad (trailing dot only allowed when rfc_1034 is requested) + ("yu.", False, False), + # bad (a lone dot has no label to strip down to) + (".", True, False), ], ) def test_returns_failed_validation_on_invalid_hostname(value: str, rfc_1034: bool, rfc_2782: bool):