Merge pull request #6427 from duplicati/feature/update-uri-encode
Dots in url hostname
This commit is contained in:
@@ -24,6 +24,8 @@ using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Duplicati.Library.Utility
|
||||
{
|
||||
// TODO: This class should be deleted.
|
||||
@@ -48,6 +50,11 @@ namespace Duplicati.Library.Utility
|
||||
/// </summary>
|
||||
private static readonly System.Text.RegularExpressions.Regex URL_PARSER = new System.Text.RegularExpressions.Regex(@"(?<scheme>[^:]+)://(((?<username>[^\:\?/]+)(\:(?<password>[^@\:\?/]*))?\@))?((?<hostname>(?:[^\[/\?\:][^/\?\:]*)|(?:\[[^\]]+\]))(\:(?<port>\d+))?)?((?<path>[^\?]*))?(\?(?<query>.+))?");
|
||||
|
||||
/// <summary>
|
||||
/// Detects a Windows path
|
||||
/// </summary>
|
||||
private static readonly System.Text.RegularExpressions.Regex WINDOWS_PATH = new System.Text.RegularExpressions.Regex(@"^/?[a-zA-Z]:[\\/]");
|
||||
|
||||
/// <summary>
|
||||
/// The URL scheme, e.g. http
|
||||
/// </summary>
|
||||
@@ -55,12 +62,12 @@ namespace Duplicati.Library.Utility
|
||||
/// <summary>
|
||||
/// The server name, e.g. www.example.com
|
||||
/// </summary>
|
||||
public readonly string Host;
|
||||
public readonly string? Host;
|
||||
/// <summary>
|
||||
/// The server path, e.g. index.html.
|
||||
/// Note that the path does NOT have a leading /.
|
||||
/// </summary>
|
||||
public readonly string Path;
|
||||
public readonly string? Path;
|
||||
/// <summary>
|
||||
/// The server port, e.g. 80, is -1 if using the default port
|
||||
/// </summary>
|
||||
@@ -68,15 +75,15 @@ namespace Duplicati.Library.Utility
|
||||
/// <summary>
|
||||
/// The querystring, e.g. ?id=1
|
||||
/// </summary>
|
||||
public readonly string Query;
|
||||
public readonly string? Query;
|
||||
/// <summary>
|
||||
/// The username, if any
|
||||
/// </summary>
|
||||
public readonly string Username;
|
||||
public readonly string? Username;
|
||||
/// <summary>
|
||||
/// The password, if any
|
||||
/// </summary>
|
||||
public readonly string Password;
|
||||
public readonly string? Password;
|
||||
|
||||
/// <summary>
|
||||
/// The original URI.
|
||||
@@ -86,7 +93,7 @@ namespace Duplicati.Library.Utility
|
||||
/// <summary>
|
||||
/// Cache for the query parameters.
|
||||
/// </summary>
|
||||
private NameValueCollection m_queryParams;
|
||||
private NameValueCollection? m_queryParams;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameters in the query string
|
||||
@@ -117,7 +124,7 @@ namespace Duplicati.Library.Utility
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(Path))
|
||||
return Host;
|
||||
return Host ?? "";
|
||||
else if (string.IsNullOrEmpty(Host))
|
||||
return Path;
|
||||
else
|
||||
@@ -194,6 +201,10 @@ namespace Duplicati.Library.Utility
|
||||
h = null;
|
||||
}
|
||||
|
||||
// Support correctly encoded file:///C:\test
|
||||
if ((h == null || h.Length == 0) && Scheme == "file" && WINDOWS_PATH.IsMatch(p) && p.StartsWith("/", StringComparison.Ordinal))
|
||||
p = p.Substring(1);
|
||||
|
||||
this.Host = h;
|
||||
this.Path = p;
|
||||
|
||||
@@ -216,7 +227,7 @@ namespace Duplicati.Library.Utility
|
||||
/// <param name="username">The username</param>
|
||||
/// <param name="password">The password</param>
|
||||
/// <param name="port">The port</param>
|
||||
public Uri(string scheme, string host, string path = null, string query = null, string username = null, string password = null, int port = -1)
|
||||
public Uri(string scheme, string? host, string? path = null, string? query = null, string? username = null, string? password = null, int port = -1)
|
||||
{
|
||||
m_queryParams = null;
|
||||
Scheme = scheme;
|
||||
@@ -258,7 +269,7 @@ namespace Duplicati.Library.Utility
|
||||
/// <param name="username">The username</param>
|
||||
/// <param name="password">The password</param>
|
||||
/// <param name="port">The port</param>
|
||||
private static string AsString(string scheme, string host, string path, string query, string username, string password, int port)
|
||||
private static string AsString(string scheme, string? host, string? path, string? query, string? username, string? password, int port)
|
||||
{
|
||||
var s = scheme + "://";
|
||||
if (!string.IsNullOrEmpty(username) || !string.IsNullOrEmpty(password))
|
||||
@@ -279,8 +290,10 @@ namespace Duplicati.Library.Utility
|
||||
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(host))
|
||||
// Append the leading `/` to the Windows path for file:///c:\test
|
||||
if (!string.IsNullOrEmpty(host) || (WINDOWS_PATH.IsMatch(path) && !path.StartsWith("/")))
|
||||
s += "/";
|
||||
|
||||
s += string.Join('/', path.Split('/').Select(x => UrlPathEncode(x)));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(query))
|
||||
@@ -353,7 +366,7 @@ namespace Duplicati.Library.Utility
|
||||
/// <summary>
|
||||
/// The regular expression that matches %20 type values in a querystring
|
||||
/// </summary>
|
||||
private static readonly System.Text.RegularExpressions.Regex RE_ESCAPECHAR = new System.Text.RegularExpressions.Regex(@"[^0-9a-zA-Z\-_]", System.Text.RegularExpressions.RegexOptions.Compiled);
|
||||
private static readonly System.Text.RegularExpressions.Regex RE_ESCAPECHAR = new System.Text.RegularExpressions.Regex(@"[^0-9a-zA-Z\-_.]", System.Text.RegularExpressions.RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Encodes a URL, like System.Web.HttpUtility.UrlEncode
|
||||
@@ -361,7 +374,7 @@ namespace Duplicati.Library.Utility
|
||||
/// <returns>The encoded URL</returns>
|
||||
/// <param name="value">The URL fragment to encode</param>
|
||||
/// <param name="encoding">The encoding to use</param>
|
||||
public static string UrlPathEncode(string value, System.Text.Encoding encoding = null)
|
||||
public static string UrlPathEncode(string value, System.Text.Encoding? encoding = null)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
@@ -375,7 +388,7 @@ namespace Duplicati.Library.Utility
|
||||
/// <returns>The encoded URL</returns>
|
||||
/// <param name="value">The URL fragment to encode</param>
|
||||
/// <param name="encoding">The encoding to use</param>
|
||||
public static string UrlEncode(string value, System.Text.Encoding encoding = null, string spacevalue = "+")
|
||||
public static string UrlEncode(string value, System.Text.Encoding? encoding = null, string spacevalue = "+")
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
@@ -419,7 +432,7 @@ namespace Duplicati.Library.Utility
|
||||
/// <returns>The decoded URL</returns>
|
||||
/// <param name="value">The URL fragment to decode</param>
|
||||
/// <param name="encoding">The encoding to use</param>
|
||||
public static string UrlDecode(string value, System.Text.Encoding encoding = null)
|
||||
public static string UrlDecode(string value, System.Text.Encoding? encoding = null)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
@@ -542,7 +555,7 @@ namespace Duplicati.Library.Utility
|
||||
/// <param name="url">Base URL, containing schema, host, port.</param>
|
||||
/// <param name="path">Base path.</param>
|
||||
/// <param name="query">A collection of name value pairs to be translated into a query string.</param>
|
||||
public static string UriBuilder(string url, string path, NameValueCollection query)
|
||||
public static string UriBuilder(string url, string path, NameValueCollection? query)
|
||||
{
|
||||
var builder = new UriBuilder(url)
|
||||
{
|
||||
@@ -558,7 +571,7 @@ namespace Duplicati.Library.Utility
|
||||
/// </summary>
|
||||
/// <returns>The path.</returns>
|
||||
/// <param name="url">URL.</param>
|
||||
public static string ExtractPath(string url)
|
||||
public static string? ExtractPath(string url)
|
||||
{
|
||||
return new Uri(url).Path;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user