Skip to content

Commit a09ba4f

Browse files
committed
CSHARP-734: SOCKS5 Proxy Support
1 parent 0cbd39b commit a09ba4f

File tree

3 files changed

+186
-0
lines changed

3 files changed

+186
-0
lines changed

src/MongoDB.Driver/Core/Configuration/ConnectionString.cs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ public sealed class ConnectionString
9292
private string _replicaSet;
9393
private bool? _retryReads;
9494
private bool? _retryWrites;
95+
private string _proxyHost;
96+
private int? _proxyPort;
97+
private string _proxyUsername;
98+
private string _proxyPassword;
9599
private ConnectionStringScheme _scheme;
96100
private ServerMonitoringMode? _serverMonitoringMode;
97101
private TimeSpan? _serverSelectionTimeout;
@@ -356,6 +360,26 @@ public string Password
356360
get { return _password; }
357361
}
358362

363+
/// <summary>
364+
/// Gets the proxy host.
365+
/// </summary>
366+
public string ProxyHost => _proxyHost;
367+
368+
/// <summary>
369+
/// Gets the proxy port.
370+
/// </summary>
371+
public int? ProxyPort => _proxyPort;
372+
373+
/// <summary>
374+
/// Gets the proxy username.
375+
/// </summary>
376+
public string ProxyUsername => _proxyUsername;
377+
378+
/// <summary>
379+
/// Gets the proxy password.
380+
/// </summary>
381+
public string ProxyPassword => _proxyPassword;
382+
359383
/// <summary>
360384
/// Gets the read concern level.
361385
/// </summary>
@@ -903,6 +927,29 @@ private void Parse()
903927
}
904928
}
905929

930+
if (string.IsNullOrEmpty(_proxyHost))
931+
{
932+
if (_proxyPort is not null)
933+
{
934+
throw new MongoConfigurationException("proxyPort cannot be specified without proxyHost.");
935+
}
936+
937+
if (!string.IsNullOrEmpty(_proxyUsername))
938+
{
939+
throw new MongoConfigurationException("proxyUsername cannot be specified without proxyHost.");
940+
}
941+
942+
if (!string.IsNullOrEmpty(_proxyPassword))
943+
{
944+
throw new MongoConfigurationException("proxyPassword cannot be specified without proxyHost.");
945+
}
946+
}
947+
948+
if (string.IsNullOrEmpty(_proxyUsername) != string.IsNullOrEmpty(_proxyPassword))
949+
{
950+
throw new MongoConfigurationException("proxyUsername and proxyPassword must both be specified or neither.");
951+
}
952+
906953
string ProtectConnectionString(string connectionString)
907954
{
908955
var protectedString = Regex.Replace(connectionString, @"(?<=://)[^/]*(?=@)", "<hidden>");
@@ -995,6 +1042,35 @@ private void ParseOption(string name, string value)
9951042
case "minpoolsize":
9961043
_minPoolSize = ParseInt32(name, value);
9971044
break;
1045+
case "proxyhost":
1046+
_proxyHost = value;
1047+
if (_proxyHost.Length == 0)
1048+
{
1049+
throw new MongoConfigurationException("proxyHost cannot be empty.");
1050+
}
1051+
break;
1052+
case "proxyport":
1053+
var proxyPortValue = ParseInt32(name, value);
1054+
if (proxyPortValue is < 0 or > 65535)
1055+
{
1056+
throw new MongoConfigurationException("proxyPort must be between 0 and 65535.");
1057+
}
1058+
_proxyPort = proxyPortValue;
1059+
break;
1060+
case "proxyusername":
1061+
_proxyUsername = value;
1062+
if (_proxyUsername.Length == 0)
1063+
{
1064+
throw new MongoConfigurationException("proxyUsername cannot be empty.");
1065+
}
1066+
break;
1067+
case "proxypassword":
1068+
_proxyPassword = value;
1069+
if (_proxyPassword.Length == 0)
1070+
{
1071+
throw new MongoConfigurationException("proxyPassword cannot be empty.");
1072+
}
1073+
break;
9981074
case "readconcernlevel":
9991075
_readConcernLevel = ParseEnum<ReadConcernLevel>(name, value);
10001076
break;

src/MongoDB.Driver/MongoUrl.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ public class MongoUrl : IEquatable<MongoUrl>
6464
private readonly bool? _retryReads;
6565
private readonly bool? _retryWrites;
6666
private readonly TimeSpan _localThreshold;
67+
private readonly string _proxyHost;
68+
private readonly int? _proxyPort;
69+
private readonly string _proxyUsername;
70+
private readonly string _proxyPassword;
6771
private readonly ConnectionStringScheme _scheme;
6872
private readonly IEnumerable<MongoServerAddress> _servers;
6973
private readonly ServerMonitoringMode? _serverMonitoringMode;
@@ -117,6 +121,10 @@ internal MongoUrl(MongoUrlBuilder builder)
117121
_maxConnectionPoolSize = builder.MaxConnectionPoolSize;
118122
_minConnectionPoolSize = builder.MinConnectionPoolSize;
119123
_password = builder.Password;
124+
_proxyHost = builder.ProxyHost;
125+
_proxyPort = builder.ProxyPort;
126+
_proxyUsername = builder.ProxyUsername;
127+
_proxyPassword = builder.ProxyPassword;
120128
_readConcernLevel = builder.ReadConcernLevel;
121129
_readPreference = builder.ReadPreference;
122130
_replicaSetName = builder.ReplicaSetName;
@@ -358,6 +366,26 @@ public string Password
358366
get { return _password; }
359367
}
360368

