SqlClient mono friendly bits
[mono.git] / mcs / class / System.Net / System.Net.Policy / ClientAccessPolicyParser.cs
1 //
2 // ClientAccessPolicyParser.cs
3 //
4 // Authors:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //      Moonlight List (moonlight-list@lists.ximian.com)
7 //
8 // Copyright (C) 2009-2010 Novell, Inc.  http://www.novell.com
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 #if NET_2_1
31
32 using System;
33 using System.Collections.Generic;
34 using System.IO;
35 using System.Linq;
36 using System.Xml;
37
38 /*
39 default namespace = ""
40
41 grammar {
42
43 start = access-policy
44
45 access-policy = element access-policy {
46   element cross-domain-access {
47     element policy { allow-from, grant-to }
48   }
49 }
50
51 allow-from = element allow-from {
52   attribute http-request-headers { text },
53   element domain {
54     attribute uri { text }
55   }
56 }
57
58 grant-to = element grant-to {
59   (resource | socket-resource)+
60 }
61
62 resource = element resource {
63   attribute path { text },
64   attribute include-subpaths { "true" | "false" }
65 }
66
67 socket-resource = element socket-resource {
68   attribute port { text },
69   attribute protocol { text }
70 }
71
72 }
73 */
74
75 namespace System.Net.Policy {
76
77         partial class ClientAccessPolicy {
78
79                 static bool IsNonElement (XmlReader reader)
80                 {
81                         return (reader.NodeType != XmlNodeType.Element);
82                 }
83
84                 static bool IsNonEmptyElement (XmlReader reader)
85                 {
86                         return (reader.IsEmptyElement || IsNonElement (reader));
87                 }
88
89                 static public ICrossDomainPolicy FromStream (Stream stream)
90                 {
91                         ClientAccessPolicy cap = new ClientAccessPolicy ();
92
93                         // Silverlight accepts whitespaces before the XML - which is invalid XML
94                         StreamReader sr = new StreamReader (stream);
95                         while (Char.IsWhiteSpace ((char) sr.Peek ()))
96                                 sr.Read ();
97
98                         XmlReaderSettings policy_settings = new XmlReaderSettings ();
99                         policy_settings.DtdProcessing = DtdProcessing.Ignore;
100                         using (XmlReader reader = XmlReader.Create (sr, policy_settings)) {
101                                 reader.MoveToContent ();
102                                 if (reader.IsEmptyElement) {
103                                         reader.Skip ();
104                                         return null;
105                                 }
106                                 reader.ReadStartElement ("access-policy", String.Empty);
107                                 for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
108                                         if (IsNonEmptyElement (reader) || (reader.LocalName != "cross-domain-access")) {
109                                                 reader.Skip ();
110                                                 continue;
111                                         }
112
113                                         reader.ReadStartElement ("cross-domain-access", String.Empty);
114                                         for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
115                                                 if (IsNonEmptyElement (reader) || (reader.Name != "policy")) {
116                                                         reader.Skip ();
117                                                         continue;
118                                                 }
119
120                                                 ReadPolicyElement (reader, cap);
121                                         }
122                                         reader.ReadEndElement ();
123                                 }
124                                 reader.ReadEndElement ();
125                         }
126                         return cap;
127                 }
128
129                 static void ReadPolicyElement (XmlReader reader, ClientAccessPolicy cap)
130                 {
131                         if (reader.HasAttributes || reader.IsEmptyElement) {
132                                 reader.Skip ();
133                                 return;
134                         }
135
136                         var policy = new AccessPolicy ();
137                         bool valid = true;
138
139                         reader.ReadStartElement ("policy", String.Empty);
140                         for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
141                                 if (IsNonElement (reader)) {
142                                         reader.Skip ();
143                                         continue;
144                                 }
145
146                                 switch (reader.LocalName) {
147                                 case "allow-from":
148                                         ReadAllowFromElement (reader, policy);
149                                         break;
150                                 case "grant-to":
151                                         ReadGrantToElement (reader, policy);
152                                         break;
153                                 default:
154                                         valid = false;
155                                         reader.Skip ();
156                                         break;
157                                 }
158                         }
159
160                         if (valid)
161                                 cap.AccessPolicyList.Add (policy);
162                         reader.ReadEndElement ();
163                 }
164
165                 static void ReadAllowFromElement (XmlReader reader, AccessPolicy policy)
166                 {
167                         if (IsNonEmptyElement (reader)) {
168                                 reader.Skip ();
169                                 return;
170                         }
171
172                         bool valid = true;
173                         string headers = null;
174                         string methods = null;          // new in SL3
175                         if (reader.HasAttributes) {
176                                 int n = reader.AttributeCount;
177                                 headers = reader.GetAttribute ("http-request-headers");
178                                 if (headers != null)
179                                         n--;
180                                 methods = reader.GetAttribute ("http-methods");
181                                 if (methods != null)
182                                         n--;
183                                 valid = (n == 0);
184                         }
185
186                         var v = new AllowFrom ();
187                         v.HttpRequestHeaders.SetHeaders (headers);
188                         v.AllowAnyMethod = (methods == "*"); // only legal value defined, otherwise restricted to GET and POST
189                         reader.ReadStartElement ("allow-from", String.Empty);
190                         for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
191                                 if (IsNonElement (reader) || !String.IsNullOrEmpty (reader.NamespaceURI)) {
192                                         reader.Skip ();
193                                         continue;
194                                 }
195                                 switch (reader.LocalName) {
196                                 case "domain":
197                                         var d = reader.GetAttribute ("uri");
198                                         if (d == "*")
199                                                 v.AllowAnyDomain = true;
200                                         else
201                                                 v.Domains.Add (d);
202                                         reader.Skip ();
203                                         break;
204                                 default:
205                                         valid = false;
206                                         reader.Skip ();
207                                         continue;
208                                 }
209                         }
210                         if (valid)
211                                 policy.AllowedServices.Add (v);
212                         reader.ReadEndElement ();
213                 }
214
215                 // only "path" and "include-subpaths" attributes are allowed - anything else is not considered
216                 static Resource CreateResource (XmlReader reader)
217                 {
218                         int n = reader.AttributeCount;
219                         string path = reader.GetAttribute ("path");
220                         if (path != null)
221                                 n--;
222                         string subpaths = reader.GetAttribute ("include-subpaths");
223                         if (subpaths != null)
224                                 n--;
225                         if ((n != 0) || !reader.IsEmptyElement)
226                                 return null;
227
228                         return new Resource () { 
229                                 Path = path,
230                                 IncludeSubpaths = subpaths == null ? false : XmlConvert.ToBoolean (subpaths)
231                         };
232                 }
233
234                 static void ReadGrantToElement (XmlReader reader, AccessPolicy policy)
235                 {
236                         var v = new GrantTo ();
237                         bool valid = true;
238
239                         if (reader.HasAttributes || reader.IsEmptyElement) {
240                                 reader.Skip ();
241                                 return;
242                         }
243
244                         reader.ReadStartElement ("grant-to", String.Empty);
245                         for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
246                                 if (IsNonElement (reader) || !String.IsNullOrEmpty (reader.NamespaceURI)) {
247                                         reader.Skip ();
248                                         continue;
249                                 }
250
251                                 switch (reader.LocalName) {
252                                 case "resource":
253                                         var r = CreateResource (reader);
254                                         if (r == null)
255                                                 valid = false;
256                                         else
257                                                 v.Resources.Add (r);
258                                         break;
259                                 case "socket-resource":
260                                         // ignore everything that is not TCP
261                                         if (reader.GetAttribute ("protocol") != "tcp")
262                                                 break;
263                                         // we can merge them all together inside a policy
264                                         policy.PortMask |= ParsePorts (reader.GetAttribute ("port"));
265                                         break;
266                                 default:
267                                         valid = false;
268                                         break;
269                                 }
270                                 reader.Skip ();
271                         }
272                         if (valid)
273                                 policy.GrantedResources.Add (v);
274                         reader.ReadEndElement ();
275                 }
276
277                 // e.g. reserved ? 4534-4502
278                 static long ParsePorts (string ports)
279                 {
280                         long mask = 0;
281                         int sep = ports.IndexOf ('-');
282                         if (sep >= 0) {
283                                 // range
284                                 ushort from = ParsePort (ports.Substring (0, sep));
285                                 ushort to = ParsePort (ports.Substring (sep + 1));
286                                 for (int port = from; port <= to; port++)
287                                         mask |= (long) (1ul << (port - AccessPolicy.MinPort));
288                         } else {
289                                 // single
290                                 ushort port = ParsePort (ports);
291                                 mask |= (long) (1ul << (port - AccessPolicy.MinPort));
292                         }
293                         return mask;
294                 }
295
296                 static ushort ParsePort (string s)
297                 {
298                         ushort port;
299                         if (!UInt16.TryParse (s, out port) || (port < AccessPolicy.MinPort) || (port > AccessPolicy.MaxPort))
300                                 throw new XmlException ("Invalid port");
301                         return port;
302                 }
303         }
304 }
305
306 #endif
307