MongoUrl.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. /* Copyright 2010-present MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Linq;
  18. using System.Threading;
  19. using System.Threading.Tasks;
  20. using MongoDB.Bson;
  21. using MongoDB.Driver.Core.Configuration;
  22. namespace MongoDB.Driver
  23. {
  24. /// <summary>
  25. /// Represents an immutable URL style connection string. See also MongoUrlBuilder.
  26. /// </summary>
  27. #if NET452
  28. [Serializable]
  29. #endif
  30. public class MongoUrl : IEquatable<MongoUrl>
  31. {
  32. // private static fields
  33. private static object __staticLock = new object();
  34. private static Dictionary<string, MongoUrl> __cache = new Dictionary<string, MongoUrl>();
  35. // private fields
  36. private readonly string _applicationName;
  37. private readonly string _authenticationMechanism;
  38. private readonly IEnumerable<KeyValuePair<string, string>> _authenticationMechanismProperties;
  39. private readonly string _authenticationSource;
  40. private readonly ConnectionMode _connectionMode;
  41. private readonly TimeSpan _connectTimeout;
  42. private readonly string _databaseName;
  43. private readonly bool? _fsync;
  44. private readonly GuidRepresentation _guidRepresentation;
  45. private readonly TimeSpan _heartbeatInterval;
  46. private readonly TimeSpan _heartbeatTimeout;
  47. private readonly bool _ipv6;
  48. private readonly bool? _journal;
  49. private readonly TimeSpan _maxConnectionIdleTime;
  50. private readonly TimeSpan _maxConnectionLifeTime;
  51. private readonly int _maxConnectionPoolSize;
  52. private readonly int _minConnectionPoolSize;
  53. private readonly string _password;
  54. private readonly ReadConcernLevel? _readConcernLevel;
  55. private readonly ReadPreference _readPreference;
  56. private readonly string _replicaSetName;
  57. private readonly bool? _retryWrites;
  58. private readonly TimeSpan _localThreshold;
  59. private readonly ConnectionStringScheme _scheme;
  60. private readonly IEnumerable<MongoServerAddress> _servers;
  61. private readonly TimeSpan _serverSelectionTimeout;
  62. private readonly TimeSpan _socketTimeout;
  63. private readonly string _username;
  64. private readonly bool _useSsl;
  65. private readonly bool _verifySslCertificate;
  66. private readonly WriteConcern.WValue _w;
  67. private readonly double _waitQueueMultiple;
  68. private readonly int _waitQueueSize;
  69. private readonly TimeSpan _waitQueueTimeout;
  70. private readonly TimeSpan? _wTimeout;
  71. private readonly string _url;
  72. private readonly string _originalUrl;
  73. // constructors
  74. /// <summary>
  75. /// Creates a new instance of MongoUrl.
  76. /// </summary>
  77. /// <param name="url">The URL containing the settings.</param>
  78. public MongoUrl(string url)
  79. {
  80. _originalUrl = url;
  81. var builder = new MongoUrlBuilder(url); // parses url
  82. _applicationName = builder.ApplicationName;
  83. _authenticationMechanism = builder.AuthenticationMechanism;
  84. _authenticationMechanismProperties = builder.AuthenticationMechanismProperties;
  85. _authenticationSource = builder.AuthenticationSource;
  86. _connectionMode = builder.ConnectionMode;
  87. _connectTimeout = builder.ConnectTimeout;
  88. _databaseName = builder.DatabaseName;
  89. _fsync = builder.FSync;
  90. _guidRepresentation = builder.GuidRepresentation;
  91. _heartbeatInterval = builder.HeartbeatInterval;
  92. _heartbeatTimeout = builder.HeartbeatTimeout;
  93. _ipv6 = builder.IPv6;
  94. _journal = builder.Journal;
  95. _localThreshold = builder.LocalThreshold;
  96. _maxConnectionIdleTime = builder.MaxConnectionIdleTime;
  97. _maxConnectionLifeTime = builder.MaxConnectionLifeTime;
  98. _maxConnectionPoolSize = builder.MaxConnectionPoolSize;
  99. _minConnectionPoolSize = builder.MinConnectionPoolSize;
  100. _password = builder.Password;
  101. _readConcernLevel = builder.ReadConcernLevel;
  102. _readPreference = builder.ReadPreference;
  103. _replicaSetName = builder.ReplicaSetName;
  104. _retryWrites = builder.RetryWrites;
  105. _scheme = builder.Scheme;
  106. _servers = builder.Servers;
  107. _serverSelectionTimeout = builder.ServerSelectionTimeout;
  108. _socketTimeout = builder.SocketTimeout;
  109. _username = builder.Username;
  110. _useSsl = builder.UseSsl;
  111. _verifySslCertificate = builder.VerifySslCertificate;
  112. _w = builder.W;
  113. _waitQueueMultiple = builder.WaitQueueMultiple;
  114. _waitQueueSize = builder.WaitQueueSize;
  115. _waitQueueTimeout = builder.WaitQueueTimeout;
  116. _wTimeout = builder.WTimeout;
  117. _url = builder.ToString(); // keep canonical form
  118. }
  119. // public properties
  120. /// <summary>
  121. /// Gets the application name.
  122. /// </summary>
  123. public string ApplicationName
  124. {
  125. get { return _applicationName; }
  126. }
  127. /// <summary>
  128. /// Gets the authentication mechanism.
  129. /// </summary>
  130. public string AuthenticationMechanism
  131. {
  132. get { return _authenticationMechanism; }
  133. }
  134. /// <summary>
  135. /// Gets the authentication mechanism properties.
  136. /// </summary>
  137. public IEnumerable<KeyValuePair<string, string>> AuthenticationMechanismProperties
  138. {
  139. get { return _authenticationMechanismProperties; }
  140. }
  141. /// <summary>
  142. /// Gets the authentication source.
  143. /// </summary>
  144. public string AuthenticationSource
  145. {
  146. get { return _authenticationSource; }
  147. }
  148. /// <summary>
  149. /// Gets the actual wait queue size (either WaitQueueSize or WaitQueueMultiple x MaxConnectionPoolSize).
  150. /// </summary>
  151. public int ComputedWaitQueueSize
  152. {
  153. get
  154. {
  155. if (_waitQueueMultiple == 0.0)
  156. {
  157. return _waitQueueSize;
  158. }
  159. else
  160. {
  161. return (int)(_waitQueueMultiple * _maxConnectionPoolSize);
  162. }
  163. }
  164. }
  165. /// <summary>
  166. /// Gets the connection mode.
  167. /// </summary>
  168. public ConnectionMode ConnectionMode
  169. {
  170. get { return _connectionMode; }
  171. }
  172. /// <summary>
  173. /// Gets the connect timeout.
  174. /// </summary>
  175. public TimeSpan ConnectTimeout
  176. {
  177. get { return _connectTimeout; }
  178. }
  179. /// <summary>
  180. /// Gets the optional database name.
  181. /// </summary>
  182. public string DatabaseName
  183. {
  184. get { return _databaseName; }
  185. }
  186. /// <summary>
  187. /// Gets the FSync component of the write concern.
  188. /// </summary>
  189. public bool? FSync
  190. {
  191. get { return _fsync; }
  192. }
  193. /// <summary>
  194. /// Gets the representation to use for Guids.
  195. /// </summary>
  196. public GuidRepresentation GuidRepresentation
  197. {
  198. get { return _guidRepresentation; }
  199. }
  200. /// <summary>
  201. /// Gets a value indicating whether this instance has authentication settings.
  202. /// </summary>
  203. public bool HasAuthenticationSettings
  204. {
  205. get
  206. {
  207. return
  208. _username != null ||
  209. _password != null ||
  210. _authenticationMechanism != null ||
  211. _authenticationSource != null;
  212. }
  213. }
  214. /// <summary>
  215. /// Gets the heartbeat interval.
  216. /// </summary>
  217. public TimeSpan HeartbeatInterval
  218. {
  219. get { return _heartbeatInterval; }
  220. }
  221. /// <summary>
  222. /// Gets the heartbeat timeout.
  223. /// </summary>
  224. public TimeSpan HeartbeatTimeout
  225. {
  226. get { return _heartbeatTimeout; }
  227. }
  228. /// <summary>
  229. /// Gets a value indicating whether to use IPv6.
  230. /// </summary>
  231. public bool IPv6
  232. {
  233. get { return _ipv6; }
  234. }
  235. /// <summary>
  236. /// Gets the Journal component of the write concern.
  237. /// </summary>
  238. public bool? Journal
  239. {
  240. get { return _journal; }
  241. }
  242. /// <summary>
  243. /// Gets the local threshold.
  244. /// </summary>
  245. public TimeSpan LocalThreshold
  246. {
  247. get { return _localThreshold; }
  248. }
  249. /// <summary>
  250. /// Gets the max connection idle time.
  251. /// </summary>
  252. public TimeSpan MaxConnectionIdleTime
  253. {
  254. get { return _maxConnectionIdleTime; }
  255. }
  256. /// <summary>
  257. /// Gets the max connection life time.
  258. /// </summary>
  259. public TimeSpan MaxConnectionLifeTime
  260. {
  261. get { return _maxConnectionLifeTime; }
  262. }
  263. /// <summary>
  264. /// Gets the max connection pool size.
  265. /// </summary>
  266. public int MaxConnectionPoolSize
  267. {
  268. get { return _maxConnectionPoolSize; }
  269. }
  270. /// <summary>
  271. /// Gets the min connection pool size.
  272. /// </summary>
  273. public int MinConnectionPoolSize
  274. {
  275. get { return _minConnectionPoolSize; }
  276. }
  277. /// <summary>
  278. /// Gets the password.
  279. /// </summary>
  280. public string Password
  281. {
  282. get { return _password; }
  283. }
  284. /// <summary>
  285. /// Gets the read concern level.
  286. /// </summary>
  287. public ReadConcernLevel? ReadConcernLevel
  288. {
  289. get { return _readConcernLevel; }
  290. }
  291. /// <summary>
  292. /// Gets the read preference.
  293. /// </summary>
  294. public ReadPreference ReadPreference
  295. {
  296. get { return _readPreference; }
  297. }
  298. /// <summary>
  299. /// Gets the name of the replica set.
  300. /// </summary>
  301. public string ReplicaSetName
  302. {
  303. get { return _replicaSetName; }
  304. }
  305. /// <summary>
  306. /// Gets whether writes will be retried.
  307. /// </summary>
  308. public bool? RetryWrites
  309. {
  310. get { return _retryWrites; }
  311. }
  312. /// <summary>
  313. /// Gets the scheme.
  314. /// </summary>
  315. public ConnectionStringScheme Scheme
  316. {
  317. get { return _scheme; }
  318. }
  319. /// <summary>
  320. /// Gets the address of the server (see also Servers if using more than one address).
  321. /// </summary>
  322. public MongoServerAddress Server
  323. {
  324. get { return (_servers == null) ? null : _servers.Single(); }
  325. }
  326. /// <summary>
  327. /// Gets the list of server addresses (see also Server if using only one address).
  328. /// </summary>
  329. public IEnumerable<MongoServerAddress> Servers
  330. {
  331. get { return _servers; }
  332. }
  333. /// <summary>
  334. /// Gets the server selection timeout.
  335. /// </summary>
  336. public TimeSpan ServerSelectionTimeout
  337. {
  338. get { return _serverSelectionTimeout; }
  339. }
  340. /// <summary>
  341. /// Gets the socket timeout.
  342. /// </summary>
  343. public TimeSpan SocketTimeout
  344. {
  345. get { return _socketTimeout; }
  346. }
  347. /// <summary>
  348. /// Gets the URL (in canonical form).
  349. /// </summary>
  350. public string Url
  351. {
  352. get { return _url; }
  353. }
  354. /// <summary>
  355. /// Gets the username.
  356. /// </summary>
  357. public string Username
  358. {
  359. get { return _username; }
  360. }
  361. /// <summary>
  362. /// Gets a value indicating whether to use SSL.
  363. /// </summary>
  364. public bool UseSsl
  365. {
  366. get { return _useSsl; }
  367. }
  368. /// <summary>
  369. /// Gets a value indicating whether to verify an SSL certificate.
  370. /// </summary>
  371. public bool VerifySslCertificate
  372. {
  373. get { return _verifySslCertificate; }
  374. }
  375. /// <summary>
  376. /// Gets the W component of the write concern.
  377. /// </summary>
  378. public WriteConcern.WValue W
  379. {
  380. get { return _w; }
  381. }
  382. /// <summary>
  383. /// Gets the wait queue multiple (the actual wait queue size will be WaitQueueMultiple x MaxConnectionPoolSize).
  384. /// </summary>
  385. public double WaitQueueMultiple
  386. {
  387. get { return _waitQueueMultiple; }
  388. }
  389. /// <summary>
  390. /// Gets the wait queue size.
  391. /// </summary>
  392. public int WaitQueueSize
  393. {
  394. get { return _waitQueueSize; }
  395. }
  396. /// <summary>
  397. /// Gets the wait queue timeout.
  398. /// </summary>
  399. public TimeSpan WaitQueueTimeout
  400. {
  401. get { return _waitQueueTimeout; }
  402. }
  403. /// <summary>
  404. /// Gets the WTimeout component of the write concern.
  405. /// </summary>
  406. public TimeSpan? WTimeout
  407. {
  408. get { return _wTimeout; }
  409. }
  410. // public operators
  411. /// <summary>
  412. /// Compares two MongoUrls.
  413. /// </summary>
  414. /// <param name="lhs">The first URL.</param>
  415. /// <param name="rhs">The other URL.</param>
  416. /// <returns>True if the two URLs are equal (or both null).</returns>
  417. public static bool operator ==(MongoUrl lhs, MongoUrl rhs)
  418. {
  419. return object.Equals(lhs, rhs);
  420. }
  421. /// <summary>
  422. /// Compares two MongoUrls.
  423. /// </summary>
  424. /// <param name="lhs">The first URL.</param>
  425. /// <param name="rhs">The other URL.</param>
  426. /// <returns>True if the two URLs are not equal (or one is null and the other is not).</returns>
  427. public static bool operator !=(MongoUrl lhs, MongoUrl rhs)
  428. {
  429. return !(lhs == rhs);
  430. }
  431. // public static methods
  432. /// <summary>
  433. /// Clears the URL cache. When a URL is parsed it is stored in the cache so that it doesn't have to be
  434. /// parsed again. There is rarely a need to call this method.
  435. /// </summary>
  436. public static void ClearCache()
  437. {
  438. __cache.Clear();
  439. }
  440. /// <summary>
  441. /// Creates an instance of MongoUrl (might be an existing existence if the same URL has been used before).
  442. /// </summary>
  443. /// <param name="url">The URL containing the settings.</param>
  444. /// <returns>An instance of MongoUrl.</returns>
  445. public static MongoUrl Create(string url)
  446. {
  447. // cache previously seen urls to avoid repeated parsing
  448. lock (__staticLock)
  449. {
  450. MongoUrl mongoUrl;
  451. if (!__cache.TryGetValue(url, out mongoUrl))
  452. {
  453. mongoUrl = new MongoUrl(url);
  454. var canonicalUrl = mongoUrl.ToString();
  455. if (canonicalUrl != url)
  456. {
  457. if (__cache.ContainsKey(canonicalUrl))
  458. {
  459. mongoUrl = __cache[canonicalUrl]; // use existing MongoUrl
  460. }
  461. else
  462. {
  463. __cache[canonicalUrl] = mongoUrl; // cache under canonicalUrl also
  464. }
  465. }
  466. __cache[url] = mongoUrl;
  467. }
  468. return mongoUrl;
  469. }
  470. }
  471. // public methods
  472. /// <summary>
  473. /// Compares two MongoUrls.
  474. /// </summary>
  475. /// <param name="rhs">The other URL.</param>
  476. /// <returns>True if the two URLs are equal.</returns>
  477. public bool Equals(MongoUrl rhs)
  478. {
  479. if (object.ReferenceEquals(rhs, null) || GetType() != rhs.GetType()) { return false; }
  480. return _url == rhs._url; // this works because URL is in canonical form
  481. }
  482. /// <summary>
  483. /// Compares two MongoUrls.
  484. /// </summary>
  485. /// <param name="obj">The other URL.</param>
  486. /// <returns>True if the two URLs are equal.</returns>
  487. public override bool Equals(object obj)
  488. {
  489. return Equals(obj as MongoUrl); // works even if obj is null or of a different type
  490. }
  491. /// <summary>
  492. /// Gets the credential.
  493. /// </summary>
  494. /// <returns>The credential (or null if the URL has not authentication settings).</returns>
  495. public MongoCredential GetCredential()
  496. {
  497. if (HasAuthenticationSettings)
  498. {
  499. return MongoCredential.FromComponents(
  500. _authenticationMechanism,
  501. _authenticationSource ?? _databaseName,
  502. _username,
  503. _password);
  504. }
  505. else
  506. {
  507. return null;
  508. }
  509. }
  510. /// <summary>
  511. /// Gets the hash code.
  512. /// </summary>
  513. /// <returns>The hash code.</returns>
  514. public override int GetHashCode()
  515. {
  516. return _url.GetHashCode(); // this works because URL is in canonical form
  517. }
  518. /// <summary>
  519. /// Returns a WriteConcern value based on this instance's settings and a default enabled value.
  520. /// </summary>
  521. /// <param name="enabledDefault">The default enabled value.</param>
  522. /// <returns>A WriteConcern.</returns>
  523. public WriteConcern GetWriteConcern(bool enabledDefault)
  524. {
  525. if (_w == null && !_wTimeout.HasValue && !_fsync.HasValue && !_journal.HasValue)
  526. {
  527. return enabledDefault ? WriteConcern.Acknowledged : WriteConcern.Unacknowledged;
  528. }
  529. return new WriteConcern(_w, _wTimeout, _fsync, _journal);
  530. }
  531. /// <summary>
  532. /// Resolves a connection string. If the connection string indicates more information is available
  533. /// in the DNS system, it will acquire that information as well.
  534. /// </summary>
  535. /// <returns>A resolved MongoURL.</returns>
  536. public MongoUrl Resolve()
  537. {
  538. if (_scheme == ConnectionStringScheme.MongoDB)
  539. {
  540. return this;
  541. }
  542. var connectionString = new ConnectionString(_originalUrl);
  543. var resolved = connectionString.Resolve();
  544. return new MongoUrl(resolved.ToString());
  545. }
  546. /// <summary>
  547. /// Resolves a connection string. If the connection string indicates more information is available
  548. /// in the DNS system, it will acquire that information as well.
  549. /// </summary>
  550. /// <param name="cancellationToken">The cancellation token.</param>
  551. /// <returns>A resolved MongoURL.</returns>
  552. public async Task<MongoUrl> ResolveAsync(CancellationToken cancellationToken = default(CancellationToken))
  553. {
  554. if (_scheme == ConnectionStringScheme.MongoDB)
  555. {
  556. return this;
  557. }
  558. var connectionString = new ConnectionString(_originalUrl);
  559. var resolved = await connectionString.ResolveAsync(cancellationToken).ConfigureAwait(false);
  560. return new MongoUrl(resolved.ToString());
  561. }
  562. /// <summary>
  563. /// Returns the canonical URL based on the settings in this MongoUrlBuilder.
  564. /// </summary>
  565. /// <returns>The canonical URL.</returns>
  566. public override string ToString()
  567. {
  568. return _url;
  569. }
  570. // private methods
  571. private bool AnyWriteConcernSettingsAreSet()
  572. {
  573. return _fsync != null || _journal != null || _w != null || _wTimeout != null;
  574. }
  575. }
  576. }