HttpCapabilitiesEvaluator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / Web / Configuration / HttpCapabilitiesEvaluator.cs / 1305376 / HttpCapabilitiesEvaluator.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.Configuration { 
 
    using System.Collections;
    using System.Collections.Specialized; 
    using System.Diagnostics;
    using System.Globalization;
    using System.Reflection;
    using System.Security; 
    using System.Text;
    using System.Text.RegularExpressions; 
    using System.Threading; 
    using System.Web.Caching;
    using System.Web.Compilation; 
    using System.Web.Hosting;
    using System.Security.Permissions;

    public abstract class HttpCapabilitiesProvider { 
        public abstract HttpBrowserCapabilities GetBrowserCapabilities(HttpRequest request);
    } 
 
    //
    // CapabilitiesEvaluator encapabilitiesulates a set of rules for deducing 
    // a capabilities object from an HttpRequest
    //
    public class HttpCapabilitiesDefaultProvider : HttpCapabilitiesProvider {
 
        internal CapabilitiesRule _rule;
        internal Hashtable _variables; 
        internal Type _resultType; 
        internal TimeSpan _cachetime;
        internal string _cacheKeyPrefix; 

        private int _userAgentCacheKeyLength;
        private static int _idCounter;
        private const string _isMobileDeviceCapKey = "isMobileDevice"; 
        private static object _disableOptimisticCachingSingleton = new object();
        private const int _defaultUserAgentCacheKeyLength = 64; 
        private string _browserCapabilitiesProviderType = null; 
        private HttpCapabilitiesProvider _browserCapabilitiesProvider = null;
 
        public int UserAgentCacheKeyLength {
            get {
                return _userAgentCacheKeyLength;
            } 
            set {
                _userAgentCacheKeyLength = value; 
            } 
        }
 
        public Type ResultType {
            get {
                return _resultType;
            } 
            set {
                _resultType = value; 
            } 
        }
 
        public TimeSpan CacheTime {
            get {
                return _cachetime;
            } 
            set {
                _cachetime = value; 
            } 
        }
 
        internal string BrowserCapabilitiesProviderType {
            get {
                return _browserCapabilitiesProviderType;
            } 
            set {
                _browserCapabilitiesProviderType = value; 
            } 
        }
 
        internal HttpCapabilitiesProvider BrowserCapabilitiesProvider {
            get {
                if (_browserCapabilitiesProvider == null) {
                    if (BrowserCapabilitiesProviderType != null) { 
                        Type t = System.Type.GetType(BrowserCapabilitiesProviderType, true, true);
                        _browserCapabilitiesProvider = (HttpCapabilitiesProvider)Activator.CreateInstance(t); 
                    } 
                }
                return _browserCapabilitiesProvider; 
            }
            set {
                _browserCapabilitiesProvider = value;
            } 
        }
 
        public HttpCapabilitiesDefaultProvider() : this(RuntimeConfig.GetAppConfig().BrowserCaps){ 
            if (RuntimeConfig.GetAppConfig().BrowserCaps != null) {
                _userAgentCacheKeyLength = RuntimeConfig.GetAppConfig().BrowserCaps.UserAgentCacheKeyLength; 
            }
            if (_userAgentCacheKeyLength == 0) {
                _userAgentCacheKeyLength = _defaultUserAgentCacheKeyLength;
            } 
        }
 
        // 
        // internal constructor; inherit from parent
        // 
        public HttpCapabilitiesDefaultProvider(HttpCapabilitiesDefaultProvider parent) {
            int id = Interlocked.Increment(ref _idCounter);
            // don't do id.ToString() on every request, do it here
            _cacheKeyPrefix = CacheInternal.PrefixHttpCapabilities + id.ToString(CultureInfo.InvariantCulture); 

            if (parent == null) { 
                ClearParent(); 
            }
            else { 
                _rule = parent._rule;

                if (parent._variables == null)
                    _variables = null; 
                else
                    _variables = new Hashtable(parent._variables); 
 
                _cachetime = parent._cachetime;
                _resultType = parent._resultType; 
            }
            //
            AddDependency(String.Empty);
        } 

        internal BrowserCapabilitiesFactoryBase BrowserCapFactory { 
            get { 
                return BrowserCapabilitiesCompiler.BrowserCapabilitiesFactory;
            } 
        }

        //
        // remove inheritance for  
        //
        internal void ClearParent() { 
            _rule = null; 
            _cachetime = TimeSpan.FromSeconds(60); // one minute default expiry
            _variables = new Hashtable(); 
            _resultType = typeof(HttpCapabilitiesBase);
        }

        // 
        // add a dependency when we encounter a 
        // 
        public void AddDependency(String variable) { 
            if (variable.Equals("HTTP_USER_AGENT"))
                variable = String.Empty; 

            _variables[variable] = true;
        }
 
        //
        // sets the set of rules 
        // 
        public virtual void AddRuleList(ArrayList ruleList) {
            if (ruleList.Count == 0) 
                return;

            if (_rule != null)
                ruleList.Insert(0, _rule); 

            _rule = new CapabilitiesSection(CapabilitiesRule.Filter, null, null, ruleList); 
        } 

        internal static string GetUserAgent(HttpRequest request) { 
            string userAgent;

            if (request.ClientTarget.Length > 0) {
                userAgent = GetUserAgentFromClientTarget( 
                    request.Context.ConfigurationPath, request.ClientTarget);
            } 
            else { 
                userAgent = request.UserAgent;
            } 

            // Protect against attacks with long User-Agent headers
            if (userAgent != null && userAgent.Length > 512) {
                userAgent = userAgent.Substring(0, 512); 
            }
 
            return userAgent; 
        }
 
        internal static string GetUserAgentFromClientTarget(VirtualPath configPath, string clientTarget) {

            // Lookup ClientTarget section in config.
            ClientTargetSection clientTargetConfig = RuntimeConfig.GetConfig(configPath).ClientTarget; 

            string userAgent = null; 
 
            if ( clientTargetConfig.ClientTargets[ clientTarget ] != null )
            { 
                userAgent = clientTargetConfig.ClientTargets[ clientTarget ].UserAgent;
            }

            if ( userAgent == null ) 
            {
                throw new HttpException(SR.GetString(SR.Invalid_client_target, clientTarget)); 
            } 

            return userAgent; 
        }

        private void CacheBrowserCapResult(ref HttpCapabilitiesBase result) {
            // Use the previously cached browserCap object if an identical 
            // browserCap is found.
            CacheInternal cacheInternal = System.Web.HttpRuntime.CacheInternal; 
 
            if (result.Capabilities == null) {
                return; 
            }

            string hashKey = CacheInternal.PrefixBrowserCapsHash;
            StringBuilder builder = new StringBuilder(); 
            foreach (string attribute in result.Capabilities.Keys) {
                // Ignore useragent that is stored with empty key. 
                if (String.IsNullOrEmpty(attribute)) { 
                    continue;
                } 

                string value = (String)result.Capabilities[attribute];
                if (value != null) {
                    builder.Append(attribute); 
                    builder.Append("$");
                    builder.Append(value); 
                    builder.Append("$"); 
                }
            } 
            hashKey += builder.ToString().GetHashCode().ToString(CultureInfo.InvariantCulture);

            HttpCapabilitiesBase newResult = cacheInternal.Get(hashKey) as HttpCapabilitiesBase;
            if (newResult != null) { 
                result = newResult;
            } 
            else { 
                // cache it and respect cachetime
                cacheInternal.UtcInsert(hashKey, result, null, Cache.NoAbsoluteExpiration, _cachetime); 
            }
        }

        public override HttpBrowserCapabilities GetBrowserCapabilities(HttpRequest request) { 
            return (HttpBrowserCapabilities)Evaluate(request);
        } 
 
        //
        // Actually computes the browser capabilities 
        //
        internal HttpCapabilitiesBase Evaluate(HttpRequest request) {

            HttpCapabilitiesBase result; 
            CacheInternal cacheInternal = System.Web.HttpRuntime.CacheInternal;
 
            // 
            // 1) grab UA and do optimistic cache lookup (if UA is in dependency list)
            // 
            string userAgent = GetUserAgent(request);
            string userAgentCacheKey = userAgent;

            // Use the shorten userAgent as the cache key. 
            Debug.Assert(UserAgentCacheKeyLength != 0);
            // Trim the useragent string based on  config 
            if (userAgentCacheKey != null && userAgentCacheKey.Length > UserAgentCacheKeyLength) { 
                userAgentCacheKey = userAgentCacheKey.Substring(0, UserAgentCacheKeyLength);
            } 

            bool doFullCacheKeyLookup = false;
            string optimisticCacheKey = _cacheKeyPrefix + userAgentCacheKey;
            object optimisticCacheResult = cacheInternal.Get(optimisticCacheKey); 

            // optimize for common case (desktop browser) 
            result = optimisticCacheResult as HttpCapabilitiesBase; 
            if (result != null) {
                return result; 
            }

            //
            // 1.1) optimistic cache entry could tell us to do full cache lookup 
            //
            if (optimisticCacheResult == _disableOptimisticCachingSingleton) { 
                doFullCacheKeyLookup = true; 
            }
            else { 
                // cache it and respect _cachetime
                result = EvaluateFinal(request, true);

                // Optimized cache key is disabled if the request matches any headers defined within identifications. 
                if (result.UseOptimizedCacheKey) {
 
                    // Use the same browserCap result if one with the same capabilities can be found in the cache. 
                    // This is to reduce the number of identical browserCap instances being cached.
                    CacheBrowserCapResult(ref result); 

                    // Cache the result using the optimisicCacheKey
                    cacheInternal.UtcInsert(optimisticCacheKey, result, null, Cache.NoAbsoluteExpiration, _cachetime);
 
                    return result;
                } 
            } 

            // 
            // 2) either:
            //
            //      We've never seen the UA before (parse all headers to
            //          determine if the new UA also carries modile device 
            //          httpheaders).
            // 
            //      It's a mobile UA (so parse all headers) and do full 
            //          cache lookup
            // 
            //      UA isn't in dependency list (customer custom caps section)
            //

            IDictionaryEnumerator de = _variables.GetEnumerator(); 
            StringBuilder sb = new StringBuilder(_cacheKeyPrefix);
 
            InternalSecurityPermissions.AspNetHostingPermissionLevelLow.Assert(); 

            while (de.MoveNext()) { 
                string key = (string)de.Key;
                string value;

                if (key.Length == 0) { 
                    value = userAgent;
                } 
                else { 
                    value = request.ServerVariables[key];
                } 

                if (value != null) {
                    sb.Append(value);
                } 
            }
 
            CodeAccessPermission.RevertAssert(); 

            sb.Append(BrowserCapabilitiesFactoryBase.GetBrowserCapKey(BrowserCapFactory.InternalGetMatchedHeaders(), request)); 
            string fullCacheKey = sb.ToString();

            //
            // Only do full cache lookup if the optimistic cache 
            // result was _disableOptimisticCachingSingleton or
            // if UserAgent wasn't in the cap var list. 
            // 
            if (userAgent == null || doFullCacheKeyLookup) {
 
                result = cacheInternal.Get(fullCacheKey) as HttpCapabilitiesBase;

                if (result != null)
                    return result; 
            }
 
            result = EvaluateFinal(request, false); 

            // Use the same browserCap result if one with the same matched nodes can be found in the cache. 
            // This is to reduce the number of identical browserCap instances being cached.
            CacheBrowserCapResult(ref result);

             // cache it and respect _cachetime 
            cacheInternal.UtcInsert(fullCacheKey, result, null, Cache.NoAbsoluteExpiration, _cachetime);
            if(optimisticCacheKey != null) { 
                cacheInternal.UtcInsert(optimisticCacheKey, _disableOptimisticCachingSingleton, null, Cache.NoAbsoluteExpiration, _cachetime); 
            }
 
            return result;
        }

        internal HttpCapabilitiesBase EvaluateFinal(HttpRequest request, bool onlyEvaluateUserAgent) { 
            HttpBrowserCapabilities browserCaps = BrowserCapFactory.GetHttpBrowserCapabilities(request);
            CapabilitiesState state = new CapabilitiesState(request, browserCaps.Capabilities); 
            if (onlyEvaluateUserAgent) { 
                state.EvaluateOnlyUserAgent = true;
            } 

            if(_rule != null) {
                string oldIsMobileDevice = browserCaps[_isMobileDeviceCapKey];
                browserCaps.Capabilities[_isMobileDeviceCapKey] = null; 

                _rule.Evaluate(state); 
 
                string newIsMobileDevice = browserCaps[_isMobileDeviceCapKey];
                if (newIsMobileDevice == null) { 
                    browserCaps.Capabilities[_isMobileDeviceCapKey] = oldIsMobileDevice;
                }
                else if (newIsMobileDevice.Equals("true")) {
                    browserCaps.DisableOptimizedCacheKey(); 
                }
            } 
 
            // create the new type
            // 
            HttpCapabilitiesBase result = (HttpCapabilitiesBase)HttpRuntime.CreateNonPublicInstance(_resultType);
            result.InitInternal(browserCaps);

            return result; 
        }
 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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