[System] HttpListenerRequest: ignore bad cookies and keep request alive (#5657)
[mono.git] / mcs / class / System / System.Net / EndpointPermission.cs
1 //\r
2 // System.Net.EndpointPermission.cs\r
3 //\r
4 // Author:\r
5 //   Lawrence Pit (loz@cable.a2000.nl)\r
6 //\r
7 \r
8 //\r
9 // Permission is hereby granted, free of charge, to any person obtaining\r
10 // a copy of this software and associated documentation files (the\r
11 // "Software"), to deal in the Software without restriction, including\r
12 // without limitation the rights to use, copy, modify, merge, publish,\r
13 // distribute, sublicense, and/or sell copies of the Software, and to\r
14 // permit persons to whom the Software is furnished to do so, subject to\r
15 // the following conditions:\r
16 // \r
17 // The above copyright notice and this permission notice shall be\r
18 // included in all copies or substantial portions of the Software.\r
19 // \r
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
27 //\r
28 \r
29 using System;\r
30 using System.Collections;\r
31 using System.Security;\r
32 using System.Security.Permissions;\r
33 \r
34 namespace System.Net\r
35 {\r
36         [Serializable]\r
37         public class EndpointPermission // too bad about the lowercase p, not consistent with IPEndPoint ;)\r
38         {\r
39                 private static char [] dot_char = new char [] { '.' };\r
40                 \r
41                 // Fields\r
42                 private string hostname;\r
43                 private int port;\r
44                 private TransportType transport;\r
45 \r
46                 private bool resolved;          \r
47                 private bool hasWildcard;\r
48                 private IPAddress [] addresses;\r
49                 \r
50                 // Constructors\r
51                 internal EndpointPermission (string hostname, \r
52                                              int port, \r
53                                              TransportType transport) : base () \r
54                 {                       \r
55                         if (hostname == null)\r
56                                 throw new ArgumentNullException ("hostname");\r
57                         this.hostname = hostname;\r
58                         this.port = port;\r
59                         this.transport = transport;\r
60                         this.resolved = false;\r
61                         this.hasWildcard = false;\r
62                         this.addresses = null;\r
63                 }               \r
64                 \r
65                 // Properties\r
66 \r
67                 public string Hostname {\r
68                         get { return hostname; }\r
69                 }\r
70 \r
71                 public int Port {\r
72                         get { return port; }\r
73                 }\r
74                 \r
75                 public TransportType Transport {\r
76                         get { return transport; }\r
77                 }\r
78                 \r
79                 // Methods\r
80                 \r
81                 public override bool Equals (object obj) \r
82                 {\r
83                         EndpointPermission epp = obj as EndpointPermission;\r
84                         return ((epp != null) &&\r
85                                 (this.port == epp.port) &&\r
86                                 (this.transport == epp.transport) &&\r
87                                 (String.Compare (this.hostname, epp.hostname, true) == 0));\r
88                 }\r
89                 \r
90                 public override int GetHashCode () \r
91                 {\r
92                         return ToString ().GetHashCode ();\r
93                 }\r
94                 \r
95                 public override string ToString () \r
96                 {\r
97                         return hostname + "#" + port + "#" + (int) transport;\r
98                 }\r
99                 \r
100                 // Internal & Private Methods\r
101                 \r
102                 internal bool IsSubsetOf (EndpointPermission perm) \r
103                 {\r
104                         if (perm == null)\r
105                                 return false;\r
106                         \r
107                         if (perm.port != SocketPermission.AllPorts &&\r
108                             this.port != perm.port)\r
109                                 return false;\r
110                         \r
111                         if (perm.transport != TransportType.All &&\r
112                             this.transport != perm.transport)\r
113                                 return false;\r
114                         \r
115                         this.Resolve ();\r
116                         perm.Resolve ();\r
117                         \r
118                         if (this.hasWildcard) {\r
119                                 if (perm.hasWildcard)\r
120                                         return IsSubsetOf (this.hostname, perm.hostname);\r
121                                 else \r
122                                         return false;\r
123                         } \r
124                         \r
125                         if (this.addresses == null) \r
126                                 return false;\r
127                         \r
128                         if (perm.hasWildcard) \r
129                                 // a bit dubious... should they all be a subset or is one \r
130                                 // enough in this case?\r
131                                 foreach (IPAddress addr in this.addresses)\r
132                                         if (IsSubsetOf (addr.ToString (), perm.hostname))\r
133                                                 return true;\r
134                                 \r
135                         if (perm.addresses == null) \r
136                                 return false;\r
137                                 \r
138                         // a bit dubious... should they all be a subset or is one \r
139                         // enough in this case?\r
140                         foreach (IPAddress addr in perm.addresses)\r
141                                 if (IsSubsetOf (this.hostname, addr.ToString ())) \r
142                                         return true;    \r
143                                         \r
144                         return false;           \r
145                 }               \r
146                 \r
147                 private bool IsSubsetOf (string addr1, string addr2)\r
148                 {\r
149                         string [] h1 = addr1.Split (dot_char);          \r
150                         string [] h2 = addr2.Split (dot_char);\r
151                                 \r
152                         for (int i = 0; i < 4; i++) {\r
153                                 int part1 = ToNumber (h1 [i]);\r
154                                 if (part1 == -1) \r
155                                         return false;                           \r
156 \r
157                                 int part2 = ToNumber (h2 [i]);\r
158                                 if (part2 == -1)\r
159                                         return false;                           \r
160                                 if (part1 == 256)\r
161                                         continue;\r
162                                 if (part1 != part2 && part2 != 256)\r
163                                         return false;\r
164                         }\r
165                         return true;\r
166                 }\r
167                 \r
168                 internal EndpointPermission Intersect (EndpointPermission perm) \r
169                 {\r
170                         if (perm == null)\r
171                                 return null;\r
172                         \r
173                         int _port;\r
174                         if (this.port == perm.port)\r
175                                 _port = this.port;\r
176                         else if (this.port == SocketPermission.AllPorts)\r
177                                 _port = perm.port;\r
178                         else if (perm.port == SocketPermission.AllPorts)\r
179                                 _port = this.port;\r
180                         else\r
181                                 return null;\r
182 \r
183                         TransportType _transport;\r
184                         if (this.transport == perm.transport)\r
185                                 _transport = this.transport;\r
186                         else if (this.transport == TransportType.All)\r
187                                 _transport = perm.transport;\r
188                         else if (perm.transport == TransportType.All)\r
189                                 _transport = this.transport;\r
190                         else\r
191                                 return null;\r
192 \r
193                         string _hostname = IntersectHostname (perm);                                            \r
194                         \r
195                         if (_hostname == null)\r
196                                 return null;\r
197 \r
198                         if (!this.hasWildcard)\r
199                                 return this;\r
200                                 \r
201                         if (!perm.hasWildcard)\r
202                                 return perm;\r
203                                 \r
204                         EndpointPermission newperm = new EndpointPermission (_hostname, _port, _transport);\r
205                         newperm.hasWildcard = true;\r
206                         newperm.resolved = true;\r
207                         return newperm;\r
208                 }\r
209                 \r
210                 private string IntersectHostname (EndpointPermission perm)\r
211                 {\r
212                         if (this.hostname == perm.hostname)\r
213                                 return this.hostname;\r
214                                 \r
215                         this.Resolve ();\r
216                         perm.Resolve ();\r
217                         \r
218                         string _hostname = null;\r
219                         \r
220                         if (this.hasWildcard) {\r
221                                 if (perm.hasWildcard) {\r
222                                         _hostname = Intersect (this.hostname, perm.hostname);\r
223                                 } else if (perm.addresses != null) {\r
224                                         for (int j = 0; j < perm.addresses.Length; j++) {\r
225                                                 _hostname = Intersect (this.hostname, perm.addresses [j].ToString ());\r
226                                                 if (_hostname != null) \r
227                                                         break;\r
228                                         }\r
229                                 }\r
230                         } else if (this.addresses != null) {\r
231                                 for (int i = 0; i < this.addresses.Length; i++) {\r
232                                         string thisaddr = this.addresses [i].ToString ();\r
233                                         if (perm.hasWildcard) {\r
234                                                 _hostname = Intersect (thisaddr, perm.hostname);\r
235                                         } else if (perm.addresses != null) {\r
236                                                 for (int j = 0; j < perm.addresses.Length; j++) {\r
237                                                         _hostname = Intersect (thisaddr, perm.addresses [j].ToString ());\r
238                                                         if (_hostname != null) \r
239                                                                 break;\r
240                                                 }\r
241                                         }\r
242                                 }\r
243                         }\r
244                         \r
245                         return _hostname;\r
246                 }\r
247                 \r
248                 // alas, currently we'll only support IPv4 as that's MS.Net behaviour\r
249                 // returns null when both host strings do not intersect\r
250                 private string Intersect (string addr1, string addr2)\r
251                 {\r
252                         string [] h1 = addr1.Split (dot_char);          \r
253                         string [] h2 = addr2.Split (dot_char);\r
254                                 \r
255                         string [] s = new string [7];\r
256                         for (int i = 0; i < 4; i++) {\r
257                                 int part1 = ToNumber (h1 [i]);\r
258                                 if (part1 == -1) \r
259                                         return null;                            \r
260 \r
261                                 int part2 = ToNumber (h2 [i]);\r
262                                 if (part2 == -1)\r
263                                         return null;                            \r
264 \r
265                                 if (part1 == 256) \r
266                                         s [i << 1] = (part2 == 256) ? "*" : String.Empty + part2;\r
267                                 else if (part2 == 256)\r
268                                         s [i << 1] = (part1 == 256) ? "*" : String.Empty + part1;                               \r
269                                 else if (part1 == part2)\r
270                                         s [i << 1] = String.Empty + part1;\r
271                                 else\r
272                                         return null;\r
273                         }\r
274                         \r
275                         s [1] = s [3] = s [5] = ".";\r
276                         return String.Concat (s);\r
277                 }\r
278                 \r
279                 // returns 256 if value is a '*' character\r
280                 // returns -1 if value isn't a number between 0 and 255         \r
281                 private int ToNumber (string value)\r
282                 {\r
283                         if (value == "*")\r
284                                 return 256;\r
285                                 \r
286                         int len = value.Length;\r
287                         if (len < 1 || len > 3)\r
288                                 return -1;\r
289                                 \r
290                         int val = 0;                            \r
291                         for (int i = 0; i < len; i++) {\r
292                                 char c = value [i];\r
293                                 if ('0' <= c && c <= '9') \r
294                                         val = checked (val * 10 + (c - '0'));\r
295                                 else\r
296                                         return -1;\r
297                         }\r
298                         \r
299                         return val <= 255 ? val : -1;\r
300                 }\r
301 \r
302                 internal void Resolve ()\r
303                 {\r
304                         if (resolved)   \r
305                                 return;\r
306                                 \r
307                         bool isHostname = false;                                \r
308                         bool hasWildcard = false;\r
309                         this.addresses = null;\r
310                         \r
311                         string [] s = hostname.Split (dot_char);\r
312 \r
313                         if (s.Length != 4) {\r
314                                 isHostname = true;\r
315                         } else {\r
316                                 for (int i = 0; i < 4; i++) {\r
317                                         int quad = ToNumber (s [i]);\r
318                                         if (quad == -1) {\r
319                                                 isHostname = true;\r
320                                                 break;\r
321                                         }\r
322                                         if (quad == 256)\r
323                                                 hasWildcard = true;\r
324                                 }\r
325                         }\r
326                         \r
327                         if (isHostname) {\r
328                                 this.hasWildcard = false;\r
329                                 try {\r
330                                         this.addresses = Dns.GetHostAddresses (hostname);\r
331                                 } catch (System.Net.Sockets.SocketException) {                                  \r
332                                 }\r
333                         } else {\r
334                                 this.hasWildcard = hasWildcard;\r
335                                 if (!hasWildcard) {\r
336                                         addresses = new IPAddress [1];\r
337                                         addresses [0] = IPAddress.Parse (hostname);\r
338                                 }\r
339                         }\r
340                         \r
341                         this.resolved = true;                           \r
342                 }\r
343                 \r
344                 internal void UndoResolve ()\r
345                 {\r
346                         resolved = false;\r
347                 }\r
348         }\r
349 }\r