Example #1
0
        // only used by internal cache
        private static void EntryRemovedCallback(string key, object value, CacheItemRemovedReason reason)
        {
            Debug.Trace("OutputCache", "EntryRemovedCallback: reason=" + reason + ", key=" + key);

            DecrementCount();

            PerfCounters.DecrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES);
            PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE);

            CachedRawResponse cachedRawResponse = value as CachedRawResponse;

            if (cachedRawResponse != null)
            {
                String kernelCacheUrl = cachedRawResponse._kernelCacheUrl;
                // if it is kernel cached, the url will be non-null.
                // if the entry was re-inserted, don't remove kernel entry since it will be updated
                if (kernelCacheUrl != null && HttpRuntime.CacheInternal.Get(key) == null)
                {
                    // invalidate kernel cache entry
                    if (HttpRuntime.UseIntegratedPipeline)
                    {
                        UnsafeIISMethods.MgdFlushKernelCache(kernelCacheUrl);
                    }
                    else
                    {
                        UnsafeNativeMethods.InvalidateKernelCache(kernelCacheUrl);
                    }
                }
            }
        }
Example #2
0
        private static OutputCacheEntry Convert(CachedRawResponse cachedRawResponse, string depKey, string[] fileDependencies)
        {
            List <HeaderElement> headerElements = null;
            ArrayList            headers        = cachedRawResponse._rawResponse.Headers;
            int count = (headers != null) ? headers.Count : 0;

            for (int i = 0; i < count; i++)
            {
                if (headerElements == null)
                {
                    headerElements = new List <HeaderElement>(count);
                }
                HttpResponseHeader h = (HttpResponseHeader)(headers[i]);
                headerElements.Add(new HeaderElement(h.Name, h.Value));
            }

            List <ResponseElement> responseElements = null;
            ArrayList buffers = cachedRawResponse._rawResponse.Buffers;

            count = (buffers != null) ? buffers.Count : 0;
            for (int i = 0; i < count; i++)
            {
                if (responseElements == null)
                {
                    responseElements = new List <ResponseElement>(count);
                }
                IHttpResponseElement elem = buffers[i] as IHttpResponseElement;
                if (elem is HttpFileResponseElement)
                {
                    HttpFileResponseElement fileElement = elem as HttpFileResponseElement;
                    responseElements.Add(new FileResponseElement(fileElement.FileName, fileElement.Offset, elem.GetSize()));
                }
                else if (elem is HttpSubstBlockResponseElement)
                {
                    HttpSubstBlockResponseElement substElement = elem as HttpSubstBlockResponseElement;
                    responseElements.Add(new SubstitutionResponseElement(substElement.Callback));
                }
                else
                {
                    byte[] b      = elem.GetBytes();
                    long   length = (b != null) ? b.Length : 0;
                    responseElements.Add(new MemoryResponseElement(b, length));
                }
            }

            OutputCacheEntry oce = new OutputCacheEntry(
                cachedRawResponse._cachedVaryId,
                cachedRawResponse._settings,
                cachedRawResponse._kernelCacheUrl,
                depKey,
                fileDependencies,
                cachedRawResponse._rawResponse.StatusCode,
                cachedRawResponse._rawResponse.StatusDescription,
                headerElements,
                responseElements
                );

            return(oce);
        }
Example #3
0
        static void OnRawResponseRemoved(string key, object value, CacheItemRemovedReason reason)
        {
            CachedRawResponse c = (CachedRawResponse)value;

            c.VaryBy.ItemList.Remove(key);
            if (c.VaryBy.ItemList.Count != 0)
            {
                return;
            }

            HttpRuntime.Cache.Remove(c.VaryBy.Key);
        }
Example #4
0
        private static OutputCacheEntry Convert(CachedRawResponse cachedRawResponse, string depKey, string[] fileDependencies)
        {
            List <HeaderElement> headerElements = null;
            ArrayList            headers        = cachedRawResponse._rawResponse.Headers;
            int capacity = (headers != null) ? headers.Count : 0;

            for (int i = 0; i < capacity; i++)
            {
                if (headerElements == null)
                {
                    headerElements = new List <HeaderElement>(capacity);
                }
                HttpResponseHeader header = (HttpResponseHeader)headers[i];
                headerElements.Add(new HeaderElement(header.Name, header.Value));
            }
            List <ResponseElement> responseElements = null;
            ArrayList buffers = cachedRawResponse._rawResponse.Buffers;

            capacity = (buffers != null) ? buffers.Count : 0;
            for (int j = 0; j < capacity; j++)
            {
                if (responseElements == null)
                {
                    responseElements = new List <ResponseElement>(capacity);
                }
                IHttpResponseElement element = buffers[j] as IHttpResponseElement;
                if (element is HttpFileResponseElement)
                {
                    HttpFileResponseElement element2 = element as HttpFileResponseElement;
                    responseElements.Add(new FileResponseElement(element2.FileName, element2.Offset, element.GetSize()));
                }
                else if (element is HttpSubstBlockResponseElement)
                {
                    HttpSubstBlockResponseElement element3 = element as HttpSubstBlockResponseElement;
                    responseElements.Add(new SubstitutionResponseElement(element3.Callback));
                }
                else
                {
                    byte[] bytes  = element.GetBytes();
                    long   length = (bytes != null) ? ((long)bytes.Length) : ((long)0);
                    responseElements.Add(new MemoryResponseElement(bytes, length));
                }
            }
            return(new OutputCacheEntry(cachedRawResponse._cachedVaryId, cachedRawResponse._settings, cachedRawResponse._kernelCacheUrl, depKey, fileDependencies, cachedRawResponse._rawResponse.StatusCode, cachedRawResponse._rawResponse.StatusDescription, headerElements, responseElements));
        }