369+
/// <summary>
370+
/// Gets the proxy host.
371+
/// </summary>
372+
public string ProxyHost => _proxyHost;
373+
374+
/// <summary>
375+
/// Gets the proxy port.
376+
/// </summary>
377+
public int ProxyPort => _proxyPort;
378+
379+
/// <summary>
380+
/// Gets the proxy username.
381+
/// </summary>
382+
public string ProxyUsername => _proxyUsername;
383+
384+
/// <summary>
385+
/// Gets the proxy password.
386+
/// </summary>
387+
public string ProxyPassword => _proxyPassword;
388+
361389
/// <summary>
362390
/// Gets the read concern level.
363391
/// </summary>

src/MongoDB.Driver/MongoUrlBuilder.cs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ public class MongoUrlBuilder
6060
private string _replicaSetName;
6161
private bool? _retryReads;
6262
private bool? _retryWrites;
63+
private string _proxyHost;
64+
private int? _proxyPort;
65+
private string _proxyUsername;
66+
private string _proxyPassword;
6367
private ConnectionStringScheme _scheme;
6468
private IEnumerable<MongoServerAddress> _servers;
6569
private ServerMonitoringMode? _serverMonitoringMode;
@@ -104,6 +108,10 @@ public MongoUrlBuilder()
104108
_maxConnectionPoolSize = MongoDefaults.MaxConnectionPoolSize;
105109
_minConnectionPoolSize = MongoDefaults.MinConnectionPoolSize;
106110
_password = null;
111+
_proxyHost = null;
112+
_proxyPort = null;
113+
_proxyUsername = null;
114+
_proxyPassword = null;
107115
_readConcernLevel = null;
108116
_readPreference = null;
109117
_replicaSetName = null;
@@ -438,6 +446,59 @@ public string Password
438446
set { _password = value; }
439447
}
440448

449+
/// <summary>
450+
///
451+
/// </summary>
452+
public string ProxyHost
453+
{
454+
get => _proxyHost;
455+
set
456+
{
457+
_proxyHost = Ensure.IsNotNullOrEmpty(value, nameof(ProxyHost));
458+
}
459+
}
460+
461+
/// <summary>
462+
///
463+
/// </summary>
464+
/// <exception cref="ArgumentOutOfRangeException"></exception>
465+
public int? ProxyPort
466+
{
467+
get => _proxyPort;
468+
set
469+
{
470+
if (value is < 0 or > 65535)
471+
{
472+
throw new ArgumentOutOfRangeException(nameof(value), "ProxyPort must be between 0 and 65535.");
473+
}
474+
_proxyPort = value;
475+
}
476+
}
477+
478+
/// <summary>
479+
///
480+
/// </summary>
481+
public string ProxyUsername
482+
{
483+
get => _proxyUsername;
484+
set
485+
{
486+
_proxyUsername = Ensure.IsNotNullOrEmpty(value, nameof(ProxyUsername));
487+
}
488+
}
489+
490+
/// <summary>
491+
///
492+
/// </summary>
493+
public string ProxyPassword
494+
{
495+
get => _proxyPassword;
496+
set
497+
{
498+
_proxyPassword = Ensure.IsNotNullOrEmpty(value, nameof(ProxyPassword));
499+
}
500+
}
501+
441502
/// <summary>
442503
/// Gets or sets the read concern level.
443504
/// </summary>
@@ -760,6 +821,7 @@ public MongoUrl ToMongoUrl()
760821
/// <returns>The canonical URL.</returns>
761822
public override string ToString()
762823
{
824+
//TODO Need to add options here too
763825
StringBuilder url = new StringBuilder();
764826
if (_scheme == ConnectionStringScheme.MongoDB)
765827
{
@@ -980,6 +1042,22 @@ public override string ToString()
9801042
{
9811043
query.AppendFormat("retryWrites={0}&", JsonConvert.ToString(_retryWrites.Value));
9821044
}
1045+
if(!string.IsNullOrEmpty(_proxyHost))
1046+
{
1047+
query.AppendFormat("proxyHost={0}&", _proxyHost);
1048+
}
1049+
if (_proxyPort.HasValue)
1050+
{
1051+
query.AppendFormat("proxyPort={0}&", _proxyPort);
1052+
}
1053+
if (!string.IsNullOrEmpty(_proxyUsername))
1054+
{
1055+
query.AppendFormat("proxyUsername={0}&", _proxyUsername);
1056+
}
1057+
if (!string.IsNullOrEmpty(_proxyPassword))
1058+
{
1059+
query.AppendFormat("proxyPassword={0}&", _proxyPassword);
1060+
}
9831061
if (_srvMaxHosts.HasValue)
9841062
{
9851063
query.AppendFormat("srvMaxHosts={0}&", _srvMaxHosts);
@@ -1026,6 +1104,10 @@ private void InitializeFromConnectionString(ConnectionString connectionString)
10261104
_maxConnectionPoolSize = connectionString.MaxPoolSize.GetValueOrDefault(MongoDefaults.MaxConnectionPoolSize);
10271105
_minConnectionPoolSize = connectionString.MinPoolSize.GetValueOrDefault(MongoDefaults.MinConnectionPoolSize);
10281106
_password = connectionString.Password;
1107+
_proxyHost = connectionString.ProxyHost;
1108+
_proxyPort = connectionString.ProxyPort;
1109+
_proxyUsername = connectionString.ProxyUsername;
1110+
_proxyPassword = connectionString.ProxyPassword;
10291111
_readConcernLevel = connectionString.ReadConcernLevel;
10301112
if (connectionString.ReadPreference.HasValue || connectionString.ReadPreferenceTags != null || connectionString.MaxStaleness.HasValue)
10311113
{

0 commit comments

Comments
 (0)