示例#1
0
 private static bool IsOutDated(string ifRangeHeader, DateTime lastModified)
 {
     try {
         DateTime utcLastModified = lastModified.ToUniversalTime();
         DateTime utc             = HttpDate.UtcParse(ifRangeHeader);
         return(utc < utcLastModified);
     }
     catch {
         return(true);
     }
 }
示例#2
0
        /*
         * Try to find this request in the cache. If so, return it. Otherwise,
         * store the cache key for use on Leave.
         */
        /// <include file='doc\OutputCacheModule.uex' path='docs/doc[@for="OutputCacheModule.OnEnter"]/*' />
        /// <devdoc>
        /// <para>Raises the <see langword='Enter'/>
        /// event, which searches the output cache for an item to satisfy the HTTP request. </para>
        /// </devdoc>
        internal /*public*/ void OnEnter(Object source, EventArgs eventArgs)
        {
            HttpApplication         app;
            HttpContext             context;
            string                  key;
            HttpRequest             request;
            HttpResponse            response;
            Object                  item;
            CachedRawResponse       cachedRawResponse;
            HttpCachePolicySettings settings;
            int  i, n;
            bool sendBody;
            HttpValidationStatus   validationStatus, validationStatusFinal;
            ValidationCallbackInfo callbackInfo;
            string   ifModifiedSinceHeader;
            DateTime utcIfModifiedSince;
            string   etag;

            string[] etags;
            int      send304;
            string   cacheControl;

            string[] cacheDirectives = null;
            string   pragma;

            string[]      pragmaDirectives = null;
            string        directive;
            int           maxage;
            int           minfresh;
            int           age;
            int           fresh;
            bool          hasValidationPolicy;
            CachedVary    cachedVary;
            CacheInternal cacheInternal;

            Debug.Trace("OutputCacheModuleEnter", "Beginning OutputCacheModule::Enter");

            app                = (HttpApplication)source;
            context            = app.Context;
            request            = context.Request;
            response           = context.Response;
            _key               = null;
            _recordedCacheMiss = false;
            _method            = CacheRequestMethod.Invalid;

            /*
             * Check if the request can be resolved for this method.
             */
            switch (request.HttpMethod)
            {
            case "HEAD":
                _method = CacheRequestMethod.Head;
                break;

            case "GET":
                _method = CacheRequestMethod.Get;
                break;

            case "POST":
                _method = CacheRequestMethod.Post;
                break;

            default:
                Debug.Trace("OutputCacheModuleEnter", "Output cache miss, Http method not GET, POST, or HEAD" +
                            "\nReturning from OutputCacheModule::Enter");

                return;
            }

            /*
             * Create a lookup key. Remember the key for use inside Leave()
             */
            _key = key = CreateOutputCachedItemKey(context, null);
            Debug.Assert(_key != null, "_key != null");

            /*
             *  Lookup the cached item.
             */
            cacheInternal = HttpRuntime.CacheInternal;
            item          = cacheInternal.Get(key);
            if (item == null)
            {
                Debug.Trace("OutputCacheModuleEnter", "Output cache miss, item not found.\n\tkey=" + key +
                            "\nReturning from OutputCacheModule::Enter");

                return;
            }

            cachedVary = item as CachedVary;
            if (cachedVary != null)
            {
                /*
                 * This cached output has a Vary policy. Create a new key based
                 * on the vary headers in cachedRawResponse and try again.
                 */
                Debug.Trace("OutputCacheModuleEnter", "Output cache found CachedVary, \n\tkey=" + key);
                key = CreateOutputCachedItemKey(context, cachedVary);
                if (key == null)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache miss, key could not be created for vary-by item." +
                                "\nReturning from OutputCacheModule::Enter");

                    return;
                }

                item = cacheInternal.Get(key);
                if (item == null)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache miss, item not found.\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");

                    return;
                }
            }

            Debug.Assert(item.GetType() == typeof(CachedRawResponse), "item.GetType() == typeof(CachedRawResponse)");
            cachedRawResponse = (CachedRawResponse)item;
            settings          = cachedRawResponse._settings;
            if (cachedVary == null && !settings.IgnoreParams)
            {
                /*
                 * This cached output has no vary policy, so make sure it doesn't have a query string or form post.
                 */
                if (_method == CacheRequestMethod.Post)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache item found but method is POST and no VaryByParam specified." +
                                "\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");
                    RecordCacheMiss();
                    return;
                }

                string queryStringText = request.QueryStringText;
                if (queryStringText != null && queryStringText.Length > 0)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache item found but contains a querystring and no VaryByParam specified." +
                                "\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");
                    RecordCacheMiss();
                    return;
                }
            }

            hasValidationPolicy = settings.HasValidationPolicy();

            /*
             * Determine whether the client can accept a cached copy, and
             * get values of other cache control directives.
             *
             * We do this after lookup so we don't have to crack the headers
             * if the item is not found. Cracking the headers is expensive.
             */
            if (!hasValidationPolicy)
            {
                cacheControl = request.Headers["Cache-Control"];
                if (cacheControl != null)
                {
                    cacheDirectives = cacheControl.Split(s_fieldSeparators);
                    for (i = 0; i < cacheDirectives.Length; i++)
                    {
                        directive = cacheDirectives[i];
                        if (directive == "no-cache")
                        {
                            Debug.Trace("OutputCacheModuleEnter",
                                        "Skipping lookup because of Cache-Control: no-cache directive." +
                                        "\nReturning from OutputCacheModule::Enter");

                            RecordCacheMiss();
                            return;
                        }

                        if (directive.StartsWith("max-age="))
                        {
                            try {
                                maxage = Convert.ToInt32(directive.Substring(8));
                            }
                            catch {
                                maxage = -1;
                            }

                            if (maxage >= 0)
                            {
                                age = (int)((context.UtcTimestamp.Ticks - settings.UtcTimestampCreated.Ticks) / TimeSpan.TicksPerSecond);
                                if (age >= maxage)
                                {
                                    Debug.Trace("OutputCacheModuleEnter",
                                                "Not returning found item due to Cache-Control: max-age directive." +
                                                "\nReturning from OutputCacheModule::Enter");

                                    RecordCacheMiss();
                                    return;
                                }
                            }
                        }
                        else if (directive.StartsWith("min-fresh="))
                        {
                            try {
                                minfresh = Convert.ToInt32(directive.Substring(10));
                            }
                            catch {
                                minfresh = -1;
                            }

                            if (minfresh >= 0 && settings.IsExpiresSet && !settings.SlidingExpiration)
                            {
                                fresh = (int)((settings.UtcExpires.Ticks - context.UtcTimestamp.Ticks) / TimeSpan.TicksPerSecond);
                                if (fresh < minfresh)
                                {
                                    Debug.Trace("OutputCacheModuleEnter",
                                                "Not returning found item due to Cache-Control: min-fresh directive." +
                                                "\nReturning from OutputCacheModule::Enter");

                                    RecordCacheMiss();
                                    return;
                                }
                            }
                        }
                    }
                }

                pragma = request.Headers["Pragma"];
                if (pragma != null)
                {
                    pragmaDirectives = pragma.Split(s_fieldSeparators);
                    for (i = 0; i < pragmaDirectives.Length; i++)
                    {
                        if (pragmaDirectives[i] == "no-cache")
                        {
                            Debug.Trace("OutputCacheModuleEnter",
                                        "Skipping lookup because of Pragma: no-cache directive." +
                                        "\nReturning from OutputCacheModule::Enter");

                            RecordCacheMiss();
                            return;
                        }
                    }
                }
            }
            else if (settings.ValidationCallbackInfo != null)
            {
                /*
                 * Check if the item is still valid.
                 */
                validationStatus      = HttpValidationStatus.Valid;
                validationStatusFinal = validationStatus;
                for (i = 0, n = settings.ValidationCallbackInfo.Length; i < n; i++)
                {
                    callbackInfo = settings.ValidationCallbackInfo[i];
                    try {
                        callbackInfo.handler(context, callbackInfo.data, ref validationStatus);
                    }
                    catch (Exception e) {
                        validationStatus = HttpValidationStatus.Invalid;
                        HttpApplicationFactory.RaiseError(e);
                    }

                    switch (validationStatus)
                    {
                    case HttpValidationStatus.Invalid:
                        Debug.Trace("OutputCacheModuleEnter", "Output cache item found but callback invalidated it." +
                                    "\n\tkey=" + key +
                                    "\nReturning from OutputCacheModule::Enter");

                        cacheInternal.Remove(key);
                        RecordCacheMiss();
                        return;

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

                    case HttpValidationStatus.Valid:
                        break;

                    default:
                        Debug.Trace("OutputCacheModuleEnter", "Invalid validation status, ignoring it, status=" + validationStatus +
                                    "\n\tkey=" + key);

                        validationStatus = validationStatusFinal;
                        break;
                    }
                }

                if (validationStatusFinal == HttpValidationStatus.IgnoreThisRequest)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache item found but callback status is IgnoreThisRequest." +
                                "\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");


                    RecordCacheMiss();
                    return;
                }

                Debug.Assert(validationStatusFinal == HttpValidationStatus.Valid,
                             "validationStatusFinal == HttpValidationStatus.Valid");
            }

            /*
             * Try to satisfy a conditional request. The cached response
             * must satisfy all conditions that are present.
             *
             * We can only satisfy a conditional request if the response
             * is buffered and has no substitution blocks.
             *
             * N.B. RFC 2616 says conditional requests only occur
             * with the GET method, but we try to satisfy other
             * verbs (HEAD, POST) as well.
             */
            send304 = -1;

            if (response.IsBuffered() && !cachedRawResponse._rawResponse.HasSubstBlocks)
            {
                /* Check "If-Modified-Since" header */
                ifModifiedSinceHeader = request.IfModifiedSince;
                if (ifModifiedSinceHeader != null)
                {
                    send304 = 0;
                    try {
                        utcIfModifiedSince = HttpDate.UtcParse(ifModifiedSinceHeader);
                        if (settings.IsLastModifiedSet &&
                            settings.UtcLastModified <= utcIfModifiedSince &&
                            utcIfModifiedSince <= context.UtcTimestamp)
                        {
                            send304 = 1;
                        }
                    }
                    catch {
                        Debug.Trace("OutputCacheModuleEnter", "Ignore If-Modified-Since header, invalid format: " + ifModifiedSinceHeader);
                    }
                }

                /* Check "If-None-Match" header */
                if (send304 != 0)
                {
                    etag = request.IfNoneMatch;
                    if (etag != null)
                    {
                        send304 = 0;
                        etags   = etag.Split(s_fieldSeparators);
                        for (i = 0, n = etags.Length; i < n; i++)
                        {
                            if (i == 0 && etags[i].Equals("*"))
                            {
                                send304 = 1;
                                break;
                            }

                            if (etags[i].Equals(settings.ETag))
                            {
                                send304 = 1;
                                break;
                            }
                        }
                    }
                }
            }

            if (send304 == 1)
            {
                /*
                 * Send 304 Not Modified
                 */
                Debug.Trace("OutputCacheModuleEnter", "Output cache hit & conditional request satisfied, status=304." +
                            "\n\tkey=" + key +
                            "\nReturning from OutputCacheModule::Enter");

                response.ClearAll();
                response.StatusCode = 304;
            }
            else
            {
                /*
                 * Send the full response.
                 */
#if DBG
                if (send304 == -1)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache hit.\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");
                }
                else
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache hit but conditional request not satisfied.\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");
                }
#endif

                sendBody = (_method != CacheRequestMethod.Head);

                // UseSnapshot calls ClearAll
                response.UseSnapshot(cachedRawResponse._rawResponse, sendBody);
            }

            response.Cache.ResetFromHttpCachePolicySettings(settings, context.UtcTimestamp);

            PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_RATIO_BASE);
            PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_HITS);

            _key = null;
            _recordedCacheMiss = false;
            _method            = CacheRequestMethod.Invalid;

            app.CompleteRequest();
        }
        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;
                }
                }
            }
        }