@@ -67,10 +67,31 @@ } - (instancetype)of_initWithCharacterSet: (OFCharacterSet *)characterSet OF_METHOD_FAMILY(init); @end + +bool +of_url_is_ipv6_host(OFString *host) +{ + const char *UTF8String = host.UTF8String; + bool hasColon = false; + + while (*UTF8String != '\0') { + if (!of_ascii_isdigit(*UTF8String) && *UTF8String != ':' && + (*UTF8String < 'a' || *UTF8String > 'f') && + (*UTF8String < 'A' || *UTF8String > 'F')) + return false; + + if (*UTF8String == ':') + hasColon = true; + + UTF8String++; + } + + return hasColon; +} @implementation OFURLAllowedCharacterSetBase - (instancetype)init { OF_INVALID_INIT_METHOD @@ -829,10 +850,21 @@ return _URLEncodedScheme; } - (OFString *)host { + if ([_URLEncodedHost hasPrefix: @"["] && + [_URLEncodedHost hasSuffix: @"]"]) { + OFString *host = [_URLEncodedHost substringWithRange: + of_range(1, _URLEncodedHost.length - 2)]; + + if (!of_url_is_ipv6_host(host)) + @throw [OFInvalidArgumentException exception]; + + return host; + } + return _URLEncodedHost.stringByURLDecoding; } - (OFString *)URLEncodedHost {