Beispiel #1
0
        private void LoadXPathDocument()
        {
            Debug.Assert(_xpathDocument == null && _document == null && _xpathNavigator == null);

            if (!String.IsNullOrEmpty(_documentContent))
            {
                _xpathDocument = XmlUtils.CreateXPathDocumentFromContent(_documentContent);
                return;
            }

            if (String.IsNullOrEmpty(_documentSource))
            {
                return;
            }

            // First, figure out if it's a physical or virtual path
            VirtualPath virtualPath;
            string      physicalPath;

            ResolvePhysicalOrVirtualPath(_documentSource, out virtualPath, out physicalPath);

            CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache;
            string             key           = CacheInternal.PrefixLoadXPath + ((physicalPath != null) ?
                                                                                physicalPath : virtualPath.VirtualPathString);

            _xpathDocument = (XPathDocument)cacheInternal.Get(key);
            if (_xpathDocument == null)
            {
                Debug.Trace("XmlControl", "XPathDocument not found in cache (" + _documentSource + ")");

                // Get the stream, and open the doc
                CacheDependency dependency;
                using (Stream stream = OpenFileAndGetDependency(virtualPath, physicalPath, out dependency)) {
                    // The same comments as in LoadTransformFromSource() (VSWhidbey 545322, 546662)
                    if (physicalPath == null)
                    {
                        physicalPath = virtualPath.MapPath();
                    }

                    _xpathDocument = new XPathDocument(XmlUtils.CreateXmlReader(stream, physicalPath));
                }

                // Cache it, but only if we got a dependency
                if (dependency != null)
                {
                    using (dependency) {
                        cacheInternal.Insert(key, _xpathDocument, new CacheInsertOptions()
                        {
                            Dependencies = dependency
                        });
                    }
                }
            }
            else
            {
                Debug.Trace("XmlControl", "XPathDocument found in cache (" + _documentSource + ")");
            }
        }
Beispiel #2
0
        /// <devdoc>
        ///   Gets the ad data for the given file by loading the file, or reading from the
        ///   application-level cache.
        /// </devdoc>
        private AdRec [] GetFileData(string fileName)
        {
            // VSWhidbey 208626: Adopting similar code from xml.cs to support virtual path provider

            // First, figure out if it's a physical or virtual path
            VirtualPath virtualPath;
            string      physicalPath;

            ResolvePhysicalOrVirtualPath(fileName, out virtualPath, out physicalPath);

            // try to get it from the ASP.NET cache
            string fileKey = CacheInternal.PrefixAdRotator + ((!String.IsNullOrEmpty(physicalPath)) ?
                                                              physicalPath : virtualPath.VirtualPathString);
            CacheStoreProvider cacheInternal = System.Web.HttpRuntime.Cache.InternalCache;

            AdRec[] adRecs = cacheInternal.Get(fileKey) as AdRec[];

            if (adRecs == null)
            {
                // Otherwise load it
                CacheDependency dependency;
                try {
                    using (Stream stream = OpenFileAndGetDependency(virtualPath, physicalPath, out dependency)) {
                        adRecs = LoadStream(stream);
                        Debug.Assert(adRecs != null);
                    }
                }
                catch (Exception e) {
                    if (!String.IsNullOrEmpty(physicalPath) && HttpRuntime.HasPathDiscoveryPermission(physicalPath))
                    {
                        // We want to catch the error message, but not propage the inner exception. Otherwise we can throw up
                        // logon prompts through IE;
                        throw new HttpException(SR.GetString(SR.AdRotator_cant_open_file, ID, e.Message));
                    }
                    else
                    {
                        throw new HttpException(SR.GetString(SR.AdRotator_cant_open_file_no_permission, ID));
                    }
                }

                // Cache it, but only if we got a dependency
                if (dependency != null)
                {
                    using (dependency) {
                        // and store it in the cache, dependent on the file name
                        cacheInternal.Insert(fileKey, adRecs, new CacheInsertOptions()
                        {
                            Dependencies = dependency
                        });
                    }
                }
            }
            return(adRecs);
        }
