DBConnectionString.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Data / System / Data / Common / DBConnectionString.cs / 1 / DBConnectionString.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
#if ORACLE
namespace System.Data.OracleClient { 
#else
namespace System.Data.Common {
#endif
 
    using System;
    using System.Collections; 
    using System.Collections.Generic; 
    using System.Data;
    using System.Data.Common; 
    using System.Diagnostics;
    using System.Globalization;
    using System.Runtime.Serialization;
    using System.Security.Permissions; 
    using System.Text;
    using System.Text.RegularExpressions; 
 
    [Serializable] // MDAC 83147
    internal sealed class DBConnectionString { 
        // instances of this class are intended to be immutable, i.e readonly
        // used by permission classes so it is much easier to verify correctness
        // when not worried about the class being modified during execution
 
        private static class KEY {
            internal const string Password            = "password"; 
            internal const string PersistSecurityInfo = "persist security info"; 
            internal const string Pwd                 = "pwd";
        }; 

        // this class is serializable with Everett, so ugly field names can't be changed
        readonly private string        _encryptedUsersConnectionString;
 
        // hash of unique keys to values
        readonly private Hashtable     _parsetable; 
 
        // a linked list of key/value and their length in _encryptedUsersConnectionString
        readonly private NameValuePair _keychain; 

        // track the existance of "password" or "pwd" in the connection string
        // not used for anything anymore but must keep it set correct for V1.1 serialization
        readonly private bool          _hasPassword; 

        readonly private string[] _restrictionValues; 
        readonly private string   _restrictions; 

        readonly private KeyRestrictionBehavior _behavior; 

#pragma warning disable 169
        // this field is no longer used, hence the warning was disabled
        // however, it can not be removed or it will break serialization with V1.1 
        readonly private string _encryptedActualConnectionString;
#pragma warning restore 169 
 
        internal DBConnectionString(string value, string restrictions, KeyRestrictionBehavior behavior, Hashtable synonyms, bool useOdbcRules)
            : this(new DbConnectionOptions(value, synonyms, useOdbcRules), restrictions, behavior, synonyms, false) 
        {
            // useOdbcRules is only used to parse the connection string, not to parse restrictions because values don't apply there
            // the hashtable doesn't need clone since it isn't shared with anything else
        } 

        internal DBConnectionString(DbConnectionOptions connectionOptions) 
            : this(connectionOptions, (string)null, KeyRestrictionBehavior.AllowOnly, (Hashtable)null, true) 
        {
            // used by DBDataPermission to convert from DbConnectionOptions to DBConnectionString 
            // since backward compatability requires Everett level classes
        }

        private DBConnectionString(DbConnectionOptions connectionOptions, string restrictions, KeyRestrictionBehavior behavior, Hashtable synonyms, bool mustCloneDictionary) { // used by DBDataPermission 
            Debug.Assert(null != connectionOptions, "null connectionOptions");
            switch(behavior) { 
            case KeyRestrictionBehavior.PreventUsage: 
            case KeyRestrictionBehavior.AllowOnly:
                _behavior = behavior; 
                break;
            default:
                throw ADP.InvalidKeyRestrictionBehavior(behavior);
            } 

            // grab all the parsed details from DbConnectionOptions 
            _encryptedUsersConnectionString = connectionOptions.UsersConnectionString(false); 
            _hasPassword = connectionOptions.HasPasswordKeyword;
            _parsetable = connectionOptions.Parsetable; 
            _keychain = connectionOptions.KeyChain;

            // we do not want to serialize out user password unless directed so by "persist security info=true"
            // otherwise all instances of user's password will be replaced with "*" 
            if (_hasPassword && !connectionOptions.HasPersistablePassword) {
 
                if (mustCloneDictionary) { 
                    // clone the hashtable to replace user's password/pwd value with "*"
                    // we only need to clone if coming from DbConnectionOptions and password exists 
                    _parsetable = (Hashtable) _parsetable.Clone();
                }

                // different than Everett in that instead of removing password/pwd from 
                // the hashtable, we replace the value with '*'.  This is okay since we
                // serialize out with '*' so already knows what we do.  Better this way 
                // than to treat password specially later on which causes problems. 
                const string star = "*";
                if (_parsetable.ContainsKey(KEY.Password)) { 
                    _parsetable[KEY.Password] = star;
                }
                if (_parsetable.ContainsKey(KEY.Pwd)) {
                    _parsetable[KEY.Pwd] = star; 
                }
 
                // replace user's password/pwd value with "*" in the linked list and build a new string 
                _keychain = connectionOptions.ReplacePasswordPwd(out _encryptedUsersConnectionString, true);
            } 

            if (!ADP.IsEmpty(restrictions)) {
                _restrictionValues = ParseRestrictions(restrictions, synonyms);
                _restrictions = restrictions; 
            }
        } 
 
