// //------------------------------------------------------------------------------ | |
// // <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 | |
// |