Files
linux-packaging-mono/mcs/class/System/System/UriParser.cs
Jo Shields 181b81b4a4 Imported Upstream version 3.12.0
Former-commit-id: cf92446697332992ec36726e78eb8703e1f259d7
2015-01-13 10:44:36 +00:00

360 lines
12 KiB
C#

//
// System.UriParser abstract class
//
// Author:
// Sebastien Pouliot <sebastien@ximian.com>
//
// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.Collections;
using System.Globalization;
using System.Security.Permissions;
using System.Text;
namespace System {
public abstract class UriParser {
static object lock_object = new object ();
static Hashtable table;
internal string scheme_name;
private int default_port;
protected UriParser ()
{
}
// protected methods
protected internal virtual string GetComponents (Uri uri, UriComponents components, UriFormat format)
{
if ((format < UriFormat.UriEscaped) || (format > UriFormat.SafeUnescaped))
throw new ArgumentOutOfRangeException ("format");
if ((components & UriComponents.SerializationInfoString) != 0) {
if (components != UriComponents.SerializationInfoString)
throw new ArgumentOutOfRangeException ("components", "UriComponents.SerializationInfoString must not be combined with other UriComponents.");
if (!uri.IsAbsoluteUri)
return UriHelper.FormatRelative (uri.OriginalString, "", format);
components |= UriComponents.AbsoluteUri;
}
return GetComponentsHelper (uri, components, format);
}
internal string GetComponentsHelper (Uri uri, UriComponents components, UriFormat format)
{
UriElements elements = UriParseComponents.ParseComponents (uri.OriginalString.Trim (), UriKind.Absolute);
string scheme = scheme_name;
int dp = default_port;
if ((scheme == null) || (scheme == "*")) {
scheme = elements.scheme;
dp = Uri.GetDefaultPort (scheme);
} else if (String.Compare (scheme, elements.scheme, true) != 0) {
throw new SystemException ("URI Parser: scheme mismatch: " + scheme + " vs. " + elements.scheme);
}
var formatFlags = UriHelper.FormatFlags.None;
if (UriHelper.HasCharactersToNormalize (uri.OriginalString))
formatFlags |= UriHelper.FormatFlags.HasUriCharactersToNormalize;
if (uri.UserEscaped)
formatFlags |= UriHelper.FormatFlags.UserEscaped;
if (!string.IsNullOrEmpty (elements.host))
formatFlags |= UriHelper.FormatFlags.HasHost;
// it's easier to answer some case directly (as the output isn't identical
// when mixed with others components, e.g. leading slash, # ...)
switch (components) {
case UriComponents.Scheme:
return scheme;
case UriComponents.UserInfo:
return elements.user ?? "";
case UriComponents.Host:
return elements.host;
case UriComponents.Port: {
int p = elements.port;
if (p >= 0 && p != dp)
return p.ToString (CultureInfo.InvariantCulture);
return String.Empty;
}
case UriComponents.Path:
var path = elements.path;
if (scheme != Uri.UriSchemeMailto && scheme != Uri.UriSchemeNews)
path = IgnoreFirstCharIf (elements.path, '/');
return UriHelper.FormatAbsolute (path, scheme, UriComponents.Path, format, formatFlags);
case UriComponents.Query:
return UriHelper.FormatAbsolute (elements.query, scheme, UriComponents.Query, format, formatFlags);
case UriComponents.Fragment:
return UriHelper.FormatAbsolute (elements.fragment, scheme, UriComponents.Fragment, format, formatFlags);
case UriComponents.StrongPort: {
return elements.port >= 0
? elements.port.ToString (CultureInfo.InvariantCulture)
: dp.ToString (CultureInfo.InvariantCulture);
}
case UriComponents.SerializationInfoString:
components = UriComponents.AbsoluteUri;
break;
}
// now we deal with multiple flags...
StringBuilder sb = new StringBuilder ();
if ((components & UriComponents.Scheme) != 0) {
sb.Append (scheme);
sb.Append (elements.delimiter);
}
if ((components & UriComponents.UserInfo) != 0) {
string userinfo = elements.user;
if (userinfo != null) {
sb.Append (elements.user);
sb.Append ('@');
}
}
if ((components & UriComponents.Host) != 0)
sb.Append (elements.host);
// for StrongPort always show port - even if -1
// otherwise only display if ut's not the default port
if ((components & UriComponents.StrongPort) != 0) {
sb.Append (":");
if (elements.port >= 0) {
sb.Append (elements.port);
} else {
sb.Append (dp);
}
}
if ((components & UriComponents.Port) != 0) {
int p = elements.port;
if (p >= 0 && p != dp) {
sb.Append (":");
sb.Append (elements.port);
}
}
if ((components & UriComponents.Path) != 0) {
string path = elements.path;
if ((components & UriComponents.PathAndQuery) != 0 &&
(path.Length == 0 || !path.StartsWith ("/", StringComparison.Ordinal)) &&
elements.delimiter == Uri.SchemeDelimiter)
sb.Append ("/");
sb.Append (UriHelper.FormatAbsolute (path, scheme, UriComponents.Path, format, formatFlags));
}
if ((components & UriComponents.Query) != 0) {
string query = elements.query;
if (query != null) {
sb.Append ("?");
sb.Append (UriHelper.FormatAbsolute (query, scheme, UriComponents.Query, format, formatFlags));
}
}
if ((components & UriComponents.Fragment) != 0) {
string f = elements.fragment;
if (f != null) {
sb.Append ("#");
sb.Append (UriHelper.FormatAbsolute (f, scheme, UriComponents.Fragment, format, formatFlags));
}
}
return sb.ToString ();
}
protected internal virtual void InitializeAndValidate (Uri uri, out UriFormatException parsingError)
{
// bad boy, it should check null arguments.
if ((uri.Scheme != scheme_name) && (scheme_name != "*"))
// Here .NET seems to return "The Authority/Host could not be parsed", but it does not make sense.
parsingError = new UriFormatException ("The argument Uri's scheme does not match");
else
parsingError = null;
}
protected internal virtual bool IsBaseOf (Uri baseUri, Uri relativeUri)
{
if (baseUri == null)
throw new ArgumentNullException ("baseUri");
if (relativeUri == null)
throw new ArgumentNullException ("relativeUri");
// compare, not case sensitive, the scheme, host and port (+ user informations)
if (Uri.Compare (baseUri, relativeUri, UriComponents.SchemeAndServer | UriComponents.UserInfo, UriFormat.Unescaped, StringComparison.InvariantCultureIgnoreCase) != 0)
return false;
string base_string = baseUri.LocalPath;
int last_slash = base_string.LastIndexOf ('/') + 1; // keep the slash
return (String.Compare (base_string, 0, relativeUri.LocalPath, 0, last_slash, StringComparison.InvariantCultureIgnoreCase) == 0);
}
protected internal virtual bool IsWellFormedOriginalString (Uri uri)
{
// well formed according to RFC2396 and RFC2732
// see Uri.IsWellFormedOriginalString for some docs
// Though this class does not seem to do anything. Even null arguments aren't checked :/
return uri.IsWellFormedOriginalString ();
}
protected internal virtual UriParser OnNewUri ()
{
// nice time for init
return this;
}
[MonoTODO]
protected virtual void OnRegister (string schemeName, int defaultPort)
{
// unit tests shows that schemeName and defaultPort aren't usable from here
}
[MonoTODO]
protected internal virtual string Resolve (Uri baseUri, Uri relativeUri, out UriFormatException parsingError)
{
// used by Uri.ctor and Uri.TryCreate
throw new NotImplementedException ();
}
// internal properties
internal string SchemeName {
get { return scheme_name; }
set { scheme_name = value; }
}
internal int DefaultPort {
get { return default_port; }
set { default_port = value; }
}
// private stuff
private string IgnoreFirstCharIf (string s, char c)
{
if (s.Length == 0)
return String.Empty;
if (s[0] == c)
return s.Substring (1);
return s;
}
// static methods
private static void CreateDefaults ()
{
if (table != null)
return;
Hashtable newtable = new Hashtable ();
InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeFile, -1);
InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeFtp, 21);
InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeGopher, 70);
InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeHttp, 80);
InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeHttps, 443);
InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeMailto, 25);
InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeNetPipe, -1);
InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeNetTcp, -1);
InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeNews, -1);
InternalRegister (newtable, new DefaultUriParser (), Uri.UriSchemeNntp, 119);
// not defined in Uri.UriScheme* but a parser class exists
InternalRegister (newtable, new DefaultUriParser (), "ldap", 389);
lock (lock_object) {
if (table == null)
table = newtable;
else
newtable = null;
}
}
public static bool IsKnownScheme (string schemeName)
{
if (schemeName == null)
throw new ArgumentNullException ("schemeName");
if (schemeName.Length == 0)
throw new ArgumentOutOfRangeException ("schemeName");
CreateDefaults ();
string lc = schemeName.ToLower (CultureInfo.InvariantCulture);
return (table [lc] != null);
}
// *no* check version
private static void InternalRegister (Hashtable table, UriParser uriParser, string schemeName, int defaultPort)
{
uriParser.SchemeName = schemeName;
uriParser.DefaultPort = defaultPort;
// FIXME: MS doesn't seems to call most inherited parsers
if (uriParser is GenericUriParser) {
table.Add (schemeName, uriParser);
} else {
DefaultUriParser parser = new DefaultUriParser ();
parser.SchemeName = schemeName;
parser.DefaultPort = defaultPort;
table.Add (schemeName, parser);
}
// note: we cannot set schemeName and defaultPort inside OnRegister
uriParser.OnRegister (schemeName, defaultPort);
}
[SecurityPermission (SecurityAction.Demand, Infrastructure = true)]
public static void Register (UriParser uriParser, string schemeName, int defaultPort)
{
if (uriParser == null)
throw new ArgumentNullException ("uriParser");
if (schemeName == null)
throw new ArgumentNullException ("schemeName");
if ((defaultPort < -1) || (defaultPort >= UInt16.MaxValue))
throw new ArgumentOutOfRangeException ("defaultPort");
CreateDefaults ();
string lc = schemeName.ToLower (CultureInfo.InvariantCulture);
if (table [lc] != null) {
string msg = Locale.GetText ("Scheme '{0}' is already registred.");
throw new InvalidOperationException (msg);
}
InternalRegister (table, uriParser, lc, defaultPort);
}
internal static UriParser GetParser (string schemeName)
{
if (schemeName == null)
return null;
CreateDefaults ();
string lc = schemeName.ToLower (CultureInfo.InvariantCulture);
return (UriParser) table [lc];
}
}
}