2 // System.Net.ServicePointManager
5 // Lawrence Pit (loz@cable.a2000.nl)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections;
31 using System.Collections.Specialized;
32 using System.Configuration;
33 using System.Net.Configuration;
34 using System.Security.Cryptography.X509Certificates;
38 // A service point manager manages service points (duh!).
39 // A service point maintains a list of connections (per scheme + authority).
40 // According to HttpWebRequest.ConnectionGroupName each connection group
41 // creates additional connections. therefor, a service point has a hashtable
42 // of connection groups where each value is a list of connections.
44 // when we need to make an HttpWebRequest, we need to do the following:
45 // 1. find service point, given Uri and Proxy
46 // 2. find connection group, given service point and group name
47 // 3. find free connection in connection group, or create one (if ok due to limits)
48 // 4. lease connection
50 // 6. when finished, return connection
56 public class ServicePointManager
58 private static HybridDictionary servicePoints = new HybridDictionary ();
62 private static ICertificatePolicy policy = new DefaultCertificatePolicy ();
63 private static int defaultConnectionLimit = DefaultPersistentConnectionLimit;
64 private static int maxServicePointIdleTime = 900000; // 15 minutes
65 private static int maxServicePoints = 0;
66 private static bool _checkCRL = false;
67 #if (NET_1_0 || NET_1_1)
68 private static SecurityProtocolType _securityProtocol = SecurityProtocolType.Ssl3;
70 private static SecurityProtocolType _securityProtocol = SecurityProtocolType.Default;
73 static bool expectContinue = true;
79 public const int DefaultNonPersistentConnectionLimit = 4;
80 public const int DefaultPersistentConnectionLimit = 2;
82 const string configKey = "system.net/connectionManagement";
83 static ConnectionManagementData manager;
85 static ServicePointManager ()
87 manager = (ConnectionManagementData) ConfigurationSettings.GetConfig (configKey);
90 private ServicePointManager ()
96 public static ICertificatePolicy CertificatePolicy {
97 get { return policy; }
98 set { policy = value; }
102 // we need it for SslClientStream
105 [MonoTODO("CRL checks not implemented")]
108 static bool CheckCertificateRevocationList {
109 get { return _checkCRL; }
110 set { _checkCRL = false; } // TODO - don't yet accept true
113 public static int DefaultConnectionLimit {
114 get { return defaultConnectionLimit; }
117 throw new ArgumentOutOfRangeException ("value");
119 defaultConnectionLimit = value;
123 public static int MaxServicePointIdleTime {
125 return maxServicePointIdleTime;
128 if (value < -2 || value > Int32.MaxValue)
129 throw new ArgumentOutOfRangeException ("value");
130 maxServicePointIdleTime = value;
134 public static int MaxServicePoints {
136 return maxServicePoints;
140 throw new ArgumentException ("value");
142 maxServicePoints = value;
143 RecycleServicePoints ();
148 // we need it for SslClientStream
153 static SecurityProtocolType SecurityProtocol {
154 get { return _securityProtocol; }
155 set { _securityProtocol = value; }
159 public static bool Expect100Continue {
160 get { return expectContinue; }
161 set { expectContinue = value; }
164 public static bool UseNagleAlgorithm {
165 get { return useNagle; }
166 set { useNagle = value; }
171 public static ServicePoint FindServicePoint (Uri address)
173 return FindServicePoint (address, GlobalProxySelection.Select);
176 public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
178 return FindServicePoint (new Uri(uriString), proxy);
181 public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
184 throw new ArgumentNullException ("address");
186 RecycleServicePoints ();
188 bool usesProxy = false;
189 bool useConnect = false;
190 if (proxy != null && !proxy.IsBypassed(address)) {
192 bool isSecure = address.Scheme == "https";
193 address = proxy.GetProxy (address);
194 if (address.Scheme != "http" && !isSecure)
195 throw new NotSupportedException ("Proxy scheme not supported.");
197 if (isSecure && address.Scheme == "http")
201 address = new Uri (address.Scheme + "://" + address.Authority);
203 ServicePoint sp = null;
204 lock (servicePoints) {
205 sp = servicePoints [address] as ServicePoint;
209 if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)
210 throw new InvalidOperationException ("maximum number of service points reached");
212 string addr = address.ToString ();
213 int limit = (int) manager.GetMaxConnections (addr);
214 sp = new ServicePoint (address, limit, maxServicePointIdleTime);
216 sp.Expect100Continue = expectContinue;
217 sp.UseNagleAlgorithm = useNagle;
219 sp.UsesProxy = usesProxy;
220 sp.UseConnect = useConnect;
221 servicePoints.Add (address, sp);
229 internal static void RecycleServicePoints ()
231 ArrayList toRemove = new ArrayList ();
232 lock (servicePoints) {
233 IDictionaryEnumerator e = servicePoints.GetEnumerator ();
234 while (e.MoveNext ()) {
235 ServicePoint sp = (ServicePoint) e.Value;
236 if (sp.AvailableForRecycling) {
237 toRemove.Add (e.Key);
241 for (int i = 0; i < toRemove.Count; i++)
242 servicePoints.Remove (toRemove [i]);
244 if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)
247 // get rid of the ones with the longest idle time
248 SortedList list = new SortedList (servicePoints.Count);
249 e = servicePoints.GetEnumerator ();
250 while (e.MoveNext ()) {
251 ServicePoint sp = (ServicePoint) e.Value;
252 if (sp.CurrentConnections == 0) {
253 while (list.ContainsKey (sp.IdleSince))
254 sp.IdleSince.AddMilliseconds (1);
255 list.Add (sp.IdleSince, sp.Address);
259 for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)
260 servicePoints.Remove (list.GetByIndex (i));