Skip to content

Instantly share code, notes, and snippets.

@joydeepsaha05
Created September 6, 2018 14:37
Show Gist options
  • Save joydeepsaha05/b2dbf2de44cf6cd025f74b3735649d82 to your computer and use it in GitHub Desktop.
Save joydeepsaha05/b2dbf2de44cf6cd025f74b3735649d82 to your computer and use it in GitHub Desktop.
Checks whether the given URL is valid. Extracted from https://github.com/karan/validator.dart to support Dart2.
class URLValidator {
RegExp _ipv4Maybe =
new RegExp(r'^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$');
RegExp _ipv6 =
new RegExp(r'^::|^::1|^([a-fA-F0-9]{1,4}::?){1,7}([a-fA-F0-9]{1,4})$');
_shift(List l) {
if (l.length >= 1) {
var first = l.first;
l.removeAt(0);
return first;
}
return null;
}
Map _merge(Map obj, defaults) {
if (obj == null) {
obj = new Map();
}
defaults.forEach((key, val) => obj.putIfAbsent(key, () => val));
return obj;
}
/// check if the string matches the comparison
bool equals(String str, comparison) {
return str == comparison.toString();
}
/// check if the string contains the seed
bool contains(String str, seed) {
return str.indexOf(seed.toString()) >= 0;
}
/// check if string matches the pattern.
bool matches(String str, pattern) {
RegExp re = new RegExp(pattern);
return re.hasMatch(str);
}
/// check if the string is a URL
///
/// `options` is a `Map` which defaults to
/// `{ 'protocols': ['http','https','ftp'], 'require_tld': true,
/// 'require_protocol': false, 'allow_underscores': false,
/// 'host_whitelist': false, 'host_blacklist': false }`.
bool isURL(String str, [Map options]) {
if (str == null ||
str.length == 0 ||
str.length > 2083 ||
str.indexOf('mailto:') == 0) {
return false;
}
Map defaultUrlOptions = {
'protocols': ['http', 'https', 'ftp'],
'require_tld': true,
'require_protocol': false,
'allow_underscores': false
};
options = _merge(options, defaultUrlOptions);
var protocol,
user,
auth,
host,
hostname,
port,
portStr,
path,
query,
hash,
split;
// check protocol
split = str.split('://');
if (split.length > 1) {
protocol = _shift(split);
if (options['protocols'].indexOf(protocol) == -1) {
return false;
}
} else if (options['require_protocols'] == true) {
return false;
}
str = split.join('://');
// check hash
split = str.split('#');
str = _shift(split);
hash = split.join('#');
if (hash != null && hash != "" && new RegExp(r'\s').hasMatch(hash)) {
return false;
}
// check query params
split = str.split('?');
str = _shift(split);
query = split.join('?');
if (query != null && query != "" && new RegExp(r'\s').hasMatch(query)) {
return false;
}
// check path
split = str.split('/');
str = _shift(split);
path = split.join('/');
if (path != null && path != "" && new RegExp(r'\s').hasMatch(path)) {
return false;
}
// check auth type urls
split = str.split('@');
if (split.length > 1) {
auth = _shift(split);
if (auth.indexOf(':') >= 0) {
auth = auth.split(':');
user = _shift(auth);
if (!new RegExp(r'^\S+$').hasMatch(user)) {
return false;
}
if (!new RegExp(r'^\S*$').hasMatch(user)) {
return false;
}
}
}
// check hostname
hostname = split.join('@');
split = hostname.split(':');
host = _shift(split);
if (split.length > 0) {
portStr = split.join(':');
try {
port = int.parse(portStr, radix: 10);
} catch (e) {
return false;
}
if (!new RegExp(r'^[0-9]+$').hasMatch(portStr) ||
port <= 0 ||
port > 65535) {
return false;
}
}
if (!isIP(host) && !isFQDN(host, options) && host != 'localhost') {
return false;
}
if (options['host_whitelist'] == true &&
options['host_whitelist'].indexOf(host) == -1) {
return false;
}
if (options['host_blacklist'] == true &&
options['host_blacklist'].indexOf(host) != -1) {
return false;
}
return true;
}
/// check if the string is an IP (version 4 or 6)
///
/// `version` is a String or an `int`.
bool isIP(String str, [version]) {
version = version.toString();
if (version == 'null') {
return isIP(str, 4) || isIP(str, 6);
} else if (version == '4') {
if (!_ipv4Maybe.hasMatch(str)) {
return false;
}
var parts = str.split('.');
parts.sort((a, b) => int.parse(a) - int.parse(b));
return int.parse(parts[3]) <= 255;
}
return version == '6' && _ipv6.hasMatch(str);
}
/// check if the string is a fully qualified domain name (e.g. domain.com).
///
/// `options` is a `Map` which defaults to `{ 'require_tld': true, 'allow_underscores': false }`.
bool isFQDN(str, [options]) {
Map defaultFqdnOptions = {'require_tld': true, 'allow_underscores': false};
options = _merge(options, defaultFqdnOptions);
List parts = str.split('.');
if (options['require_tld']) {
var tld = parts.removeLast();
if (parts.length == 0 || !new RegExp(r'^[a-z]{2,}$').hasMatch(tld)) {
return false;
}
}
for (var part, i = 0; i < parts.length; i++) {
part = parts[i];
if (options['allow_underscores']) {
if (part.indexOf('__') >= 0) {
return false;
}
}
if (!new RegExp(r'^[a-z\\u00a1-\\uffff0-9-]+$').hasMatch(part)) {
return false;
}
if (part[0] == '-' ||
part[part.length - 1] == '-' ||
part.indexOf('---') >= 0) {
return false;
}
}
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment