Reworked HttpWebRequest and related classes.
[mono.git] / mcs / class / System / System.Net / ServicePointManager.cs
1 //\r
2 // System.Net.ServicePointManager\r
3 //\r
4 // Author:\r
5 //   Lawrence Pit (loz@cable.a2000.nl)\r
6 //\r
7 \r
8 using System;\r
9 using System.Collections;\r
10 using System.Collections.Specialized;\r
11 using System.Security.Cryptography.X509Certificates;\r
12 \r
13 //\r
14 // notes:\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
20 // \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
28 //\r
29 \r
30 \r
31 namespace System.Net \r
32 {\r
33         class DummyPolicy : ICertificatePolicy\r
34         {\r
35                 public bool CheckValidationResult (ServicePoint point,\r
36                                                    X509Certificate certificate,\r
37                                                    WebRequest request,\r
38                                                    int certificateProblem)\r
39                 {\r
40                         return (certificateProblem == 0);\r
41                 }\r
42         }\r
43         \r
44         public class ServicePointManager\r
45         {\r
46                 private static HybridDictionary servicePoints = new HybridDictionary ();\r
47                 \r
48                 // Static properties\r
49                 \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
54                 \r
55                 // Fields\r
56                 \r
57                 public const int DefaultNonPersistentConnectionLimit = 4;\r
58                 public const int DefaultPersistentConnectionLimit = 2;\r
59                 \r
60                 // Constructors\r
61                 private ServicePointManager ()\r
62                 {\r
63                 }               \r
64                 \r
65                 // Properties\r
66                 \r
67                 public static ICertificatePolicy CertificatePolicy {\r
68                         get { return policy; }\r
69                         set { policy = value; }\r
70                 }\r
71                 \r
72                 public static int DefaultConnectionLimit {\r
73                         get { return defaultConnectionLimit; }\r
74                         set { \r
75                                 if (value <= 0)\r
76                                         throw new ArgumentOutOfRangeException ("value");\r
77 \r
78                                 defaultConnectionLimit = value; \r
79                         }\r
80                 }\r
81                 \r
82                 public static int MaxServicePointIdleTime {\r
83                         get { \r
84                                 return maxServicePointIdleTime;\r
85                         }\r
86                         set { \r
87                                 if (value < -2 || value > Int32.MaxValue)\r
88                                         throw new ArgumentOutOfRangeException ("value");\r
89                                 maxServicePointIdleTime = value;\r
90                         }\r
91                 }\r
92                 \r
93                 public static int MaxServicePoints {\r
94                         get { \r
95                                 return maxServicePoints; \r
96                         }\r
97                         set {  \r
98                                 if (value < 0)\r
99                                         throw new ArgumentException ("value");                          \r
100 \r
101                                 maxServicePoints = value;\r
102                                 RecycleServicePoints ();\r
103                         }\r
104                 }\r
105                 \r
106                 // Methods\r
107                 \r
108                 public static ServicePoint FindServicePoint (Uri address) \r
109                 {\r
110                         return FindServicePoint (address, GlobalProxySelection.Select);\r
111                 }\r
112                 \r
113                 public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)\r
114                 {\r
115                         return FindServicePoint (new Uri(uriString), proxy);\r
116                 }\r
117                 \r
118                 public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)\r
119                 {\r
120                         if (address == null)\r
121                                 throw new ArgumentNullException ("address");\r
122 \r
123                         RecycleServicePoints ();\r
124                         \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
129                         } \r
130 \r
131                         address = new Uri (address.Scheme + "://" + address.Authority);\r
132                         \r
133                         ServicePoint sp = null;\r
134                         lock (servicePoints) {\r
135                                 sp = servicePoints [address] as ServicePoint;\r
136                                 if (sp != null)\r
137                                         return sp;\r
138 \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
143                         }\r
144                         \r
145                         return sp;\r
146                 }\r
147                 \r
148                 // Internal Methods\r
149 \r
150                 internal static void RecycleServicePoints ()\r
151                 {\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
159                                         }\r
160                                 }\r
161                                 \r
162                                 for (int i = 0; i < toRemove.Count; i++) \r
163                                         servicePoints.Remove (toRemove [i]);\r
164 \r
165                                 if (maxServicePoints == 0 || servicePoints.Count <= maxServicePoints)\r
166                                         return;\r
167 \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
177                                         }\r
178                                 }\r
179                                 \r
180                                 for (int i = 0; i < list.Count && servicePoints.Count > maxServicePoints; i++)\r
181                                         servicePoints.Remove (list.GetByIndex (i));\r
182                         }\r
183                 }\r
184         }\r
185 }\r