-//\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));
+ }
+ }
+ }
+}