        private DBConnectionString(DBConnectionString connectionString, string[] restrictionValues, KeyRestrictionBehavior behavior) {
            // used by intersect for two equal connection strings with different restrictions 
            _encryptedUsersConnectionString = connectionString._encryptedUsersConnectionString;
            _parsetable = connectionString._parsetable;
            _keychain = connectionString._keychain;
            _hasPassword = connectionString._hasPassword; 

            _restrictionValues = restrictionValues; 
            _restrictions = null; 
            _behavior = behavior;
 
            Verify(restrictionValues);
        }

        internal KeyRestrictionBehavior Behavior { 
            get { return _behavior; }
        } 
 
        internal string ConnectionString {
            get { return _encryptedUsersConnectionString; } 
        }

        internal bool IsEmpty {
            get { return (null == _keychain); } 
        }
 
        internal NameValuePair KeyChain { 
            get { return _keychain; }
        } 

        internal string Restrictions {
            get {
                string restrictions = _restrictions; 
                if (null == restrictions) {
                    string[] restrictionValues = _restrictionValues; 
                    if ((null != restrictionValues) && (0 < restrictionValues.Length)) { 
                        StringBuilder builder = new StringBuilder();
                        for(int i = 0; i < restrictionValues.Length; ++i) { 
                            if (!ADP.IsEmpty(restrictionValues[i])) {
                                builder.Append(restrictionValues[i]);
                                builder.Append("=;");
                            } 
#if DEBUG
                            else { 
                                Debug.Assert(false, "empty restriction"); 
                            }
#endif 
                        }
                        restrictions = builder.ToString();
                    }
                } 
                return ((null != restrictions) ? restrictions: "");
            } 
        } 

        internal string this[string keyword] { 
            get { return (string)_parsetable[keyword]; }
        }

        internal bool ContainsKey(string keyword) { 
            return _parsetable.ContainsKey(keyword);
        } 
 
        internal DBConnectionString Intersect(DBConnectionString entry) {
            KeyRestrictionBehavior behavior = _behavior; 
            string[] restrictionValues = null;

            if (null == entry) {
                //Debug.WriteLine("0 entry AllowNothing"); 
                behavior = KeyRestrictionBehavior.AllowOnly;
            } 
            else if (this._behavior != entry._behavior) { // subset of the AllowOnly array 
                behavior = KeyRestrictionBehavior.AllowOnly;
 
                if (KeyRestrictionBehavior.AllowOnly == entry._behavior) { // this PreventUsage and entry AllowOnly
                    if (!ADP.IsEmptyArray(_restrictionValues)) {
                        if (!ADP.IsEmptyArray(entry._restrictionValues)) {
                            //Debug.WriteLine("1 this PreventUsage with restrictions and entry AllowOnly with restrictions"); 
                            restrictionValues = NewRestrictionAllowOnly(entry._restrictionValues, _restrictionValues);
                        } 
                        else { 
                            //Debug.WriteLine("2 this PreventUsage with restrictions and entry AllowOnly with no restrictions");
                        } 
                    }
                    else {
                        //Debug.WriteLine("3/4 this PreventUsage with no restrictions and entry AllowOnly");
                        restrictionValues = entry._restrictionValues; 
                    }
                } 
                else if (!ADP.IsEmptyArray(_restrictionValues)) { // this AllowOnly and entry PreventUsage 
                    if (!ADP.IsEmptyArray(entry._restrictionValues)) {
                        //Debug.WriteLine("5 this AllowOnly with restrictions and entry PreventUsage with restrictions"); 
                        restrictionValues = NewRestrictionAllowOnly(_restrictionValues, entry._restrictionValues);
                    }
                    else {
                        //Debug.WriteLine("6 this AllowOnly and entry PreventUsage with no restrictions"); 
                        restrictionValues = _restrictionValues;
                    } 
                } 
                else {
                    //Debug.WriteLine("7/8 this AllowOnly with no restrictions and entry PreventUsage"); 
                }
            }
            else if (KeyRestrictionBehavior.PreventUsage == this._behavior) { // both PreventUsage
                if (ADP.IsEmptyArray(_restrictionValues)) { 
                    //Debug.WriteLine("9/10 both PreventUsage and this with no restrictions");
                    restrictionValues = entry._restrictionValues; 
                } 
                else if (ADP.IsEmptyArray(entry._restrictionValues)) {
                    //Debug.WriteLine("11 both PreventUsage and entry with no restrictions"); 
                    restrictionValues = _restrictionValues;
                }
                else {
                    //Debug.WriteLine("12 both PreventUsage with restrictions"); 
                    restrictionValues = NoDuplicateUnion(_restrictionValues, entry._restrictionValues);
                } 
            } 
            else if (!ADP.IsEmptyArray(_restrictionValues) && !ADP.IsEmptyArray(entry._restrictionValues)) { // both AllowOnly with restrictions
                if (this._restrictionValues.Length <= entry._restrictionValues.Length) { 
                    //Debug.WriteLine("13a this AllowOnly with restrictions and entry AllowOnly with restrictions");
                    restrictionValues = NewRestrictionIntersect(_restrictionValues, entry._restrictionValues);
                }
                else { 
                    //Debug.WriteLine("13b this AllowOnly with restrictions and entry AllowOnly with restrictions");
                    restrictionValues = NewRestrictionIntersect(entry._restrictionValues, _restrictionValues); 
                } 
            }
            else { // both AllowOnly 
                //Debug.WriteLine("14/15/16 this AllowOnly and entry AllowOnly but no restrictions");
            }

            // verify _hasPassword & _parsetable are in sync between Everett/Whidbey 
            Debug.Assert(!_hasPassword || ContainsKey(KEY.Password) || ContainsKey(KEY.Pwd), "OnDeserialized password mismatch this");
            Debug.Assert(null == entry || !entry._hasPassword || entry.ContainsKey(KEY.Password) || entry.ContainsKey(KEY.Pwd), "OnDeserialized password mismatch entry"); 
 
            DBConnectionString value = new DBConnectionString(this, restrictionValues, behavior);
            Debug.Assert(value._hasPassword == (this._hasPassword && ((null != entry) && entry._hasPassword)), "password mismatch"); 
            Debug.Assert(this.IsSupersetOf(value), "intersection is not a subset of original this");
            Debug.Assert((null == entry) || entry.IsSupersetOf(value), "intersection is not a subset of original entry");
            return value;
        } 

