2010-04-06 Sebastien Pouliot <sebastien@ximian.com>
[mono-project.git] / mcs / class / System.Net / System.Net.Policy / ClientAccessPolicyParser.cs
blob37847dc7f9c03aa66d1930f17e866c3067a6cda2
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.
30 #if NET_2_1
32 using System;
33 using System.Collections.Generic;
34 using System.IO;
35 using System.Linq;
36 using System.Xml;
39 default namespace = ""
41 grammar {
43 start = access-policy
45 access-policy = element access-policy {
46 element cross-domain-access {
47 element policy { allow-from, grant-to }
51 allow-from = element allow-from {
52 attribute http-request-headers { text },
53 element domain {
54 attribute uri { text }
58 grant-to = element grant-to {
59 (resource | socket-resource)+
62 resource = element resource {
63 attribute path { text },
64 attribute include-subpaths { "true" | "false" }
67 socket-resource = element socket-resource {
68 attribute port { text },
69 attribute protocol { text }
75 namespace System.Net.Policy {
77 partial class ClientAccessPolicy {
79 static public ICrossDomainPolicy FromStream (Stream stream)
81 ClientAccessPolicy cap = new ClientAccessPolicy ();
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 ();
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;
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));
101 if ((reader.LocalName != "cross-domain-access") || reader.IsEmptyElement) {
102 reader.Skip ();
103 continue;
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));
111 if ((reader.Name != "policy") || reader.IsEmptyElement) {
112 reader.Skip ();
113 continue;
116 ReadPolicyElement (reader, cap);
118 reader.ReadEndElement ();
120 reader.ReadEndElement ();
122 return cap;
125 static void ReadPolicyElement (XmlReader reader, ClientAccessPolicy cap)
127 if (reader.HasAttributes || reader.IsEmptyElement) {
128 reader.Skip ();
129 return;
132 var policy = new AccessPolicy ();
133 bool valid = true;
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));
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;
154 if (valid)
155 cap.AccessPolicyList.Add (policy);
156 reader.ReadEndElement ();
159 static void ReadAllowFromElement (XmlReader reader, AccessPolicy policy)
161 var v = new AllowFrom ();
162 bool valid = true;
164 if (reader.HasAttributes || reader.IsEmptyElement) {
165 reader.Skip ();
166 return;
169 v.HttpRequestHeaders.SetHeaders (reader.GetAttribute ("http-request-headers"));
170 reader.ReadStartElement ("allow-from", String.Empty);
171 for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
172 if (reader.NodeType != XmlNodeType.Element)
173 throw new XmlException (String.Format ("Unexpected allow-from content: {0}", reader.NodeType));
174 if (!String.IsNullOrEmpty (reader.NamespaceURI)) {
175 reader.Skip ();
176 continue;
178 switch (reader.LocalName) {
179 case "domain":
180 var d = reader.GetAttribute ("uri");
181 switch (d) {
182 case "*":
183 v.AllowAnyDomain = true;
184 break;
185 case "http://*":
186 v.Scheme = "http";
187 break;
188 case "https://*":
189 v.Scheme = "https";
190 break;
191 case "file:///":
192 v.Scheme = "file";
193 break;
194 default:
195 v.Domains.Add (d);
196 break;
198 reader.Skip ();
199 break;
200 default:
201 valid = false;
202 reader.Skip ();
203 continue;
206 if (valid)
207 policy.AllowedServices.Add (v);
208 reader.ReadEndElement ();
211 // only "path" and "include-subpaths" attributes are allowed - anything else is not considered
212 static Resource CreateResource (XmlReader reader)
214 int n = reader.AttributeCount;
215 string path = reader.GetAttribute ("path");
216 if (path != null)
217 n--;
218 string subpaths = reader.GetAttribute ("include-subpaths");
219 if (subpaths != null)
220 n--;
221 if ((n != 0) || !reader.IsEmptyElement)
222 return null;
224 return new Resource () {
225 Path = path,
226 IncludeSubpaths = subpaths == null ? false : XmlConvert.ToBoolean (subpaths)
230 static void ReadGrantToElement (XmlReader reader, AccessPolicy policy)
232 var v = new GrantTo ();
233 bool valid = true;
235 if (reader.HasAttributes || reader.IsEmptyElement) {
236 reader.Skip ();
237 return;
240 reader.ReadStartElement ("grant-to", String.Empty);
241 for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
242 if (reader.NodeType != XmlNodeType.Element)
243 throw new XmlException (String.Format ("Unexpected grant-to content: {0}", reader.NodeType));
244 if (!String.IsNullOrEmpty (reader.NamespaceURI)) {
245 reader.Skip ();
246 continue;
249 switch (reader.LocalName) {
250 case "resource":
251 var r = CreateResource (reader);
252 if (r == null)
253 valid = false;
254 else
255 v.Resources.Add (r);
256 break;
257 case "socket-resource":
258 // ignore everything that is not TCP
259 if (reader.GetAttribute ("protocol") != "tcp")
260 break;
261 // we can merge them all together inside a policy
262 policy.PortMask |= ParsePorts (reader.GetAttribute ("port"));
263 break;
264 default:
265 valid = false;
266 break;
268 reader.Skip ();
270 if (valid)
271 policy.GrantedResources.Add (v);
272 reader.ReadEndElement ();
275 // e.g. reserved ? 4534-4502
276 static long ParsePorts (string ports)
278 long mask = 0;
279 int sep = ports.IndexOf ('-');
280 if (sep >= 0) {
281 // range
282 ushort from = ParsePort (ports.Substring (0, sep));
283 ushort to = ParsePort (ports.Substring (sep + 1));
284 for (int port = from; port <= to; port++)
285 mask |= (long) (1ul << (port - AccessPolicy.MinPort));
286 } else {
287 // single
288 ushort port = ParsePort (ports);
289 mask |= (long) (1ul << (port - AccessPolicy.MinPort));
291 return mask;
294 static ushort ParsePort (string s)
296 ushort port;
297 if (!UInt16.TryParse (s, out port) || (port < AccessPolicy.MinPort) || (port > AccessPolicy.MaxPort))
298 throw new XmlException ("Invalid port");
299 return port;
304 #endif