// insert cached vary or output cache entry internal static void InsertResponse(String cachedVaryKey, CachedVary cachedVary, String rawResponseKey, CachedRawResponse rawResponse, CacheDependency dependencies, DateTime absExp, TimeSpan slidingExp) { // if the provider is undefined or the fragment can't be inserted in the // provider, insert it in the internal cache. OutputCacheProvider provider = GetProvider(HttpContext.Current); // // CachedVary can be serialized. // CachedRawResponse is not always serializable. // bool useProvider = (provider != null); if (useProvider) { bool canUseProvider = (IsSubstBlockSerializable(rawResponse._rawResponse) && rawResponse._settings.IsValidationCallbackSerializable() && slidingExp == Cache.NoSlidingExpiration && (dependencies == null || dependencies.IsFileDependency())); if (useProvider && !canUseProvider) { throw new ProviderException(SR.GetString(SR.Provider_does_not_support_policy_for_responses, provider.Name)); } } #if DBG bool cachedVaryPutInCache = (cachedVary != null); #endif if (cachedVary != null) { /* * Add the CachedVary item so that a request will know * which headers are needed to issue another request. * * Use the Add method so that we guarantee we only use * a single CachedVary and don't overwrite existing ones. */ CachedVary cachedVaryInCache; if (!useProvider) { cachedVaryInCache = OutputCache.UtcAdd(cachedVaryKey, cachedVary); } else { cachedVaryInCache = (CachedVary) provider.Add(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } if (cachedVaryInCache != null) { if (!cachedVary.Equals(cachedVaryInCache)) { if (!useProvider) { HttpRuntime.CacheInternal.UtcInsert(cachedVaryKey, cachedVary); } else { provider.Set(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } } else { cachedVary = cachedVaryInCache; #if DBG cachedVaryPutInCache = false; #endif } } if (!useProvider) { AddCacheKeyToDependencies(ref dependencies, cachedVaryKey); } // not all caches support cache key dependencies, but we can use a "change number" to associate // the ControlCachedVary and the PartialCachingCacheEntry rawResponse._cachedVaryId = cachedVary.CachedVaryId; } // Now insert into the cache (use cache provider if possible, otherwise use internal cache) if (!useProvider) { HttpRuntime.CacheInternal.UtcInsert(rawResponseKey, rawResponse, dependencies, absExp, slidingExp, CacheItemPriority.Normal, s_entryRemovedCallback); IncrementCount(); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE); } else { string depKey = null; string[] fileDeps = null; if (dependencies != null) { depKey = OUTPUTCACHE_KEYPREFIX_DEPENDENCIES + dependencies.GetUniqueID(); fileDeps = dependencies.GetFileDependencies(); } OutputCacheEntry oce = Convert(rawResponse, depKey, fileDeps); provider.Set(rawResponseKey, oce, absExp); if (dependencies != null) { // use Add and dispose dependencies if there's already one in the cache Object d = HttpRuntime.CacheInternal.UtcAdd(depKey, new DependencyCacheEntry(rawResponseKey, oce.KernelCacheUrl, provider.Name), dependencies, absExp, Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_dependencyRemovedCallback); if (d != null) { dependencies.Dispose(); } } } #if DBG string cachedVaryType = (cachedVaryPutInCache) ? "CachedVary" : ""; string providerUsed = (useProvider) ? provider.Name : "CacheInternal"; Debug.Trace("OutputCache", "InsertResposne(" + cachedVaryKey + ", " + cachedVaryType + ", " + rawResponseKey + ", CachedRawResponse, ...) -->" + providerUsed); #endif }
/* * If the item is cacheable, add it to the cache. */ /// <include file='doc\OutputCacheModule.uex' path='docs/doc[@for="OutputCacheModule.OnLeave"]/*' /> /// <devdoc> /// <para>Raises the <see langword='Leave'/> event, which causes any cacheable items to /// be put into the output cache.</para> /// </devdoc> internal /*public*/ void OnLeave(Object source, EventArgs eventArgs) { HttpApplication app; HttpContext context; bool cacheable; CachedRawResponse cachedRawResponse; CachedVary cachedVary; CachedVary cachedVaryInCache; HttpCachePolicy cache; HttpCachePolicySettings settings; CacheDependency dependency; CacheDependency dependencyVary; string keyRawResponse; string[] varyByHeaders; string[] varyByParams; bool varyByAllParams; HttpRequest request; HttpResponse response; DateTime utcTimestamp; TimeSpan slidingDelta; HttpRawResponse httpRawResponse; int i, n; DateTime utcExpires; bool cacheAuthorizedPage; CacheInternal cacheInternal; Debug.Trace("OutputCacheModuleLeave", "Beginning OutputCacheModule::Leave"); app = (HttpApplication)source; context = app.Context; request = context.Request; response = context.Response; cache = response.Cache; #if DBG string reason = null; #endif /* * Determine whether the response is cacheable. */ cacheable = false; do { if (!cache.IsModified()) { #if DBG reason = "CachePolicy was not modified from non-caching default."; #endif break; } if (_key == null) { #if DBG reason = "no key was created for Request in Enter method."; #endif break; } if (response.StatusCode != 200) { #if DBG reason = "response.StatusCode != 200."; #endif break; } if (_method == CacheRequestMethod.Head) { #if DBG reason = "the cache cannot cache responses to HEAD requests."; #endif break; } if (!response.IsBuffered()) { #if DBG reason = "the response is not buffered."; #endif break; } /* * Change a response with HttpCacheability.Public to HttpCacheability.Private * if it requires authorization, and allow it to be cached. * * Note that setting Cacheability to ServerAndPrivate would accomplish * the same thing without needing the "cacheAuthorizedPage" variable, * but in RTM we did not have ServerAndPrivate, and setting that value * would change the behavior. */ cacheAuthorizedPage = false; if (cache.GetCacheability() == HttpCacheability.Public && context.RequestRequiresAuthorization()) { cache.SetCacheability(HttpCacheability.Private); cacheAuthorizedPage = true; } if (cache.GetCacheability() != HttpCacheability.Public && cache.GetCacheability() != HttpCacheability.ServerAndPrivate && cache.GetCacheability() != HttpCacheability.ServerAndNoCache && !cacheAuthorizedPage) { #if DBG reason = "CachePolicy.Cacheability is not Public, ServerAndPrivate, or ServerAndNoCache."; #endif break; } if (cache.GetNoServerCaching()) { #if DBG reason = "CachePolicy.NoServerCaching is set."; #endif break; } if (!cache.HasExpirationPolicy() && !cache.HasValidationPolicy()) { #if DBG reason = "CachePolicy has no expiration policy or validation policy."; #endif break; } if (cache.VaryByHeaders.GetVaryByUnspecifiedParameters()) { #if DBG reason = "CachePolicy.Vary.VaryByUnspecifiedParameters was called."; #endif break; } if (!cache.VaryByParams.AcceptsParams() && (_method == CacheRequestMethod.Post || request.QueryStringText != String.Empty)) { #if DBG reason = "the cache cannot cache responses to POSTs or GETs with query strings unless Cache.VaryByParams is modified."; #endif break; } cacheable = true; } while (false); /* * Add response to cache. */ if (!cacheable) { #if DBG Debug.Assert(reason != null, "reason != null"); Debug.Trace("OutputCacheModuleLeave", "Item is not output cacheable because " + reason + "\n\tUrl=" + request.Url.ToString() + "\nReturning from OutputCacheModule::Leave"); #endif return; } RecordCacheMiss(); settings = cache.GetCurrentSettings(response); /* Determine the size of the sliding expiration.*/ utcTimestamp = context.UtcTimestamp; utcExpires = DateTime.MaxValue; if (settings.SlidingExpiration) { slidingDelta = settings.SlidingDelta; utcExpires = Cache.NoAbsoluteExpiration; } else { slidingDelta = Cache.NoSlidingExpiration; if (settings.IsMaxAgeSet) { utcExpires = utcTimestamp + settings.MaxAge; } else if (settings.IsExpiresSet) { utcExpires = settings.UtcExpires; } } varyByHeaders = settings.VaryByHeaders; if (settings.IgnoreParams) { varyByParams = null; } else { varyByParams = settings.VaryByParams; } cacheInternal = HttpRuntime.CacheInternal; if (varyByHeaders == null && varyByParams == null && settings.VaryByCustom == null) { /* * This is not a varyBy item. */ keyRawResponse = _key; cachedVary = null; dependencyVary = null; } else { /* * There is a vary in the cache policy. We handle this * by adding another item to the cache which contains * a list of the vary headers. A request for the item * without the vary headers in the key will return this * item. From the headers another key can be constructed * to lookup the item with the raw response. */ if (varyByHeaders != null) { for (i = 0, n = varyByHeaders.Length; i < n; i++) { varyByHeaders[i] = "HTTP_" + CultureInfo.InvariantCulture.TextInfo.ToUpper( varyByHeaders[i].Replace('-', '_')); } } varyByAllParams = false; if (varyByParams != null) { varyByAllParams = (varyByParams.Length == 1 && varyByParams[0] == "*"); if (varyByAllParams) { varyByParams = null; } else { for (i = 0, n = varyByParams.Length; i < n; i++) { varyByParams[i] = CultureInfo.InvariantCulture.TextInfo.ToLower(varyByParams[i]); } } } cachedVary = new CachedVary(varyByHeaders, varyByParams, varyByAllParams, settings.VaryByCustom); keyRawResponse = CreateOutputCachedItemKey(context, cachedVary); if (keyRawResponse == null) { Debug.Trace("OutputCacheModuleLeave", "Couldn't add non-cacheable post.\n\tkey=" + _key); return; } // it is possible that the user code calculating custom vary-by // string would Flush making the response non-cacheable. Check fo it here. if (!response.IsBuffered()) { Debug.Trace("OutputCacheModuleLeave", "Response.Flush() inside GetVaryByCustomString\n\tkey=" + _key); return; } /* * Add the CachedVary item so that a request will know * which headers are needed to issue another request. * * Use the Add method so that we guarantee we only use * a single CachedVary and don't overwrite existing ones. */ cachedVaryInCache = (CachedVary)cacheInternal.UtcAdd( _key, cachedVary, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Default, null); if (cachedVaryInCache != null) { if (cachedVary.Equals(cachedVaryInCache)) { cachedVary = cachedVaryInCache; } else { Debug.Trace("OutputCacheModuleLeave", "CachedVary definition changed, new CachedVary inserted into cache.\n\tkey=" + _key); cacheInternal.UtcInsert(_key, cachedVary); } } #if DBG else { Debug.Trace("OutputCacheModuleLeave", "Added CachedVary to cache.\n\tkey=" + _key); } #endif dependencyVary = new CacheDependency(false, null, new string[1] { _key }); } Debug.Trace("OutputCacheModuleLeave", "Adding response to cache.\n\tkey=" + keyRawResponse + "\nReturning from OutputCacheModule::Leave"); dependency = response.GetCacheDependency(dependencyVary); /* * Create the response object to be sent on cache hits. */ httpRawResponse = response.GetSnapshot(); cachedRawResponse = new CachedRawResponse(httpRawResponse, settings, cachedVary); Debug.Trace("OutputCacheModuleLeave", "utcExpires=" + utcExpires + "expires=" + DateTimeUtil.ConvertToLocalTime(utcExpires)); cacheInternal.UtcInsert( keyRawResponse, cachedRawResponse, dependency, utcExpires, slidingDelta, CacheItemPriority.Normal, s_cacheItemRemovedCallback); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE); }
internal static void InsertResponse(string cachedVaryKey, CachedVary cachedVary, string rawResponseKey, CachedRawResponse rawResponse, CacheDependency dependencies, DateTime absExp, TimeSpan slidingExp) { OutputCacheProvider provider = GetProvider(HttpContext.Current); bool flag = provider != null; if (flag) { bool flag2 = ((IsSubstBlockSerializable(rawResponse._rawResponse) && rawResponse._settings.IsValidationCallbackSerializable()) && (slidingExp == Cache.NoSlidingExpiration)) && ((dependencies == null) || dependencies.IsFileDependency()); if (flag && !flag2) { throw new ProviderException(System.Web.SR.GetString("Provider_does_not_support_policy_for_responses", new object[] { provider.Name })); } } if (cachedVary != null) { CachedVary vary; if (!flag) { vary = UtcAdd(cachedVaryKey, cachedVary); } else { vary = (CachedVary)provider.Add(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } if (vary != null) { if (!cachedVary.Equals(vary)) { if (!flag) { HttpRuntime.CacheInternal.UtcInsert(cachedVaryKey, cachedVary); } else { provider.Set(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } } else { cachedVary = vary; } } if (!flag) { AddCacheKeyToDependencies(ref dependencies, cachedVaryKey); } rawResponse._cachedVaryId = cachedVary.CachedVaryId; } if (!flag) { HttpRuntime.CacheInternal.UtcInsert(rawResponseKey, rawResponse, dependencies, absExp, slidingExp, CacheItemPriority.Normal, s_entryRemovedCallback); IncrementCount(); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE); } else { string depKey = null; string[] fileDependencies = null; if (dependencies != null) { depKey = "aD" + dependencies.GetUniqueID(); fileDependencies = dependencies.GetFileDependencies(); } OutputCacheEntry entry = Convert(rawResponse, depKey, fileDependencies); provider.Set(rawResponseKey, entry, absExp); if ((dependencies != null) && (HttpRuntime.CacheInternal.UtcAdd(depKey, new DependencyCacheEntry(rawResponseKey, entry.KernelCacheUrl, provider.Name), dependencies, absExp, Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_dependencyRemovedCallback) != null)) { dependencies.Dispose(); } } }
// insert cached vary or output cache entry internal static void InsertResponse(String cachedVaryKey, CachedVary cachedVary, String rawResponseKey, CachedRawResponse rawResponse, CacheDependency dependencies, DateTime absExp, TimeSpan slidingExp) { // if the provider is undefined or the fragment can't be inserted in the // provider, insert it in the internal cache. OutputCacheProvider provider = GetProvider(HttpContext.Current); // // CachedVary can be serialized. // CachedRawResponse is not always serializable. // bool useProvider = (provider != null); if (useProvider) { bool canUseProvider = (IsSubstBlockSerializable(rawResponse._rawResponse) && rawResponse._settings.IsValidationCallbackSerializable() && slidingExp == Cache.NoSlidingExpiration && (dependencies == null || dependencies.IsFileDependency())); if (useProvider && !canUseProvider) { throw new ProviderException(SR.GetString(SR.Provider_does_not_support_policy_for_responses, provider.Name)); } } #if DBG bool cachedVaryPutInCache = (cachedVary != null); #endif if (cachedVary != null) { /* * Add the CachedVary item so that a request will know * which headers are needed to issue another request. * * Use the Add method so that we guarantee we only use * a single CachedVary and don't overwrite existing ones. */ CachedVary cachedVaryInCache; if (!useProvider) { cachedVaryInCache = OutputCache.UtcAdd(cachedVaryKey, cachedVary); } else { cachedVaryInCache = (CachedVary)provider.Add(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } if (cachedVaryInCache != null) { if (!cachedVary.Equals(cachedVaryInCache)) { if (!useProvider) { HttpRuntime.CacheInternal.UtcInsert(cachedVaryKey, cachedVary); } else { provider.Set(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } } else { cachedVary = cachedVaryInCache; #if DBG cachedVaryPutInCache = false; #endif } } if (!useProvider) { AddCacheKeyToDependencies(ref dependencies, cachedVaryKey); } // not all caches support cache key dependencies, but we can use a "change number" to associate // the ControlCachedVary and the PartialCachingCacheEntry rawResponse._cachedVaryId = cachedVary.CachedVaryId; } // Now insert into the cache (use cache provider if possible, otherwise use internal cache) if (!useProvider) { HttpRuntime.CacheInternal.UtcInsert(rawResponseKey, rawResponse, dependencies, absExp, slidingExp, CacheItemPriority.Normal, s_entryRemovedCallback); IncrementCount(); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE); } else { string depKey = null; string[] fileDeps = null; if (dependencies != null) { depKey = OUTPUTCACHE_KEYPREFIX_DEPENDENCIES + dependencies.GetUniqueID(); fileDeps = dependencies.GetFileDependencies(); } OutputCacheEntry oce = Convert(rawResponse, depKey, fileDeps); provider.Set(rawResponseKey, oce, absExp); if (dependencies != null) { // use Add and dispose dependencies if there's already one in the cache Object d = HttpRuntime.CacheInternal.UtcAdd(depKey, new DependencyCacheEntry(rawResponseKey, oce.KernelCacheUrl, provider.Name), dependencies, absExp, Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_dependencyRemovedCallback); if (d != null) { dependencies.Dispose(); } } } #if DBG string cachedVaryType = (cachedVaryPutInCache) ? "CachedVary" : ""; string providerUsed = (useProvider) ? provider.Name : "CacheInternal"; Debug.Trace("OutputCache", "InsertResposne(" + cachedVaryKey + ", " + cachedVaryType + ", " + rawResponseKey + ", CachedRawResponse, ...) -->" + providerUsed); #endif }
internal static void InsertResponse(string cachedVaryKey, CachedVary cachedVary, string rawResponseKey, CachedRawResponse rawResponse, CacheDependency dependencies, DateTime absExp, TimeSpan slidingExp) { OutputCacheProvider provider = GetProvider(HttpContext.Current); bool flag = provider != null; if (flag) { bool flag2 = ((IsSubstBlockSerializable(rawResponse._rawResponse) && rawResponse._settings.IsValidationCallbackSerializable()) && (slidingExp == Cache.NoSlidingExpiration)) && ((dependencies == null) || dependencies.IsFileDependency()); if (flag && !flag2) { throw new ProviderException(System.Web.SR.GetString("Provider_does_not_support_policy_for_responses", new object[] { provider.Name })); } } if (cachedVary != null) { CachedVary vary; if (!flag) { vary = UtcAdd(cachedVaryKey, cachedVary); } else { vary = (CachedVary) provider.Add(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } if (vary != null) { if (!cachedVary.Equals(vary)) { if (!flag) { HttpRuntime.CacheInternal.UtcInsert(cachedVaryKey, cachedVary); } else { provider.Set(cachedVaryKey, cachedVary, Cache.NoAbsoluteExpiration); } } else { cachedVary = vary; } } if (!flag) { AddCacheKeyToDependencies(ref dependencies, cachedVaryKey); } rawResponse._cachedVaryId = cachedVary.CachedVaryId; } if (!flag) { HttpRuntime.CacheInternal.UtcInsert(rawResponseKey, rawResponse, dependencies, absExp, slidingExp, CacheItemPriority.Normal, s_entryRemovedCallback); IncrementCount(); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES); PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE); } else { string depKey = null; string[] fileDependencies = null; if (dependencies != null) { depKey = "aD" + dependencies.GetUniqueID(); fileDependencies = dependencies.GetFileDependencies(); } OutputCacheEntry entry = Convert(rawResponse, depKey, fileDependencies); provider.Set(rawResponseKey, entry, absExp); if ((dependencies != null) && (HttpRuntime.CacheInternal.UtcAdd(depKey, new DependencyCacheEntry(rawResponseKey, entry.KernelCacheUrl, provider.Name), dependencies, absExp, Cache.NoSlidingExpiration, CacheItemPriority.Normal, s_dependencyRemovedCallback) != null)) { dependencies.Dispose(); } } }