Merge pull request #6427 from duplicati/feature/update-uri-encode

Dots in url hostname
This commit is contained in:
Kenneth Skovhede
2025-07-15 19:41:47 +02:00
parent 1e083b6166
commit 58cd2d975c
+29 -16
View File
@@ -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;
}