2 Copyright (c) Microsoft Corporation
9 This internal class implements a static mutlithreaded dictionary for user-registered SPNs.
10 An SPN is mapped based on a Uri prefix that contains scheme, host and port.
15 Alexei Vopilov 15-Nov-2003
21 namespace System.Net {
23 using System.Collections;
24 using System.Collections.Specialized;
25 using System.Security.Permissions;
27 internal class SpnDictionary : StringDictionary {
30 //A Hashtable can support one writer and multiple readers concurrently
33 // Maps Uri keys to SpnToken values. The SpnTokens should not be exposed publicly.
34 private Hashtable m_SyncTable = Hashtable.Synchronized(new Hashtable());
35 private ValueCollection m_ValuesWrapper;
39 internal SpnDictionary():base() {
44 public override int Count {
47 ExceptionHelper.WebPermissionUnrestricted.Demand();
49 return m_SyncTable.Count;
55 public override bool IsSynchronized {
61 // Internal lookup, bypasses security checks
63 internal SpnToken InternalGet(string canonicalKey)
68 // This lock is required to avoid getting InvalidOperationException
69 // because the collection was modified during enumeration. By design
70 // a Synchronized Hashtable throws if modifications occur while an
71 // enumeration is in progress. Manually locking the Hashtable to
72 // prevent modification during enumeration is the best solution.
73 // Catching the exception and retrying could potentially never
74 // succeed in the face of significant updates.
75 lock (m_SyncTable.SyncRoot) {
76 foreach (object o in m_SyncTable.Keys){
77 string s = (string) o;
78 if(s != null && s.Length > lastLength){
79 if(String.Compare(s,0,canonicalKey,0,s.Length,StringComparison.OrdinalIgnoreCase) == 0){
80 lastLength = s.Length;
86 return (key != null) ? (SpnToken)m_SyncTable[key] : null;
89 internal void InternalSet(string canonicalKey, SpnToken spnToken)
91 m_SyncTable[canonicalKey] = spnToken;
94 // Public lookup method
96 public override string this[string key] {
98 key = GetCanonicalKey(key);
99 SpnToken token = InternalGet(key);
100 return (token == null ? null : token.Spn);
103 key = GetCanonicalKey(key);
105 InternalSet(key, new SpnToken(value));
109 public override ICollection Keys {
112 ExceptionHelper.WebPermissionUnrestricted.Demand();
114 return m_SyncTable.Keys;
118 public override object SyncRoot {
119 [HostProtection(Synchronization=true)]
122 ExceptionHelper.WebPermissionUnrestricted.Demand();
128 public override ICollection Values {
131 ExceptionHelper.WebPermissionUnrestricted.Demand();
133 if (m_ValuesWrapper == null)
135 m_ValuesWrapper = new ValueCollection(this);
137 return m_ValuesWrapper;
141 public override void Add(string key, string value) {
142 key = GetCanonicalKey(key);
143 m_SyncTable.Add(key, new SpnToken(value));
146 public override void Clear() {
148 ExceptionHelper.WebPermissionUnrestricted.Demand();
153 public override bool ContainsKey(string key) {
154 key = GetCanonicalKey(key);
155 return m_SyncTable.ContainsKey(key);
158 public override bool ContainsValue(string value) {
160 ExceptionHelper.WebPermissionUnrestricted.Demand();
162 foreach (SpnToken spnToken in m_SyncTable.Values)
164 if (spnToken.Spn == value)
170 // We have to unwrap the SpnKey and just expose the Spn
171 public override void CopyTo(Array array, int index) {
173 ExceptionHelper.WebPermissionUnrestricted.Demand();
175 CheckCopyToArguments(array, index, Count);
178 foreach (object entry in this)
180 array.SetValue(entry, offset + index);
185 public override IEnumerator GetEnumerator() {
187 ExceptionHelper.WebPermissionUnrestricted.Demand();
190 foreach (string key in m_SyncTable.Keys)
192 // We must unwrap the SpnToken and not expose it publicly
193 SpnToken spnToken = (SpnToken)m_SyncTable[key];
194 yield return new DictionaryEntry(key, spnToken.Spn);
198 public override void Remove(string key) {
199 key = GetCanonicalKey(key);
200 m_SyncTable.Remove(key);
204 // Private stuff: We want to serialize on updates on one thread
206 private static string GetCanonicalKey(string key)
209 throw new ArgumentNullException("key");
212 Uri uri = new Uri(key);
213 key = uri.GetParts(UriComponents.Scheme | UriComponents.Host | UriComponents.Port | UriComponents.Path, UriFormat.SafeUnescaped);
215 new WebPermission(NetworkAccess.Connect, new Uri(key)).Demand();
218 catch(UriFormatException e) {
219 throw new ArgumentException(SR.GetString(SR.net_mustbeuri, "key"), "key", e);
224 private static void CheckCopyToArguments(Array array, int index, int count)
226 // Coppied from HashTable.CopyTo
229 throw new ArgumentNullException("array");
233 throw new ArgumentException(SR.GetString(SR.Arg_RankMultiDimNotSupported));
237 throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNum));
239 if ((array.Length - index) < count)
241 throw new ArgumentException(SR.GetString(SR.Arg_ArrayPlusOffTooSmall));
245 // Wrap HashTable.Values so we can unwrap the SpnTokens
246 private class ValueCollection : ICollection
248 private SpnDictionary spnDictionary;
250 internal ValueCollection(SpnDictionary spnDictionary)
252 this.spnDictionary = spnDictionary;
255 public void CopyTo(Array array, int index)
257 CheckCopyToArguments(array, index, Count);
260 foreach (object entry in this)
262 array.SetValue(entry, offset + index);
269 get { return spnDictionary.m_SyncTable.Values.Count; }
272 public bool IsSynchronized
277 public object SyncRoot
279 get { return spnDictionary.m_SyncTable.SyncRoot; }
282 public IEnumerator GetEnumerator()
284 foreach (SpnToken spnToken in spnDictionary.m_SyncTable.Values)
286 yield return (spnToken != null ? spnToken.Spn : null);
292 internal class SpnToken
294 private readonly string spn;
295 private bool isTrusted;
297 // Assume the spn is trusted unless a specific reason is found not to trust it.
298 internal bool IsTrusted
300 get { return isTrusted; }
301 set { isTrusted = false; }
309 internal SpnToken(string spn)
313 internal SpnToken(string spn, bool trusted)
316 this.isTrusted = trusted;