The Labs \ Source Viewer \ SSCLI \ System \ BuiltInUriParser

  1. //------------------------------------------------------------------------------
  2. // <copyright file="_UriSyntax.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. //
  16. // This file utilizes partial class feature and contains
  17. // only internal implementation of UriParser type
  18. //
  19. namespace System
  20. {
  21.    
  22.     using System.Globalization;
  23.     using System.Collections;
  24.     using System.Security.Permissions;
  25.    
  26.     // This enum specifies the Uri syntax flags that is understood by builtin Uri parser.
  27.     [Flags()]
  28.     internal enum UriSyntaxFlags
  29.     {
  30.         MustHaveAuthority = 1,
  31.         // must have "//" after scheme:
  32.         OptionalAuthority = 2,
  33.         // used by generic parser due to unknown Uri syntax
  34.         MayHaveUserInfo = 4,
  35.         MayHavePort = 8,
  36.         MayHavePath = 16,
  37.         MayHaveQuery = 32,
  38.         MayHaveFragment = 64,
  39.        
  40.         AllowEmptyHost = 128,
  41.         AllowUncHost = 256,
  42.         AllowDnsHost = 512,
  43.         AllowIPv4Host = 1024,
  44.         AllowIPv6Host = 2048,
  45.         AllowAnInternetHost = AllowDnsHost | AllowIPv4Host | AllowIPv6Host,
  46.         AllowAnyOtherHost = 4096,
  47.         // Relaxed authority syntax
  48.         FileLikeUri = 8192,
  49.         //Special case to allow file:\\balbla or file://\\balbla
  50.         MailToLikeUri = 16384,
  51.         //V1 parser inheritance mailTo:AuthorityButNoSlashes
  52.         V1_UnknownUri = 65536,
  53.         // a Compatibility with V1 parser for an unknown scheme
  54.         SimpleUserSyntax = 131072,
  55.         // It is safe to not call virtual UriParser methods
  56.         BuiltInSyntax = 262144,
  57.         // This is a simple Uri plus it is hardcoded in the product
  58.         ParserSchemeOnly = 524288,
  59.         // This is a Parser that does only Uri scheme parsing
  60.         AllowDOSPath = 1048576,
  61.         // will check for "x:\"
  62.         PathIsRooted = 2097152,
  63.         // For an authority based Uri the first path char is '/'
  64.         ConvertPathSlashes = 4194304,
  65.         // will turn '\' into '/'
  66.         CompressPath = 8388608,
  67.         // For an authority based Uri remove/compress /./ /../ in the path
  68.         CanonicalizeAsFilePath = 16777216,
  69.         // remove/convert sequences /.../ /x../ /x./ dangerous for a DOS path
  70.         UnEscapeDotsAndSlashes = 33554432
  71.         // additionally unescape dots and slashes before doing path compression
  72.         // KeepTailLWS = 0x8000000,
  73.     }
  74.     //
  75.     // Only internal members are included here
  76.     //
  77.     public abstract partial class UriParser
  78.     {
  79.         private static readonly System.Collections.Hashtable m_Table;
  80.         private static System.Collections.Hashtable m_TempTable;
  81.        
  82.         private UriSyntaxFlags m_Flags;
  83.         private int m_Port;
  84.         private string m_Scheme;
  85.        
  86.         internal const int NoDefaultPort = -1;
  87.         private const int c_InitialTableSize = 25;
  88.        
  89.         // These are always available without paying hashtable lookup cost
  90.         // Note: see UpdateStaticSyntaxReference()
  91.         static internal UriParser HttpUri;
  92.         static internal UriParser HttpsUri;
  93.         static internal UriParser FtpUri;
  94.         static internal UriParser FileUri;
  95.         static internal UriParser GopherUri;
  96.         static internal UriParser NntpUri;
  97.         static internal UriParser NewsUri;
  98.         static internal UriParser MailToUri;
  99.         static internal UriParser UuidUri;
  100.         static internal UriParser TelnetUri;
  101.         static internal UriParser LdapUri;
  102.         static internal UriParser NetTcpUri;
  103.         static internal UriParser NetPipeUri;
  104.        
  105.         static internal UriParser VsMacrosUri;
  106.        
  107.         static UriParser()
  108.         {
  109.            
  110.             m_Table = new System.Collections.Hashtable(c_InitialTableSize);
  111.             m_TempTable = new System.Collections.Hashtable(c_InitialTableSize);
  112.            
  113.             //Now we will call for the instance constructors that will interrupt this static one.
  114.            
  115.             // Below we simulate calls into FetchSyntax() but avoid using lock() and other things redundant for a .cctor
  116.            
  117.             HttpUri = new BuiltInUriParser("http", 80, HttpSyntaxFlags);
  118.             m_Table[HttpUri.SchemeName] = HttpUri;
  119.             //HTTP
  120.             HttpsUri = new BuiltInUriParser("https", 443, HttpUri.m_Flags);
  121.             m_Table[HttpsUri.SchemeName] = HttpsUri;
  122.             //HTTPS cloned from HTTP
  123.             FtpUri = new BuiltInUriParser("ftp", 21, FtpSyntaxFlags);
  124.             m_Table[FtpUri.SchemeName] = FtpUri;
  125.             //FTP
  126.             FileUri = new BuiltInUriParser("file", NoDefaultPort, FileSyntaxFlags);
  127.             m_Table[FileUri.SchemeName] = FileUri;
  128.             //FILE
  129.             GopherUri = new BuiltInUriParser("gopher", 70, GopherSyntaxFlags);
  130.             m_Table[GopherUri.SchemeName] = GopherUri;
  131.             //GOPHER
  132.             NntpUri = new BuiltInUriParser("nntp", 119, NntpSyntaxFlags);
  133.             m_Table[NntpUri.SchemeName] = NntpUri;
  134.             //NNTP
  135.             NewsUri = new BuiltInUriParser("news", NoDefaultPort, NewsSyntaxFlags);
  136.             m_Table[NewsUri.SchemeName] = NewsUri;
  137.             //NEWS
  138.             MailToUri = new BuiltInUriParser("mailto", 25, MailtoSyntaxFlags);
  139.             m_Table[MailToUri.SchemeName] = MailToUri;
  140.             //MAILTO
  141.             UuidUri = new BuiltInUriParser("uuid", NoDefaultPort, NewsUri.m_Flags);
  142.             m_Table[UuidUri.SchemeName] = UuidUri;
  143.             //UUID cloned from NEWS
  144.             TelnetUri = new BuiltInUriParser("telnet", 23, TelnetSyntaxFlags);
  145.             m_Table[TelnetUri.SchemeName] = TelnetUri;
  146.             //TELNET
  147.             LdapUri = new BuiltInUriParser("ldap", 389, LdapSyntaxFlags);
  148.             m_Table[LdapUri.SchemeName] = LdapUri;
  149.             //LDAP
  150.             NetTcpUri = new BuiltInUriParser("net.tcp", 808, NetTcpSyntaxFlags);
  151.             m_Table[NetTcpUri.SchemeName] = NetTcpUri;
  152.            
  153.             NetPipeUri = new BuiltInUriParser("net.pipe", NoDefaultPort, NetPipeSyntaxFlags);
  154.             m_Table[NetPipeUri.SchemeName] = NetPipeUri;
  155.            
  156.             VsMacrosUri = new BuiltInUriParser("vsmacros", NoDefaultPort, VsmacrosSyntaxFlags);
  157.             m_Table[VsMacrosUri.SchemeName] = VsMacrosUri;
  158.             //VSMACROS
  159.         }
  160.         //
  161.         private class BuiltInUriParser : UriParser
  162.         {
  163.             //
  164.             // All BuiltIn parsers use that ctor. They are marked with "simple" and "built-in" flags
  165.             //
  166.             internal BuiltInUriParser(string lwrCaseScheme, int defaultPort, UriSyntaxFlags syntaxFlags) : base((syntaxFlags | UriSyntaxFlags.SimpleUserSyntax | UriSyntaxFlags.BuiltInSyntax))
  167.             {
  168.                 m_Scheme = lwrCaseScheme;
  169.                 m_Port = defaultPort;
  170.             }
  171.         }
  172.         //
  173.         internal UriSyntaxFlags Flags {
  174.             get { return m_Flags; }
  175.         }
  176.         //
  177.         internal bool NotAny(UriSyntaxFlags flags)
  178.         {
  179.             return (m_Flags & flags) == 0;
  180.         }
  181.         //
  182.         internal bool InFact(UriSyntaxFlags flags)
  183.         {
  184.             return (m_Flags & flags) != 0;
  185.         }
  186.         //
  187.         internal bool IsAllSet(UriSyntaxFlags flags)
  188.         {
  189.             return (m_Flags & flags) == flags;
  190.         }
  191.         //
  192.         // Internal .ctor, any ctor eventually goes through this one
  193.         //
  194.         internal UriParser(UriSyntaxFlags flags)
  195.         {
  196.             m_Flags = flags;
  197.             m_Scheme = string.Empty;
  198.         }
  199.         //
  200.         private static void FetchSyntax(UriParser syntax, string lwrCaseSchemeName, int defaultPort)
  201.         {
  202.             if (syntax.SchemeName.Length != 0)
  203.                 throw new InvalidOperationException(SR.GetString(SR.net_uri_NeedFreshParser, syntax.SchemeName));
  204.            
  205.             lock (m_Table) {
  206.                 syntax.m_Flags &= ~UriSyntaxFlags.V1_UnknownUri;
  207.                 UriParser oldSyntax = (UriParser)m_Table[lwrCaseSchemeName];
  208.                 if (oldSyntax != null)
  209.                     throw new InvalidOperationException(SR.GetString(SR.net_uri_AlreadyRegistered, oldSyntax.SchemeName));
  210.                
  211.                 oldSyntax = (UriParser)m_TempTable[syntax.SchemeName];
  212.                 if (oldSyntax != null) {
  213.                     // optimization on schemeName, will try to keep the first reference
  214.                     lwrCaseSchemeName = oldSyntax.m_Scheme;
  215.                     m_TempTable.Remove(lwrCaseSchemeName);
  216.                 }
  217.                
  218.                 syntax.OnRegister(lwrCaseSchemeName, defaultPort);
  219.                 syntax.m_Scheme = lwrCaseSchemeName;
  220.                 syntax.CheckSetIsSimpleFlag();
  221.                 syntax.m_Port = defaultPort;
  222.                
  223.                 m_Table[syntax.SchemeName] = syntax;
  224.             }
  225.         }
  226.         //
  227.         private const int c_MaxCapacity = 512;
  228.         //schemeStr must be in lower case!
  229.         static internal UriParser FindOrFetchAsUnknownV1Syntax(string lwrCaseScheme)
  230.         {
  231.            
  232.             // check may be other thread just added one
  233.             UriParser syntax = (UriParser)m_Table[lwrCaseScheme];
  234.             if (syntax != null) {
  235.                 return syntax;
  236.             }
  237.             syntax = (UriParser)m_TempTable[lwrCaseScheme];
  238.             if (syntax != null) {
  239.                 return syntax;
  240.             }
  241.             lock (m_Table) {
  242.                 if (m_TempTable.Count >= c_MaxCapacity) {
  243.                     m_TempTable = new System.Collections.Hashtable(c_InitialTableSize);
  244.                 }
  245.                 syntax = new BuiltInUriParser(lwrCaseScheme, NoDefaultPort, UnknownV1SyntaxFlags);
  246.                 m_TempTable[lwrCaseScheme] = syntax;
  247.                 return syntax;
  248.             }
  249.         }
  250.         //
  251.         static internal UriParser GetSyntax(string lwrCaseScheme)
  252.         {
  253.             object ret = m_Table[lwrCaseScheme];
  254.             if (ret == null) {
  255.                 ret = m_TempTable[lwrCaseScheme];
  256.             }
  257.             return (UriParser)ret;
  258.         }
  259.         //
  260.         // Builtin and User Simple syntaxes do not need custom validation/parsing (i.e. virtual method calls),
  261.         //
  262.         internal bool IsSimple {
  263.             get { return InFact(UriSyntaxFlags.SimpleUserSyntax); }
  264.         }
  265.         //
  266.         internal void CheckSetIsSimpleFlag()
  267.         {
  268.             Type type = this.GetType();
  269.            
  270.             if (type == typeof(GenericUriParser) || type == typeof(HttpStyleUriParser) || type == typeof(FtpStyleUriParser) || type == typeof(FileStyleUriParser) || type == typeof(NewsStyleUriParser) || type == typeof(GopherStyleUriParser) || type == typeof(NetPipeStyleUriParser) || type == typeof(NetTcpStyleUriParser) || type == typeof(LdapStyleUriParser)) {
  271.                 m_Flags |= UriSyntaxFlags.SimpleUserSyntax;
  272.             }
  273.         }
  274.         //
  275.         // Copied from Uri class
  276.         //
  277.         private static bool CheckSchemeName(string schemeName)
  278.         {
  279.             if (((object)schemeName == null) || (schemeName.Length == 0) || !IsAsciiLetter(schemeName[0])) {
  280.                 return false;
  281.             }
  282.            
  283.             for (int i = schemeName.Length - 1; i > 0; --i) {
  284.                 if (!(IsAsciiLetterOrDigit(schemeName[i]) || (schemeName[i] == '+') || (schemeName[i] == '-') || (schemeName[i] == '.'))) {
  285.                     return false;
  286.                 }
  287.             }
  288.            
  289.             return true;
  290.         }
  291.         private static bool IsAsciiLetter(char character)
  292.         {
  293.             return (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z');
  294.         }
  295.         private static bool IsAsciiLetterOrDigit(char character)
  296.         {
  297.             return IsAsciiLetter(character) || (character >= '0' && character <= '9');
  298.         }
  299.         //
  300.         // These are simple internal wrappers that will call virtual protected methods
  301.         // (to avoid "protected internal" siganures in the public docs)
  302.         //
  303.         internal UriParser InternalOnNewUri()
  304.         {
  305.             UriParser effectiveParser = OnNewUri();
  306.             if ((object)this != (object)effectiveParser) {
  307.                 effectiveParser.m_Scheme = m_Scheme;
  308.                 effectiveParser.m_Port = m_Port;
  309.                 effectiveParser.m_Flags = m_Flags;
  310.             }
  311.             return effectiveParser;
  312.         }
  313.         //
  314.         internal void InternalValidate(Uri thisUri, out UriFormatException parsingError)
  315.         {
  316.             InitializeAndValidate(thisUri, out parsingError);
  317.         }
  318.         //
  319.         internal string InternalResolve(Uri thisBaseUri, Uri uriLink, out UriFormatException parsingError)
  320.         {
  321.             return Resolve(thisBaseUri, uriLink, out parsingError);
  322.         }
  323.         //
  324.         internal bool InternalIsBaseOf(Uri thisBaseUri, Uri uriLink)
  325.         {
  326.             return IsBaseOf(thisBaseUri, uriLink);
  327.         }
  328.         //
  329.         internal string InternalGetComponents(Uri thisUri, UriComponents uriComponents, UriFormat uriFormat)
  330.         {
  331.             return GetComponents(thisUri, uriComponents, uriFormat);
  332.         }
  333.         //
  334.         internal bool InternalIsWellFormedOriginalString(Uri thisUri)
  335.         {
  336.             return IsWellFormedOriginalString(thisUri);
  337.         }
  338.         //
  339.         // Various Uri scheme syntax flags
  340.         //
  341.             // This flag must be always set here
  342.             //
  343.             //
  344.             // UriSyntaxFlags.AllowAnyOtherHost | // V1.1 has a bug and so does not support this case
  345.             //
  346.             // V1 compat, it will always convert backslashes
  347.         private const UriSyntaxFlags UnknownV1SyntaxFlags = UriSyntaxFlags.V1_UnknownUri | UriSyntaxFlags.OptionalAuthority | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.AllowEmptyHost | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.PathIsRooted | UriSyntaxFlags.AllowDOSPath | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.CompressPath;
  348.         // V1 compat, it will always compress path even for non hierarchical Uris
  349.             //
  350.             //
  351.             //
  352.             //
  353.         private const UriSyntaxFlags HttpSyntaxFlags = UriSyntaxFlags.MustHaveAuthority | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.PathIsRooted | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.CompressPath | UriSyntaxFlags.CanonicalizeAsFilePath | UriSyntaxFlags.UnEscapeDotsAndSlashes;
  354.        
  355.             //
  356.             //
  357.             //
  358.             //
  359.         private const UriSyntaxFlags FtpSyntaxFlags = UriSyntaxFlags.MustHaveAuthority | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.PathIsRooted | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.CompressPath | UriSyntaxFlags.CanonicalizeAsFilePath;
  360.        
  361.             //
  362.             //
  363.             //
  364.             //
  365.             //
  366.         private const UriSyntaxFlags FileSyntaxFlags = UriSyntaxFlags.MustHaveAuthority | UriSyntaxFlags.AllowEmptyHost | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.FileLikeUri | UriSyntaxFlags.PathIsRooted | UriSyntaxFlags.AllowDOSPath | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.CompressPath | UriSyntaxFlags.CanonicalizeAsFilePath | UriSyntaxFlags.UnEscapeDotsAndSlashes;
  367.        
  368.             //
  369.             //
  370.             //
  371.             //
  372.         private const UriSyntaxFlags VsmacrosSyntaxFlags = UriSyntaxFlags.MustHaveAuthority | UriSyntaxFlags.AllowEmptyHost | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.FileLikeUri | UriSyntaxFlags.AllowDOSPath | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.CompressPath | UriSyntaxFlags.CanonicalizeAsFilePath | UriSyntaxFlags.UnEscapeDotsAndSlashes;
  373.        
  374.             //
  375.             //
  376.             //
  377.         private const UriSyntaxFlags GopherSyntaxFlags = UriSyntaxFlags.MustHaveAuthority | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.PathIsRooted;
  378.         // UriSyntaxFlags.KeepTailLWS |
  379.        
  380.         //Note that NNTP and NEWS are quite different in syntax
  381.         private const UriSyntaxFlags NewsSyntaxFlags = UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveFragment;
  382.        
  383.             //
  384.             //
  385.             //
  386.         private const UriSyntaxFlags NntpSyntaxFlags = UriSyntaxFlags.MustHaveAuthority | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.PathIsRooted;
  387.        
  388.             //
  389.             //
  390.             //
  391.         private const UriSyntaxFlags TelnetSyntaxFlags = UriSyntaxFlags.MustHaveAuthority | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.PathIsRooted;
  392.        
  393.             //
  394.             //
  395.             //
  396.         private const UriSyntaxFlags LdapSyntaxFlags = UriSyntaxFlags.MustHaveAuthority | UriSyntaxFlags.AllowEmptyHost | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.PathIsRooted;
  397.        
  398.             //
  399.             //
  400.         private const UriSyntaxFlags MailtoSyntaxFlags = UriSyntaxFlags.AllowEmptyHost | UriSyntaxFlags.AllowUncHost | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.MayHaveUserInfo | UriSyntaxFlags.MayHavePort | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MailToLikeUri;
  401.        
  402.        
  403.         private const UriSyntaxFlags NetPipeSyntaxFlags = UriSyntaxFlags.MustHaveAuthority | UriSyntaxFlags.MayHavePath | UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment | UriSyntaxFlags.AllowAnInternetHost | UriSyntaxFlags.PathIsRooted | UriSyntaxFlags.ConvertPathSlashes | UriSyntaxFlags.CompressPath | UriSyntaxFlags.CanonicalizeAsFilePath | UriSyntaxFlags.UnEscapeDotsAndSlashes;
  404.        
  405.        
  406.         private const UriSyntaxFlags NetTcpSyntaxFlags = NetPipeSyntaxFlags | UriSyntaxFlags.MayHavePort;
  407.        
  408.     }
  409. }

Developer Fusion