2008-11-04 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mcs / class / System / System.Net / ServicePointManager.cs
index 0d31196108f92dd933a9895c68feb628a5e7384d..bea42e48cc30dfc838ff743830182e460c2e373c 100644 (file)
-//\r
-// System.Net.ServicePointManager\r
-//\r
-// Author:\r
-//   Lawrence Pit (loz@cable.a2000.nl)\r
-//\r
-\r
-using System;\r
-using System.Collections;\r
-using System.Collections.Specialized;\r
-using System.Security.Cryptography.X509Certificates;\r
-\r
-//\r
-// notes:\r
-// A service point manager manages service points (duh!).\r
-// A service point maintains a list of connections (per scheme + authority).\r
-// According to HttpWebRequest.ConnectionGroupName each connection group\r
-// creates additional connections. therefor, a service point has a hashtable\r
-// of connection groups where each value is a list of connections.\r
-// \r
-// when we need to make an HttpWebRequest, we need to do the following:\r
-// 1. find service point, given Uri and Proxy \r
-// 2. find connection group, given service point and group name\r
-// 3. find free connection in connection group, or create one (if ok due to limits)\r
-// 4. lease connection\r
-// 5. execute request\r
-// 6. when finished, return connection\r
-//\r
-\r
-\r
-namespace System.Net \r
-{\r
-       class DummyPolicy : ICertificatePolicy\r
-       {\r
-               public bool CheckValidationResult (ServicePoint point,\r
-                                                  X509Certificate certificate,\r
-                                                  WebRequest request,\r
-                                                  int certificateProblem)\r
-               {\r
-                       return (certificateProblem == 0);\r
-               }\r
-       }\r
-       \r
-       public class ServicePointManager\r
-       {\r
-               private static HybridDictionary servicePoints = new HybridDictionary ();\r
-               \r
-               // Static properties\r
-               \r
-               private static ICertificatePolicy policy = new DummyPolicy ();\r
-               private static int defaultConnectionLimit = DefaultPersistentConnectionLimit;\r
-               private static int maxServicePointIdleTime = 900000; // 15 minutes\r
-               private static int maxServicePoints = 0;\r
-               \r
-               // Fields\r
-               \r
-               public const int DefaultNonPersistentConnectionLimit = 4;\r
-               public const int DefaultPersistentConnectionLimit = 2;\r
-               \r
-               // Constructors\r
-               private ServicePointManager ()\r
-               {\r
-               }               \r
-               \r
-               // Properties\r
-               \r
-               public static ICertificatePolicy CertificatePolicy {\r
-                       get { return policy; }\r
-                       set { policy = value; }\r
-               }\r
-               \r
-               public static int DefaultConnectionLimit {\r
-                       get { return defaultConnectionLimit; }\r
-                       set { \r
-                               if (value <= 0)\r
-                                       throw new ArgumentOutOfRangeException ("value");\r
-\r
-                               defaultConnectionLimit = value; \r
-                       }\r
-               }\r
-               \r
-               public static int MaxServicePointIdleTime {\r
-                       get { \r
-                               return maxServicePointIdleTime;\r
-                       }\r
-                       set { \r
-                               if (value < -2 || value > Int32.MaxValue)\r
-                                       throw new ArgumentOutOfRangeException ("value");\r
-                               maxServicePointIdleTime = value;\r
-                       }\r
-               }\r
-               \r
-               public static int MaxServicePoints {\r
-                       get { \r
-                               return maxServicePoints; \r
-                       }\r
-                       set {  \r
-                               if (value < 0)\r
-                                       throw new ArgumentException ("value");                          \r
-\r
-                               maxServicePoints = value;\r
-                               RecycleServicePoints ();\r
-                       }\r
-               }\r
-               \r
-               // Methods\r
-               \r
-               public static ServicePoint FindServicePoint (Uri address) \r
-               {\r
-                       return FindServicePoint (address, GlobalProxySelection.Select);\r
-               }\r
-               \r
-               public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)\r
-               {\r
-                       return FindServicePoint (new Uri(uriString), proxy);\r
-               }\r
-               \r
-               public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)\r
-               {\r
-                       if (address == null)\r
-                               throw new ArgumentNullException ("address");\r
-\r
-                       RecycleServicePoints ();\r
-                       \r
-                       bool usesProxy = false;\r
-                       if (proxy != null && !proxy.IsBypassed(address)) {\r
-                               usesProxy = true;\r
-                               address = proxy.GetProxy (address);\r
-                               if (address.Scheme != "http" && address.Scheme != "https")\r
-                                       throw new NotSupportedException ("Proxy scheme not supported.");\r
-                       } \r
-\r
-                       address = new Uri (address.Scheme + "://" + address.Authority);\r
-                       \r
-                       ServicePoint sp = null;\r
-                       lock (servicePoints) {\r
-                               sp = servicePoints [address] as ServicePoint;\r
-                               if (sp != null)\r
-                                       return sp;\r
-\r
-                               if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)\r
-                                       throw new InvalidOperationException ("maximum number of service points reached");\r
-\r
-                               sp = new ServicePoint (address, defaultConnectionLimit, maxServicePointIdleTime);\r
-                               sp.UsesProxy = usesProxy;\r
-                               servicePoints.Add (address, sp);\r
-                       }\r
-                       \r
-                       return sp;\r
-               }\r
-               \r
-               // Internal Methods\r
-\r
-               internal static void RecycleServicePoints ()\r
-               {\r
-                       ArrayList toRemove = new ArrayList ();\r
-                       lock (servicePoints) {\r
-                               IDictionaryEnumerator e = servicePoints.GetEnumerator ();\r
-                               while (e.MoveNext ()) {\r
-                                       ServicePoint sp = (ServicePoint) e.Value;\r
-                                       if (sp.AvailableForRecycling) {\r
-                                               toRemove.Add (e.Key);\r
-                                       }\r
-                               }\r
-                               \r
-                               for (int i = 0; i < toRemove.Count; i++) \r
-                                       servicePoints.Remove (toRemove [i]);\r
-\r
-                               if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)\r
-                                       return;\r
-\r
-                               // get rid of the ones with the longest idle time\r
-                               SortedList list = new SortedList (servicePoints.Count);\r
-                               e = servicePoints.GetEnumerator ();\r
-                               while (e.MoveNext ()) {\r
-                                       ServicePoint sp = (ServicePoint) e.Value;\r
-                                       if (sp.CurrentConnections == 0) {\r
-                                               while (list.ContainsKey (sp.IdleSince))\r
-                                                       sp.IdleSince.AddMilliseconds (1);\r
-                                               list.Add (sp.IdleSince, sp.Address);\r
-                                       }\r
-                               }\r
-                               \r
-                               for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)\r
-                                       servicePoints.Remove (list.GetByIndex (i));\r
-                       }\r
-               }\r
-       }\r
-}\r
+//
+// System.Net.ServicePointManager
+//
+// Author:
+//   Lawrence Pit (loz@cable.a2000.nl)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Configuration;
+using System.Net.Configuration;
+using System.Security.Cryptography.X509Certificates;
+
+#if NET_2_0
+using System.Net.Security;
+#endif
+
+//
+// notes:
+// A service point manager manages service points (duh!).
+// A service point maintains a list of connections (per scheme + authority).
+// According to HttpWebRequest.ConnectionGroupName each connection group
+// creates additional connections. therefor, a service point has a hashtable
+// of connection groups where each value is a list of connections.
+// 
+// when we need to make an HttpWebRequest, we need to do the following:
+// 1. find service point, given Uri and Proxy 
+// 2. find connection group, given service point and group name
+// 3. find free connection in connection group, or create one (if ok due to limits)
+// 4. lease connection
+// 5. execute request
+// 6. when finished, return connection
+//
+
+
+namespace System.Net 
+{
+       public class ServicePointManager
+       {
+               class SPKey {
+                       Uri uri; // schema/host/port
+                       bool use_connect;
+
+                       public SPKey (Uri uri, bool use_connect) {
+                               this.uri = uri;
+                               this.use_connect = use_connect;
+                       }
+
+                       public Uri Uri {
+                               get { return uri; }
+                       }
+
+                       public bool UseConnect {
+                               get { return use_connect; }
+                       }
+
+                       public override int GetHashCode () {
+                               return uri.GetHashCode () + ((use_connect) ? 1 : 0);
+                       }
+
+                       public override bool Equals (object obj) {
+                               SPKey other = obj as SPKey;
+                               if (obj == null) {
+                                       return false;
+                               }
+
+                               return (uri.Equals (other.uri) && other.use_connect == use_connect);
+                       }
+               }
+
+               private static HybridDictionary servicePoints = new HybridDictionary ();
+               
+               // Static properties
+               
+               private static ICertificatePolicy policy = new DefaultCertificatePolicy ();
+               private static int defaultConnectionLimit = DefaultPersistentConnectionLimit;
+               private static int maxServicePointIdleTime = 900000; // 15 minutes
+               private static int maxServicePoints = 0;
+               private static bool _checkCRL = false;
+               private static SecurityProtocolType _securityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
+
+#if NET_1_1
+#if TARGET_JVM
+               static bool expectContinue = false;
+#else
+               static bool expectContinue = true;
+#endif
+               static bool useNagle;
+#endif
+
+               // Fields
+               
+               public const int DefaultNonPersistentConnectionLimit = 4;
+               public const int DefaultPersistentConnectionLimit = 2;
+
+               const string configKey = "system.net/connectionManagement";
+               static ConnectionManagementData manager;
+               
+               static ServicePointManager ()
+               {
+#if NET_2_0 && CONFIGURATION_DEP
+                       object cfg = ConfigurationManager.GetSection (configKey);
+                       ConnectionManagementSection s = cfg as ConnectionManagementSection;
+                       if (s != null) {
+                               manager = new ConnectionManagementData (null);
+                               foreach (ConnectionManagementElement e in s.ConnectionManagement)
+                                       manager.Add (e.Address, e.MaxConnection);
+
+                               defaultConnectionLimit = (int) manager.GetMaxConnections ("*");                         
+                               return;
+                       }
+#endif
+                       manager = (ConnectionManagementData) ConfigurationSettings.GetConfig (configKey);
+                       if (manager != null) {
+                               defaultConnectionLimit = (int) manager.GetMaxConnections ("*");                         
+                       }
+               }
+
+               // Constructors
+               private ServicePointManager ()
+               {
+               }               
+               
+               // Properties
+               
+#if NET_2_0
+               [Obsolete ("Use ServerCertificateValidationCallback instead",
+                          false)]
+#endif
+               public static ICertificatePolicy CertificatePolicy {
+                       get { return policy; }
+                       set { policy = value; }
+               }
+
+#if NET_1_0
+               // we need it for SslClientStream
+               internal
+#else
+               [MonoTODO("CRL checks not implemented")]
+               public
+#endif
+               static bool CheckCertificateRevocationList {
+                       get { return _checkCRL; }
+                       set { _checkCRL = false; }      // TODO - don't yet accept true
+               }
+               
+               public static int DefaultConnectionLimit {
+                       get { return defaultConnectionLimit; }
+                       set { 
+                               if (value <= 0)
+                                       throw new ArgumentOutOfRangeException ("value");
+
+                               defaultConnectionLimit = value; 
+                       }
+               }
+
+#if NET_2_0
+               static Exception GetMustImplement ()
+               {
+                       return new NotImplementedException ();
+               }
+               
+               [MonoTODO]
+               public static int DnsRefreshTimeout
+               {
+                       get {
+                               throw GetMustImplement ();
+                       }
+                       set {
+                               throw GetMustImplement ();
+                       }
+               }
+               
+               [MonoTODO]
+               public static bool EnableDnsRoundRobin
+               {
+                       get {
+                               throw GetMustImplement ();
+                       }
+                       set {
+                               throw GetMustImplement ();
+                       }
+               }
+#endif
+               
+               public static int MaxServicePointIdleTime {
+                       get { 
+                               return maxServicePointIdleTime;
+                       }
+                       set { 
+                               if (value < -2 || value > Int32.MaxValue)
+                                       throw new ArgumentOutOfRangeException ("value");
+                               maxServicePointIdleTime = value;
+                       }
+               }
+               
+               public static int MaxServicePoints {
+                       get { 
+                               return maxServicePoints; 
+                       }
+                       set {  
+                               if (value < 0)
+                                       throw new ArgumentException ("value");                          
+
+                               maxServicePoints = value;
+                               RecycleServicePoints ();
+                       }
+               }
+
+#if NET_1_0
+               // we need it for SslClientStream
+               internal
+#else
+               public
+#endif
+               static SecurityProtocolType SecurityProtocol {
+                       get { return _securityProtocol; }
+                       set { _securityProtocol = value; }
+               }
+
+#if NET_2_0 && SECURITY_DEP
+               [MonoTODO]
+               public static RemoteCertificateValidationCallback ServerCertificateValidationCallback
+               {
+                       get {
+                               throw GetMustImplement ();
+                       }
+                       set {
+                               throw GetMustImplement ();
+                       }
+               }
+#endif
+
+#if NET_1_1
+               public static bool Expect100Continue {
+                       get { return expectContinue; }
+                       set { expectContinue = value; }
+               }
+
+               public static bool UseNagleAlgorithm {
+                       get { return useNagle; }
+                       set { useNagle = value; }
+               }
+#endif
+               // Methods
+               
+               public static ServicePoint FindServicePoint (Uri address) 
+               {
+                       return FindServicePoint (address, GlobalProxySelection.Select);
+               }
+               
+               public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
+               {
+                       return FindServicePoint (new Uri(uriString), proxy);
+               }
+
+               public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
+               {
+                       if (address == null)
+                               throw new ArgumentNullException ("address");
+
+                       RecycleServicePoints ();
+                       
+                       bool usesProxy = false;
+                       bool useConnect = false;
+                       if (proxy != null && !proxy.IsBypassed(address)) {
+                               usesProxy = true;
+                               bool isSecure = address.Scheme == "https";
+                               address = proxy.GetProxy (address);
+                               if (address.Scheme != "http" && !isSecure)
+                                       throw new NotSupportedException ("Proxy scheme not supported.");
+
+                               if (isSecure && address.Scheme == "http")
+                                       useConnect = true;
+                       } 
+
+                       address = new Uri (address.Scheme + "://" + address.Authority);
+                       
+                       ServicePoint sp = null;
+                       lock (servicePoints) {
+                               SPKey key = new SPKey (address, useConnect);
+                               sp = servicePoints [key] as ServicePoint;
+                               if (sp != null)
+                                       return sp;
+
+                               if (maxServicePoints > 0 && servicePoints.Count >= maxServicePoints)
+                                       throw new InvalidOperationException ("maximum number of service points reached");
+
+                               string addr = address.ToString ();
+                               int limit = (int) manager.GetMaxConnections (addr);
+                               sp = new ServicePoint (address, limit, maxServicePointIdleTime);
+#if NET_1_1
+                               sp.Expect100Continue = expectContinue;
+                               sp.UseNagleAlgorithm = useNagle;
+#endif
+                               sp.UsesProxy = usesProxy;
+                               sp.UseConnect = useConnect;
+                               servicePoints.Add (key, sp);
+                       }
+                       
+                       return sp;
+               }
+               
+               // Internal Methods
+
+               internal static void RecycleServicePoints ()
+               {
+                       ArrayList toRemove = new ArrayList ();
+                       lock (servicePoints) {
+                               IDictionaryEnumerator e = servicePoints.GetEnumerator ();
+                               while (e.MoveNext ()) {
+                                       ServicePoint sp = (ServicePoint) e.Value;
+                                       if (sp.AvailableForRecycling) {
+                                               toRemove.Add (e.Key);
+                                       }
+                               }
+                               
+                               for (int i = 0; i < toRemove.Count; i++) 
+                                       servicePoints.Remove (toRemove [i]);
+
+                               if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)
+                                       return;
+
+                               // get rid of the ones with the longest idle time
+                               SortedList list = new SortedList (servicePoints.Count);
+                               e = servicePoints.GetEnumerator ();
+                               while (e.MoveNext ()) {
+                                       ServicePoint sp = (ServicePoint) e.Value;
+                                       if (sp.CurrentConnections == 0) {
+                                               while (list.ContainsKey (sp.IdleSince))
+                                                       sp.IdleSince = sp.IdleSince.AddMilliseconds (1);
+                                               list.Add (sp.IdleSince, sp.Address);
+                                       }
+                               }
+                               
+                               for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)
+                                       servicePoints.Remove (list.GetByIndex (i));
+                       }
+               }
+       }
+}