2 // System.Net.ServicePointManager
\r
5 // Lawrence Pit (loz@cable.a2000.nl)
\r
9 using System.Collections;
\r
10 using System.Collections.Specialized;
\r
11 using System.Security.Cryptography.X509Certificates;
\r
15 // A service point manager manages service points (duh!).
\r
16 // A service point maintains a list of connections (per scheme + authority).
\r
17 // According to HttpWebRequest.ConnectionGroupName each connection group
\r
18 // creates additional connections. therefor, a service point has a hashtable
\r
19 // of connection groups where each value is a list of connections.
\r
21 // when we need to make an HttpWebRequest, we need to do the following:
\r
22 // 1. find service point, given Uri and Proxy
\r
23 // 2. find connection group, given service point and group name
\r
24 // 3. find free connection in connection group, or create one (if ok due to limits)
\r
25 // 4. lease connection
\r
26 // 5. execute request
\r
27 // 6. when finished, return connection
\r
31 namespace System.Net
\r
33 class DummyPolicy : ICertificatePolicy
\r
35 public bool CheckValidationResult (ServicePoint point,
\r
36 X509Certificate certificate,
\r
38 int certificateProblem)
\r
40 return (certificateProblem == 0);
\r
44 public class ServicePointManager
\r
46 private static HybridDictionary servicePoints = new HybridDictionary ();
\r
48 // Static properties
\r
50 private static ICertificatePolicy policy = new DummyPolicy ();
\r
51 private static int defaultConnectionLimit = DefaultPersistentConnectionLimit;
\r
52 private static int maxServicePointIdleTime = 900000; // 15 minutes
\r
53 private static int maxServicePoints = 0;
\r
57 public const int DefaultNonPersistentConnectionLimit = 4;
\r
58 public const int DefaultPersistentConnectionLimit = 2;
\r
61 private ServicePointManager ()
\r
67 public static ICertificatePolicy CertificatePolicy {
\r
68 get { return policy; }
\r
69 set { policy = value; }
\r
72 public static int DefaultConnectionLimit {
\r
73 get { return defaultConnectionLimit; }
\r
76 throw new ArgumentOutOfRangeException ("value");
\r
78 defaultConnectionLimit = value;
\r
82 public static int MaxServicePointIdleTime {
\r
84 return maxServicePointIdleTime;
\r
87 if (value < -2 || value > Int32.MaxValue)
\r
88 throw new ArgumentOutOfRangeException ("value");
\r
89 maxServicePointIdleTime = value;
\r
93 public static int MaxServicePoints {
\r
95 return maxServicePoints;
\r
99 throw new ArgumentException ("value");
\r
101 maxServicePoints = value;
\r
102 RecycleServicePoints ();
\r
108 public static ServicePoint FindServicePoint (Uri address)
\r
110 return FindServicePoint (address, GlobalProxySelection.Select);
\r
113 public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
\r
115 return FindServicePoint (new Uri(uriString), proxy);
\r
118 public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
\r
120 if (address == null)
\r
121 throw new ArgumentNullException ("address");
\r
123 RecycleServicePoints ();
\r
125 if (proxy != null && !proxy.IsBypassed(address)) {
\r
126 address = proxy.GetProxy (address);
\r
127 if (address.Scheme != "http" && address.Scheme != "https")
\r
128 throw new NotSupportedException ("Proxy scheme not supported.");
\r
131 address = new Uri (address.Scheme + "://" + address.Authority);
\r
133 ServicePoint sp = null;
\r
134 lock (servicePoints) {
\r
135 sp = servicePoints [address] as ServicePoint;
\r
139 if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)
\r
140 throw new InvalidOperationException ("maximum number of service points reached");
\r
141 sp = new ServicePoint (address, defaultConnectionLimit, maxServicePointIdleTime);
\r
142 servicePoints.Add (address, sp);
\r
148 // Internal Methods
\r
150 internal static void RecycleServicePoints ()
\r
152 ArrayList toRemove = new ArrayList ();
\r
153 lock (servicePoints) {
\r
154 IDictionaryEnumerator e = servicePoints.GetEnumerator ();
\r
155 while (e.MoveNext ()) {
\r
156 ServicePoint sp = (ServicePoint) e.Value;
\r
157 if (sp.AvailableForRecycling) {
\r
158 toRemove.Add (e.Key);
\r
162 for (int i = 0; i < toRemove.Count; i++)
\r
163 servicePoints.Remove (toRemove [i]);
\r
165 if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)
\r
168 // get rid of the ones with the longest idle time
\r
169 SortedList list = new SortedList (servicePoints.Count);
\r
170 e = servicePoints.GetEnumerator ();
\r
171 while (e.MoveNext ()) {
\r
172 ServicePoint sp = (ServicePoint) e.Value;
\r
173 if (sp.CurrentConnections == 0) {
\r
174 while (list.ContainsKey (sp.IdleSince))
\r
175 sp.IdleSince.AddMilliseconds (1);
\r
176 list.Add (sp.IdleSince, sp.Address);
\r
180 for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)
\r
181 servicePoints.Remove (list.GetByIndex (i));
\r