| // //------------------------------------------------------------------------------ | |
| // // <copyright file="URI.cs" company="Microsoft"> | |
| // // Copyright (c) Microsoft Corporation. All rights reserved. | |
| // // </copyright> | |
| // //------------------------------------------------------------------------------ | |
| // | |
| // namespace System { | |
| // using System.Runtime.InteropServices; | |
| // using System.Text; | |
| // using System.Globalization; | |
| // using System.Security; | |
| // using System.ComponentModel; | |
| // // Not in SL: | |
| // using System.Configuration; | |
| // using System.Security.Permissions; | |
| // using System.Runtime.Serialization; | |
| // using Microsoft.Win32; | |
| // using System.Threading; | |
| // using System.Diagnostics.CodeAnalysis; | |
| // using System.Net; | |
| // [Serializable] | |
| // [TypeConverter(typeof(UriTypeConverter))] | |
| // public partial class Uri : ISerializable { | |
| // | |
| // public static readonly string UriSchemeFile = UriParser.FileUri.SchemeName; | |
| // public static readonly string UriSchemeFtp = UriParser.FtpUri.SchemeName; | |
| // public static readonly string UriSchemeGopher = UriParser.GopherUri.SchemeName; | |
| // public static readonly string UriSchemeHttp = UriParser.HttpUri.SchemeName; | |
| // public static readonly string UriSchemeHttps = UriParser.HttpsUri.SchemeName; | |
| // internal static readonly string UriSchemeWs = UriParser.WsUri.SchemeName; | |
| // internal static readonly string UriSchemeWss = UriParser.WssUri.SchemeName; | |
| // public static readonly string UriSchemeMailto = UriParser.MailToUri.SchemeName; | |
| // public static readonly string UriSchemeNews = UriParser.NewsUri.SchemeName; | |
| // public static readonly string UriSchemeNntp = UriParser.NntpUri.SchemeName; | |
| // public static readonly string UriSchemeNetTcp = UriParser.NetTcpUri.SchemeName; | |
| // public static readonly string UriSchemeNetPipe = UriParser.NetPipeUri.SchemeName; | |
| // public static readonly string SchemeDelimiter = "://"; | |
| // | |
| // | |
| // private const int c_Max16BitUtf8SequenceLength = 3+3+3+3; //each unicode byte takes 3 escaped chars | |
| // internal const int c_MaxUriBufferSize = 0xFFF0; | |
| // private const int c_MaxUriSchemeName = 1024; | |
| // | |
| // // untouched user string unless string has unicode chars and iriparsing is enabled | |
| // // or idn is on and we have unicode host or idn host | |
| // // In that case, this string is normalized, stripped of bidi chars, and validated | |
| // // with char limits | |
| // private string m_String; | |
| // | |
| // // untouched user string if string has unicode with iri on or unicode/idn host with idn on | |
| // private string m_originalUnicodeString; | |
| // | |
| // private UriParser m_Syntax; // This is a whole Uri syntax, not only the scheme name | |
| // // temporarily stores dnssafe host when we have unicode/idn host and idn is on | |
| // private string m_DnsSafeHost = null; | |
| // | |
| // [Flags] | |
| // private enum Flags : ulong { | |
| // Zero = 0x00000000, | |
| // | |
| // SchemeNotCanonical = 0x1, | |
| // UserNotCanonical = 0x2, | |
| // HostNotCanonical = 0x4, | |
| // PortNotCanonical = 0x8, | |
| // PathNotCanonical = 0x10, | |
| // QueryNotCanonical = 0x20, | |
| // FragmentNotCanonical = 0x40, | |
| // CannotDisplayCanonical = 0x7F, | |
| // | |
| // E_UserNotCanonical = 0x80, | |
| // E_HostNotCanonical = 0x100, | |
| // E_PortNotCanonical = 0x200, | |
| // E_PathNotCanonical = 0x400, | |
| // E_QueryNotCanonical = 0x800, | |
| // E_FragmentNotCanonical = 0x1000, | |
| // E_CannotDisplayCanonical = 0x1F80, | |
| // | |
| // | |
| // ShouldBeCompressed = 0x2000, | |
| // FirstSlashAbsent = 0x4000, | |
| // BackslashInPath = 0x8000, | |
| // | |
| // IndexMask = 0x0000FFFF, | |
| // HostTypeMask = 0x00070000, | |
| // HostNotParsed = 0x00000000, | |
| // IPv6HostType = 0x00010000, | |
| // IPv4HostType = 0x00020000, | |
| // DnsHostType = 0x00030000, | |
| // #if !PLATFORM_UNIX | |
| // UncHostType = 0x00040000, | |
| // #endif // !PLATFORM_UNIX | |
| // BasicHostType = 0x00050000, | |
| // UnusedHostType = 0x00060000, | |
| // UnknownHostType = 0x00070000, | |
| // | |
| // UserEscaped = 0x00080000, | |
| // AuthorityFound = 0x00100000, | |
| // HasUserInfo = 0x00200000, | |
| // LoopbackHost = 0x00400000, | |
| // NotDefaultPort = 0x00800000, | |
| // | |
| // UserDrivenParsing = 0x01000000, | |
| // CanonicalDnsHost = 0x02000000, | |
| // ErrorOrParsingRecursion = 0x04000000, // Used to signal a default parser error and alsoe to confirm Port | |
| // // and Host values in case of a custom user Parser | |
| // #if !PLATFORM_UNIX | |
| // DosPath = 0x08000000, | |
| // UncPath = 0x10000000, | |
| // #endif // !PLATFORM_UNIX | |
| // ImplicitFile = 0x20000000, | |
| // MinimalUriInfoSet = 0x40000000, | |
| // AllUriInfoSet = unchecked(0x80000000), | |
| // IdnHost = 0x100000000, | |
| // HasUnicode = 0x200000000, | |
| // HostUnicodeNormalized = 0x400000000, | |
| // RestUnicodeNormalized = 0x800000000, | |
| // UnicodeHost = 0x1000000000, | |
| // IntranetUri = 0x2000000000, | |
| // UseOrigUncdStrOffset= 0x4000000000, | |
| // // Is this component Iri canonical | |
| // UserIriCanonical = 0x8000000000, | |
| // PathIriCanonical = 0x10000000000, | |
| // QueryIriCanonical = 0x20000000000, | |
| // FragmentIriCanonical = 0x40000000000, | |
| // IriCanonical = 0x78000000000, | |
| // } | |
| // | |
| // private Flags m_Flags; | |
| // private UriInfo m_Info; | |
| // | |
| // private class UriInfo { | |
| // public string Host; | |
| // public string ScopeId; //only IP v6 may need this | |
| // public string String; | |
| // public Offset Offset; | |
| // public string DnsSafeHost; // stores dns safe host when idn is on and we have unicode or idn host | |
| // public MoreInfo MoreInfo; // Multi-threading: This field must be always accessed through a _local_ | |
| // // stack copy of m_Info. | |
| // }; | |
| // | |
| // [StructLayout(LayoutKind.Sequential, Pack=1)] | |
| // private struct Offset { | |
| // public ushort Scheme; | |
| // public ushort User; | |
| // public ushort Host; | |
| // public ushort PortValue; | |
| // public ushort Path; | |
| // public ushort Query; | |
| // public ushort Fragment; | |
| // public ushort End; | |
| // }; | |
| // | |
| // private class MoreInfo { | |
| // public string Path; | |
| // public string Query; | |
| // public string Fragment; | |
| // public string AbsoluteUri; | |
| // public int Hash; | |
| // public string RemoteUrl; | |
| // }; | |
| // | |
| // private bool IsImplicitFile { | |
| // get {return (m_Flags & Flags.ImplicitFile) != 0;} | |
| // } | |
| // | |
| // private bool IsUncOrDosPath { | |
| // #if !PLATFORM_UNIX | |
| // get {return (m_Flags & (Flags.UncPath|Flags.DosPath)) != 0;} | |
| // #else | |
| // get {return false;} | |
| // #endif // !PLATFORM_UNIX | |
| // } | |
| // | |
| // private bool IsDosPath { | |
| // #if !PLATFORM_UNIX | |
| // get {return (m_Flags & Flags.DosPath) != 0;} | |
| // #else | |
| // get {return false;} | |
| // #endif // !PLATFORM_UNIX | |
| // } | |
| // | |
| // private bool IsUncPath { | |
| // #if !PLATFORM_UNIX | |
| // get {return (m_Flags & Flags.UncPath) != 0;} | |
| // #else | |
| // get {return false;} | |
| // #endif // !PLATFORM_UNIX | |
| // } | |
| // | |
| // private Flags HostType { | |
| // get {return m_Flags & Flags.HostTypeMask;} | |
| // } | |
| // | |
| // private UriParser Syntax { | |
| // get { | |
| // return m_Syntax; | |
| // } | |
| // } | |
| // | |
| // private bool IsNotAbsoluteUri { | |
| // get {return (object) m_Syntax == null;} | |
| // } | |
| // | |
| // // | |
| // // Checks if Iri parsing is allowed by the syntax & by config | |
| // // | |
| // private bool m_iriParsing; | |
| // | |
| // // | |
| // // Statically checks if Iri parsing is allowed by the syntax & by config | |
| // // | |
| // internal static bool IriParsingStatic( UriParser syntax ) | |
| // { | |
| // return (s_IriParsing && (((syntax != null) && syntax.InFact(UriSyntaxFlags.AllowIriParsing)) || | |
| // (syntax == null))); | |
| // } | |
| // | |
| // // | |
| // // Checks if Idn is allowed by the syntax & by config | |
| // // | |
| // private bool AllowIdn | |
| // { | |
| // get { return ((m_Syntax != null) && ((m_Syntax.Flags & UriSyntaxFlags.AllowIdn) != 0) && | |
| // ((s_IdnScope == UriIdnScope.All) || ((s_IdnScope == UriIdnScope.AllExceptIntranet) | |
| // && NotAny(Flags.IntranetUri)))); } | |
| // } | |
| // | |
| // // | |
| // // Checks statically if Idn is allowed by the syntax & by config | |
| // // | |
| // private bool AllowIdnStatic(UriParser syntax, Flags flags) | |
| // { | |
| // return ((syntax != null) && ((syntax.Flags & UriSyntaxFlags.AllowIdn) != 0) && | |
| // ((s_IdnScope == UriIdnScope.All) || ((s_IdnScope == UriIdnScope.AllExceptIntranet) | |
| // && StaticNotAny(flags, Flags.IntranetUri)))); | |
| // } | |
| // | |
| // // | |
| // // check if the scheme + host are in intranet or not | |
| // // Used to determine of we apply idn or not | |
| // // | |
| // private static volatile IInternetSecurityManager s_ManagerRef = null; | |
| // private static object s_IntranetLock = new object(); | |
| // | |
| // private bool IsIntranet(string schemeHost) | |
| // { | |
| // bool error = false; | |
| // int zone = -1; | |
| // int E_FAIL = unchecked((int)0x80004005); | |
| // | |
| // // MapUrlToZone call below fails on scheme length > 32 so we consider this | |
| // // not be be intranet | |
| // // | |
| // if (m_Syntax.SchemeName.Length > 32) | |
| // return false; | |
| // | |
| // if (s_ManagerRef == null){ | |
| // lock (s_IntranetLock){ | |
| // if(s_ManagerRef == null) | |
| // { | |
| // #if !FEATURE_PAL | |
| // // Go through CoCreateInstance as creating arbitary COM object is no longer supported in AppX scenario | |
| // Guid clsid = typeof(InternetSecurityManager).GUID; | |
| // Guid iid = typeof(IInternetSecurityManager).GUID; | |
| // | |
| // object managerRef; | |
| // UnsafeNclNativeMethods.CoCreateInstance( | |
| // ref clsid , | |
| // IntPtr.Zero, | |
| // UnsafeNclNativeMethods.CLSCTX_SERVER, | |
| // ref iid, | |
| // out managerRef | |
| // ); | |
| // s_ManagerRef = managerRef as IInternetSecurityManager; | |
| // #else | |
| // s_ManagerRef = (IInternetSecurityManager)new InternetSecurityManager(); | |
| // #endif // !FEATURE_PAL | |
| // } | |
| // } | |
| // } | |
| // | |
| // try{ | |
| // s_ManagerRef.MapUrlToZone(schemeHost.TrimStart(_WSchars), out zone, 0); | |
| // } | |
| // catch (COMException ex){ | |
| // if (ex.ErrorCode == E_FAIL){ // E_FAIL | |
| // error = true; | |
| // } | |
| // } | |
| // // If s_ManagerRef was initilized on an STA thread then it cannot be accessed from other threads. | |
| // // Visual Studio Unit Tests are the primary scenario for this. | |
| // catch (InvalidComObjectException) { | |
| // error = true; | |
| // } | |
| // | |
| // if(zone == (int) SecurityZone.Intranet) | |
| // return true; | |
| // | |
| // // Do dot check for intranet if zone is trusted or untrusted | |
| // // since an intranet zone may be in these zones as well | |
| // if ((zone == (int)SecurityZone.Trusted) || | |
| // (zone == (int)SecurityZone.Untrusted) || error) | |
| // { | |
| // // do dot check | |
| // for (int i = 0; i < schemeHost.Length; ++i) | |
| // { | |
| // if (schemeHost[i] == '.') | |
| // return false; | |
| // } | |
| // return true; | |
| // } | |
| // return false; | |
| // } | |
| // | |
| // internal bool UserDrivenParsing | |
| // { | |
| // get { | |
| // return (m_Flags & Flags.UserDrivenParsing) != 0; | |
| // } | |
| // } | |
| // private void SetUserDrivenParsing() | |
| // { | |
| // // we use = here to clear all parsing flags for a uri that we think is invalid. | |
| // m_Flags = Flags.UserDrivenParsing | (m_Flags & Flags.UserEscaped); | |
| // } | |
| // | |
| // private ushort SecuredPathIndex { | |
| // get { | |
| // // This is one more trouble with a Dos Path. | |
| // // This property gets "safe" first path slash that is not the first if path = c:\ | |
| // if (IsDosPath) { | |
| // char ch = m_String[m_Info.Offset.Path]; | |
| // return (ushort)((ch == '/' || ch == '\\')? 3 :2); | |
| // } | |
| // return (ushort)0; | |
| // } | |
| // } | |
| // | |
| // private bool NotAny(Flags flags) { | |
| // return (m_Flags & flags) == 0; | |
| // } | |
| // | |
| // private bool InFact(Flags flags) { | |
| // return (m_Flags & flags) != 0; | |
| // } | |
| // | |
| // private static bool StaticNotAny(Flags allFlags, Flags checkFlags) { | |
| // return (allFlags & checkFlags) == 0; | |
| // } | |
| // | |
| // private static bool StaticInFact(Flags allFlags, Flags checkFlags) { | |
| // return (allFlags & checkFlags) != 0; | |
| // } | |
| // | |
| // // | |
| // // | |
| // private UriInfo EnsureUriInfo() { | |
| // Flags cF = m_Flags; | |
| // if ((m_Flags & Flags.MinimalUriInfoSet) == 0) { | |
| // CreateUriInfo(cF); | |
| // } | |
| // return m_Info; | |
| // } | |
| // // | |
| // // | |
| // private void EnsureParseRemaining() { | |
| // if ((m_Flags & Flags.AllUriInfoSet) == 0) { | |
| // ParseRemaining(); | |
| // } | |
| // } | |
| // // | |
| // // | |
| // private void EnsureHostString(bool allowDnsOptimization) { | |
| // EnsureUriInfo(); | |
| // if ((object)m_Info.Host == null) { | |
| // if (allowDnsOptimization && InFact(Flags.CanonicalDnsHost)) { | |
| // /* Optimization for a canonical DNS name | |
| // * ATTN: the host string won't be created, | |
| // * Hence ALL m_Info.Host callers first call EnsureHostString(false) | |
| // * For example IsLoopBack property is one of such callers. | |
| // */ | |
| // return; | |
| // } | |
| // CreateHostString(); | |
| // } | |
| // } | |
| // | |
| // // | |
| // // Uri(string) | |
| // // | |
| // // We expect to create a Uri from a display name - e.g. that was typed by | |
| // // a user, or that was copied & pasted from a document. That is, we do not | |
| // // expect already encoded URI to be supplied. | |
| // // | |
| // public Uri(string uriString){ | |
| // if ((object)uriString == null) | |
| // throw new ArgumentNullException("uriString"); | |
| // | |
| // CreateThis(uriString, false, UriKind.Absolute); | |
| // } | |
| // | |
| // | |
| // // | |
| // // Uri(string, bool) | |
| // // | |
| // // Uri constructor. Assumes that input string is canonically escaped | |
| // // | |
| // [Obsolete("The constructor has been deprecated. Please use new Uri(string). The dontEscape parameter is deprecated and is always false. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // public Uri(string uriString, bool dontEscape) { | |
| // if ((object)uriString == null) | |
| // throw new ArgumentNullException("uriString"); | |
| // | |
| // CreateThis(uriString, dontEscape, UriKind.Absolute); | |
| // } | |
| // | |
| // // | |
| // // Uri(Uri, string, bool) | |
| // // | |
| // // Uri combinatorial constructor. Do not perform character escaping if | |
| // // DontEscape is true | |
| // // | |
| // [Obsolete("The constructor has been deprecated. Please new Uri(Uri, string). The dontEscape parameter is deprecated and is always false. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // public Uri(Uri baseUri, string relativeUri, bool dontEscape){ | |
| // if ((object)baseUri == null) | |
| // throw new ArgumentNullException("baseUri"); | |
| // | |
| // if (!baseUri.IsAbsoluteUri) | |
| // throw new ArgumentOutOfRangeException("baseUri"); | |
| // | |
| // CreateUri(baseUri, relativeUri, dontEscape); | |
| // } | |
| // | |
| // // | |
| // // Uri(string, UriKind); | |
| // // | |
| // public Uri(string uriString, UriKind uriKind) | |
| // { | |
| // if ((object)uriString == null) | |
| // throw new ArgumentNullException("uriString"); | |
| // | |
| // CreateThis(uriString, false, uriKind); | |
| // } | |
| // | |
| // | |
| // // | |
| // // Uri(Uri, string) | |
| // // | |
| // // Construct a new Uri from a base and relative URI. The relative URI may | |
| // // also be an absolute URI, in which case the resultant URI is constructed | |
| // // entirely from it | |
| // // | |
| // public Uri(Uri baseUri, string relativeUri){ | |
| // if ((object)baseUri == null) | |
| // throw new ArgumentNullException("baseUri"); | |
| // | |
| // if (!baseUri.IsAbsoluteUri) | |
| // throw new ArgumentOutOfRangeException("baseUri"); | |
| // | |
| // CreateUri(baseUri, relativeUri, false); | |
| // } | |
| // | |
| // private void CreateUri(Uri baseUri, string relativeUri, bool dontEscape) | |
| // { | |
| // // Parse relativeUri and populate Uri internal data. | |
| // CreateThis(relativeUri, dontEscape, UriKind.RelativeOrAbsolute); | |
| // | |
| // UriFormatException e; | |
| // if (baseUri.Syntax.IsSimple) | |
| // { | |
| // // Resolve Uris if possible OR get merged Uri String to re-parse below | |
| // Uri uriResult = ResolveHelper(baseUri, this, ref relativeUri, ref dontEscape, out e); | |
| // | |
| // if (e != null) | |
| // throw e; | |
| // | |
| // // If resolved into a Uri then we build from that Uri | |
| // if (uriResult != null) | |
| // { | |
| // if ((object)uriResult != (object)this) | |
| // CreateThisFromUri(uriResult); | |
| // | |
| // return; | |
| // } | |
| // } | |
| // else | |
| // { | |
| // dontEscape = false; | |
| // relativeUri = baseUri.Syntax.InternalResolve(baseUri, this, out e); | |
| // if (e != null) | |
| // throw e; | |
| // } | |
| // | |
| // m_Flags = Flags.Zero; | |
| // m_Info = null; | |
| // m_Syntax = null; | |
| // // If not resolved, we reparse modified Uri string and populate Uri internal data. | |
| // CreateThis(relativeUri, dontEscape, UriKind.Absolute); | |
| // } | |
| // | |
| // // | |
| // // Uri(Uri , Uri ) | |
| // // Note: a static Create() method should be used by users, not this .ctor | |
| // // | |
| // public Uri(Uri baseUri, Uri relativeUri) | |
| // { | |
| // if ((object)baseUri == null) | |
| // throw new ArgumentNullException("baseUri"); | |
| // | |
| // if (!baseUri.IsAbsoluteUri) | |
| // throw new ArgumentOutOfRangeException("baseUri"); | |
| // | |
| // CreateThisFromUri(relativeUri); | |
| // | |
| // string newUriString = null; | |
| // UriFormatException e; | |
| // bool dontEscape; | |
| // | |
| // if (baseUri.Syntax.IsSimple) | |
| // { | |
| // dontEscape = InFact(Flags.UserEscaped); | |
| // relativeUri = ResolveHelper(baseUri, this, ref newUriString, ref dontEscape, out e); | |
| // | |
| // if (e != null) | |
| // throw e; | |
| // | |
| // if (relativeUri != null) | |
| // { | |
| // if ((object)relativeUri != (object)this) | |
| // CreateThisFromUri(relativeUri); | |
| // | |
| // return; | |
| // } | |
| // } | |
| // else | |
| // { | |
| // dontEscape = false; | |
| // newUriString = baseUri.Syntax.InternalResolve(baseUri, this, out e); | |
| // if (e != null) | |
| // throw e; | |
| // } | |
| // | |
| // m_Flags = Flags.Zero; | |
| // m_Info = null; | |
| // m_Syntax = null; | |
| // CreateThis(newUriString, dontEscape, UriKind.Absolute); | |
| // } | |
| // | |
| // // | |
| // // This method is shared by base+relative Uris constructors and is only called from them. | |
| // // The assumptions: | |
| // // - baseUri is a valid absolute Uri | |
| // // - relative part is not null and not empty | |
| // private unsafe static ParsingError GetCombinedString(Uri baseUri, string relativeStr, | |
| // bool dontEscape, ref string result) | |
| // { | |
| // // NB: This is not RFC2396 compliant although it is inline with w3c.org recommendations | |
| // // This parser will allow the relativeStr to be an absolute Uri with the different scheme | |
| // // In fact this is strict violation of RFC2396 | |
| // // | |
| // for (int i=0; i < relativeStr.Length; ++i) | |
| // { | |
| // if (relativeStr[i] == '/' || relativeStr[i] == '\\' || relativeStr[i] == '?' || relativeStr[i] == '#') | |
| // { | |
| // break; | |
| // } | |
| // else if (relativeStr[i] == ':') | |
| // { | |
| // if (i < 2) | |
| // { | |
| // // Note we don't support one-letter Uri schemes. | |
| // // Hence anything like x:sdsd is a relative path and be added to the baseUri Path | |
| // break; | |
| // } | |
| // string scheme = relativeStr.Substring(0, i); | |
| // fixed (char* sptr = scheme) { | |
| // UriParser syntax = null; | |
| // if (CheckSchemeSyntax(sptr, (ushort) scheme.Length, ref syntax) == ParsingError.None) { | |
| // if (baseUri.Syntax == syntax) { | |
| // //Remove the scheme for backward Uri parsers compatibility | |
| // if (i+1 < relativeStr.Length) { | |
| // relativeStr = relativeStr.Substring(i+1); | |
| // } | |
| // else { | |
| // relativeStr = string.Empty; | |
| // } | |
| // } | |
| // else { | |
| // // This is the place where we switch the scheme. | |
| // // Return relative part as the result Uri. | |
| // result = relativeStr; | |
| // return ParsingError.None; | |
| // } | |
| // } | |
| // } | |
| // break; | |
| // } | |
| // } | |
| // | |
| // if (relativeStr.Length == 0) { | |
| // result = baseUri.OriginalString; | |
| // return ParsingError.None; | |
| // } | |
| // | |
| // result = CombineUri(baseUri, relativeStr, dontEscape? UriFormat.UriEscaped: UriFormat.SafeUnescaped); | |
| // return ParsingError.None; | |
| // } | |
| // // | |
| // private static UriFormatException GetException(ParsingError err) | |
| // { | |
| // switch (err) | |
| // { | |
| // case ParsingError.None: | |
| // return null; | |
| // // Could be OK for Relative Uri | |
| // case ParsingError.BadFormat: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_BadFormat)); | |
| // case ParsingError.BadScheme: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_BadScheme)); | |
| // case ParsingError.BadAuthority: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_BadAuthority)); | |
| // case ParsingError.EmptyUriString: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_EmptyUri)); | |
| // // Fatal | |
| // case ParsingError.SchemeLimit: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_SchemeLimit)); | |
| // case ParsingError.SizeLimit: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_SizeLimit)); | |
| // case ParsingError.MustRootedPath: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_MustRootedPath)); | |
| // // Derived class controllable | |
| // case ParsingError.BadHostName: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_BadHostName)); | |
| // case ParsingError.NonEmptyHost: //unix-only | |
| // return new UriFormatException(SR.GetString(SR.net_uri_BadFormat)); | |
| // case ParsingError.BadPort: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_BadPort)); | |
| // case ParsingError.BadAuthorityTerminator: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_BadAuthorityTerminator)); | |
| // case ParsingError.CannotCreateRelative: | |
| // return new UriFormatException(SR.GetString(SR.net_uri_CannotCreateRelative)); | |
| // default: | |
| // break; | |
| // } | |
| // return new UriFormatException(SR.GetString(SR.net_uri_BadFormat)); | |
| // } | |
| // | |
| // #region !Silverlight | |
| // | |
| // // | |
| // // ISerializable constructor | |
| // // | |
| // protected Uri(SerializationInfo serializationInfo, StreamingContext streamingContext) | |
| // { | |
| // string uriString = serializationInfo.GetString("AbsoluteUri"); | |
| // | |
| // if (uriString.Length != 0) | |
| // { | |
| // CreateThis(uriString, false, UriKind.Absolute); | |
| // return; | |
| // } | |
| // | |
| // uriString = serializationInfo.GetString("RelativeUri"); | |
| // if ((object)uriString == null) | |
| // throw new ArgumentNullException("uriString"); | |
| // | |
| // CreateThis(uriString, false, UriKind.Relative); | |
| // } | |
| // | |
| // // | |
| // // ISerializable method | |
| // // | |
| // /// <internalonly/> | |
| // [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")] | |
| // [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)] | |
| // void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext) | |
| // { | |
| // GetObjectData(serializationInfo, streamingContext); | |
| // } | |
| // | |
| // // | |
| // // FxCop: provide some way for derived classes to access GetObjectData even if the derived class | |
| // // explicitly re-inherits ISerializable. | |
| // // | |
| // [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)] | |
| // protected void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext) | |
| // { | |
| // | |
| // if (IsAbsoluteUri) | |
| // serializationInfo.AddValue("AbsoluteUri", GetParts(UriComponents.SerializationInfoString, UriFormat.UriEscaped)); | |
| // else | |
| // { | |
| // serializationInfo.AddValue("AbsoluteUri", string.Empty); | |
| // serializationInfo.AddValue("RelativeUri", GetParts(UriComponents.SerializationInfoString, UriFormat.UriEscaped)); | |
| // } | |
| // } | |
| // | |
| // #endregion !Silverlight | |
| // | |
| // // | |
| // // | |
| // // | |
| // public string AbsolutePath { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // string path = PrivateAbsolutePath; | |
| // // | |
| // // | |
| // | |
| // | |
| // if (IsDosPath && path[0] == '/') { | |
| // path = path.Substring(1); | |
| // } | |
| // return path; | |
| // } | |
| // } | |
| // // | |
| // private string PrivateAbsolutePath { | |
| // get { | |
| // UriInfo info = EnsureUriInfo(); | |
| // if ((object) info.MoreInfo == null) { | |
| // info.MoreInfo = new MoreInfo(); | |
| // } | |
| // string result = info.MoreInfo.Path; | |
| // if ((object) result == null) { | |
| // result = GetParts(UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.UriEscaped); | |
| // info.MoreInfo.Path = result; | |
| // } | |
| // return result; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // | |
| // // | |
| // public string AbsoluteUri { | |
| // get { | |
| // if (m_Syntax == null){ | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // UriInfo info = EnsureUriInfo(); | |
| // if ((object) info.MoreInfo == null) { | |
| // info.MoreInfo = new MoreInfo(); | |
| // } | |
| // string result = info.MoreInfo.AbsoluteUri; | |
| // if ((object) result == null) { | |
| // result = GetParts(UriComponents.AbsoluteUri, UriFormat.UriEscaped); | |
| // info.MoreInfo.AbsoluteUri = result; | |
| // } | |
| // return result; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // LocalPath | |
| // // | |
| // // Returns a 'local' version of the path. This is mainly for file: URI | |
| // // such that DOS and UNC paths are returned with '/' converted back to | |
| // // '\', and any escape sequences converted | |
| // // | |
| // // The form of the returned path is in NOT Escaped | |
| // // | |
| // public string LocalPath { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // return GetLocalPath(); | |
| // } | |
| // } | |
| // | |
| // #region !Silverlight | |
| // // | |
| // // | |
| // // The result is of the form "hostname[:port]" Port is omitted if default | |
| // // | |
| // public string Authority { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // // | |
| // return GetParts(UriComponents.Host | UriComponents.Port, UriFormat.UriEscaped); | |
| // } | |
| // } | |
| // // | |
| // // | |
| // public UriHostNameType HostNameType { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // if (m_Syntax.IsSimple) | |
| // EnsureUriInfo(); | |
| // else | |
| // { | |
| // // For a custom parser we request HostString creation to confirm HostType | |
| // EnsureHostString(false); | |
| // } | |
| // | |
| // switch (HostType) { | |
| // case Flags.DnsHostType: return UriHostNameType.Dns; | |
| // case Flags.IPv4HostType: return UriHostNameType.IPv4; | |
| // case Flags.IPv6HostType: return UriHostNameType.IPv6; | |
| // case Flags.BasicHostType: return UriHostNameType.Basic; | |
| // #if !PLATFORM_UNIX | |
| // case Flags.UncHostType: return UriHostNameType.Basic; //return (UriHostNameType)(UriHostNameType.Basic+10); | |
| // #endif // !PLATFORM_UNIX | |
| // case Flags.UnknownHostType: return UriHostNameType.Unknown; | |
| // default: | |
| // break; | |
| // } | |
| // return UriHostNameType.Unknown; | |
| // } | |
| // } | |
| // // | |
| // // | |
| // public bool IsDefaultPort { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // if (m_Syntax.IsSimple) | |
| // EnsureUriInfo(); | |
| // else | |
| // { | |
| // // For a custom parser we request HostString creation that will aso set the port | |
| // EnsureHostString(false); | |
| // } | |
| // | |
| // return NotAny(Flags.NotDefaultPort); | |
| // } | |
| // } | |
| // // | |
| // // | |
| // public bool IsFile { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // return (object)m_Syntax.SchemeName == (object)UriSchemeFile; | |
| // } | |
| // } | |
| // // | |
| // // | |
| // public bool IsLoopback { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // EnsureHostString(false); | |
| // | |
| // return InFact(Flags.LoopbackHost); | |
| // } | |
| // } | |
| // | |
| // // | |
| // // | |
| // // Gets the escaped Uri.AbsolutePath and Uri.Query | |
| // // properties separated by a "?" character. | |
| // public string PathAndQuery { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // string result = GetParts(UriComponents.PathAndQuery, UriFormat.UriEscaped); | |
| // // | |
| // // | |
| // | |
| // | |
| // if (IsDosPath && result[0] == '/') { | |
| // result = result.Substring(1); | |
| // } | |
| // return result; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // | |
| // // Gets an array of the segments that make up a URI. | |
| // public string[] Segments { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // string[] segments = null; // used to be a class cached result | |
| // if (segments == null) { | |
| // | |
| // string path = PrivateAbsolutePath; | |
| // | |
| // if (path.Length == 0) { | |
| // segments = new string[0]; | |
| // } | |
| // else { | |
| // System.Collections.ArrayList pathSegments = new System.Collections.ArrayList(); | |
| // int current = 0; | |
| // while (current < path.Length) { | |
| // int next = path.IndexOf('/', current); | |
| // if (next == -1) { | |
| // next = path.Length - 1; | |
| // } | |
| // pathSegments.Add(path.Substring(current, (next - current) + 1)); | |
| // current = next + 1; | |
| // } | |
| // segments = (string[])(pathSegments.ToArray(typeof(string))); | |
| // } | |
| // } | |
| // return segments; | |
| // } | |
| // } | |
| // | |
| // #endregion !Silverlight | |
| // | |
| // // | |
| // // | |
| // public bool IsUnc { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // return IsUncPath; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // Gets a hostname part (special formatting for IPv6 form) | |
| // public string Host { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // return GetParts(UriComponents.Host, UriFormat.UriEscaped); | |
| // } | |
| // } | |
| // | |
| // private static bool StaticIsFile(UriParser syntax) | |
| // { | |
| // return syntax.InFact(UriSyntaxFlags.FileLikeUri); | |
| // } | |
| // | |
| // private static volatile bool s_ConfigInitialized; // Have the config values been initalized from config file | |
| // private static volatile bool s_ConfigInitializing; // used for recursion detection while init. config values | |
| // | |
| // // Value from config Uri section | |
| // // The use of this IDN mechanic is discouraged on Win8+ due to native platform improvements. | |
| // private static volatile UriIdnScope s_IdnScope = IdnElement.EnabledDefaultValue; | |
| // | |
| // // Value from config Uri section | |
| // // On by default in .NET 4.5+ and cannot be disabled by config. | |
| // private static volatile bool s_IriParsing = | |
| // (UriParser.ShouldUseLegacyV2Quirks ? IriParsingElement.EnabledDefaultValue : true); | |
| // | |
| // private static object s_initLock; | |
| // | |
| // private static object InitializeLock { | |
| // get { | |
| // if (s_initLock == null) { | |
| // object o = new object(); | |
| // Interlocked.CompareExchange(ref s_initLock, o, null); | |
| // } | |
| // return s_initLock; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // Reads values from config uri section | |
| // // | |
| // // This method is called if: | |
| // // - a Uri is constructed, we parse the string and we find '%', >127 chars, or 'xn--' | |
| // // - we parse the host and figure out if it is an IPv6 address | |
| // private static void InitializeUriConfig() | |
| // { | |
| // if (!s_ConfigInitialized) { | |
| // lock(InitializeLock) { | |
| // if (!s_ConfigInitialized && !s_ConfigInitializing) { | |
| // | |
| // // setting s_ConfigInitializing to true makes sure, that in web scenarios, | |
| // // where Uri instances may be created while parsing the web.config files, will not | |
| // // call into this code block again. We'll enter the following code only once per | |
| // // AppDomain. | |
| // s_ConfigInitializing = true; | |
| // UriSectionInternal section = UriSectionInternal.GetSection(); | |
| // | |
| // if (section != null) { | |
| // s_IdnScope = section.IdnScope; | |
| // // Iri can no longer be altered by the config, it is always on. | |
| // if (UriParser.ShouldUseLegacyV2Quirks) { | |
| // s_IriParsing = section.IriParsing; | |
| // } | |
| // | |
| // SetEscapedDotSlashSettings(section, "http"); | |
| // SetEscapedDotSlashSettings(section, "https"); | |
| // SetEscapedDotSlashSettings(section, Uri.UriSchemeWs); | |
| // SetEscapedDotSlashSettings(section, Uri.UriSchemeWss); | |
| // } | |
| // | |
| // s_ConfigInitialized = true; | |
| // s_ConfigInitializing = false; | |
| // } | |
| // } | |
| // } | |
| // } | |
| // | |
| // // Legacy - This no longer has any affect in .NET 4.5 (non-quirks). See UriParser.HttpSyntaxFlags. | |
| // private static void SetEscapedDotSlashSettings(UriSectionInternal uriSection, string scheme) | |
| // { | |
| // // Currently we only support setting DontUnescapePathDotsAndSlashes for HTTP and HTTPS schemes. | |
| // // We ignore all other values. We won't throw for two reasons: | |
| // // - backward compatibility: Uri didn't throw so far. | |
| // // - the config section gets only read if we actually find e.g. a %-character in the Uri. If not, this | |
| // // code never gets executed, resulting in a weird behavior for the customer: If one application run | |
| // // doesn't use Uris with %-characters, it doesn't throw, if another run uses %-characters it throws. | |
| // // => If we want to throw we have to rethink the current implementation. | |
| // SchemeSettingInternal schemeSetting = uriSection.GetSchemeSetting(scheme); | |
| // if (schemeSetting != null) { | |
| // // We check for equality, not if Options contains DontUnescapePathDotsAndSlashes: | |
| // // Currently we only support this flag. If more than this flag are set, then it is an invalid | |
| // // setting and we ignore it. | |
| // if (schemeSetting.Options == GenericUriParserOptions.DontUnescapePathDotsAndSlashes) { | |
| // UriParser parser = UriParser.GetSyntax(scheme); | |
| // parser.SetUpdatableFlags(UriSyntaxFlags.None); | |
| // } | |
| // } | |
| // } | |
| // | |
| // private string GetLocalPath(){ | |
| // EnsureParseRemaining(); | |
| // | |
| // //Other cases will get a Unix-style path | |
| // if (IsUncOrDosPath) | |
| // { | |
| // EnsureHostString(false); | |
| // int start; | |
| // | |
| // // Do we have a valid local path right in m_string? | |
| // if (NotAny(Flags.HostNotCanonical|Flags.PathNotCanonical|Flags.ShouldBeCompressed)) { | |
| // | |
| // start = IsUncPath? m_Info.Offset.Host-2 :m_Info.Offset.Path; | |
| // | |
| // string str = (IsImplicitFile && m_Info.Offset.Host == (IsDosPath ? 0 : 2) && | |
| // m_Info.Offset.Query == m_Info.Offset.End) | |
| // ? m_String | |
| // : (IsDosPath && (m_String[start] == '/' || m_String[start] == '\\')) | |
| // ? m_String.Substring(start + 1, m_Info.Offset.Query - start - 1) | |
| // : m_String.Substring(start, m_Info.Offset.Query - start); | |
| // | |
| // // Should be a rare case, convert c|\ into c:\ | |
| // if (IsDosPath && str[1] == '|') { | |
| // // Sadly, today there is no method for replacong just one occurrence | |
| // str = str.Remove(1, 1); | |
| // str = str.Insert(1, ":"); | |
| // } | |
| // | |
| // // check for all back slashes (though may be string.Replace is smart?) | |
| // for (int i = 0; i < str.Length; ++i) { | |
| // if (str[i] == '/') { | |
| // str = str.Replace('/', '\\'); | |
| // break; | |
| // } | |
| // } | |
| // | |
| // return str; | |
| // } | |
| // | |
| // // Not everything went well, trying harder | |
| // | |
| // char[] result; | |
| // int count = 0; | |
| // start = m_Info.Offset.Path; | |
| // | |
| // string host = m_Info.Host; | |
| // result = new char [host.Length + 3 + m_Info.Offset.Fragment - m_Info.Offset.Path ]; | |
| // | |
| // if (IsUncPath) | |
| // { | |
| // result[0] = '\\'; | |
| // result[1] = '\\'; | |
| // count = 2; | |
| // | |
| // UriHelper.UnescapeString(host, 0, host.Length, result, ref count, c_DummyChar, c_DummyChar, | |
| // c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, false); | |
| // | |
| // } | |
| // else { | |
| // // Dos path | |
| // if(m_String[start] == '/' || m_String[start] == '\\') { | |
| // // Skip leading slash for a DOS path | |
| // ++start; | |
| // } | |
| // } | |
| // | |
| // | |
| // ushort pathStart = (ushort)count; //save for optional Compress() call | |
| // | |
| // UnescapeMode mode = (InFact(Flags.PathNotCanonical) && !IsImplicitFile) | |
| // ? (UnescapeMode.Unescape | UnescapeMode.UnescapeAll): UnescapeMode.CopyOnly; | |
| // UriHelper.UnescapeString(m_String, start, m_Info.Offset.Query, result, ref count, c_DummyChar, | |
| // c_DummyChar, c_DummyChar, mode, m_Syntax, true); | |
| // | |
| // // Possibly convert c|\ into c:\ | |
| // if (result[1] == '|') | |
| // result[1] = ':'; | |
| // | |
| // if (InFact(Flags.ShouldBeCompressed)) { | |
| // // suspecting not compressed path | |
| // // For a dos path we won't compress the "x:" part if found /../ sequences | |
| // result = Compress(result, (ushort)(IsDosPath? pathStart + 2: pathStart), ref count, m_Syntax); | |
| // } | |
| // | |
| // // We don't know whether all slashes were the back ones | |
| // // Plus going through Compress will turn them into / anyway | |
| // // Converting / back into \ | |
| // for (ushort i = 0; i < (ushort) count; ++i) { | |
| // if (result[i] == '/') { | |
| // result[i] = '\\'; | |
| // } | |
| // } | |
| // | |
| // return new string(result, 0, count); | |
| // | |
| // } | |
| // else { | |
| // // Return unescaped canonical path | |
| // // Note we cannot call GetParts here because it has circular dependancy on GelLocalPath method | |
| // return GetUnescapedParts(UriComponents.Path | UriComponents.KeepDelimiter, UriFormat.Unescaped); | |
| // } | |
| // } | |
| // | |
| // // | |
| // // | |
| // // | |
| // // | |
| // public int Port { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // if (m_Syntax.IsSimple) | |
| // EnsureUriInfo(); | |
| // else | |
| // { | |
| // // For a custom parser we request HostString creation that will aso set the port | |
| // EnsureHostString(false); | |
| // } | |
| // | |
| // if (InFact(Flags.NotDefaultPort)) { | |
| // return (int)m_Info.Offset.PortValue; | |
| // } | |
| // return m_Syntax.DefaultPort; | |
| // } | |
| // } | |
| // // | |
| // // | |
| // // | |
| // // Gets the escaped query. | |
| // public string Query { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // UriInfo info = EnsureUriInfo(); | |
| // if ((object)info.MoreInfo == null) { | |
| // info.MoreInfo = new MoreInfo(); | |
| // } | |
| // string result = info.MoreInfo.Query; | |
| // if ((object)result == null) { | |
| // result = GetParts(UriComponents.Query | UriComponents.KeepDelimiter, UriFormat.UriEscaped); | |
| // info.MoreInfo.Query = result; | |
| // } | |
| // return result; | |
| // } | |
| // } | |
| // // | |
| // // | |
| // // | |
| // // Gets the escaped fragment. | |
| // public string Fragment { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // UriInfo info = EnsureUriInfo(); | |
| // if ((object)info.MoreInfo == null) { | |
| // info.MoreInfo = new MoreInfo(); | |
| // } | |
| // string result = info.MoreInfo.Fragment; | |
| // if ((object)result == null) { | |
| // result = GetParts(UriComponents.Fragment | UriComponents.KeepDelimiter, UriFormat.UriEscaped); | |
| // info.MoreInfo.Fragment = result; | |
| // } | |
| // return result; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // Gets the Scheme string of this Uri | |
| // // | |
| // // | |
| // public string Scheme { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // return m_Syntax.SchemeName; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // Was the original string switched from m_String to m_OriginalUnicodeString | |
| // // Will happen when Iri is turned on and we have unicode chars or of idn is | |
| // // is on and we have an idn or unicode host. | |
| // // | |
| // private bool OriginalStringSwitched | |
| // { | |
| // get{return ((m_iriParsing && InFact(Flags.HasUnicode)) || | |
| // (AllowIdn && (InFact(Flags.IdnHost) || InFact(Flags.UnicodeHost))));} | |
| // } | |
| // // | |
| // // Gets the exact string passed by a user. | |
| // public String OriginalString { | |
| // get { | |
| // return OriginalStringSwitched ? m_originalUnicodeString : m_String; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // Gets the host string that is unescaped and if it's Ipv6 host, | |
| // // then the returned string is suitable for DNS lookup. | |
| // // | |
| // // For Ipv6 this will strip [] and add ScopeId if was found in the original string | |
| // public string DnsSafeHost { | |
| // get { | |
| // | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // if (AllowIdn && (((m_Flags & Flags.IdnHost) != 0) || ((m_Flags & Flags.UnicodeHost) != 0))){ | |
| // // return pre generated idn | |
| // EnsureUriInfo(); | |
| // return m_Info.DnsSafeHost; | |
| // } | |
| // | |
| // EnsureHostString(false); | |
| // | |
| // if (!String.IsNullOrEmpty(m_Info.DnsSafeHost)) { | |
| // // Cached | |
| // return m_Info.DnsSafeHost; | |
| // } else if (m_Info.Host.Length == 0) { | |
| // // Empty host, no possible processing | |
| // return String.Empty; | |
| // } | |
| // | |
| // // Special case, will include ScopeID and strip [] around IPv6 | |
| // // This will also unescape the host string | |
| // string ret = m_Info.Host; | |
| // | |
| // if (HostType == Flags.IPv6HostType) { | |
| // ret = ret.Substring(1, ret.Length - 2); | |
| // if ((object)m_Info.ScopeId != null) { | |
| // ret += m_Info.ScopeId; | |
| // } | |
| // } | |
| // // Validate that this basic host qualifies as Dns safe, | |
| // // It has looser parsing rules that might allow otherwise. | |
| // // It might be a registry-based host from RFC 2396 Section 3.2.1 | |
| // else if (HostType == Flags.BasicHostType | |
| // && InFact(Flags.HostNotCanonical | Flags.E_HostNotCanonical)) { | |
| // // Unescape everything | |
| // char[] dest = new char[ret.Length]; | |
| // int count = 0; | |
| // UriHelper.UnescapeString(ret, 0, ret.Length, dest, ref count, c_DummyChar, c_DummyChar, | |
| // c_DummyChar, UnescapeMode.Unescape | UnescapeMode.UnescapeAll, m_Syntax, false); | |
| // ret = new string(dest, 0, count); | |
| // } | |
| // | |
| // m_Info.DnsSafeHost = ret; | |
| // | |
| // return ret; | |
| // } | |
| // } | |
| // | |
| // // Returns the host name represented as IDN (using punycode encoding) regardless of app.config settings | |
| // public string IdnHost { | |
| // get { | |
| // string host = this.DnsSafeHost; | |
| // | |
| // if (HostType == Flags.DnsHostType) { | |
| // host = DomainNameHelper.IdnEquivalent(host); | |
| // } | |
| // | |
| // return host; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // Returns false if the string passed in the constructor cannot be parsed as | |
| // // valid AbsoluteUri. This could be a relative Uri instead. | |
| // // | |
| // public bool IsAbsoluteUri { | |
| // get { | |
| // return m_Syntax != null; | |
| // } | |
| // } | |
| // // | |
| // // | |
| // // Returns 'true' if the 'dontEscape' parameter was set to 'true ' when the Uri instance was created. | |
| // public bool UserEscaped { | |
| // get { | |
| // return InFact(Flags.UserEscaped); | |
| // } | |
| // } | |
| // // | |
| // // | |
| // // Gets the user name, password, and other user specific information associated | |
| // // with the Uniform Resource Identifier (URI). | |
| // public string UserInfo { | |
| // get { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // return GetParts(UriComponents.UserInfo, UriFormat.UriEscaped); | |
| // } | |
| // } | |
| // | |
| // #region !Silverlight | |
| // | |
| // // | |
| // // CheckHostName | |
| // // | |
| // // Determines whether a host name authority is a valid Host name according | |
| // // to DNS naming rules and IPv4 canonicalization rules | |
| // // | |
| // // Returns: | |
| // // true if <name> is valid else false | |
| // // | |
| // // Throws: | |
| // // Nothing | |
| // // | |
| // public static UriHostNameType CheckHostName(string name) { | |
| // | |
| // if ((object)name == null || name.Length == 0 || name.Length > short.MaxValue) { | |
| // return UriHostNameType.Unknown; | |
| // } | |
| // int end = name.Length; | |
| // unsafe { | |
| // fixed (char* fixedName = name) { | |
| // | |
| // if (name[0] == '[' && name[name.Length-1] == ']') { | |
| // // we require that _entire_ name is recognized as ipv6 address | |
| // if (IPv6AddressHelper.IsValid(fixedName, 1, ref end) && end == name.Length) { | |
| // return UriHostNameType.IPv6; | |
| // } | |
| // } | |
| // end = name.Length; | |
| // if (IPv4AddressHelper.IsValid(fixedName, 0 , ref end, false, false, false) && end == name.Length) { | |
| // return UriHostNameType.IPv4; | |
| // } | |
| // end = name.Length; | |
| // bool dummyBool = false; | |
| // if (DomainNameHelper.IsValid(fixedName, 0, ref end, ref dummyBool, false) && end == name.Length) { | |
| // return UriHostNameType.Dns; | |
| // } | |
| // | |
| // end = name.Length; | |
| // dummyBool = false; | |
| // if (DomainNameHelper.IsValidByIri(fixedName, 0, ref end, ref dummyBool, false) | |
| // && end == name.Length) { | |
| // return UriHostNameType.Dns; | |
| // } | |
| // } | |
| // | |
| // //This checks the form without [] | |
| // end = name.Length+2; | |
| // // we require that _entire_ name is recognized as ipv6 address | |
| // name = "["+name+"]"; | |
| // fixed (char* newFixedName = name) { | |
| // if (IPv6AddressHelper.IsValid(newFixedName, 1, ref end) && end == name.Length) { | |
| // return UriHostNameType.IPv6; | |
| // } | |
| // } | |
| // } | |
| // return UriHostNameType.Unknown; | |
| // } | |
| // | |
| // // | |
| // // GetLeftPart | |
| // // | |
| // // Returns part of the URI based on the parameters: | |
| // // | |
| // // Inputs: | |
| // // <argument> part | |
| // // Which part of the URI to return | |
| // // | |
| // // Returns: | |
| // // The requested substring | |
| // // | |
| // // Throws: | |
| // // UriFormatException if URI type doesn't have host-port or authority parts | |
| // // | |
| // public string GetLeftPart(UriPartial part) { | |
| // if (IsNotAbsoluteUri) { | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // } | |
| // | |
| // EnsureUriInfo(); | |
| // const UriComponents NonPathPart = (UriComponents.Scheme | UriComponents.UserInfo | UriComponents.Host | UriComponents.Port); | |
| // | |
| // switch (part) { | |
| // case UriPartial.Scheme: | |
| // | |
| // return GetParts(UriComponents.Scheme | UriComponents.KeepDelimiter, UriFormat.UriEscaped); | |
| // | |
| // case UriPartial.Authority: | |
| // | |
| // if (NotAny(Flags.AuthorityFound) || IsDosPath) { | |
| // | |
| // // | |
| // | |
| // | |
| // | |
| // // From V1.0 comments: | |
| // | |
| // // anything that didn't have "//" after the scheme name | |
| // // (mailto: and news: e.g.) doesn't have an authority | |
| // // | |
| // | |
| // return String.Empty; | |
| // } | |
| // return GetParts(NonPathPart, UriFormat.UriEscaped); | |
| // | |
| // case UriPartial.Path: | |
| // return GetParts(NonPathPart | UriComponents.Path, UriFormat.UriEscaped); | |
| // | |
| // case UriPartial.Query: | |
| // return GetParts(NonPathPart | UriComponents.Path | UriComponents.Query, UriFormat.UriEscaped); | |
| // | |
| // } | |
| // throw new ArgumentException("part"); | |
| // } | |
| // | |
| // // | |
| // // | |
| // /// Transforms a character into its hexadecimal representation. | |
| // public static string HexEscape(char character) { | |
| // if (character > '\xff') { | |
| // throw new ArgumentOutOfRangeException("character"); | |
| // } | |
| // char[] chars = new char[3]; | |
| // int pos = 0; | |
| // UriHelper.EscapeAsciiChar(character, chars, ref pos); | |
| // return new string(chars); | |
| // } | |
| // | |
| // // | |
| // // HexUnescape | |
| // // | |
| // // Converts a substring of the form "%XX" to the single character represented | |
| // // by the hexadecimal value XX. If the substring s[Index] does not conform to | |
| // // the hex encoding format then the character at s[Index] is returned | |
| // // | |
| // // Inputs: | |
| // // <argument> pattern | |
| // // String from which to read the hexadecimal encoded substring | |
| // // | |
| // // <argument> index | |
| // // Offset within <pattern> from which to start reading the hexadecimal | |
| // // encoded substring | |
| // // | |
| // // Outputs: | |
| // // <argument> index | |
| // // Incremented to the next character position within the string. This | |
| // // may be EOS if this was the last character/encoding within <pattern> | |
| // // | |
| // // Returns: | |
| // // Either the converted character if <pattern>[<index>] was hex encoded, or | |
| // // the character at <pattern>[<index>] | |
| // // | |
| // // Throws: | |
| // // ArgumentOutOfRangeException | |
| // // | |
| // | |
| // public static char HexUnescape(string pattern, ref int index) { | |
| // if ((index < 0) || (index >= pattern.Length)) { | |
| // throw new ArgumentOutOfRangeException("index"); | |
| // } | |
| // if ((pattern[index] == '%') | |
| // && (pattern.Length - index >= 3)) { | |
| // char ret = UriHelper.EscapedAscii(pattern[index + 1], pattern[index + 2]); | |
| // if (ret != c_DummyChar) { | |
| // index += 3; | |
| // return ret; | |
| // } | |
| // } | |
| // return pattern[index++]; | |
| // } | |
| // | |
| // // | |
| // // IsHexEncoding | |
| // // | |
| // // Determines whether a substring has the URI hex encoding format of '%' | |
| // // followed by 2 hexadecimal characters | |
| // // | |
| // // Inputs: | |
| // // <argument> pattern | |
| // // String to check | |
| // // | |
| // // <argument> index | |
| // // Offset in <pattern> at which to check substring for hex encoding | |
| // // | |
| // // Assumes: | |
| // // 0 <= <index> < <pattern>.Length | |
| // // | |
| // // Returns: | |
| // // true if <pattern>[<index>] is hex encoded, else false | |
| // // | |
| // // Throws: | |
| // // Nothing | |
| // // | |
| // public static bool IsHexEncoding(string pattern, int index) { | |
| // if ((pattern.Length - index) < 3) { | |
| // return false; | |
| // } | |
| // if ((pattern[index] == '%') && UriHelper.EscapedAscii(pattern[index + 1], pattern[index + 2]) != c_DummyChar) { | |
| // return true; | |
| // } | |
| // return false; | |
| // } | |
| // | |
| // // | |
| // // Is this a gen delim char from RFC 3986 | |
| // // | |
| // internal static bool IsGenDelim(char ch) | |
| // { | |
| // return (ch == ':' || ch == '/' || ch == '?' || ch == '#' || ch == '[' || ch == ']' || ch == '@'); | |
| // } | |
| // | |
| // #endregion !Silverlight | |
| // | |
| // // | |
| // // CheckSchemeName | |
| // // | |
| // // Determines whether a string is a valid scheme name according to RFC 2396. | |
| // // Syntax is: | |
| // // scheme = alpha *(alpha | digit | '+' | '-' | '.') | |
| // // | |
| // public static bool CheckSchemeName(string schemeName) { | |
| // if (((object)schemeName == null) | |
| // || (schemeName.Length == 0) | |
| // || !IsAsciiLetter(schemeName[0])) { | |
| // return false; | |
| // } | |
| // for (int i = schemeName.Length - 1; i > 0; --i) { | |
| // if (!(IsAsciiLetterOrDigit(schemeName[i]) | |
| // || (schemeName[i] == '+') | |
| // || (schemeName[i] == '-') | |
| // || (schemeName[i] == '.'))) { | |
| // return false; | |
| // } | |
| // } | |
| // return true; | |
| // } | |
| // | |
| // // | |
| // // IsHexDigit | |
| // // | |
| // // Determines whether a character is a valid hexadecimal digit in the range | |
| // // [0..9] | [A..F] | [a..f] | |
| // // | |
| // // Inputs: | |
| // // <argument> character | |
| // // Character to test | |
| // // | |
| // // Returns: | |
| // // true if <character> is a hexadecimal digit character | |
| // // | |
| // // Throws: | |
| // // Nothing | |
| // // | |
| // public static bool IsHexDigit(char character) { | |
| // return ((character >= '0') && (character <= '9')) | |
| // || ((character >= 'A') && (character <= 'F')) | |
| // || ((character >= 'a') && (character <= 'f')); | |
| // } | |
| // | |
| // // | |
| // // Returns: | |
| // // Number in the range 0..15 | |
| // // | |
| // // Throws: | |
| // // ArgumentException | |
| // // | |
| // public static int FromHex(char digit) { | |
| // if (((digit >= '0') && (digit <= '9')) | |
| // || ((digit >= 'A') && (digit <= 'F')) | |
| // || ((digit >= 'a') && (digit <= 'f'))) { | |
| // return (digit <= '9') | |
| // ? ((int)digit - (int)'0') | |
| // : (((digit <= 'F') | |
| // ? ((int)digit - (int)'A') | |
| // : ((int)digit - (int)'a')) | |
| // + 10); | |
| // } | |
| // throw new ArgumentException("digit"); | |
| // } | |
| // // | |
| // // GetHashCode | |
| // // | |
| // // Overrides default function (in Object class) | |
| // // | |
| // // | |
| // [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] | |
| // public override int GetHashCode() { | |
| // if (IsNotAbsoluteUri) | |
| // { | |
| // return CalculateCaseInsensitiveHashCode(OriginalString); | |
| // } | |
| // | |
| // // Consider moving hash code storage from m_Info.MoreInfo to m_Info | |
| // UriInfo info = EnsureUriInfo(); | |
| // if ((object)info.MoreInfo == null) { | |
| // info.MoreInfo = new MoreInfo(); | |
| // } | |
| // int tempHash = info.MoreInfo.Hash; | |
| // if (tempHash == 0) { | |
| // string chkString = info.MoreInfo.RemoteUrl; | |
| // if ((object) chkString == null) | |
| // chkString = GetParts(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped); | |
| // tempHash = CalculateCaseInsensitiveHashCode(chkString); | |
| // if (tempHash == 0) { | |
| // tempHash = 0x1000000; //making it not zero still large enough to be maped to zero by a hashtable | |
| // } | |
| // info.MoreInfo.Hash = tempHash; | |
| // } | |
| // return tempHash; | |
| // } | |
| // | |
| // // | |
| // // ToString | |
| // // | |
| // // The better implementation would be just | |
| // // | |
| // private const UriFormat V1ToStringUnescape = (UriFormat)0x7FFF; | |
| // | |
| // [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] | |
| // public override string ToString() | |
| // { | |
| // if (m_Syntax == null) { | |
| // return (m_iriParsing && InFact(Flags.HasUnicode)) ? m_String : OriginalString; | |
| // } | |
| // | |
| // EnsureUriInfo(); | |
| // if ((object)m_Info.String == null) | |
| // { | |
| // | |
| // // V1.1 compat unless #353711 is appoved, otheriwse it should be just a call into GetParts() as shown below | |
| // // m_Info.String = GetParts(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped); | |
| // | |
| // if (Syntax.IsSimple) | |
| // m_Info.String = GetComponentsHelper(UriComponents.AbsoluteUri, V1ToStringUnescape); | |
| // else | |
| // m_Info.String = GetParts(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped); | |
| // | |
| // } | |
| // return m_Info.String; | |
| // } | |
| // | |
| // // | |
| // // | |
| // // A static shortcut to Uri.Equals | |
| // // | |
| // [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] | |
| // public static bool operator == (Uri uri1, Uri uri2) { | |
| // if ((object)uri1 == (object)uri2) { | |
| // return true; | |
| // } | |
| // if ((object)uri1 == null || (object)uri2 == null) { | |
| // return false; | |
| // } | |
| // return uri2.Equals(uri1); | |
| // } | |
| // | |
| // // | |
| // // | |
| // // A static shortcut to !Uri.Equals | |
| // // | |
| // [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] | |
| // public static bool operator != (Uri uri1, Uri uri2) { | |
| // if ((object)uri1 == (object)uri2) { | |
| // return false; | |
| // } | |
| // | |
| // if ((object)uri1 == null || (object)uri2 == null) { | |
| // return true; | |
| // } | |
| // | |
| // return !uri2.Equals(uri1); | |
| // } | |
| // | |
| // | |
| // | |
| // // | |
| // // Equals | |
| // // | |
| // // Overrides default function (in Object class) | |
| // // | |
| // // Assumes: | |
| // // <comparand> is an object of class Uri | |
| // // | |
| // // Returns: | |
| // // true if objects have the same value, else false | |
| // // | |
| // // Throws: | |
| // // Nothing | |
| // // | |
| // [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.Infrastructure)] | |
| // public override bool Equals(object comparand) { | |
| // if ((object) comparand == null) { | |
| // return false; | |
| // } | |
| // | |
| // if ((object)this == (object)comparand) { | |
| // return true; | |
| // } | |
| // | |
| // Uri obj = comparand as Uri; | |
| // | |
| // // | |
| // // we allow comparisons of Uri and String objects only. If a string | |
| // // is passed, convert to Uri. This is inefficient, but allows us to | |
| // // canonicalize the comparand, making comparison possible | |
| // // | |
| // if ((object)obj == null) { | |
| // string s = comparand as string; | |
| // | |
| // if ((object)s == null) | |
| // return false; | |
| // | |
| // if (!TryCreate(s, UriKind.RelativeOrAbsolute, out obj)) | |
| // return false; | |
| // } | |
| // | |
| // // Since v1.0 two Uris are equal if everything but fragment and UserInfo does match | |
| // | |
| // // This check is for a case where we already fixed up the equal references | |
| // if ((object)this.m_String == (object)obj.m_String) { | |
| // return true; | |
| // } | |
| // | |
| // if (IsAbsoluteUri != obj.IsAbsoluteUri) | |
| // return false; | |
| // | |
| // if (IsNotAbsoluteUri) | |
| // return OriginalString.Equals(obj.OriginalString); | |
| // | |
| // if (NotAny(Flags.AllUriInfoSet) || obj.NotAny(Flags.AllUriInfoSet)) { | |
| // // Try raw compare for m_Strings as the last chance to keep the working set small | |
| // if (!IsUncOrDosPath ) { | |
| // if (m_String.Length == obj.m_String.Length) { | |
| // unsafe { | |
| // // Try case sensitive compare on m_Strings | |
| // fixed (char* pMe = m_String) { | |
| // fixed (char* pShe = obj.m_String) { | |
| // // This will never go negative since m_String is checked to be a valid URI | |
| // int i = (m_String.Length-1); | |
| // for ( ;i >= 0 ; --i) { | |
| // if (*(pMe+i) != *(pShe+i)) { | |
| // break; | |
| // } | |
| // } | |
| // if (i == -1) { | |
| // return true; | |
| // } | |
| // } | |
| // } | |
| // } | |
| // } | |
| // } | |
| // else if (String.Compare(m_String, obj.m_String, StringComparison.OrdinalIgnoreCase) == 0) { | |
| // return true; | |
| // } | |
| // } | |
| // | |
| // // Note that equality test will bring the working set of both | |
| // // objects up to creation of m_Info.MoreInfo member | |
| // EnsureUriInfo(); | |
| // obj.EnsureUriInfo(); | |
| // | |
| // if (!UserDrivenParsing && !obj.UserDrivenParsing && Syntax.IsSimple && obj.Syntax.IsSimple) | |
| // { | |
| // // Optimization of canonical DNS names by avoiding host string creation. | |
| // // Note there could be explicit ports specified that would invalidate path offsets | |
| // if (InFact(Flags.CanonicalDnsHost) && obj.InFact(Flags.CanonicalDnsHost)) { | |
| // ushort i1 = m_Info.Offset.Host; | |
| // ushort end1 = m_Info.Offset.Path; | |
| // | |
| // ushort i2 = obj.m_Info.Offset.Host; | |
| // ushort end2 = obj.m_Info.Offset.Path; | |
| // string str = obj.m_String; | |
| // //Taking the shortest part | |
| // if (end1-i1 > end2-i2) { | |
| // end1 = (ushort)(i1 + end2-i2); | |
| // } | |
| // // compare and break on ':' if found | |
| // while (i1 < end1) { | |
| // if (m_String[i1] != str[i2]) { | |
| // return false; | |
| // } | |
| // if (str[i2] == ':') { | |
| // // The other must have ':' too to have equal host | |
| // break; | |
| // } | |
| // ++i1;++i2; | |
| // } | |
| // | |
| // // The longest host must have ':' or be of the same size | |
| // if (i1 < m_Info.Offset.Path && m_String[i1] != ':') { | |
| // return false; | |
| // } | |
| // if (i2 < end2 && str[i2] != ':') { | |
| // return false; | |
| // } | |
| // //hosts are equal! | |
| // } | |
| // else { | |
| // EnsureHostString(false); | |
| // obj.EnsureHostString(false); | |
| // if (!m_Info.Host.Equals(obj.m_Info.Host)) { | |
| // return false; | |
| // } | |
| // } | |
| // | |
| // if (Port != obj.Port) { | |
| // return false; | |
| // } | |
| // } | |
| // | |
| // // see Whidbey#21590 | |
| // // We want to cache RemoteUrl to improve perf for Uri as a key. | |
| // // We should consider reducing the overall working set by not caching some other properties mentioned in MoreInfo | |
| // | |
| // // Mutli-threading! | |
| // UriInfo meInfo = m_Info; | |
| // UriInfo sheInfo = obj.m_Info; | |
| // if ((object)meInfo.MoreInfo == null) { | |
| // meInfo.MoreInfo = new MoreInfo(); | |
| // } | |
| // if ((object)sheInfo.MoreInfo == null) { | |
| // sheInfo.MoreInfo = new MoreInfo(); | |
| // } | |
| // | |
| // // NB: To avoid a race condition when creating MoreInfo field | |
| // // "meInfo" and "sheInfo" shall remain as local copies. | |
| // string me = meInfo.MoreInfo.RemoteUrl; | |
| // if ((object)me == null) { | |
| // me = GetParts(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped); | |
| // meInfo.MoreInfo.RemoteUrl = me; | |
| // } | |
| // string she = sheInfo.MoreInfo.RemoteUrl; | |
| // if ((object)she == null) { | |
| // she = obj.GetParts(UriComponents.HttpRequestUrl, UriFormat.SafeUnescaped); | |
| // sheInfo.MoreInfo.RemoteUrl = she; | |
| // } | |
| // | |
| // if (!IsUncOrDosPath ) { | |
| // if (me.Length != she.Length) { | |
| // return false; | |
| // } | |
| // unsafe { | |
| // // Try case sensitive compare on m_Strings | |
| // fixed (char* pMe = me) { | |
| // fixed (char* pShe = she) { | |
| // char *endMe = pMe + me.Length; | |
| // char *endShe = pShe + me.Length; | |
| // while (endMe != pMe) { | |
| // if (*--endMe != *--endShe) { | |
| // return false; | |
| // } | |
| // } | |
| // return true; | |
| // } | |
| // } | |
| // } | |
| // } | |
| // | |
| // | |
| // // if IsUncOrDosPath is true then we ignore case in the path comparison | |
| // // Get Unescaped form as most safe for the comparison | |
| // // Fragment AND UserInfo are ignored | |
| // // | |
| // return (String.Compare(meInfo.MoreInfo.RemoteUrl, | |
| // sheInfo.MoreInfo.RemoteUrl, | |
| // IsUncOrDosPath ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal ) == 0); | |
| // } | |
| // // | |
| // public Uri MakeRelativeUri(Uri uri) | |
| // { | |
| // if ((object)uri == null) | |
| // throw new ArgumentNullException("uri"); | |
| // | |
| // if (IsNotAbsoluteUri || uri.IsNotAbsoluteUri) | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // | |
| // // Note that the UserInfo part is ignored when computing a relative Uri. | |
| // if ((Scheme == uri.Scheme) && (Host == uri.Host) && (Port == uri.Port)) | |
| // { | |
| // String otherPath = uri.AbsolutePath; | |
| // | |
| // // Relative Path | |
| // String relativeUriString = PathDifference(AbsolutePath, otherPath, !IsUncOrDosPath); | |
| // | |
| // // Relative Uri's cannot have a colon ':' in the first path segment (RFC 3986, Section 4.2) | |
| // if (CheckForColonInFirstPathSegment(relativeUriString) | |
| // // Except for full implicit dos file paths | |
| // && !(uri.IsDosPath && otherPath.Equals(relativeUriString, StringComparison.Ordinal))) | |
| // relativeUriString = "./" + relativeUriString; | |
| // | |
| // // Query & Fragment | |
| // relativeUriString += uri.GetParts(UriComponents.Query | UriComponents.Fragment, UriFormat.UriEscaped); | |
| // | |
| // return new Uri(relativeUriString, UriKind.Relative); | |
| // } | |
| // return uri; | |
| // } | |
| // | |
| // // | |
| // // http://www.ietf.org/rfc/rfc3986.txt | |
| // // | |
| // // 3.3. Path | |
| // // In addition, a URI reference (Section 4.1) may be a relative-path reference, in which case the first | |
| // // path segment cannot contain a colon (":") character. | |
| // // | |
| // // 4.2. Relative Reference | |
| // // A path segment that contains a colon character (e.g., "this:that") cannot be used as the first segment | |
| // // of a relative-path reference, as it would be mistaken for a scheme name. Such a segment must be | |
| // // preceded by a dot-segment (e.g., "./this:that") to make a relative-path reference. | |
| // // | |
| // // 5.4.2. Abnormal Examples | |
| // // http:(relativeUri) may be considered a valid relative Uri. | |
| // // | |
| // // Returns true if a colon is found in the first path segment, false otherwise | |
| // // | |
| // private static bool CheckForColonInFirstPathSegment(String uriString) | |
| // { | |
| // // Check for anything that may terminate the first regular path segment | |
| // // or an illegal colon | |
| // char[] pathDelims = new char[] { ':', '\\', '/', '?', '#' }; | |
| // int index = uriString.IndexOfAny(pathDelims); | |
| // | |
| // return (index >= 0 && uriString[index] == ':'); | |
| // } | |
| // // This is used by UriBuilder, | |
| // | |
| // internal unsafe static string InternalEscapeString(string rawString) { | |
| // if ((object)rawString == null) | |
| // return String.Empty; | |
| // | |
| // int position = 0; | |
| // char[] dest = UriHelper.EscapeString(rawString, 0, rawString.Length, null, ref position, true, '?', '#', '%'); | |
| // if ((object)dest == null) | |
| // return rawString; | |
| // | |
| // return new string(dest, 0, position); | |
| // } | |
| // | |
| // // | |
| // // This method is called first to figure out the scheme or a simple file path | |
| // // Is called only at the .ctor time | |
| // // | |
| // private static unsafe ParsingError ParseScheme(string uriString, ref Flags flags, ref UriParser syntax) | |
| // { | |
| // int length = uriString.Length; | |
| // if (length == 0) | |
| // return ParsingError.EmptyUriString; | |
| // | |
| // // we don;t work with >= 64k Uris | |
| // if (length >= c_MaxUriBufferSize) | |
| // return ParsingError.SizeLimit; | |
| // | |
| // //STEP1: parse scheme, lookup this Uri Syntax or create one using UnknownV1SyntaxFlags uri syntax template | |
| // fixed (char* pUriString = uriString) | |
| // { | |
| // ParsingError err = ParsingError.None; | |
| // ushort idx = ParseSchemeCheckImplicitFile(pUriString, (ushort)length, ref err, ref flags, ref syntax); | |
| // | |
| // if (err != ParsingError.None) | |
| // return err; | |
| // | |
| // flags |= (Flags)idx; | |
| // } | |
| // return ParsingError.None; | |
| // } | |
| // | |
| // // | |
| // // A wrapper for ParseMinimal() called from a user parser | |
| // // It signals back that the call has been done | |
| // // plus it communicates back a flag for an error if any | |
| // // | |
| // internal UriFormatException ParseMinimal() | |
| // { | |
| // ParsingError result = PrivateParseMinimal(); | |
| // if (result == ParsingError.None) | |
| // return null; | |
| // | |
| // // Means the we think the Uri is invalid, bu that can be later overriden by a user parser | |
| // m_Flags |= Flags.ErrorOrParsingRecursion; | |
| // | |
| // return GetException(result); | |
| // } | |
| // // | |
| // // | |
| // // This method tries to parse the minimal information needed to certify the valifity | |
| // // of a uri string | |
| // // | |
| // // scheme://userinfo@host:Port/Path?Query#Fragment | |
| // // | |
| // // The method must be called only at the .ctor time | |
| // // | |
| // // Returns ParsingError.None if the Uri syntax is valid, an error otheriwse | |
| // // | |
| // private unsafe ParsingError PrivateParseMinimal() | |
| // { | |
| // ushort idx = (ushort) (m_Flags & Flags.IndexMask); | |
| // ushort length = (ushort) m_String.Length; | |
| // string newHost = null; // stores newly parsed host when original strings are being switched | |
| // | |
| // // Means a custom UriParser did call "base" InitializeAndValidate() | |
| // m_Flags &= ~(Flags.IndexMask | Flags.UserDrivenParsing); | |
| // | |
| // //STEP2: Parse up to the port | |
| // | |
| // fixed (char* pUriString = ((m_iriParsing && | |
| // ((m_Flags & Flags.HasUnicode)!=0) && | |
| // ((m_Flags & Flags.HostUnicodeNormalized) == 0)) ? m_originalUnicodeString : m_String)) | |
| // { | |
| // // Cut trailing spaces in m_String | |
| // if (length > idx && IsLWS(pUriString[length-1])) | |
| // { | |
| // --length; | |
| // while (length != idx && IsLWS(pUriString[--length])) | |
| // ; | |
| // ++length; | |
| // } | |
| // | |
| // // Microsoft codereview: | |
| // // Old Uri parser tries to figure out on a DosPath in all cases. | |
| // // Hence http://c:/ is treated as as DosPath without the host while it should be a host "c", port 80 | |
| // // | |
| // // This block is compatible with Old Uri parser in terms it will look for the DosPath if the scheme | |
| // // syntax allows both empty hostnames and DosPath | |
| // // | |
| // #if !PLATFORM_UNIX | |
| // if (m_Syntax.IsAllSet(UriSyntaxFlags.AllowEmptyHost | UriSyntaxFlags.AllowDOSPath) | |
| // && NotAny(Flags.ImplicitFile) && (idx + 1 < length)) { | |
| // | |
| // char c; | |
| // ushort i = (ushort) idx; | |
| // | |
| // // V1 Compat: Allow _compression_ of > 3 slashes only for File scheme, see VsWhidbey 87448. | |
| // // This will skip all slashes and if their number is 2+ it sets the AuthorityFound flag | |
| // for (; i < length; ++i) { | |
| // if (!((c=pUriString[i])== '\\' || c == '/')) | |
| // break; | |
| // } | |
| // | |
| // if (m_Syntax.InFact(UriSyntaxFlags.FileLikeUri) || i-idx <= 3) { | |
| // // if more than one slash after the scheme, the authority is present | |
| // if (i-idx >= 2) { | |
| // m_Flags |= Flags.AuthorityFound; | |
| // } | |
| // // DOS-like path? | |
| // if (i+1 < (ushort) length && ((c=pUriString[i+1]) == ':' || c == '|') && | |
| // IsAsciiLetter(pUriString[i])) { | |
| // | |
| // if (i+2 >= (ushort) length || ((c=pUriString[i+2]) != '\\' && c != '/')) | |
| // { | |
| // // report an error but only for a file: scheme | |
| // if (m_Syntax.InFact(UriSyntaxFlags.FileLikeUri)) | |
| // return ParsingError.MustRootedPath; | |
| // } | |
| // else | |
| // { | |
| // // This will set IsDosPath | |
| // m_Flags |= Flags.DosPath; | |
| // | |
| // if (m_Syntax.InFact(UriSyntaxFlags.MustHaveAuthority)) { | |
| // // when DosPath found and Authority is required, set this flag even if Authority is empty | |
| // m_Flags |= Flags.AuthorityFound; | |
| // } | |
| // if (i != idx && i-idx != 2) { | |
| // //This will remember that DosPath is rooted | |
| // idx = (ushort)(i-1); | |
| // } | |
| // else { | |
| // idx = i; | |
| // } | |
| // } | |
| // } | |
| // else if (m_Syntax.InFact(UriSyntaxFlags.FileLikeUri) && (i - idx >= 2 && i - idx != 3 && | |
| // i < length && pUriString[i] != '?' && pUriString[i] != '#')) | |
| // { | |
| // // see VsWhidbey#226745 V1.0 did not support file:///, fixing it with minimal behavior change impact | |
| // // Only FILE scheme may have UNC Path flag set | |
| // m_Flags |= Flags.UncPath; | |
| // idx = i; | |
| // } | |
| // } | |
| // } | |
| // #endif // !PLATFORM_UNIX | |
| // // | |
| // //STEP 1.5 decide on the Authority component | |
| // // | |
| // #if !PLATFORM_UNIX | |
| // if ((m_Flags & (Flags.UncPath|Flags.DosPath)) != 0) { | |
| // } | |
| // #else | |
| // if ((m_Flags & Flags.ImplicitFile) != 0) { | |
| // // Already parsed up to the path | |
| // } | |
| // #endif // !PLATFORM_UNIX | |
| // else if ((idx+2) <= length) { | |
| // char first = pUriString[idx]; | |
| // char second = pUriString[idx+1]; | |
| // | |
| // if (m_Syntax.InFact(UriSyntaxFlags.MustHaveAuthority)) { | |
| // // (V1.0 compatiblity) This will allow http:\\ http:\/ http:/\ | |
| // #if !PLATFORM_UNIX | |
| // if ((first == '/' || first == '\\') && (second == '/' || second == '\\')) | |
| // #else | |
| // if (first == '/' && second == '/') | |
| // #endif // !PLATFORM_UNIX | |
| // { | |
| // m_Flags |= Flags.AuthorityFound; | |
| // idx+=2; | |
| // } | |
| // else { | |
| // return ParsingError.BadAuthority; | |
| // } | |
| // } | |
| // else if (m_Syntax.InFact(UriSyntaxFlags.OptionalAuthority) && (InFact(Flags.AuthorityFound) || | |
| // (first == '/' && second == '/'))) { | |
| // m_Flags |= Flags.AuthorityFound; | |
| // idx+=2; | |
| // } | |
| // // | |
| // else if (m_Syntax.NotAny(UriSyntaxFlags.MailToLikeUri)) { | |
| // // By now we know the URI has no Authority, so if the URI must be normalized, initialize it without one. | |
| // if (m_iriParsing && (m_Flags & Flags.HasUnicode) != 0 && (m_Flags & Flags.HostUnicodeNormalized) == 0) | |
| // { | |
| // m_String = m_String.Substring(0, idx); | |
| // } | |
| // // Since there is no Authority, the path index is just the end of the scheme. | |
| // m_Flags |= ((Flags)idx | Flags.UnknownHostType); | |
| // return ParsingError.None; | |
| // } | |
| // } | |
| // else if (m_Syntax.InFact(UriSyntaxFlags.MustHaveAuthority)) { | |
| // return ParsingError.BadAuthority; | |
| // } | |
| // // | |
| // else if (m_Syntax.NotAny(UriSyntaxFlags.MailToLikeUri)) { | |
| // // By now we know the URI has no Authority, so if the URI must be normalized, initialize it without one. | |
| // if (m_iriParsing && (m_Flags & Flags.HasUnicode) != 0 && (m_Flags & Flags.HostUnicodeNormalized) == 0) | |
| // { | |
| // m_String = m_String.Substring(0, idx); | |
| // } | |
| // // Since there is no Authority, the path index is just the end of the scheme. | |
| // m_Flags |= ((Flags)idx | Flags.UnknownHostType); | |
| // return ParsingError.None; | |
| // } | |
| // | |
| // #if !PLATFORM_UNIX | |
| // // The following sample taken from the original parser comments makes the whole story sad | |
| // // vsmacros://c:\path\file | |
| // // Note that two slashes say there must be an Authority but instead the path goes | |
| // // Fro V1 compat the next block allow this case but not for schemes like http | |
| // if (InFact(Flags.DosPath)) { | |
| // | |
| // m_Flags |= (((m_Flags & Flags.AuthorityFound)!= 0)? Flags.BasicHostType :Flags.UnknownHostType); | |
| // m_Flags |= (Flags)idx; | |
| // return ParsingError.None; | |
| // } | |
| // #endif // !PLATFORM_UNIX | |
| // | |
| // //STEP 2: Check the syntax of authority expecting at least one character in it | |
| // // | |
| // // Note here we do know that there is an authority in the string OR it's a DOS path | |
| // | |
| // // We may find a userInfo and the port when parsing an authority | |
| // // Also we may find a registry based authority. | |
| // // We must ensure that known schemes do use a server-based authority | |
| // { | |
| // ParsingError err = ParsingError.None; | |
| // idx = CheckAuthorityHelper(pUriString, idx, (ushort)length, ref err, ref m_Flags, m_Syntax, ref newHost); | |
| // if (err != ParsingError.None) | |
| // return err; | |
| // | |
| // // This will disallow '\' as the host terminator for any scheme that is not implicitFile or cannot have a Dos Path | |
| // if ((idx < (ushort)length && pUriString[idx] == '\\') && NotAny(Flags.ImplicitFile) && | |
| // m_Syntax.NotAny(UriSyntaxFlags.AllowDOSPath)) { | |
| // return ParsingError.BadAuthorityTerminator; | |
| // } | |
| // | |
| // } | |
| // | |
| // // The Path (or Port) parsing index is reloaded on demand in CreateUriInfo when accessing a Uri property | |
| // m_Flags |= (Flags)idx; | |
| // | |
| // // The rest of the string will be parsed on demand | |
| // // The Host/Authorty is all checked, the type is known but the host value string | |
| // // is not created/canonicalized at this point. | |
| // } | |
| // | |
| // if((s_IdnScope != UriIdnScope.None) || m_iriParsing) | |
| // PrivateParseMinimalIri(newHost, idx); | |
| // | |
| // return ParsingError.None; | |
| // } | |
| // | |
| // private void PrivateParseMinimalIri(string newHost, ushort idx) | |
| // { | |
| // // we have a new host! | |
| // if (newHost != null) | |
| // m_String = newHost; | |
| // | |
| // // conditions where we dont need to go to parseremaining, so we copy the rest of the | |
| // // original string.. and switch offsets | |
| // if ((!m_iriParsing && AllowIdn && (((m_Flags & Flags.IdnHost) != 0) || ((m_Flags & Flags.UnicodeHost) != 0))) || | |
| // (m_iriParsing && ((m_Flags & Flags.HasUnicode) == 0) && AllowIdn && ((m_Flags & Flags.IdnHost) != 0))){ | |
| // // update the start of path from the end of new string | |
| // m_Flags &= ~(Flags.IndexMask); | |
| // m_Flags |= (Flags)m_String.Length; | |
| // | |
| // m_String += m_originalUnicodeString.Substring(idx, m_originalUnicodeString.Length - idx); | |
| // } | |
| // | |
| // // Indicate to createuriinfo that offset is in m_originalUnicodeString | |
| // if (m_iriParsing && ((m_Flags & Flags.HasUnicode) != 0)){ | |
| // // offset in Flags.IndexMask refers to m_originalUnicodeString | |
| // m_Flags |= Flags.UseOrigUncdStrOffset; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // | |
| // // The method is called when we have to access m_Info members | |
| // // This will create the m_Info based on the copied parser context | |
| // // Under milti-threading ---- this method may do duplicated yet harmless work | |
| // // | |
| // private unsafe void CreateUriInfo(Flags cF) { | |
| // | |
| // UriInfo info = new UriInfo(); | |
| // | |
| // // This will be revisited in ParseRemaining but for now just have it at least m_String.Length | |
| // info.Offset.End = (ushort)m_String.Length; | |
| // | |
| // if (UserDrivenParsing) | |
| // goto Done; | |
| // | |
| // ushort idx; | |
| // bool notCanonicalScheme = false; | |
| // | |
| // // The m_String may have leading spaces, figure that out | |
| // // plus it will set idx value for next steps | |
| // if ((cF & Flags.ImplicitFile) != 0) { | |
| // idx = (ushort)0; | |
| // while (IsLWS(m_String[idx])) { | |
| // ++idx; | |
| // ++info.Offset.Scheme; | |
| // } | |
| // | |
| // #if !PLATFORM_UNIX | |
| // if (StaticInFact(cF, Flags.UncPath)) { | |
| // // For implicit file AND Unc only | |
| // idx += 2; | |
| // //skip any other slashes (compatibility with V1.0 parser) | |
| // while(idx < (ushort)(cF & Flags.IndexMask) && (m_String[idx] == '/' || m_String[idx] == '\\')) { | |
| // ++idx; | |
| // } | |
| // } | |
| // #endif // !PLATFORM_UNIX | |
| // } | |
| // else { | |
| // // This is NOT an ImplicitFile uri | |
| // idx = (ushort)m_Syntax.SchemeName.Length; | |
| // | |
| // while (m_String[idx++] != ':') { | |
| // ++info.Offset.Scheme; | |
| // } | |
| // | |
| // if ((cF & Flags.AuthorityFound) != 0) | |
| // { | |
| // if (m_String[idx] == '\\' || m_String[idx+1] == '\\') | |
| // notCanonicalScheme = true; | |
| // | |
| // idx+=2; | |
| // #if !PLATFORM_UNIX | |
| // if ((cF & (Flags.UncPath|Flags.DosPath)) != 0) { | |
| // // Skip slashes if it was allowed during ctor time | |
| // // NB: Today this is only allowed if a Unc or DosPath was found after the scheme | |
| // while( idx < (ushort)(cF & Flags.IndexMask) && (m_String[idx] == '/' || m_String[idx] == '\\')) { | |
| // notCanonicalScheme = true; | |
| // ++idx; | |
| // } | |
| // } | |
| // #endif // !PLATFORM_UNIX | |
| // } | |
| // } | |
| // | |
| // // This is weird but some schemes (mailto) do not have Authority-based syntax, still they do have a port | |
| // if (m_Syntax.DefaultPort != UriParser.NoDefaultPort) | |
| // info.Offset.PortValue = (ushort)m_Syntax.DefaultPort; | |
| // | |
| // //Here we set the indexes for already parsed components | |
| // if ((cF & Flags.HostTypeMask) == Flags.UnknownHostType | |
| // #if !PLATFORM_UNIX | |
| // || StaticInFact(cF, Flags.DosPath) | |
| // #endif // !PLATFORM_UNIX | |
| // ) { | |
| // //there is no Authotity component defined | |
| // info.Offset.User = (ushort) (cF & Flags.IndexMask); | |
| // info.Offset.Host = info.Offset.User; | |
| // info.Offset.Path = info.Offset.User; | |
| // cF &= ~Flags.IndexMask; | |
| // if (notCanonicalScheme) { | |
| // cF |= Flags.SchemeNotCanonical; | |
| // } | |
| // goto Done; | |
| // } | |
| // | |
| // info.Offset.User = idx; | |
| // | |
| // //Basic Host Type does not have userinfo and port | |
| // if (HostType == Flags.BasicHostType) { | |
| // info.Offset.Host = idx; | |
| // info.Offset.Path = (ushort) (cF & Flags.IndexMask); | |
| // cF &= ~Flags.IndexMask; | |
| // goto Done; | |
| // } | |
| // | |
| // if ((cF & Flags.HasUserInfo) != 0) { | |
| // // we previously found a userinfo, get it again | |
| // while (m_String[idx] != '@') { | |
| // ++idx; | |
| // } | |
| // ++idx; | |
| // info.Offset.Host = idx; | |
| // } | |
| // else { | |
| // info.Offset.Host = idx; | |
| // } | |
| // | |
| // //Now reload the end of the parsed host | |
| // | |
| // idx = (ushort) (cF & Flags.IndexMask); | |
| // | |
| // //From now on we do not need IndexMask bits, and reuse the space for X_NotCanonical flags | |
| // //clear them now | |
| // cF &= ~Flags.IndexMask; | |
| // | |
| // // If this is not canonical, don't count on user input to be good | |
| // if (notCanonicalScheme) { | |
| // cF |= Flags.SchemeNotCanonical; | |
| // } | |
| // | |
| // //Guessing this is a path start | |
| // info.Offset.Path = idx; | |
| // | |
| // // parse Port if any. The new spec allows a port after ':' to be empty (assuming default?) | |
| // bool notEmpty = false; | |
| // // Note we already checked on general port syntax in ParseMinimal() | |
| // | |
| // // If iri parsing is on with unicode chars then the end of parsed host | |
| // // points to m_orig string and not m_String | |
| // | |
| // bool UseOrigUnicodeStrOffset = ((cF& Flags.UseOrigUncdStrOffset) != 0); | |
| // // This should happen only once. Reset it | |
| // cF &= ~Flags.UseOrigUncdStrOffset; | |
| // | |
| // if (UseOrigUnicodeStrOffset) | |
| // info.Offset.End = (ushort)m_originalUnicodeString.Length; | |
| // | |
| // if (idx < info.Offset.End ){ | |
| // fixed (char* userString = UseOrigUnicodeStrOffset ? m_originalUnicodeString : m_String){ | |
| // if (userString[idx] == ':'){ | |
| // int port = 0; | |
| // | |
| // //Check on some noncanonical cases http://host:0324/, http://host:03, http://host:0, etc | |
| // if (++idx < info.Offset.End){ | |
| // port = (ushort)(userString[idx] - '0'); | |
| // if (!(port == unchecked((ushort)('/' - '0')) || port == (ushort)('?' - '0') || | |
| // port == unchecked((ushort)('#' - '0')))) { | |
| // notEmpty = true; | |
| // if (port == 0){ | |
| // cF |= (Flags.PortNotCanonical | Flags.E_PortNotCanonical); | |
| // } | |
| // for (++idx; idx < info.Offset.End; ++idx){ | |
| // ushort val = (ushort)((ushort)userString[idx] - (ushort)'0'); | |
| // if (val == unchecked((ushort)('/' - '0')) || val == (ushort)('?' - '0') || | |
| // val == unchecked((ushort)('#' - '0'))){ | |
| // break; | |
| // } | |
| // port = (port * 10 + val); | |
| // } | |
| // } | |
| // } | |
| // if (notEmpty && info.Offset.PortValue != (ushort)port){ | |
| // info.Offset.PortValue = (ushort)port; | |
| // cF |= Flags.NotDefaultPort; | |
| // } | |
| // else{ | |
| // //This will tell that we do have a ':' but the port value does | |
| // //not follow to canonical rules | |
| // cF |= (Flags.PortNotCanonical | Flags.E_PortNotCanonical); | |
| // } | |
| // info.Offset.Path = (ushort)idx; | |
| // } | |
| // } | |
| // } | |
| // | |
| // Done: | |
| // cF |= Flags.MinimalUriInfoSet; | |
| // /********* | |
| // // The spinlock would be better than below lock but it's too late for Beta2, consider for RTM | |
| // // Also DON'T forget to check EnsureUriInfo method | |
| // int copyF = m_Flags; | |
| // while ((copyF & Flags.MinimalUriInfoSet) == 0) | |
| // { | |
| // if (copyF != (copyF = Interlocked.CompareExchange(ref m_Flags, cF | (copyF & ~Flags.IndexMask), copyF)) | |
| // continue; | |
| // m_Info = info; | |
| // } | |
| // *********/ | |
| // info.DnsSafeHost = m_DnsSafeHost; | |
| // lock (m_String) | |
| // { | |
| // if (( m_Flags & Flags.MinimalUriInfoSet) == 0) | |
| // { | |
| // m_Info = info; | |
| // m_Flags = (m_Flags & ~Flags.IndexMask) | cF; | |
| // } | |
| // } | |
| // | |
| // } | |
| // | |
| // // | |
| // // This will create a Host string. The validity has been already checked | |
| // // | |
| // // Assuming: UriInfo memeber is already set at this point | |
| // private unsafe void CreateHostString() { | |
| // // | |
| // // Mutlithrreading! | |
| // // | |
| // if (!m_Syntax.IsSimple) | |
| // { | |
| // lock (m_Info) | |
| // { | |
| // // ATTN: Avoid possible recursion through | |
| // // CreateHostString->Syntax.GetComponents->Uri.GetComponentsHelper->CreateHostString | |
| // if (NotAny(Flags.ErrorOrParsingRecursion)) | |
| // { | |
| // m_Flags |= Flags.ErrorOrParsingRecursion; | |
| // // Need to get host string through the derived type | |
| // GetHostViaCustomSyntax(); | |
| // m_Flags &= ~Flags.ErrorOrParsingRecursion; | |
| // return; | |
| // } | |
| // } | |
| // } | |
| // Flags flags = m_Flags; | |
| // string host = CreateHostStringHelper(m_String, m_Info.Offset.Host, m_Info.Offset.Path, ref flags, ref m_Info.ScopeId); | |
| // | |
| // // now check on canonical host representation | |
| // if (host.Length != 0) | |
| // { | |
| // // An Authority may need escaping except when it's an inet server address | |
| // // | |
| // // We do not escape UNC names and will get rid of this type when switching to IDN spec | |
| // // | |
| // if (HostType == Flags.BasicHostType) { | |
| // ushort idx = 0; | |
| // Check result; | |
| // fixed (char* pHost = host) { | |
| // result = CheckCanonical(pHost, ref idx, (ushort)host.Length, c_DummyChar); | |
| // } | |
| // | |
| // if ((result & Check.DisplayCanonical) == 0) { | |
| // // For implicit file the user string must be in perfect display format, | |
| // // Hence, ignoring complains from CheckCanonical() | |
| // if (NotAny(Flags.ImplicitFile) || (result & Check.ReservedFound) != 0) { | |
| // flags |= Flags.HostNotCanonical; | |
| // } | |
| // } | |
| // | |
| // if (InFact(Flags.ImplicitFile) && (result & (Check.ReservedFound | Check.EscapedCanonical)) != 0) { | |
| // // need to re-escape this host if any escaped sequence was found | |
| // result &= ~Check.EscapedCanonical; | |
| // } | |
| // | |
| // if ((result & (Check.EscapedCanonical|Check.BackslashInPath)) != Check.EscapedCanonical) { | |
| // // we will make a canonical host in m_Info.Host, but mark that m_String holds wrong data | |
| // flags |= Flags.E_HostNotCanonical; | |
| // if (NotAny(Flags.UserEscaped)) | |
| // { | |
| // int position = 0; | |
| // char[] dest = UriHelper.EscapeString(host, 0, host.Length, null, ref position, true, '?', | |
| // '#', IsImplicitFile ? c_DummyChar : '%'); | |
| // if ((object)dest != null) | |
| // host = new string(dest, 0, position); | |
| // } | |
| // else { | |
| // // | |
| // | |
| // } | |
| // } | |
| // } | |
| // else if (NotAny(Flags.CanonicalDnsHost)){ | |
| // // Check to see if we can take the canonical host string out of m_String | |
| // if ((object)m_Info.ScopeId != null) { | |
| // // IPv6 ScopeId is included when serializing a Uri | |
| // flags |= (Flags.HostNotCanonical | Flags.E_HostNotCanonical); | |
| // } | |
| // else { | |
| // for (int i=0 ; i < host.Length; ++i) { | |
| // if ((m_Info.Offset.Host + i) >= m_Info.Offset.End || | |
| // host[i] != m_String[m_Info.Offset.Host + i]) { | |
| // flags |= (Flags.HostNotCanonical | Flags.E_HostNotCanonical); | |
| // break; | |
| // } | |
| // } | |
| // } | |
| // } | |
| // } | |
| // | |
| // m_Info.Host = host; | |
| // lock (m_Info) | |
| // { | |
| // m_Flags |= flags; | |
| // } | |
| // } | |
| // // | |
| // private static string CreateHostStringHelper(string str, ushort idx, ushort end, ref Flags flags, ref string scopeId) | |
| // { | |
| // bool loopback = false; | |
| // string host; | |
| // switch (flags & Flags.HostTypeMask) { | |
| // | |
| // case Flags.DnsHostType: | |
| // host = DomainNameHelper.ParseCanonicalName(str, idx, end, ref loopback); | |
| // break; | |
| // | |
| // case Flags.IPv6HostType: | |
| // //Microsoft codereview | |
| // // The helper will return [...] string that is not suited for Dns.Resolve() | |
| // host = IPv6AddressHelper.ParseCanonicalName(str, idx, ref loopback, ref scopeId); | |
| // break; | |
| // | |
| // case Flags.IPv4HostType: | |
| // host = IPv4AddressHelper.ParseCanonicalName(str, idx, end, ref loopback); | |
| // break; | |
| // | |
| // #if !PLATFORM_UNIX | |
| // case Flags.UncHostType: | |
| // host = UncNameHelper.ParseCanonicalName(str, idx, end, ref loopback); | |
| // break; | |
| // #endif // !PLATFORM_UNIX | |
| // | |
| // case Flags.BasicHostType: | |
| // #if !PLATFORM_UNIX | |
| // if (StaticInFact(flags, Flags.DosPath)) { | |
| // host = string.Empty; | |
| // } | |
| // else | |
| // #endif // !PLATFORM_UNIX | |
| // { | |
| // // This is for a registry-based authority, not relevant for known schemes | |
| // host = str.Substring(idx, end-idx); | |
| // } | |
| // // A empty host would count for a loopback | |
| // if (host.Length == 0) { | |
| // loopback = true; | |
| // } | |
| // //there will be no port | |
| // break; | |
| // | |
| // case Flags.UnknownHostType: | |
| // //means the host is *not expected* for this uri type | |
| // host = string.Empty; | |
| // break; | |
| // | |
| // default: //it's a bug | |
| // throw GetException(ParsingError.BadHostName); | |
| // } | |
| // | |
| // if (loopback) { | |
| // flags |= Flags.LoopbackHost; | |
| // } | |
| // return host; | |
| // } | |
| // // | |
| // // Called under lock() | |
| // // | |
| // private unsafe void GetHostViaCustomSyntax() | |
| // { | |
| // // A multithreading check | |
| // if (m_Info.Host != null) | |
| // return; | |
| // | |
| // string host = m_Syntax.InternalGetComponents(this, UriComponents.Host, UriFormat.UriEscaped); | |
| // | |
| // // ATTN: Check on whether recursion has not happened | |
| // if ((object)m_Info.Host == null) | |
| // { | |
| // if (host.Length >= c_MaxUriBufferSize) | |
| // throw GetException(ParsingError.SizeLimit); | |
| // | |
| // ParsingError err = ParsingError.None; | |
| // Flags flags = m_Flags & ~Flags.HostTypeMask; | |
| // | |
| // fixed (char *pHost = host) | |
| // { | |
| // string newHost = null; | |
| // if (CheckAuthorityHelper(pHost, 0, (ushort)host.Length, ref err, ref flags, m_Syntax, ref newHost) != | |
| // (ushort)host.Length) | |
| // { | |
| // // We cannot parse the entire host string | |
| // flags &= ~Flags.HostTypeMask; | |
| // flags |= Flags.UnknownHostType; | |
| // } | |
| // } | |
| // | |
| // if (err != ParsingError.None || (flags & Flags.HostTypeMask) == Flags.UnknownHostType) | |
| // { | |
| // // Well, custom parser has returned a not known host type, take it as Basic then. | |
| // m_Flags = (m_Flags & ~Flags.HostTypeMask) | Flags.BasicHostType; | |
| // } | |
| // else | |
| // { | |
| // host = CreateHostStringHelper(host, 0, (ushort)host.Length, ref flags, ref m_Info.ScopeId); | |
| // for (int i=0 ; i < host.Length; ++i) { | |
| // if ((m_Info.Offset.Host + i) >= m_Info.Offset.End || host[i] != m_String[m_Info.Offset.Host + i]) { | |
| // m_Flags |= (Flags.HostNotCanonical | Flags.E_HostNotCanonical); | |
| // break; | |
| // } | |
| // } | |
| // m_Flags = (m_Flags & ~Flags.HostTypeMask) | (flags & Flags.HostTypeMask); | |
| // } | |
| // } | |
| // // | |
| // // This is a chance for a custom parser to report a different port value | |
| // // | |
| // string portStr = m_Syntax.InternalGetComponents(this, UriComponents.StrongPort, UriFormat.UriEscaped); | |
| // int port = 0; | |
| // if ((object)portStr == null || portStr.Length == 0) | |
| // { | |
| // // It's like no port | |
| // m_Flags &= ~Flags.NotDefaultPort; | |
| // m_Flags |= (Flags.PortNotCanonical|Flags.E_PortNotCanonical); | |
| // m_Info.Offset.PortValue = 0; | |
| // } | |
| // else | |
| // { | |
| // for (int idx=0; idx < portStr.Length; ++idx) | |
| // { | |
| // int val = portStr[idx] - '0'; | |
| // if (val < 0 || val > 9 || (port = (port * 10 + val)) > 0xFFFF) | |
| // throw new UriFormatException(SR.GetString(SR.net_uri_PortOutOfRange, m_Syntax.GetType().FullName, portStr)); | |
| // } | |
| // if (port != m_Info.Offset.PortValue) | |
| // { | |
| // if (port == m_Syntax.DefaultPort) | |
| // m_Flags &= ~Flags.NotDefaultPort; | |
| // else | |
| // m_Flags |= Flags.NotDefaultPort; | |
| // | |
| // m_Flags |= (Flags.PortNotCanonical|Flags.E_PortNotCanonical); | |
| // m_Info.Offset.PortValue = (ushort) port; | |
| // } | |
| // } | |
| // // This must be done as the last thing in this method | |
| // m_Info.Host = host; | |
| // } | |
| // // | |
| // // An internal shortcut into Uri extenisiblity API | |
| // // | |
| // internal string GetParts(UriComponents uriParts, UriFormat formatAs) | |
| // { | |
| // return GetComponents(uriParts, formatAs); | |
| // } | |
| // | |
| // // | |
| // // | |
| // // | |
| // private string GetEscapedParts(UriComponents uriParts) { | |
| // // Which Uri parts are not escaped canonically ? | |
| // // Notice that public UriPart and private Flags must me in Sync so below code can work | |
| // // | |
| // ushort nonCanonical = (ushort)(((ushort)m_Flags & ((ushort)Flags.CannotDisplayCanonical<<7)) >> 6); | |
| // if (InFact(Flags.SchemeNotCanonical)) { | |
| // nonCanonical |= (ushort)Flags.SchemeNotCanonical; | |
| // } | |
| // | |
| // // We keep separate flags for some of path canonicalization facts | |
| // if ((uriParts & UriComponents.Path) != 0) { | |
| // if (InFact(Flags.ShouldBeCompressed|Flags.FirstSlashAbsent|Flags.BackslashInPath)) { | |
| // nonCanonical |= (ushort)Flags.PathNotCanonical; | |
| // } | |
| // else if (IsDosPath && m_String[m_Info.Offset.Path + SecuredPathIndex - 1] == '|') { | |
| // // A rare case of c|\ | |
| // nonCanonical |= (ushort)Flags.PathNotCanonical; | |
| // } | |
| // } | |
| // | |
| // if (((ushort)uriParts & nonCanonical) == 0) { | |
| // string ret = GetUriPartsFromUserString(uriParts); | |
| // if ((object)ret != null) { | |
| // return ret; | |
| // } | |
| // } | |
| // | |
| // return ReCreateParts(uriParts, nonCanonical, UriFormat.UriEscaped); | |
| // } | |
| // | |
| // private string GetUnescapedParts(UriComponents uriParts, UriFormat formatAs) { | |
| // // Which Uri parts are not escaped canonically ? | |
| // // Notice that public UriComponents and private Uri.Flags must me in Sync so below code can work | |
| // // | |
| // ushort nonCanonical = (ushort)((ushort)m_Flags & (ushort)Flags.CannotDisplayCanonical); | |
| // | |
| // // We keep separate flags for some of path canonicalization facts | |
| // if ((uriParts & UriComponents.Path) != 0) { | |
| // if ((m_Flags & (Flags.ShouldBeCompressed|Flags.FirstSlashAbsent|Flags.BackslashInPath)) !=0) { | |
| // nonCanonical |= (ushort)Flags.PathNotCanonical; | |
| // } | |
| // else if (IsDosPath && m_String[m_Info.Offset.Path + SecuredPathIndex - 1] == '|') { | |
| // // A rare case of c|\ | |
| // nonCanonical |= (ushort)Flags.PathNotCanonical; | |
| // } | |
| // | |
| // } | |
| // | |
| // if (((ushort)uriParts & nonCanonical) == 0) { | |
| // string ret = GetUriPartsFromUserString(uriParts); | |
| // if ((object)ret != null) { | |
| // return ret; | |
| // } | |
| // } | |
| // | |
| // return ReCreateParts(uriParts, nonCanonical, formatAs); | |
| // } | |
| // | |
| // // | |
| // // | |
| // // | |
| // private string ReCreateParts(UriComponents parts, ushort nonCanonical, UriFormat formatAs) | |
| // { | |
| // // going hard core | |
| // EnsureHostString(false); | |
| // string stemp = (parts & UriComponents.Host) == 0? string.Empty: m_Info.Host; | |
| // // we reserve more space than required because a canonical Ipv6 Host | |
| // // may take more characteres than in original m_String | |
| // // Also +3 is for :// and +1 is for absent first slash | |
| // // Also we may escape every character, hence multiplying by 12 | |
| // // UTF-8 can use up to 4 bytes per char * 3 chars per byte (%A4) = 12 encoded chars | |
| // int count = (m_Info.Offset.End-m_Info.Offset.User) * (formatAs == UriFormat.UriEscaped?12:1); | |
| // char[] chars = new char[stemp.Length + count + m_Syntax.SchemeName.Length + 3 + 1]; | |
| // count = 0; | |
| // | |
| // //Scheme and slashes | |
| // if ((parts & UriComponents.Scheme) != 0) { | |
| // m_Syntax.SchemeName.CopyTo(0, chars, count, m_Syntax.SchemeName.Length); | |
| // count += m_Syntax.SchemeName.Length; | |
| // if (parts != UriComponents.Scheme) { | |
| // chars[count++] = ':'; | |
| // if (InFact(Flags.AuthorityFound)) { | |
| // chars[count++] = '/'; | |
| // chars[count++] = '/'; | |
| // } | |
| // } | |
| // } | |
| // | |
| // //UserInfo | |
| // if ((parts & UriComponents.UserInfo) != 0 && InFact(Flags.HasUserInfo)) | |
| // { | |
| // if ((nonCanonical & (ushort)UriComponents.UserInfo) != 0) { | |
| // switch (formatAs) { | |
| // case UriFormat.UriEscaped: | |
| // if (NotAny(Flags.UserEscaped)) | |
| // { | |
| // chars = UriHelper.EscapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, | |
| // ref count, true, '?', '#', '%'); | |
| // } | |
| // else { | |
| // if (InFact(Flags.E_UserNotCanonical)) { | |
| // // | |
| // | |
| // } | |
| // m_String.CopyTo(m_Info.Offset.User, chars, count, m_Info.Offset.Host - m_Info.Offset.User); | |
| // count += (m_Info.Offset.Host - m_Info.Offset.User); | |
| // } | |
| // break; | |
| // | |
| // case UriFormat.SafeUnescaped: | |
| // chars = UriHelper.UnescapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host - 1, | |
| // chars, ref count, '@', '/', '\\', InFact(Flags.UserEscaped) ? UnescapeMode.Unescape : | |
| // UnescapeMode.EscapeUnescape, m_Syntax, false); | |
| // chars[count++] = '@'; | |
| // break; | |
| // | |
| // case UriFormat.Unescaped: | |
| // chars = UriHelper.UnescapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, | |
| // ref count, c_DummyChar, c_DummyChar, c_DummyChar, | |
| // UnescapeMode.Unescape | UnescapeMode.UnescapeAll, m_Syntax, false); | |
| // break; | |
| // | |
| // default: //V1ToStringUnescape | |
| // chars = UriHelper.UnescapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, | |
| // ref count, c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, | |
| // false); | |
| // break; | |
| // } | |
| // } | |
| // else { | |
| // UriHelper.UnescapeString(m_String, m_Info.Offset.User, m_Info.Offset.Host, chars, ref count, | |
| // c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, false); | |
| // } | |
| // if (parts == UriComponents.UserInfo) | |
| // { | |
| // //strip '@' delimiter | |
| // --count; | |
| // } | |
| // } | |
| // | |
| // // Host | |
| // if ((parts & UriComponents.Host) != 0 && stemp.Length != 0) | |
| // { | |
| // UnescapeMode mode; | |
| // if (formatAs != UriFormat.UriEscaped && HostType == Flags.BasicHostType | |
| // && (nonCanonical & (ushort)UriComponents.Host) != 0) { | |
| // // only Basic host could be in the escaped form | |
| // mode = formatAs == UriFormat.Unescaped | |
| // ? (UnescapeMode.Unescape | UnescapeMode.UnescapeAll) : | |
| // (InFact(Flags.UserEscaped) ? UnescapeMode.Unescape : UnescapeMode.EscapeUnescape); | |
| // | |
| // } | |
| // else { | |
| // mode = UnescapeMode.CopyOnly; | |
| // } | |
| // // NormalizedHost | |
| // if ((parts & UriComponents.NormalizedHost) != 0) | |
| // { | |
| // unsafe | |
| // { | |
| // fixed (char* hostPtr = stemp) | |
| // { | |
| // bool allAscii = false; | |
| // bool atLeastOneValidIdn = false; | |
| // try | |
| // { | |
| // // Upconvert any punycode to unicode, xn--pck -> ? | |
| // stemp = DomainNameHelper.UnicodeEquivalent( | |
| // hostPtr, 0, stemp.Length, ref allAscii, ref atLeastOneValidIdn); | |
| // } | |
| // // The host may be invalid punycode (www.xn--?-pck.com), | |
| // // but we shouldn't throw after the constructor. | |
| // catch (UriFormatException) { } | |
| // } | |
| // } | |
| // } | |
| // chars = UriHelper.UnescapeString(stemp, 0, stemp.Length, chars, ref count, '/', '?', '#', mode, | |
| // m_Syntax, false); | |
| // | |
| // // A fix up only for SerializationInfo and IpV6 host with a scopeID | |
| // if ((parts & UriComponents.SerializationInfoString) != 0 && HostType == Flags.IPv6HostType && | |
| // (object)m_Info.ScopeId != null) | |
| // { | |
| // m_Info.ScopeId.CopyTo(0, chars, count-1, m_Info.ScopeId.Length); | |
| // count += m_Info.ScopeId.Length; | |
| // chars[count-1] = ']'; | |
| // } | |
| // } | |
| // | |
| // //Port (always wants a ':' delimiter if got to this method) | |
| // if ((parts & UriComponents.Port) != 0) | |
| // { | |
| // if ((nonCanonical & (ushort)UriComponents.Port) == 0) { | |
| // //take it from m_String | |
| // if (InFact(Flags.NotDefaultPort)) { | |
| // ushort start = m_Info.Offset.Path; | |
| // while (m_String[--start] != ':') { | |
| // ; | |
| // } | |
| // m_String.CopyTo(start, chars, count, m_Info.Offset.Path - start); | |
| // count += (m_Info.Offset.Path - start); | |
| // } | |
| // else if ((parts & UriComponents.StrongPort) != 0 && m_Syntax.DefaultPort != UriParser.NoDefaultPort) { | |
| // chars[count++]= ':'; | |
| // stemp = m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture); | |
| // stemp.CopyTo(0, chars, count, stemp.Length); | |
| // count += stemp.Length; | |
| // } | |
| // } | |
| // else if (InFact(Flags.NotDefaultPort) || ((parts & UriComponents.StrongPort) != 0 && | |
| // m_Syntax.DefaultPort != UriParser.NoDefaultPort)) { | |
| // // recreate string from port value | |
| // chars[count++]= ':'; | |
| // stemp = m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture); | |
| // stemp.CopyTo(0, chars, count, stemp.Length); | |
| // count += stemp.Length; | |
| // } | |
| // } | |
| // | |
| // ushort delimiterAwareIndex; | |
| // | |
| // //Path | |
| // if ((parts & UriComponents.Path) != 0) | |
| // { | |
| // chars = GetCanonicalPath(chars, ref count, formatAs); | |
| // | |
| // // (possibly strip the leading '/' delimiter) | |
| // if (parts == UriComponents.Path) | |
| // { | |
| // if (InFact(Flags.AuthorityFound) && count !=0 && chars[0] == '/') | |
| // { | |
| // delimiterAwareIndex = 1; --count; | |
| // } | |
| // else | |
| // { | |
| // delimiterAwareIndex = 0; | |
| // } | |
| // return count == 0? string.Empty: new string(chars, delimiterAwareIndex, count); | |
| // } | |
| // } | |
| // | |
| // //Query (possibly strip the '?' delimiter) | |
| // if ((parts & UriComponents.Query) != 0 && m_Info.Offset.Query < m_Info.Offset.Fragment) | |
| // { | |
| // delimiterAwareIndex = (ushort)(m_Info.Offset.Query+1); | |
| // if(parts != UriComponents.Query) | |
| // chars[count++] = '?'; //see Fragment+1 below | |
| // | |
| // if ((nonCanonical & (ushort)UriComponents.Query) != 0) | |
| // { | |
| // switch (formatAs) | |
| // { | |
| // case UriFormat.UriEscaped: | |
| // //Can Assert IsImplicitfile == false | |
| // if (NotAny(Flags.UserEscaped)) | |
| // chars = UriHelper.EscapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, | |
| // ref count, true, '#', c_DummyChar, '%'); | |
| // else | |
| // { | |
| // // | |
| // | |
| // | |
| // UriHelper.UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, | |
| // ref count, c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, | |
| // true); | |
| // } | |
| // break; | |
| // | |
| // case V1ToStringUnescape: | |
| // | |
| // chars = UriHelper.UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, | |
| // ref count, '#', c_DummyChar, c_DummyChar, (InFact(Flags.UserEscaped) ? | |
| // UnescapeMode.Unescape : UnescapeMode.EscapeUnescape) | UnescapeMode.V1ToStringFlag, | |
| // m_Syntax, true); | |
| // break; | |
| // | |
| // case UriFormat.Unescaped: | |
| // | |
| // chars = UriHelper.UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, | |
| // ref count, '#', c_DummyChar, c_DummyChar, | |
| // (UnescapeMode.Unescape | UnescapeMode.UnescapeAll), m_Syntax, true); | |
| // break; | |
| // | |
| // default: // UriFormat.SafeUnescaped | |
| // | |
| // chars = UriHelper.UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, | |
| // ref count, '#', c_DummyChar, c_DummyChar, (InFact(Flags.UserEscaped) ? | |
| // UnescapeMode.Unescape : UnescapeMode.EscapeUnescape), m_Syntax, true); | |
| // break; | |
| // } | |
| // } | |
| // else | |
| // { | |
| // UriHelper.UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.Fragment, chars, ref count, | |
| // c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, true); | |
| // } | |
| // } | |
| // | |
| // //Fragment (possibly strip the '#' delimiter) | |
| // if ((parts & UriComponents.Fragment) != 0 && m_Info.Offset.Fragment < m_Info.Offset.End) | |
| // { | |
| // delimiterAwareIndex = (ushort)(m_Info.Offset.Fragment+1); | |
| // if(parts != UriComponents.Fragment) | |
| // chars[count++] = '#'; //see Fragment+1 below | |
| // | |
| // if ((nonCanonical & (ushort)UriComponents.Fragment) != 0) | |
| // { | |
| // switch (formatAs) { | |
| // case UriFormat.UriEscaped: | |
| // if (NotAny(Flags.UserEscaped)) | |
| // chars = UriHelper.EscapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, | |
| // ref count, true, UriParser.ShouldUseLegacyV2Quirks ? '#' : c_DummyChar, c_DummyChar, '%'); | |
| // else | |
| // { | |
| // // | |
| // | |
| // | |
| // UriHelper.UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, | |
| // ref count, c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, | |
| // false); | |
| // } | |
| // break; | |
| // | |
| // case V1ToStringUnescape: | |
| // | |
| // chars = UriHelper.UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, | |
| // ref count, '#', c_DummyChar, c_DummyChar, (InFact(Flags.UserEscaped) ? | |
| // UnescapeMode.Unescape : UnescapeMode.EscapeUnescape) | UnescapeMode.V1ToStringFlag, | |
| // m_Syntax, false); | |
| // break; | |
| // case UriFormat.Unescaped: | |
| // | |
| // chars = UriHelper.UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, | |
| // ref count, '#', c_DummyChar, c_DummyChar, | |
| // UnescapeMode.Unescape | UnescapeMode.UnescapeAll, m_Syntax, false); | |
| // break; | |
| // | |
| // default: // UriFormat.SafeUnescaped | |
| // | |
| // chars = UriHelper.UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, | |
| // ref count, '#', c_DummyChar, c_DummyChar, (InFact(Flags.UserEscaped) ? | |
| // UnescapeMode.Unescape : UnescapeMode.EscapeUnescape), m_Syntax, false); | |
| // break; | |
| // } | |
| // } | |
| // else | |
| // { | |
| // UriHelper.UnescapeString(m_String, delimiterAwareIndex, m_Info.Offset.End, chars, ref count, | |
| // c_DummyChar, c_DummyChar, c_DummyChar, UnescapeMode.CopyOnly, m_Syntax, false); | |
| // } | |
| // } | |
| // | |
| // return new string(chars, 0, count); | |
| // } | |
| // | |
| // // | |
| // // This method is called only if the user string has a canonical representation | |
| // // of requested parts | |
| // // | |
| // private string GetUriPartsFromUserString(UriComponents uriParts) { | |
| // | |
| // ushort delimiterAwareIdx; | |
| // | |
| // switch (uriParts & ~UriComponents.KeepDelimiter) { | |
| // // For FindServicePoint perf | |
| // case UriComponents.Scheme | UriComponents.Host | UriComponents.Port: | |
| // if (!InFact(Flags.HasUserInfo)) | |
| // return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Path - m_Info.Offset.Scheme); | |
| // | |
| // return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme) | |
| // + m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Path - m_Info.Offset.Host); | |
| // | |
| // // For HttpWebRequest.ConnectHostAndPort perf | |
| // case UriComponents.HostAndPort: //Host|StrongPort | |
| // | |
| // if (!InFact(Flags.HasUserInfo)) | |
| // goto case UriComponents.StrongAuthority; | |
| // | |
| // if (InFact(Flags.NotDefaultPort) || m_Syntax.DefaultPort == UriParser.NoDefaultPort) | |
| // return m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Path - m_Info.Offset.Host); | |
| // | |
| // return m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Path - m_Info.Offset.Host) | |
| // + ':' + m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture); | |
| // | |
| // // For an obvious common case perf | |
| // case UriComponents.AbsoluteUri: //Scheme|UserInfo|Host|Port|Path|Query|Fragment, | |
| // if (m_Info.Offset.Scheme == 0 && m_Info.Offset.End == m_String.Length) | |
| // return m_String; | |
| // | |
| // return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.End - m_Info.Offset.Scheme); | |
| // | |
| // // For Uri.Equals() and HttpWebRequest through a proxy perf | |
| // case UriComponents.HttpRequestUrl: //Scheme|Host|Port|Path|Query, | |
| // if (InFact(Flags.HasUserInfo)) { | |
| // return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme) | |
| // + m_String.Substring(m_Info.Offset.Host, m_Info.Offset.Fragment - m_Info.Offset.Host); | |
| // } | |
| // if (m_Info.Offset.Scheme == 0 && m_Info.Offset.Fragment == m_String.Length) | |
| // return m_String; | |
| // | |
| // return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Fragment - m_Info.Offset.Scheme); | |
| // | |
| // // For CombineUri() perf | |
| // case UriComponents.SchemeAndServer|UriComponents.UserInfo: | |
| // return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Path - m_Info.Offset.Scheme); | |
| // | |
| // // For Cache perf | |
| // case (UriComponents.AbsoluteUri & ~UriComponents.Fragment): | |
| // if (m_Info.Offset.Scheme == 0 && m_Info.Offset.Fragment == m_String.Length) | |
| // return m_String; | |
| // | |
| // return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.Fragment - m_Info.Offset.Scheme); | |
| // | |
| // | |
| // // Strip scheme delimiter if was not requested | |
| // case UriComponents.Scheme: | |
| // if (uriParts != UriComponents.Scheme) | |
| // return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme); | |
| // | |
| // return m_Syntax.SchemeName; | |
| // | |
| // // KeepDelimiter makes no sense for this component | |
| // case UriComponents.Host: | |
| // ushort idx = m_Info.Offset.Path; | |
| // if (InFact(Flags.NotDefaultPort|Flags.PortNotCanonical)) { | |
| // //Means we do have ':' after the host | |
| // while (m_String[--idx] != ':') | |
| // ; | |
| // } | |
| // return (idx - m_Info.Offset.Host == 0)? string.Empty: m_String.Substring(m_Info.Offset.Host, | |
| // idx - m_Info.Offset.Host); | |
| // | |
| // case UriComponents.Path: | |
| // | |
| // // Strip the leading '/' for a hierarchical URI if no delimiter was requested | |
| // if (uriParts == UriComponents.Path && InFact(Flags.AuthorityFound) && | |
| // m_Info.Offset.End > m_Info.Offset.Path && m_String[m_Info.Offset.Path] == '/') | |
| // delimiterAwareIdx = (ushort)(m_Info.Offset.Path + 1); | |
| // else | |
| // delimiterAwareIdx = m_Info.Offset.Path; | |
| // | |
| // if (delimiterAwareIdx >= m_Info.Offset.Query) | |
| // return string.Empty; | |
| // | |
| // | |
| // return m_String.Substring(delimiterAwareIdx, m_Info.Offset.Query - delimiterAwareIdx); | |
| // | |
| // case UriComponents.Query: | |
| // // Strip the '?' if no delimiter was requested | |
| // if (uriParts == UriComponents.Query) | |
| // delimiterAwareIdx = (ushort)(m_Info.Offset.Query + 1); | |
| // else | |
| // delimiterAwareIdx = m_Info.Offset.Query; | |
| // | |
| // if (delimiterAwareIdx >= m_Info.Offset.Fragment) | |
| // return string.Empty; | |
| // | |
| // return m_String.Substring(delimiterAwareIdx, m_Info.Offset.Fragment - delimiterAwareIdx); | |
| // | |
| // case UriComponents.Fragment: | |
| // // Strip the '#' if no delimiter was requested | |
| // if (uriParts == UriComponents.Fragment) | |
| // delimiterAwareIdx = (ushort)(m_Info.Offset.Fragment + 1); | |
| // else | |
| // delimiterAwareIdx = m_Info.Offset.Fragment; | |
| // | |
| // if (delimiterAwareIdx >= m_Info.Offset.End) | |
| // return string.Empty; | |
| // | |
| // return m_String.Substring(delimiterAwareIdx, m_Info.Offset.End - delimiterAwareIdx); | |
| // | |
| // case UriComponents.UserInfo | UriComponents.Host | UriComponents.Port: | |
| // return (m_Info.Offset.Path - m_Info.Offset.User == 0) ? string.Empty : | |
| // m_String.Substring(m_Info.Offset.User, m_Info.Offset.Path - m_Info.Offset.User); | |
| // | |
| // case UriComponents.StrongAuthority: //UserInfo|Host|StrongPort | |
| // if (InFact(Flags.NotDefaultPort) || m_Syntax.DefaultPort == UriParser.NoDefaultPort) | |
| // goto case UriComponents.UserInfo | UriComponents.Host | UriComponents.Port; | |
| // | |
| // return m_String.Substring(m_Info.Offset.User, m_Info.Offset.Path - m_Info.Offset.User) | |
| // + ':' + m_Info.Offset.PortValue.ToString(CultureInfo.InvariantCulture); | |
| // | |
| // case UriComponents.PathAndQuery: //Path|Query, | |
| // return m_String.Substring(m_Info.Offset.Path, m_Info.Offset.Fragment - m_Info.Offset.Path); | |
| // | |
| // case UriComponents.HttpRequestUrl|UriComponents.Fragment: //Scheme|Host|Port|Path|Query|Fragment, | |
| // if (InFact(Flags.HasUserInfo)) { | |
| // return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.User - m_Info.Offset.Scheme) | |
| // + m_String.Substring(m_Info.Offset.Host, m_Info.Offset.End - m_Info.Offset.Host); | |
| // } | |
| // if (m_Info.Offset.Scheme == 0 && m_Info.Offset.End == m_String.Length) | |
| // return m_String; | |
| // | |
| // return m_String.Substring(m_Info.Offset.Scheme, m_Info.Offset.End - m_Info.Offset.Scheme); | |
| // | |
| // case UriComponents.PathAndQuery|UriComponents.Fragment: //LocalUrl|Fragment | |
| // return m_String.Substring(m_Info.Offset.Path, m_Info.Offset.End - m_Info.Offset.Path); | |
| // | |
| // case UriComponents.UserInfo: | |
| // // Strip the '@' if no delimiter was requested | |
| // | |
| // if (NotAny(Flags.HasUserInfo)) | |
| // return string.Empty; | |
| // | |
| // if (uriParts == UriComponents.UserInfo) | |
| // delimiterAwareIdx = (ushort)(m_Info.Offset.Host - 1); | |
| // else | |
| // delimiterAwareIdx = m_Info.Offset.Host; | |
| // | |
| // if (m_Info.Offset.User >= delimiterAwareIdx) | |
| // return string.Empty; | |
| // | |
| // return m_String.Substring(m_Info.Offset.User, delimiterAwareIdx - m_Info.Offset.User); | |
| // | |
| // default: | |
| // return null; | |
| // } | |
| // } | |
| // | |
| // | |
| // // | |
| // //This method does: | |
| // // - Creates m_Info member | |
| // // - checks all componenets up to path on their canonical representation | |
| // // - continues parsing starting the path position | |
| // // - Sets the offsets of remaining components | |
| // // - Sets the Canonicalization flags if applied | |
| // // - Will NOT create MoreInfo members | |
| // // | |
| // private unsafe void ParseRemaining() { | |
| // | |
| // // ensure we parsed up to the path | |
| // EnsureUriInfo(); | |
| // | |
| // Flags cF = Flags.Zero; | |
| // | |
| // if (UserDrivenParsing) | |
| // goto Done; | |
| // | |
| // // Do we have to continue building Iri'zed string from original string | |
| // bool buildIriStringFromPath = m_iriParsing && ((m_Flags & Flags.HasUnicode) != 0) && ((m_Flags & Flags.RestUnicodeNormalized) == 0); | |
| // | |
| // ushort origIdx; // stores index to switched original string | |
| // ushort idx = m_Info.Offset.Scheme; | |
| // ushort length = (ushort)m_String.Length; | |
| // Check result = Check.None; | |
| // UriSyntaxFlags syntaxFlags = m_Syntax.Flags; // perf | |
| // | |
| // // Multithreading! | |
| // // m_Info.Offset values may be parsed twice but we lock only on m_Flags update. | |
| // | |
| // fixed (char* str = m_String){ | |
| // // Cut trailing spaces in m_String | |
| // if (length > idx && IsLWS(str[length - 1])) | |
| // { | |
| // --length; | |
| // while (length != idx && IsLWS(str[--length])) | |
| // ; | |
| // ++length; | |
| // } | |
| // | |
| // if (IsImplicitFile){ | |
| // cF |= Flags.SchemeNotCanonical; | |
| // } | |
| // else { | |
| // ushort i = 0; | |
| // ushort syntaxLength = (ushort)m_Syntax.SchemeName.Length; | |
| // for (; i < syntaxLength; ++i) | |
| // { | |
| // if (m_Syntax.SchemeName[i] != str[idx + i]) | |
| // cF |= Flags.SchemeNotCanonical; | |
| // } | |
| // // For an authority Uri only // after the scheme would be canonical | |
| // // (compatibility bug http:\\host) | |
| // if (((m_Flags & Flags.AuthorityFound) != 0) && (idx + i + 3 >= length || str[idx + i + 1] != '/' || | |
| // str[idx + i + 2] != '/')) | |
| // { | |
| // cF |= Flags.SchemeNotCanonical; | |
| // } | |
| // } | |
| // | |
| // | |
| // //Check the form of the user info | |
| // if ((m_Flags & Flags.HasUserInfo) != 0){ | |
| // idx = m_Info.Offset.User; | |
| // result = CheckCanonical(str, ref idx, m_Info.Offset.Host, '@'); | |
| // if ((result & Check.DisplayCanonical) == 0){ | |
| // cF |= Flags.UserNotCanonical; | |
| // } | |
| // if ((result & (Check.EscapedCanonical | Check.BackslashInPath)) != Check.EscapedCanonical){ | |
| // cF |= Flags.E_UserNotCanonical; | |
| // } | |
| // if (m_iriParsing && ((result & (Check.DisplayCanonical | Check.EscapedCanonical | Check.BackslashInPath | |
| // | Check.FoundNonAscii | Check.NotIriCanonical)) | |
| // == (Check.DisplayCanonical | Check.FoundNonAscii))){ | |
| // cF |= Flags.UserIriCanonical; | |
| // } | |
| // } | |
| // } | |
| // // | |
| // // Delay canonical Host checking to avoid creation of a host string | |
| // // Will do that on demand. | |
| // // | |
| // | |
| // | |
| // // | |
| // //We have already checked on the port in EnsureUriInfo() that calls CreateUriInfo | |
| // // | |
| // | |
| // // | |
| // // Parsing the Path if any | |
| // // | |
| // | |
| // // For iri parsing if we found unicode the idx has offset into m_orig string.. | |
| // // so restart parsing from there and make m_Info.Offset.Path as m_string.length | |
| // | |
| // idx = m_Info.Offset.Path; | |
| // origIdx = m_Info.Offset.Path; | |
| // | |
| // //Some uris do not have a query | |
| // // When '?' is passed as delimiter, then it's special case | |
| // // so both '?' and '#' will work as delimiters | |
| // if (buildIriStringFromPath){ | |
| // | |
| // // Dos paths have no host. Other schemes cleared/set m_String with host information in PrivateParseMinimal. | |
| // if (IsDosPath) { | |
| // if (IsImplicitFile) { | |
| // m_String = String.Empty; | |
| // } | |
| // else { | |
| // m_String = m_Syntax.SchemeName + SchemeDelimiter; | |
| // } | |
| // } | |
| // | |
| // m_Info.Offset.Path = (ushort)m_String.Length; | |
| // idx = m_Info.Offset.Path; | |
| // | |
| // ushort offset = origIdx; | |
| // if (IsImplicitFile || ((syntaxFlags & (UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment)) == 0)){ | |
| // FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length, c_DummyChar); | |
| // } | |
| // else{ | |
| // FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length, | |
| // (m_Syntax.InFact(UriSyntaxFlags.MayHaveQuery) ? '?' : m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment) ? '#' : c_EOL)); | |
| // } | |
| // | |
| // // Correctly escape unescape | |
| // string escapedPath = EscapeUnescapeIri(m_originalUnicodeString, offset, origIdx, UriComponents.Path); | |
| // | |
| // // Normalize path | |
| // try{ | |
| // if (UriParser.ShouldUseLegacyV2Quirks) | |
| // m_String += escapedPath.Normalize(NormalizationForm.FormC); | |
| // else | |
| // m_String += escapedPath; | |
| // } | |
| // catch (ArgumentException){ | |
| // UriFormatException e = GetException(ParsingError.BadFormat); | |
| // throw e; | |
| // } | |
| // | |
| // if (!ServicePointManager.AllowAllUriEncodingExpansion && m_String.Length > ushort.MaxValue){ | |
| // UriFormatException e = GetException(ParsingError.SizeLimit); | |
| // throw e; | |
| // } | |
| // | |
| // length = (ushort)m_String.Length; | |
| // } | |
| // | |
| // fixed (char* str = m_String){ | |
| // if (IsImplicitFile || ((syntaxFlags & (UriSyntaxFlags.MayHaveQuery | UriSyntaxFlags.MayHaveFragment)) == 0)){ | |
| // result = CheckCanonical(str, ref idx, length, c_DummyChar); | |
| // } | |
| // else { | |
| // result = CheckCanonical(str, ref idx, length, (((syntaxFlags & UriSyntaxFlags.MayHaveQuery) != 0) | |
| // ? '?' : m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment) ? '#' : c_EOL)); | |
| // } | |
| // | |
| // // ATTN: | |
| // // This may render problems for unknown schemes, but in general for an authority based Uri | |
| // // (that has slashes) a path should start with "/" | |
| // // This becomes more interesting knowning how a file uri is used in "file://c:/path" | |
| // // It will be converted to file:///c:/path | |
| // // | |
| // // However, even more interesting is that vsmacros://c:\path will not add the third slash in the _canoical_ case | |
| // // (vsmacros inventors have violated the RFC) | |
| // // | |
| // // We use special syntax flag to check if the path is rooted, i.e. has a first slash | |
| // // | |
| // if (((m_Flags & Flags.AuthorityFound) != 0) && ((syntaxFlags & UriSyntaxFlags.PathIsRooted) != 0) | |
| // && (m_Info.Offset.Path == length || (str[m_Info.Offset.Path] != '/' && str[m_Info.Offset.Path] != '\\'))){ | |
| // cF |= Flags.FirstSlashAbsent; | |
| // } | |
| // } | |
| // // Check the need for compression or backslashes conversion | |
| // // we included IsDosPath since it may come with other than FILE uri, for ex. scheme://C:\path | |
| // // (This is very unfortunate that the original design has included that feature) | |
| // bool nonCanonical = false; | |
| // if (IsDosPath || (((m_Flags & Flags.AuthorityFound) != 0) && | |
| // (((syntaxFlags & (UriSyntaxFlags.CompressPath | UriSyntaxFlags.ConvertPathSlashes)) != 0) || | |
| // m_Syntax.InFact(UriSyntaxFlags.UnEscapeDotsAndSlashes)))) | |
| // { | |
| // if (((result & Check.DotSlashEscaped) != 0) && m_Syntax.InFact(UriSyntaxFlags.UnEscapeDotsAndSlashes)) | |
| // { | |
| // cF |= (Flags.E_PathNotCanonical | Flags.PathNotCanonical); | |
| // nonCanonical = true; | |
| // } | |
| // | |
| // if (((syntaxFlags & (UriSyntaxFlags.ConvertPathSlashes)) != 0) && (result & Check.BackslashInPath) != 0){ | |
| // cF |= (Flags.E_PathNotCanonical | Flags.PathNotCanonical); | |
| // nonCanonical = true; | |
| // } | |
| // | |
| // if (((syntaxFlags & (UriSyntaxFlags.CompressPath)) != 0) && ((cF & Flags.E_PathNotCanonical) != 0 || | |
| // (result & Check.DotSlashAttn) != 0)) | |
| // { | |
| // cF |= Flags.ShouldBeCompressed; | |
| // } | |
| // | |
| // if ((result & Check.BackslashInPath) != 0) | |
| // cF |= Flags.BackslashInPath; | |
| // | |
| // } | |
| // else if ((result & Check.BackslashInPath) != 0){ | |
| // // for a "generic" path '\' should be escaped | |
| // cF |= Flags.E_PathNotCanonical; | |
| // nonCanonical = true; | |
| // } | |
| // | |
| // if ((result & Check.DisplayCanonical) == 0){ | |
| // // For implicit file the user string is usually in perfect display format, | |
| // // Hence, ignoring complains from CheckCanonical() | |
| // // | |
| // | |
| // if (((m_Flags & Flags.ImplicitFile) == 0) || ((m_Flags & Flags.UserEscaped) != 0) || | |
| // (result & Check.ReservedFound) != 0) { | |
| // //means it's found as escaped or has unescaped Reserved Characters | |
| // cF |= Flags.PathNotCanonical; | |
| // nonCanonical = true; | |
| // } | |
| // } | |
| // | |
| // if (((m_Flags & Flags.ImplicitFile) != 0) && (result & (Check.ReservedFound | Check.EscapedCanonical)) != 0){ | |
| // // need to escape reserved chars or re-escape '%' if an "escaped sequence" was found | |
| // result &= ~Check.EscapedCanonical; | |
| // } | |
| // | |
| // if ((result & Check.EscapedCanonical) == 0){ | |
| // //means it's found as not completely escaped | |
| // cF |= Flags.E_PathNotCanonical; | |
| // } | |
| // | |
| // if (m_iriParsing && !nonCanonical & ((result & (Check.DisplayCanonical | Check.EscapedCanonical | |
| // | Check.FoundNonAscii | Check.NotIriCanonical)) | |
| // == (Check.DisplayCanonical | Check.FoundNonAscii))){ | |
| // cF |= Flags.PathIriCanonical; | |
| // } | |
| // | |
| // // | |
| // //Now we've got to parse the Query if any. Note that Query requires the presence of '?' | |
| // // | |
| // if (buildIriStringFromPath){ | |
| // ushort offset = origIdx; | |
| // | |
| // if (origIdx < m_originalUnicodeString.Length && m_originalUnicodeString[origIdx] == '?'){ | |
| // ++origIdx; // This is to exclude first '?' character from checking | |
| // FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length, ((syntaxFlags &(UriSyntaxFlags.MayHaveFragment)) != 0) ? '#' : c_EOL); | |
| // | |
| // // Correctly escape unescape | |
| // string escapedPath = EscapeUnescapeIri(m_originalUnicodeString, offset, origIdx, UriComponents.Query); | |
| // | |
| // // Normalize path | |
| // try{ | |
| // if (UriParser.ShouldUseLegacyV2Quirks) | |
| // m_String += escapedPath.Normalize(NormalizationForm.FormC); | |
| // else | |
| // m_String += escapedPath; | |
| // } | |
| // catch (ArgumentException){ | |
| // UriFormatException e = GetException(ParsingError.BadFormat); | |
| // throw e; | |
| // } | |
| // | |
| // if (!ServicePointManager.AllowAllUriEncodingExpansion && m_String.Length > ushort.MaxValue){ | |
| // UriFormatException e = GetException(ParsingError.SizeLimit); | |
| // throw e; | |
| // } | |
| // | |
| // length = (ushort)m_String.Length; | |
| // } | |
| // } | |
| // | |
| // m_Info.Offset.Query = idx; | |
| // | |
| // fixed (char* str = m_String){ | |
| // if (idx < length && str[idx] == '?'){ | |
| // ++idx; // This is to exclude first '?' character from checking | |
| // result = CheckCanonical(str, ref idx, length, ((syntaxFlags & (UriSyntaxFlags.MayHaveFragment)) != 0) | |
| // ? '#' : c_EOL); | |
| // if ((result & Check.DisplayCanonical) == 0){ | |
| // cF |= Flags.QueryNotCanonical; | |
| // } | |
| // | |
| // if ((result & (Check.EscapedCanonical | Check.BackslashInPath)) != Check.EscapedCanonical){ | |
| // cF |= Flags.E_QueryNotCanonical; | |
| // } | |
| // | |
| // if (m_iriParsing && ((result & (Check.DisplayCanonical | Check.EscapedCanonical | Check.BackslashInPath | |
| // | Check.FoundNonAscii | Check.NotIriCanonical)) | |
| // == (Check.DisplayCanonical | Check.FoundNonAscii))){ | |
| // cF |= Flags.QueryIriCanonical; | |
| // } | |
| // | |
| // } | |
| // } | |
| // // | |
| // //Now we've got to parse the Fragment if any. Note that Fragment requires the presense of '#' | |
| // // | |
| // if (buildIriStringFromPath){ | |
| // ushort offset = origIdx; | |
| // | |
| // if (origIdx < m_originalUnicodeString.Length && m_originalUnicodeString[origIdx] == '#') | |
| // { | |
| // ++origIdx; // This is to exclude first '#' character from checking | |
| // FindEndOfComponent(m_originalUnicodeString, ref origIdx, (ushort)m_originalUnicodeString.Length, c_EOL); | |
| // | |
| // // Correctly escape unescape | |
| // string escapedPath = EscapeUnescapeIri(m_originalUnicodeString, offset, origIdx, UriComponents.Fragment); | |
| // | |
| // // Normalize path | |
| // try{ | |
| // if (UriParser.ShouldUseLegacyV2Quirks) | |
| // m_String += escapedPath.Normalize(NormalizationForm.FormC); | |
| // else | |
| // m_String += escapedPath; | |
| // } | |
| // catch (ArgumentException){ | |
| // UriFormatException e = GetException(ParsingError.BadFormat); | |
| // throw e; | |
| // } | |
| // | |
| // if (!ServicePointManager.AllowAllUriEncodingExpansion && m_String.Length > ushort.MaxValue){ | |
| // UriFormatException e = GetException(ParsingError.SizeLimit); | |
| // throw e; | |
| // } | |
| // | |
| // length = (ushort)m_String.Length; | |
| // } | |
| // } | |
| // | |
| // m_Info.Offset.Fragment = idx; | |
| // | |
| // fixed (char* str = m_String){ | |
| // if (idx < length && str[idx] == '#'){ | |
| // ++idx; // This is to exclude first '#' character from checking | |
| // //We don't using c_DummyChar since want to allow '?' and '#' as unescaped | |
| // result = CheckCanonical(str, ref idx, length, c_EOL); | |
| // if ((result & Check.DisplayCanonical) == 0){ | |
| // cF |= Flags.FragmentNotCanonical; | |
| // } | |
| // | |
| // if ((result & (Check.EscapedCanonical | Check.BackslashInPath)) != Check.EscapedCanonical){ | |
| // cF |= Flags.E_FragmentNotCanonical; | |
| // } | |
| // | |
| // if (m_iriParsing && ((result & (Check.DisplayCanonical | Check.EscapedCanonical | Check.BackslashInPath | |
| // | Check.FoundNonAscii | Check.NotIriCanonical)) | |
| // == (Check.DisplayCanonical | Check.FoundNonAscii))){ | |
| // cF |= Flags.FragmentIriCanonical; | |
| // } | |
| // | |
| // } | |
| // } | |
| // m_Info.Offset.End = idx; | |
| // Done: | |
| // | |
| // cF |= Flags.AllUriInfoSet; | |
| // lock (m_Info) | |
| // { | |
| // m_Flags |= cF; | |
| // } | |
| // m_Flags |= Flags.RestUnicodeNormalized; | |
| // } | |
| // | |
| // // | |
| // // | |
| // // verifies the syntax of the scheme part | |
| // // Checks on implicit File: scheme due to simple Dos/Unc path passed | |
| // // returns the start of the next component position | |
| // // throws UriFormatException if invalid scheme | |
| // // | |
| // unsafe static private ushort ParseSchemeCheckImplicitFile(char *uriString, ushort length, | |
| // ref ParsingError err, ref Flags flags, ref UriParser syntax) { | |
| // | |
| // ushort idx = 0; | |
| // | |
| // //skip whitespaces | |
| // while(idx < length && IsLWS(uriString[idx])) { | |
| // ++idx; | |
| // } | |
| // | |
| // // sets the recognizer for well known registered schemes | |
| // // file, ftp, http, https, uuid, etc | |
| // // Note that we don't support one-letter schemes that will be put into a DOS path bucket | |
| // | |
| // // | |
| // ushort end = idx; | |
| // while (end < length && uriString[end] != ':') { | |
| // ++end; | |
| // } | |
| // | |
| // // NB: On 64-bits we will use less optimized code from CheckSchemeSyntax() | |
| // // | |
| // if (IntPtr.Size == 4) { | |
| // // long = 4chars: The minimal size of a known scheme is 2 + ':' | |
| // if (end != length && end >= idx+2 && | |
| // CheckKnownSchemes((long*) (uriString + idx), (ushort)(end-idx), ref syntax)) { | |
| // return (ushort)(end+1); | |
| // } | |
| // } | |
| // | |
| // //NB: A string must have at least 3 characters and at least 1 before ':' | |
| // if (idx+2 >= length || end == idx) { | |
| // err = ParsingError.BadFormat; | |
| // return 0; | |
| // } | |
| // | |
| // //Check for supported special cases like a DOS file path OR a UNC share path | |
| // //NB: A string may not have ':' if this is a UNC path | |
| // { | |
| // char c; | |
| // if ((c=uriString[idx+1]) == ':' || c == '|') { | |
| // #if !PLATFORM_UNIX | |
| // //DOS-like path? | |
| // if (IsAsciiLetter(uriString[idx])) { | |
| // if((c=uriString[idx+2]) == '\\' || c== '/') { | |
| // flags |= (Flags.DosPath|Flags.ImplicitFile|Flags.AuthorityFound); | |
| // syntax = UriParser.FileUri; | |
| // return idx; | |
| // } | |
| // err = ParsingError.MustRootedPath; | |
| // return 0; | |
| // } | |
| // #endif // !PLATFORM_UNIX | |
| // if (c == ':') | |
| // err = ParsingError.BadScheme; | |
| // else | |
| // err = ParsingError.BadFormat; | |
| // return 0; | |
| // } | |
| // #if !PLATFORM_UNIX | |
| // else if ((c=uriString[idx]) == '/' || c == '\\') { | |
| // //UNC share ? | |
| // if ((c=uriString[idx+1]) == '\\' || c == '/') { | |
| // flags |= (Flags.UncPath|Flags.ImplicitFile|Flags.AuthorityFound); | |
| // syntax = UriParser.FileUri; | |
| // idx+=2; | |
| // // V1.1 compat this will simply eat any slashes prepended to a UNC path | |
| // while (idx < length && ((c=uriString[idx]) == '/' || c == '\\')) | |
| // ++idx; | |
| // | |
| // return idx; | |
| // } | |
| // err = ParsingError.BadFormat; | |
| // return 0; | |
| // } | |
| // #else | |
| // else if (uriString[idx] == '/') { | |
| // // On UNIX an implicit file has the form /<path> or scheme:///<path> | |
| // if (idx == 0 || uriString[idx-1] != ':' ) { | |
| // // No scheme present; implicit /<path> starting at idx | |
| // flags |= (Flags.ImplicitFile|Flags.AuthorityFound); | |
| // syntax = UriParser.FileUri; | |
| // return idx; | |
| // } else if (uriString[idx+1] == '/' && uriString[idx+2] == '/') { | |
| // // scheme present; rooted path starts at idx + 2 | |
| // flags |= (Flags.ImplicitFile|Flags.AuthorityFound); | |
| // syntax = UriParser.FileUri; | |
| // idx+=2; | |
| // return idx; | |
| // } | |
| // } | |
| // else if (uriString[idx] == '\\') { | |
| // err = ParsingError.BadFormat; | |
| // return 0; | |
| // } | |
| // #endif // !PLATFORM_UNIX | |
| // } | |
| // | |
| // if (end == length) { | |
| // err = ParsingError.BadFormat; | |
| // return 0; | |
| // } | |
| // | |
| // // Here could be a possibly valid, and not well-known scheme | |
| // // Finds the scheme delimiter | |
| // // we don;t work with the schemes names > c_MaxUriSchemeName (should be ~1k) | |
| // if ((end-idx) > c_MaxUriSchemeName) { | |
| // err = ParsingError.SchemeLimit; | |
| // return 0; | |
| // } | |
| // | |
| // //Check the syntax, canonicalize and avoid a GC call | |
| // char* schemePtr = stackalloc char[end-idx]; | |
| // for (length = 0; idx < end; ++idx) { | |
| // schemePtr[length++] = uriString[idx]; | |
| // } | |
| // err = CheckSchemeSyntax(schemePtr, length, ref syntax); | |
| // if (err != ParsingError.None) { | |
| // return 0; | |
| // } | |
| // return (ushort)(end+1); | |
| // } | |
| // // | |
| // // Quickly parses well known schemes. | |
| // // nChars does not include the last ':'. Assuming there is one at the end of passed buffer | |
| // unsafe static private bool CheckKnownSchemes(long *lptr, ushort nChars, ref UriParser syntax) { | |
| // //NOTE beware of too short input buffers! | |
| // | |
| // const long _HTTP_Mask0 = 'h'|('t'<<16)|((long)'t'<<32)|((long)'p'<<48); | |
| // const char _HTTPS_Mask1 = 's'; | |
| // const int _WS_Mask = 'w'|('s'<<16); | |
| // const long _WSS_Mask = 'w'|('s'<<16)|((long)'s'<<32)|((long)':'<<48); | |
| // const long _FTP_Mask = 'f'|('t'<<16)|((long)'p'<<32)|((long)':'<<48); | |
| // const long _FILE_Mask0 = 'f'|('i'<<16)|((long)'l'<<32)|((long)'e'<<48); | |
| // const long _GOPHER_Mask0 = 'g'|('o'<<16)|((long)'p'<<32)|((long)'h'<<48); | |
| // const int _GOPHER_Mask1 = 'e'|('r'<<16); | |
| // const long _MAILTO_Mask0 = 'm'|('a'<<16)|((long)'i'<<32)|((long)'l'<<48); | |
| // const int _MAILTO_Mask1 = 't'|('o'<<16); | |
| // const long _NEWS_Mask0 = 'n'|('e'<<16)|((long)'w'<<32)|((long)'s'<<48); | |
| // const long _NNTP_Mask0 = 'n'|('n'<<16)|((long)'t'<<32)|((long)'p'<<48); | |
| // const long _UUID_Mask0 = 'u'|('u'<<16)|((long)'i'<<32)|((long)'d'<<48); | |
| // | |
| // const long _TELNET_Mask0 = 't'|('e'<<16)|((long)'l'<<32)|((long)'n'<<48); | |
| // const int _TELNET_Mask1 = 'e'|('t'<<16); | |
| // | |
| // const long _NETXXX_Mask0 = 'n'|('e'<<16)|((long)'t'<<32)|((long)'.'<<48); | |
| // const long _NETTCP_Mask1 = 't'|('c'<<16)|((long)'p'<<32)|((long)':'<<48); | |
| // const long _NETPIPE_Mask1 = 'p'|('i'<<16)|((long)'p'<<32)|((long)'e'<<48); | |
| // | |
| // const long _LDAP_Mask0 = 'l'|('d'<<16)|((long)'a'<<32)|((long)'p'<<48); | |
| // | |
| // | |
| // const long _LOWERCASE_Mask = 0x0020002000200020L; | |
| // const int _INT_LOWERCASE_Mask = 0x00200020; | |
| // | |
| // if (nChars == 2) { | |
| // // This is the only known scheme of length 2 | |
| // if ((((int)*lptr) | _INT_LOWERCASE_Mask) == _WS_Mask) { | |
| // syntax = UriParser.WsUri; | |
| // return true; | |
| // } | |
| // return false; | |
| // } | |
| // | |
| // //Map to a known scheme if possible | |
| // //upgrade 4 letters to ASCII lower case, keep a false case to stay false | |
| // switch (*lptr | _LOWERCASE_Mask) { | |
| // case _HTTP_Mask0: | |
| // if (nChars == 4) { | |
| // syntax = UriParser.HttpUri; | |
| // return true; | |
| // } | |
| // if (nChars == 5 && ((*(char*)(lptr+1))|0x20) == _HTTPS_Mask1) { | |
| // syntax = UriParser.HttpsUri; | |
| // return true; | |
| // } | |
| // break; | |
| // case _WSS_Mask: | |
| // if (nChars == 3) | |
| // { | |
| // syntax = UriParser.WssUri; | |
| // return true; | |
| // } | |
| // break; | |
| // case _FILE_Mask0: | |
| // if (nChars == 4) { | |
| // syntax = UriParser.FileUri; | |
| // return true; | |
| // } | |
| // break; | |
| // case _FTP_Mask: | |
| // if (nChars == 3) { | |
| // syntax = UriParser.FtpUri; | |
| // return true; | |
| // } | |
| // break; | |
| // | |
| // case _NEWS_Mask0: | |
| // if (nChars == 4) { | |
| // syntax = UriParser.NewsUri; | |
| // return true; | |
| // } | |
| // break; | |
| // | |
| // case _NNTP_Mask0: | |
| // if (nChars == 4) { | |
| // syntax = UriParser.NntpUri; | |
| // return true; | |
| // } | |
| // break; | |
| // | |
| // case _UUID_Mask0: | |
| // if (nChars == 4) { | |
| // syntax = UriParser.UuidUri; | |
| // return true; | |
| // } | |
| // break; | |
| // | |
| // case _GOPHER_Mask0: | |
| // if (nChars == 6 && (*(int*)(lptr+1)|_INT_LOWERCASE_Mask) == _GOPHER_Mask1) { | |
| // syntax = UriParser.GopherUri; | |
| // return true; | |
| // } | |
| // break; | |
| // case _MAILTO_Mask0: | |
| // if (nChars == 6 && (*(int*)(lptr+1)|_INT_LOWERCASE_Mask) == _MAILTO_Mask1) { | |
| // syntax = UriParser.MailToUri; | |
| // return true; | |
| // } | |
| // break; | |
| // | |
| // case _TELNET_Mask0: | |
| // if (nChars == 6 && (*(int*)(lptr+1)|_INT_LOWERCASE_Mask) == _TELNET_Mask1) { | |
| // syntax = UriParser.TelnetUri; | |
| // return true; | |
| // } | |
| // break; | |
| // | |
| // case _NETXXX_Mask0: | |
| // if (nChars == 8 && (*(lptr+1)|_LOWERCASE_Mask) == _NETPIPE_Mask1) { | |
| // syntax = UriParser.NetPipeUri; | |
| // return true; | |
| // } | |
| // else if (nChars == 7 && (*(lptr+1)|_LOWERCASE_Mask) == _NETTCP_Mask1) { | |
| // syntax = UriParser.NetTcpUri; | |
| // return true; | |
| // } | |
| // break; | |
| // | |
| // case _LDAP_Mask0: | |
| // if (nChars == 4) { | |
| // syntax = UriParser.LdapUri; | |
| // return true; | |
| // } | |
| // break; | |
| // default: break; | |
| // } | |
| // return false; | |
| // } | |
| // | |
| // // | |
| // // | |
| // // This will check whether a scheme string follows the rules | |
| // // | |
| // unsafe static private ParsingError CheckSchemeSyntax(char* ptr, ushort length, ref UriParser syntax) { | |
| // //First character must be an alpha | |
| // { | |
| // char c = *ptr; | |
| // if (c >= 'a' && c <= 'z') { | |
| // ; | |
| // } else if (c >= 'A' && c <= 'Z') { | |
| // *ptr = (char)(c | 0x20); //make it lowercase | |
| // } else { | |
| // return ParsingError.BadScheme; | |
| // } | |
| // } | |
| // | |
| // for (ushort i = 1; i < length; ++i) { | |
| // char c = ptr[i]; | |
| // if (c >= 'a' && c <= 'z') { | |
| // ; | |
| // } else if (c >= 'A' && c <= 'Z') { | |
| // ptr[i] = (char)(c | 0x20); //make it lowercase | |
| // } else if (c >= '0' && c <= '9') { | |
| // ; | |
| // } else if (c == '+' || c == '-' || c == '.') { | |
| // ; | |
| // } else { | |
| // return ParsingError.BadScheme; | |
| // } | |
| // } | |
| // // A not well-known scheme, needs string creation | |
| // // Note it is already in the lower case as required. | |
| // string str = new string(ptr, 0, length); | |
| // syntax = UriParser.FindOrFetchAsUnknownV1Syntax(str); | |
| // return ParsingError.None; | |
| // } | |
| // // | |
| // // | |
| // // Checks the syntax of an authority component. It may also get a userInfo if present | |
| // // Returns an error if no/mailformed authority found | |
| // // Does not NOT touch m_Info | |
| // // Returns position of the Path component | |
| // // | |
| // // Must be called in the ctor only | |
| // private unsafe ushort CheckAuthorityHelper( char* pString, ushort idx, ushort length, | |
| // ref ParsingError err, ref Flags flags, UriParser syntax, ref string newHost ) | |
| // { | |
| // int end = length; | |
| // char ch; | |
| // int startInput = idx; | |
| // ushort start = idx; | |
| // newHost = null; | |
| // bool justNormalized = false; | |
| // bool iriParsing = (s_IriParsing && IriParsingStatic(syntax)); // perf | |
| // bool hasUnicode = ((flags & Flags.HasUnicode) != 0); // perf | |
| // bool hostNotUnicodeNormalized = ((flags & Flags.HostUnicodeNormalized) == 0); // perf | |
| // UriSyntaxFlags syntaxFlags = syntax.Flags; | |
| // | |
| // // need to build new Iri'zed string | |
| // if (hasUnicode && iriParsing && hostNotUnicodeNormalized){ | |
| // newHost = m_originalUnicodeString.Substring(0, startInput); | |
| // } | |
| // | |
| // //Special case is an empty authority | |
| // if (idx == length || ((ch=pString[idx]) == '/' || (ch == '\\' && StaticIsFile(syntax)) || ch == '#' || ch == '?')) | |
| // { | |
| // if (syntax.InFact(UriSyntaxFlags.AllowEmptyHost)) | |
| // { | |
| // flags &= ~Flags.UncPath; //UNC cannot have an empty hostname | |
| // if (StaticInFact(flags, Flags.ImplicitFile)) | |
| // err = ParsingError.BadHostName; | |
| // else | |
| // flags |= Flags.BasicHostType; | |
| // } | |
| // else | |
| // err = ParsingError.BadHostName; | |
| // | |
| // if (hasUnicode && iriParsing && hostNotUnicodeNormalized){ | |
| // flags |= Flags.HostUnicodeNormalized;// no host | |
| // } | |
| // | |
| // return idx; | |
| // } | |
| // | |
| // //#if PLATFORM_UNIX | |
| // // if (StaticIsFile(syntax) && ch != '/') { | |
| // // // On UNIX a file URL may only have an empty authority | |
| // // err = ParsingError.NonEmptyHost; | |
| // // return idx; | |
| // // } | |
| // //#endif // PLATFORM_UNIX | |
| // | |
| // string userInfoString = null; | |
| // // Attempt to parse user info first | |
| // | |
| // if ((syntaxFlags & UriSyntaxFlags.MayHaveUserInfo) != 0) | |
| // { | |
| // for (; start < end; ++start) | |
| // { | |
| // if (start == end - 1 || pString[start] == '?' || pString[start] == '#' || pString[start] == '\\' || | |
| // pString[start] == '/') | |
| // { | |
| // start = idx; | |
| // break; | |
| // } | |
| // else if (pString[start] == '@') | |
| // { | |
| // flags |= Flags.HasUserInfo; | |
| // | |
| // // Iri'ze userinfo | |
| // if (iriParsing || (s_IdnScope != UriIdnScope.None)){ | |
| // if (iriParsing && hasUnicode && hostNotUnicodeNormalized){ | |
| // // Normalize user info | |
| // userInfoString = IriHelper.EscapeUnescapeIri(pString, startInput, start + 1, UriComponents.UserInfo); | |
| // try{ | |
| // if (UriParser.ShouldUseLegacyV2Quirks) | |
| // userInfoString = userInfoString.Normalize(NormalizationForm.FormC); | |
| // } | |
| // catch (ArgumentException){ | |
| // err = ParsingError.BadFormat; | |
| // return idx; | |
| // } | |
| // | |
| // newHost += userInfoString; | |
| // | |
| // if (!ServicePointManager.AllowAllUriEncodingExpansion && newHost.Length > ushort.MaxValue){ | |
| // err = ParsingError.SizeLimit; | |
| // return idx; | |
| // } | |
| // } | |
| // else{ | |
| // userInfoString = new string(pString, startInput, start - startInput + 1); | |
| // } | |
| // } | |
| // ++start; | |
| // ch = pString[start]; | |
| // break; | |
| // } | |
| // } | |
| // } | |
| // | |
| // // DNS name only optimization | |
| // // Fo an overriden parsing the optimization is suppressed since hostname can be changed to anything | |
| // bool dnsNotCanonical = ((syntaxFlags & UriSyntaxFlags.SimpleUserSyntax) == 0); | |
| // | |
| // if (ch == '[' && syntax.InFact(UriSyntaxFlags.AllowIPv6Host) | |
| // && IPv6AddressHelper.IsValid(pString, (int)start+1, ref end)) | |
| // { | |
| // flags |= Flags.IPv6HostType; | |
| // | |
| // // Force load config here if config not loaded earlier since we handle IsWellFormed differently | |
| // // for IPv6 if the iri parsing flag is on or off | |
| // if (!s_ConfigInitialized) { | |
| // InitializeUriConfig(); | |
| // m_iriParsing = (s_IriParsing && IriParsingStatic(syntax)); | |
| // } | |
| // | |
| // if (hasUnicode && iriParsing && hostNotUnicodeNormalized) { | |
| // newHost += new string(pString, start, end - start); | |
| // flags |= Flags.HostUnicodeNormalized; | |
| // justNormalized = true; | |
| // } | |
| // } | |
| // else if ( ch <= '9' && ch >= '0' && syntax.InFact(UriSyntaxFlags.AllowIPv4Host) && | |
| // IPv4AddressHelper.IsValid(pString, (int) start, ref end, false, StaticNotAny(flags, Flags.ImplicitFile), syntax.InFact(UriSyntaxFlags.V1_UnknownUri))) | |
| // { | |
| // flags |= Flags.IPv4HostType; | |
| // | |
| // if (hasUnicode && iriParsing && hostNotUnicodeNormalized){ | |
| // newHost += new string(pString, start, end - start); | |
| // flags |= Flags.HostUnicodeNormalized; | |
| // justNormalized = true; | |
| // } | |
| // } | |
| // else if (((syntaxFlags & UriSyntaxFlags.AllowDnsHost)!= 0) && !iriParsing && | |
| // DomainNameHelper.IsValid(pString, start, ref end, ref dnsNotCanonical, StaticNotAny(flags, Flags.ImplicitFile))) | |
| // { | |
| // // comes here if there are only ascii chars in host with original parsing and no Iri | |
| // | |
| // flags |= Flags.DnsHostType; | |
| // if (!dnsNotCanonical) { | |
| // flags |= Flags.CanonicalDnsHost; | |
| // } | |
| // | |
| // if ((s_IdnScope != UriIdnScope.None)){ | |
| // // check if intranet | |
| // // | |
| // if ((s_IdnScope == UriIdnScope.AllExceptIntranet) && IsIntranet(new string(pString, 0, end))){ | |
| // flags |= Flags.IntranetUri; | |
| // } | |
| // if (AllowIdnStatic(syntax, flags)){ | |
| // bool allAscii = true; | |
| // bool atLeastOneIdn = false; | |
| // | |
| // string idnValue = DomainNameHelper.UnicodeEquivalent(pString, start, end, ref allAscii, ref atLeastOneIdn); | |
| // | |
| // // did we find at least one valid idn | |
| // if (atLeastOneIdn) | |
| // { | |
| // // need to switch string here since we didnt know before hand there there was an idn host | |
| // if (StaticNotAny(flags, Flags.HasUnicode)) | |
| // m_originalUnicodeString = m_String; // lazily switching strings | |
| // flags |= Flags.IdnHost; | |
| // | |
| // // need to build string for this special scenario | |
| // newHost = m_originalUnicodeString.Substring(0, startInput) + userInfoString + idnValue; | |
| // flags |= Flags.CanonicalDnsHost; | |
| // m_DnsSafeHost = new string(pString, start, end - start); | |
| // justNormalized = true; | |
| // } | |
| // flags |= Flags.HostUnicodeNormalized; | |
| // } | |
| // } | |
| // } | |
| // else if (((syntaxFlags & UriSyntaxFlags.AllowDnsHost) != 0) | |
| // && ((syntax.InFact(UriSyntaxFlags.AllowIriParsing) && hostNotUnicodeNormalized) | |
| // || syntax.InFact(UriSyntaxFlags.AllowIdn)) | |
| // && DomainNameHelper.IsValidByIri(pString, start, ref end, ref dnsNotCanonical, | |
| // StaticNotAny(flags, Flags.ImplicitFile))) | |
| // { | |
| // CheckAuthorityHelperHandleDnsIri(pString, start, end, startInput, iriParsing, hasUnicode, syntax, | |
| // userInfoString, ref flags, ref justNormalized, ref newHost, ref err); | |
| // } | |
| // #if !PLATFORM_UNIX | |
| // else if ((syntaxFlags & UriSyntaxFlags.AllowUncHost) != 0) | |
| // { | |
| // // | |
| // // This must remain as the last check befor BasicHost type | |
| // // | |
| // if (UncNameHelper.IsValid(pString, start, ref end, StaticNotAny(flags, Flags.ImplicitFile))) | |
| // { | |
| // if (end - start <= UncNameHelper.MaximumInternetNameLength) | |
| // { | |
| // flags |= Flags.UncHostType; | |
| // if (hasUnicode && iriParsing && hostNotUnicodeNormalized) | |
| // { | |
| // newHost += new string(pString, start, end - start); | |
| // flags |= Flags.HostUnicodeNormalized; | |
| // justNormalized = true; | |
| // } | |
| // } | |
| // } | |
| // } | |
| // #endif // !PLATFORM_UNIX | |
| // | |
| // // The deal here is that we won't allow '\' host terminator except for the File scheme | |
| // // If we see '\' we try to make it a part of of a Basic host | |
| // if (end < length && pString[end] == '\\' && (flags & Flags.HostTypeMask) != Flags.HostNotParsed | |
| // && !StaticIsFile(syntax)) | |
| // { | |
| // if (syntax.InFact(UriSyntaxFlags.V1_UnknownUri)) | |
| // { | |
| // err = ParsingError.BadHostName; | |
| // flags |= Flags.UnknownHostType; | |
| // return (ushort) end; | |
| // } | |
| // flags &= ~Flags.HostTypeMask; | |
| // } | |
| // // Here we have checked the syntax up to the end of host | |
| // // The only thing that can cause an exception is the port value | |
| // // Spend some (duplicated) cycles on that. | |
| // else if (end < length && pString[end] == ':') | |
| // { | |
| // if (syntax.InFact(UriSyntaxFlags.MayHavePort)) | |
| // { | |
| // int port = 0; | |
| // int startPort = end; | |
| // for (idx = (ushort)(end+1); idx < length; ++idx) { | |
| // ushort val = (ushort)((ushort)pString[idx] - (ushort)'0'); | |
| // if ((val >= 0) && (val <= 9)) | |
| // { | |
| // if ((port = (port * 10 + val)) > 0xFFFF) | |
| // break; | |
| // } | |
| // else if (val == unchecked((ushort)('/' - '0')) || val == (ushort)('?' - '0') | |
| // || val == unchecked((ushort)('#' - '0'))) | |
| // { | |
| // break; | |
| // } | |
| // else | |
| // { | |
| // // The second check is to keep compatibility with V1 until the UriParser is registered | |
| // if(syntax.InFact(UriSyntaxFlags.AllowAnyOtherHost) | |
| // && syntax.NotAny(UriSyntaxFlags.V1_UnknownUri)) | |
| // { | |
| // flags &= ~Flags.HostTypeMask; | |
| // break; | |
| // } | |
| // else | |
| // { | |
| // err = ParsingError.BadPort; | |
| // return idx; | |
| // } | |
| // } | |
| // } | |
| // // check on 0-ffff range | |
| // if (port > 0xFFFF) | |
| // { | |
| // if (syntax.InFact(UriSyntaxFlags.AllowAnyOtherHost)) | |
| // { | |
| // flags &= ~Flags.HostTypeMask; | |
| // } | |
| // else | |
| // { | |
| // err = ParsingError.BadPort; | |
| // return idx; | |
| // } | |
| // } | |
| // | |
| // if (iriParsing && hasUnicode && justNormalized){ | |
| // newHost += new string(pString, startPort, idx - startPort); | |
| // } | |
| // } | |
| // else | |
| // { | |
| // flags &= ~Flags.HostTypeMask; | |
| // } | |
| // | |
| // } | |
| // | |
| // // check on whether nothing has worked out | |
| // if ((flags & Flags.HostTypeMask) == Flags.HostNotParsed) | |
| // { | |
| // //No user info for a Basic hostname | |
| // flags &= ~Flags.HasUserInfo; | |
| // // Some schemes do not allow HostType = Basic (plus V1 almost never understands this cause of a bug) | |
| // // | |
| // if(syntax.InFact(UriSyntaxFlags.AllowAnyOtherHost)) | |
| // { | |
| // flags |= Flags.BasicHostType; | |
| // for (end = idx; end < length; ++end) { | |
| // if (pString[end] == '/' || (pString[end] == '?' || pString[end] == '#')) { | |
| // break; | |
| // } | |
| // } | |
| // CheckAuthorityHelperHandleAnyHostIri(pString, startInput, end, iriParsing, hasUnicode, syntax, | |
| // ref flags, ref newHost, ref err); | |
| // } | |
| // else | |
| // { | |
| // // | |
| // // ATTN V1 compat: V1 supports hostnames like ".." and ".", and so we do but only for unknown schemes. | |
| // // (VsWhidbey#438821) | |
| // if (syntax.InFact(UriSyntaxFlags.V1_UnknownUri)) | |
| // { | |
| // // Can assert here that the host is not empty so we will set dotFound | |
| // // at least once or fail before exiting the loop | |
| // bool dotFound = false; | |
| // int startOtherHost = idx; | |
| // for (end = idx; end < length; ++end) | |
| // { | |
| // if (dotFound && (pString[end] == '/' || pString[end] == '?' || pString[end] == '#')) | |
| // break; | |
| // else if (end < (idx + 2) && pString[end] == '.') | |
| // { | |
| // // allow one or two dots | |
| // dotFound = true; | |
| // } | |
| // else | |
| // { | |
| // //failure | |
| // err = ParsingError.BadHostName; | |
| // flags |= Flags.UnknownHostType; | |
| // return idx; | |
| // } | |
| // } | |
| // //success | |
| // flags |= Flags.BasicHostType; | |
| // | |
| // if (iriParsing && hasUnicode | |
| // && StaticNotAny(flags, Flags.HostUnicodeNormalized)){ | |
| // // Normalize any other host | |
| // String user = new string(pString, startOtherHost, end - startOtherHost); | |
| // try | |
| // { | |
| // newHost += user.Normalize(NormalizationForm.FormC); | |
| // } | |
| // catch (ArgumentException){ | |
| // err = ParsingError.BadFormat; | |
| // return idx; | |
| // } | |
| // | |
| // flags |= Flags.HostUnicodeNormalized; | |
| // } | |
| // } | |
| // else if (syntax.InFact(UriSyntaxFlags.MustHaveAuthority) || | |
| // (syntax.InFact(UriSyntaxFlags.MailToLikeUri) && !UriParser.ShouldUseLegacyV2Quirks)) | |
| // { | |
| // err = ParsingError.BadHostName; | |
| // flags |= Flags.UnknownHostType; | |
| // return idx; | |
| // } | |
| // } | |
| // } | |
| // return (ushort) end; | |
| // } | |
| // | |
| // unsafe void CheckAuthorityHelperHandleDnsIri( char* pString, ushort start, int end, int startInput, | |
| // bool iriParsing, bool hasUnicode, UriParser syntax, string userInfoString, ref Flags flags, | |
| // ref bool justNormalized, ref string newHost, ref ParsingError err) | |
| // { | |
| // // comes here only if host has unicode chars and iri is on or idn is allowed | |
| // | |
| // flags |= Flags.DnsHostType; | |
| // | |
| // // check if intranet | |
| // // | |
| // if ((s_IdnScope == UriIdnScope.AllExceptIntranet) && IsIntranet(new string(pString, 0, end))) | |
| // { | |
| // flags |= Flags.IntranetUri; | |
| // } | |
| // | |
| // if (AllowIdnStatic(syntax, flags)) | |
| // { | |
| // bool allAscii = true; | |
| // bool atLeastOneIdn = false; | |
| // | |
| // string idnValue = DomainNameHelper.IdnEquivalent(pString, start, end, ref allAscii, ref atLeastOneIdn); | |
| // string UniEquvlt = DomainNameHelper.UnicodeEquivalent(idnValue, pString, start, end); | |
| // | |
| // if (!allAscii) | |
| // flags |= Flags.UnicodeHost; // we have a unicode host | |
| // | |
| // if (atLeastOneIdn) | |
| // flags |= Flags.IdnHost; // we have at least one valid idn label | |
| // | |
| // if (allAscii && atLeastOneIdn && StaticNotAny(flags, Flags.HasUnicode)) | |
| // { | |
| // // original string location changed lazily | |
| // m_originalUnicodeString = m_String; | |
| // newHost = m_originalUnicodeString.Substring(0, startInput) + | |
| // (StaticInFact(flags, Flags.HasUserInfo) ? userInfoString : null); | |
| // justNormalized = true; | |
| // } | |
| // else if (!iriParsing && (StaticInFact(flags, Flags.UnicodeHost) || StaticInFact(flags, Flags.IdnHost))) | |
| // { | |
| // // original string location changed lazily | |
| // m_originalUnicodeString = m_String; | |
| // newHost = m_originalUnicodeString.Substring(0, startInput) + | |
| // (StaticInFact(flags, Flags.HasUserInfo) ? userInfoString : null); | |
| // justNormalized = true; | |
| // } | |
| // | |
| // if (!(allAscii && !atLeastOneIdn)) | |
| // { | |
| // m_DnsSafeHost = idnValue; | |
| // newHost += UniEquvlt; | |
| // justNormalized = true; | |
| // } | |
| // else if (allAscii && !atLeastOneIdn && iriParsing && hasUnicode) | |
| // { | |
| // newHost += UniEquvlt; | |
| // justNormalized = true; | |
| // } | |
| // } | |
| // else | |
| // { | |
| // if (hasUnicode) | |
| // { | |
| // string temp = StripBidiControlCharacter(pString, start, end - start); | |
| // try{ | |
| // newHost += ((temp != null) ? temp.Normalize(NormalizationForm.FormC) : null); | |
| // } | |
| // catch (ArgumentException){ | |
| // err = ParsingError.BadHostName; | |
| // } | |
| // justNormalized = true; | |
| // } | |
| // } | |
| // flags |= Flags.HostUnicodeNormalized; | |
| // } | |
| // | |
| // unsafe void CheckAuthorityHelperHandleAnyHostIri(char* pString, int startInput, int end, | |
| // bool iriParsing, bool hasUnicode, UriParser syntax, | |
| // ref Flags flags, ref string newHost, ref ParsingError err) | |
| // { | |
| // if (StaticNotAny(flags, Flags.HostUnicodeNormalized) && (AllowIdnStatic(syntax, flags) || | |
| // (iriParsing && hasUnicode))) | |
| // { | |
| // // Normalize any other host or do idn | |
| // String user = new string(pString, startInput, end - startInput); | |
| // | |
| // if (AllowIdnStatic(syntax, flags)) | |
| // { | |
| // bool allAscii = true; | |
| // bool atLeastOneIdn = false; | |
| // | |
| // string UniEquvlt = DomainNameHelper.UnicodeEquivalent(pString, startInput, end, ref allAscii, | |
| // ref atLeastOneIdn); | |
| // | |
| // if (((allAscii && atLeastOneIdn) || !allAscii) && !(iriParsing && hasUnicode)) | |
| // { | |
| // // original string location changed lazily | |
| // m_originalUnicodeString = m_String; | |
| // newHost = m_originalUnicodeString.Substring(0, startInput); | |
| // flags |= Flags.HasUnicode; | |
| // } | |
| // if (atLeastOneIdn || !allAscii) | |
| // { | |
| // newHost += UniEquvlt; | |
| // string bidiStrippedHost = null; | |
| // m_DnsSafeHost = DomainNameHelper.IdnEquivalent(pString, startInput, end, ref allAscii, | |
| // ref bidiStrippedHost); | |
| // if (atLeastOneIdn) | |
| // flags |= Flags.IdnHost; | |
| // if (!allAscii) | |
| // flags |= Flags.UnicodeHost; | |
| // } | |
| // else if (iriParsing && hasUnicode) | |
| // { | |
| // newHost += user; | |
| // | |
| // } | |
| // } | |
| // else | |
| // { | |
| // try{ | |
| // newHost += user.Normalize(NormalizationForm.FormC); | |
| // } | |
| // catch (ArgumentException){ | |
| // err = ParsingError.BadHostName; | |
| // } | |
| // } | |
| // | |
| // flags |= Flags.HostUnicodeNormalized; | |
| // } | |
| // } | |
| // | |
| // // | |
| // // | |
| // // The method checks whether a string needs transformation before going to display or wire | |
| // // | |
| // // Parameters: | |
| // // - escaped true = treat all valid escape sequences as escaped sequences, false = escape all % | |
| // // - delim a character signalling the termination of the component being checked | |
| // // | |
| // // When delim=='?', then '#' character is also considered as delimiter additionally to passed '?'. | |
| // // | |
| // // The method pays attention to the dots and slashes so to signal potential Path compression action needed. | |
| // // Even that is not required for other components, the cycles are still spent (little inefficiency) | |
| // // | |
| // | |
| // internal const char c_DummyChar = (char) 0xFFFF; //An Invalid Unicode character used as a dummy char passed into the parameter | |
| // internal const char c_EOL = (char) 0xFFFE; //An Invalid Unicode character used by CheckCanonical as "no delimiter condition" | |
| // [Flags] | |
| // private enum Check { | |
| // None = 0x0, | |
| // EscapedCanonical= 0x1, | |
| // DisplayCanonical= 0x2, | |
| // DotSlashAttn = 0x4, | |
| // DotSlashEscaped = 0x80, | |
| // BackslashInPath = 0x10, | |
| // ReservedFound = 0x20, | |
| // NotIriCanonical = 0x40, | |
| // FoundNonAscii = 0x8 | |
| // } | |
| // | |
| // // | |
| // // Finds the end of component | |
| // // | |
| // | |
| // private unsafe void FindEndOfComponent(string input, ref ushort idx, ushort end, char delim) | |
| // { | |
| // fixed (char* str = input) | |
| // { | |
| // FindEndOfComponent(str, ref idx, end, delim); | |
| // } | |
| // } | |
| // private unsafe void FindEndOfComponent(char* str, ref ushort idx, ushort end, char delim) | |
| // { | |
| // char c = c_DummyChar; | |
| // ushort i=idx; | |
| // for (; i < end; ++i) | |
| // { | |
| // c = str[i]; | |
| // if (c == delim) | |
| // { | |
| // break; | |
| // } | |
| // else if (delim == '?' && c == '#' && (m_Syntax != null && m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment))) | |
| // { | |
| // // this is a special case when deciding on Query/Fragment | |
| // break; | |
| // } | |
| // } | |
| // idx = i; | |
| // } | |
| // | |
| // // | |
| // // Used by ParseRemaining as well by InternalIsWellFormedOriginalString | |
| // // | |
| // private unsafe Check CheckCanonical(char* str, ref ushort idx, ushort end, char delim) { | |
| // Check res = Check.None; | |
| // bool needsEscaping = false; | |
| // bool foundEscaping = false; | |
| // | |
| // char c = c_DummyChar; | |
| // ushort i=idx; | |
| // for (; i < end; ++i) | |
| // { | |
| // c = str[i]; | |
| // // Control chars usually should be escaped in any case | |
| // if (c <= '\x1F' || (c >= '\x7F' && c <= '\x9F')) | |
| // { | |
| // needsEscaping = true; | |
| // foundEscaping = true; | |
| // res |= Check.ReservedFound; | |
| // } | |
| // else if (c > 'z' && c != '~') { | |
| // if(m_iriParsing){ | |
| // bool valid = false; | |
| // res |= Check.FoundNonAscii; | |
| // | |
| // if (Char.IsHighSurrogate(c)){ | |
| // if ((i + 1) < end){ | |
| // bool surrPair = false; | |
| // valid = IriHelper.CheckIriUnicodeRange(c, str[i + 1], ref surrPair, true); | |
| // } | |
| // } | |
| // else{ | |
| // valid = IriHelper.CheckIriUnicodeRange(c, true); | |
| // } | |
| // if (!valid) res |= Check.NotIriCanonical; | |
| // } | |
| // | |
| // if (!needsEscaping) needsEscaping = true; | |
| // } | |
| // else if (c == delim) { | |
| // break; | |
| // } | |
| // else if (delim == '?' && c == '#' && (m_Syntax != null && m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment))) { | |
| // // this is a special case when deciding on Query/Fragment | |
| // break; | |
| // } | |
| // else if (c == '?') { | |
| // if (IsImplicitFile || (m_Syntax != null && !m_Syntax.InFact(UriSyntaxFlags.MayHaveQuery) | |
| // && delim != c_EOL)) | |
| // { | |
| // // VsWhidbey#87423 | |
| // // If found as reserved this char is not suitable for safe unescaped display | |
| // // Will need to escape it when both escaping and unescaping the string | |
| // res |= Check.ReservedFound; | |
| // foundEscaping = true; | |
| // needsEscaping = true; | |
| // } | |
| // } | |
| // else if (c == '#') { | |
| // needsEscaping = true; | |
| // if (IsImplicitFile || (m_Syntax != null && !m_Syntax.InFact(UriSyntaxFlags.MayHaveFragment))) { | |
| // // VsWhidbey#87423, 122037 | |
| // // If found as reserved this char is not suitable for safe unescaped display | |
| // // Will need to escape it when both escaping and unescaping the string | |
| // res |= Check.ReservedFound; | |
| // foundEscaping = true; | |
| // } | |
| // } | |
| // else if (c == '/' || c == '\\') { | |
| // if ((res & Check.BackslashInPath) == 0 && c == '\\') { | |
| // res |= Check.BackslashInPath; | |
| // } | |
| // if ((res & Check.DotSlashAttn) == 0 && i+1 != end && (str[i+1] == '/' || str[i+1] == '\\' )) { | |
| // res |= Check.DotSlashAttn; | |
| // } | |
| // } | |
| // else if (c == '.') { | |
| // if ((res & Check.DotSlashAttn) == 0 && i+1 == end || str[i+1] == '.' || str[i+1] == '/' | |
| // || str[i+1] == '\\' || str[i+1] == '?' || str[i+1] == '#') { | |
| // res |= Check.DotSlashAttn; | |
| // } | |
| // } | |
| // else if (!needsEscaping && ((c <= '"' && c != '!') || (c >= '[' && c <= '^') || c == '>' | |
| // || c == '<' || c == '`')) { | |
| // needsEscaping = true; | |
| // } | |
| // else if (c == '%') { | |
| // if (!foundEscaping) foundEscaping = true; | |
| // //try unescape a byte hex escaping | |
| // if (i + 2 < end && (c = UriHelper.EscapedAscii(str[i + 1], str[i + 2])) != c_DummyChar) | |
| // { | |
| // if (c == '.' || c == '/' || c == '\\') { | |
| // res |= Check.DotSlashEscaped; | |
| // } | |
| // i+=2; | |
| // continue; | |
| // } | |
| // // otherwise we follow to non escaped case | |
| // if (!needsEscaping) { | |
| // needsEscaping = true; | |
| // } | |
| // } | |
| // } | |
| // | |
| // if (foundEscaping) { | |
| // if (!needsEscaping) { | |
| // res |= Check.EscapedCanonical; | |
| // } | |
| // } | |
| // else { | |
| // res |= Check.DisplayCanonical; | |
| // if (!needsEscaping) { | |
| // res |= Check.EscapedCanonical; | |
| // } | |
| // } | |
| // idx = i; | |
| // return res; | |
| // } | |
| // | |
| // // | |
| // // Returns the escaped and canonicalized path string | |
| // // the passed array must be long enough to hold at least | |
| // // canonical unescaped path representation (allocated by the caller) | |
| // // | |
| // private unsafe char[] GetCanonicalPath(char[] dest, ref int pos, UriFormat formatAs) | |
| // { | |
| // | |
| // if (InFact(Flags.FirstSlashAbsent)) | |
| // dest[pos++] = '/'; | |
| // | |
| // if (m_Info.Offset.Path == m_Info.Offset.Query) | |
| // return dest; | |
| // | |
| // int end = pos; | |
| // | |
| // int dosPathIdx = SecuredPathIndex; | |
| // | |
| // // Note that unescaping and then escapig back is not transitive hence not safe. | |
| // // We are vulnerable due to the way the UserEscaped flag is processed (see NDPWhidbey#10612 bug). | |
| // // Try to unescape only needed chars. | |
| // if (formatAs == UriFormat.UriEscaped) | |
| // { | |
| // if (InFact(Flags.ShouldBeCompressed)) | |
| // { | |
| // m_String.CopyTo(m_Info.Offset.Path, dest, end, m_Info.Offset.Query - m_Info.Offset.Path); | |
| // end += (m_Info.Offset.Query - m_Info.Offset.Path); | |
| // | |
| // // If the path was found as needed compression and contains escaped characters, unescape only | |
| // // interesting characters (safe) | |
| // | |
| // if (m_Syntax.InFact(UriSyntaxFlags.UnEscapeDotsAndSlashes) && InFact(Flags.PathNotCanonical) | |
| // && !IsImplicitFile) | |
| // { | |
| // fixed (char* pdest = dest) | |
| // { | |
| // UnescapeOnly(pdest, pos, ref end, '.', '/', | |
| // m_Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes) ? '\\' : c_DummyChar); | |
| // } | |
| // } | |
| // } | |
| // else | |
| // { | |
| // // | |
| // if (InFact(Flags.E_PathNotCanonical) && NotAny(Flags.UserEscaped)) { | |
| // string str = m_String; | |
| // | |
| // // Check on not canonical disk designation like C|\, should be rare, rare case | |
| // if (dosPathIdx != 0 && str[dosPathIdx + m_Info.Offset.Path -1] == '|') | |
| // { | |
| // str = str.Remove(dosPathIdx + m_Info.Offset.Path -1, 1); | |
| // str = str.Insert(dosPathIdx + m_Info.Offset.Path -1, ":"); | |
| // } | |
| // dest = UriHelper.EscapeString(str, m_Info.Offset.Path, m_Info.Offset.Query, dest, ref end, true, | |
| // '?', '#', IsImplicitFile? c_DummyChar: '%'); | |
| // } | |
| // else { | |
| // m_String.CopyTo(m_Info.Offset.Path, dest, end, m_Info.Offset.Query - m_Info.Offset.Path); | |
| // end += (m_Info.Offset.Query - m_Info.Offset.Path); | |
| // } | |
| // } | |
| // } | |
| // else | |
| // { | |
| // m_String.CopyTo(m_Info.Offset.Path, dest, end, m_Info.Offset.Query - m_Info.Offset.Path); | |
| // end += (m_Info.Offset.Query - m_Info.Offset.Path); | |
| // | |
| // if (InFact(Flags.ShouldBeCompressed)) | |
| // { | |
| // // If the path was found as needed compression and contains escaped characters, | |
| // // unescape only interesting characters (safe) | |
| // | |
| // if (m_Syntax.InFact(UriSyntaxFlags.UnEscapeDotsAndSlashes) && InFact(Flags.PathNotCanonical) | |
| // && !IsImplicitFile) | |
| // { | |
| // fixed (char* pdest = dest) | |
| // { | |
| // UnescapeOnly(pdest, pos, ref end, '.', '/', | |
| // m_Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes) ? '\\' : c_DummyChar); | |
| // } | |
| // } | |
| // } | |
| // } | |
| // | |
| // // Here we already got output data as copied into dest array | |
| // // We just may need more processing of that data | |
| // | |
| // // | |
| // // if this URI is using 'non-proprietary' disk drive designation, convert to MS-style | |
| // // | |
| // // (path is already >= 3 chars if recognized as a DOS-like) | |
| // // | |
| // if (dosPathIdx != 0 && dest[dosPathIdx + pos - 1] == '|') | |
| // dest[dosPathIdx + pos - 1] = ':'; | |
| // | |
| // if (InFact(Flags.ShouldBeCompressed)) | |
| // { | |
| // // It will also convert back slashes if needed | |
| // dest = Compress(dest, (ushort)(pos + dosPathIdx), ref end, m_Syntax); | |
| // if (dest[pos] == '\\') | |
| // dest[pos] = '/'; | |
| // | |
| // // Escape path if requested and found as not fully escaped | |
| // if (formatAs == UriFormat.UriEscaped && NotAny(Flags.UserEscaped) && InFact(Flags.E_PathNotCanonical)) { | |
| // // | |
| // string srcString = new string(dest, pos, end-pos); | |
| // dest = UriHelper.EscapeString(srcString, 0, end - pos, dest, ref pos, true, '?', '#', | |
| // IsImplicitFile ? c_DummyChar : '%'); | |
| // end = pos; | |
| // } | |
| // } | |
| // else if (m_Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes) && InFact(Flags.BackslashInPath)) | |
| // { | |
| // for (int i = pos; i < end; ++i) | |
| // if (dest[i] == '\\') dest[i] = '/'; | |
| // } | |
| // | |
| // if (formatAs != UriFormat.UriEscaped && InFact(Flags.PathNotCanonical)) | |
| // { | |
| // UnescapeMode mode; | |
| // if (InFact(Flags.PathNotCanonical)) | |
| // { | |
| // switch (formatAs) | |
| // { | |
| // case V1ToStringUnescape: | |
| // | |
| // mode = (InFact(Flags.UserEscaped) ? UnescapeMode.Unescape : UnescapeMode.EscapeUnescape) | |
| // | UnescapeMode.V1ToStringFlag; | |
| // if (IsImplicitFile) | |
| // mode &= ~UnescapeMode.Unescape; | |
| // break; | |
| // | |
| // case UriFormat.Unescaped: | |
| // mode = IsImplicitFile ? UnescapeMode.CopyOnly | |
| // : UnescapeMode.Unescape | UnescapeMode.UnescapeAll; | |
| // break; | |
| // | |
| // default: // UriFormat.SafeUnescaped | |
| // | |
| // mode = InFact(Flags.UserEscaped)? UnescapeMode.Unescape: UnescapeMode.EscapeUnescape; | |
| // if (IsImplicitFile) | |
| // mode &= ~UnescapeMode.Unescape; | |
| // break; | |
| // } | |
| // } | |
| // else { | |
| // mode = UnescapeMode.CopyOnly; | |
| // } | |
| // | |
| // char[] dest1 = new char[dest.Length]; | |
| // Buffer.BlockCopy(dest, 0, dest1, 0, end<<1); | |
| // fixed (char *pdest = dest1) | |
| // { | |
| // dest = UriHelper.UnescapeString(pdest, pos, end, dest, ref pos, '?', '#', c_DummyChar, mode, | |
| // m_Syntax, false); | |
| // } | |
| // } | |
| // else | |
| // { | |
| // pos = end; | |
| // } | |
| // | |
| // return dest; | |
| // } | |
| // | |
| // // works only with ASCII characters, used to partially unescape path before compressing | |
| // private unsafe static void UnescapeOnly(char* pch, int start, ref int end, char ch1, char ch2, char ch3) { | |
| // if (end - start < 3) { | |
| // //no chance that something is escaped | |
| // return; | |
| // } | |
| // | |
| // char *pend = pch + end-2; | |
| // pch += start; | |
| // char *pnew = null; | |
| // | |
| // over: | |
| // | |
| // // Just looking for a interested escaped char | |
| // if (pch >= pend) goto done; | |
| // if(*pch++ != '%') goto over; | |
| // | |
| // char ch = UriHelper.EscapedAscii(*pch++, *pch++); | |
| // if (!(ch == ch1 || ch == ch2 || ch == ch3)) goto over; | |
| // | |
| // // Here we found something and now start copying the scanned chars | |
| // pnew = pch-2; | |
| // *(pnew-1) = ch; | |
| // | |
| // over_new: | |
| // | |
| // if (pch >= pend) goto done; | |
| // if((*pnew++ = *pch++) != '%') goto over_new; | |
| // | |
| // ch = UriHelper.EscapedAscii((*pnew++ = *pch++), (*pnew++ = *pch++)); | |
| // if (!(ch == ch1 || ch == ch2 || ch == ch3)) { | |
| // goto over_new; | |
| // } | |
| // | |
| // pnew -= 2; | |
| // *(pnew-1) = ch; | |
| // | |
| // goto over_new; | |
| // | |
| // done: | |
| // pend+=2; | |
| // | |
| // if (pnew == null) { | |
| // //nothing was found | |
| // return; | |
| // } | |
| // | |
| // //the tail may be already processed | |
| // if(pch == pend) { | |
| // end -= (int) (pch-pnew); | |
| // return; | |
| // } | |
| // | |
| // *pnew++ = *pch++; | |
| // if(pch == pend) { | |
| // end -= (int) (pch-pnew); | |
| // return; | |
| // } | |
| // *pnew++ = *pch++; | |
| // end -= (int) (pch-pnew); | |
| // } | |
| // | |
| // // | |
| // // | |
| // // This will compress any "\" "/../" "/./" "///" "/..../" /XXX.../, etc found in the input | |
| // // | |
| // // The passed syntax controls whether to use agressive compression or the one specified in RFC 2396 | |
| // // | |
| // // | |
| // private static char[] Compress(char[] dest, ushort start, ref int destLength, UriParser syntax) | |
| // { | |
| // ushort slashCount = 0; | |
| // ushort lastSlash = 0; | |
| // ushort dotCount = 0; | |
| // ushort removeSegments = 0; | |
| // | |
| // unchecked { | |
| // //ushort i == -1 and start == -1 overflow is ok here | |
| // ushort i = (ushort)((ushort)destLength - (ushort)1); | |
| // start = (ushort)(start-1); | |
| // | |
| // for (; i != start ; --i) { | |
| // char ch = dest[i]; | |
| // if (ch == '\\' && syntax.InFact(UriSyntaxFlags.ConvertPathSlashes)) { | |
| // dest[i] = ch = '/'; | |
| // } | |
| // | |
| // // | |
| // // compress multiple '/' for file URI | |
| // // | |
| // if (ch == '/') { | |
| // ++slashCount; | |
| // /* | |
| // QFE 4390 - remove the compression of multiple slashes to a single slash | |
| // if (slashCount > 1) { | |
| // continue; | |
| // } | |
| // */ | |
| // } | |
| // else { | |
| // if (slashCount > 1) { | |
| // /* | |
| // QFE 4390 - remove the compression of multiple slashes to a single slash | |
| // if (syntax.InFact(UriSyntaxFlags.CanonicalizeAsFilePath)) | |
| // { | |
| // // We saw > 1 slashes so remove all but the last one | |
| // // dest.Remove(i+1, slashCount -1); | |
| // Buffer.BlockCopy(dest, (i + slashCount) << 1, dest, (i + 1) << 1, | |
| // (destLength - (i + slashCount)) << 1); | |
| // destLength -= (slashCount - 1); | |
| // } | |
| // */ | |
| // // else preserve repeated slashes | |
| // lastSlash = (ushort)(i + 1); | |
| // } | |
| // slashCount = 0; | |
| // } | |
| // | |
| // if (ch == '.') { | |
| // ++dotCount; | |
| // continue; | |
| // } | |
| // else if (dotCount != 0) { | |
| // | |
| // bool skipSegment = syntax.NotAny(UriSyntaxFlags.CanonicalizeAsFilePath) | |
| // && (dotCount > 2 || ch != '/' || i == start); | |
| // | |
| // // | |
| // // Cases: | |
| // // /./ = remove this segment | |
| // // /../ = remove this segment, mark next for removal | |
| // // /....x = DO NOT TOUCH, leave as is | |
| // // x.../ = DO NOT TOUCH, leave as is, except for V2 legacy mode | |
| // // | |
| // if (!skipSegment && ch == '/') { | |
| // if ((lastSlash == i + dotCount + 1 // "/..../" | |
| // || (lastSlash == 0 && i + dotCount + 1 == destLength)) // "/..." | |
| // && (UriParser.ShouldUseLegacyV2Quirks || dotCount <= 2)) { | |
| // // | |
| // // /./ or /.<eos> or /../ or /..<eos> | |
| // // | |
| // // just reusing a variable slot we perform //dest.Remove(i+1, dotCount + (lastSlash==0?0:1)); | |
| // lastSlash = (ushort)(i + 1 + dotCount + (lastSlash==0?0:1)); | |
| // Buffer.BlockCopy(dest, lastSlash<<1, dest, (i+1)<<1, (destLength - lastSlash)<<1); | |
| // destLength -= (lastSlash-i-1); | |
| // | |
| // lastSlash = i; | |
| // if (dotCount == 2) { | |
| // // | |
| // // We have 2 dots in between like /../ or /..<eos>, | |
| // // Mark next segment for removal and remove this /../ or /.. | |
| // // | |
| // ++removeSegments; | |
| // } | |
| // dotCount = 0; | |
| // continue; | |
| // } | |
| // } | |
| // else if (UriParser.ShouldUseLegacyV2Quirks | |
| // && !skipSegment | |
| // && (removeSegments == 0) | |
| // && (lastSlash == i+dotCount+1 || (lastSlash == 0 && i+dotCount+1 == destLength))) { | |
| // // | |
| // // Note if removeSegments!=0, then ignore and remove the whole segment later | |
| // // | |
| // // x.../ or x...<eos> | |
| // // remove trailing dots | |
| // // | |
| // // | |
| // // just reusing a variable slot we perform //dest.Remove(i+1, dotCount); | |
| // dotCount = (ushort)(i + 1 + dotCount); | |
| // Buffer.BlockCopy(dest, dotCount<<1, dest, (i+1)<<1, (destLength - dotCount)<<1); | |
| // destLength -= (dotCount-i-1); | |
| // lastSlash = 0; //the other dots in this segment will stay intact | |
| // dotCount = 0; | |
| // continue; | |
| // } | |
| // // .NET 4.5 no longer removes trailing dots in a path segment x.../ or x...<eos> | |
| // dotCount = 0; | |
| // | |
| // // | |
| // // Here all other cases go such as | |
| // // x.[..]y or /.[..]x or (/x.[...][/] && removeSegments !=0) | |
| // } | |
| // | |
| // // | |
| // // Now we may want to remove a segment because of previous /../ | |
| // // | |
| // if (ch == '/') { | |
| // if (removeSegments != 0) { | |
| // --removeSegments; | |
| // | |
| // // just reusing a variable slot we perform //dest.Remove(i+1, lastSlash - i); | |
| // lastSlash = (ushort)(lastSlash + 1); | |
| // Buffer.BlockCopy(dest, lastSlash<<1, dest, (i+1)<<1, (destLength - lastSlash)<<1); | |
| // destLength -= (lastSlash-i-1); | |
| // } | |
| // lastSlash = i; | |
| // } | |
| // } | |
| // | |
| // start = (ushort)((ushort)start + (ushort)1); | |
| // } //end of unchecked | |
| // | |
| // // Dead Code? | |
| // if ((ushort)destLength > start && syntax.InFact(UriSyntaxFlags.CanonicalizeAsFilePath)) | |
| // { | |
| // if (slashCount > 1) { | |
| // /* | |
| // Buffer.BlockCopy(dest, lastSlash << 1, dest, start << 1, (destLength - lastSlash) << 1); | |
| // destLength -= (slashCount - 1); | |
| // */ | |
| // //QFE 4390 - Fall through for compat after not multiple slashes to a single slashl | |
| // } | |
| // else if (removeSegments != 0 && dest[start] != '/') { | |
| // //remove first not rooted segment | |
| // // dest.Remove(i+1, lastSlash - i); | |
| // lastSlash = (ushort)(lastSlash + 1); | |
| // Buffer.BlockCopy(dest, lastSlash<<1, dest, start<<1, (destLength - lastSlash)<<1); | |
| // destLength -= lastSlash; | |
| // } | |
| // else if (dotCount != 0) { | |
| // // If final string starts with a segment looking like .[...]/ or .[...]<eos> | |
| // // then we remove this fisrt segment | |
| // if (lastSlash == dotCount+1 || (lastSlash == 0 && dotCount + 1 == destLength)) { | |
| // //dest.Remove(0, dotCount + (lastSlash==0?0:1)); | |
| // dotCount = (ushort)(dotCount + (lastSlash==0?0:1)); | |
| // Buffer.BlockCopy(dest, dotCount<<1, dest, start<<1, (destLength - dotCount)<<1); | |
| // destLength -= dotCount; | |
| // } | |
| // } | |
| // } | |
| // return dest; | |
| // } | |
| // | |
| // //used by DigestClient | |
| // internal static readonly char[] HexLowerChars = { | |
| // '0', '1', '2', '3', '4', '5', '6', '7', | |
| // '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' | |
| // }; | |
| // | |
| // internal static int CalculateCaseInsensitiveHashCode(string text) | |
| // { | |
| // return StringComparer.InvariantCultureIgnoreCase.GetHashCode(text); | |
| // } | |
| // // | |
| // // CombineUri | |
| // // | |
| // // Given 2 URI strings, combine them into a single resultant URI string | |
| // // | |
| // // Inputs: | |
| // // <argument> basePart | |
| // // Base URI to combine with | |
| // // | |
| // // <argument> relativePart | |
| // // String expected to be relative URI | |
| // // | |
| // // Assumes: | |
| // // <basePart> is in canonic form | |
| // // | |
| // // Returns: | |
| // // Resulting combined URI string | |
| // // | |
| // private static string CombineUri(Uri basePart, string relativePart, UriFormat uriFormat) { | |
| // //NB: relativePart is ensured as not empty by the caller | |
| // // Another assumption is that basePart is an AbsoluteUri | |
| // | |
| // // This method was not optimized for efficiency | |
| // // Means a relative Uri ctor may be relatively slow plus it increases the footprint of the baseUri | |
| // | |
| // char c1 = relativePart[0]; | |
| // | |
| // #if !PLATFORM_UNIX | |
| // //check a special case for the base as DOS path and a rooted relative string | |
| // if ( basePart.IsDosPath && | |
| // (c1 == '/' || c1 == '\\') && | |
| // (relativePart.Length == 1 || (relativePart[1] != '/' && relativePart[1] != '\\'))) | |
| // { | |
| // // take relative part appended to the base string after the drive letter | |
| // int idx = basePart.OriginalString.IndexOf(':'); | |
| // if (basePart.IsImplicitFile) { | |
| // return basePart.OriginalString.Substring(0, idx+1 ) + relativePart; | |
| // } | |
| // // The basePart has explicit scheme (could be not file:), take the DOS drive ':' position | |
| // idx = basePart.OriginalString.IndexOf(':', idx+1); | |
| // return basePart.OriginalString.Substring(0, idx+1 ) + relativePart; | |
| // } | |
| // #endif // !PLATFORM_UNIX | |
| // | |
| // // Check special case for Unc or absolute path in relativePart when base is FILE | |
| // if (StaticIsFile(basePart.Syntax)) | |
| // { | |
| // | |
| // if (c1 == '\\' || c1 == '/') { | |
| // | |
| // if(relativePart.Length >= 2 && (relativePart[1] == '\\' || relativePart[1] == '/')) { | |
| // //Assuming relative is a Unc path and base is a file uri. | |
| // return basePart.IsImplicitFile? relativePart: "file:" + relativePart; | |
| // } | |
| // | |
| // // here we got an absolute path in relativePart, | |
| // // For compatibility with V1.0 parser we restrict the compression scope to Unc Share, i.e. \\host\share\ | |
| // if (basePart.IsUnc) { | |
| // string share = basePart.GetParts(UriComponents.Path | UriComponents.KeepDelimiter, | |
| // UriFormat.Unescaped); | |
| // for (int i = 1; i < share.Length; ++i) { | |
| // if (share[i] == '/') { | |
| // share = share.Substring(0, i); | |
| // break; | |
| // } | |
| // } | |
| // if (basePart.IsImplicitFile) { | |
| // return @"\\" | |
| // + basePart.GetParts(UriComponents.Host, UriFormat.Unescaped) | |
| // + share | |
| // + relativePart; | |
| // } | |
| // return "file://" | |
| // + basePart.GetParts(UriComponents.Host, uriFormat) | |
| // + share | |
| // + relativePart; | |
| // | |
| // } | |
| // // It's not obvious but we've checked (for this relativePart format) that baseUti is nor UNC nor DOS path | |
| // // | |
| // // Means base is a Unix style path and, btw, IsImplicitFile cannot be the case either | |
| // return "file://" + relativePart; | |
| // } | |
| // } | |
| // | |
| // // If we are here we did not recognize absolute DOS/UNC path for a file: base uri | |
| // // Note that DOS path may still happen in the relativePart and if so it may override the base uri scheme. | |
| // | |
| // bool convBackSlashes = basePart.Syntax.InFact(UriSyntaxFlags.ConvertPathSlashes); | |
| // | |
| // string left = null; | |
| // | |
| // // check for network or local absolute path | |
| // if (c1 == '/' || (c1 == '\\' && convBackSlashes)) { | |
| // if (relativePart.Length >= 2 && relativePart[1] == '/') { | |
| // // got an authority in relative path and the base scheme is not file (checked) | |
| // return basePart.Scheme + ':' + relativePart; | |
| // } | |
| // | |
| // // Got absolute relative path, and the base is nor FILE nor a DOS path (checked at the method start) | |
| // if (basePart.HostType == Flags.IPv6HostType) { | |
| // left = basePart.GetParts(UriComponents.Scheme|UriComponents.UserInfo, uriFormat) | |
| // + '[' + basePart.DnsSafeHost + ']' | |
| // + basePart.GetParts(UriComponents.KeepDelimiter|UriComponents.Port, uriFormat); | |
| // } | |
| // else { | |
| // left = basePart.GetParts(UriComponents.SchemeAndServer|UriComponents.UserInfo, uriFormat); | |
| // } | |
| // //VsWhidbey#241426 | |
| // if (convBackSlashes && c1 == '\\') | |
| // relativePart = '/' + relativePart.Substring(1); | |
| // | |
| // return left + relativePart; | |
| // } | |
| // | |
| // // Here we got a relative path | |
| // // Need to run path Compression because this is how relative Uri combining works | |
| // | |
| // // Take the base part path up to and including the last slash | |
| // left = basePart.GetParts(UriComponents.Path | UriComponents.KeepDelimiter, | |
| // basePart.IsImplicitFile ? UriFormat.Unescaped : uriFormat); | |
| // int length = left.Length; | |
| // char[] path = new char[length + relativePart.Length]; | |
| // | |
| // if (length > 0) { | |
| // left.CopyTo(0, path, 0, length); | |
| // while(length > 0) { | |
| // if (path[--length] == '/') { | |
| // ++length; | |
| // break; | |
| // } | |
| // } | |
| // } | |
| // | |
| // //Append relative path to the result | |
| // relativePart.CopyTo(0, path, length, relativePart.Length); | |
| // | |
| // // Split relative on path and extra (for compression) | |
| // c1 = basePart.Syntax.InFact(UriSyntaxFlags.MayHaveQuery)? '?': c_DummyChar; | |
| // | |
| // // The implcit file check is to avoid a fragment in the implicit file combined uri. | |
| // // The behavior change request is tracked vis VsWhidbey#261387 ans that was approved through VsWhidbey#266417. | |
| // char c2 = (!basePart.IsImplicitFile && basePart.Syntax.InFact(UriSyntaxFlags.MayHaveFragment)) ? '#' : | |
| // c_DummyChar; | |
| // string extra = String.Empty; | |
| // | |
| // // assuming c_DummyChar may not happen in an unicode uri string | |
| // if (!(c1 == c_DummyChar && c2 == c_DummyChar)) { | |
| // int i=0; | |
| // for (;i < relativePart.Length; ++i) { | |
| // if (path[length + i] == c1 || path[length + i] == c2) { | |
| // break; | |
| // } | |
| // } | |
| // if (i == 0) { | |
| // extra = relativePart; | |
| // } | |
| // else if (i < relativePart.Length) { | |
| // extra = relativePart.Substring(i); | |
| // } | |
| // length += i; | |
| // } | |
| // else { | |
| // length += relativePart.Length; | |
| // } | |
| // | |
| // // Take the base part up to the path | |
| // if (basePart.HostType == Flags.IPv6HostType) { | |
| // if (basePart.IsImplicitFile) { | |
| // left = @"\\[" + basePart.DnsSafeHost + ']'; | |
| // } | |
| // else { | |
| // left = basePart.GetParts(UriComponents.Scheme|UriComponents.UserInfo, uriFormat) | |
| // + '[' + basePart.DnsSafeHost + ']' | |
| // + basePart.GetParts(UriComponents.KeepDelimiter|UriComponents.Port, uriFormat); | |
| // } | |
| // } | |
| // else { | |
| // if (basePart.IsImplicitFile) { | |
| // #if !PLATFORM_UNIX | |
| // if (basePart.IsDosPath) { | |
| // // The FILE DOS path comes as /c:/path, we have to exclude first 3 chars from compression | |
| // path = Compress(path, 3, ref length, basePart.Syntax); | |
| // return new string(path, 1, length-1) + extra; | |
| // } | |
| // else { | |
| // left = @"\\" + basePart.GetParts(UriComponents.Host, UriFormat.Unescaped); | |
| // } | |
| // #else | |
| // left = basePart.GetParts(UriComponents.Host, UriFormat.Unescaped); | |
| // #endif // !PLATFORM_UNIX | |
| // | |
| // } | |
| // else { | |
| // left = basePart.GetParts(UriComponents.SchemeAndServer|UriComponents.UserInfo, uriFormat); | |
| // } | |
| // } | |
| // //compress the path | |
| // path = Compress(path, basePart.SecuredPathIndex, ref length, basePart.Syntax); | |
| // return left + new string(path, 0, length) + extra; | |
| // } | |
| // | |
| // // | |
| // // PathDifference | |
| // // | |
| // // Performs the relative path calculation for MakeRelative() | |
| // // | |
| // // Inputs: | |
| // // <argument> path1 | |
| // // <argument> path2 | |
| // // Paths for which we calculate the difference | |
| // // | |
| // // <argument> compareCase | |
| // // False if we consider characters that differ only in case to be | |
| // // equal | |
| // // | |
| // // Returns: | |
| // // A string which is the relative path difference between <path1> and | |
| // // <path2> such that if <path1> and the calculated difference are used | |
| // // as arguments to Combine(), <path2> is returned | |
| // // | |
| // // Throws: | |
| // // Nothing | |
| // // | |
| // private static string PathDifference(string path1, string path2, bool compareCase) { | |
| // | |
| // int i; | |
| // int si = -1; | |
| // | |
| // for (i = 0; (i < path1.Length) && (i < path2.Length); ++i) { | |
| // if ((path1[i] != path2[i]) | |
| // && (compareCase | |
| // || (Char.ToLower(path1[i], CultureInfo.InvariantCulture) | |
| // != Char.ToLower(path2[i], CultureInfo.InvariantCulture)))) | |
| // { | |
| // break; | |
| // | |
| // } else if (path1[i] == '/') { | |
| // si = i; | |
| // } | |
| // } | |
| // | |
| // if (i == 0) { | |
| // return path2; | |
| // } | |
| // if ((i == path1.Length) && (i == path2.Length)) { | |
| // return String.Empty; | |
| // } | |
| // | |
| // StringBuilder relPath = new StringBuilder(); | |
| // // Walk down several dirs | |
| // for (; i < path1.Length; ++i) { | |
| // if (path1[i] == '/') { | |
| // relPath.Append("../"); | |
| // } | |
| // } | |
| // // Same path except that path1 ended with a file name and path2 didn't | |
| // if (relPath.Length == 0 && path2.Length - 1 == si) | |
| // return "./"; // Truncate the file name | |
| // return relPath.ToString() + path2.Substring(si + 1); | |
| // } | |
| // | |
| // //Used by Uribuilder | |
| // internal bool HasAuthority { | |
| // get { | |
| // return InFact(Flags.AuthorityFound); | |
| // } | |
| // } | |
| // | |
| // private static readonly char[] _WSchars = new char[] {' ', '\n', '\r', '\t'}; | |
| // private static bool IsLWS(char ch) { | |
| // | |
| // return (ch <= ' ') && (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'); | |
| // } | |
| // | |
| // //Only consider ASCII characters | |
| // private static bool IsAsciiLetter(char character) { | |
| // | |
| // return (character >= 'a' && character <= 'z') || | |
| // (character >= 'A' && character <= 'Z'); | |
| // } | |
| // | |
| // internal static bool IsAsciiLetterOrDigit(char character) { | |
| // return IsAsciiLetter(character) || (character >= '0' && character <= '9'); | |
| // } | |
| // | |
| // // | |
| // // Is this a Bidirectional control char.. These get stripped | |
| // // | |
| // internal static bool IsBidiControlCharacter(char ch) | |
| // { | |
| // return (ch == '\u200E' /*LRM*/ || ch == '\u200F' /*RLM*/ || ch == '\u202A' /*LRE*/ || | |
| // ch == '\u202B' /*RLE*/ || ch == '\u202C' /*PDF*/ || ch == '\u202D' /*LRO*/ || | |
| // ch == '\u202E' /*RLO*/); | |
| // } | |
| // | |
| // // | |
| // // Strip Bidirectional control charcters from this string | |
| // // | |
| // internal static unsafe string StripBidiControlCharacter(char* strToClean, int start, int length) | |
| // { | |
| // if (length <= 0) return ""; | |
| // | |
| // char [] cleanStr = new char[length]; | |
| // int count = 0; | |
| // for (int i = 0; i < length; ++i){ | |
| // char c = strToClean[start + i]; | |
| // if (c < '\u200E' || c > '\u202E' || !IsBidiControlCharacter(c)){ | |
| // cleanStr[count++] = c; | |
| // } | |
| // } | |
| // return new string(cleanStr, 0, count); | |
| // } | |
| // | |
| // // | |
| // // MakeRelative (toUri) | |
| // // | |
| // // Return a relative path which when applied to this Uri would create the | |
| // // resulting Uri <toUri> | |
| // // | |
| // // Inputs: | |
| // // <argument> toUri | |
| // // Uri to which we calculate the transformation from this Uri | |
| // // | |
| // // Returns: | |
| // // If the 2 Uri are common except for a relative path difference, then that | |
| // // difference, else the display name of this Uri | |
| // // | |
| // // Throws: | |
| // // ArgumentNullException, InvalidOperationException | |
| // // | |
| // [Obsolete("The method has been deprecated. Please use MakeRelativeUri(Uri uri). http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // public string MakeRelative(Uri toUri) | |
| // { | |
| // if ((object)toUri == null) | |
| // throw new ArgumentNullException("toUri"); | |
| // | |
| // if (IsNotAbsoluteUri || toUri.IsNotAbsoluteUri) | |
| // throw new InvalidOperationException(SR.GetString(SR.net_uri_NotAbsolute)); | |
| // | |
| // if ((Scheme == toUri.Scheme) && (Host == toUri.Host) && (Port == toUri.Port)) | |
| // return PathDifference(AbsolutePath, toUri.AbsolutePath, !IsUncOrDosPath); | |
| // | |
| // return toUri.ToString(); | |
| // } | |
| // | |
| // /// <internalonly/> | |
| // [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // protected virtual void Parse() | |
| // { | |
| // // Microsoft cr: In V1-Everett this method if suppressed by the derived class | |
| // // would lead to an unconstructed Uri instance. | |
| // // It does not make any sense and violates Fxcop on calling a virtual method in the ctor. | |
| // // Should be deprecated and removed asap. | |
| // } | |
| // /// <internalonly/> | |
| // [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // protected virtual void Canonicalize() | |
| // { | |
| // // Microsoft cr: In V1-Everett this method if suppressed by the derived class | |
| // // would lead to supressing of a path compression | |
| // // It does not make much sense and violates Fxcop on calling a virtual method in the ctor. | |
| // // Should be deprecated and removed asap. | |
| // } | |
| // /// <internalonly/> | |
| // [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // protected virtual void Escape() | |
| // { | |
| // // Microsoft cr: In V1-Everett this method if suppressed by the derived class | |
| // // would lead to the same effect as dontEscape=true. | |
| // // It does not make much sense and violates Fxcop on calling a virtual method in the ctor. | |
| // // Should be deprecated and removed asap. | |
| // } | |
| // // | |
| // // Unescape | |
| // // | |
| // // Convert any escape sequences in <path>. Escape sequences can be | |
| // // hex encoded reserved characters (e.g. %40 == '@') or hex encoded | |
| // // UTF-8 sequences (e.g. %C4%D2 == 'Latin capital Ligature Ij') | |
| // // | |
| // /// <internalonly/> | |
| // [Obsolete("The method has been deprecated. Please use GetComponents() or static UnescapeDataString() to unescape a Uri component or a string. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // protected virtual string Unescape(string path) { | |
| // | |
| // // Microsoft cr: This method is dangerous since it gives path unescaping control | |
| // // to the derived class without any permission demand. | |
| // // Should be deprecated and removed asap. | |
| // | |
| // char[] dest = new char[path.Length]; | |
| // int count = 0; | |
| // dest = UriHelper.UnescapeString(path, 0, path.Length, dest, ref count, c_DummyChar, c_DummyChar, | |
| // c_DummyChar, UnescapeMode.Unescape | UnescapeMode.UnescapeAll, null, false); | |
| // return new string(dest, 0, count); | |
| // } | |
| // | |
| // [Obsolete("The method has been deprecated. Please use GetComponents() or static EscapeUriString() to escape a Uri component or a string. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // protected static string EscapeString(string str) { | |
| // | |
| // // Microsoft cr: This method just does not make sense sa protected | |
| // // It should go public static asap | |
| // | |
| // if ((object)str == null) { | |
| // return string.Empty; | |
| // } | |
| // | |
| // int destStart = 0; | |
| // char[] dest = UriHelper.EscapeString(str, 0, str.Length, null, ref destStart, true, '?', '#', '%'); | |
| // if ((object)dest == null) | |
| // return str; | |
| // return new string(dest, 0, destStart); | |
| // } | |
| // | |
| // // | |
| // // CheckSecurity | |
| // // | |
| // // Check for any invalid or problematic character sequences | |
| // // | |
| // /// <internalonly/> | |
| // [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // protected virtual void CheckSecurity() { | |
| // | |
| // // Microsoft cr: This method just does not make sense | |
| // // Should be deprecated and removed asap. | |
| // | |
| // if (Scheme == "telnet") { | |
| // | |
| // // | |
| // // remove everything after ';' for telnet | |
| // // | |
| // | |
| // } | |
| // } | |
| // | |
| // // | |
| // // IsReservedCharacter | |
| // // | |
| // // Determine whether a character is part of the reserved set | |
| // // | |
| // // Returns: | |
| // // true if <character> is reserved else false | |
| // // | |
| // /// <internalonly/> | |
| // [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // protected virtual bool IsReservedCharacter(char character) { | |
| // | |
| // // Microsoft cr: This method just does not make sense as virtual protected | |
| // // It should go public static asap | |
| // | |
| // return (character == ';') | |
| // || (character == '/') | |
| // || (character == ':') | |
| // || (character == '@') // OK FS char | |
| // || (character == '&') | |
| // || (character == '=') | |
| // || (character == '+') // OK FS char | |
| // || (character == '$') // OK FS char | |
| // || (character == ',') | |
| // ; | |
| // } | |
| // | |
| // // | |
| // // IsExcludedCharacter | |
| // // | |
| // // Determine if a character should be exluded from a URI and therefore be | |
| // // escaped | |
| // // | |
| // // Returns: | |
| // // true if <character> should be escaped else false | |
| // // | |
| // /// <internalonly/> | |
| // [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // protected static bool IsExcludedCharacter(char character) { | |
| // | |
| // // Microsoft cr: This method just does not make sense sa protected | |
| // // It should go public static asap | |
| // | |
| // // | |
| // // the excluded characters... | |
| // // | |
| // | |
| // return (character <= 0x20) | |
| // || (character >= 0x7f) | |
| // || (character == '<') | |
| // || (character == '>') | |
| // || (character == '#') | |
| // || (character == '%') | |
| // || (character == '"') | |
| // | |
| // // | |
| // // the 'unwise' characters... | |
| // // | |
| // | |
| // || (character == '{') | |
| // || (character == '}') | |
| // || (character == '|') | |
| // || (character == '\\') | |
| // || (character == '^') | |
| // || (character == '[') | |
| // || (character == ']') | |
| // || (character == '`') | |
| // ; | |
| // } | |
| // | |
| // // | |
| // // IsBadFileSystemCharacter | |
| // // | |
| // // Determine whether a character would be an invalid character if used in | |
| // // a file system name. Note, this is really based on NTFS rules | |
| // // | |
| // // Returns: | |
| // // true if <character> would be a treated as a bad file system character | |
| // // else false | |
| // // | |
| // [Obsolete("The method has been deprecated. It is not used by the system. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| // protected virtual bool IsBadFileSystemCharacter(char character) { | |
| // | |
| // // Microsoft cr: This method just does not make sense sa protected virtual | |
| // // It should go public static asap | |
| // | |
| // return (character < 0x20) | |
| // || (character == ';') | |
| // || (character == '/') | |
| // || (character == '?') | |
| // || (character == ':') | |
| // || (character == '&') | |
| // || (character == '=') | |
| // || (character == ',') | |
| // || (character == '*') | |
| // || (character == '<') | |
| // || (character == '>') | |
| // || (character == '"') | |
| // || (character == '|') | |
| // || (character == '\\') | |
| // || (character == '^') | |
| // ; | |
| // } | |
| // | |
| // | |
| // } // class Uri | |
| // } // namespace System | |
| // |