bring Mono Security to monotouch
[mcs.git] / class / System / System.Net / ServicePointManager.cs
blob811b0d510fb83b0db0711004f7fb6e55bae68a15
1 //
2 // System.Net.ServicePointManager
3 //
4 // Author:
5 // Lawrence Pit (loz@cable.a2000.nl)
6 //
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
29 using System;
30 using System.Collections;
31 using System.Collections.Specialized;
32 using System.Configuration;
33 using System.Net.Configuration;
34 using System.Security.Cryptography.X509Certificates;
36 #if NET_2_0
37 using System.Net.Security;
38 #endif
41 // notes:
42 // A service point manager manages service points (duh!).
43 // A service point maintains a list of connections (per scheme + authority).
44 // According to HttpWebRequest.ConnectionGroupName each connection group
45 // creates additional connections. therefor, a service point has a hashtable
46 // of connection groups where each value is a list of connections.
47 //
48 // when we need to make an HttpWebRequest, we need to do the following:
49 // 1. find service point, given Uri and Proxy
50 // 2. find connection group, given service point and group name
51 // 3. find free connection in connection group, or create one (if ok due to limits)
52 // 4. lease connection
53 // 5. execute request
54 // 6. when finished, return connection
58 namespace System.Net
60 public class ServicePointManager
62 class SPKey {
63 Uri uri; // schema/host/port
64 bool use_connect;
66 public SPKey (Uri uri, bool use_connect) {
67 this.uri = uri;
68 this.use_connect = use_connect;
71 public Uri Uri {
72 get { return uri; }
75 public bool UseConnect {
76 get { return use_connect; }
79 public override int GetHashCode () {
80 return uri.GetHashCode () + ((use_connect) ? 1 : 0);
83 public override bool Equals (object obj) {
84 SPKey other = obj as SPKey;
85 if (obj == null) {
86 return false;
89 return (uri.Equals (other.uri) && other.use_connect == use_connect);
93 private static HybridDictionary servicePoints = new HybridDictionary ();
95 // Static properties
97 private static ICertificatePolicy policy = new DefaultCertificatePolicy ();
98 private static int defaultConnectionLimit = DefaultPersistentConnectionLimit;
99 private static int maxServicePointIdleTime = 900000; // 15 minutes
100 private static int maxServicePoints = 0;
101 private static bool _checkCRL = false;
102 private static SecurityProtocolType _securityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
104 #if NET_1_1
105 #if TARGET_JVM
106 static bool expectContinue = false;
107 #else
108 static bool expectContinue = true;
109 #endif
110 static bool useNagle;
111 #endif
112 #if NET_2_0
113 static RemoteCertificateValidationCallback server_cert_cb;
114 #endif
116 // Fields
118 public const int DefaultNonPersistentConnectionLimit = 4;
119 public const int DefaultPersistentConnectionLimit = 2;
121 #if !MONOTOUCH
122 const string configKey = "system.net/connectionManagement";
123 static ConnectionManagementData manager;
124 #endif
126 static ServicePointManager ()
128 #if !MONOTOUCH
129 #if NET_2_0 && CONFIGURATION_DEP
130 object cfg = ConfigurationManager.GetSection (configKey);
131 ConnectionManagementSection s = cfg as ConnectionManagementSection;
132 if (s != null) {
133 manager = new ConnectionManagementData (null);
134 foreach (ConnectionManagementElement e in s.ConnectionManagement)
135 manager.Add (e.Address, e.MaxConnection);
137 defaultConnectionLimit = (int) manager.GetMaxConnections ("*");
138 return;
140 #endif
141 manager = (ConnectionManagementData) ConfigurationSettings.GetConfig (configKey);
142 if (manager != null) {
143 defaultConnectionLimit = (int) manager.GetMaxConnections ("*");
145 #endif
148 // Constructors
149 private ServicePointManager ()
153 // Properties
155 #if NET_2_0
156 [Obsolete ("Use ServerCertificateValidationCallback instead",
157 false)]
158 #endif
159 public static ICertificatePolicy CertificatePolicy {
160 get { return policy; }
161 set { policy = value; }
164 #if NET_1_0
165 // we need it for SslClientStream
166 internal
167 #else
168 [MonoTODO("CRL checks not implemented")]
169 public
170 #endif
171 static bool CheckCertificateRevocationList {
172 get { return _checkCRL; }
173 set { _checkCRL = false; } // TODO - don't yet accept true
176 public static int DefaultConnectionLimit {
177 get { return defaultConnectionLimit; }
178 set {
179 if (value <= 0)
180 throw new ArgumentOutOfRangeException ("value");
182 defaultConnectionLimit = value;
186 #if NET_2_0
187 static Exception GetMustImplement ()
189 return new NotImplementedException ();
192 [MonoTODO]
193 public static int DnsRefreshTimeout
195 get {
196 throw GetMustImplement ();
198 set {
199 throw GetMustImplement ();
203 [MonoTODO]
204 public static bool EnableDnsRoundRobin
206 get {
207 throw GetMustImplement ();
209 set {
210 throw GetMustImplement ();
213 #endif
215 public static int MaxServicePointIdleTime {
216 get {
217 return maxServicePointIdleTime;
219 set {
220 if (value < -2 || value > Int32.MaxValue)
221 throw new ArgumentOutOfRangeException ("value");
222 maxServicePointIdleTime = value;
226 public static int MaxServicePoints {
227 get {
228 return maxServicePoints;
230 set {
231 if (value < 0)
232 throw new ArgumentException ("value");
234 maxServicePoints = value;
235 RecycleServicePoints ();
239 #if NET_1_0
240 // we need it for SslClientStream
241 internal
242 #else
243 public
244 #endif
245 static SecurityProtocolType SecurityProtocol {
246 get { return _securityProtocol; }
247 set { _securityProtocol = value; }
250 #if NET_2_0
251 public static RemoteCertificateValidationCallback ServerCertificateValidationCallback
253 get {
254 return server_cert_cb;
256 set {
257 server_cert_cb = value;
260 #endif
262 #if NET_1_1
263 public static bool Expect100Continue {
264 get { return expectContinue; }
265 set { expectContinue = value; }
268 public static bool UseNagleAlgorithm {
269 get { return useNagle; }
270 set { useNagle = value; }
272 #endif
273 // Methods
275 public static ServicePoint FindServicePoint (Uri address)
277 return FindServicePoint (address, GlobalProxySelection.Select);
280 public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
282 return FindServicePoint (new Uri(uriString), proxy);
285 public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
287 if (address == null)
288 throw new ArgumentNullException ("address");
290 RecycleServicePoints ();
292 bool usesProxy = false;
293 bool useConnect = false;
294 if (proxy != null && !proxy.IsBypassed(address)) {
295 usesProxy = true;
296 bool isSecure = address.Scheme == "https";
297 address = proxy.GetProxy (address);
298 if (address.Scheme != "http" && !isSecure)
299 throw new NotSupportedException ("Proxy scheme not supported.");
301 if (isSecure && address.Scheme == "http")
302 useConnect = true;
305 address = new Uri (address.Scheme + "://" + address.Authority);
307 ServicePoint sp = null;
308 lock (servicePoints) {
309 SPKey key = new SPKey (address, useConnect);
310 sp = servicePoints [key] as ServicePoint;
311 if (sp != null)
312 return sp;
314 if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)
315 throw new InvalidOperationException ("maximum number of service points reached");
317 string addr = address.ToString ();
318 #if MONOTOUCH
319 int limit = defaultConnectionLimit;
320 #else
321 int limit = (int) manager.GetMaxConnections (addr);
322 #endif
323 sp = new ServicePoint (address, limit, maxServicePointIdleTime);
324 #if NET_1_1
325 sp.Expect100Continue = expectContinue;
326 sp.UseNagleAlgorithm = useNagle;
327 #endif
328 sp.UsesProxy = usesProxy;
329 sp.UseConnect = useConnect;
330 servicePoints.Add (key, sp);
333 return sp;
336 // Internal Methods
338 internal static void RecycleServicePoints ()
340 ArrayList toRemove = new ArrayList ();
341 lock (servicePoints) {
342 IDictionaryEnumerator e = servicePoints.GetEnumerator ();
343 while (e.MoveNext ()) {
344 ServicePoint sp = (ServicePoint) e.Value;
345 if (sp.AvailableForRecycling) {
346 toRemove.Add (e.Key);
350 for (int i = 0; i < toRemove.Count; i++)
351 servicePoints.Remove (toRemove [i]);
353 if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)
354 return;
356 // get rid of the ones with the longest idle time
357 SortedList list = new SortedList (servicePoints.Count);
358 e = servicePoints.GetEnumerator ();
359 while (e.MoveNext ()) {
360 ServicePoint sp = (ServicePoint) e.Value;
361 if (sp.CurrentConnections == 0) {
362 while (list.ContainsKey (sp.IdleSince))
363 sp.IdleSince = sp.IdleSince.AddMilliseconds (1);
364 list.Add (sp.IdleSince, sp.Address);
368 for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)
369 servicePoints.Remove (list.GetByIndex (i));