Beispiel #3
0
        internal /*public*/ void DoDelete(HttpContext context)
        {
            string             key           = CreateKey(context.Request);
            CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache;
            CachedContent      content       = (CachedContent)cacheInternal.Get(key);

            /* If the item isn't there, we probably took too long to run. */
            if (content == null)
            {
                ReportNotFound(context);
                return;
            }

            int lockCookie;

            if (!GetOptionalNonNegativeInt32HeaderValue(context, StateHeaders.LOCKCOOKIE_NAME, out lockCookie))
            {
                return;
            }

            content._spinLock.AcquireWriterLock();
            try {
                if (content._content == null)
                {
                    ReportNotFound(context);
                    return;
                }

                /* Only remove the item if we are the owner */
                if (content._locked && (lockCookie == -1 || content._lockCookie != lockCookie))
                {
                    ReportLocked(context, content);
                    return;
                }

                /*
                 * If not locked, keep it locked until it is completely removed.
                 * Prevent overwriting when we drop the lock.
                 */
                content._locked     = true;
                content._lockCookie = 0;
            }
            finally {
                content._spinLock.ReleaseWriterLock();
            }


            cacheInternal.Remove(key);
        }
Beispiel #4
0
        private void LoadXmlDocument()
        {
            Debug.Assert(_xpathDocument == null && _document == null && _xpathNavigator == null);

            if (!String.IsNullOrEmpty(_documentContent))
            {
                _document = XmlUtils.CreateXmlDocumentFromContent(_documentContent);
                return;
            }

            if (String.IsNullOrEmpty(_documentSource))
            {
                return;
            }

            // Make it absolute and check security
            string physicalPath = MapPathSecure(_documentSource);

            CacheStoreProvider cacheInternal = System.Web.HttpRuntime.Cache.InternalCache;
            string             key           = CacheInternal.PrefixLoadXml + physicalPath;

            _document = (XmlDocument)cacheInternal.Get(key);

            if (_document == null)
            {
                Debug.Trace("XmlControl", "XmlDocument not found in cache (" + _documentSource + ")");

                CacheDependency dependency;
                using (Stream stream = OpenFileAndGetDependency(null, physicalPath, out dependency)) {
                    _document = new XmlDocument();
                    _document.Load(XmlUtils.CreateXmlReader(stream, physicalPath));
                    cacheInternal.Insert(key, _document, new CacheInsertOptions()
                    {
                        Dependencies = dependency
                    });
                }
            }
            else
            {
                Debug.Trace("XmlControl", "XmlDocument found in cache (" + _documentSource + ")");
            }

            //
            lock (_document) {
                // Always return a clone of the cached copy
                _document = (XmlDocument)_document.CloneNode(true /*deep*/);
            }
        }
        private void CacheBrowserCapResult(ref HttpCapabilitiesBase result)
        {
            // Use the previously cached browserCap object if an identical
            // browserCap is found.
            CacheStoreProvider cacheInternal = System.Web.HttpRuntime.Cache.InternalCache;

            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.Insert(hashKey, result, new CacheInsertOptions()
                {
                    SlidingExpiration = _cachetime
                });
            }
        }
Beispiel #6
0
        // Disallow Apartment components in when ASPCOMPAT is off

        internal static void CheckThreadingModel(String progidDisplayName, Guid clsid)
        {
            if (IsInAspCompatMode)
            {
                return;
            }

            // try cache first
            CacheStoreProvider cacheInternal  = HttpRuntime.Cache.InternalCache;
            String             key            = CacheInternal.PrefixAspCompatThreading + progidDisplayName;
            String             threadingModel = (String)cacheInternal.Get(key);
            RegistryKey        regKey         = null;

            if (threadingModel == null)
            {
                try {
                    regKey = Registry.ClassesRoot.OpenSubKey("CLSID\\{" + clsid + "}\\InprocServer32");
                    if (regKey != null)
                    {
                        threadingModel = (String)regKey.GetValue("ThreadingModel");
                    }
                }
                catch {
                }
                finally {
                    if (regKey != null)
                    {
                        regKey.Close();
                    }
                }

                if (threadingModel == null)
                {
                    threadingModel = String.Empty;
                }

                cacheInternal.Insert(key, threadingModel, null);
            }

            if (StringUtil.EqualsIgnoreCase(threadingModel, "Apartment"))
            {
                throw new HttpException(
                          SR.GetString(SR.Apartment_component_not_allowed, progidDisplayName));
            }
        }