        private bool IsRestrictedKeyword(string key) { 
            // restricted if not found 
            return ((null == _restrictionValues) || (0 > Array.BinarySearch(_restrictionValues, key, StringComparer.Ordinal)));
        } 

        internal bool IsSupersetOf(DBConnectionString entry) {
            Debug.Assert(!_hasPassword || ContainsKey(KEY.Password) || ContainsKey(KEY.Pwd), "OnDeserialized password mismatch this");
            Debug.Assert(!entry._hasPassword || entry.ContainsKey(KEY.Password) || entry.ContainsKey(KEY.Pwd), "OnDeserialized password mismatch entry"); 

            switch(_behavior) { 
            case KeyRestrictionBehavior.AllowOnly: 
                // every key must either be in the resticted connection string or in the allowed keywords
                // keychain may contain duplicates, but it is better than GetEnumerator on _parsetable.Keys 
                for(NameValuePair current = entry.KeyChain; null != current; current = current.Next) {
                    if (!ContainsKey(current.Name) && IsRestrictedKeyword(current.Name)) {
#if DATAPERMIT
                        Debug.WriteLine("DBDataPermission failed AllowOnly"); 
#endif
                        return false; 
                    } 
                }
                break; 
            case KeyRestrictionBehavior.PreventUsage:
                // every key can not be in the restricted keywords (even if in the restricted connection string)
                if (null != _restrictionValues) {
                    foreach(string restriction in _restrictionValues) { 
                        if (entry.ContainsKey(restriction)) {
#if DATAPERMIT 
                            Debug.WriteLine("DBDataPermission failed PreventUsage"); 
#endif
                            return false; 
                        }
                    }
                }
                break; 
            default:
                Debug.Assert(false, "invalid KeyRestrictionBehavior"); 
                throw ADP.InvalidKeyRestrictionBehavior(_behavior); 
            }
            return true; 
        }

        static private string[] NewRestrictionAllowOnly(string[] allowonly, string[] preventusage) {
            List newlist = null; 
            for (int i = 0; i < allowonly.Length; ++i) {
                if (0 > Array.BinarySearch(preventusage, allowonly[i], StringComparer.Ordinal)) { 
                    if (null == newlist) { 
                        newlist = new List();
                    } 
                    newlist.Add(allowonly[i]);
                }
            }
            string[] restrictionValues = null; 
            if (null != newlist) {
                restrictionValues = newlist.ToArray(); 
            } 
            Verify(restrictionValues);
            return restrictionValues; 
        }

