| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace System.ServiceModel.Description
- {
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Xml;
- using WsdlNS = System.Web.Services.Description;
- using System.Globalization;
- //
- // PolicyReader is a complex nested class in the MetadataImporter
- //
- public abstract partial class MetadataImporter
- {
- internal MetadataImporterQuotas Quotas;
- PolicyReader policyNormalizer = null;
-
- internal delegate void PolicyWarningHandler(XmlElement contextAssertion, string warningMessage);
-
- // Consider, [....], make this public?
- internal event PolicyWarningHandler PolicyWarningOccured;
- internal IEnumerable<IEnumerable<XmlElement>> NormalizePolicy(IEnumerable<XmlElement> policyAssertions)
- {
- if (this.policyNormalizer == null)
- {
- this.policyNormalizer = new PolicyReader(this);
- }
- return this.policyNormalizer.NormalizePolicy(policyAssertions);
- }
- //DevNote: The error handling goal for this class is to NEVER throw an exception.
- // * Any Ignored Policy should generate a warning
- // * All policy parsing errors should be logged as warnings in the WSDLImporter.Errors collection.
- sealed class PolicyReader
- {
- int nodesRead = 0;
-
- readonly MetadataImporter metadataImporter;
- internal PolicyReader(MetadataImporter metadataImporter)
- {
- this.metadataImporter = metadataImporter;
- }
- static IEnumerable<XmlElement> Empty = new PolicyHelper.EmptyEnumerable<XmlElement>();
- static IEnumerable<IEnumerable<XmlElement>> EmptyEmpty = new PolicyHelper.SingleEnumerable<IEnumerable<XmlElement>>(new PolicyHelper.EmptyEnumerable<XmlElement>());
- //
- // the core policy reading logic
- // each step returns a list of lists -- an "and of ors":
- // each inner list is a policy alternative: it contains the set of assertions that comprise the alternative
- // the outer list represents the choice between alternatives
- //
- IEnumerable<IEnumerable<XmlElement>> ReadNode(XmlNode node, XmlElement contextAssertion, YieldLimiter yieldLimiter)
- {
- if (nodesRead >= this.metadataImporter.Quotas.MaxPolicyNodes)
- {
- if (nodesRead == this.metadataImporter.Quotas.MaxPolicyNodes)
- {
- // add wirning once
- string warningMsg = SR.GetString(SR.ExceededMaxPolicyComplexity, node.Name, PolicyHelper.GetFragmentIdentifier((XmlElement)node));
- metadataImporter.PolicyWarningOccured.Invoke(contextAssertion, warningMsg);
- nodesRead++;
- }
- return EmptyEmpty;
- }
- nodesRead++;
- IEnumerable<IEnumerable<XmlElement>> nodes = EmptyEmpty;
- switch (PolicyHelper.GetNodeType(node))
- {
- case PolicyHelper.NodeType.Policy:
- case PolicyHelper.NodeType.All:
- nodes = ReadNode_PolicyOrAll((XmlElement)node, contextAssertion, yieldLimiter);
- break;
- case PolicyHelper.NodeType.ExactlyOne:
- nodes = ReadNode_ExactlyOne((XmlElement)node, contextAssertion, yieldLimiter);
- break;
- case PolicyHelper.NodeType.Assertion:
- nodes = ReadNode_Assertion((XmlElement)node, yieldLimiter);
- break;
- case PolicyHelper.NodeType.PolicyReference:
- nodes = ReadNode_PolicyReference((XmlElement)node, contextAssertion, yieldLimiter);
- break;
- case PolicyHelper.NodeType.UnrecognizedWSPolicy:
- string warningMsg = SR.GetString(SR.UnrecognizedPolicyElementInNamespace, node.Name, node.NamespaceURI);
- metadataImporter.PolicyWarningOccured.Invoke(contextAssertion, warningMsg);
- break;
- //consider [....], add more error handling here. default?
- }
- return nodes;
- }
- IEnumerable<IEnumerable<XmlElement>> ReadNode_PolicyReference(XmlElement element, XmlElement contextAssertion, YieldLimiter yieldLimiter)
- {
- string idRef = element.GetAttribute(MetadataStrings.WSPolicy.Attributes.URI);
- if (idRef == null)
- {
- string warningMsg = SR.GetString(SR.PolicyReferenceMissingURI, MetadataStrings.WSPolicy.Attributes.URI);
- metadataImporter.PolicyWarningOccured.Invoke(contextAssertion, warningMsg);
- return EmptyEmpty;
- }
- else if (idRef == string.Empty)
- {
- string warningMsg = SR.GetString(SR.PolicyReferenceInvalidId);
- metadataImporter.PolicyWarningOccured.Invoke(contextAssertion, warningMsg);
- return EmptyEmpty;
- }
- XmlElement policy = metadataImporter.ResolvePolicyReference(idRef, contextAssertion);
- if (policy == null)
- {
- string warningMsg = SR.GetString(SR.UnableToFindPolicyWithId, idRef);
- metadataImporter.PolicyWarningOccured.Invoke(contextAssertion, warningMsg);
- return EmptyEmpty;
- }
- //
- // Since we looked up a reference, the context assertion changes.
- //
- return ReadNode_PolicyOrAll(policy, policy, yieldLimiter);
- }
- IEnumerable<IEnumerable<XmlElement>> ReadNode_Assertion(XmlElement element, YieldLimiter yieldLimiter)
- {
- if (yieldLimiter.IncrementAndLogIfExceededLimit())
- yield return Empty;
- else
- yield return new PolicyHelper.SingleEnumerable<XmlElement>(element);
- }
- IEnumerable<IEnumerable<XmlElement>> ReadNode_ExactlyOne(XmlElement element, XmlElement contextAssertion, YieldLimiter yieldLimiter)
- {
- foreach (XmlNode child in element.ChildNodes)
- {
- if (child.NodeType == XmlNodeType.Element)
- {
- foreach (IEnumerable<XmlElement> alternative in ReadNode(child, contextAssertion, yieldLimiter))
- {
- if (yieldLimiter.IncrementAndLogIfExceededLimit())
- {
- yield break;
- }
- else
- {
- yield return alternative;
- }
- }
- }
- }
- }
- IEnumerable<IEnumerable<XmlElement>> ReadNode_PolicyOrAll(XmlElement element, XmlElement contextAssertion, YieldLimiter yieldLimiter)
- {
- IEnumerable<IEnumerable<XmlElement>> target = EmptyEmpty;
-
- foreach (XmlNode child in element.ChildNodes)
- {
- if (child.NodeType == XmlNodeType.Element)
- {
- IEnumerable<IEnumerable<XmlElement>> childPolicy = ReadNode(child, contextAssertion, yieldLimiter);
- target = PolicyHelper.CrossProduct<XmlElement>(target, childPolicy, yieldLimiter);
- }
- }
- return target;
- }
- internal IEnumerable<IEnumerable<XmlElement>> NormalizePolicy(IEnumerable<XmlElement> policyAssertions)
- {
- IEnumerable<IEnumerable<XmlElement>> target = EmptyEmpty;
- YieldLimiter yieldLimiter = new YieldLimiter(this.metadataImporter.Quotas.MaxYields, this.metadataImporter);
- foreach (XmlElement child in policyAssertions)
- {
- IEnumerable<IEnumerable<XmlElement>> childPolicy = ReadNode(child, child, yieldLimiter);
- target = PolicyHelper.CrossProduct<XmlElement>(target, childPolicy, yieldLimiter);
- }
- return target;
- }
- }
- internal class YieldLimiter
- {
- int maxYields;
- int yieldsHit;
- readonly MetadataImporter metadataImporter;
- internal YieldLimiter(int maxYields, MetadataImporter metadataImporter)
- {
- this.metadataImporter = metadataImporter;
- this.yieldsHit = 0;
- this.maxYields = maxYields;
- }
- internal bool IncrementAndLogIfExceededLimit()
- {
- if (++yieldsHit > maxYields)
- {
- string warningMsg = SR.GetString(SR.ExceededMaxPolicySize);
- metadataImporter.PolicyWarningOccured.Invoke(null, warningMsg);
- return true;
- }
- else
- {
- return false;
- }
- }
- }
- internal static class PolicyHelper
- {
-
- internal static string GetFragmentIdentifier(XmlElement element)
- {
- string id = element.GetAttribute(MetadataStrings.Wsu.Attributes.Id, MetadataStrings.Wsu.NamespaceUri);
- if (id == null)
- {
- id = element.GetAttribute(MetadataStrings.Xml.Attributes.Id, MetadataStrings.Xml.NamespaceUri);
- }
- if (string.IsNullOrEmpty(id))
- return string.Empty;
- else
- return string.Format(CultureInfo.InvariantCulture, "#{0}", id);
- }
- internal static bool IsPolicyURIs(XmlAttribute attribute)
- {
- return ((attribute.NamespaceURI == MetadataStrings.WSPolicy.NamespaceUri
- || attribute.NamespaceURI == MetadataStrings.WSPolicy.NamespaceUri15)
- && attribute.LocalName == MetadataStrings.WSPolicy.Attributes.PolicyURIs);
- }
- internal static NodeType GetNodeType(XmlNode node)
- {
- XmlElement currentElement = node as XmlElement;
- if (currentElement == null)
- return PolicyHelper.NodeType.NonElement;
- if (currentElement.NamespaceURI != MetadataStrings.WSPolicy.NamespaceUri
- && currentElement.NamespaceURI != MetadataStrings.WSPolicy.NamespaceUri15)
- return NodeType.Assertion;
- else if (currentElement.LocalName == MetadataStrings.WSPolicy.Elements.Policy)
- return NodeType.Policy;
- else if (currentElement.LocalName == MetadataStrings.WSPolicy.Elements.All)
- return NodeType.All;
- else if (currentElement.LocalName == MetadataStrings.WSPolicy.Elements.ExactlyOne)
- return NodeType.ExactlyOne;
- else if (currentElement.LocalName == MetadataStrings.WSPolicy.Elements.PolicyReference)
- return NodeType.PolicyReference;
- else
- return PolicyHelper.NodeType.UnrecognizedWSPolicy;
- }
- //
- // some helpers for dealing with ands of ors
- //
- internal static IEnumerable<IEnumerable<T>> CrossProduct<T>(IEnumerable<IEnumerable<T>> xs, IEnumerable<IEnumerable<T>> ys, YieldLimiter yieldLimiter)
- {
- foreach (IEnumerable<T> x in AtLeastOne<T>(xs, yieldLimiter))
- {
- foreach (IEnumerable<T> y in AtLeastOne<T>(ys, yieldLimiter))
- {
- if (yieldLimiter.IncrementAndLogIfExceededLimit())
- {
- yield break;
- }
- else
- {
- yield return Merge<T>(x, y, yieldLimiter);
- }
- }
- }
- }
- static IEnumerable<IEnumerable<T>> AtLeastOne<T>(IEnumerable<IEnumerable<T>> xs, YieldLimiter yieldLimiter)
- {
- bool gotOne = false;
- foreach (IEnumerable<T> x in xs)
- {
- gotOne = true;
- if (yieldLimiter.IncrementAndLogIfExceededLimit())
- {
- yield break;
- }
- else
- {
- yield return x;
- }
- }
- if (!gotOne)
- {
- if (yieldLimiter.IncrementAndLogIfExceededLimit())
- {
- yield break;
- }
- else
- {
- yield return new EmptyEnumerable<T>();
- }
- }
- }
- static IEnumerable<T> Merge<T>(IEnumerable<T> e1, IEnumerable<T> e2, YieldLimiter yieldLimiter)
- {
- foreach (T t1 in e1)
- {
- if (yieldLimiter.IncrementAndLogIfExceededLimit())
- {
- yield break;
- }
- else
- {
- yield return t1;
- }
-
- }
- foreach (T t2 in e2)
- {
- if (yieldLimiter.IncrementAndLogIfExceededLimit())
- {
- yield break;
- }
- else
- {
- yield return t2;
- }
- }
- }
- //
- // some helper enumerators
- //
- internal class EmptyEnumerable<T> : IEnumerable<T>, IEnumerator<T>
- {
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this.GetEnumerator();
- }
- public IEnumerator<T> GetEnumerator()
- {
- return this;
- }
- object IEnumerator.Current
- {
- get { return this.Current; }
- }
- public T Current
- {
- get
- {
- #pragma warning suppress 56503 // [....], IEnumerator guidelines, Current throws exception before calling MoveNext
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.NoValue0)));
- }
- }
- public bool MoveNext()
- {
- return false;
- }
- public void Dispose()
- {
- }
- void IEnumerator.Reset()
- {
- }
- }
- internal class SingleEnumerable<T> : IEnumerable<T>
- {
- T value;
- internal SingleEnumerable(T value)
- {
- this.value = value;
- }
- IEnumerator IEnumerable.GetEnumerator()
- {
- return this.GetEnumerator();
- }
- public IEnumerator<T> GetEnumerator()
- {
- yield return this.value;
- }
- }
- //
- // the NodeType enum
- //
- internal enum NodeType
- {
- NonElement,
- Policy,
- All,
- ExactlyOne,
- Assertion,
- PolicyReference,
- UnrecognizedWSPolicy,
- }
- }
- }
- }
|