/// <summary> /// Gets the list of TLD rules from the cache /// </summary> /// <returns></returns> private IDictionary <TLDRule.RuleType, IDictionary <string, TLDRule> > GetTLDRules() { var results = new Dictionary <TLDRule.RuleType, IDictionary <string, TLDRule> >(); var rules = Enum.GetValues(typeof(TLDRule.RuleType)).Cast <TLDRule.RuleType>(); foreach (var rule in rules) { results[rule] = new Dictionary <string, TLDRule>(StringComparer.InvariantCultureIgnoreCase); } var ruleStrings = ReadRulesData(); // Strip out any lines that are: // a.) A comment // b.) Blank foreach (var ruleString in ruleStrings.Where(ruleString => !ruleString.StartsWith("//", StringComparison.InvariantCultureIgnoreCase) && ruleString.Trim().Length != 0)) { var result = new TLDRule(ruleString); results[result.Type][result.Name] = result; } // Return our results: Debug.WriteLine(string.Format("Loaded {0} rules into cache.", results.Values.Sum(r => r.Values.Count))); return(results); }
/// <summary> /// Constructs a DomainName object from its 3 parts /// </summary> /// <param name="TLD">The top-level domain</param> /// <param name="SLD">The second-level domain</param> /// <param name="SubDomain">The subdomain portion</param> /// <param name="TLDRule">The rule used to parse the domain</param> private DomainName(string TLD, string SLD, string SubDomain, TLDRule TLDRule) { this._tld = TLD; this._domain = SLD; this._subDomain = SubDomain; this._tldRule = TLDRule; }
/// <summary> /// Converts the string representation of a domain to its DomainName equivalent. A return value /// indicates whether the operation succeeded. /// </summary> /// <param name="domainString"></param> /// <param name="result"></param> /// <returns></returns> public static bool TryParse(string domainString, out DomainName result) { bool retval = false; // Our temporary domain parts: string _tld = string.Empty; string _sld = string.Empty; string _subdomain = string.Empty; TLDRule _tldrule = null; result = null; try { // Try parsing the domain name ... this might throw formatting exceptions ParseDomainName(domainString, out _tld, out _sld, out _subdomain, out _tldrule); // Construct a new DomainName object and return it result = new DomainName(_tld, _sld, _subdomain, _tldrule); // Return 'true' retval = true; } catch { // Looks like something bad happened -- return 'false' retval = false; } return(retval); }
/// <summary> /// Finds matching rule for a domain. If no rule is found, /// returns a null TLDRule object /// </summary> /// <param name="domainString"></param> /// <returns></returns> private static TLDRule FindMatchingTLDRule(string domainString) { // Split our domain into parts (based on the '.') // ...Put these parts in a list // ...Make sure these parts are in reverse order (we'll be checking rules from the right-most pat of the domain) List <string> lstDomainParts = domainString.Split('.').ToList <string>(); lstDomainParts.Reverse(); // Begin building our partial domain to check rules with: string checkAgainst = string.Empty; // Our 'matches' collection: List <TLDRule> ruleMatches = new List <TLDRule>(); foreach (string domainPart in lstDomainParts) { // Add on our next domain part: checkAgainst = string.Format("{0}.{1}", domainPart, checkAgainst); // If we end in a period, strip it off: if (checkAgainst.EndsWith(".")) { checkAgainst = checkAgainst.Substring(0, checkAgainst.Length - 1); } var rules = Enum.GetValues(typeof(TLDRule.RuleType)).Cast <TLDRule.RuleType>(); var ruleList = TLDRulesCache.Instance.GetTLDRuleList(); foreach (var rule in rules) { // Try to match rule: TLDRule result; if (ruleList[rule].TryGetValue(checkAgainst, out result)) { ruleMatches.Add(result); } Debug.WriteLine(string.Format("Domain part {0} matched {1} {2} rules", checkAgainst, result == null ? 0 : 1, rule)); } } // Sort our matches list (longest rule wins, according to : var results = from match in ruleMatches orderby match.Name.Length descending select match; // Take the top result (our primary match): TLDRule primaryMatch = results.Take(1).SingleOrDefault(); if (primaryMatch != null) { Debug.WriteLine( string.Format("Looks like our match is: {0}, which is a(n) {1} rule.", primaryMatch.Name, primaryMatch.Type) ); } else { Debug.WriteLine( string.Format("No rules matched domain: {0}", domainString) ); } return(primaryMatch); }
/// <summary> /// Converts the string representation of a domain to it's 3 distinct components: /// Top Level Domain (TLD), Second Level Domain (SLD), and subdomain information /// </summary> /// <param name="domainString">The domain to parse</param> /// <param name="TLD"></param> /// <param name="SLD"></param> /// <param name="SubDomain"></param> /// <param name="MatchingRule"></param> private static void ParseDomainName(string domainString, out string TLD, out string SLD, out string SubDomain, out TLDRule MatchingRule) { TLD = string.Empty; SLD = string.Empty; SubDomain = string.Empty; MatchingRule = null; // If the fqdn is empty, we have a problem already if (domainString.Trim() == string.Empty) { throw new ArgumentException("The domain cannot be blank"); } // Next, find the matching rule: MatchingRule = FindMatchingTLDRule(domainString); // At this point, no rules match, we have a problem if (MatchingRule == null) { throw new FormatException("The domain does not have a recognized TLD"); } // Based on the tld rule found, get the domain (and possibly the subdomain) string tempSudomainAndDomain = string.Empty; int tldIndex = 0; // First, determine what type of rule we have, and set the TLD accordingly switch (MatchingRule.Type) { case TLDRule.RuleType.Normal: tldIndex = domainString.LastIndexOf("." + MatchingRule.Name, StringComparison.InvariantCultureIgnoreCase); tempSudomainAndDomain = domainString.Substring(0, tldIndex); TLD = domainString.Substring(tldIndex + 1); break; case TLDRule.RuleType.Wildcard: // This finds the last portion of the TLD... tldIndex = domainString.LastIndexOf("." + MatchingRule.Name, StringComparison.InvariantCultureIgnoreCase); tempSudomainAndDomain = domainString.Substring(0, tldIndex); // But we need to find the wildcard portion of it: tldIndex = tempSudomainAndDomain.LastIndexOf(".", StringComparison.InvariantCultureIgnoreCase); tempSudomainAndDomain = domainString.Substring(0, tldIndex); TLD = domainString.Substring(tldIndex + 1); break; case TLDRule.RuleType.Exception: tldIndex = domainString.LastIndexOf(".", StringComparison.InvariantCultureIgnoreCase); tempSudomainAndDomain = domainString.Substring(0, tldIndex); TLD = domainString.Substring(tldIndex + 1); break; } // See if we have a subdomain: List <string> lstRemainingParts = new List <string>(tempSudomainAndDomain.Split('.')); // If we have 0 parts left, there is just a tld and no domain or subdomain // If we have 1 part, it's the domain, and there is no subdomain // If we have 2+ parts, the last part is the domain, the other parts (combined) are the subdomain if (lstRemainingParts.Count > 0) { // Set the domain: SLD = lstRemainingParts[lstRemainingParts.Count - 1]; // Set the subdomain, if there is one to set: if (lstRemainingParts.Count > 1) { // We strip off the trailing period, too SubDomain = tempSudomainAndDomain.Substring(0, tempSudomainAndDomain.Length - SLD.Length - 1); } } }