Replace SIZEOF_REGISTER with sizeof(mgreg_t) for consistency with sizeof(gpointer)
[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 public ICrossDomainPolicy FromStream (Stream stream)
80                 {
81                         ClientAccessPolicy cap = new ClientAccessPolicy ();
82
83                         // Silverlight accepts whitespaces before the XML - which is invalid XML
84                         StreamReader sr = new StreamReader (stream);
85                         while (Char.IsWhiteSpace ((char) sr.Peek ()))
86                                 sr.Read ();
87
88                         XmlReaderSettings policy_settings = new XmlReaderSettings ();
89                         policy_settings.DtdProcessing = DtdProcessing.Ignore;
90                         using (XmlReader reader = XmlReader.Create (sr, policy_settings)) {
91                                 reader.MoveToContent ();
92                                 if (reader.IsEmptyElement) {
93                                         reader.Skip ();
94                                         return null;
95                                 }
96                                 reader.ReadStartElement ("access-policy", String.Empty);
97                                 for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
98                                         if (reader.NodeType != XmlNodeType.Element)
99                                                 throw new XmlException (String.Format ("Unexpected access-policy content: {0}", reader.NodeType));
100
101                                         if ((reader.LocalName != "cross-domain-access") || reader.IsEmptyElement) {
102                                                 reader.Skip ();
103                                                 continue;
104                                         }
105
106                                         reader.ReadStartElement ("cross-domain-access", String.Empty);
107                                         for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
108                                                 if (reader.NodeType != XmlNodeType.Element)
109                                                         throw new XmlException (String.Format ("Unexpected access-policy content: {0}", reader.NodeType));
110
111                                                 if ((reader.Name != "policy") || reader.IsEmptyElement) {
112                                                         reader.Skip ();
113                                                         continue;
114                                                 }
115
116                                                 ReadPolicyElement (reader, cap);
117                                         }
118                                         reader.ReadEndElement ();
119                                 }
120                                 reader.ReadEndElement ();
121                         }
122                         return cap;
123                 }
124
125                 static void ReadPolicyElement (XmlReader reader, ClientAccessPolicy cap)
126                 {
127                         if (reader.HasAttributes || reader.IsEmptyElement) {
128                                 reader.Skip ();
129                                 return;
130                         }
131
132                         var policy = new AccessPolicy ();
133                         bool valid = true;
134
135                         reader.ReadStartElement ("policy", String.Empty);
136                         for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
137                                 if (reader.NodeType != XmlNodeType.Element)
138                                         throw new XmlException (String.Format ("Unexpected policy content: {0}", reader.NodeType));
139
140                                 switch (reader.LocalName) {
141                                 case "allow-from":
142                                         ReadAllowFromElement (reader, policy);
143                                         break;
144                                 case "grant-to":
145                                         ReadGrantToElement (reader, policy);
146                                         break;
147                                 default:
148                                         valid = false;
149                                         reader.Skip ();
150                                         break;
151                                 }
152                         }
153
154                         if (valid)
155                                 cap.AccessPolicyList.Add (policy);
156                         reader.ReadEndElement ();
157                 }
158
159                 static void ReadAllowFromElement (XmlReader reader, AccessPolicy policy)
160                 {
161                         if (reader.IsEmptyElement) {
162                                 reader.Skip ();
163                                 return;
164                         }
165
166                         bool valid = true;
167                         string headers = null;
168                         string methods = null;          // new in SL3
169                         if (reader.HasAttributes) {
170                                 int n = reader.AttributeCount;
171                                 headers = reader.GetAttribute ("http-request-headers");
172                                 if (headers != null)
173                                         n--;
174                                 methods = reader.GetAttribute ("http-methods");
175                                 if (methods != null)
176                                         n--;
177                                 valid = (n == 0);
178                         }
179
180                         var v = new AllowFrom ();
181                         v.HttpRequestHeaders.SetHeaders (headers);
182                         v.AllowAnyMethod = (methods == "*"); // only legal value defined, otherwise restricted to GET and POST
183                         reader.ReadStartElement ("allow-from", String.Empty);
184                         for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
185                                 if (reader.NodeType != XmlNodeType.Element)
186                                         throw new XmlException (String.Format ("Unexpected allow-from content: {0}", reader.NodeType));
187                                 if (!String.IsNullOrEmpty (reader.NamespaceURI)) {
188                                         reader.Skip ();
189                                         continue;
190                                 }
191                                 switch (reader.LocalName) {
192                                 case "domain":
193                                         var d = reader.GetAttribute ("uri");
194                                         switch (d) {
195                                         case "*":
196                                                 v.AllowAnyDomain = true;
197                                                 break;
198                                         case "http://*":
199                                                 v.Scheme = "http";
200                                                 break;
201                                         case "https://*":
202                                                 v.Scheme = "https";
203                                                 break;
204                                         case "file:///":
205                                                 v.Scheme = "file";
206                                                 break;
207                                         default:
208                                                 v.Domains.Add (d);
209                                                 break;
210                                         }
211                                         reader.Skip ();
212                                         break;
213                                 default:
214                                         valid = false;
215                                         reader.Skip ();
216                                         continue;
217                                 }
218                         }
219                         if (valid)
220                                 policy.AllowedServices.Add (v);
221                         reader.ReadEndElement ();
222                 }
223
224                 // only "path" and "include-subpaths" attributes are allowed - anything else is not considered
225                 static Resource CreateResource (XmlReader reader)
226                 {
227                         int n = reader.AttributeCount;
228                         string path = reader.GetAttribute ("path");
229                         if (path != null)
230                                 n--;
231                         string subpaths = reader.GetAttribute ("include-subpaths");
232                         if (subpaths != null)
233                                 n--;
234                         if ((n != 0) || !reader.IsEmptyElement)
235                                 return null;
236
237                         return new Resource () { 
238                                 Path = path,
239                                 IncludeSubpaths = subpaths == null ? false : XmlConvert.ToBoolean (subpaths)
240                         };
241                 }
242
243                 static void ReadGrantToElement (XmlReader reader, AccessPolicy policy)
244                 {
245                         var v = new GrantTo ();
246                         bool valid = true;
247
248                         if (reader.HasAttributes || reader.IsEmptyElement) {
249                                 reader.Skip ();
250                                 return;
251                         }
252
253                         reader.ReadStartElement ("grant-to", String.Empty);
254                         for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
255                                 if (reader.NodeType != XmlNodeType.Element)
256                                         throw new XmlException (String.Format ("Unexpected grant-to content: {0}", reader.NodeType));
257                                 if (!String.IsNullOrEmpty (reader.NamespaceURI)) {
258                                         reader.Skip ();
259                                         continue;
260                                 }
261
262                                 switch (reader.LocalName) {
263                                 case "resource":
264                                         var r = CreateResource (reader);
265                                         if (r == null)
266                                                 valid = false;
267                                         else
268                                                 v.Resources.Add (r);
269                                         break;
270                                 case "socket-resource":
271                                         // ignore everything that is not TCP
272                                         if (reader.GetAttribute ("protocol") != "tcp")
273                                                 break;
274                                         // we can merge them all together inside a policy
275                                         policy.PortMask |= ParsePorts (reader.GetAttribute ("port"));
276                                         break;
277                                 default:
278                                         valid = false;
279                                         break;
280                                 }
281                                 reader.Skip ();
282                         }
283                         if (valid)
284                                 policy.GrantedResources.Add (v);
285                         reader.ReadEndElement ();
286                 }
287
288                 // e.g. reserved ? 4534-4502
289                 static long ParsePorts (string ports)
290                 {
291                         long mask = 0;
292                         int sep = ports.IndexOf ('-');
293                         if (sep >= 0) {
294                                 // range
295                                 ushort from = ParsePort (ports.Substring (0, sep));
296                                 ushort to = ParsePort (ports.Substring (sep + 1));
297                                 for (int port = from; port <= to; port++)
298                                         mask |= (long) (1ul << (port - AccessPolicy.MinPort));
299                         } else {
300                                 // single
301                                 ushort port = ParsePort (ports);
302                                 mask |= (long) (1ul << (port - AccessPolicy.MinPort));
303                         }
304                         return mask;
305                 }
306
307                 static ushort ParsePort (string s)
308                 {
309                         ushort port;
310                         if (!UInt16.TryParse (s, out port) || (port < AccessPolicy.MinPort) || (port > AccessPolicy.MaxPort))
311                                 throw new XmlException ("Invalid port");
312                         return port;
313                 }
314         }
315 }
316
317 #endif
318