예제 #1
0
 internal CachedRawResponse(
     HttpRawResponse rawResponse,
     HttpCachePolicySettings settings,
     CachedVary cachedVary)
 {
     _rawResponse = rawResponse;
     _settings    = settings;
     _cachedVary  = cachedVary;
 }
예제 #2
0
        //
        // helpers for accessing CacheInternal
        //

        // add CachedVary
        private static CachedVary UtcAdd(String key, CachedVary cachedVary)
        {
            return((CachedVary)HttpRuntime.CacheInternal.UtcAdd(key,
                                                                cachedVary,
                                                                null /*dependencies*/,
                                                                Cache.NoAbsoluteExpiration,
                                                                Cache.NoSlidingExpiration,
                                                                CacheItemPriority.Normal,
                                                                null /*callback*/));
        }
        public override bool Equals(object obj)
        {
            CachedVary vary = obj as CachedVary;

            if (vary == null)
            {
                return(false);
            }
            return((((this._varyByAllParams == vary._varyByAllParams) && (this._varyByCustom == vary._varyByCustom)) && (StringUtil.StringArrayEquals(this._contentEncodings, vary._contentEncodings) && StringUtil.StringArrayEquals(this._headers, vary._headers))) && StringUtil.StringArrayEquals(this._params, vary._params));
        }
예제 #4
0
        public override bool Equals(Object obj)
        {
            if (!(obj is CachedVary))
            {
                return(false);
            }

            CachedVary cv = (CachedVary)obj;

            return(_varyByAllParams == cv._varyByAllParams &&
                   StringEquals(_varyByCustom, cv._varyByCustom) &&
                   StringArrayEquals(_headers, cv._headers) &&
                   StringArrayEquals(_params, cv._params));
        }
예제 #5
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
        }
예제 #6
0
 private static CachedVary UtcAdd(string key, CachedVary cachedVary)
 {
     return((CachedVary)HttpRuntime.CacheInternal.UtcAdd(key, cachedVary, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null));
 }
 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();
         }
     }
 }
