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 bool IsNonElement (XmlReader reader)
81 return (reader.NodeType != XmlNodeType.Element);
84 static bool IsNonEmptyElement (XmlReader reader)
86 return (reader.IsEmptyElement || IsNonElement (reader));
89 static public ICrossDomainPolicy FromStream (Stream stream)
91 ClientAccessPolicy cap = new ClientAccessPolicy ();
93 // Silverlight accepts whitespaces before the XML - which is invalid XML
94 StreamReader sr = new StreamReader (stream);
95 while (Char.IsWhiteSpace ((char) sr.Peek ()))
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) {
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")) {
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")) {
120 ReadPolicyElement (reader, cap);
122 reader.ReadEndElement ();
124 reader.ReadEndElement ();
129 static void ReadPolicyElement (XmlReader reader, ClientAccessPolicy cap)
131 if (reader.HasAttributes || reader.IsEmptyElement) {
136 var policy = new AccessPolicy ();
139 reader.ReadStartElement ("policy", String.Empty);
140 for (reader.MoveToContent (); reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
141 if (IsNonElement (reader)) {
146 switch (reader.LocalName) {
148 ReadAllowFromElement (reader, policy);
151 ReadGrantToElement (reader, policy);
161 cap.AccessPolicyList.Add (policy);
162 reader.ReadEndElement ();
165 static void ReadAllowFromElement (XmlReader reader, AccessPolicy policy)
167 if (IsNonEmptyElement (reader)) {
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");
180 methods = reader.GetAttribute ("http-methods");
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)) {
195 switch (reader.LocalName) {
197 var d = reader.GetAttribute ("uri");
199 v.AllowAnyDomain = true;
211 policy.AllowedServices.Add (v);
212 reader.ReadEndElement ();
215 // only "path" and "include-subpaths" attributes are allowed - anything else is not considered
216 static Resource CreateResource (XmlReader reader)
218 int n = reader.AttributeCount;
219 string path = reader.GetAttribute ("path");
222 string subpaths = reader.GetAttribute ("include-subpaths");
223 if (subpaths != null)
225 if ((n != 0) || !reader.IsEmptyElement)
228 return new Resource () {
230 IncludeSubpaths = subpaths == null ? false : XmlConvert.ToBoolean (subpaths)
234 static void ReadGrantToElement (XmlReader reader, AccessPolicy policy)
236 var v = new GrantTo ();
239 if (reader.HasAttributes || reader.IsEmptyElement) {
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)) {
251 switch (reader.LocalName) {
253 var r = CreateResource (reader);
259 case "socket-resource":
260 // ignore everything that is not TCP
261 if (reader.GetAttribute ("protocol") != "tcp")
263 // we can merge them all together inside a policy
264 policy.PortMask |= ParsePorts (reader.GetAttribute ("port"));
273 policy.GrantedResources.Add (v);
274 reader.ReadEndElement ();
277 // e.g. reserved ? 4534-4502
278 static long ParsePorts (string ports)
281 int sep = ports.IndexOf ('-');
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));
290 ushort port = ParsePort (ports);
291 mask |= (long) (1ul << (port - AccessPolicy.MinPort));
296 static ushort ParsePort (string s)
299 if (!UInt16.TryParse (s, out port) || (port < AccessPolicy.MinPort) || (port > AccessPolicy.MaxPort))
300 throw new XmlException ("Invalid port");