273 lines
8.7 KiB
C#
273 lines
8.7 KiB
C#
// /**
|
|
// * File: URI.cs
|
|
// * Author: haraldwolff
|
|
// *
|
|
// * This file and it's content is copyrighted by the Author and / or copyright holder.
|
|
// * Any use wihtout proper permission is illegal and may lead to legal actions.
|
|
// *
|
|
// *
|
|
// **/
|
|
using System;
|
|
using System.Reflection.Metadata;
|
|
using System.Text;
|
|
namespace ln.type
|
|
{
|
|
/**
|
|
* Quick and Dirty RFC3986 URI
|
|
*
|
|
**/
|
|
|
|
public class URI
|
|
{
|
|
public String Scheme { get; private set; } = String.Empty;
|
|
public String Authority { get; private set; } = String.Empty;
|
|
|
|
public String[] UserInfo { get; private set; } = new String[0];
|
|
public String Host { get; private set; } = String.Empty;
|
|
public String Port { get; private set; } = String.Empty;
|
|
|
|
public String Path { get; private set; } = String.Empty;
|
|
public String Query { get; private set; } = String.Empty;
|
|
public String Fragment { get; private set; } = String.Empty;
|
|
|
|
private URI()
|
|
{
|
|
}
|
|
|
|
public URI(String uri)
|
|
{
|
|
Parse(uri);
|
|
ParseAuthority();
|
|
}
|
|
public URI(String scheme, String authority, string path)
|
|
{
|
|
Parse(String.Format("{0}://{1}{2}", scheme, authority, path));
|
|
ParseAuthority();
|
|
}
|
|
public URI(String scheme,string[] userinfo,string host,string port,string path,string query,string fragment)
|
|
{
|
|
Scheme = scheme;
|
|
UserInfo = userinfo ?? new string[0];
|
|
Host = host;
|
|
Port = port;
|
|
if (userinfo.Length == 0)
|
|
Authority = String.Format("{0}:{1}", Host, Port);
|
|
else
|
|
Authority = String.Format("{2}@{0}:{1}", Host, Port, string.Join(':', UserInfo));
|
|
Path = path;
|
|
Query = query;
|
|
Fragment = fragment;
|
|
}
|
|
public URI(String scheme,String authority,string path,string query,string fragment)
|
|
{
|
|
Scheme = scheme;
|
|
Authority = authority;
|
|
Path = path;
|
|
Query = query;
|
|
Fragment = fragment;
|
|
ParseAuthority();
|
|
}
|
|
|
|
public URI(URI uri, string path)
|
|
{
|
|
Parse(String.Format("{0}://{1}{2}", uri.Scheme, uri.Authority, path));
|
|
ParseAuthority();
|
|
}
|
|
|
|
public URI Follow(String path)
|
|
{
|
|
if (path.StartsWith("/",StringComparison.InvariantCulture))
|
|
{
|
|
return new URI(Scheme, Authority, path);
|
|
} else if (Path.EndsWith("/",StringComparison.InvariantCulture) || path.StartsWith("?",StringComparison.InvariantCulture) || path.StartsWith("#", StringComparison.InvariantCulture))
|
|
{
|
|
return new URI(Scheme, Authority, String.Format("{0}{1}", Path, path));
|
|
}
|
|
else
|
|
{
|
|
int indSlash = Path.LastIndexOf('/');
|
|
return new URI(Scheme, Authority, String.Format("{0}/{1}",Path.Substring(0,indSlash),path));
|
|
}
|
|
}
|
|
|
|
public URI WithUserInfo(params string[] userInfo) => new URI(Scheme,userInfo, Host, Port, Path, Query, Fragment);
|
|
public URI WithHost(string host) => new URI(Scheme,UserInfo, host, Port, Path, Query, Fragment);
|
|
public URI WithPort(string port) => new URI(Scheme,UserInfo, Host, port, Path, Query, Fragment);
|
|
public URI WithScheme(string scheme) => new URI(scheme, UserInfo, Host, Port, Path, Query, Fragment);
|
|
public URI WithPath(string path) => new URI(Scheme, UserInfo, Host, Port, path, Query, Fragment);
|
|
public URI WithQuery(string query) => new URI(Scheme, UserInfo, Host, Port, Path, query, Fragment);
|
|
public URI WithFragment(string fragment) => new URI(Scheme, UserInfo, Host, Port, Path, Query, fragment);
|
|
|
|
private void Parse(String uri)
|
|
{
|
|
char[] chUri = uri.ToCharArray();
|
|
int n = 0;
|
|
int m = 0;
|
|
|
|
// Scheme
|
|
|
|
while ((chUri[n] != ':') && ((++n) < chUri.Length)) { };
|
|
|
|
if (n < 2)
|
|
throw new FormatException(String.Format("URL malformed: {0}",uri));
|
|
|
|
Scheme = new string(chUri, 0, n);
|
|
n++;
|
|
|
|
if (n < chUri.Length)
|
|
{
|
|
if ((chUri.Length - n > 1) && (chUri[n] == '/') && (chUri[n+1] == '/'))
|
|
{
|
|
// Authority
|
|
n += 2;
|
|
m = n;
|
|
|
|
while (
|
|
(m < chUri.Length) &&
|
|
(chUri[m] != '/') &&
|
|
(chUri[m] != '?') &&
|
|
(chUri[m] != '#')
|
|
) { m++; }
|
|
|
|
Authority = new string(chUri, n, (m - n));
|
|
n = m;
|
|
}
|
|
|
|
// Path
|
|
m = n;
|
|
while (
|
|
(m < chUri.Length) &&
|
|
(chUri[m] != '?') &&
|
|
(chUri[m] != '#')
|
|
)
|
|
{ m++; }
|
|
|
|
Path = new string(chUri, n, (m - n));
|
|
n = m;
|
|
|
|
if (n < chUri.Length)
|
|
{
|
|
if (chUri[n] == '?')
|
|
{
|
|
n++;
|
|
m = n;
|
|
while (
|
|
(m < chUri.Length) &&
|
|
(chUri[m] != '#')
|
|
)
|
|
{ m++; }
|
|
|
|
Query = new string(chUri, n, (m - n));
|
|
n = m;
|
|
}
|
|
if ((n<chUri.Length) && (chUri[n] == '#'))
|
|
{
|
|
n++;
|
|
m = n;
|
|
while (
|
|
(m < chUri.Length) &&
|
|
(chUri[m] != '#')
|
|
)
|
|
{ m++; }
|
|
|
|
Fragment = new string(chUri, n, (m - n));
|
|
n = m;
|
|
}
|
|
|
|
if (n < chUri.Length)
|
|
throw new FormatException(String.Format("Malformed URI: {0}", uri));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ParseAuthority()
|
|
{
|
|
int indAt = Authority.IndexOf('@');
|
|
if (indAt != -1)
|
|
{
|
|
UserInfo = Authority.Substring(0, indAt).Split(':');
|
|
}
|
|
indAt++;
|
|
|
|
int indPort = Authority.IndexOf(':', indAt);
|
|
|
|
if (indPort != -1)
|
|
{
|
|
Host = Authority.Substring(indAt, indPort - indAt);
|
|
Port = Authority.Substring(indPort + 1);
|
|
}
|
|
else
|
|
{
|
|
Host = Authority.Substring(indAt);
|
|
}
|
|
}
|
|
|
|
|
|
public override string ToString() => ToString(false);
|
|
public string ToString(bool withFullUserInfo)
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
|
|
stringBuilder.Append(Scheme);
|
|
stringBuilder.Append(':');
|
|
|
|
if (!String.Empty.Equals(Authority))
|
|
{
|
|
stringBuilder.Append("//");
|
|
if (UserInfo.Length > 0)
|
|
{
|
|
if (withFullUserInfo)
|
|
stringBuilder.Append(String.Join(':',UserInfo));
|
|
else
|
|
stringBuilder.Append(UserInfo[0]);
|
|
stringBuilder.Append('@');
|
|
}
|
|
|
|
stringBuilder.Append(Host);
|
|
|
|
if (!String.Empty.Equals(Port))
|
|
{
|
|
stringBuilder.Append(':');
|
|
stringBuilder.Append(Port);
|
|
}
|
|
}
|
|
|
|
stringBuilder.Append(Path);
|
|
|
|
if (!string.Empty.Equals(Query))
|
|
{
|
|
stringBuilder.Append("?");
|
|
stringBuilder.Append(Query);
|
|
}
|
|
if (!string.Empty.Equals(Fragment))
|
|
{
|
|
stringBuilder.Append('#');
|
|
stringBuilder.Append(Fragment);
|
|
}
|
|
|
|
return stringBuilder.ToString();
|
|
}
|
|
|
|
private int GetHashCode(String s)
|
|
{
|
|
return (s == null) ? -1 : s.GetHashCode();
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return GetHashCode(Scheme) ^ GetHashCode(Authority) ^ GetHashCode(Path) ^ GetHashCode(Query) ^ GetHashCode(Fragment);
|
|
}
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (obj is URI)
|
|
{
|
|
URI other = obj as URI;
|
|
return Scheme.Equals(other.Scheme) && Authority.Equals(other.Authority) && Path.Equals(other.Path) && Query.Equals(other.Query) && Fragment.Equals(other.Fragment);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
}
|
|
}
|