diff --git a/Duplicati/Library/DynamicLoader/BackendLoader.cs b/Duplicati/Library/DynamicLoader/BackendLoader.cs
index e515777d4..b87cec4bc 100644
--- a/Duplicati/Library/DynamicLoader/BackendLoader.cs
+++ b/Duplicati/Library/DynamicLoader/BackendLoader.cs
@@ -55,6 +55,39 @@ namespace Duplicati.Library.DynamicLoader
get { return new string[] {"backends"}; }
}
+ ///
+ /// Parses the URL into components
+ ///
+ /// The url to parse, the parser will remove the querystring
+ /// The url scheme
+ /// Extra options from the query string
+ public static void ParseUrl(ref string url, out string scheme, out NameValueCollection extraOptions)
+ {
+ extraOptions = new NameValueCollection();
+
+ //If possible, we avoid parsing the string as a URL to allow flexible string handling
+ if (false && url.IndexOf("://") > 0)
+ {
+ scheme = url.Substring(0, url.IndexOf("://"));
+ var ix = url.IndexOf('?');
+ if (ix > 0)
+ {
+ extraOptions = HttpUtility.ParseQueryString(url.Substring(ix));
+ url = url.Substring(0, ix);
+ }
+ }
+ else
+ {
+ var uri = new Uri(url);
+ scheme = uri.Scheme.ToLower();
+ if (!string.IsNullOrEmpty(uri.Query))
+ {
+ extraOptions = HttpUtility.ParseQueryString(uri.Query);
+ url = url.Substring(0, url.Length - uri.Query.Length);
+ }
+ }
+ }
+
///
/// Instanciates a specific backend, given the url and options
///
@@ -67,24 +100,9 @@ namespace Duplicati.Library.DynamicLoader
throw new ArgumentNullException("url");
string scheme;
- NameValueCollection extraOptions = new NameValueCollection();
+ NameValueCollection extraOptions;
+ ParseUrl(ref url, out scheme, out extraOptions);
- //If possible, we avoid parsing the string as a URL to allow flexible string handling
- if (url.IndexOf("://") > 0)
- {
- scheme = url.Substring(0, url.IndexOf("://"));
- var ix = url.IndexOf('?');
- if (ix > 0)
- extraOptions = HttpUtility.ParseQueryString(url.Substring(ix));
- }
- else
- {
- var uri = new Uri(url);
- scheme = uri.Scheme.ToLower();
- if (!string.IsNullOrEmpty(uri.Query))
- extraOptions = HttpUtility.ParseQueryString(uri.Query);
- }
-
LoadInterfaces();
var newOpts = new Dictionary(options);
@@ -117,26 +135,53 @@ namespace Duplicati.Library.DynamicLoader
}
///
- /// Gets the supported commands for a certain key
+ /// Gets the supported commands for a certain url
///
- /// The key to find commands for
- /// The supported commands or null if the key was not found
- public IList GetSupportedCommands(string key)
+ /// The url to find commands for
+ /// The supported commands or null if the url scheme was not supported
+ public IList GetSupportedCommands(string url)
{
- if (string.IsNullOrEmpty(key))
- throw new ArgumentNullException("key");
+ if (string.IsNullOrEmpty(url))
+ throw new ArgumentNullException("url");
+
+ string scheme;
+ NameValueCollection extraOptions;
+ ParseUrl(ref url, out scheme, out extraOptions);
LoadInterfaces();
lock (m_lock)
{
IBackend b;
- if (m_interfaces.TryGetValue(key, out b) && b != null)
+ if (m_interfaces.TryGetValue(scheme, out b) && b != null)
return b.SupportedCommands;
- else
- return null;
+ else if (scheme.EndsWith("s"))
+ {
+ var tmpscheme = scheme.Substring(0, scheme.Length - 1);
+ if (m_interfaces.ContainsKey(tmpscheme))
+ return m_interfaces[tmpscheme].SupportedCommands;
+ }
+
+ return null;
}
}
+
+ ///
+ /// Gets the extra url commands encoded in the query string
+ ///
+ /// The url to extract commands from
+ /// The extra commands
+ public NameValueCollection GetExtraCommands(string url)
+ {
+ if (string.IsNullOrEmpty(url))
+ throw new ArgumentNullException("url");
+
+ string scheme;
+ NameValueCollection extraOptions;
+ ParseUrl(ref url, out scheme, out extraOptions);
+ return extraOptions;
+
+ }
}
///
@@ -159,18 +204,32 @@ namespace Duplicati.Library.DynamicLoader
///
/// Gets the supported commands for a given backend
///
- /// The backend to find the commands for, either just the scheme or a full url
- /// The supported commands or null if the key is not supported
- public static IList GetSupportedCommands(string key)
+ /// The url to find the commands for
+ /// The supported commands or null if the url is not supported
+ public static IList GetSupportedCommands(string url)
{
- if (string.IsNullOrEmpty(key))
- throw new ArgumentNullException("key");
+ if (string.IsNullOrEmpty(url))
+ throw new ArgumentNullException("url");
- //Extract the scheme, don't use new Uri() as the url may not be valid
- if (key.IndexOf("://") > 0)
- key = key.Substring(0, key.IndexOf("://"));
+ return _backendLoader.GetSupportedCommands(url);
+ }
- return _backendLoader.GetSupportedCommands(key.ToLower());
+ ///
+ /// Gets the extra url-encoded commands for a given backend
+ ///
+ /// The backend to find the commands for
+ /// The extra supported commands
+ public static IDictionary GetExtraCommands(string url)
+ {
+ if (string.IsNullOrEmpty(url))
+ throw new ArgumentNullException("url");
+
+ var tmp = _backendLoader.GetExtraCommands(url);
+ var dict = new Dictionary();
+ foreach(var k in tmp.AllKeys)
+ dict[k] = tmp[k];
+
+ return dict;
}
diff --git a/Duplicati/Library/Main/Interface.cs b/Duplicati/Library/Main/Interface.cs
index 6403e2125..855a67745 100644
--- a/Duplicati/Library/Main/Interface.cs
+++ b/Duplicati/Library/Main/Interface.cs
@@ -2574,7 +2574,7 @@ namespace Duplicati.Library.Main
return;
//Keep a list of all supplied options
- Dictionary ropts = m_options.RawOptions;
+ Dictionary ropts = new Dictionary(m_options.RawOptions);
//Keep a list of all supported options
Dictionary supportedOptions = new Dictionary();
@@ -2602,6 +2602,11 @@ namespace Duplicati.Library.Main
disabledModuleOptions[s] = disabledModuleOptions[c.Name];
}
}
+
+ // Throw url-encoded options into the mix
+ //TODO: This can hide values if both commandline and url-parameters supply the same key
+ foreach(var k in DynamicLoader.BackendLoader.GetExtraCommands(m_backend))
+ ropts[k.Key] = k.Value;
//Now run through all supported options, and look for deprecated options
foreach (IList l in new IList[] {