Example #5
0
        void OnRawResponseRemoved(string key, object value, CacheItemRemovedReason reason)
        {
            CachedRawResponse c      = value as CachedRawResponse;
            CachedVaryBy      varyby = c != null ? c.VaryBy : null;

            if (varyby == null)
            {
                return;
            }

            List <string>       itemList = varyby.ItemList;
            OutputCacheProvider provider = FindCacheProvider(null);

            itemList.Remove(key);
            provider.Remove(key);

            if (itemList.Count != 0)
            {
                return;
            }

            provider.Remove(varyby.Key);
        }
Example #6
0
        private static void EntryRemovedCallback(string key, object value, CacheItemRemovedReason reason)
        {
            DecrementCount();
            PerfCounters.DecrementCounter(AppPerfCounter.OUTPUT_CACHE_ENTRIES);
            PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_TURNOVER_RATE);
            CachedRawResponse response = value as CachedRawResponse;

            if (response != null)
            {
                string cacheKey = response._kernelCacheUrl;
                if ((cacheKey != null) && (HttpRuntime.CacheInternal.Get(key) == null))
                {
                    if (HttpRuntime.UseIntegratedPipeline)
                    {
                        UnsafeIISMethods.MgdFlushKernelCache(cacheKey);
                    }
                    else
                    {
                        System.Web.UnsafeNativeMethods.InvalidateKernelCache(cacheKey);
                    }
                }
            }
        }
Example #7
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
        }
 private static OutputCacheEntry Convert(CachedRawResponse cachedRawResponse, string depKey, string[] fileDependencies)
 {
     List<HeaderElement> headerElements = null;
     ArrayList headers = cachedRawResponse._rawResponse.Headers;
     int capacity = (headers != null) ? headers.Count : 0;
     for (int i = 0; i < capacity; i++)
     {
         if (headerElements == null)
         {
             headerElements = new List<HeaderElement>(capacity);
         }
         HttpResponseHeader header = (HttpResponseHeader) headers[i];
         headerElements.Add(new HeaderElement(header.Name, header.Value));
     }
     List<ResponseElement> responseElements = null;
     ArrayList buffers = cachedRawResponse._rawResponse.Buffers;
     capacity = (buffers != null) ? buffers.Count : 0;
     for (int j = 0; j < capacity; j++)
     {
         if (responseElements == null)
         {
             responseElements = new List<ResponseElement>(capacity);
         }
         IHttpResponseElement element = buffers[j] as IHttpResponseElement;
         if (element is HttpFileResponseElement)
         {
             HttpFileResponseElement element2 = element as HttpFileResponseElement;
             responseElements.Add(new FileResponseElement(element2.FileName, element2.Offset, element.GetSize()));
         }
         else if (element is HttpSubstBlockResponseElement)
         {
             HttpSubstBlockResponseElement element3 = element as HttpSubstBlockResponseElement;
             responseElements.Add(new SubstitutionResponseElement(element3.Callback));
         }
         else
         {
             byte[] bytes = element.GetBytes();
             long length = (bytes != null) ? ((long) bytes.Length) : ((long) 0);
             responseElements.Add(new MemoryResponseElement(bytes, length));
         }
     }
     return new OutputCacheEntry(cachedRawResponse._cachedVaryId, cachedRawResponse._settings, cachedRawResponse._kernelCacheUrl, depKey, fileDependencies, cachedRawResponse._rawResponse.StatusCode, cachedRawResponse._rawResponse.StatusDescription, headerElements, responseElements);
 }
Example #9
0
        private static CachedRawResponse Convert(OutputCacheEntry oce)
        {
            ArrayList headers = null;

            if (oce.HeaderElements != null && oce.HeaderElements.Count > 0)
            {
                headers = new ArrayList(oce.HeaderElements.Count);
                for (int i = 0; i < oce.HeaderElements.Count; i++)
                {
                    HttpResponseHeader h = new HttpResponseHeader(oce.HeaderElements[i].Name, oce.HeaderElements[i].Value);
                    headers.Add(h);
                }
            }

            ArrayList buffers = null;

            if (oce.ResponseElements != null && oce.ResponseElements.Count > 0)
            {
                buffers = new ArrayList(oce.ResponseElements.Count);
                for (int i = 0; i < oce.ResponseElements.Count; i++)
                {
                    ResponseElement      re   = oce.ResponseElements[i];
                    IHttpResponseElement elem = null;
                    if (re is FileResponseElement)
                    {
                        HttpContext       context     = HttpContext.Current;
                        HttpWorkerRequest wr          = (context != null) ? context.WorkerRequest : null;
                        bool supportsLongTransmitFile = (wr != null && wr.SupportsLongTransmitFile);
                        bool isImpersonating          = ((context != null && context.IsClientImpersonationConfigured) || HttpRuntime.IsOnUNCShareInternal);
                        FileResponseElement fre       = (FileResponseElement)re;

                        // DevDiv #21203: Need to verify permission to access the requested file since handled by native code.
                        HttpRuntime.CheckFilePermission(fre.Path);

                        elem = new HttpFileResponseElement(fre.Path, fre.Offset, fre.Length, isImpersonating, supportsLongTransmitFile);
                    }
                    else if (re is MemoryResponseElement)
                    {
                        MemoryResponseElement mre = (MemoryResponseElement)re;
                        int size = System.Convert.ToInt32(mre.Length);
                        elem = new HttpResponseBufferElement(mre.Buffer, size);
                    }
                    else if (re is SubstitutionResponseElement)
                    {
                        SubstitutionResponseElement sre = (SubstitutionResponseElement)re;
                        elem = new HttpSubstBlockResponseElement(sre.Callback);
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }
                    buffers.Add(elem);
                }
            }
            else
            {
                buffers = new ArrayList();
            }

            HttpRawResponse   rawResponse       = new HttpRawResponse(oce.StatusCode, oce.StatusDescription, headers, buffers, false /*hasSubstBlocks*/);
            CachedRawResponse cachedRawResponse = new CachedRawResponse(rawResponse, oce.Settings, oce.KernelCacheUrl, oce.CachedVaryId);

            return(cachedRawResponse);
        }
 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();
         }
     }
 }