Beispiel #7
0
        // Mark CachedPathData as completed when the first request for the path results in a
        // status outside the 400 range. We need to mark all data up the path to account for
        // virtual files.
        static internal void MarkCompleted(CachedPathData pathData)
        {
            CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache;

            string configPath = pathData._configPath;

            do
            {
                pathData.CompletedFirstRequest = true;

                configPath = ConfigPathUtility.GetParent(configPath);
                if (configPath == null)
                {
                    break;
                }

                string key = CreateKey(configPath);
                pathData = (CachedPathData)cacheInternal.Get(key);
            } while (pathData != null && !pathData.CompletedFirstRequest);
        }
        // Get the page-level IResourceProvider
        internal static IResourceProvider GetLocalResourceProvider(VirtualPath virtualPath)
        {
            // If we have it cached, return it (it may be null if there are no local resources)
            CacheStoreProvider cacheInternal    = System.Web.HttpRuntime.Cache.InternalCache;
            string             cacheKey         = CacheInternal.PrefixResourceProvider + virtualPath.VirtualPathString;
            IResourceProvider  resourceProvider = cacheInternal.Get(cacheKey) as IResourceProvider;

            if (resourceProvider != null)
            {
                return(resourceProvider);
            }

            EnsureResourceProviderFactory();
            resourceProvider = s_resourceProviderFactory.CreateLocalResourceProvider(virtualPath.VirtualPathString);

            // Cache it
            cacheInternal.Insert(cacheKey, resourceProvider, null);

            return(resourceProvider);
        }
        // Remove an item.  Note that the item is originally obtained by GetExclusive
        // Same note as Set on lockId
        public override void RemoveItem(HttpContext context,
                                        String id,
                                        object lockId,
                                        SessionStateStoreData item)
        {
            Debug.Assert(lockId != null, "lockId != null");

            string             key           = CreateSessionStateCacheKey(id);
            CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache;
            int lockCookie = (int)lockId;

            SessionIDManager.CheckIdLength(id, true /* throwOnFail */);

            InProcSessionState state = (InProcSessionState)cacheInternal.Get(key);

            /* If the item isn't there, we probably took too long to run. */
            if (state == null)
            {
                return;
            }

            state._spinLock.AcquireWriterLock();

            try {
                /* Only remove the item if we are the owner */
                if (!state._locked || state._lockCookie != lockCookie)
                {
                    return;
                }

                /* prevent overwriting when we drop the lock */
                state._lockCookie = 0;
            }
            finally {
                state._spinLock.ReleaseWriterLock();
            }

            cacheInternal.Remove(key);

            TraceSessionStats();
        }
Beispiel #10
0
        // Remove CachedPathData when the first request for the path results in a
        // 400 range error. We need to remove all data up the path to account for
        // virtual files.
        // An example of a 400 range error is "path not found".
        static internal void RemoveBadPathData(CachedPathData pathData)
        {
            CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache;

            string configPath = pathData._configPath;
            string key        = CreateKey(configPath);

            while (pathData != null && !pathData.CompletedFirstRequest && !pathData.Exists)
            {
                cacheInternal.Remove(key);

                configPath = ConfigPathUtility.GetParent(configPath);
                if (configPath == null)
                {
                    break;
                }

                key      = CreateKey(configPath);
                pathData = (CachedPathData)cacheInternal.Get(key);
            }
        }
        private static IResourceProvider GetGlobalResourceProvider(string classKey)
        {
            string fullClassName = BaseResourcesBuildProvider.DefaultResourcesNamespace +
                                   "." + classKey;

            // If we have it cached, return it
            CacheStoreProvider cacheInternal    = System.Web.HttpRuntime.Cache.InternalCache;
            string             cacheKey         = CacheInternal.PrefixResourceProvider + fullClassName;
            IResourceProvider  resourceProvider = cacheInternal.Get(cacheKey) as IResourceProvider;

            if (resourceProvider != null)
            {
                return(resourceProvider);
            }

            EnsureResourceProviderFactory();
            resourceProvider = s_resourceProviderFactory.CreateGlobalResourceProvider(classKey);

            // Cache it
            cacheInternal.Insert(cacheKey, resourceProvider, null);

            return(resourceProvider);
        }
Beispiel #12
0
        // Example of configPath = "machine/webroot/1/fxtest/sub/foo.aspx"
        // The configPath parameter must be lower case.
        static private CachedPathData GetConfigPathData(string configPath)
        {
            Debug.Assert(ConfigPathUtility.IsValid(configPath), "ConfigPathUtility.IsValid(configPath)");
            Debug.Assert(configPath == configPath.ToLower(CultureInfo.InvariantCulture), "configPath == configPath.ToLower(CultureInfo.InvariantCulture)");
            bool exists      = false;
            bool isDirectory = false;
            bool isRemovable = IsCachedPathDataRemovable(configPath);

            // if the sliding expiration is zero, we won't cache it unless it is a configPath for root web.config or above
            if (isRemovable && DoNotCacheUrlMetadata)
            {
                string      pathSiteID       = null;
                VirtualPath virtualFilePath  = null;
                string      physicalFilePath = null;
                WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out pathSiteID, out virtualFilePath);
                physicalFilePath = GetPhysicalPath(virtualFilePath);

                string         parentConfigPath = ConfigPathUtility.GetParent(configPath);
                CachedPathData pathParentData   = GetConfigPathData(parentConfigPath);
                if (!String.IsNullOrEmpty(physicalFilePath))
                {
                    FileUtil.PhysicalPathStatus(physicalFilePath, false, false, out exists, out isDirectory);
                }
                CachedPathData pathData = new CachedPathData(configPath, virtualFilePath, physicalFilePath, exists);
                pathData.Init(pathParentData);

                return(pathData);
            }

            //
            // First, see if the CachedPathData is in the cache.
            // we don't use Add for this lookup, as doing so requires
            // creating a CacheDependency, which can be slow as it may hit
            // the filesystem.
            //
            string             key           = CreateKey(configPath);
            CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache;
            CachedPathData     data          = (CachedPathData)cacheInternal.Get(key);

            // if found, return the data
            if (data != null)
            {
                data.WaitForInit();
                return(data);
            }

            // WOS


            bool cacheEntryIsNotRemovable = false;

            // if not found, try to add it
            string          siteID       = null;
            VirtualPath     virtualPath  = null;
            CachedPathData  parentData   = null;
            CacheDependency dependency   = null;
            string          physicalPath = null;

            string[] fileDependencies      = null;
            string[] cacheItemDependencies = null;

            if (WebConfigurationHost.IsMachineConfigPath(configPath))
            {
                cacheEntryIsNotRemovable = true;
            }
            else
            {
                // Make sure we have the parent data so we can create a dependency on the parent.
                // The parent dependency will ensure that configuration data in the parent
                // will be referenced by a cache hit on the child. (see UtcUpdateUsageRecursive in Cache.cs)
                string parentConfigPath = ConfigPathUtility.GetParent(configPath);
                parentData = GetConfigPathData(parentConfigPath);
                string parentKey = CreateKey(parentConfigPath);
                cacheItemDependencies = new string[1] {
                    parentKey
                };

                if (!WebConfigurationHost.IsVirtualPathConfigPath(configPath))
                {
                    // assume hardcoded levels above the path, such as root web.config, exist
                    cacheEntryIsNotRemovable = true;
                }
                else
                {
                    cacheEntryIsNotRemovable = !isRemovable;
                    WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out siteID, out virtualPath);
                    physicalPath = GetPhysicalPath(virtualPath);

                    // Add a dependency on the path itself, if it is a file,
                    // to handle the case where a file is deleted and replaced
                    // with a directory of the same name.
                    if (!String.IsNullOrEmpty(physicalPath))
                    {
                        FileUtil.PhysicalPathStatus(physicalPath, false, false, out exists, out isDirectory);
                        if (exists && !isDirectory)
                        {
                            fileDependencies = new string[1] {
                                physicalPath
                            };
                        }
                    }
                }

                try {
                    dependency = new CacheDependency(0, fileDependencies, cacheItemDependencies);
                }
                catch {
                    // CacheDependency ctor could fail because of bogus file path
                    // and it is ok not to watch those
                }
            }

            // Try to add the CachedPathData to the cache.
            CachedPathData    dataAdd           = null;
            bool              isDataCreator     = false;
            bool              initCompleted     = false;
            CacheItemPriority priority          = cacheEntryIsNotRemovable ? CacheItemPriority.NotRemovable : CacheItemPriority.Normal;
            TimeSpan          slidingExpiration = cacheEntryIsNotRemovable ? Cache.NoSlidingExpiration : UrlMetadataSlidingExpiration;

            try {
                using (dependency) {
                    dataAdd = new CachedPathData(configPath, virtualPath, physicalPath, exists);
                    try {
                    }
                    finally {
                        data = (CachedPathData)cacheInternal.Add(key, dataAdd, new CacheInsertOptions()
                        {
                            Dependencies      = dependency,
                            SlidingExpiration = slidingExpiration,
                            Priority          = priority,
                            OnRemovedCallback = s_callback
                        });

                        if (data == null)
                        {
                            isDataCreator = true;
                        }
                    }
                }

                // If another thread added it first, return the data
                if (!isDataCreator)
                {
                    data.WaitForInit();
                    return(data);
                }

                // This thread is the creator of the CachedPathData, initialize it
                lock (dataAdd) {
                    try {
                        dataAdd.Init(parentData);
                        initCompleted = true;
                    }
                    finally {
                        // free waiters
                        dataAdd._flags[FInited] = true;

                        // Wake up waiters.
                        Monitor.PulseAll(dataAdd);

                        if (dataAdd._flags[FCloseNeeded])
                        {
                            // If we have received a call back to close, then lets
                            // make sure that our config object is cleaned up
                            dataAdd.Close();
                        }
                    }
                }
            }
            finally {
                // All the work in this finally block is for the case where we're the
                // creator of the CachedPathData.
                if (isDataCreator)
                {
                    //



                    if (!dataAdd._flags[FInited])
                    {
                        lock (dataAdd) {
                            // free waiters
                            dataAdd._flags[FInited] = true;

                            // Wake up waiters.
                            Monitor.PulseAll(dataAdd);

                            if (dataAdd._flags[FCloseNeeded])
                            {
                                // If we have received a call back to close, then lets
                                // make sure that our config object is cleaned up
                                dataAdd.Close();
                            }
                        }
                    }

                    //
                    // Even though there is a try/catch handler surrounding the call to Init,
                    // a ThreadAbortException can still cause the handler to be bypassed.
                    //
                    // If there is an error, either a thread abort or an error in the config
                    // file itself, we do want to leave the item cached for a short period
                    // so that we do not revisit the error and potentially reparse the config file
                    // on every request.
                    //
                    // The reason we simply do not leave the item in the cache forever is that the
                    // problem that caused the configuration exception may be fixed without touching
                    // the config file in a way that causes a file change notification (for example, an
                    // acl change in a parent directory, or a change of path mapping in the metabase).
                    //
                    // NOTE: It is important to reinsert the item into the cache AFTER dropping
                    // the lock on dataAdd, in order to prevent the possibility of deadlock.
                    //
                    Debug.Assert(dataAdd._flags[FInited], "_flags[FInited]");
                    if (!initCompleted || (dataAdd.ConfigRecord != null && dataAdd.ConfigRecord.HasInitErrors))
                    {
                        //
                        // Create a new dependency object as the old one cannot be reused.
                        // Do not include a file dependency if initialization could not be completed,
                        // as invoking the file system could lead to further errors during a thread abort.
                        //
                        if (dependency != null)
                        {
                            if (!initCompleted)
                            {
                                dependency = new CacheDependency(0, null, cacheItemDependencies);
                            }
                            else
                            {
                                dependency = new CacheDependency(0, fileDependencies, cacheItemDependencies);
                            }
                        }

                        using (dependency) {
                            cacheInternal.Insert(key, dataAdd, new CacheInsertOptions()
                            {
                                Dependencies       = dependency,
                                AbsoluteExpiration = DateTime.UtcNow.AddSeconds(5),
                                OnRemovedCallback  = s_callback
                            });
                        }
                    }
                }
            }

            return(dataAdd);
        }
