1 //------------------------------------------------------------ 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //------------------------------------------------------------ 4 namespace System.ServiceModel.Dispatcher 5 { 6 using System.Diagnostics; 7 using System.ServiceModel.Channels; 8 using System.Collections; 9 using System.Collections.Generic; 10 using System.Collections.ObjectModel; 11 using System.Runtime.Serialization; 12 using System.Xml.XPath; 13 using System.ServiceModel.Diagnostics; 14 15 /// <summary> 16 /// Multi-reader, single writer 17 /// </summary> 18 [DataContract] 19 public class XPathMessageFilterTable<TFilterData> : IMessageFilterTable<TFilterData> 20 { 21 internal Dictionary<MessageFilter, TFilterData> filters; 22 InverseQueryMatcher iqMatcher; // inverse query matcher 23 XPathMessageFilterTable()24 public XPathMessageFilterTable() 25 { 26 Init(-1); 27 } 28 XPathMessageFilterTable(int capacity)29 public XPathMessageFilterTable(int capacity) 30 { 31 if (capacity < 0) 32 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("capacity", capacity, SR.GetString(SR.FilterCapacityNegative))); 33 34 Init(capacity); 35 } 36 37 [OnDeserializing] OnDeserializing(StreamingContext context)38 private void OnDeserializing(StreamingContext context) 39 { 40 Init(-1); 41 } 42 Init(int capacity)43 void Init(int capacity) 44 { 45 if (capacity <= 0) 46 this.filters = new Dictionary<MessageFilter, TFilterData>(); 47 else 48 this.filters = new Dictionary<MessageFilter, TFilterData>(capacity); 49 50 if (this.iqMatcher == null) 51 this.iqMatcher = new InverseQueryMatcher(true); 52 } 53 54 bool CanMatch 55 { 56 get 57 { 58 return (this.filters.Count > 0 && null != this.iqMatcher); 59 } 60 } 61 62 public TFilterData this[MessageFilter filter] 63 { 64 get 65 { 66 return this.filters[filter]; 67 } 68 set 69 { 70 if (this.filters.ContainsKey(filter)) 71 { 72 this.filters[filter] = value; 73 } 74 else 75 { 76 this.Add(filter, value); 77 } 78 } 79 } 80 81 public int Count 82 { 83 get 84 { 85 return this.filters.Count; 86 } 87 } 88 89 [DataMember] 90 Entry[] Entries 91 { 92 get 93 { 94 Entry[] entries = new Entry[Count]; 95 int i = 0; 96 foreach (KeyValuePair<MessageFilter, TFilterData> item in filters) 97 entries[i++] = new Entry(item.Key, item.Value); 98 99 return entries; 100 } 101 set 102 { 103 Init(value.Length); 104 105 for (int i = 0; i < value.Length; ++i) 106 Add(value[i].filter, value[i].data); 107 } 108 } 109 110 public bool IsReadOnly 111 { 112 get 113 { 114 return false; 115 } 116 } 117 118 public ICollection<MessageFilter> Keys 119 { 120 get 121 { 122 return this.filters.Keys; 123 } 124 } 125 126 /// <summary> 127 /// Some filters could be extremely expensive to evaluate or are very long running (infinite). A 128 /// filter table could have a very large number of relatively simple filters that taken as a whole would have 129 /// a very long running time. XPathFilters could be created using XPath off the wire, which may be malicious. 130 /// Since filters operate on Xml infosets, a natural and simple way to set computational limits on filter tables 131 /// is to specify the maximum # of nodes that should be looked at while evaluating ANY of the filters in this 132 /// table. 133 /// </summary> 134 [DataMember] 135 public int NodeQuota 136 { 137 get 138 { 139 //return (null == this.iqMatcher) ? int.MaxValue : this.iqMatcher.NodeQuota; 140 return this.iqMatcher.NodeQuota; 141 } 142 set 143 { 144 if (value <= 0) 145 { 146 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("NodeQuota", value, SR.GetString(SR.FilterQuotaRange))); 147 } 148 149 if (null == this.iqMatcher) 150 { 151 this.iqMatcher = new InverseQueryMatcher(true); 152 } 153 this.iqMatcher.NodeQuota = value; 154 } 155 } 156 157 public ICollection<TFilterData> Values 158 { 159 get 160 { 161 return this.filters.Values; 162 } 163 } 164 Add(MessageFilter filter, TFilterData data)165 public void Add(MessageFilter filter, TFilterData data) 166 { 167 this.Add((XPathMessageFilter)filter, data); 168 } 169 Add(KeyValuePair<MessageFilter, TFilterData> item)170 public void Add(KeyValuePair<MessageFilter, TFilterData> item) 171 { 172 this.Add(item.Key, item.Value); 173 } 174 Add(XPathMessageFilter filter, TFilterData data)175 public void Add(XPathMessageFilter filter, TFilterData data) 176 { 177 this.Add(filter, data, false); 178 } 179 Add(XPathMessageFilter filter, TFilterData data, bool forceExternal)180 internal void Add(XPathMessageFilter filter, TFilterData data, bool forceExternal) 181 { 182 if (null == filter) 183 { 184 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("filter"); 185 } 186 187 //this.EnsureMatcher(); 188 this.filters.Add(filter, data); 189 this.iqMatcher.Add(filter.XPath, filter.Namespaces, filter, forceExternal); 190 } 191 Clear()192 public void Clear() 193 { 194 this.iqMatcher.Clear(); 195 this.filters.Clear(); 196 } 197 Contains(KeyValuePair<MessageFilter, TFilterData> item)198 public bool Contains(KeyValuePair<MessageFilter, TFilterData> item) 199 { 200 return ((IDictionary<MessageFilter, TFilterData>)this.filters).Contains(item); 201 } 202 ContainsKey(MessageFilter filter)203 public bool ContainsKey(MessageFilter filter) 204 { 205 return this.filters.ContainsKey(filter); 206 } 207 CopyTo(KeyValuePair<MessageFilter, TFilterData>[] array, int arrayIndex)208 public void CopyTo(KeyValuePair<MessageFilter, TFilterData>[] array, int arrayIndex) 209 { 210 ((IDictionary<MessageFilter, TFilterData>)this.filters).CopyTo(array, arrayIndex); 211 } 212 213 #if NO EnsureMatcher()214 void EnsureMatcher() 215 { 216 if (null == this.iqMatcher) 217 { 218 this.iqMatcher = new InverseQueryMatcher(); 219 } 220 } 221 #endif 222 IEnumerable.GetEnumerator()223 IEnumerator IEnumerable.GetEnumerator() 224 { 225 return this.GetEnumerator(); 226 } 227 GetEnumerator()228 public IEnumerator<KeyValuePair<MessageFilter, TFilterData>> GetEnumerator() 229 { 230 return ((IDictionary<MessageFilter, TFilterData>)this.filters).GetEnumerator(); 231 } 232 GetMatchingValue(Message message, out TFilterData data)233 public bool GetMatchingValue(Message message, out TFilterData data) 234 { 235 if (null == message) 236 { 237 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message"); 238 } 239 240 if (this.CanMatch) 241 { 242 return this.ProcessMatch(this.iqMatcher.Match(message, false, null), out data); 243 } 244 245 data = default(TFilterData); 246 return false; 247 } 248 GetMatchingValue(MessageBuffer messageBuffer, out TFilterData data)249 public bool GetMatchingValue(MessageBuffer messageBuffer, out TFilterData data) 250 { 251 if (null == messageBuffer) 252 { 253 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("messageBuffer"); 254 } 255 256 if (this.CanMatch) 257 { 258 return this.ProcessMatch(this.iqMatcher.Match(messageBuffer, null), out data); 259 } 260 261 data = default(TFilterData); 262 return false; 263 } 264 GetMatchingValue(SeekableXPathNavigator navigator, out TFilterData data)265 public bool GetMatchingValue(SeekableXPathNavigator navigator, out TFilterData data) 266 { 267 if (null == navigator) 268 { 269 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("navigator"); 270 } 271 272 if (this.CanMatch) 273 { 274 return this.ProcessMatch(this.iqMatcher.Match(navigator, null), out data); 275 } 276 277 data = default(TFilterData); 278 return false; 279 } 280 GetMatchingValue(XPathNavigator navigator, out TFilterData data)281 public bool GetMatchingValue(XPathNavigator navigator, out TFilterData data) 282 { 283 if (null == navigator) 284 { 285 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("navigator"); 286 } 287 288 if (this.CanMatch) 289 { 290 return this.ProcessMatch(this.iqMatcher.Match(navigator, null), out data); 291 } 292 293 data = default(TFilterData); 294 return false; 295 } 296 GetMatchingFilter(Message message, out MessageFilter filter)297 public bool GetMatchingFilter(Message message, out MessageFilter filter) 298 { 299 Collection<MessageFilter> filters = new Collection<MessageFilter>(); 300 this.GetMatchingFilters(message, filters); 301 if (filters.Count > 1) 302 { 303 throw TraceUtility.ThrowHelperError(new MultipleFilterMatchesException(SR.GetString(SR.FilterMultipleMatches), null, filters), message); 304 } 305 else if (filters.Count == 1) 306 { 307 filter = filters[0]; 308 return true; 309 } 310 else 311 { 312 filter = null; 313 return false; 314 } 315 } 316 GetMatchingFilter(MessageBuffer messageBuffer, out MessageFilter filter)317 public bool GetMatchingFilter(MessageBuffer messageBuffer, out MessageFilter filter) 318 { 319 Collection<MessageFilter> filters = new Collection<MessageFilter>(); 320 this.GetMatchingFilters(messageBuffer, filters); 321 if (filters.Count > 1) 322 { 323 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MultipleFilterMatchesException(SR.GetString(SR.FilterMultipleMatches), null, filters)); 324 } 325 else if (filters.Count == 1) 326 { 327 filter = filters[0]; 328 return true; 329 } 330 else 331 { 332 filter = null; 333 return false; 334 } 335 } 336 GetMatchingFilter(SeekableXPathNavigator navigator, out MessageFilter filter)337 public bool GetMatchingFilter(SeekableXPathNavigator navigator, out MessageFilter filter) 338 { 339 Collection<MessageFilter> filters = new Collection<MessageFilter>(); 340 this.GetMatchingFilters(navigator, filters); 341 if (filters.Count > 1) 342 { 343 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MultipleFilterMatchesException(SR.GetString(SR.FilterMultipleMatches), null, filters)); 344 } 345 else if (filters.Count == 1) 346 { 347 filter = filters[0]; 348 return true; 349 } 350 else 351 { 352 filter = null; 353 return false; 354 } 355 } 356 GetMatchingFilter(XPathNavigator navigator, out MessageFilter filter)357 public bool GetMatchingFilter(XPathNavigator navigator, out MessageFilter filter) 358 { 359 Collection<MessageFilter> filters = new Collection<MessageFilter>(); 360 this.GetMatchingFilters(navigator, filters); 361 if (filters.Count > 1) 362 { 363 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MultipleFilterMatchesException(SR.GetString(SR.FilterMultipleMatches), null, filters)); 364 } 365 else if (filters.Count == 1) 366 { 367 filter = filters[0]; 368 return true; 369 } 370 else 371 { 372 filter = null; 373 return false; 374 } 375 } 376 GetMatchingFilters(Message message, ICollection<MessageFilter> results)377 public bool GetMatchingFilters(Message message, ICollection<MessageFilter> results) 378 { 379 if (null == message) 380 { 381 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message"); 382 } 383 if (null == results) 384 { 385 throw TraceUtility.ThrowHelperArgumentNull("results", message); 386 } 387 388 if (this.CanMatch) 389 { 390 int count = results.Count; 391 this.iqMatcher.ReleaseResult(this.iqMatcher.Match(message, false, results)); 392 return count != results.Count; 393 } 394 return false; 395 } 396 GetMatchingFilters(MessageBuffer messageBuffer, ICollection<MessageFilter> results)397 public bool GetMatchingFilters(MessageBuffer messageBuffer, ICollection<MessageFilter> results) 398 { 399 if (null == messageBuffer) 400 { 401 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("messageBuffer"); 402 } 403 if (null == results) 404 { 405 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("results"); 406 } 407 408 if (this.CanMatch) 409 { 410 int count = results.Count; 411 this.iqMatcher.ReleaseResult(iqMatcher.Match(messageBuffer, results)); 412 return count != results.Count; 413 } 414 return false; 415 } 416 GetMatchingFilters(SeekableXPathNavigator navigator, ICollection<MessageFilter> results)417 public bool GetMatchingFilters(SeekableXPathNavigator navigator, ICollection<MessageFilter> results) 418 { 419 if (null == navigator) 420 { 421 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("navigator"); 422 } 423 if (null == results) 424 { 425 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("results"); 426 } 427 428 if (this.CanMatch) 429 { 430 int count = results.Count; 431 this.iqMatcher.ReleaseResult(this.iqMatcher.Match(navigator, results)); 432 return count != results.Count; 433 } 434 return false; 435 } 436 GetMatchingFilters(XPathNavigator navigator, ICollection<MessageFilter> results)437 public bool GetMatchingFilters(XPathNavigator navigator, ICollection<MessageFilter> results) 438 { 439 if (null == navigator) 440 { 441 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("navigator"); 442 } 443 if (null == results) 444 { 445 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("results"); 446 } 447 448 if (this.CanMatch) 449 { 450 int count = results.Count; 451 this.iqMatcher.ReleaseResult(this.iqMatcher.Match(navigator, results)); 452 return count != results.Count; 453 } 454 return false; 455 } 456 GetMatchingValues(Message message, ICollection<TFilterData> results)457 public bool GetMatchingValues(Message message, ICollection<TFilterData> results) 458 { 459 if (null == message) 460 { 461 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message"); 462 } 463 if (null == results) 464 { 465 throw TraceUtility.ThrowHelperArgumentNull("results", message); 466 } 467 468 if (this.CanMatch) 469 { 470 int count = results.Count; 471 this.ProcessMatches(this.iqMatcher.Match(message, false, null), results); 472 return count != results.Count; 473 } 474 return false; 475 } 476 GetMatchingValues(MessageBuffer messageBuffer, ICollection<TFilterData> results)477 public bool GetMatchingValues(MessageBuffer messageBuffer, ICollection<TFilterData> results) 478 { 479 if (null == messageBuffer) 480 { 481 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("messageBuffer"); 482 } 483 if (null == results) 484 { 485 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("results"); 486 } 487 488 if (this.CanMatch) 489 { 490 int count = results.Count; 491 this.ProcessMatches(this.iqMatcher.Match(messageBuffer, null), results); 492 return count != results.Count; 493 } 494 return false; 495 } 496 GetMatchingValues(SeekableXPathNavigator navigator, ICollection<TFilterData> results)497 public bool GetMatchingValues(SeekableXPathNavigator navigator, ICollection<TFilterData> results) 498 { 499 if (null == navigator) 500 { 501 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("navigator"); 502 } 503 if (null == results) 504 { 505 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("results"); 506 } 507 508 if (this.CanMatch) 509 { 510 int count = results.Count; 511 this.ProcessMatches(this.iqMatcher.Match(navigator, null), results); 512 return count != results.Count; 513 } 514 return false; 515 } 516 GetMatchingValues(XPathNavigator navigator, ICollection<TFilterData> results)517 public bool GetMatchingValues(XPathNavigator navigator, ICollection<TFilterData> results) 518 { 519 if (null == navigator) 520 { 521 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("navigator"); 522 } 523 if (null == results) 524 { 525 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("results"); 526 } 527 528 if (this.CanMatch) 529 { 530 int count = results.Count; 531 this.ProcessMatches(this.iqMatcher.Match(navigator, null), results); 532 return count != results.Count; 533 } 534 return false; 535 } 536 ProcessMatch(FilterResult result, out TFilterData data)537 bool ProcessMatch(FilterResult result, out TFilterData data) 538 { 539 bool retVal = false; 540 data = default(TFilterData); 541 MessageFilter match = result.GetSingleMatch(); 542 if (null != match) 543 { 544 data = this.filters[match]; 545 retVal = true; 546 } 547 this.iqMatcher.ReleaseResult(result); 548 return retVal; 549 } 550 ProcessMatches(FilterResult result, ICollection<TFilterData> results)551 void ProcessMatches(FilterResult result, ICollection<TFilterData> results) 552 { 553 Collection<MessageFilter> matches = result.Processor.MatchList; 554 for (int i = 0, count = matches.Count; i < count; ++i) 555 { 556 results.Add(this.filters[matches[i]]); 557 } 558 this.iqMatcher.ReleaseResult(result); 559 } 560 Remove(MessageFilter filter)561 public bool Remove(MessageFilter filter) 562 { 563 if (null == filter) 564 { 565 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("filter"); 566 } 567 568 XPathMessageFilter xpf = filter as XPathMessageFilter; 569 if (xpf != null) 570 { 571 return this.Remove(xpf); 572 } 573 return false; 574 } 575 Remove(KeyValuePair<MessageFilter, TFilterData> item)576 public bool Remove(KeyValuePair<MessageFilter, TFilterData> item) 577 { 578 if (((IDictionary<MessageFilter, TFilterData>)this.filters).Remove(item)) 579 { 580 this.iqMatcher.Remove((XPathMessageFilter)item.Key); 581 return true; 582 } 583 584 return false; 585 } 586 Remove(XPathMessageFilter filter)587 public bool Remove(XPathMessageFilter filter) 588 { 589 if (null == filter) 590 { 591 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("filter"); 592 } 593 594 if (this.filters.Remove(filter)) 595 { 596 this.iqMatcher.Remove(filter); 597 return true; 598 } 599 600 // Not in this table 601 return false; 602 } 603 TrimToSize()604 public void TrimToSize() 605 { 606 this.iqMatcher.Trim(); 607 } 608 TryGetValue(MessageFilter filter, out TFilterData data)609 public bool TryGetValue(MessageFilter filter, out TFilterData data) 610 { 611 return this.filters.TryGetValue(filter, out data); 612 } 613 614 [DataContract] 615 class Entry 616 { 617 [DataMember(IsRequired = true)] 618 internal MessageFilter filter; 619 620 [DataMember(IsRequired = true)] 621 internal TFilterData data; 622 Entry(MessageFilter f, TFilterData d)623 internal Entry(MessageFilter f, TFilterData d) 624 { 625 filter = f; 626 data = d; 627 } 628 } 629 } 630 } 631