Example #11
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();
                }
            }
        }
        /*
         * If the item is cacheable, add it to the cache.
         */

        /// <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;
            CachedVary              cachedVary;
            HttpCachePolicy         cache;
            HttpCachePolicySettings settings;
            string                  keyRawResponse;                
            string[]                varyByContentEncodings;
            string[]                varyByHeaders;
            string[]                varyByParams;
            bool                    varyByAllParams;
            HttpRequest             request;                        
            HttpResponse            response;                       
            int                     i, n;
            bool                    cacheAuthorizedPage;

            Debug.Trace("OutputCacheModuleLeave", "Beginning OutputCacheModule::Leave");

            app = (HttpApplication)source;
            context = app.Context;
            request = context.Request;
            response = context.Response;
            cache = null;

#if DBG
            string  reason = null;
#endif
            /*
             * Determine whether the response is cacheable.
             */
            cacheable = false;
            do {
                if (!response.HasCachePolicy) {
#if DBG
                    reason = "CachePolicy not created, not modified from non-caching default.";
#endif
                    break;
                }

                cache = response.Cache;
                if (!cache.IsModified()) {
#if DBG
                    reason = "CachePolicy created, but not modified from non-caching default.";
#endif
                    break;
                }

                if (response.StatusCode != 200) {
#if DBG
                    reason = "response.StatusCode != 200.";
#endif
                    break;
                }

                if (request.HttpVerb != HttpVerb.GET && request.HttpVerb != HttpVerb.POST) {
#if DBG
                    reason = "the cache can only cache responses to GET and POST.";
#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;
                }

                // MSRC 11855 (DevDiv 297240 / 362405) - We should suppress output caching for responses which contain non-shareable cookies.
                // We already disable the HTTP.SYS and IIS user mode cache when *any* response cookie is present (see IIS7WorkerRequest.SendUnknownResponseHeader)
                if (response.ContainsNonShareableCookies()) {
#if DBG
                    reason = "Non-shareable response cookies were present.";
#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() && (request.HttpVerb == HttpVerb.POST || request.HasQueryString)) {
#if DBG
                    reason = "the cache cannot cache responses to POSTs or GETs with query strings unless Cache.VaryByParams is modified.";
#endif
                    break;
                }

                if (cache.VaryByContentEncodings.IsModified() && !cache.VaryByContentEncodings.IsCacheableEncoding(context.Response.GetHttpHeaderContentEncoding())) {
#if DBG
                    reason = "the cache cannot cache encoded responses that are not listed in the VaryByContentEncodings collection.";
#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.Path + 
                            "\nReturning from OutputCacheModule::Leave");
#endif

                return;
            }

            RecordCacheMiss();

            settings = cache.GetCurrentSettings(response);

            varyByContentEncodings = settings.VaryByContentEncodings;

            varyByHeaders = settings.VaryByHeaders;
            if (settings.IgnoreParams) {
                varyByParams = null;
            }
            else {
                varyByParams = settings.VaryByParams;
            }


            /* Create the key if it was not created in OnEnter */
            if (_key == null) {
                _key = CreateOutputCachedItemKey(context, null);
                Debug.Assert(_key != null, "_key != null");
            }


            if (varyByContentEncodings == null && varyByHeaders == null && varyByParams == null && settings.VaryByCustom == null) {
                /*
                 * This is not a varyBy item.
                 */
                keyRawResponse = _key;
                cachedVary = 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] == ASTERISK);
                    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(varyByContentEncodings, 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;
                }
            }

            DateTime utcExpires = Cache.NoAbsoluteExpiration;
            TimeSpan slidingDelta = Cache.NoSlidingExpiration;

            if (settings.SlidingExpiration) {
                slidingDelta = settings.SlidingDelta;
            }
            else if (settings.IsMaxAgeSet) {
                DateTime utcTimestamp = (settings.UtcTimestampCreated != DateTime.MinValue) ? settings.UtcTimestampCreated : context.UtcTimestamp;
                utcExpires = utcTimestamp + settings.MaxAge;
            }
            else if (settings.IsExpiresSet) {
                utcExpires = settings.UtcExpires;
            }
            
            // Check and ensure that item hasn't expired:
            if (utcExpires > DateTime.UtcNow) {

                // Create the response object to be sent on cache hits.
                HttpRawResponse httpRawResponse = response.GetSnapshot();
                string kernelCacheUrl = response.SetupKernelCaching(null);
                Guid cachedVaryId = (cachedVary != null) ? cachedVary.CachedVaryId : Guid.Empty;
                CachedRawResponse cachedRawResponse = new CachedRawResponse(httpRawResponse, settings, kernelCacheUrl, cachedVaryId);

                Debug.Trace("OutputCacheModuleLeave", "Adding response to cache.\n\tkey=" + keyRawResponse);

                CacheDependency dep = response.CreateCacheDependencyForResponse();
                try {
                    OutputCache.InsertResponse(_key, cachedVary,
                                               keyRawResponse, cachedRawResponse,
                                               dep,
                                               utcExpires, slidingDelta);
                }
                catch {
                    if (dep != null) {
                        dep.Dispose();
                    }
                    throw;
                }
            }

            _key = null;
            
            Debug.Trace("OutputCacheModuleLeave", "Returning from OutputCacheModule::Leave");
        }
        private static CachedRawResponse Convert(OutputCacheEntry oce) {            
            ArrayList headers = null;
            if (oce.HeaderElements != null && oce.HeaderElements.Count > 0) {
                headers = new ArrayList(oce.HeaderElements.Count);
                for (int i = 0; i < oce.HeaderElements.Count; i++) {
                    HttpResponseHeader h = new HttpResponseHeader(oce.HeaderElements[i].Name, oce.HeaderElements[i].Value);
                    headers.Add(h);
                }                
            }

            ArrayList buffers = null;
            if (oce.ResponseElements != null && oce.ResponseElements.Count > 0) {
                buffers = new ArrayList(oce.ResponseElements.Count);
                for (int i = 0; i < oce.ResponseElements.Count; i++) {
                    ResponseElement re = oce.ResponseElements[i];
                    IHttpResponseElement elem = null;
                    if (re is FileResponseElement) {
                        HttpContext context = HttpContext.Current;
                        HttpWorkerRequest wr = (context != null) ? context.WorkerRequest : null;
                        bool supportsLongTransmitFile = (wr != null && wr.SupportsLongTransmitFile);
                        bool isImpersonating = ((context != null && context.IsClientImpersonationConfigured) || HttpRuntime.IsOnUNCShareInternal);
                        FileResponseElement fre = (FileResponseElement)re;

                        // DevDiv #21203: Need to verify permission to access the requested file since handled by native code.
                        HttpRuntime.CheckFilePermission(fre.Path);

                        elem = new HttpFileResponseElement(fre.Path, fre.Offset, fre.Length, isImpersonating, supportsLongTransmitFile);
                    }
                    else if (re is MemoryResponseElement) {
                        MemoryResponseElement mre = (MemoryResponseElement)re;
                        int size = System.Convert.ToInt32(mre.Length);
                        elem = new HttpResponseBufferElement(mre.Buffer, size);
                    }
                    else if (re is SubstitutionResponseElement) {
                        SubstitutionResponseElement sre = (SubstitutionResponseElement)re;
                        elem = new HttpSubstBlockResponseElement(sre.Callback);                        
                    }
                    else {
                        throw new NotSupportedException();
                    }
                    buffers.Add(elem);
                }
            }
            else {
                buffers = new ArrayList();
            }
            
            HttpRawResponse rawResponse = new HttpRawResponse(oce.StatusCode, oce.StatusDescription, headers, buffers, false /*hasSubstBlocks*/);
            CachedRawResponse cachedRawResponse = new CachedRawResponse(rawResponse, oce.Settings, oce.KernelCacheUrl, oce.CachedVaryId);

            return cachedRawResponse;
        }
