2 // ClientAccessPolicyParser.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
6 // Moonlight List (moonlight-list@lists.ximian.com)
8 // Copyright (C) 2009-2010 Novell, Inc. http://www.novell.com
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
33 using System.Collections.Generic;
39 default namespace = ""
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 },
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 ()))
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) {
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) {
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) {
116 ReadPolicyElement (reader, cap);
118 reader.ReadEndElement ();
120 reader.ReadEndElement ();
125 static void ReadPolicyElement (XmlReader reader, ClientAccessPolicy cap)
127 if (reader.HasAttributes || reader.IsEmptyElement) {
132 var policy = new AccessPolicy ();
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) {
142 ReadAllowFromElement (reader, policy);
145 ReadGrantToElement (reader, policy);
155 cap.AccessPolicyList.Add (policy);
156 reader.ReadEndElement ();
159 static void ReadAllowFromElement (XmlReader reader, AccessPolicy policy)
161 if (reader.IsEmptyElement) {
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");
174 methods = reader.GetAttribute ("http-methods");
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)) {
191 switch (reader.LocalName) {
193 var d = reader.GetAttribute ("uri");
196 v.AllowAnyDomain = true;
220 policy.AllowedServices.Add (v);
221 reader.ReadEndElement ();
224 // only "path" and "include-subpaths" attributes are allowed - anything else is not considered
225 static Resource CreateResource (XmlReader reader)
227 int n = reader.AttributeCount;
228 string path = reader.GetAttribute ("path");
231 string subpaths = reader.GetAttribute ("include-subpaths");
232 if (subpaths != null)
234 if ((n != 0) || !reader.IsEmptyElement)
237 return new Resource () {
239 IncludeSubpaths = subpaths == null ? false : XmlConvert.ToBoolean (subpaths)
243 static void ReadGrantToElement (XmlReader reader, AccessPolicy policy)
245 var v = new GrantTo ();
248 if (reader.HasAttributes || reader.IsEmptyElement) {
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)) {
262 switch (reader.LocalName) {
264 var r = CreateResource (reader);
270 case "socket-resource":
271 // ignore everything that is not TCP
272 if (reader.GetAttribute ("protocol") != "tcp")
274 // we can merge them all together inside a policy
275 policy.PortMask |= ParsePorts (reader.GetAttribute ("port"));
284 policy.GrantedResources.Add (v);
285 reader.ReadEndElement ();
288 // e.g. reserved ? 4534-4502
289 static long ParsePorts (string ports)
292 int sep = ports.IndexOf ('-');
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));
301 ushort port = ParsePort (ports);
302 mask |= (long) (1ul << (port - AccessPolicy.MinPort));
307 static ushort ParsePort (string s)
310 if (!UInt16.TryParse (s, out port) || (port < AccessPolicy.MinPort) || (port > AccessPolicy.MaxPort))
311 throw new XmlException ("Invalid port");