private static PublicSuffixRule FindMatchingRule(List <string> domainLabels, PublicSuffixRuleCache ruleCache) { var ruleMatches = ruleCache.PublicSuffixRules.Where(r => r.AppliesTo(domainLabels)).ToList(); // If there is only one match, return it. if (ruleMatches.Count() == 1) { return(ruleMatches[0]); } // If more than one rule matches, the prevailing rule is the one which is an exception rule. var exceptionRules = ruleMatches.Where(r => r.Type == PublicSuffixRule.RuleType.Exception).ToList(); if (exceptionRules.Count() == 1) { return(exceptionRules[0]); } if (exceptionRules.Count() > 1) { throw new ApplicationException("Unexpectedly found multiple matching exception rules."); } // If there is no matching exception rule, the prevailing rule is the one with the most labels. var prevailingRule = ruleMatches.OrderByDescending(r => r.Labels.Count).Take(1).SingleOrDefault(); return(prevailingRule); }
public static bool TryParse(string rawDomainName, PublicSuffixRuleCache ruleCache, out DomainName domainName) { if (string.IsNullOrEmpty(rawDomainName) || !rawDomainName.Contains('.') || rawDomainName.StartsWith(".")) { domainName = new DomainName(rawDomainName, null, null); return(true); } try { rawDomainName = rawDomainName.ToLower(); // Split our domain into parts (based on the '.') // We'll be checking rules from the right-most part of the domain var domainLabels = rawDomainName.Trim().Split('.').ToList(); domainLabels.Reverse(); // If no rules match, the prevailing rule is "*" var prevailingRule = FindMatchingRule(domainLabels, ruleCache) ?? new PublicSuffixRule("*"); // If the prevailing rule is an exception rule, modify it by removing the leftmost label. if (prevailingRule.Type == PublicSuffixRule.RuleType.Exception) { var labels = prevailingRule.Labels; labels.Reverse(); labels.RemoveAt(0); prevailingRule = new PublicSuffixRule(string.Join(".", labels)); } // The public suffix is the set of labels from the domain which directly match the labels of the prevailing rule (joined by dots). var publicSuffix = Enumerable.Range(0, prevailingRule.Labels.Count).Aggregate(string.Empty, (current, i) => string.Format("{0}.{1}", domainLabels[i], current).Trim('.')); // The registered or registrable domain is the public suffix plus one additional label. var registrableDomain = string.Format("{0}.{1}", domainLabels[prevailingRule.Labels.Count], publicSuffix); domainName = new DomainName(rawDomainName, publicSuffix, registrableDomain); return(true); } catch { domainName = null; return(false); } }