Example #14
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);
        }
Example #15
0
        void DoCacheInsert(HttpContext context, HttpApplication app, HttpResponse response)
        {
            string vary_key = context.Request.FilePath;
            string key;
            OutputCacheProvider provider = FindCacheProvider(app);
            CachedVaryBy        varyby = provider.Get(vary_key) as CachedVaryBy;
            CachedRawResponse   prev = null;
            bool            lookup = true;
            string          cacheKey = null, cacheValue = null;
            HttpCachePolicy cachePolicy = response.Cache;

            if (varyby == null)
            {
                varyby = new CachedVaryBy(cachePolicy, vary_key);
                provider.Add(vary_key, varyby, Cache.NoAbsoluteExpiration);
                lookup   = false;
                cacheKey = vary_key;
            }

            key = varyby.CreateKey(vary_key, context);

            if (lookup)
            {
                prev = provider.Get(key) as CachedRawResponse;
            }

            if (prev == null)
            {
                CachedRawResponse c = response.GetCachedResponse();
                if (c != null)
                {
                    string [] keys = new string [] { vary_key };
                    DateTime  utcExpiry, absoluteExpiration;
                    TimeSpan  slidingExpiration;

                    c.VaryBy = varyby;
                    varyby.ItemList.Add(key);

                    if (cachePolicy.Sliding)
                    {
                        slidingExpiration  = TimeSpan.FromSeconds(cachePolicy.Duration);
                        absoluteExpiration = Cache.NoAbsoluteExpiration;
                        utcExpiry          = DateTime.UtcNow + slidingExpiration;
                    }
                    else
                    {
                        slidingExpiration  = Cache.NoSlidingExpiration;
                        absoluteExpiration = cachePolicy.Expires;
                        utcExpiry          = absoluteExpiration.ToUniversalTime();
                    }

                    provider.Set(key, c, utcExpiry);
                    HttpRuntime.InternalCache.Insert(key, c, new CacheDependency(null, keys), absoluteExpiration, slidingExpiration,
                                                     CacheItemPriority.Normal, response_removed);
                    cacheValue = key;
                }
            }

            if (cacheKey != null)
            {
                lock (keysCacheLock) {
                    if (keysCache == null)
                    {
                        BuildManager.RemoveEntry += new BuildManagerRemoveEntryEventHandler(OnBuildManagerRemoveEntry);
                        keysCache = new Dictionary <string, string> (StringComparer.Ordinal);
                        keysCache.Add(cacheKey, cacheValue);
                    }
                    else if (!keysCache.ContainsKey(cacheKey))
                    {
                        keysCache.Add(cacheKey, cacheValue);
                    }
                }
            }
        }
        internal void OnLeave(object source, EventArgs eventArgs)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext     context     = application.Context;
            HttpRequest     request     = context.Request;
            HttpResponse    response    = context.Response;
            HttpCachePolicy cache       = null;
            bool            flag        = false;

            if (response.HasCachePolicy)
            {
                cache = response.Cache;
                if (((cache.IsModified() && (response.Cookies.Count <= 0)) && (response.StatusCode == 200)) && (((request.HttpVerb == HttpVerb.GET) || (request.HttpVerb == HttpVerb.POST)) && response.IsBuffered()))
                {
                    bool flag3 = false;
                    if ((cache.GetCacheability() == HttpCacheability.Public) && context.RequestRequiresAuthorization())
                    {
                        cache.SetCacheability(HttpCacheability.Private);
                        flag3 = true;
                    }
                    if (((((cache.GetCacheability() == HttpCacheability.Public) || (cache.GetCacheability() == HttpCacheability.ServerAndPrivate)) || ((cache.GetCacheability() == HttpCacheability.Server) || flag3)) && (!cache.GetNoServerCaching() && (cache.HasExpirationPolicy() || cache.HasValidationPolicy()))) && ((!cache.VaryByHeaders.GetVaryByUnspecifiedParameters() && (cache.VaryByParams.AcceptsParams() || ((request.HttpVerb != HttpVerb.POST) && !request.HasQueryString))) && (!cache.VaryByContentEncodings.IsModified() || cache.VaryByContentEncodings.IsCacheableEncoding(context.Response.GetHttpHeaderContentEncoding()))))
                    {
                        flag = true;
                    }
                }
            }
            if (flag)
            {
                CachedVary vary;
                string     str;
                string[]   varyByParams;
                this.RecordCacheMiss();
                HttpCachePolicySettings currentSettings = cache.GetCurrentSettings(response);
                string[] varyByContentEncodings         = currentSettings.VaryByContentEncodings;
                string[] varyByHeaders = currentSettings.VaryByHeaders;
                if (currentSettings.IgnoreParams)
                {
                    varyByParams = null;
                }
                else
                {
                    varyByParams = currentSettings.VaryByParams;
                }
                if (this._key == null)
                {
                    this._key = this.CreateOutputCachedItemKey(context, null);
                }
                if (((varyByContentEncodings == null) && (varyByHeaders == null)) && ((varyByParams == null) && (currentSettings.VaryByCustom == null)))
                {
                    str  = this._key;
                    vary = null;
                }
                else
                {
                    int num;
                    int length;
                    if (varyByHeaders != null)
                    {
                        num    = 0;
                        length = varyByHeaders.Length;
                        while (num < length)
                        {
                            varyByHeaders[num] = "HTTP_" + CultureInfo.InvariantCulture.TextInfo.ToUpper(varyByHeaders[num].Replace('-', '_'));
                            num++;
                        }
                    }
                    bool varyByAllParams = false;
                    if (varyByParams != null)
                    {
                        varyByAllParams = (varyByParams.Length == 1) && (varyByParams[0] == "*");
                        if (varyByAllParams)
                        {
                            varyByParams = null;
                        }
                        else
                        {
                            num    = 0;
                            length = varyByParams.Length;
                            while (num < length)
                            {
                                varyByParams[num] = CultureInfo.InvariantCulture.TextInfo.ToLower(varyByParams[num]);
                                num++;
                            }
                        }
                    }
                    vary = new CachedVary(varyByContentEncodings, varyByHeaders, varyByParams, varyByAllParams, currentSettings.VaryByCustom);
                    str  = this.CreateOutputCachedItemKey(context, vary);
                    if (str == null)
                    {
                        return;
                    }
                    if (!response.IsBuffered())
                    {
                        return;
                    }
                }
                DateTime noAbsoluteExpiration = Cache.NoAbsoluteExpiration;
                TimeSpan noSlidingExpiration  = Cache.NoSlidingExpiration;
                if (currentSettings.SlidingExpiration)
                {
                    noSlidingExpiration = currentSettings.SlidingDelta;
                }
                else if (currentSettings.IsMaxAgeSet)
                {
                    DateTime time2 = (currentSettings.UtcTimestampCreated != DateTime.MinValue) ? currentSettings.UtcTimestampCreated : context.UtcTimestamp;
                    noAbsoluteExpiration = time2 + currentSettings.MaxAge;
                }
                else if (currentSettings.IsExpiresSet)
                {
                    noAbsoluteExpiration = currentSettings.UtcExpires;
                }
                if (noAbsoluteExpiration > DateTime.UtcNow)
                {
                    HttpRawResponse   snapshot       = response.GetSnapshot();
                    string            kernelCacheUrl = response.SetupKernelCaching(null);
                    Guid              cachedVaryId   = (vary != null) ? vary.CachedVaryId : Guid.Empty;
                    CachedRawResponse rawResponse    = new CachedRawResponse(snapshot, currentSettings, kernelCacheUrl, cachedVaryId);
                    CacheDependency   dependencies   = response.CreateCacheDependencyForResponse();
                    try
                    {
                        OutputCache.InsertResponse(this._key, vary, str, rawResponse, dependencies, noAbsoluteExpiration, noSlidingExpiration);
                    }
                    catch
                    {
                        if (dependencies != null)
                        {
                            dependencies.Dispose();
                        }
                        throw;
                    }
                }
                this._key = null;
            }
        }
        internal void OnEnter(object source, EventArgs eventArgs)
        {
            this._key = null;
            this._recordedCacheMiss = false;
            if (OutputCache.InUse)
            {
                string[]        strArray2   = null;
                string[]        strArray3   = null;
                HttpApplication application = (HttpApplication)source;
                HttpContext     context     = application.Context;
                context.GetFilePathData();
                HttpRequest  request  = context.Request;
                HttpResponse response = context.Response;
                switch (request.HttpVerb)
                {
                case HttpVerb.GET:
                case HttpVerb.HEAD:
                case HttpVerb.POST:
                {
                    string str;
                    this._key = str = this.CreateOutputCachedItemKey(context, null);
                    object obj2 = OutputCache.Get(str);
                    if (obj2 != null)
                    {
                        int        num;
                        int        length;
                        CachedVary cachedVary = obj2 as CachedVary;
                        if (cachedVary != null)
                        {
                            str = this.CreateOutputCachedItemKey(context, cachedVary);
                            if (str == null)
                            {
                                return;
                            }
                            if (cachedVary._contentEncodings == null)
                            {
                                obj2 = OutputCache.Get(str);
                            }
                            else
                            {
                                obj2 = null;
                                bool   flag3 = true;
                                string knownRequestHeader = context.WorkerRequest.GetKnownRequestHeader(0x16);
                                if (knownRequestHeader != null)
                                {
                                    string[] contentEncodings = cachedVary._contentEncodings;
                                    int      startIndex       = 0;
                                    bool     flag4            = false;
                                    while (!flag4)
                                    {
                                        flag4 = true;
                                        int index = GetAcceptableEncoding(contentEncodings, startIndex, knownRequestHeader);
                                        if (index > -1)
                                        {
                                            flag3 = false;
                                            obj2  = OutputCache.Get(str + contentEncodings[index]);
                                            if (obj2 == null)
                                            {
                                                startIndex = index + 1;
                                                if (startIndex < contentEncodings.Length)
                                                {
                                                    flag4 = false;
                                                }
                                            }
                                        }
                                        else if (index == -2)
                                        {
                                            flag3 = false;
                                        }
                                    }
                                }
                                if ((obj2 == null) && flag3)
                                {
                                    obj2 = OutputCache.Get(str);
                                }
                            }
                            if ((obj2 == null) || (((CachedRawResponse)obj2)._cachedVaryId != cachedVary.CachedVaryId))
                            {
                                if (obj2 != null)
                                {
                                    OutputCache.Remove(str, context);
                                }
                                return;
                            }
                        }
                        CachedRawResponse       response2 = (CachedRawResponse)obj2;
                        HttpCachePolicySettings settings  = response2._settings;
                        if ((cachedVary == null) && !settings.IgnoreParams)
                        {
                            if (request.HttpVerb == HttpVerb.POST)
                            {
                                this.RecordCacheMiss();
                                return;
                            }
                            if (request.HasQueryString)
                            {
                                this.RecordCacheMiss();
                                return;
                            }
                        }
                        if (settings.IgnoreRangeRequests)
                        {
                            string str8 = request.Headers["Range"];
                            if (StringUtil.StringStartsWithIgnoreCase(str8, "bytes"))
                            {
                                return;
                            }
                        }
                        if (!settings.HasValidationPolicy())
                        {
                            string str4 = request.Headers["Cache-Control"];
                            if (str4 != null)
                            {
                                strArray2 = str4.Split(s_fieldSeparators);
                                for (num = 0; num < strArray2.Length; num++)
                                {
                                    string str6 = strArray2[num];
                                    switch (str6)
                                    {
                                    case "no-cache":
                                    case "no-store":
                                        this.RecordCacheMiss();
                                        return;
                                    }
                                    if (StringUtil.StringStartsWith(str6, "max-age="))
                                    {
                                        int num4;
                                        try
                                        {
                                            num4 = Convert.ToInt32(str6.Substring(8), CultureInfo.InvariantCulture);
                                        }
                                        catch
                                        {
                                            num4 = -1;
                                        }
                                        if (num4 >= 0)
                                        {
                                            int num6 = (int)((context.UtcTimestamp.Ticks - settings.UtcTimestampCreated.Ticks) / 0x989680L);
                                            if (num6 >= num4)
                                            {
                                                this.RecordCacheMiss();
                                                return;
                                            }
                                        }
                                    }
                                    else if (StringUtil.StringStartsWith(str6, "min-fresh="))
                                    {
                                        int num5;
                                        try
                                        {
                                            num5 = Convert.ToInt32(str6.Substring(10), CultureInfo.InvariantCulture);
                                        }
                                        catch
                                        {
                                            num5 = -1;
                                        }
                                        if (((num5 >= 0) && settings.IsExpiresSet) && !settings.SlidingExpiration)
                                        {
                                            int num7 = (int)((settings.UtcExpires.Ticks - context.UtcTimestamp.Ticks) / 0x989680L);
                                            if (num7 < num5)
                                            {
                                                this.RecordCacheMiss();
                                                return;
                                            }
                                        }
                                    }
                                }
                            }
                            string str5 = request.Headers["Pragma"];
                            if (str5 != null)
                            {
                                strArray3 = str5.Split(s_fieldSeparators);
                                for (num = 0; num < strArray3.Length; num++)
                                {
                                    if (strArray3[num] == "no-cache")
                                    {
                                        this.RecordCacheMiss();
                                        return;
                                    }
                                }
                            }
                        }
                        else if (settings.ValidationCallbackInfo != null)
                        {
                            HttpValidationStatus valid             = HttpValidationStatus.Valid;
                            HttpValidationStatus ignoreThisRequest = valid;
                            num    = 0;
                            length = settings.ValidationCallbackInfo.Length;
                            while (num < length)
                            {
                                ValidationCallbackInfo info = settings.ValidationCallbackInfo[num];
                                try
                                {
                                    info.handler(context, info.data, ref valid);
                                }
                                catch (Exception exception)
                                {
                                    valid = HttpValidationStatus.Invalid;
                                    HttpApplicationFactory.RaiseError(exception);
                                }
                                switch (valid)
                                {
                                case HttpValidationStatus.Invalid:
                                    OutputCache.Remove(str, context);
                                    this.RecordCacheMiss();
                                    return;

                                case HttpValidationStatus.IgnoreThisRequest:
                                    ignoreThisRequest = HttpValidationStatus.IgnoreThisRequest;
                                    break;

                                case HttpValidationStatus.Valid:
                                    break;

                                default:
                                    valid = ignoreThisRequest;
                                    break;
                                }
                                num++;
                            }
                            if (ignoreThisRequest == HttpValidationStatus.IgnoreThisRequest)
                            {
                                this.RecordCacheMiss();
                                return;
                            }
                        }
                        HttpRawResponse rawResponse = response2._rawResponse;
                        if ((cachedVary == null) || (cachedVary._contentEncodings == null))
                        {
                            string    acceptEncoding  = request.Headers["Accept-Encoding"];
                            string    contentEncoding = null;
                            ArrayList headers         = rawResponse.Headers;
                            if (headers != null)
                            {
                                foreach (HttpResponseHeader header in headers)
                                {
                                    if (header.Name == "Content-Encoding")
                                    {
                                        contentEncoding = header.Value;
                                        break;
                                    }
                                }
                            }
                            if (!IsAcceptableEncoding(contentEncoding, acceptEncoding))
                            {
                                this.RecordCacheMiss();
                                return;
                            }
                        }
                        int num3 = -1;
                        if (!rawResponse.HasSubstBlocks)
                        {
                            string ifModifiedSince = request.IfModifiedSince;
                            if (ifModifiedSince != null)
                            {
                                num3 = 0;
                                try
                                {
                                    DateTime time = HttpDate.UtcParse(ifModifiedSince);
                                    if ((settings.IsLastModifiedSet && (settings.UtcLastModified <= time)) && (time <= context.UtcTimestamp))
                                    {
                                        num3 = 1;
                                    }
                                }
                                catch
                                {
                                }
                            }
                            if (num3 != 0)
                            {
                                string ifNoneMatch = request.IfNoneMatch;
                                if (ifNoneMatch != null)
                                {
                                    num3 = 0;
                                    string[] strArray = ifNoneMatch.Split(s_fieldSeparators);
                                    num    = 0;
                                    length = strArray.Length;
                                    while (num < length)
                                    {
                                        if ((num == 0) && strArray[num].Equals("*"))
                                        {
                                            num3 = 1;
                                            break;
                                        }
                                        if (strArray[num].Equals(settings.ETag))
                                        {
                                            num3 = 1;
                                            break;
                                        }
                                        num++;
                                    }
                                }
                            }
                        }
                        if (num3 == 1)
                        {
                            response.ClearAll();
                            response.StatusCode = 0x130;
                        }
                        else
                        {
                            bool sendBody = request.HttpVerb != HttpVerb.HEAD;
                            response.UseSnapshot(rawResponse, sendBody);
                        }
                        response.Cache.ResetFromHttpCachePolicySettings(settings, context.UtcTimestamp);
                        string originalCacheUrl = response2._kernelCacheUrl;
                        if (originalCacheUrl != null)
                        {
                            response.SetupKernelCaching(originalCacheUrl);
                        }
                        PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_RATIO_BASE);
                        PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_HITS);
                        this._key = null;
                        this._recordedCacheMiss = false;
                        application.CompleteRequest();
                        return;
                    }
                    return;
                }
                }
            }
        }
        private static OutputCacheEntry Convert(CachedRawResponse cachedRawResponse, string depKey, string[] fileDependencies) {
            List<HeaderElement> headerElements = null;
            ArrayList headers = cachedRawResponse._rawResponse.Headers;
            int count = (headers != null) ? headers.Count : 0;
            for (int i = 0; i < count; i++) {
                if (headerElements == null) {
                    headerElements = new List<HeaderElement>(count);
                }
                HttpResponseHeader h = (HttpResponseHeader)(headers[i]);
                headerElements.Add(new HeaderElement(h.Name, h.Value));
            }
            
            List<ResponseElement> responseElements = null;
            ArrayList buffers = cachedRawResponse._rawResponse.Buffers;
            count = (buffers != null) ? buffers.Count : 0;
            for (int i = 0; i < count; i++) {
                if (responseElements == null) {
                    responseElements = new List<ResponseElement>(count);
                }
                IHttpResponseElement elem = buffers[i] as IHttpResponseElement;
                if (elem is HttpFileResponseElement) {
                    HttpFileResponseElement fileElement = elem as HttpFileResponseElement;
                    responseElements.Add(new FileResponseElement(fileElement.FileName, fileElement.Offset, elem.GetSize()));
                }
                else if (elem is HttpSubstBlockResponseElement) {
                    HttpSubstBlockResponseElement substElement = elem as HttpSubstBlockResponseElement;
                    responseElements.Add(new SubstitutionResponseElement(substElement.Callback));
                }
                else {
                    byte[] b = elem.GetBytes();
                    long length = (b != null) ? b.Length : 0;
                    responseElements.Add(new MemoryResponseElement(b, length));
                }
            }                

            OutputCacheEntry oce = new OutputCacheEntry(
                cachedRawResponse._cachedVaryId,
                cachedRawResponse._settings,
                cachedRawResponse._kernelCacheUrl,
                depKey,
                fileDependencies,
                cachedRawResponse._rawResponse.StatusCode,
                cachedRawResponse._rawResponse.StatusDescription,
                headerElements,
                responseElements
                );

            return oce;
        }
		private void OnCacheabilityUpdated (object sender, CacheabilityUpdatedEventArgs e)
		{
			if (e.Cacheability >= HttpCacheability.Server && !IsCached)
				cached_response = new CachedRawResponse (_CachePolicy);
			else if (e.Cacheability <= HttpCacheability.Private)
				cached_response = null;
		}
        // 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
        }
