The Labs \ Source Viewer \ SSCLI \ System \ DomainNameHelper

  1. //------------------------------------------------------------------------------
  2. // <copyright file="_DomainName.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System.Globalization;
  16. namespace System
  17. {
  18.    
  19.     // The class designed as to keep working set of Uri class as minimal.
  20.     // The idea is to stay with static helper methods and strings
  21.     internal class DomainNameHelper
  22.     {
  23.        
  24.         private DomainNameHelper()
  25.         {
  26.         }
  27.        
  28.         internal const string Localhost = "localhost";
  29.         internal const string Loopback = "loopback";
  30.        
  31.         static internal string ParseCanonicalName(string str, int start, int end, ref bool loopback)
  32.         {
  33.             string res = null;
  34.            
  35.             for (int i = end - 1; i >= start; --i) {
  36.                 if (str[i] >= 'A' && str[i] <= 'Z') {
  37.                     res = str.Substring(start, end - start).ToLower(CultureInfo.InvariantCulture);
  38.                     break;
  39.                 }
  40.                 if (str[i] == ':')
  41.                     end = i;
  42.             }
  43.            
  44.             if (res == null) {
  45.                 res = str.Substring(start, end - start);
  46.             }
  47.            
  48.             if (res == Localhost || res == Loopback) {
  49.                 loopback = true;
  50.                 return Localhost;
  51.             }
  52.             return res;
  53.         }
  54.         //
  55.         // IsValid
  56.         //
  57.         // Determines whether a string is a valid domain name
  58.         //
  59.         // subdomain -> <label> | <label> "." <subdomain>
  60.         //
  61.         // Inputs:
  62.         // - name as Name to test
  63.         // - starting position
  64.         // - ending position
  65.         //
  66.         // Outputs:
  67.         // The end position of a valid domain name string, the canonical flag if found so
  68.         //
  69.         // Returns:
  70.         // bool
  71.         //
  72.         // Remarks: Optimized for speed as a most comon case,
  73.         // MUST NOT be used unless all input indexes are are verified and trusted.
  74.         //
  75.        
  76.         unsafe static internal bool IsValid(char* name, ushort pos, ref int returnedEnd, ref bool notCanonical, bool notImplicitFile)
  77.         {
  78.            
  79.             char* curPos = name + pos;
  80.             char* newPos = curPos;
  81.             char* end = name + returnedEnd;
  82.             for (; newPos < end; ++newPos) {
  83.                 char ch = *newPos;
  84.                 if (ch == '/' || ch == '\\' || (notImplicitFile && (ch == ':' || ch == '?' || ch == '#'))) {
  85.                     end = newPos;
  86.                     break;
  87.                 }
  88.             }
  89.            
  90.             if (end == curPos) {
  91.                 return false;
  92.             }
  93.            
  94.             do {
  95.                 // Determines whether a string is a valid domain name label. In keeping
  96.                 // with RFC 1123, section 2.1, the requirement that the first character
  97.                 // of a label be alphabetic is dropped. Therefore, Domain names are
  98.                 // formed as:
  99.                 //
  100.                 // <label> -> <alphanum> [<alphanum> | <hyphen> | <underscore>] * 62
  101.                
  102.                 //find the dot or hit the end
  103.                 newPos = curPos;
  104.                 while (newPos < end) {
  105.                     if (*newPos == '.')
  106.                         break;
  107.                     ++newPos;
  108.                 }
  109.                
  110.                 //check the label start/range
  111.                 if (curPos == newPos || newPos - curPos > 63 || !IsASCIILetterOrDigit(*curPos++, ref notCanonical)) {
  112.                     return false;
  113.                 }
  114.                 //check the label content
  115.                 while (curPos < newPos) {
  116.                     if (!IsValidDomainLabelCharacter(*curPos++, ref notCanonical)) {
  117.                         return false;
  118.                     }
  119.                 }
  120.                 ++curPos;
  121.                
  122.             }
  123.             while (curPos < end);
  124.            
  125.             returnedEnd = (ushort)(end - name);
  126.             return true;
  127.         }
  128.         // Determines whether a character is a valid letter according to
  129.         // RFC 1035. Note: we don't use Char.IsLetter() because it assumes
  130.         // some non-ANSI characters out of the range A..Za..z are also
  131.         // valid letters
  132.         //
  133.         private static bool IsASCIILetter(char character, ref bool notCanonical)
  134.         {
  135.            
  136.             if (character >= 'a' && character <= 'z')
  137.                 return true;
  138.            
  139.             if (character >= 'A' && character <= 'Z') {
  140.                 if (!notCanonical)
  141.                     notCanonical = true;
  142.                 return true;
  143.             }
  144.             return false;
  145.         }
  146.         //
  147.         // Determines whether a character is a letter or digit according to the
  148.         // DNS specification [RFC 1035]. We use our own variant of IsLetterOrDigit
  149.         // because the base version returns false positives for non-ANSI characters
  150.         //
  151.         private static bool IsASCIILetterOrDigit(char character, ref bool notCanonical)
  152.         {
  153.             return IsASCIILetter(character, ref notCanonical) || (character >= '0' && character <= '9');
  154.         }
  155.         //
  156.         // Takes into account the additional legal domain name characters '-' and '_'
  157.         // Note that '_' char is formally invalid but is historically in use, especially on corpnets
  158.         //
  159.         private static bool IsValidDomainLabelCharacter(char character, ref bool notCanonical)
  160.         {
  161.             return IsASCIILetterOrDigit(character, ref notCanonical) || (character == '-') || (character == '_');
  162.         }
  163.        
  164.     }
  165. }

Developer Fusion