ServicePointManager.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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.Security.Cryptography.X509Certificates;
  11. //
  12. // notes:
  13. // A service point manager manages service points (duh!).
  14. // A service point maintains a list of connections (per scheme + authority).
  15. // According to HttpWebRequest.ConnectionGroupName each connection group
  16. // creates additional connections. therefor, a service point has a hashtable
  17. // of connection groups where each value is a list of connections.
  18. //
  19. // when we need to make an HttpWebRequest, we need to do the following:
  20. // 1. find service point, given Uri and Proxy
  21. // 2. find connection group, given service point and group name
  22. // 3. find free connection in connection group, or create one (if ok due to limits)
  23. // 4. lease connection
  24. // 5. execute request
  25. // 6. when finished, return connection
  26. //
  27. namespace System.Net
  28. {
  29. class DummyPolicy : ICertificatePolicy
  30. {
  31. public bool CheckValidationResult (ServicePoint point,
  32. X509Certificate certificate,
  33. WebRequest request,
  34. int certificateProblem)
  35. {
  36. return (certificateProblem == 0);
  37. }
  38. }
  39. public class ServicePointManager
  40. {
  41. private static HybridDictionary servicePoints = new HybridDictionary ();
  42. // Static properties
  43. private static ICertificatePolicy policy = new DummyPolicy ();
  44. private static int defaultConnectionLimit = DefaultPersistentConnectionLimit;
  45. private static int maxServicePointIdleTime = 900000; // 15 minutes
  46. private static int maxServicePoints = 0;
  47. // Fields
  48. public const int DefaultNonPersistentConnectionLimit = 4;
  49. public const int DefaultPersistentConnectionLimit = 2;
  50. // Constructors
  51. private ServicePointManager ()
  52. {
  53. }
  54. // Properties
  55. public static ICertificatePolicy CertificatePolicy {
  56. get { return policy; }
  57. set { policy = value; }
  58. }
  59. public static int DefaultConnectionLimit {
  60. get { return defaultConnectionLimit; }
  61. set {
  62. if (value <= 0)
  63. throw new ArgumentOutOfRangeException ("value");
  64. defaultConnectionLimit = value;
  65. }
  66. }
  67. public static int MaxServicePointIdleTime {
  68. get {
  69. return maxServicePointIdleTime;
  70. }
  71. set {
  72. if (value < -2 || value > Int32.MaxValue)
  73. throw new ArgumentOutOfRangeException ("value");
  74. maxServicePointIdleTime = value;
  75. }
  76. }
  77. public static int MaxServicePoints {
  78. get {
  79. return maxServicePoints;
  80. }
  81. set {
  82. if (value < 0)
  83. throw new ArgumentException ("value");
  84. maxServicePoints = value;
  85. RecycleServicePoints ();
  86. }
  87. }
  88. // Methods
  89. public static ServicePoint FindServicePoint (Uri address)
  90. {
  91. return FindServicePoint (address, GlobalProxySelection.Select);
  92. }
  93. public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
  94. {
  95. return FindServicePoint (new Uri(uriString), proxy);
  96. }
  97. public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
  98. {
  99. if (address == null)
  100. throw new ArgumentNullException ("address");
  101. RecycleServicePoints ();
  102. if (proxy != null && !proxy.IsBypassed(address)) {
  103. address = proxy.GetProxy (address);
  104. if (address.Scheme != "http" && address.Scheme != "https")
  105. throw new NotSupportedException ("Proxy scheme not supported.");
  106. }
  107. address = new Uri (address.Scheme + "://" + address.Authority);
  108. ServicePoint sp = null;
  109. lock (servicePoints) {
  110. sp = servicePoints [address] as ServicePoint;
  111. if (sp != null)
  112. return sp;
  113. if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)
  114. throw new InvalidOperationException ("maximum number of service points reached");
  115. sp = new ServicePoint (address, defaultConnectionLimit, maxServicePointIdleTime);
  116. servicePoints.Add (address, sp);
  117. }
  118. return sp;
  119. }
  120. // Internal Methods
  121. internal static void RecycleServicePoints ()
  122. {
  123. ArrayList toRemove = new ArrayList ();
  124. lock (servicePoints) {
  125. IDictionaryEnumerator e = servicePoints.GetEnumerator ();
  126. while (e.MoveNext ()) {
  127. ServicePoint sp = (ServicePoint) e.Value;
  128. if (sp.AvailableForRecycling) {
  129. toRemove.Add (e.Key);
  130. }
  131. }
  132. for (int i = 0; i < toRemove.Count; i++)
  133. servicePoints.Remove (toRemove [i]);
  134. if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)
  135. return;
  136. // get rid of the ones with the longest idle time
  137. SortedList list = new SortedList (servicePoints.Count);
  138. e = servicePoints.GetEnumerator ();
  139. while (e.MoveNext ()) {
  140. ServicePoint sp = (ServicePoint) e.Value;
  141. if (sp.CurrentConnections == 0) {
  142. while (list.ContainsKey (sp.IdleSince))
  143. sp.IdleSince.AddMilliseconds (1);
  144. list.Add (sp.IdleSince, sp.Address);
  145. }
  146. }
  147. for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)
  148. servicePoints.Remove (list.GetByIndex (i));
  149. }
  150. }
  151. }
  152. }