Example #21
0
        void DoCacheInsert(HttpContext context)
        {
            string            vary_key = context.Request.FilePath;
            string            key;
            CachedVaryBy      varyby = context.Cache [vary_key] as CachedVaryBy;
            CachedRawResponse prev   = null;
            bool lookup = true;

#if NET_2_0
            string cacheKey = null, cacheValue = null;
#endif

            if (varyby == null)
            {
                string    path  = context.Request.MapPath(vary_key);
                string [] files = new string [] { path };
                string [] keys  = new string [0];
                varyby = new CachedVaryBy(context.Response.Cache, vary_key);
                context.Cache.Insert(vary_key, varyby,
                                     new CacheDependency(files, keys),
                                     Cache.NoAbsoluteExpiration,
                                     Cache.NoSlidingExpiration,
                                     CacheItemPriority.Normal, null);
                lookup = false;
#if NET_2_0
                cacheKey = vary_key;
#endif
            }

            key = varyby.CreateKey(vary_key, context);

            if (lookup)
            {
                prev = context.InternalCache [key] as CachedRawResponse;
            }

            if (prev == null)
            {
                CachedRawResponse c = context.Response.GetCachedResponse();
                if (c != null)
                {
                    string [] files   = new string [] { };
                    string [] keys    = new string [] { vary_key };
                    bool      sliding = context.Response.Cache.Sliding;

                    context.InternalCache.Insert(key, c, new CacheDependency(files, keys),
                                                 (sliding ? Cache.NoAbsoluteExpiration :
                                                  context.Response.Cache.Expires),
                                                 (sliding ? TimeSpan.FromSeconds(
                                                      context.Response.Cache.Duration) :
                                                  Cache.NoSlidingExpiration),
                                                 CacheItemPriority.Normal, response_removed);
                    c.VaryBy = varyby;
                    varyby.ItemList.Add(key);
#if NET_2_0
                    cacheValue = key;
#endif
                }
            }

#if NET_2_0
            if (cacheKey != null)
            {
                lock (keysCacheLock) {
                    if (keysCache == null)
                    {
                        BuildManager.RemoveEntry += new BuildManagerRemoveEntryEventHandler(OnBuildManagerRemoveEntry);
                        keysCache = new Dictionary <string, string> (StringComparer.Ordinal);
                        keysCache.Add(cacheKey, cacheValue);
                    }
                    else if (!keysCache.ContainsKey(cacheKey))
                    {
                        keysCache.Add(cacheKey, cacheValue);
                    }
                }
            }
#endif
        }