예제 #8
0
        //
        // helpers for accessing CacheInternal
        //

        // add CachedVary
        private static CachedVary UtcAdd(String key, CachedVary cachedVary) {
            return (CachedVary) HttpRuntime.CacheInternal.UtcAdd(key, 
                                                                 cachedVary, 
                                                                 null /*dependencies*/, 
                                                                 Cache.NoAbsoluteExpiration, 
                                                                 Cache.NoSlidingExpiration, 
                                                                 CacheItemPriority.Normal, 
                                                                 null /*callback*/);
        }        
        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 string CreateOutputCachedItemKey(HttpContext context, CachedVary cachedVary)
 {
     return(CreateOutputCachedItemKey(context.Request.Path, context.Request.HttpVerb, context, cachedVary));
 }
 /*
  * Return a key to lookup a cached response. The key contains 
  * the path and optionally, vary parameters, vary headers, custom strings,
  * and form posted data.
  */
 string CreateOutputCachedItemKey(HttpContext context, CachedVary cachedVary) {
     return CreateOutputCachedItemKey(context.Request.Path, context.Request.HttpVerb, context, cachedVary);
 }
        internal static string CreateOutputCachedItemKey(
                string              path, 
                HttpVerb            verb,
                HttpContext         context,
                CachedVary          cachedVary) {

            StringBuilder       sb;
            int                 i, j, n;
            string              name, value;
            string[]            a;
            byte[]              buf;
            HttpRequest         request;
            NameValueCollection col;
            int                 contentLength;
            bool                getAllParams;

            if (verb == HttpVerb.POST) {
                sb = new StringBuilder(OUTPUTCACHE_KEYPREFIX_POST, path.Length + OUTPUTCACHE_KEYPREFIX_POST.Length);
            }
            else {
                sb = new StringBuilder(OUTPUTCACHE_KEYPREFIX_GET, path.Length + OUTPUTCACHE_KEYPREFIX_GET.Length);
            }

            sb.Append(CultureInfo.InvariantCulture.TextInfo.ToLower(path));

            /* key for cached vary item has additional information */
            if (cachedVary != null) {
                request = context.Request;

                /* params part */
                for (j = 0; j <= 2; j++) {
                    a = null;
                    col = null;
                    getAllParams = false;

                    switch (j) {
                        case 0:
                            sb.Append("H");
                            a = cachedVary._headers;
                            if (a != null) {
                                col = request.GetServerVarsWithoutDemand();
                            }

                            break;

                        case 1:
                            Debug.Assert(cachedVary._params == null || !cachedVary._varyByAllParams, "cachedVary._params == null || !cachedVary._varyByAllParams");

                            sb.Append("Q");
                            a = cachedVary._params;
                            if (request.HasQueryString && (a != null || cachedVary._varyByAllParams)) {
                                col = request.QueryString;
                                getAllParams = cachedVary._varyByAllParams;
                            }

                            break;

                        case 2:
                        default:
                            Debug.Assert(cachedVary._params == null || !cachedVary._varyByAllParams, "cachedVary._params == null || !cachedVary._varyByAllParams");

                            sb.Append("F");
                            if (verb == HttpVerb.POST) {
                                a = cachedVary._params;
                                if (request.HasForm && (a != null || cachedVary._varyByAllParams)) {
                                    col = request.Form;
                                    getAllParams = cachedVary._varyByAllParams;
                                }
                            }

                            break;
                    }

                    Debug.Assert(a == null || !getAllParams, "a == null || !getAllParams");

                    /* handle all params case (VaryByParams[*] = true) */
                    if (getAllParams && col.Count > 0) {
                        a = col.AllKeys;
                        for (i = a.Length - 1; i >= 0; i--) {
                            if (a[i] != null)
                                a[i] = CultureInfo.InvariantCulture.TextInfo.ToLower(a[i]);
                        }

                        Array.Sort(a, InvariantComparer.Default);
                    }

                    if (a != null) {
                        for (i = 0, n = a.Length; i < n; i++) {
                            name = a[i];
                            if (col == null) {
                                value = NULL_VARYBY_VALUE;
                            }
                            else {
                                value = col[name];
                                if (value == null) {
                                    value = NULL_VARYBY_VALUE;
                                }
                            }

                            sb.Append("N");
                            sb.Append(name);
                            sb.Append("V");
                            sb.Append(value);
                        }
                    }
                }

                /* custom string part */
                sb.Append("C");
                if (cachedVary._varyByCustom != null) {
                    sb.Append("N");
                    sb.Append(cachedVary._varyByCustom);
                    sb.Append("V");

                    try {
                        value = context.ApplicationInstance.GetVaryByCustomString(
                                context, cachedVary._varyByCustom);
                        if (value == null) {
                            value = NULL_VARYBY_VALUE;
                        }
                    }
                    catch (Exception e) {
                        value = ERROR_VARYBY_VALUE;
                        HttpApplicationFactory.RaiseError(e);
                    }

                    sb.Append(value);
                }

                /* 
                 * if VaryByParms=*, and method is not a form, then 
                 * use a cryptographically strong hash of the data as
                 * part of the key.
                 */
                sb.Append("D");
                if (    verb == HttpVerb.POST && 
                        cachedVary._varyByAllParams && 
                        request.Form.Count == 0) {

                    contentLength = request.ContentLength;
                    if (contentLength > MAX_POST_KEY_LENGTH || contentLength < 0) {
                        return null;
                    }

                    if (contentLength > 0) {
                        buf = ((HttpInputStream)request.InputStream).GetAsByteArray();
                        if (buf == null) {
                            return null;
                        }

                        // Use SHA256 to generate a collision-free hash of the input data
                        value = Convert.ToBase64String(CryptoUtil.ComputeSHA256Hash(buf));
                        sb.Append(value);
                    }
                }

                /*
                 * VaryByContentEncoding
                 */
                sb.Append("E");
                string[] contentEncodings = cachedVary._contentEncodings;
                if (contentEncodings != null) {
                    string coding = context.Response.GetHttpHeaderContentEncoding();
                    if (coding != null) {
                        for (int k = 0; k < contentEncodings.Length; k++) {
                            if (contentEncodings[k] == coding) {
                                sb.Append(coding);
                                break;
                            }
                        }
                    }
                }

                // The key must end in "E", or the VaryByContentEncoding feature will break. Unfortunately, 
                // there was no good way to encapsulate the logic within this routine.  See the code in
                // OnEnter where we append the result of GetAcceptableEncoding to the key.
            }

            return sb.ToString();
        }
        /*
         * 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 CachedVary UtcAdd(string key, CachedVary cachedVary)
 {
     return (CachedVary) HttpRuntime.CacheInternal.UtcAdd(key, cachedVary, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
 }
예제 #15
0
        internal static string CreateOutputCachedItemKey(
            string path,
            CacheRequestMethod method,
            HttpContext context,
            CachedVary cachedVary)
        {
            StringBuilder sb;
            int           i, j, n;
            string        name, value;

            string[]            a;
            byte[]              buf, hash;
            HttpRequest         request;
            NameValueCollection col;
            int contentLength;

            if (method == CacheRequestMethod.Post)
            {
                sb = new StringBuilder("System.Web.Http.HttpRawResponse\nM=3\n");
            }
            else
            {
                sb = new StringBuilder("System.Web.Http.HttpRawResponse\nM=2\n");
            }

            sb.Append(CultureInfo.InvariantCulture.TextInfo.ToLower(path));

            /* key for cached vary item has additional information */
            if (cachedVary != null)
            {
                request = context.Request;

                /* params part */
                for (j = 0; j <= 2; j++)
                {
                    switch (j)
                    {
                    case 0:
                        sb.Append("\nVH");
                        a   = cachedVary._headers;
                        col = request.ServerVariables;
                        break;

                    case 1:
                        sb.Append("\nVPQ");
                        a   = cachedVary._params;
                        col = request.QueryString;
                        break;

                    case 2:
                    default:
                        sb.Append("\nVPF");
                        a   = cachedVary._params;
                        col = request.Form;
                        if (method != CacheRequestMethod.Post)
                        {
                            col = null;
                        }

                        break;
                    }

                    if (col == null)
                    {
                        continue;
                    }

                    /* handle all params case (VaryByParams[*] = true) */
                    if (a == null && cachedVary._varyByAllParams && j != 0)
                    {
                        a = col.AllKeys;
                        for (i = a.Length - 1; i >= 0; i--)
                        {
                            if (a[i] != null)
                            {
                                a[i] = CultureInfo.InvariantCulture.TextInfo.ToLower(a[i]);
                            }
                        }

                        Array.Sort(a, InvariantComparer.Default);
                    }

                    if (a != null)
                    {
                        for (i = 0, n = a.Length; i < n; i++)
                        {
                            name  = a[i];
                            value = col[name];
                            if (value == null)
                            {
                                value = NULL_VARYBY_VALUE;
                            }

                            sb.Append("\tPN:");
                            sb.Append(name);
                            sb.Append("\tPV:");
                            sb.Append(value);
                        }
                    }
                }

                /* custom string part */
                sb.Append("\nVC");
                if (cachedVary._varyByCustom != null)
                {
                    sb.Append("\tCN:");
                    sb.Append(cachedVary._varyByCustom);
                    sb.Append("\tCV:");

                    try {
                        value = context.ApplicationInstance.GetVaryByCustomString(
                            context, cachedVary._varyByCustom);
                        if (value == null)
                        {
                            value = NULL_VARYBY_VALUE;
                        }
                    }
                    catch (Exception e) {
                        value = ERROR_VARYBY_VALUE;
                        HttpApplicationFactory.RaiseError(e);
                    }

                    sb.Append(value);
                }

                /*
                 * if VaryByParms=*, and method is not a form, then
                 * use a cryptographically strong hash of the data as
                 * part of the key.
                 */
                sb.Append("\nVPD");
                if (method == CacheRequestMethod.Post &&
                    cachedVary._varyByAllParams &&
                    request.Form.Count == 0)
                {
                    contentLength = request.ContentLength;
                    if (contentLength > MAX_POST_KEY_LENGTH || contentLength < 0)
                    {
                        return(null);
                    }

                    if (contentLength > 0)
                    {
                        buf = ((HttpInputStream)request.InputStream).Data;
                        if (buf == null)
                        {
                            return(null);
                        }

                        hash  = MachineKey.HashData(buf, s_hashModifier, 0, buf.Length);
                        value = Convert.ToBase64String(hash);
                        sb.Append(value);
                    }
                }

                sb.Append("\nEOV");
            }

            return(sb.ToString());
        }
        internal static string CreateOutputCachedItemKey(string path, HttpVerb verb, HttpContext context, CachedVary cachedVary)
        {
            StringBuilder builder;

            if (verb == HttpVerb.POST)
            {
                builder = new StringBuilder("a1", path.Length + "a1".Length);
            }
            else
            {
                builder = new StringBuilder("a2", path.Length + "a2".Length);
            }
            builder.Append(CultureInfo.InvariantCulture.TextInfo.ToLower(path));
            if (cachedVary != null)
            {
                string      varyByCustomString;
                HttpRequest request = context.Request;
                for (int i = 0; i <= 2; i++)
                {
                    int                 num;
                    string[]            array = null;
                    NameValueCollection serverVarsWithoutDemand = null;
                    bool                flag = false;
                    switch (i)
                    {
                    case 0:
                        builder.Append("H");
                        array = cachedVary._headers;
                        if (array != null)
                        {
                            serverVarsWithoutDemand = request.GetServerVarsWithoutDemand();
                        }
                        break;

                    case 1:
                        builder.Append("Q");
                        array = cachedVary._params;
                        if (request.HasQueryString && ((array != null) || cachedVary._varyByAllParams))
                        {
                            serverVarsWithoutDemand = request.QueryString;
                            flag = cachedVary._varyByAllParams;
                        }
                        break;

                    default:
                        builder.Append("F");
                        if (verb == HttpVerb.POST)
                        {
                            array = cachedVary._params;
                            if (request.HasForm && ((array != null) || cachedVary._varyByAllParams))
                            {
                                serverVarsWithoutDemand = request.Form;
                                flag = cachedVary._varyByAllParams;
                            }
                        }
                        break;
                    }
                    if (flag && (serverVarsWithoutDemand.Count > 0))
                    {
                        array = serverVarsWithoutDemand.AllKeys;
                        num   = array.Length - 1;
                        while (num >= 0)
                        {
                            if (array[num] != null)
                            {
                                array[num] = CultureInfo.InvariantCulture.TextInfo.ToLower(array[num]);
                            }
                            num--;
                        }
                        Array.Sort(array, System.InvariantComparer.Default);
                    }
                    if (array != null)
                    {
                        num = 0;
                        int length = array.Length;
                        while (num < length)
                        {
                            string str = array[num];
                            if (serverVarsWithoutDemand == null)
                            {
                                varyByCustomString = "+n+";
                            }
                            else
                            {
                                varyByCustomString = serverVarsWithoutDemand[str];
                                if (varyByCustomString == null)
                                {
                                    varyByCustomString = "+n+";
                                }
                            }
                            builder.Append("N");
                            builder.Append(str);
                            builder.Append("V");
                            builder.Append(varyByCustomString);
                            num++;
                        }
                    }
                }
                builder.Append("C");
                if (cachedVary._varyByCustom != null)
                {
                    builder.Append("N");
                    builder.Append(cachedVary._varyByCustom);
                    builder.Append("V");
                    try
                    {
                        varyByCustomString = context.ApplicationInstance.GetVaryByCustomString(context, cachedVary._varyByCustom);
                        if (varyByCustomString == null)
                        {
                            varyByCustomString = "+n+";
                        }
                    }
                    catch (Exception exception)
                    {
                        varyByCustomString = "+e+";
                        HttpApplicationFactory.RaiseError(exception);
                    }
                    builder.Append(varyByCustomString);
                }
                builder.Append("D");
                if (((verb == HttpVerb.POST) && cachedVary._varyByAllParams) && (request.Form.Count == 0))
                {
                    int contentLength = request.ContentLength;
                    if ((contentLength > 0x3a98) || (contentLength < 0))
                    {
                        return(null);
                    }
                    if (contentLength > 0)
                    {
                        byte[] asByteArray = ((HttpInputStream)request.InputStream).GetAsByteArray();
                        if (asByteArray == null)
                        {
                            return(null);
                        }
                        varyByCustomString = Convert.ToBase64String(MachineKeySection.HashData(asByteArray, null, 0, asByteArray.Length));
                        builder.Append(varyByCustomString);
                    }
                }
                builder.Append("E");
                string[] strArray2 = cachedVary._contentEncodings;
                if (strArray2 != null)
                {
                    string httpHeaderContentEncoding = context.Response.GetHttpHeaderContentEncoding();
                    if (httpHeaderContentEncoding != null)
                    {
                        for (int j = 0; j < strArray2.Length; j++)
                        {
                            if (strArray2[j] == httpHeaderContentEncoding)
                            {
                                builder.Append(httpHeaderContentEncoding);
                                break;
                            }
                        }
                    }
                }
            }
            return(builder.ToString());
        }
예제 #17
0
 /*
  * Return a key to lookup a cached response. The key contains
  * the path and optionally, vary parameters, vary headers, custom strings,
  * and form posted data.
  */
 string CreateOutputCachedItemKey(HttpContext context, CachedVary cachedVary)
 {
     return(CreateOutputCachedItemKey(context.Request.Path, _method, context, cachedVary));
 }
        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;
            }
        }
예제 #19
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);
        }
예제 #20
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();
                }
            }
        }
예제 #21
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
        }
예제 #22
0
        //
        // helpers for accessing InternalCache
        //

        // add CachedVary
        private static CachedVary UtcAdd(String key, CachedVary cachedVary)
        {
            return((CachedVary)HttpRuntime.Cache.InternalCache.Add(key, cachedVary, null));
        }