        static private string[] NewRestrictionIntersect(string[] a, string[] b) {
            List newlist = null; 
            for (int i = 0; i < a.Length; ++i) {
                if (0 <= Array.BinarySearch(b, a[i], StringComparer.Ordinal)) { 
                    if (null == newlist) { 
                        newlist = new List();
                    } 
                    newlist.Add(a[i]);
                }
            }
            string[] restrictionValues = null; 
            if (newlist != null) {
                restrictionValues = newlist.ToArray(); 
            } 
            Verify(restrictionValues);
            return restrictionValues; 
        }

        static private string[] NoDuplicateUnion(string[] a, string[] b) {
#if DEBUG 
            Debug.Assert(null != a && 0 < a.Length, "empty a");
            Debug.Assert(null != b && 0 < b.Length, "empty b"); 
            Verify(a); 
            Verify(b);
#endif 
            List newlist = new List(a.Length + b.Length);
            for(int i = 0; i < a.Length; ++i) {
                newlist.Add(a[i]);
            } 
            for(int i = 0; i < b.Length; ++i) { // find duplicates
                if (0 > Array.BinarySearch(a, b[i], StringComparer.Ordinal)) { 
                    newlist.Add(b[i]); 
                }
            } 
            string[] restrictionValues = newlist.ToArray();
            Array.Sort(restrictionValues, StringComparer.Ordinal);
            Verify(restrictionValues);
            return restrictionValues; 
        }
 
        private static string[] ParseRestrictions(string restrictions, Hashtable synonyms) { 
#if DEBUG
            if (Bid.AdvancedOn) { 
                Bid.Trace(" Restrictions='%ls'\n", restrictions);
            }
#endif
            List restrictionValues = new List(); 
            StringBuilder buffer = new StringBuilder(restrictions.Length);
 
            int nextStartPosition = 0; 
            int endPosition = restrictions.Length;
            while (nextStartPosition < endPosition) { 
                int startPosition = nextStartPosition;

                string keyname, keyvalue; // since parsing restrictions ignores values, it doesn't matter if we use ODBC rules or OLEDB rules
                nextStartPosition = DbConnectionOptions.GetKeyValuePair(restrictions, startPosition, buffer, false, out keyname, out keyvalue); 
                if (!ADP.IsEmpty(keyname)) {
#if DEBUG 
                    if (Bid.AdvancedOn) { 
                        Bid.Trace(" KeyName='%ls'\n", keyname);
                    } 
#endif
                    string realkeyname = ((null != synonyms) ? (string)synonyms[keyname] : keyname); // MDAC 85144
                    if (ADP.IsEmpty(realkeyname)) {
                        throw ADP.KeywordNotSupported(keyname); 
                    }
                    restrictionValues.Add(realkeyname); 
                } 
            }
            return RemoveDuplicates(restrictionValues.ToArray()); 

        }

        static internal string[] RemoveDuplicates(string[] restrictions) { 
            int count = restrictions.Length;
            if (0 < count) { 
                Array.Sort(restrictions, StringComparer.Ordinal); 

                for (int i = 1; i < restrictions.Length; ++i) { 
                    string prev = restrictions[i-1];
                    if ((0 == prev.Length) || (prev == restrictions[i])) {
                        restrictions[i-1] = null;
                        count--; 
                    }
                } 
                if (0 == restrictions[restrictions.Length-1].Length) { 
                    restrictions[restrictions.Length-1] = null;
                    count--; 
                }
                if (count != restrictions.Length) {
                    string[] tmp = new String[count];
                    count = 0; 
                    for (int i = 0; i < restrictions.Length; ++i) {
                        if (null != restrictions[i]) { 
                            tmp[count++] = restrictions[i]; 
                        }
                    } 
                    restrictions = tmp;
                }
            }
            Verify(restrictions); 
            return restrictions;
        } 
 
        [ConditionalAttribute("DEBUG")]
        private static void Verify(string[] restrictionValues) { 
            if (null != restrictionValues) {
                for (int i = 1; i < restrictionValues.Length; ++i) {
                    Debug.Assert(!ADP.IsEmpty(restrictionValues[i-1]), "empty restriction");
                    Debug.Assert(!ADP.IsEmpty(restrictionValues[i]), "empty restriction"); 
                    Debug.Assert(0 >= StringComparer.Ordinal.Compare(restrictionValues[i-1], restrictionValues[i]));
                } 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK