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 + ")"); } }
/// <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); }
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); }
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 }); } }
// 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)); } }
// 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(); }
// 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); }
// 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); }
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); }
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); }