internal bool Contains(Uri url) {
if (url.Scheme != this.Scheme) {
return false;
}
if (url.Port != this.Port) {
return false;
}
if (!this.DomainWildcard) {
if (url.Host != this.Host) {
return false;
}
} else {
Debug.Assert(!string.IsNullOrEmpty(this.Host), "The host part of the Regex should evaluate to at least one char for successful parsed trust roots.");
string[] host_parts = this.Host.Split('.');
string[] url_parts = url.Host.Split('.');
// If the domain containing the wildcard has more parts than the URL to match against,
// it naturally can't be valid.
// Unless *.example.com actually matches example.com too.
if (host_parts.Length > url_parts.Length) {
return false;
}
// Compare last part first and move forward.
// Maybe could be done by using EndsWith, but piecewies helps ensure that
// *.my.com doesn't match ohmeohmy.com but can still match my.com.
for (int i = 0; i < host_parts.Length; i++) {
string hostPart = host_parts[host_parts.Length - 1 - i];
string urlPart = url_parts[url_parts.Length - 1 - i];
if (!string.Equals(hostPart, urlPart, StringComparison.OrdinalIgnoreCase)) {
return false;
}
}
}
// If path matches or is specified to root ...
// (deliberately case sensitive to protect security on case sensitive systems)
if (this.PathAndQuery.Equals(url.PathAndQuery, StringComparison.Ordinal)
|| this.PathAndQuery.Equals("/", StringComparison.Ordinal)) {
return true;
}
// If trust root has a longer path, the return URL must be invalid.
if (this.PathAndQuery.Length > url.PathAndQuery.Length) {
return false;
}
// The following code assures that http://example.com/directory isn't below http://example.com/dir,
// but makes sure http://example.com/dir/ectory is below http://example.com/dir
int path_len = this.PathAndQuery.Length;
string url_prefix = url.PathAndQuery.Substring(0, path_len);
if (this.PathAndQuery != url_prefix) {
return false;
}
// If trust root includes a query string ...
if (this.PathAndQuery.Contains("?")) {
// ... make sure return URL begins with a new argument
return url.PathAndQuery[path_len] == '&';
}
// Or make sure a query string is introduced or a path below trust root
return this.PathAndQuery.EndsWith("/", StringComparison.Ordinal)
|| url.PathAndQuery[path_len] == '?'
|| url.PathAndQuery[path_len] == '/';
}