예제 #1
0
        // 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
        }
예제 #2
0
        /*
         * 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);
        }
예제 #3
0
        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();
                }
            }
        }
예제 #4
0
        // 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();
         }
     }
 }