一、前言
基于apache的commons-validator源码包中的org.apache.commons.validator.UrlValidator类,对URL地址进行有效验证isValid、是否有效授权isValidAuthority等操作。
二、源码说明
1.UrlValidator类
package org.apache.commons.validator;@b@@b@import java.io.Serializable;@b@import java.util.Arrays;@b@import java.util.HashSet;@b@import java.util.Set;@b@import org.apache.commons.validator.util.Flags;@b@import org.apache.oro.text.perl.Perl5Util;@b@@b@public class UrlValidator@b@ implements Serializable@b@{@b@ public static final int ALLOW_ALL_SCHEMES = 1;@b@ public static final int ALLOW_2_SLASHES = 2;@b@ public static final int NO_FRAGMENTS = 4;@b@ private static final String ALPHA_CHARS = "a-zA-Z";@b@ private static final String ALPHA_NUMERIC_CHARS = "a-zA-Z\\d";@b@ private static final String SPECIAL_CHARS = ";/@&=,.?:+$";@b@ private static final String VALID_CHARS = "[^\\s;/@&=,.?:+$]";@b@ private static final String SCHEME_CHARS = "a-zA-Z";@b@ private static final String AUTHORITY_CHARS = "a-zA-Z\\d\\-\\.";@b@ private static final String ATOM = "[^\\s;/@&=,.?:+$]+";@b@ private static final String URL_PATTERN = "/^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?/";@b@ private static final int PARSE_URL_SCHEME = 2;@b@ private static final int PARSE_URL_AUTHORITY = 4;@b@ private static final int PARSE_URL_PATH = 5;@b@ private static final int PARSE_URL_QUERY = 7;@b@ private static final int PARSE_URL_FRAGMENT = 9;@b@ private static final String SCHEME_PATTERN = "/^[a-zA-Z]/";@b@ private static final String AUTHORITY_PATTERN = "/^([a-zA-Z\\d\\-\\.]*)(:\\d*)?(.*)?/";@b@ private static final int PARSE_AUTHORITY_HOST_IP = 1;@b@ private static final int PARSE_AUTHORITY_PORT = 2;@b@ private static final int PARSE_AUTHORITY_EXTRA = 3;@b@ private static final String PATH_PATTERN = "/^(/[-\\w:@&?=+,.!/~*'%$]*)?$/";@b@ private static final String QUERY_PATTERN = "/^(.*)$/";@b@ private static final String LEGAL_ASCII_PATTERN = "/^[\\000-\\177]+$/";@b@ private static final String IP_V4_DOMAIN_PATTERN = "/^(\\d{1,3})[.](\\d{1,3})[.](\\d{1,3})[.](\\d{1,3})$/";@b@ private static final String DOMAIN_PATTERN = "/^[^\\s;/@&=,.?:+$]+(\\.[^\\s;/@&=,.?:+$]+)*$/";@b@ private static final String PORT_PATTERN = "/^:(\\d{1,5})$/";@b@ private static final String ATOM_PATTERN = "/([^\\s;/@&=,.?:+$]+)/";@b@ private static final String ALPHA_PATTERN = "/^[a-zA-Z]/";@b@ private Flags options;@b@ private Set allowedSchemes;@b@ protected String[] defaultSchemes;@b@@b@ public UrlValidator()@b@ {@b@ this(null);@b@ }@b@@b@ public UrlValidator(String[] schemes)@b@ {@b@ this(schemes, 0);@b@ }@b@@b@ public UrlValidator(int options)@b@ {@b@ this(null, options);@b@ }@b@@b@ public UrlValidator(String[] schemes, int options)@b@ {@b@ this.options = null;@b@@b@ this.allowedSchemes = new HashSet();@b@@b@ this.defaultSchemes = new String[] { "http", "https", "ftp" };@b@@b@ this.options = new Flags(options);@b@@b@ if (this.options.isOn(1L)) {@b@ return;@b@ }@b@@b@ if (schemes == null) {@b@ schemes = this.defaultSchemes;@b@ }@b@@b@ this.allowedSchemes.addAll(Arrays.asList(schemes));@b@ }@b@@b@ public boolean isValid(String value)@b@ {@b@ if (value == null) {@b@ return false;@b@ }@b@@b@ Perl5Util matchUrlPat = new Perl5Util();@b@ Perl5Util matchAsciiPat = new Perl5Util();@b@@b@ if (!(matchAsciiPat.match("/^[\\000-\\177]+$/", value))) {@b@ return false;@b@ }@b@@b@ if (!(matchUrlPat.match("/^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?/", value))) {@b@ return false;@b@ }@b@@b@ if (!(isValidScheme(matchUrlPat.group(2)))) {@b@ return false;@b@ }@b@@b@ if (!(isValidAuthority(matchUrlPat.group(4)))) {@b@ return false;@b@ }@b@@b@ if (!(isValidPath(matchUrlPat.group(5)))) {@b@ return false;@b@ }@b@@b@ if (!(isValidQuery(matchUrlPat.group(7)))) {@b@ return false;@b@ }@b@@b@ return (isValidFragment(matchUrlPat.group(9)));@b@ }@b@@b@ protected boolean isValidScheme(String scheme)@b@ {@b@ if (scheme == null) {@b@ return false;@b@ }@b@@b@ Perl5Util schemeMatcher = new Perl5Util();@b@ if (!(schemeMatcher.match("/^[a-zA-Z]/", scheme))) {@b@ return false;@b@ }@b@@b@ return ((!(this.options.isOff(1L))) || @b@ (this.allowedSchemes.contains(scheme)));@b@ }@b@@b@ protected boolean isValidAuthority(String authority)@b@ {@b@ if (authority == null) {@b@ return false;@b@ }@b@@b@ Perl5Util authorityMatcher = new Perl5Util();@b@ Perl5Util matchIPV4Pat = new Perl5Util();@b@@b@ if (!(authorityMatcher.match("/^([a-zA-Z\\d\\-\\.]*)(:\\d*)?(.*)?/", authority))) {@b@ return false;@b@ }@b@@b@ boolean ipV4Address = false;@b@ boolean hostname = false;@b@@b@ String hostIP = authorityMatcher.group(1);@b@ ipV4Address = matchIPV4Pat.match("/^(\\d{1,3})[.](\\d{1,3})[.](\\d{1,3})[.](\\d{1,3})$/", hostIP);@b@@b@ if (ipV4Address)@b@ {@b@ for (int i = 1; i <= 4; ++i) {@b@ String ipSegment = matchIPV4Pat.group(i);@b@ if ((ipSegment == null) || (ipSegment.length() <= 0))@b@ return false;@b@@b@ try@b@ {@b@ if (Integer.parseInt(ipSegment) > 255)@b@ return false;@b@ }@b@ catch (NumberFormatException e) {@b@ return false;@b@ }@b@ }@b@ }@b@ else@b@ {@b@ Perl5Util domainMatcher = new Perl5Util();@b@ hostname = domainMatcher.match("/^[^\\s;/@&=,.?:+$]+(\\.[^\\s;/@&=,.?:+$]+)*$/", hostIP);@b@ }@b@@b@ if (hostname) {@b@ String[] domainSegment = new String[10];@b@ boolean match = true;@b@ int segmentCount = 0;@b@ int segmentLength = 0;@b@ Perl5Util atomMatcher = new Perl5Util();@b@@b@ while (match) {@b@ match = atomMatcher.match("/([^\\s;/@&=,.?:+$]+)/", hostIP);@b@ if (match) {@b@ domainSegment[segmentCount] = atomMatcher.group(1);@b@ segmentLength = domainSegment[segmentCount].length() + 1;@b@ hostIP = (segmentLength >= hostIP.length()) ? "" : hostIP.substring(segmentLength);@b@@b@ ++segmentCount;@b@ }@b@ }@b@ String topLevel = domainSegment[(segmentCount - 1)];@b@ if ((topLevel.length() < 2) || (topLevel.length() > 4)) {@b@ return false;@b@ }@b@@b@ Perl5Util alphaMatcher = new Perl5Util();@b@ if (!(alphaMatcher.match("/^[a-zA-Z]/", topLevel.substring(0, 1)))) {@b@ return false;@b@ }@b@@b@ if (segmentCount < 2)@b@ return false;@b@@b@ }@b@@b@ if ((!(hostname)) && (!(ipV4Address))) {@b@ return false;@b@ }@b@@b@ String port = authorityMatcher.group(2);@b@ if (port != null) {@b@ Perl5Util portMatcher = new Perl5Util();@b@ if (!(portMatcher.match("/^:(\\d{1,5})$/", port)))@b@ return false;@b@@b@ }@b@@b@ String extra = authorityMatcher.group(3);@b@@b@ return (GenericValidator.isBlankOrNull(extra));@b@ }@b@@b@ protected boolean isValidPath(String path)@b@ {@b@ if (path == null) {@b@ return false;@b@ }@b@@b@ Perl5Util pathMatcher = new Perl5Util();@b@@b@ if (!(pathMatcher.match("/^(/[-\\w:@&?=+,.!/~*'%$]*)?$/", path))) {@b@ return false;@b@ }@b@@b@ int slash2Count = countToken("//", path);@b@ if ((this.options.isOff(2L)) && (slash2Count > 0)) {@b@ return false;@b@ }@b@@b@ int slashCount = countToken("/", path);@b@ int dot2Count = countToken("..", path);@b@@b@ return ((dot2Count <= 0) || @b@ (slashCount - slash2Count - 1 > dot2Count));@b@ }@b@@b@ protected boolean isValidQuery(String query)@b@ {@b@ if (query == null) {@b@ return true;@b@ }@b@@b@ Perl5Util queryMatcher = new Perl5Util();@b@ return queryMatcher.match("/^(.*)$/", query);@b@ }@b@@b@ protected boolean isValidFragment(String fragment)@b@ {@b@ if (fragment == null) {@b@ return true;@b@ }@b@@b@ return this.options.isOff(4L);@b@ }@b@@b@ protected int countToken(String token, String target)@b@ {@b@ int tokenIndex = 0;@b@ int count = 0;@b@ while (tokenIndex != -1) {@b@ tokenIndex = target.indexOf(token, tokenIndex);@b@ if (tokenIndex > -1) {@b@ ++tokenIndex;@b@ ++count;@b@ }@b@ }@b@ return count;@b@ }@b@}
2.Flags类
package org.apache.commons.validator.util;@b@@b@import java.io.Serializable;@b@@b@public class Flags@b@ implements Serializable@b@{@b@ private long flags = 0L;@b@@b@ public Flags()@b@ {@b@ }@b@@b@ public Flags(long flags)@b@ {@b@ this.flags = flags;@b@ }@b@@b@ public long getFlags()@b@ {@b@ return this.flags;@b@ }@b@@b@ public boolean isOn(long flag)@b@ {@b@ return ((this.flags & flag) > 0L);@b@ }@b@@b@ public boolean isOff(long flag)@b@ {@b@ return ((this.flags & flag) == 0L);@b@ }@b@@b@ public void turnOn(long flag)@b@ {@b@ this.flags |= flag;@b@ }@b@@b@ public void turnOff(long flag)@b@ {@b@ this.flags &= (flag ^ 0xFFFFFFFF);@b@ }@b@@b@ public void turnOffAll()@b@ {@b@ this.flags = 0L;@b@ }@b@@b@ public void clear()@b@ {@b@ this.flags = 0L;@b@ }@b@@b@ public void turnOnAll()@b@ {@b@ this.flags = 9223372036854775807L;@b@ }@b@@b@ public Object clone()@b@ {@b@ try@b@ {@b@ return super.clone();@b@ } catch (CloneNotSupportedException e) {@b@ throw new RuntimeException("Couldn't clone Flags object.");@b@ }@b@ }@b@@b@ public boolean equals(Object obj)@b@ {@b@ if (!(obj instanceof Flags)) {@b@ return false;@b@ }@b@@b@ if (obj == this) {@b@ return true;@b@ }@b@@b@ Flags f = (Flags)obj;@b@@b@ return (this.flags == f.flags);@b@ }@b@@b@ public int hashCode()@b@ {@b@ return (int)this.flags;@b@ }@b@@b@ public String toString()@b@ {@b@ StringBuffer bin = new StringBuffer(Long.toBinaryString(this.flags));@b@ for (int i = 64 - bin.length(); i > 0; --i)@b@ bin.insert(0, "0");@b@@b@ return bin.toString();@b@ }@b@}