EndpointAddressProcessor.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Globalization;
  9. using System.Runtime;
  10. using System.ServiceModel;
  11. using System.ServiceModel.Channels;
  12. using System.Text;
  13. using System.Xml;
  14. using System.Xml.Schema;
  15. class EndpointAddressProcessor
  16. {
  17. internal static readonly QNameKeyComparer QNameComparer = new QNameKeyComparer();
  18. // QName Attributes
  19. internal static readonly string XsiNs = XmlSchema.InstanceNamespace;
  20. internal const string SerNs = "http://schemas.microsoft.com/2003/10/Serialization/";
  21. internal const string TypeLN = "type";
  22. internal const string ItemTypeLN = "ItemType";
  23. internal const string FactoryTypeLN = "FactoryType";
  24. // Pooling
  25. internal EndpointAddressProcessor next;
  26. StringBuilder builder;
  27. byte[] resultData;
  28. internal EndpointAddressProcessor(int length)
  29. {
  30. this.builder = new StringBuilder();
  31. this.resultData = new byte[length];
  32. }
  33. internal EndpointAddressProcessor Next
  34. {
  35. get
  36. {
  37. return this.next;
  38. }
  39. set
  40. {
  41. this.next = value;
  42. }
  43. }
  44. internal static string GetComparableForm(StringBuilder builder, XmlReader reader)
  45. {
  46. List<Attr> attrSet = new List<Attr>();
  47. int valueLength = -1;
  48. while (!reader.EOF)
  49. {
  50. XmlNodeType type = reader.MoveToContent();
  51. switch (type)
  52. {
  53. case XmlNodeType.Element:
  54. CompleteValue(builder, valueLength);
  55. valueLength = -1;
  56. builder.Append("<");
  57. AppendString(builder, reader.LocalName);
  58. builder.Append(":");
  59. AppendString(builder, reader.NamespaceURI);
  60. builder.Append(" ");
  61. // Scan attributes
  62. attrSet.Clear();
  63. if (reader.MoveToFirstAttribute())
  64. {
  65. do
  66. {
  67. // Ignore namespaces
  68. if (reader.Prefix == "xmlns" || reader.Name == "xmlns")
  69. {
  70. continue;
  71. }
  72. if (reader.LocalName == AddressingStrings.IsReferenceParameter && reader.NamespaceURI == Addressing10Strings.Namespace)
  73. {
  74. continue; // ignore IsReferenceParameter
  75. }
  76. string val = reader.Value;
  77. if ((reader.LocalName == TypeLN && reader.NamespaceURI == XsiNs) ||
  78. (reader.NamespaceURI == SerNs && (reader.LocalName == ItemTypeLN || reader.LocalName == FactoryTypeLN)))
  79. {
  80. string local, ns;
  81. XmlUtil.ParseQName(reader, val, out local, out ns);
  82. val = local + "^" + local.Length.ToString(CultureInfo.InvariantCulture) + ":" + ns + "^" + ns.Length.ToString(CultureInfo.InvariantCulture);
  83. }
  84. else if (reader.LocalName == XD.UtilityDictionary.IdAttribute.Value && reader.NamespaceURI == XD.UtilityDictionary.Namespace.Value)
  85. {
  86. // ignore wsu:Id attributes added by security to sign the header
  87. continue;
  88. }
  89. attrSet.Add(new Attr(reader.LocalName, reader.NamespaceURI, val));
  90. } while (reader.MoveToNextAttribute());
  91. }
  92. reader.MoveToElement();
  93. if (attrSet.Count > 0)
  94. {
  95. attrSet.Sort();
  96. for (int i = 0; i < attrSet.Count; ++i)
  97. {
  98. Attr a = attrSet[i];
  99. AppendString(builder, a.local);
  100. builder.Append(":");
  101. AppendString(builder, a.ns);
  102. builder.Append("=\"");
  103. AppendString(builder, a.val);
  104. builder.Append("\" ");
  105. }
  106. }
  107. if (reader.IsEmptyElement)
  108. builder.Append("></>"); // Should be the same as an empty tag.
  109. else
  110. builder.Append(">");
  111. break;
  112. case XmlNodeType.EndElement:
  113. CompleteValue(builder, valueLength);
  114. valueLength = -1;
  115. builder.Append("</>");
  116. break;
  117. // Need to escape CDATA values
  118. case XmlNodeType.CDATA:
  119. CompleteValue(builder, valueLength);
  120. valueLength = -1;
  121. builder.Append("<![CDATA[");
  122. AppendString(builder, reader.Value);
  123. builder.Append("]]>");
  124. break;
  125. case XmlNodeType.SignificantWhitespace:
  126. case XmlNodeType.Text:
  127. if (valueLength < 0)
  128. valueLength = builder.Length;
  129. builder.Append(reader.Value);
  130. break;
  131. default:
  132. // Do nothing
  133. break;
  134. }
  135. reader.Read();
  136. }
  137. return builder.ToString();
  138. }
  139. static void AppendString(StringBuilder builder, string s)
  140. {
  141. builder.Append(s);
  142. builder.Append("^");
  143. builder.Append(s.Length.ToString(CultureInfo.InvariantCulture));
  144. }
  145. static void CompleteValue(StringBuilder builder, int startLength)
  146. {
  147. if (startLength < 0)
  148. return;
  149. int len = builder.Length - startLength;
  150. builder.Append("^");
  151. builder.Append(len.ToString(CultureInfo.InvariantCulture));
  152. }
  153. internal void Clear(int length)
  154. {
  155. if (this.resultData.Length == length)
  156. {
  157. Array.Clear(this.resultData, 0, this.resultData.Length);
  158. }
  159. else
  160. {
  161. this.resultData = new byte[length];
  162. }
  163. }
  164. internal void ProcessHeaders(Message msg, Dictionary<QName, int> qnameLookup, Dictionary<string, HeaderBit[]> headerLookup)
  165. {
  166. string key;
  167. HeaderBit[] bits;
  168. QName qname;
  169. MessageHeaders headers = msg.Headers;
  170. for (int j = 0; j < headers.Count; ++j)
  171. {
  172. qname.name = headers[j].Name;
  173. qname.ns = headers[j].Namespace;
  174. if (headers.MessageVersion.Addressing == AddressingVersion.WSAddressing10
  175. && !headers[j].IsReferenceParameter)
  176. {
  177. continue;
  178. }
  179. if (qnameLookup.ContainsKey(qname))
  180. {
  181. builder.Remove(0, builder.Length);
  182. XmlReader reader = headers.GetReaderAtHeader(j).ReadSubtree();
  183. reader.Read(); // Needed after call to ReadSubtree
  184. key = GetComparableForm(builder, reader);
  185. if (headerLookup.TryGetValue(key, out bits))
  186. {
  187. SetBit(bits);
  188. }
  189. }
  190. }
  191. }
  192. internal void SetBit(HeaderBit[] bits)
  193. {
  194. if (bits.Length == 1)
  195. {
  196. this.resultData[bits[0].index] |= bits[0].mask;
  197. }
  198. else
  199. {
  200. byte[] results = this.resultData;
  201. for (int i = 0; i < bits.Length; ++i)
  202. {
  203. if ((results[bits[i].index] & bits[i].mask) == 0)
  204. {
  205. results[bits[i].index] |= bits[i].mask;
  206. break;
  207. }
  208. }
  209. }
  210. }
  211. internal bool TestExact(byte[] exact)
  212. {
  213. Fx.Assert(this.resultData.Length == exact.Length, "");
  214. byte[] results = this.resultData;
  215. for (int i = 0; i < exact.Length; ++i)
  216. {
  217. if (results[i] != exact[i])
  218. {
  219. return false;
  220. }
  221. }
  222. return true;
  223. }
  224. internal bool TestMask(byte[] mask)
  225. {
  226. if (mask == null)
  227. {
  228. return true;
  229. }
  230. byte[] results = this.resultData;
  231. for (int i = 0; i < mask.Length; ++i)
  232. {
  233. if ((results[i] & mask[i]) != mask[i])
  234. {
  235. return false;
  236. }
  237. }
  238. return true;
  239. }
  240. internal struct QName
  241. {
  242. internal string name;
  243. internal string ns;
  244. }
  245. internal class QNameKeyComparer : IComparer<QName>, IEqualityComparer<QName>
  246. {
  247. internal QNameKeyComparer()
  248. {
  249. }
  250. public int Compare(QName x, QName y)
  251. {
  252. int i = string.CompareOrdinal(x.name, y.name);
  253. if (i != 0)
  254. return i;
  255. return string.CompareOrdinal(x.ns, y.ns);
  256. }
  257. public bool Equals(QName x, QName y)
  258. {
  259. int i = string.CompareOrdinal(x.name, y.name);
  260. if (i != 0)
  261. return false;
  262. return string.CompareOrdinal(x.ns, y.ns) == 0;
  263. }
  264. public int GetHashCode(QName obj)
  265. {
  266. return obj.name.GetHashCode() ^ obj.ns.GetHashCode();
  267. }
  268. }
  269. internal struct HeaderBit
  270. {
  271. internal int index;
  272. internal byte mask;
  273. internal HeaderBit(int bitNum)
  274. {
  275. this.index = bitNum / 8;
  276. this.mask = (byte)(1 << (bitNum % 8));
  277. }
  278. internal void AddToMask(ref byte[] mask)
  279. {
  280. if (mask == null)
  281. {
  282. mask = new byte[this.index + 1];
  283. }
  284. else if (mask.Length <= this.index)
  285. {
  286. Array.Resize(ref mask, this.index + 1);
  287. }
  288. mask[this.index] |= this.mask;
  289. }
  290. }
  291. class Attr : IComparable<Attr>
  292. {
  293. internal string local;
  294. internal string ns;
  295. internal string val;
  296. string key;
  297. internal Attr(string l, string ns, string v)
  298. {
  299. this.local = l;
  300. this.ns = ns;
  301. this.val = v;
  302. this.key = ns + ":" + l;
  303. }
  304. public int CompareTo(Attr a)
  305. {
  306. return string.Compare(this.key, a.key, StringComparison.Ordinal);
  307. }
  308. }
  309. }
  310. }