Beispiel #13
0
        private void LoadTransformFromSource()
        {
            // We're done if we already have a transform
            if (_transform != null)
            {
                return;
            }

            if (String.IsNullOrEmpty(_transformSource) || _transformSource.Trim().Length == 0)
            {
                return;
            }

            // First, figure out if it's a physical or virtual path
            VirtualPath virtualPath;
            string      physicalPath;

            ResolvePhysicalOrVirtualPath(_transformSource, out virtualPath, out physicalPath);

            CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache;
            string             key           = CacheInternal.PrefixLoadXPath + ((physicalPath != null) ?
                                                                                physicalPath : virtualPath.VirtualPathString);

            object xform = cacheInternal.Get(key);

            if (xform == null)
            {
                Debug.Trace("XmlControl", "Xsl Transform not found in cache (" + _transformSource + ")");

                // Get the stream, and open the doc
                CacheDependency dependency;
                using (Stream stream = OpenFileAndGetDependency(virtualPath, physicalPath, out dependency)) {
                    // If we don't have a physical path, call MapPath to get one, in order to pass it as
                    // the baseUri to XmlTextReader.  In pure VirtualPathProvider scenarios, it won't
                    // help much, but it allows the default case to have relative references (VSWhidbey 545322)
                    if (physicalPath == null)
                    {
                        physicalPath = virtualPath.MapPath();
                    }

                    // XslCompiledTransform for some reason wants to completely re-create an internal XmlReader
                    // from scratch.  In doing so, it does not respect all the settings of XmlTextReader.  So we want
                    // to be sure to specifically use XmlReader here so our settings on it will be respected by the
                    // XslCompiledTransform.
                    XmlReader xmlReader = XmlUtils.CreateXmlReader(stream, physicalPath);
                    _transform = XmlUtils.CreateXslTransform(xmlReader);
                    if (_transform == null)
                    {
                        _compiledTransform = XmlUtils.CreateXslCompiledTransform(xmlReader);
                    }
                }

                // Cache it, but only if we got a dependency
                if (dependency != null)
                {
                    using (dependency) {
                        cacheInternal.Insert(key, ((_compiledTransform == null) ? (object)_transform : (object)_compiledTransform),
                                             new CacheInsertOptions()
                        {
                            Dependencies = dependency
                        });
                    }
                }
            }
            else
            {
                Debug.Trace("XmlControl", "XslTransform found in cache (" + _transformSource + ")");

                _compiledTransform = xform as XslCompiledTransform;
                if (_compiledTransform == null)
                {
#pragma warning disable 0618    // To avoid deprecation warning
                    _transform = (XslTransform)xform;
#pragma warning restore 0618
                }
            }
        }
        public override void SetAndReleaseItemExclusive(HttpContext context,
                                                        String id,
                                                        SessionStateStoreData item,
                                                        object lockId,
                                                        bool newItem)
        {
            string             key                    = CreateSessionStateCacheKey(id);
            bool               doInsert               = true;
            CacheStoreProvider cacheInternal          = HttpRuntime.Cache.InternalCache;
            int lockCookieForInsert                   = NewLockCookie;
            ISessionStateItemCollection items         = null;
            HttpStaticObjectsCollection staticObjects = null;

            Debug.Assert(item.Items != null, "item.Items != null");
            Debug.Assert(item.StaticObjects != null, "item.StaticObjects != null");
            Debug.Assert(item.Timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES, "item.Timeout <= SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES");

            SessionIDManager.CheckIdLength(id, true /* throwOnFail */);

            if (item.Items.Count > 0)
            {
                items = item.Items;
            }

            if (!item.StaticObjects.NeverAccessed)
            {
                staticObjects = item.StaticObjects;
            }

            if (!newItem)
            {
                Debug.Assert(lockId != null, "lockId != null");
                InProcSessionState stateCurrent = (InProcSessionState)cacheInternal.Get(key);
                int lockCookie = (int)lockId;

                /* If the state isn't there, we probably took too long to run. */
                if (stateCurrent == null)
                {
                    return;
                }

                Debug.Trace("SessionStateClientSet", "state is inStorage; key = " + key);
                Debug.Assert((stateCurrent._flags & (int)SessionStateItemFlags.Uninitialized) == 0, "Should never set an unitialized item; key = " + key);

                stateCurrent._spinLock.AcquireWriterLock();

                try {
                    /* Only set the state if we are the owner */
                    if (!stateCurrent._locked || stateCurrent._lockCookie != lockCookie)
                    {
                        Debug.Trace("SessionStateClientSet", "Leave because we're not the owner; key = " + key);
                        return;
                    }

                    /* We can change the state in place if the timeout hasn't changed */
                    if (stateCurrent._timeout == item.Timeout)
                    {
                        stateCurrent.Copy(
                            items,
                            staticObjects,
                            item.Timeout,
                            false,
                            DateTime.MinValue,
                            lockCookie,
                            stateCurrent._flags);

                        // Don't need to insert into the Cache because an in-place copy is good enough.
                        doInsert = false;
                        Debug.Trace("SessionStateClientSet", "Changing state inplace; key = " + key);
                    }
                    else
                    {
                        /* We are going to insert a new item to replace the current one in Cache
                         * because the expiry time has changed.
                         *
                         * Pleas note that an insert will cause the Session_End to be incorrectly raised.
                         *
                         * Please note that the item itself should not expire between now and
                         * where we do UtcInsert below because cacheInternal.Get above have just
                         * updated its expiry time.
                         */
                        stateCurrent._flags |= (int)SessionStateItemFlags.IgnoreCacheItemRemoved;

                        /* By setting _lockCookie to 0, we prevent an overwriting by ReleaseExclusive
                         * when we drop the lock.
                         * The scenario can happen if another request is polling and trying to prempt
                         * the lock we have on the item.
                         */
                        lockCookieForInsert      = lockCookie;
                        stateCurrent._lockCookie = 0;
                    }
                }
                finally {
                    stateCurrent._spinLock.ReleaseWriterLock();
                }
            }

            if (doInsert)
            {
                Debug.Trace("SessionStateClientSet", "Inserting state into Cache; key = " + key);
                InProcSessionState state = new InProcSessionState(
                    items,
                    staticObjects,
                    item.Timeout,
                    false,
                    DateTime.MinValue,
                    lockCookieForInsert,
                    0);

                try {
                }
                finally {
                    // protected from ThreadAbortEx
                    cacheInternal.Insert(key, state, new CacheInsertOptions()
                    {
                        SlidingExpiration = new TimeSpan(0, state._timeout, 0),
                        Priority          = CacheItemPriority.NotRemovable,
                        OnRemovedCallback = _callback
                    });
                    PerfCounters.IncrementCounter(AppPerfCounter.SESSIONS_TOTAL);
                    PerfCounters.IncrementCounter(AppPerfCounter.SESSIONS_ACTIVE);

                    TraceSessionStats();
                }
            }
        }
        //
        // Actually computes the browser capabilities
        //
        internal HttpCapabilitiesBase Evaluate(HttpRequest request)
        {
            HttpCapabilitiesBase result;
            CacheStoreProvider   cacheInternal = System.Web.HttpRuntime.Cache.InternalCache;

            //
            // 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 <browserCaps> 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.Insert(optimisticCacheKey, result, new CacheInsertOptions()
                    {
                        SlidingExpiration = _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.Insert(fullCacheKey, result, new CacheInsertOptions()
            {
                SlidingExpiration = _cachetime
            });
            if (optimisticCacheKey != null)
            {
                cacheInternal.Insert(optimisticCacheKey, _disableOptimisticCachingSingleton, new CacheInsertOptions()
                {
                    SlidingExpiration = _cachetime
                });
            }

            return(result);
        }
Beispiel #16
0
        unsafe IntPtr FinishPut(HttpContext context)
        {
            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;
            Stream       requestStream;

            byte[]             buf;
            int                timeoutMinutes;
            TimeSpan           timeout;
            int                extraFlags;
            string             key;
            CachedContent      content;
            CachedContent      contentCurrent;
            int                lockCookie;
            int                lockCookieNew = 1;
            IntPtr             stateItem;
            CacheStoreProvider cacheInternal = HttpRuntime.Cache.InternalCache;

            /* create the content */
            requestStream = request.InputStream;
            int bufferSize = (int)(requestStream.Length - requestStream.Position);

            buf = new byte[bufferSize];
            requestStream.Read(buf, 0, buf.Length);

            fixed(byte *pBuf = buf)
            {
                // The ctor of StateHttpWorkerRequest convert the native pointer address
                // into an array of bytes, and in our we revert it back to an IntPtr
                stateItem = (IntPtr)(*((void **)pBuf));
            }

            /* get headers */
            if (!GetOptionalNonNegativeInt32HeaderValue(context, StateHeaders.TIMEOUT_NAME, out timeoutMinutes))
            {
                return(stateItem);
            }

            if (timeoutMinutes == -1)
            {
                timeoutMinutes = SessionStateModule.TIMEOUT_DEFAULT;
            }

            if (timeoutMinutes > SessionStateModule.MAX_CACHE_BASED_TIMEOUT_MINUTES)
            {
                ReportInvalidHeader(context, StateHeaders.TIMEOUT_NAME);
                return(stateItem);
            }

            timeout = new TimeSpan(0, timeoutMinutes, 0);

            bool found;

            if (!GetOptionalInt32HeaderValue(context, StateHeaders.EXTRAFLAGS_NAME, out extraFlags, out found))
            {
                return(stateItem);
            }

            if (!found)
            {
                extraFlags = 0;
            }

            /* lookup current value */
            key            = CreateKey(request);
            contentCurrent = (CachedContent)cacheInternal.Get(key);
            if (contentCurrent != null)
            {
                // DevDivBugs 146875: Expired Session State race condition
                // We make sure we do not overwrite an already existing item with an uninitialized item.
                if (((int)SessionStateItemFlags.Uninitialized & extraFlags) == 1)
                {
                    return(stateItem);
                }

                if (!GetOptionalNonNegativeInt32HeaderValue(context, StateHeaders.LOCKCOOKIE_NAME, out lockCookie))
                {
                    return(stateItem);
                }

                contentCurrent._spinLock.AcquireWriterLock();
                try {
                    if (contentCurrent._content == null)
                    {
                        ReportNotFound(context);
                        return(stateItem);
                    }

                    /* Only set the item if we are the owner */
                    if (contentCurrent._locked && (lockCookie == -1 || lockCookie != contentCurrent._lockCookie))
                    {
                        ReportLocked(context, contentCurrent);
                        return(stateItem);
                    }

                    if (contentCurrent._slidingExpiration == timeout && contentCurrent._content != null)
                    {
                        /* delete the old state item */
                        IntPtr stateItemOld = contentCurrent._stateItem;

                        /* change the item in place */
                        contentCurrent._content   = buf;
                        contentCurrent._stateItem = stateItem;
                        contentCurrent._locked    = false;
                        return(stateItemOld);
                    }

                    /*
                     *  The timeout has changed.  In this case, we are removing the old item and
                     *  inserting a new one.
                     *  Update _extraFlags to ignore the cache item removed callback (this way,
                     *  we will not decrease the number of active sessions).
                     */
                    contentCurrent._extraFlags |= (int)SessionStateItemFlags.IgnoreCacheItemRemoved;

                    /*
                     * If not locked, keep it locked until it is completely replaced.
                     * Prevent overwriting when we drop the lock.
                     */
                    contentCurrent._locked     = true;
                    contentCurrent._lockCookie = 0;
                    lockCookieNew = lockCookie;
                }
                finally {
                    contentCurrent._spinLock.ReleaseWriterLock();
                }
            }

            content = new CachedContent(buf, stateItem, false, DateTime.MinValue, timeout, lockCookieNew, extraFlags);
            cacheInternal.Insert(key, content, new CacheInsertOptions()
            {
                SlidingExpiration = timeout,
                Priority          = CacheItemPriority.NotRemovable,
                OnRemovedCallback = _removedHandler
            });

            if (contentCurrent == null)
            {
                IncrementStateServiceCounter(StateServicePerfCounter.STATE_SERVICE_SESSIONS_TOTAL);
                IncrementStateServiceCounter(StateServicePerfCounter.STATE_SERVICE_SESSIONS_ACTIVE);
            }

            return(IntPtr.Zero);
        }