ServicePointManager.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. //
  2. // System.Net.ServicePointManager
  3. //
  4. // Author:
  5. // Lawrence Pit ([email protected])
  6. //
  7. using System;
  8. using System.Collections;
  9. using System.Collections.Specialized;
  10. using System.Configuration;
  11. using System.Net.Configuration;
  12. using System.Security.Cryptography.X509Certificates;
  13. //
  14. // notes:
  15. // A service point manager manages service points (duh!).
  16. // A service point maintains a list of connections (per scheme + authority).
  17. // According to HttpWebRequest.ConnectionGroupName each connection group
  18. // creates additional connections. therefor, a service point has a hashtable
  19. // of connection groups where each value is a list of connections.
  20. //
  21. // when we need to make an HttpWebRequest, we need to do the following:
  22. // 1. find service point, given Uri and Proxy
  23. // 2. find connection group, given service point and group name
  24. // 3. find free connection in connection group, or create one (if ok due to limits)
  25. // 4. lease connection
  26. // 5. execute request
  27. // 6. when finished, return connection
  28. //
  29. namespace System.Net
  30. {
  31. class DummyPolicy : ICertificatePolicy
  32. {
  33. public bool CheckValidationResult (ServicePoint point,
  34. X509Certificate certificate,
  35. WebRequest request,
  36. int certificateProblem)
  37. {
  38. return (certificateProblem == 0);
  39. }
  40. }
  41. public class ServicePointManager
  42. {
  43. private static HybridDictionary servicePoints = new HybridDictionary ();
  44. // Static properties
  45. private static ICertificatePolicy policy = new DummyPolicy ();
  46. private static int defaultConnectionLimit = DefaultPersistentConnectionLimit;
  47. private static int maxServicePointIdleTime = 900000; // 15 minutes
  48. private static int maxServicePoints = 0;
  49. private static bool _checkCRL = false;
  50. #if (NET_1_0 || NET_1_1)
  51. private static SecurityProtocolType _securityProtocol = SecurityProtocolType.Ssl3;
  52. #else
  53. private static SecurityProtocolType _securityProtocol = SecurityProtocolType.Default;
  54. #endif
  55. // Fields
  56. public const int DefaultNonPersistentConnectionLimit = 4;
  57. public const int DefaultPersistentConnectionLimit = 2;
  58. const string configKey = "system.net/connectionManagement";
  59. static ConnectionManagementData manager;
  60. static ServicePointManager ()
  61. {
  62. manager = (ConnectionManagementData) ConfigurationSettings.GetConfig (configKey);
  63. }
  64. // Constructors
  65. private ServicePointManager ()
  66. {
  67. }
  68. // Properties
  69. public static ICertificatePolicy CertificatePolicy {
  70. get { return policy; }
  71. set { policy = value; }
  72. }
  73. #if NET_1_0
  74. // we need it for SslClientStream
  75. internal
  76. #else
  77. [MonoTODO("CRL checks not implemented")]
  78. public
  79. #endif
  80. static bool CheckCertificateRevocationList {
  81. get { return _checkCRL; }
  82. set { _checkCRL = false; } // TODO - don't yet accept true
  83. }
  84. public static int DefaultConnectionLimit {
  85. get { return defaultConnectionLimit; }
  86. set {
  87. if (value <= 0)
  88. throw new ArgumentOutOfRangeException ("value");
  89. defaultConnectionLimit = value;
  90. }
  91. }
  92. public static int MaxServicePointIdleTime {
  93. get {
  94. return maxServicePointIdleTime;
  95. }
  96. set {
  97. if (value < -2 || value > Int32.MaxValue)
  98. throw new ArgumentOutOfRangeException ("value");
  99. maxServicePointIdleTime = value;
  100. }
  101. }
  102. public static int MaxServicePoints {
  103. get {
  104. return maxServicePoints;
  105. }
  106. set {
  107. if (value < 0)
  108. throw new ArgumentException ("value");
  109. maxServicePoints = value;
  110. RecycleServicePoints ();
  111. }
  112. }
  113. #if NET_1_0
  114. // we need it for SslClientStream
  115. internal
  116. #else
  117. public
  118. #endif
  119. static SecurityProtocolType SecurityProtocol {
  120. get { return _securityProtocol; }
  121. set { _securityProtocol = value; }
  122. }
  123. // Methods
  124. public static ServicePoint FindServicePoint (Uri address)
  125. {
  126. return FindServicePoint (address, GlobalProxySelection.Select);
  127. }
  128. public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
  129. {
  130. return FindServicePoint (new Uri(uriString), proxy);
  131. }
  132. public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
  133. {
  134. if (address == null)
  135. throw new ArgumentNullException ("address");
  136. RecycleServicePoints ();
  137. bool usesProxy = false;
  138. if (proxy != null && !proxy.IsBypassed(address)) {
  139. usesProxy = true;
  140. address = proxy.GetProxy (address);
  141. if (address.Scheme != "http" && address.Scheme != "https")
  142. throw new NotSupportedException ("Proxy scheme not supported.");
  143. }
  144. address = new Uri (address.Scheme + "://" + address.Authority);
  145. ServicePoint sp = null;
  146. lock (servicePoints) {
  147. sp = servicePoints [address] as ServicePoint;
  148. if (sp != null)
  149. return sp;
  150. if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)
  151. throw new InvalidOperationException ("maximum number of service points reached");
  152. string addr = address.ToString ();
  153. int limit = (int) manager.GetMaxConnections (addr);
  154. sp = new ServicePoint (address, limit, maxServicePointIdleTime);
  155. sp.UsesProxy = usesProxy;
  156. servicePoints.Add (address, sp);
  157. }
  158. return sp;
  159. }
  160. // Internal Methods
  161. internal static void RecycleServicePoints ()
  162. {
  163. ArrayList toRemove = new ArrayList ();
  164. lock (servicePoints) {
  165. IDictionaryEnumerator e = servicePoints.GetEnumerator ();
  166. while (e.MoveNext ()) {
  167. ServicePoint sp = (ServicePoint) e.Value;
  168. if (sp.AvailableForRecycling) {
  169. toRemove.Add (e.Key);
  170. }
  171. }
  172. for (int i = 0; i < toRemove.Count; i++)
  173. servicePoints.Remove (toRemove [i]);
  174. if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)
  175. return;
  176. // get rid of the ones with the longest idle time
  177. SortedList list = new SortedList (servicePoints.Count);
  178. e = servicePoints.GetEnumerator ();
  179. while (e.MoveNext ()) {
  180. ServicePoint sp = (ServicePoint) e.Value;
  181. if (sp.CurrentConnections == 0) {
  182. while (list.ContainsKey (sp.IdleSince))
  183. sp.IdleSince.AddMilliseconds (1);
  184. list.Add (sp.IdleSince, sp.Address);
  185. }
  186. }
  187. for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)
  188. servicePoints.Remove (list.GetByIndex (i));
  189. }
  190. }
  191. }
  192. }