private CacheValidationStatus UpdateCache()
        {
            CacheValidationStatus status = this._Validator.UpdateCache();

            this._Validator.SetValidationStatus(status);
            return(status);
        }
 protected RequestCacheValidator(bool strictCacheErrors, TimeSpan unspecifiedMaxAge)
 {
     this._StrictCacheErrors    = strictCacheErrors;
     this._UnspecifiedMaxAge    = unspecifiedMaxAge;
     this._ValidationStatus     = CacheValidationStatus.DoNotUseCache;
     this._CacheFreshnessStatus = System.Net.Cache.CacheFreshnessStatus.Undefined;
 }
Пример #3
0
        /*
         * //
         * protected RequestCacheValidator(): this(false, TimeSpan.FromDays(1))
         * {
         * }
         */

        protected RequestCacheValidator(bool strictCacheErrors, TimeSpan unspecifiedMaxAge)
        {
            _StrictCacheErrors    = strictCacheErrors;
            _UnspecifiedMaxAge    = unspecifiedMaxAge;
            _ValidationStatus     = CacheValidationStatus.DoNotUseCache;
            _CacheFreshnessStatus = CacheFreshnessStatus.Undefined;
        }
Пример #4
0
        /// <summary>
        /// Needs to run before action runs
        /// </summary>
        /// <param name="context"></param>
        /// <returns>Whether continue or not. If false then the action MUST not run</returns>
        public async Task <bool> Before(HttpContext context)
        {
            _cacheCowHeader        = new CacheCowHeader();
            _cacheValidated        = null;
            _isRequestCacheable    = _validator.IsCacheable(context.Request);
            _cacheValidationStatus = context.Request.GetCacheValidationStatus();
            if (_cacheValidationStatus != CacheValidationStatus.None)
            {
                var timedETag = await _cacheDirectiveProvider.QueryAsync(context);

                _cacheCowHeader.QueryMadeAndSuccessful = timedETag != null;
                _cacheValidated = ApplyCacheValidation(timedETag, _cacheValidationStatus, context);
                _cacheCowHeader.ValidationApplied = true;
                if (_cacheValidated ?? false)
                {
                    _cacheCowHeader.ShortCircuited    = true;
                    _cacheCowHeader.ValidationMatched = HttpMethods.IsGet(context.Request.Method); // NOTE: In GET match result in short-circuit and in PUT the opposite
                    context.Response.Headers.Add(CacheCowHeader.Name, _cacheCowHeader.ToString());
                    // the response would have been set and no need to run the rest of the pipeline
                    return(false);
                }
            }

            _stream = context.Response.Body;
            context.Response.Body = new MemoryStream();

            return(true);
        }
 protected RequestCacheValidator(bool strictCacheErrors, TimeSpan unspecifiedMaxAge)
 {
     this._StrictCacheErrors = strictCacheErrors;
     this._UnspecifiedMaxAge = unspecifiedMaxAge;
     this._ValidationStatus = CacheValidationStatus.DoNotUseCache;
     this._CacheFreshnessStatus = System.Net.Cache.CacheFreshnessStatus.Undefined;
 }
        //
        private CacheValidationStatus UpdateCache()
        {
            CacheValidationStatus result = _Validator.UpdateCache();

            _Validator.SetValidationStatus(result);

            return(result);
        }
 internal CacheValidationStatus GetUpdateStatus(WebResponse response, Stream responseStream)
 {
     if (response == null)
     {
         throw new ArgumentNullException("response");
     }
     if (this._ProtocolStatus == CacheValidationStatus.DoNotUseCache)
     {
         return(CacheValidationStatus.DoNotUseCache);
     }
     try
     {
         if (Logging.On)
         {
             Logging.Enter(Logging.RequestCache, this, "GetUpdateStatus", (string)null);
         }
         if (this._Validator.Response == null)
         {
             this._Validator.FetchResponse(response);
         }
         if (this._ProtocolStatus == CacheValidationStatus.RemoveFromCache)
         {
             this.EnsureCacheRemoval(this._Validator.CacheKey);
             return(this._ProtocolStatus);
         }
         if (((this._ProtocolStatus != CacheValidationStatus.DoNotTakeFromCache) && (this._ProtocolStatus != CacheValidationStatus.ReturnCachedResponse)) && (this._ProtocolStatus != CacheValidationStatus.CombineCachedAndServerResponse))
         {
             if (Logging.On)
             {
                 Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_not_updated_based_on_cache_protocol_status", new object[] { "GetUpdateStatus()", this._ProtocolStatus.ToString() }));
             }
             return(this._ProtocolStatus);
         }
         this.CheckUpdateOnResponse(responseStream);
     }
     catch (Exception exception)
     {
         this._ProtocolException = exception;
         this._ProtocolStatus    = CacheValidationStatus.Fail;
         if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
         {
             throw;
         }
         if (Logging.On)
         {
             Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_object_and_exception", new object[] { "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (exception is WebException) ? exception.Message : exception.ToString() }));
         }
     }
     finally
     {
         if (Logging.On)
         {
             Logging.Exit(Logging.RequestCache, this, "GetUpdateStatus", "result = " + this._ProtocolStatus.ToString());
         }
     }
     return(this._ProtocolStatus);
 }
        private CacheValidationStatus ValidateResponse()
        {
            CacheValidationStatus status = this._Validator.ValidateResponse();

            this._Validator.SetValidationStatus(status);
            if (Logging.On)
            {
                Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_result", new object[] { "ValidateResponse()", status.ToString() }));
            }
            return(status);
        }
        //
        private CacheValidationStatus ValidateResponse()
        {
            CacheValidationStatus result = _Validator.ValidateResponse();

            _Validator.SetValidationStatus(result);

            if (Logging.On)
            {
                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_result, "ValidateResponse()", result.ToString()));
            }
            return(result);
        }
        private CacheValidationStatus ValidateRequest()
        {
            if (Logging.On)
            {
                Logging.PrintInfo(Logging.RequestCache, string.Concat(new object[] { "Request#", this._Validator.Request.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), ", Policy = ", this._Validator.Request.CachePolicy.ToString(), ", Cache Uri = ", this._Validator.Uri }));
            }
            CacheValidationStatus status = this._Validator.ValidateRequest();

            this._Validator.SetValidationStatus(status);
            if (Logging.On)
            {
                Logging.PrintInfo(Logging.RequestCache, "Selected cache Key = " + this._Validator.CacheKey);
            }
            return(status);
        }
 internal void FetchRequest(System.Uri uri, WebRequest request)
 {
     this._Request = request;
     this._Policy = request.CachePolicy;
     this._Response = null;
     this._ResponseCount = 0;
     this._ValidationStatus = CacheValidationStatus.DoNotUseCache;
     this._CacheFreshnessStatus = System.Net.Cache.CacheFreshnessStatus.Undefined;
     this._CacheStream = null;
     this._CacheStreamOffset = 0L;
     this._CacheStreamLength = 0L;
     if (!uri.Equals(this._Uri))
     {
         this._CacheKey = uri.GetParts(UriComponents.AbsoluteUri, UriFormat.Unescaped);
     }
     this._Uri = uri;
 }
 internal void FetchRequest(System.Uri uri, WebRequest request)
 {
     this._Request              = request;
     this._Policy               = request.CachePolicy;
     this._Response             = null;
     this._ResponseCount        = 0;
     this._ValidationStatus     = CacheValidationStatus.DoNotUseCache;
     this._CacheFreshnessStatus = System.Net.Cache.CacheFreshnessStatus.Undefined;
     this._CacheStream          = null;
     this._CacheStreamOffset    = 0L;
     this._CacheStreamLength    = 0L;
     if (!uri.Equals(this._Uri))
     {
         this._CacheKey = uri.GetParts(UriComponents.AbsoluteUri, UriFormat.Unescaped);
     }
     this._Uri = uri;
 }
        //
        // This optional method is only for protocols supporting a revalidation concept
        // For a retried request this method must be called again.
        //
        internal CacheValidationStatus GetRevalidateStatus(WebResponse response, Stream responseStream)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            if (_ProtocolStatus == CacheValidationStatus.DoNotUseCache)
            {
                return(CacheValidationStatus.DoNotUseCache);
            }

            // If we returned cached response, switch the state to not call cache anymore.
            if (_ProtocolStatus == CacheValidationStatus.ReturnCachedResponse)
            {
                _ProtocolStatus = CacheValidationStatus.DoNotUseCache;
                return(_ProtocolStatus);
            }

            try {
                if (Logging.On)
                {
                    Logging.Enter(Logging.RequestCache, this, "GetRevalidateStatus", (_Validator == null? null: _Validator.Request));
                }

                _Validator.FetchResponse(response);

                if (_ProtocolStatus != CacheValidationStatus.Continue && _ProtocolStatus != CacheValidationStatus.RetryResponseFromServer)
                {
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_revalidation_not_needed, "GetRevalidateStatus()"));
                    }
                    return(_ProtocolStatus);
                }
                CheckRetrieveOnResponse(responseStream);
            }
            finally {
                if (Logging.On)
                {
                    Logging.Exit(Logging.RequestCache, this, "GetRevalidateStatus", "result = " + _ProtocolStatus.ToString());
                }
            }
            return(_ProtocolStatus);
        }
Пример #14
0
        /*-------------- internal members -------------*/
        //
        internal void FetchRequest(Uri uri, WebRequest request)
        {
            _Request              = request;
            _Policy               = request.CachePolicy;
            _Response             = null;
            _ResponseCount        = 0;
            _ValidationStatus     = CacheValidationStatus.DoNotUseCache;
            _CacheFreshnessStatus = CacheFreshnessStatus.Undefined;
            _CacheStream          = null;
            _CacheStreamOffset    = 0L;
            _CacheStreamLength    = 0L;

            if (!uri.Equals(_Uri))
            {
                // it's changed from previous call
                _CacheKey = uri.GetParts(UriComponents.AbsoluteUri, UriFormat.Unescaped);
            }
            _Uri = uri;
        }
        //
        private CacheValidationStatus ValidateRequest()
        {
            if (Logging.On)
            {
                Logging.PrintInfo(Logging.RequestCache,
                                  "Request#" + _Validator.Request.GetHashCode().ToString(NumberFormatInfo.InvariantInfo) +
                                  ", Policy = " + _Validator.Request.CachePolicy.ToString() +
                                  ", Cache Uri = " + _Validator.Uri);
            }

            CacheValidationStatus result = _Validator.ValidateRequest();

            _Validator.SetValidationStatus(result);

            if (Logging.On)
            {
                Logging.PrintInfo(Logging.RequestCache, "Selected cache Key = " + _Validator.CacheKey);
            }
            return(result);
        }
 internal CacheValidationStatus GetRevalidateStatus(WebResponse response, Stream responseStream)
 {
     if (response == null)
     {
         throw new ArgumentNullException("response");
     }
     if (this._ProtocolStatus == CacheValidationStatus.DoNotUseCache)
     {
         return(CacheValidationStatus.DoNotUseCache);
     }
     if (this._ProtocolStatus == CacheValidationStatus.ReturnCachedResponse)
     {
         this._ProtocolStatus = CacheValidationStatus.DoNotUseCache;
         return(this._ProtocolStatus);
     }
     try
     {
         if (Logging.On)
         {
             Logging.Enter(Logging.RequestCache, this, "GetRevalidateStatus", (this._Validator == null) ? null : this._Validator.Request);
         }
         this._Validator.FetchResponse(response);
         if ((this._ProtocolStatus != CacheValidationStatus.Continue) && (this._ProtocolStatus != CacheValidationStatus.RetryResponseFromServer))
         {
             if (Logging.On)
             {
                 Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_revalidation_not_needed", new object[] { "GetRevalidateStatus()" }));
             }
             return(this._ProtocolStatus);
         }
         this.CheckRetrieveOnResponse(responseStream);
     }
     finally
     {
         if (Logging.On)
         {
             Logging.Exit(Logging.RequestCache, this, "GetRevalidateStatus", "result = " + this._ProtocolStatus.ToString());
         }
     }
     return(this._ProtocolStatus);
 }
 internal void SetValidationStatus(CacheValidationStatus status)
 {
     _ValidationStatus = status;
 }
        //
        // This is (optionally) called after receiveing a live response
        //
        protected internal override CacheValidationStatus RevalidateCache()
        {
            if (HttpProxyMode)
            {
                return(base.RevalidateCache());
            }


            if (Policy.Level >= RequestCacheLevel.Reload)
            {
                // For those policies cache is never returned
                GlobalLog.Assert("RevalidateCache()", "This validator should not be called for policy = " + Policy.ToString());
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_validator_invalid_for_policy, Policy.ToString()));
                }
                return(CacheValidationStatus.DoNotTakeFromCache);
            }

            // First check is do we still hold on a cached entry?
            if (CacheStream == Stream.Null)
            {
                return(CacheValidationStatus.DoNotTakeFromCache);
            }

            //
            // This is a second+ time validation after receiving at least one response
            //

            CacheValidationStatus result = CacheValidationStatus.DoNotTakeFromCache;

            FtpWebResponse resp = Response as FtpWebResponse;

            if (resp == null)
            {
                // This will result to an application error
                return(CacheValidationStatus.DoNotTakeFromCache);
            }

            if (resp.StatusCode == FtpStatusCode.FileStatus)
            {
                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_response_last_modified, resp.LastModified.ToUniversalTime().ToString("r", CultureInfo.InvariantCulture), resp.ContentLength));
                }
                if (Logging.On)
                {
                    Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_cache_last_modified, CacheEntry.LastModifiedUtc.ToString("r", CultureInfo.InvariantCulture), CacheEntry.StreamSize));
                }

                if (CacheStreamOffset != 0L && CacheEntry.IsPartialEntry)
                {
                    //should never happen
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_partial_and_non_zero_content_offset, CacheStreamOffset.ToString(CultureInfo.InvariantCulture)));
                    }
                    result = CacheValidationStatus.DoNotTakeFromCache;
                }

                if (resp.LastModified.ToUniversalTime() == CacheEntry.LastModifiedUtc)
                {
                    if (CacheEntry.IsPartialEntry)
                    {
                        // A caller will need to use Validator.CacheEntry.StreamSize to figure out what the restart point is

                        if (resp.ContentLength > 0)
                        {
                            this.CacheStreamLength = resp.ContentLength;
                        }
                        else
                        {
                            this.CacheStreamLength = -1;
                        }

                        result = CacheValidationStatus.CombineCachedAndServerResponse;
                    }
                    else if (resp.ContentLength == CacheEntry.StreamSize)
                    {
                        result = CacheValidationStatus.ReturnCachedResponse;
                    }
                    else
                    {
                        result = CacheValidationStatus.DoNotTakeFromCache;
                    }
                }
                else
                {
                    result = CacheValidationStatus.DoNotTakeFromCache;
                }
            }
            else
            {
                result = CacheValidationStatus.DoNotTakeFromCache;
            }

            return(result);
        }
        /*
        //                                    
        protected RequestCacheValidator(): this(false, TimeSpan.FromDays(1))
        {
        }
        */

        protected RequestCacheValidator(bool strictCacheErrors, TimeSpan unspecifiedMaxAge)
        {
            _StrictCacheErrors    = strictCacheErrors;
            _UnspecifiedMaxAge    = unspecifiedMaxAge;
            _ValidationStatus     = CacheValidationStatus.DoNotUseCache;
            _CacheFreshnessStatus = CacheFreshnessStatus.Undefined;
        }
        /*-------------- internal members -------------*/
        //
        internal void FetchRequest(Uri uri, WebRequest request)
        {
            _Request = request;
            _Policy  = request.CachePolicy;
            _Response = null;
            _ResponseCount = 0;
            _ValidationStatus     = CacheValidationStatus.DoNotUseCache;
            _CacheFreshnessStatus = CacheFreshnessStatus.Undefined;
            _CacheStream          = null;
            _CacheStreamOffset    = 0L;
            _CacheStreamLength    = 0L;

            if (!uri.Equals(_Uri))
            {
                // it's changed from previous call
                _CacheKey = uri.GetParts(UriComponents.AbsoluteUri, UriFormat.Unescaped);
            }
            _Uri = uri;
        }
        private void CheckRetrieveBeforeSubmit()
        {
            try
            {
                RequestCacheEntry entry;
            Label_0000:
                if ((this._Validator.CacheStream != null) && (this._Validator.CacheStream != Stream.Null))
                {
                    this._Validator.CacheStream.Close();
                    this._Validator.CacheStream = Stream.Null;
                }
                if (this._Validator.StrictCacheErrors)
                {
                    this._Validator.CacheStream = this._RequestCache.Retrieve(this._Validator.CacheKey, out entry);
                }
                else
                {
                    Stream stream;
                    this._RequestCache.TryRetrieve(this._Validator.CacheKey, out entry, out stream);
                    this._Validator.CacheStream = stream;
                }
                if (entry == null)
                {
                    entry = new RequestCacheEntry {
                        IsPrivateEntry = this._RequestCache.IsPrivateCache
                    };
                    this._Validator.FetchCacheEntry(entry);
                }
                if (this._Validator.CacheStream == null)
                {
                    this._Validator.CacheStream = Stream.Null;
                }
                this.ValidateFreshness(entry);
                this._ProtocolStatus = this.ValidateCache();
                switch (this._ProtocolStatus)
                {
                    case CacheValidationStatus.DoNotUseCache:
                    case CacheValidationStatus.DoNotTakeFromCache:
                        return;

                    case CacheValidationStatus.Fail:
                        this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_fail", new object[] { "ValidateCache" }));
                        return;

                    case CacheValidationStatus.RetryResponseFromCache:
                        goto Label_0000;

                    case CacheValidationStatus.ReturnCachedResponse:
                        if ((this._Validator.CacheStream != null) && (this._Validator.CacheStream != Stream.Null))
                        {
                            break;
                        }
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_no_cache_entry", new object[] { "ValidateCache()" }));
                        }
                        this._ProtocolStatus = CacheValidationStatus.Fail;
                        this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_no_stream", new object[] { this._Validator.CacheKey }));
                        return;

                    case CacheValidationStatus.Continue:
                        this._ResponseStream = this._Validator.CacheStream;
                        return;

                    default:
                        goto Label_02CB;
                }
                Stream cacheStream = this._Validator.CacheStream;
                this._RequestCache.UnlockEntry(this._Validator.CacheStream);
                if ((this._Validator.CacheStreamOffset != 0L) || (this._Validator.CacheStreamLength != this._Validator.CacheEntry.StreamSize))
                {
                    cacheStream = new RangeStream(cacheStream, this._Validator.CacheStreamOffset, this._Validator.CacheStreamLength);
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_returned_range_cache", new object[] { "ValidateCache()", this._Validator.CacheStreamOffset, this._Validator.CacheStreamLength }));
                    }
                }
                this._ResponseStream = cacheStream;
                this._ResponseStreamLength = this._Validator.CacheStreamLength;
                return;
            Label_02CB:
                this._ProtocolStatus = CacheValidationStatus.Fail;
                this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_result", new object[] { "ValidateCache", this._Validator.ValidationStatus.ToString() }));
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_unexpected_status", new object[] { "ValidateCache()", this._Validator.ValidationStatus.ToString() }));
                }
            }
            catch (Exception exception)
            {
                this._ProtocolStatus = CacheValidationStatus.Fail;
                this._ProtocolException = exception;
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_object_and_exception", new object[] { "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (exception is WebException) ? exception.Message : exception.ToString() }));
                }
            }
            finally
            {
                if (((this._ResponseStream == null) && (this._Validator.CacheStream != null)) && (this._Validator.CacheStream != Stream.Null))
                {
                    this._Validator.CacheStream.Close();
                    this._Validator.CacheStream = Stream.Null;
                }
            }
        }
Пример #22
0
        /// <summary>
        /// Happens at the incoming (executING)
        /// </summary>
        /// <param name="timedEtag"></param>
        /// <param name="cacheValidationStatus"></param>
        /// <param name="context">
        /// </param>
        /// <returns>
        /// True: applied and the call can exit
        /// False: tried to apply but did not match hence the call should continue
        /// null: could not apply (timedEtag was null)
        /// </returns>
        protected bool?ApplyCacheValidation(TimedEntityTagHeaderValue timedEtag,
                                            CacheValidationStatus cacheValidationStatus,
                                            ContextUnifier context)
        {
            if (timedEtag == null)
            {
                return(null);
            }

            switch (cacheValidationStatus)
            {
            case CacheValidationStatus.GetIfModifiedSince:
                if (timedEtag.LastModified == null)
                {
                    return(false);
                }
                else
                {
                    if (timedEtag.LastModified > context.Request.Headers.IfModifiedSince.Value)
                    {
                        return(false);
                    }
                    else
                    {
                        context.Response = new HttpResponseMessage(HttpStatusCode.NotModified);
                        return(true);
                    }
                }

            case CacheValidationStatus.GetIfNoneMatch:
                if (timedEtag.ETag == null)
                {
                    return(false);
                }
                else
                {
                    if (context.Request.Headers.IfNoneMatch.Any(x => x.Tag == timedEtag.ETag.Tag))
                    {
                        context.Response = new HttpResponseMessage(HttpStatusCode.NotModified);
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }

            case CacheValidationStatus.PutPatchDeleteIfMatch:
                if (timedEtag.ETag == null)
                {
                    return(false);
                }
                else
                {
                    if (context.Request.Headers.IfMatch.Any(x => x.Tag == timedEtag.ETag.Tag))
                    {
                        return(false);
                    }
                    else
                    {
                        context.Response = new HttpResponseMessage(HttpStatusCode.PreconditionFailed);
                        return(true);
                    }
                }

            case CacheValidationStatus.PutPatchDeleteIfUnModifiedSince:
                if (timedEtag.LastModified == null)
                {
                    return(false);
                }
                else
                {
                    if (timedEtag.LastModified > context.Request.Headers.IfUnmodifiedSince.Value)
                    {
                        context.Response = new HttpResponseMessage(HttpStatusCode.PreconditionFailed);
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }

            default:
                return(null);
            }
        }
        internal CacheValidationStatus GetRetrieveStatus(Uri cacheUri, WebRequest request)
        {
            if (cacheUri == null)
            {
                throw new ArgumentNullException("cacheUri");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (!this._CanTakeNewRequest || (this._ProtocolStatus == CacheValidationStatus.RetryResponseFromServer))
            {
                return(CacheValidationStatus.Continue);
            }
            this._CanTakeNewRequest    = false;
            this._ResponseStream       = null;
            this._ResponseStreamLength = 0L;
            this._ProtocolStatus       = CacheValidationStatus.Continue;
            this._ProtocolException    = null;
            if (Logging.On)
            {
                Logging.Enter(Logging.RequestCache, this, "GetRetrieveStatus", request);
            }
            try
            {
                if ((request.CachePolicy == null) || (request.CachePolicy.Level == RequestCacheLevel.BypassCache))
                {
                    this._ProtocolStatus = CacheValidationStatus.DoNotUseCache;
                    return(this._ProtocolStatus);
                }
                if ((this._RequestCache == null) || (this._Validator == null))
                {
                    this._ProtocolStatus = CacheValidationStatus.DoNotUseCache;
                    return(this._ProtocolStatus);
                }
                this._Validator.FetchRequest(cacheUri, request);
                switch ((this._ProtocolStatus = this.ValidateRequest()))
                {
                case CacheValidationStatus.DoNotUseCache:
                case CacheValidationStatus.DoNotTakeFromCache:
                case CacheValidationStatus.Continue:
                    break;

                case CacheValidationStatus.Fail:
                    this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_fail", new object[] { "ValidateRequest" }));
                    break;

                default:
                    this._ProtocolStatus    = CacheValidationStatus.Fail;
                    this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_result", new object[] { "ValidateRequest", this._Validator.ValidationStatus.ToString() }));
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_unexpected_status", new object[] { "ValidateRequest()", this._Validator.ValidationStatus.ToString() }));
                    }
                    break;
                }
                if (this._ProtocolStatus != CacheValidationStatus.Continue)
                {
                    return(this._ProtocolStatus);
                }
                this.CheckRetrieveBeforeSubmit();
            }
            catch (Exception exception)
            {
                this._ProtocolException = exception;
                this._ProtocolStatus    = CacheValidationStatus.Fail;
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_object_and_exception", new object[] { "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (exception is WebException) ? exception.Message : exception.ToString() }));
                }
            }
            finally
            {
                if (Logging.On)
                {
                    Logging.Exit(Logging.RequestCache, this, "GetRetrieveStatus", "result = " + this._ProtocolStatus.ToString());
                }
            }
            return(this._ProtocolStatus);
        }
        private void CheckUpdateOnResponse(Stream responseStream)
        {
            if (this._Validator.CacheEntry == null)
            {
                RequestCacheEntry fetchEntry = new RequestCacheEntry {
                    IsPrivateEntry = this._RequestCache.IsPrivateCache
                };
                this._Validator.FetchCacheEntry(fetchEntry);
            }
            string cacheKey = this._Validator.CacheKey;
            bool   flag     = true;

            try
            {
                Stream stream;
                switch ((this._ProtocolStatus = this.UpdateCache()))
                {
                case CacheValidationStatus.DoNotUseCache:
                case CacheValidationStatus.DoNotUpdateCache:
                    return;

                case CacheValidationStatus.Fail:
                    this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_fail", new object[] { "UpdateCache" }));
                    return;

                case CacheValidationStatus.CacheResponse:
                    if (!this._Validator.StrictCacheErrors)
                    {
                        break;
                    }
                    stream = this._RequestCache.Store(this._Validator.CacheKey, this._Validator.CacheEntry.StreamSize, this._Validator.CacheEntry.ExpiresUtc, this._Validator.CacheEntry.LastModifiedUtc, this._Validator.CacheEntry.MaxStale, this._Validator.CacheEntry.EntryMetadata, this._Validator.CacheEntry.SystemMetadata);
                    goto Label_022C;

                case CacheValidationStatus.UpdateResponseInformation:
                    this._ResponseStream = new MetadataUpdateStream(responseStream, this._RequestCache, this._Validator.CacheKey, this._Validator.CacheEntry.ExpiresUtc, this._Validator.CacheEntry.LastModifiedUtc, this._Validator.CacheEntry.LastSynchronizedUtc, this._Validator.CacheEntry.MaxStale, this._Validator.CacheEntry.EntryMetadata, this._Validator.CacheEntry.SystemMetadata, this._Validator.StrictCacheErrors);
                    flag = false;
                    this._ProtocolStatus = CacheValidationStatus.UpdateResponseInformation;
                    return;

                case CacheValidationStatus.RemoveFromCache:
                    this.EnsureCacheRemoval(cacheKey);
                    flag = false;
                    return;

                default:
                    goto Label_0298;
                }
                this._RequestCache.TryStore(this._Validator.CacheKey, this._Validator.CacheEntry.StreamSize, this._Validator.CacheEntry.ExpiresUtc, this._Validator.CacheEntry.LastModifiedUtc, this._Validator.CacheEntry.MaxStale, this._Validator.CacheEntry.EntryMetadata, this._Validator.CacheEntry.SystemMetadata, out stream);
Label_022C:
                if (stream == null)
                {
                    this._ProtocolStatus = CacheValidationStatus.DoNotUpdateCache;
                }
                else
                {
                    this._ResponseStream = new ForwardingReadStream(responseStream, stream, this._Validator.CacheStreamOffset, this._Validator.StrictCacheErrors);
                    this._ProtocolStatus = CacheValidationStatus.UpdateResponseInformation;
                }
                return;

Label_0298:
                this._ProtocolStatus    = CacheValidationStatus.Fail;
                this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_result", new object[] { "UpdateCache", this._Validator.ValidationStatus.ToString() }));
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_unexpected_status", new object[] { "UpdateCache()", this._Validator.ValidationStatus.ToString() }));
                }
            }
            finally
            {
                if (flag)
                {
                    this._RequestCache.UnlockEntry(this._Validator.CacheStream);
                }
            }
        }
        //
        // This will decide on cache update and construct the effective response stream
        //
        private void CheckUpdateOnResponse(Stream responseStream)
        {

            if  (_Validator.CacheEntry == null)
            {
                // There was no chance to create an empty entry yet
                RequestCacheEntry cacheEntry = new RequestCacheEntry();
                cacheEntry.IsPrivateEntry = _RequestCache.IsPrivateCache;
                _Validator.FetchCacheEntry(cacheEntry);
            }

            // With NoCache we may end up storing whole response as a new entry in Cache.
            // Otherwise we may end up updating Context+Metadata or just Context
            //
            // In any case we may end up doing nothing.
            //
            string retrieveKey = _Validator.CacheKey;

            bool unlockEntry = true;
            try {
                switch (_ProtocolStatus=UpdateCache()) {

                case CacheValidationStatus.RemoveFromCache:
                        EnsureCacheRemoval(retrieveKey);
                        unlockEntry = false;
                        break;

                case CacheValidationStatus.UpdateResponseInformation:
                        // NB: Just invoked validator must have updated CacheEntry and transferred
                        //     ONLY allowed headers from the response to the Context.xxxMetadata member

                        _ResponseStream = new MetadataUpdateStream(
                                                                    responseStream,
                                                                    _RequestCache,
                                                                    _Validator.CacheKey,
                                                                    _Validator.CacheEntry.ExpiresUtc,
                                                                    _Validator.CacheEntry.LastModifiedUtc,
                                                                    _Validator.CacheEntry.LastSynchronizedUtc,
                                                                    _Validator.CacheEntry.MaxStale,
                                                                    _Validator.CacheEntry.EntryMetadata,
                                                                    _Validator.CacheEntry.SystemMetadata,
                                                                    _Validator.StrictCacheErrors);
                        //
                        // This can be looked as a design hole since we have to keep the entry
                        // locked for the case when we want to update that previously retrieved entry.
                        // I think RequestCache contract should allow to detect that a new physical cache entry
                        // does not match to the "entry being updated" and so to should ignore updates on replaced entries.
                        //
                        unlockEntry = false;
                        _ProtocolStatus = CacheValidationStatus.UpdateResponseInformation;
                        break;

                case CacheValidationStatus.CacheResponse:
                        // NB: Just invoked validator must have updated CacheEntry and transferred
                        //     ONLY allowed headers from the response to the Context.xxxMetadata member

                        Stream stream;
                        if (_Validator.StrictCacheErrors)
                            {stream = _RequestCache.Store(_Validator.CacheKey, _Validator.CacheEntry.StreamSize, _Validator.CacheEntry.ExpiresUtc, _Validator.CacheEntry.LastModifiedUtc, _Validator.CacheEntry.MaxStale, _Validator.CacheEntry.EntryMetadata, _Validator.CacheEntry.SystemMetadata);}
                        else
                            {_RequestCache.TryStore(_Validator.CacheKey, _Validator.CacheEntry.StreamSize, _Validator.CacheEntry.ExpiresUtc, _Validator.CacheEntry.LastModifiedUtc, _Validator.CacheEntry.MaxStale, _Validator.CacheEntry.EntryMetadata, _Validator.CacheEntry.SystemMetadata, out stream);}

                        // Wrap the response stream into forwarding one
                        if (stream == null) {
                            _ProtocolStatus = CacheValidationStatus.DoNotUpdateCache;
                        }
                        else {
                            _ResponseStream = new ForwardingReadStream(responseStream, stream, _Validator.CacheStreamOffset, _Validator.StrictCacheErrors);
                            _ProtocolStatus = CacheValidationStatus.UpdateResponseInformation;
                        }
                        break;

                case CacheValidationStatus.DoNotUseCache:
                case CacheValidationStatus.DoNotUpdateCache:
                        break;

                case CacheValidationStatus.Fail:
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "UpdateCache"));
                        break;
                default:
                        _ProtocolStatus = CacheValidationStatus.Fail;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "UpdateCache", _Validator.ValidationStatus.ToString()));
                        if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "UpdateCache()", _Validator.ValidationStatus.ToString()));
                        break;
                }
            }
            finally {
                if (unlockEntry)
                {
                    // The entry can now be replaced as we are not going for cache entry metadata-only  update
                    _RequestCache.UnlockEntry(_Validator.CacheStream);
                }
            }
        }
        //
        private void CheckRetrieveOnResponse(Stream responseStream)
        {
            GlobalLog.Assert(_ProtocolStatus == CacheValidationStatus.Continue || _ProtocolStatus == CacheValidationStatus.RetryResponseFromServer, "CheckRetrieveOnResponse()|Unexpected _ProtocolStatus = ", _ProtocolStatus);
            bool closeCacheStream = true;

            try {
                // This will inspect the live response on the correctness matter
                switch (_ProtocolStatus = ValidateResponse())
                {
                case CacheValidationStatus.Continue:
                    closeCacheStream = false;
                    // The response looks good
                    break;

                case CacheValidationStatus.RetryResponseFromServer:
                    closeCacheStream = false;
                    break;

                case CacheValidationStatus.Fail:
                    _ProtocolStatus    = CacheValidationStatus.Fail;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "ValidateResponse"));
                    break;

                case CacheValidationStatus.DoNotUseCache:
                    break;

                default:
                    _ProtocolStatus    = CacheValidationStatus.Fail;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "ValidateResponse", _Validator.ValidationStatus.ToString()));
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "ValidateResponse()", _Validator.ValidationStatus.ToString()));
                    }
                    break;
                }
            }
            catch (Exception e) {
                closeCacheStream   = true;
                _ProtocolException = e;
                _ProtocolStatus    = CacheValidationStatus.Fail;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
                }
            }
            finally {
                // This is to release cache entry in case we are not interested in it
                if (closeCacheStream && _ResponseStream != null)
                {
                    _ResponseStream.Close();
                    _ResponseStream        = null;
                    _Validator.CacheStream = Stream.Null;
                }
            }

            if (_ProtocolStatus != CacheValidationStatus.Continue)
            {
                return;
            }

            //
            // only CacheValidationStatus.Continue goes here with closeCacheStream == false
            //

            try {
                //
                switch (_ProtocolStatus = RevalidateCache())
                {
                case CacheValidationStatus.DoNotUseCache:
                case CacheValidationStatus.RemoveFromCache:
                case CacheValidationStatus.DoNotTakeFromCache:
                    closeCacheStream = true;
                    break;

                case CacheValidationStatus.ReturnCachedResponse:
                    if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null)
                    {
                        _ProtocolStatus    = CacheValidationStatus.Fail;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_no_stream, _Validator.CacheKey));
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_null_cached_stream, "RevalidateCache()"));
                        }
                        break;
                    }

                    Stream stream = _Validator.CacheStream;

                    if (_Validator.CacheStreamOffset != 0L || _Validator.CacheStreamLength != _Validator.CacheEntry.StreamSize)
                    {
                        stream = new RangeStream(stream, _Validator.CacheStreamOffset, _Validator.CacheStreamLength);
                        if (Logging.On)
                        {
                            Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_returned_range_cache, "RevalidateCache()", _Validator.CacheStreamOffset, _Validator.CacheStreamLength));
                        }
                    }
                    _ResponseStream       = stream;
                    _ResponseStreamLength = _Validator.CacheStreamLength;
                    break;

                case CacheValidationStatus.CombineCachedAndServerResponse:

                    if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null)
                    {
                        _ProtocolStatus    = CacheValidationStatus.Fail;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_no_stream, _Validator.CacheKey));
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_requested_combined_but_null_cached_stream, "RevalidateCache()"));
                        }
                        break;
                    }
                    if (responseStream != null)
                    {
                        stream = new CombinedReadStream(_Validator.CacheStream, responseStream);
                    }
                    else
                    {
                        // So Abort can close the cache stream
                        stream = _Validator.CacheStream;
                    }
                    _ResponseStream       = stream;
                    _ResponseStreamLength = _Validator.CacheStreamLength;
                    break;


                case CacheValidationStatus.Fail:
                    closeCacheStream   = true;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "RevalidateCache"));
                    break;

                default:
                    closeCacheStream   = true;
                    _ProtocolStatus    = CacheValidationStatus.Fail;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "RevalidateCache", _Validator.ValidationStatus.ToString()));
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "RevalidateCache()", _Validator.ValidationStatus.ToString()));
                    }
                    break;
                }
            }
            catch (Exception e) {
                closeCacheStream   = true;
                _ProtocolException = e;
                _ProtocolStatus    = CacheValidationStatus.Fail;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
                }
            }
            finally {
                // This is to release cache entry in case we are not interested in it
                if (closeCacheStream && _ResponseStream != null)
                {
                    _ResponseStream.Close();
                    _ResponseStream        = null;
                    _Validator.CacheStream = Stream.Null;
                }
            }
        }
        //
        // Private methods
        //

        //
        // This method may be invoked as part of the request submission but before issuing a live request
        //
        private void CheckRetrieveBeforeSubmit() {

            GlobalLog.Assert(_ProtocolStatus == CacheValidationStatus.Continue, "CheckRetrieveBeforeSubmit()|Unexpected _ProtocolStatus = {0}", _ProtocolStatus);

            try {

                while (true)
                {
                    RequestCacheEntry cacheEntry;

                    if (_Validator.CacheStream != null && _Validator.CacheStream != Stream.Null)
                    {
                        // Reset to Initial state
                        _Validator.CacheStream.Close();
                        _Validator.CacheStream = Stream.Null;
                    }

                    if (_Validator.StrictCacheErrors)
                    {
                        _Validator.CacheStream = _RequestCache.Retrieve(_Validator.CacheKey, out cacheEntry);
                    }
                    else
                    {
                        Stream stream;
                        _RequestCache.TryRetrieve(_Validator.CacheKey, out cacheEntry, out stream);
                        _Validator.CacheStream = stream;
                    }

                    if (cacheEntry == null)
                    {
                        cacheEntry = new RequestCacheEntry();
                        cacheEntry.IsPrivateEntry = _RequestCache.IsPrivateCache;
                        _Validator.FetchCacheEntry(cacheEntry);
                    }

                    if (_Validator.CacheStream == null)
                    {
                        // If entry does not have a stream an empty stream wrapper must be returned.
                        // A null or Stream.Null value stands for non existent cache entry.
                        _Validator.CacheStream = Stream.Null;
                    }

                    ValidateFreshness(cacheEntry);

                    _ProtocolStatus = ValidateCache();

                    // This will tell us what to do next
                    switch (_ProtocolStatus) {

                    case CacheValidationStatus.ReturnCachedResponse:
                            if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null)
                            {
                                if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_no_cache_entry, "ValidateCache()"));
                                _ProtocolStatus = CacheValidationStatus.Fail;
                                _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_no_stream, _Validator.CacheKey));
                                break;
                            }

                            // Final decision is made, check on a range response from cache
                            Stream stream = _Validator.CacheStream;
                            // The entry can now be replaced as we are not going for cache entry metadata-only  update
                            _RequestCache.UnlockEntry(_Validator.CacheStream);

                            if (_Validator.CacheStreamOffset != 0L || _Validator.CacheStreamLength != _Validator.CacheEntry.StreamSize)
                            {
                                stream =  new RangeStream(stream, _Validator.CacheStreamOffset, _Validator.CacheStreamLength);
                                if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_returned_range_cache, "ValidateCache()", _Validator.CacheStreamOffset, _Validator.CacheStreamLength));
                            }
                            _ResponseStream = stream;
                            _ResponseStreamLength = _Validator.CacheStreamLength;
                            break;

                    case CacheValidationStatus.Continue:
                            // copy a cache stream ref
                            _ResponseStream = _Validator.CacheStream;
                            break;

                    case CacheValidationStatus.RetryResponseFromCache:
                            // loop thought cache retrieve
                            continue;

                    case CacheValidationStatus.DoNotTakeFromCache:
                    case CacheValidationStatus.DoNotUseCache:
                            break;

                    case CacheValidationStatus.Fail:
                            _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "ValidateCache"));
                            break;

                    default:
                        _ProtocolStatus = CacheValidationStatus.Fail;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "ValidateCache", _Validator.ValidationStatus.ToString()));
                            if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "ValidateCache()", _Validator.ValidationStatus.ToString()));
                            break;
                    }
                    break;
                }
            }
            catch (Exception e) {
                _ProtocolStatus = CacheValidationStatus.Fail;
                _ProtocolException = e;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
                    throw;
                }
                if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
            }
            finally {
                // This is to release cache entry on error
                if (_ResponseStream == null && _Validator.CacheStream != null && _Validator.CacheStream != Stream.Null)
                {
                    _Validator.CacheStream.Close();
                    _Validator.CacheStream = Stream.Null;
                }
            }
        }
        //
        // This optional method is only for protocols supporting a revalidation concept
        // For a retried request this method must be called again.
        //
        internal CacheValidationStatus GetRevalidateStatus (WebResponse response, Stream responseStream)
        {
            if (response == null)
                throw new ArgumentNullException("response");

            if (_ProtocolStatus == CacheValidationStatus.DoNotUseCache)
                return CacheValidationStatus.DoNotUseCache;

            // If we returned cached response, switch the state to not call cache anymore.
            if (_ProtocolStatus == CacheValidationStatus.ReturnCachedResponse)
            {
                _ProtocolStatus = CacheValidationStatus.DoNotUseCache;
                return _ProtocolStatus;
            }

            try {
                if(Logging.On) Logging.Enter(Logging.RequestCache, this, "GetRevalidateStatus", (_Validator == null? null: _Validator.Request));

                _Validator.FetchResponse(response);

                if (_ProtocolStatus != CacheValidationStatus.Continue && _ProtocolStatus != CacheValidationStatus.RetryResponseFromServer)
                {
                    if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_revalidation_not_needed, "GetRevalidateStatus()"));
                    return _ProtocolStatus;
                }
                CheckRetrieveOnResponse(responseStream);
            }
            finally {
                if(Logging.On) Logging.Exit(Logging.RequestCache, this, "GetRevalidateStatus", "result = " + _ProtocolStatus.ToString());
            }
            return _ProtocolStatus;
        }
        private void CheckRetrieveOnResponse(Stream responseStream)
        {
            bool flag = true;

            try
            {
                switch ((this._ProtocolStatus = this.ValidateResponse()))
                {
                case CacheValidationStatus.DoNotUseCache:
                    goto Label_01CA;

                case CacheValidationStatus.Fail:
                    this._ProtocolStatus    = CacheValidationStatus.Fail;
                    this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_fail", new object[] { "ValidateResponse" }));
                    goto Label_01CA;

                case CacheValidationStatus.RetryResponseFromServer:
                    flag = false;
                    goto Label_01CA;

                case CacheValidationStatus.Continue:
                    flag = false;
                    goto Label_01CA;
                }
                this._ProtocolStatus    = CacheValidationStatus.Fail;
                this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_result", new object[] { "ValidateResponse", this._Validator.ValidationStatus.ToString() }));
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_unexpected_status", new object[] { "ValidateResponse()", this._Validator.ValidationStatus.ToString() }));
                }
            }
            catch (Exception exception)
            {
                flag = true;
                this._ProtocolException = exception;
                this._ProtocolStatus    = CacheValidationStatus.Fail;
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_object_and_exception", new object[] { "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (exception is WebException) ? exception.Message : exception.ToString() }));
                }
            }
            finally
            {
                if (flag && (this._ResponseStream != null))
                {
                    this._ResponseStream.Close();
                    this._ResponseStream        = null;
                    this._Validator.CacheStream = Stream.Null;
                }
            }
Label_01CA:
            if (this._ProtocolStatus != CacheValidationStatus.Continue)
            {
                return;
            }
            try
            {
                switch ((this._ProtocolStatus = this.RevalidateCache()))
                {
                case CacheValidationStatus.DoNotUseCache:
                case CacheValidationStatus.DoNotTakeFromCache:
                case CacheValidationStatus.RemoveFromCache:
                    flag = true;
                    return;

                case CacheValidationStatus.Fail:
                    flag = true;
                    this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_fail", new object[] { "RevalidateCache" }));
                    return;

                case CacheValidationStatus.ReturnCachedResponse:
                    if ((this._Validator.CacheStream != null) && (this._Validator.CacheStream != Stream.Null))
                    {
                        break;
                    }
                    this._ProtocolStatus    = CacheValidationStatus.Fail;
                    this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_no_stream", new object[] { this._Validator.CacheKey }));
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_null_cached_stream", new object[] { "RevalidateCache()" }));
                    }
                    return;

                case CacheValidationStatus.CombineCachedAndServerResponse:
                    if ((this._Validator.CacheStream != null) && (this._Validator.CacheStream != Stream.Null))
                    {
                        goto Label_03FF;
                    }
                    this._ProtocolStatus    = CacheValidationStatus.Fail;
                    this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_no_stream", new object[] { this._Validator.CacheKey }));
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_requested_combined_but_null_cached_stream", new object[] { "RevalidateCache()" }));
                    }
                    return;

                default:
                    goto Label_046E;
                }
                Stream cacheStream = this._Validator.CacheStream;
                if ((this._Validator.CacheStreamOffset != 0L) || (this._Validator.CacheStreamLength != this._Validator.CacheEntry.StreamSize))
                {
                    cacheStream = new RangeStream(cacheStream, this._Validator.CacheStreamOffset, this._Validator.CacheStreamLength);
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_returned_range_cache", new object[] { "RevalidateCache()", this._Validator.CacheStreamOffset, this._Validator.CacheStreamLength }));
                    }
                }
                this._ResponseStream       = cacheStream;
                this._ResponseStreamLength = this._Validator.CacheStreamLength;
                return;

Label_03FF:
                if (responseStream != null)
                {
                    cacheStream = new CombinedReadStream(this._Validator.CacheStream, responseStream);
                }
                else
                {
                    cacheStream = this._Validator.CacheStream;
                }
                this._ResponseStream       = cacheStream;
                this._ResponseStreamLength = this._Validator.CacheStreamLength;
                return;

Label_046E:
                flag = true;
                this._ProtocolStatus    = CacheValidationStatus.Fail;
                this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_result", new object[] { "RevalidateCache", this._Validator.ValidationStatus.ToString() }));
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_unexpected_status", new object[] { "RevalidateCache()", this._Validator.ValidationStatus.ToString() }));
                }
            }
            catch (Exception exception2)
            {
                flag = true;
                this._ProtocolException = exception2;
                this._ProtocolStatus    = CacheValidationStatus.Fail;
                if (((exception2 is ThreadAbortException) || (exception2 is StackOverflowException)) || (exception2 is OutOfMemoryException))
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_object_and_exception", new object[] { "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (exception2 is WebException) ? exception2.Message : exception2.ToString() }));
                }
            }
            finally
            {
                if (flag && (this._ResponseStream != null))
                {
                    this._ResponseStream.Close();
                    this._ResponseStream        = null;
                    this._Validator.CacheStream = Stream.Null;
                }
            }
        }
Пример #30
0
        /// <summary>
        /// Happens at the incoming (executING)
        /// </summary>
        /// <param name="timedEtag"></param>
        /// <param name="cacheValidationStatus"></param>
        /// <param name="context">
        /// </param>
        /// <returns>
        /// True: applied and the call can exit
        /// False: tried to apply but did not match hence the call should continue
        /// null: could not apply (timedEtag was null)
        /// </returns>
        protected bool?ApplyCacheValidation(TimedEntityTagHeaderValue timedEtag,
                                            CacheValidationStatus cacheValidationStatus,
                                            ResourceExecutingContext context)
        {
            if (timedEtag == null)
            {
                return(null);
            }

            var headers = context.HttpContext.Request.GetTypedHeadersWithCaching();

            switch (cacheValidationStatus)
            {
            case CacheValidationStatus.GetIfModifiedSince:
                if (timedEtag.LastModified == null)
                {
                    return(false);
                }
                else
                {
                    if (timedEtag.LastModified > headers.IfModifiedSince.Value)
                    {
                        return(false);
                    }
                    else
                    {
                        context.Result = new StatusCodeResult(StatusCodes.Status304NotModified);
                        context.HttpContext.Response.StatusCode = StatusCodes.Status304NotModified;
                        return(true);
                    }
                }

            case CacheValidationStatus.GetIfNoneMatch:
                if (timedEtag.ETag == null)
                {
                    return(false);
                }
                else
                {
                    if (headers.IfNoneMatch.Any(x => x.Tag == timedEtag.ETag.Tag))
                    {
                        context.Result = new StatusCodeResult(StatusCodes.Status304NotModified);
                        context.HttpContext.Response.StatusCode = StatusCodes.Status304NotModified;
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }

            case CacheValidationStatus.PutIfMatch:
                if (timedEtag.ETag == null)
                {
                    return(false);
                }
                else
                {
                    if (headers.IfMatch.Any(x => x.Tag == timedEtag.ETag.Tag))
                    {
                        return(false);
                    }
                    else
                    {
                        context.Result = new StatusCodeResult(StatusCodes.Status409Conflict);
                        context.HttpContext.Response.StatusCode = StatusCodes.Status409Conflict;
                        return(true);
                    }
                }

            case CacheValidationStatus.PutIfUnModifiedSince:
                if (timedEtag.LastModified == null)
                {
                    return(false);
                }
                else
                {
                    if (timedEtag.LastModified > headers.IfUnmodifiedSince.Value)
                    {
                        context.Result = new StatusCodeResult(StatusCodes.Status409Conflict);
                        context.HttpContext.Response.StatusCode = StatusCodes.Status409Conflict;
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }

            default:
                return(null);
            }
        }
 internal CacheValidationStatus GetUpdateStatus(WebResponse response, Stream responseStream)
 {
     if (response == null)
     {
         throw new ArgumentNullException("response");
     }
     if (this._ProtocolStatus == CacheValidationStatus.DoNotUseCache)
     {
         return CacheValidationStatus.DoNotUseCache;
     }
     try
     {
         if (Logging.On)
         {
             Logging.Enter(Logging.RequestCache, this, "GetUpdateStatus", (string) null);
         }
         if (this._Validator.Response == null)
         {
             this._Validator.FetchResponse(response);
         }
         if (this._ProtocolStatus == CacheValidationStatus.RemoveFromCache)
         {
             this.EnsureCacheRemoval(this._Validator.CacheKey);
             return this._ProtocolStatus;
         }
         if (((this._ProtocolStatus != CacheValidationStatus.DoNotTakeFromCache) && (this._ProtocolStatus != CacheValidationStatus.ReturnCachedResponse)) && (this._ProtocolStatus != CacheValidationStatus.CombineCachedAndServerResponse))
         {
             if (Logging.On)
             {
                 Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_not_updated_based_on_cache_protocol_status", new object[] { "GetUpdateStatus()", this._ProtocolStatus.ToString() }));
             }
             return this._ProtocolStatus;
         }
         this.CheckUpdateOnResponse(responseStream);
     }
     catch (Exception exception)
     {
         this._ProtocolException = exception;
         this._ProtocolStatus = CacheValidationStatus.Fail;
         if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
         {
             throw;
         }
         if (Logging.On)
         {
             Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_object_and_exception", new object[] { "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (exception is WebException) ? exception.Message : exception.ToString() }));
         }
     }
     finally
     {
         if (Logging.On)
         {
             Logging.Exit(Logging.RequestCache, this, "GetUpdateStatus", "result = " + this._ProtocolStatus.ToString());
         }
     }
     return this._ProtocolStatus;
 }
        //
        // Private methods
        //

        //
        // This method may be invoked as part of the request submission but before issuing a live request
        //
        private void CheckRetrieveBeforeSubmit()
        {
            GlobalLog.Assert(_ProtocolStatus == CacheValidationStatus.Continue, "CheckRetrieveBeforeSubmit()|Unexpected _ProtocolStatus = {0}", _ProtocolStatus);

            try {
                while (true)
                {
                    RequestCacheEntry cacheEntry;

                    if (_Validator.CacheStream != null && _Validator.CacheStream != Stream.Null)
                    {
                        // Reset to Initial state
                        _Validator.CacheStream.Close();
                        _Validator.CacheStream = Stream.Null;
                    }

                    if (_Validator.StrictCacheErrors)
                    {
                        _Validator.CacheStream = _RequestCache.Retrieve(_Validator.CacheKey, out cacheEntry);
                    }
                    else
                    {
                        Stream stream;
                        _RequestCache.TryRetrieve(_Validator.CacheKey, out cacheEntry, out stream);
                        _Validator.CacheStream = stream;
                    }

                    if (cacheEntry == null)
                    {
                        cacheEntry = new RequestCacheEntry();
                        cacheEntry.IsPrivateEntry = _RequestCache.IsPrivateCache;
                        _Validator.FetchCacheEntry(cacheEntry);
                    }

                    if (_Validator.CacheStream == null)
                    {
                        // If entry does not have a stream an empty stream wrapper must be returned.
                        // A null or Stream.Null value stands for non existent cache entry.
                        _Validator.CacheStream = Stream.Null;
                    }

                    ValidateFreshness(cacheEntry);

                    _ProtocolStatus = ValidateCache();

                    // This will tell us what to do next
                    switch (_ProtocolStatus)
                    {
                    case CacheValidationStatus.ReturnCachedResponse:
                        if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null)
                        {
                            if (Logging.On)
                            {
                                Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_no_cache_entry, "ValidateCache()"));
                            }
                            _ProtocolStatus    = CacheValidationStatus.Fail;
                            _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_no_stream, _Validator.CacheKey));
                            break;
                        }

                        // Final decision is made, check on a range response from cache
                        Stream stream = _Validator.CacheStream;
                        // The entry can now be replaced as we are not going for cache entry metadata-only  update
                        _RequestCache.UnlockEntry(_Validator.CacheStream);

                        if (_Validator.CacheStreamOffset != 0L || _Validator.CacheStreamLength != _Validator.CacheEntry.StreamSize)
                        {
                            stream = new RangeStream(stream, _Validator.CacheStreamOffset, _Validator.CacheStreamLength);
                            if (Logging.On)
                            {
                                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_returned_range_cache, "ValidateCache()", _Validator.CacheStreamOffset, _Validator.CacheStreamLength));
                            }
                        }
                        _ResponseStream       = stream;
                        _ResponseStreamLength = _Validator.CacheStreamLength;
                        break;

                    case CacheValidationStatus.Continue:
                        // copy a cache stream ref
                        _ResponseStream = _Validator.CacheStream;
                        break;

                    case CacheValidationStatus.RetryResponseFromCache:
                        // loop thought cache retrieve
                        continue;

                    case CacheValidationStatus.DoNotTakeFromCache:
                    case CacheValidationStatus.DoNotUseCache:
                        break;

                    case CacheValidationStatus.Fail:
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "ValidateCache"));
                        break;

                    default:
                        _ProtocolStatus    = CacheValidationStatus.Fail;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "ValidateCache", _Validator.ValidationStatus.ToString()));
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "ValidateCache()", _Validator.ValidationStatus.ToString()));
                        }
                        break;
                    }
                    break;
                }
            }
            catch (Exception e) {
                _ProtocolStatus    = CacheValidationStatus.Fail;
                _ProtocolException = e;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
                }
            }
            finally {
                // This is to release cache entry on error
                if (_ResponseStream == null && _Validator.CacheStream != null && _Validator.CacheStream != Stream.Null)
                {
                    _Validator.CacheStream.Close();
                    _Validator.CacheStream = Stream.Null;
                }
            }
        }
Пример #33
0
 internal void SetValidationStatus(CacheValidationStatus status)
 {
     _ValidationStatus = status;
 }
        //
        // This will decide on cache update and construct the effective response stream
        //
        private void CheckUpdateOnResponse(Stream responseStream)
        {
            if (_Validator.CacheEntry == null)
            {
                // There was no chance to create an empty entry yet
                RequestCacheEntry cacheEntry = new RequestCacheEntry();
                cacheEntry.IsPrivateEntry = _RequestCache.IsPrivateCache;
                _Validator.FetchCacheEntry(cacheEntry);
            }

            // With NoCache we may end up storing whole response as a new entry in Cache.
            // Otherwise we may end up updating Context+Metadata or just Context
            //
            // In any case we may end up doing nothing.
            //
            string retrieveKey = _Validator.CacheKey;

            bool unlockEntry = true;

            try {
                switch (_ProtocolStatus = UpdateCache())
                {
                case CacheValidationStatus.RemoveFromCache:
                    EnsureCacheRemoval(retrieveKey);
                    unlockEntry = false;
                    break;

                case CacheValidationStatus.UpdateResponseInformation:
                    // NB: Just invoked validator must have updated CacheEntry and transferred
                    //     ONLY allowed headers from the response to the Context.xxxMetadata member

                    _ResponseStream = new MetadataUpdateStream(
                        responseStream,
                        _RequestCache,
                        _Validator.CacheKey,
                        _Validator.CacheEntry.ExpiresUtc,
                        _Validator.CacheEntry.LastModifiedUtc,
                        _Validator.CacheEntry.LastSynchronizedUtc,
                        _Validator.CacheEntry.MaxStale,
                        _Validator.CacheEntry.EntryMetadata,
                        _Validator.CacheEntry.SystemMetadata,
                        _Validator.StrictCacheErrors);
                    //
                    // This can be looked as a design hole since we have to keep the entry
                    // locked for the case when we want to update that previously retrieved entry.
                    // I think RequestCache contract should allow to detect that a new physical cache entry
                    // does not match to the "entry being updated" and so to should ignore updates on replaced entries.
                    //
                    unlockEntry     = false;
                    _ProtocolStatus = CacheValidationStatus.UpdateResponseInformation;
                    break;

                case CacheValidationStatus.CacheResponse:
                    // NB: Just invoked validator must have updated CacheEntry and transferred
                    //     ONLY allowed headers from the response to the Context.xxxMetadata member

                    Stream stream;
                    if (_Validator.StrictCacheErrors)
                    {
                        stream = _RequestCache.Store(_Validator.CacheKey, _Validator.CacheEntry.StreamSize, _Validator.CacheEntry.ExpiresUtc, _Validator.CacheEntry.LastModifiedUtc, _Validator.CacheEntry.MaxStale, _Validator.CacheEntry.EntryMetadata, _Validator.CacheEntry.SystemMetadata);
                    }
                    else
                    {
                        _RequestCache.TryStore(_Validator.CacheKey, _Validator.CacheEntry.StreamSize, _Validator.CacheEntry.ExpiresUtc, _Validator.CacheEntry.LastModifiedUtc, _Validator.CacheEntry.MaxStale, _Validator.CacheEntry.EntryMetadata, _Validator.CacheEntry.SystemMetadata, out stream);
                    }

                    // Wrap the response stream into forwarding one
                    _ResponseStream = new ForwardingReadStream(responseStream, stream, _Validator.CacheStreamOffset, _Validator.StrictCacheErrors);
                    _ProtocolStatus = CacheValidationStatus.UpdateResponseInformation;
                    break;

                case CacheValidationStatus.DoNotUseCache:
                case CacheValidationStatus.DoNotUpdateCache:
                    break;

                case CacheValidationStatus.Fail:
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "UpdateCache"));
                    break;

                default:
                    _ProtocolStatus    = CacheValidationStatus.Fail;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "UpdateCache", _Validator.ValidationStatus.ToString()));
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "UpdateCache()", _Validator.ValidationStatus.ToString()));
                    }
                    break;
                }
            }
            finally {
                if (unlockEntry)
                {
                    // The entry can now be replaced as we are not going for cache entry metadata-only  update
                    _RequestCache.UnlockEntry(_Validator.CacheStream);
                }
            }
        }
        private void CheckRetrieveBeforeSubmit()
        {
            try
            {
                RequestCacheEntry entry;
Label_0000:
                if ((this._Validator.CacheStream != null) && (this._Validator.CacheStream != Stream.Null))
                {
                    this._Validator.CacheStream.Close();
                    this._Validator.CacheStream = Stream.Null;
                }
                if (this._Validator.StrictCacheErrors)
                {
                    this._Validator.CacheStream = this._RequestCache.Retrieve(this._Validator.CacheKey, out entry);
                }
                else
                {
                    Stream stream;
                    this._RequestCache.TryRetrieve(this._Validator.CacheKey, out entry, out stream);
                    this._Validator.CacheStream = stream;
                }
                if (entry == null)
                {
                    entry = new RequestCacheEntry {
                        IsPrivateEntry = this._RequestCache.IsPrivateCache
                    };
                    this._Validator.FetchCacheEntry(entry);
                }
                if (this._Validator.CacheStream == null)
                {
                    this._Validator.CacheStream = Stream.Null;
                }
                this.ValidateFreshness(entry);
                this._ProtocolStatus = this.ValidateCache();
                switch (this._ProtocolStatus)
                {
                case CacheValidationStatus.DoNotUseCache:
                case CacheValidationStatus.DoNotTakeFromCache:
                    return;

                case CacheValidationStatus.Fail:
                    this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_fail", new object[] { "ValidateCache" }));
                    return;

                case CacheValidationStatus.RetryResponseFromCache:
                    goto Label_0000;

                case CacheValidationStatus.ReturnCachedResponse:
                    if ((this._Validator.CacheStream != null) && (this._Validator.CacheStream != Stream.Null))
                    {
                        break;
                    }
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_no_cache_entry", new object[] { "ValidateCache()" }));
                    }
                    this._ProtocolStatus    = CacheValidationStatus.Fail;
                    this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_no_stream", new object[] { this._Validator.CacheKey }));
                    return;

                case CacheValidationStatus.Continue:
                    this._ResponseStream = this._Validator.CacheStream;
                    return;

                default:
                    goto Label_02CB;
                }
                Stream cacheStream = this._Validator.CacheStream;
                this._RequestCache.UnlockEntry(this._Validator.CacheStream);
                if ((this._Validator.CacheStreamOffset != 0L) || (this._Validator.CacheStreamLength != this._Validator.CacheEntry.StreamSize))
                {
                    cacheStream = new RangeStream(cacheStream, this._Validator.CacheStreamOffset, this._Validator.CacheStreamLength);
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_returned_range_cache", new object[] { "ValidateCache()", this._Validator.CacheStreamOffset, this._Validator.CacheStreamLength }));
                    }
                }
                this._ResponseStream       = cacheStream;
                this._ResponseStreamLength = this._Validator.CacheStreamLength;
                return;

Label_02CB:
                this._ProtocolStatus    = CacheValidationStatus.Fail;
                this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_result", new object[] { "ValidateCache", this._Validator.ValidationStatus.ToString() }));
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_unexpected_status", new object[] { "ValidateCache()", this._Validator.ValidationStatus.ToString() }));
                }
            }
            catch (Exception exception)
            {
                this._ProtocolStatus    = CacheValidationStatus.Fail;
                this._ProtocolException = exception;
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_object_and_exception", new object[] { "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (exception is WebException) ? exception.Message : exception.ToString() }));
                }
            }
            finally
            {
                if (((this._ResponseStream == null) && (this._Validator.CacheStream != null)) && (this._Validator.CacheStream != Stream.Null))
                {
                    this._Validator.CacheStream.Close();
                    this._Validator.CacheStream = Stream.Null;
                }
            }
        }
Пример #36
0
        /// <summary>
        /// Happens at the incoming (executING)
        /// </summary>
        /// <param name="timedEtag"></param>
        /// <param name="cacheValidationStatus"></param>
        /// <param name="context">
        /// </param>
        /// <returns>
        /// True: applied and the call can exit (short-circuit)
        /// False: tried to apply but did not match hence the call should continue
        /// null: could not apply (timedEtag was null)
        /// </returns>
        protected bool?ApplyCacheValidation(TimedEntityTagHeaderValue timedEtag,
                                            CacheValidationStatus cacheValidationStatus,
                                            HttpContext context)
        {
            if (timedEtag == null)
            {
                return(null);
            }

            var headers = context.Request.GetTypedHeadersWithCaching();

            switch (cacheValidationStatus)
            {
            case CacheValidationStatus.GetIfModifiedSince:
                if (timedEtag.LastModified == null)
                {
                    return(false);
                }
                else
                {
                    if (timedEtag.LastModified > headers.IfModifiedSince.Value)
                    {
                        return(false);
                    }
                    else
                    {
                        context.Response.StatusCode = StatusCodes.Status304NotModified;
                        return(true);
                    }
                }

            case CacheValidationStatus.GetIfNoneMatch:
                if (timedEtag.ETag == null)
                {
                    return(false);
                }
                else
                {
                    if (headers.IfNoneMatch.Any(x => x.Tag == timedEtag.ETag.Tag))
                    {
                        context.Response.StatusCode = StatusCodes.Status304NotModified;
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }

            case CacheValidationStatus.PutPatchDeleteIfMatch:
                if (timedEtag.ETag == null)
                {
                    return(false);
                }
                else
                {
                    if (headers.IfMatch.Any(x => x.Tag == timedEtag.ETag.Tag))
                    {
                        return(false);
                    }
                    else
                    {
                        context.Response.StatusCode = StatusCodes.Status412PreconditionFailed;
                        return(true);
                    }
                }

            case CacheValidationStatus.PutPatchDeleteIfUnModifiedSince:
                if (timedEtag.LastModified == null)
                {
                    return(false);
                }
                else
                {
                    if (timedEtag.LastModified > headers.IfUnmodifiedSince.Value)
                    {
                        context.Response.StatusCode = StatusCodes.Status412PreconditionFailed;
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }

            default:
                return(null);
            }
        }
 internal CacheValidationStatus GetRevalidateStatus(WebResponse response, Stream responseStream)
 {
     if (response == null)
     {
         throw new ArgumentNullException("response");
     }
     if (this._ProtocolStatus == CacheValidationStatus.DoNotUseCache)
     {
         return CacheValidationStatus.DoNotUseCache;
     }
     if (this._ProtocolStatus == CacheValidationStatus.ReturnCachedResponse)
     {
         this._ProtocolStatus = CacheValidationStatus.DoNotUseCache;
         return this._ProtocolStatus;
     }
     try
     {
         if (Logging.On)
         {
             Logging.Enter(Logging.RequestCache, this, "GetRevalidateStatus", (this._Validator == null) ? null : this._Validator.Request);
         }
         this._Validator.FetchResponse(response);
         if ((this._ProtocolStatus != CacheValidationStatus.Continue) && (this._ProtocolStatus != CacheValidationStatus.RetryResponseFromServer))
         {
             if (Logging.On)
             {
                 Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_revalidation_not_needed", new object[] { "GetRevalidateStatus()" }));
             }
             return this._ProtocolStatus;
         }
         this.CheckRetrieveOnResponse(responseStream);
     }
     finally
     {
         if (Logging.On)
         {
             Logging.Exit(Logging.RequestCache, this, "GetRevalidateStatus", "result = " + this._ProtocolStatus.ToString());
         }
     }
     return this._ProtocolStatus;
 }
        //
        internal CacheValidationStatus  GetRetrieveStatus(Uri cacheUri, WebRequest request)
        {
            if (cacheUri == null)
            {
                throw new ArgumentNullException("cacheUri");
            }

            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            if (!_CanTakeNewRequest || _ProtocolStatus == CacheValidationStatus.RetryResponseFromServer)
            {
                return(CacheValidationStatus.Continue);
            }
            _CanTakeNewRequest = false;


            // Reset protocol state
            _ResponseStream       = null;
            _ResponseStreamLength = 0L;
            _ProtocolStatus       = CacheValidationStatus.Continue;
            _ProtocolException    = null;

            if (Logging.On)
            {
                Logging.Enter(Logging.RequestCache, this, "GetRetrieveStatus", request);
            }
            try {
                if (request.CachePolicy == null || request.CachePolicy.Level == RequestCacheLevel.BypassCache)
                {
                    _ProtocolStatus = CacheValidationStatus.DoNotUseCache;
                    return(_ProtocolStatus);
                }

                if (_RequestCache == null || _Validator == null)
                {
                    _ProtocolStatus = CacheValidationStatus.DoNotUseCache;
                    return(_ProtocolStatus);
                }

                _Validator.FetchRequest(cacheUri, request);

                switch (_ProtocolStatus = ValidateRequest())
                {
                case CacheValidationStatus.Continue:            // This is a green light for cache protocol
                    break;

                case CacheValidationStatus.DoNotTakeFromCache:  // no cache but response can be cached
                case CacheValidationStatus.DoNotUseCache:       // ignore cache entirely
                    break;

                case CacheValidationStatus.Fail:
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "ValidateRequest"));
                    break;

                default:
                    _ProtocolStatus    = CacheValidationStatus.Fail;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "ValidateRequest", _Validator.ValidationStatus.ToString()));
                    if (Logging.On)
                    {
                        Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "ValidateRequest()", _Validator.ValidationStatus.ToString()));
                    }
                    break;
                }

                if (_ProtocolStatus != CacheValidationStatus.Continue)
                {
                    return(_ProtocolStatus);
                }

                //
                // Proceed with validation
                //
                CheckRetrieveBeforeSubmit();
            }
            catch (Exception e) {
                _ProtocolException = e;
                _ProtocolStatus    = CacheValidationStatus.Fail;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
                {
                    throw;
                }

                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
                }
            }
            finally {
                if (Logging.On)
                {
                    Logging.Exit(Logging.RequestCache, this, "GetRetrieveStatus", "result = " + _ProtocolStatus.ToString());
                }
            }
            return(_ProtocolStatus);
        }
 protected internal override CacheValidationStatus RevalidateCache()
 {
     if (this.HttpProxyMode)
     {
         return(base.RevalidateCache());
     }
     if (this.Policy.Level >= RequestCacheLevel.Reload)
     {
         if (Logging.On)
         {
             Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_validator_invalid_for_policy", new object[] { this.Policy.ToString() }));
         }
         return(CacheValidationStatus.DoNotTakeFromCache);
     }
     if (base.CacheStream != Stream.Null)
     {
         CacheValidationStatus doNotTakeFromCache = CacheValidationStatus.DoNotTakeFromCache;
         FtpWebResponse        response           = base.Response as FtpWebResponse;
         if (response == null)
         {
             return(CacheValidationStatus.DoNotTakeFromCache);
         }
         if (response.StatusCode != FtpStatusCode.FileStatus)
         {
             return(CacheValidationStatus.DoNotTakeFromCache);
         }
         if (Logging.On)
         {
             Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_response_last_modified", new object[] { response.LastModified.ToUniversalTime().ToString("r", CultureInfo.InvariantCulture), response.ContentLength }));
         }
         if (Logging.On)
         {
             Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_cache_last_modified", new object[] { base.CacheEntry.LastModifiedUtc.ToString("r", CultureInfo.InvariantCulture), base.CacheEntry.StreamSize }));
         }
         if ((base.CacheStreamOffset != 0L) && base.CacheEntry.IsPartialEntry)
         {
             if (Logging.On)
             {
                 Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_partial_and_non_zero_content_offset", new object[] { base.CacheStreamOffset.ToString(CultureInfo.InvariantCulture) }));
             }
             doNotTakeFromCache = CacheValidationStatus.DoNotTakeFromCache;
         }
         if (!(response.LastModified.ToUniversalTime() == base.CacheEntry.LastModifiedUtc))
         {
             return(CacheValidationStatus.DoNotTakeFromCache);
         }
         if (base.CacheEntry.IsPartialEntry)
         {
             if (response.ContentLength > 0L)
             {
                 base.CacheStreamLength = response.ContentLength;
             }
             else
             {
                 base.CacheStreamLength = -1L;
             }
             return(CacheValidationStatus.CombineCachedAndServerResponse);
         }
         if (response.ContentLength == base.CacheEntry.StreamSize)
         {
             return(CacheValidationStatus.ReturnCachedResponse);
         }
     }
     return(CacheValidationStatus.DoNotTakeFromCache);
 }
        //
        // Returns UpdateResponseInformation if passed response stream has to be replaced (cache is updated in some way)
        // Returns Fail if request is to fail
        // Any other return value should be ignored
        //
        internal CacheValidationStatus GetUpdateStatus (WebResponse response, Stream responseStream)
        {
            if (response == null)
                throw new ArgumentNullException("response");

            if (_ProtocolStatus == CacheValidationStatus.DoNotUseCache)
                return CacheValidationStatus.DoNotUseCache;

            try {
                if(Logging.On) Logging.Enter(Logging.RequestCache, this, "GetUpdateStatus", null);

                if (_Validator.Response == null)
                    _Validator.FetchResponse(response);

                if (_ProtocolStatus == CacheValidationStatus.RemoveFromCache)
                {
                    EnsureCacheRemoval(_Validator.CacheKey);
                    return _ProtocolStatus;
                }

                if (_ProtocolStatus != CacheValidationStatus.DoNotTakeFromCache &&
                    _ProtocolStatus != CacheValidationStatus.ReturnCachedResponse &&
                    _ProtocolStatus != CacheValidationStatus.CombineCachedAndServerResponse)
                {
                    if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_not_updated_based_on_cache_protocol_status, "GetUpdateStatus()", _ProtocolStatus.ToString()));
                    return _ProtocolStatus;
                }

                CheckUpdateOnResponse(responseStream);
            }
            catch (Exception e) {
                _ProtocolException = e;
                _ProtocolStatus = CacheValidationStatus.Fail;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
                    throw;
                }
                if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
            }
            finally {
                if(Logging.On)Logging.Exit(Logging.RequestCache, this, "GetUpdateStatus", "result = " + _ProtocolStatus.ToString());
            }
            return _ProtocolStatus;
        }
        private void CheckRetrieveOnResponse(Stream responseStream)
        {
            bool flag = true;
            try
            {
                switch ((this._ProtocolStatus = this.ValidateResponse()))
                {
                    case CacheValidationStatus.DoNotUseCache:
                        goto Label_01CA;

                    case CacheValidationStatus.Fail:
                        this._ProtocolStatus = CacheValidationStatus.Fail;
                        this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_fail", new object[] { "ValidateResponse" }));
                        goto Label_01CA;

                    case CacheValidationStatus.RetryResponseFromServer:
                        flag = false;
                        goto Label_01CA;

                    case CacheValidationStatus.Continue:
                        flag = false;
                        goto Label_01CA;
                }
                this._ProtocolStatus = CacheValidationStatus.Fail;
                this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_result", new object[] { "ValidateResponse", this._Validator.ValidationStatus.ToString() }));
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_unexpected_status", new object[] { "ValidateResponse()", this._Validator.ValidationStatus.ToString() }));
                }
            }
            catch (Exception exception)
            {
                flag = true;
                this._ProtocolException = exception;
                this._ProtocolStatus = CacheValidationStatus.Fail;
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_object_and_exception", new object[] { "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (exception is WebException) ? exception.Message : exception.ToString() }));
                }
            }
            finally
            {
                if (flag && (this._ResponseStream != null))
                {
                    this._ResponseStream.Close();
                    this._ResponseStream = null;
                    this._Validator.CacheStream = Stream.Null;
                }
            }
        Label_01CA:
            if (this._ProtocolStatus != CacheValidationStatus.Continue)
            {
                return;
            }
            try
            {
                switch ((this._ProtocolStatus = this.RevalidateCache()))
                {
                    case CacheValidationStatus.DoNotUseCache:
                    case CacheValidationStatus.DoNotTakeFromCache:
                    case CacheValidationStatus.RemoveFromCache:
                        flag = true;
                        return;

                    case CacheValidationStatus.Fail:
                        flag = true;
                        this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_fail", new object[] { "RevalidateCache" }));
                        return;

                    case CacheValidationStatus.ReturnCachedResponse:
                        if ((this._Validator.CacheStream != null) && (this._Validator.CacheStream != Stream.Null))
                        {
                            break;
                        }
                        this._ProtocolStatus = CacheValidationStatus.Fail;
                        this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_no_stream", new object[] { this._Validator.CacheKey }));
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_null_cached_stream", new object[] { "RevalidateCache()" }));
                        }
                        return;

                    case CacheValidationStatus.CombineCachedAndServerResponse:
                        if ((this._Validator.CacheStream != null) && (this._Validator.CacheStream != Stream.Null))
                        {
                            goto Label_03FF;
                        }
                        this._ProtocolStatus = CacheValidationStatus.Fail;
                        this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_no_stream", new object[] { this._Validator.CacheKey }));
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_requested_combined_but_null_cached_stream", new object[] { "RevalidateCache()" }));
                        }
                        return;

                    default:
                        goto Label_046E;
                }
                Stream cacheStream = this._Validator.CacheStream;
                if ((this._Validator.CacheStreamOffset != 0L) || (this._Validator.CacheStreamLength != this._Validator.CacheEntry.StreamSize))
                {
                    cacheStream = new RangeStream(cacheStream, this._Validator.CacheStreamOffset, this._Validator.CacheStreamLength);
                    if (Logging.On)
                    {
                        Logging.PrintInfo(Logging.RequestCache, SR.GetString("net_log_cache_returned_range_cache", new object[] { "RevalidateCache()", this._Validator.CacheStreamOffset, this._Validator.CacheStreamLength }));
                    }
                }
                this._ResponseStream = cacheStream;
                this._ResponseStreamLength = this._Validator.CacheStreamLength;
                return;
            Label_03FF:
                if (responseStream != null)
                {
                    cacheStream = new CombinedReadStream(this._Validator.CacheStream, responseStream);
                }
                else
                {
                    cacheStream = this._Validator.CacheStream;
                }
                this._ResponseStream = cacheStream;
                this._ResponseStreamLength = this._Validator.CacheStreamLength;
                return;
            Label_046E:
                flag = true;
                this._ProtocolStatus = CacheValidationStatus.Fail;
                this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_result", new object[] { "RevalidateCache", this._Validator.ValidationStatus.ToString() }));
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_unexpected_status", new object[] { "RevalidateCache()", this._Validator.ValidationStatus.ToString() }));
                }
            }
            catch (Exception exception2)
            {
                flag = true;
                this._ProtocolException = exception2;
                this._ProtocolStatus = CacheValidationStatus.Fail;
                if (((exception2 is ThreadAbortException) || (exception2 is StackOverflowException)) || (exception2 is OutOfMemoryException))
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_object_and_exception", new object[] { "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (exception2 is WebException) ? exception2.Message : exception2.ToString() }));
                }
            }
            finally
            {
                if (flag && (this._ResponseStream != null))
                {
                    this._ResponseStream.Close();
                    this._ResponseStream = null;
                    this._Validator.CacheStream = Stream.Null;
                }
            }
        }
        //
        private void CheckRetrieveOnResponse(Stream responseStream) {

            GlobalLog.Assert(_ProtocolStatus == CacheValidationStatus.Continue || _ProtocolStatus == CacheValidationStatus.RetryResponseFromServer, "CheckRetrieveOnResponse()|Unexpected _ProtocolStatus = ", _ProtocolStatus);
            // if something goes wrong we release cache stream if any exists
            bool closeCacheStream = true;

            try {
                // This will inspect the live response on the correctness matter
                switch (_ProtocolStatus = ValidateResponse()) {

                case CacheValidationStatus.Continue:
                        closeCacheStream = false;
                        // The response looks good
                        break;

                case CacheValidationStatus.RetryResponseFromServer:
                        // The response is broken will need to retry or give up
                        closeCacheStream = false;
                        break;

                case CacheValidationStatus.Fail:
                        _ProtocolStatus = CacheValidationStatus.Fail;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "ValidateResponse"));
                        break;

                case CacheValidationStatus.DoNotUseCache:
                        break;

                default:
                    _ProtocolStatus = CacheValidationStatus.Fail;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "ValidateResponse", _Validator.ValidationStatus.ToString()));
                    if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "ValidateResponse()", _Validator.ValidationStatus.ToString()));
                    break;
                }

            }
            catch (Exception e) {
                closeCacheStream = true;
                _ProtocolException = e;
                _ProtocolStatus = CacheValidationStatus.Fail;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
                    throw;
                }
                if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
            }
            finally {
                // This is to release cache entry in case we are not interested in it
                if (closeCacheStream && _ResponseStream != null)
                {
                    _ResponseStream.Close();
                    _ResponseStream = null;
                    _Validator.CacheStream = Stream.Null;
                }
            }

            if (_ProtocolStatus != CacheValidationStatus.Continue) {
                return;
            }

            //
            // only CacheValidationStatus.Continue goes here with closeCacheStream == false
            //

            try {
                // This will tell us what to do next
                // Note this is a second time question to the caching protocol about a cached entry
                // Except that we now have live response to consider
                //
                // The validator can at any time replace the  cache stream and update cache Metadata (aka headers).
                //
                switch (_ProtocolStatus = RevalidateCache()) {

                case CacheValidationStatus.DoNotUseCache:
                case CacheValidationStatus.RemoveFromCache:
                case CacheValidationStatus.DoNotTakeFromCache:
                        closeCacheStream = true;
                        break;

                case CacheValidationStatus.ReturnCachedResponse:
                        if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null)
                        {
                            _ProtocolStatus = CacheValidationStatus.Fail;
                            _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_no_stream, _Validator.CacheKey));
                            if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_null_cached_stream, "RevalidateCache()"));
                            break;
                        }

                        Stream stream = _Validator.CacheStream;

                        if (_Validator.CacheStreamOffset != 0L || _Validator.CacheStreamLength != _Validator.CacheEntry.StreamSize)
                        {
                            stream =  new RangeStream(stream, _Validator.CacheStreamOffset, _Validator.CacheStreamLength);
                            if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_returned_range_cache, "RevalidateCache()", _Validator.CacheStreamOffset, _Validator.CacheStreamLength));
                        }
                        _ResponseStream = stream;
                        _ResponseStreamLength = _Validator.CacheStreamLength;
                        break;

                case CacheValidationStatus.CombineCachedAndServerResponse:

                        if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null)
                        {
                            _ProtocolStatus = CacheValidationStatus.Fail;
                            _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_no_stream, _Validator.CacheKey));
                            if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_requested_combined_but_null_cached_stream, "RevalidateCache()"));
                            break;
                        }
                        //
                        // FTP cannot give the tail of the combined stream at that point
                        // Consider: Revisit the design of the CacheProtocol class
                        if (responseStream != null)
                        {
                            stream = new CombinedReadStream(_Validator.CacheStream, responseStream);
                        }
                        else
                        {
                            // So Abort can close the cache stream
                            stream = _Validator.CacheStream;
                        }
                        _ResponseStream = stream;
                        _ResponseStreamLength = _Validator.CacheStreamLength;
                        break;


                case CacheValidationStatus.Fail:
                        closeCacheStream = true;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "RevalidateCache"));
                        break;

                default:
                        closeCacheStream = true;
                        _ProtocolStatus = CacheValidationStatus.Fail;
                        _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "RevalidateCache", _Validator.ValidationStatus.ToString()));
                        if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "RevalidateCache()", _Validator.ValidationStatus.ToString()));
                        break;
                }
            }
            catch (Exception e) {
                closeCacheStream = true;
                _ProtocolException = e;
                _ProtocolStatus = CacheValidationStatus.Fail;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
                    throw;
                }
                if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
            }
            finally {
                // This is to release cache entry in case we are not interested in it
                if (closeCacheStream && _ResponseStream != null)
                {
                    _ResponseStream.Close();
                    _ResponseStream = null;
                    _Validator.CacheStream = Stream.Null;
                }
            }
        }
        private void CheckUpdateOnResponse(Stream responseStream)
        {
            if (this._Validator.CacheEntry == null)
            {
                RequestCacheEntry fetchEntry = new RequestCacheEntry {
                    IsPrivateEntry = this._RequestCache.IsPrivateCache
                };
                this._Validator.FetchCacheEntry(fetchEntry);
            }
            string cacheKey = this._Validator.CacheKey;
            bool flag = true;
            try
            {
                Stream stream;
                switch ((this._ProtocolStatus = this.UpdateCache()))
                {
                    case CacheValidationStatus.DoNotUseCache:
                    case CacheValidationStatus.DoNotUpdateCache:
                        return;

                    case CacheValidationStatus.Fail:
                        this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_fail", new object[] { "UpdateCache" }));
                        return;

                    case CacheValidationStatus.CacheResponse:
                        if (!this._Validator.StrictCacheErrors)
                        {
                            break;
                        }
                        stream = this._RequestCache.Store(this._Validator.CacheKey, this._Validator.CacheEntry.StreamSize, this._Validator.CacheEntry.ExpiresUtc, this._Validator.CacheEntry.LastModifiedUtc, this._Validator.CacheEntry.MaxStale, this._Validator.CacheEntry.EntryMetadata, this._Validator.CacheEntry.SystemMetadata);
                        goto Label_022C;

                    case CacheValidationStatus.UpdateResponseInformation:
                        this._ResponseStream = new MetadataUpdateStream(responseStream, this._RequestCache, this._Validator.CacheKey, this._Validator.CacheEntry.ExpiresUtc, this._Validator.CacheEntry.LastModifiedUtc, this._Validator.CacheEntry.LastSynchronizedUtc, this._Validator.CacheEntry.MaxStale, this._Validator.CacheEntry.EntryMetadata, this._Validator.CacheEntry.SystemMetadata, this._Validator.StrictCacheErrors);
                        flag = false;
                        this._ProtocolStatus = CacheValidationStatus.UpdateResponseInformation;
                        return;

                    case CacheValidationStatus.RemoveFromCache:
                        this.EnsureCacheRemoval(cacheKey);
                        flag = false;
                        return;

                    default:
                        goto Label_0298;
                }
                this._RequestCache.TryStore(this._Validator.CacheKey, this._Validator.CacheEntry.StreamSize, this._Validator.CacheEntry.ExpiresUtc, this._Validator.CacheEntry.LastModifiedUtc, this._Validator.CacheEntry.MaxStale, this._Validator.CacheEntry.EntryMetadata, this._Validator.CacheEntry.SystemMetadata, out stream);
            Label_022C:
                if (stream == null)
                {
                    this._ProtocolStatus = CacheValidationStatus.DoNotUpdateCache;
                }
                else
                {
                    this._ResponseStream = new ForwardingReadStream(responseStream, stream, this._Validator.CacheStreamOffset, this._Validator.StrictCacheErrors);
                    this._ProtocolStatus = CacheValidationStatus.UpdateResponseInformation;
                }
                return;
            Label_0298:
                this._ProtocolStatus = CacheValidationStatus.Fail;
                this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_result", new object[] { "UpdateCache", this._Validator.ValidationStatus.ToString() }));
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_unexpected_status", new object[] { "UpdateCache()", this._Validator.ValidationStatus.ToString() }));
                }
            }
            finally
            {
                if (flag)
                {
                    this._RequestCache.UnlockEntry(this._Validator.CacheStream);
                }
            }
        }
        //
        internal CacheValidationStatus  GetRetrieveStatus (Uri cacheUri, WebRequest request)
        {

            if (cacheUri == null)
                throw new ArgumentNullException("cacheUri");

            if (request == null)
               throw new ArgumentNullException("request");

            if (!_CanTakeNewRequest || _ProtocolStatus == CacheValidationStatus.RetryResponseFromServer)
                return CacheValidationStatus.Continue;
            _CanTakeNewRequest = false;


            // Reset protocol state
            _ResponseStream       = null;
            _ResponseStreamLength = 0L;
            _ProtocolStatus       = CacheValidationStatus.Continue;
            _ProtocolException    = null;

            if(Logging.On) Logging.Enter(Logging.RequestCache, this, "GetRetrieveStatus", request);
            try {
                if (request.CachePolicy == null || request.CachePolicy.Level == RequestCacheLevel.BypassCache)
                {
                    _ProtocolStatus = CacheValidationStatus.DoNotUseCache;
                    return _ProtocolStatus;
                }

                if (_RequestCache == null || _Validator == null)
                {
                    _ProtocolStatus = CacheValidationStatus.DoNotUseCache;
                    return _ProtocolStatus;
                }

                _Validator.FetchRequest(cacheUri, request);

                switch(_ProtocolStatus = ValidateRequest())
                {
                case CacheValidationStatus.Continue:            // This is a green light for cache protocol
                    break;

                case CacheValidationStatus.DoNotTakeFromCache:  // no cache but response can be cached
                case CacheValidationStatus.DoNotUseCache:       // ignore cache entirely
                    break;

                case CacheValidationStatus.Fail:
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_fail, "ValidateRequest"));
                    break;

                default:
                    _ProtocolStatus = CacheValidationStatus.Fail;
                    _ProtocolException = new InvalidOperationException(SR.GetString(SR.net_cache_validator_result, "ValidateRequest", _Validator.ValidationStatus.ToString()));
                    if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_unexpected_status, "ValidateRequest()", _Validator.ValidationStatus.ToString()));
                    break;
                }

                if (_ProtocolStatus != CacheValidationStatus.Continue)
                    return _ProtocolStatus;

                //
                // Proceed with validation
                //
                CheckRetrieveBeforeSubmit();
            }
            catch (Exception e) {
                _ProtocolException = e;
                _ProtocolStatus = CacheValidationStatus.Fail;
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
                    throw;

                if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_object_and_exception, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (e is WebException? e.Message: e.ToString())));
            }
            finally {
                if(Logging.On) Logging.Exit(Logging.RequestCache, this, "GetRetrieveStatus", "result = " + _ProtocolStatus.ToString());
            }
            return _ProtocolStatus;
        }
        internal CacheValidationStatus GetRetrieveStatus(Uri cacheUri, WebRequest request)
        {
            if (cacheUri == null)
            {
                throw new ArgumentNullException("cacheUri");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (!this._CanTakeNewRequest || (this._ProtocolStatus == CacheValidationStatus.RetryResponseFromServer))
            {
                return CacheValidationStatus.Continue;
            }
            this._CanTakeNewRequest = false;
            this._ResponseStream = null;
            this._ResponseStreamLength = 0L;
            this._ProtocolStatus = CacheValidationStatus.Continue;
            this._ProtocolException = null;
            if (Logging.On)
            {
                Logging.Enter(Logging.RequestCache, this, "GetRetrieveStatus", request);
            }
            try
            {
                if ((request.CachePolicy == null) || (request.CachePolicy.Level == RequestCacheLevel.BypassCache))
                {
                    this._ProtocolStatus = CacheValidationStatus.DoNotUseCache;
                    return this._ProtocolStatus;
                }
                if ((this._RequestCache == null) || (this._Validator == null))
                {
                    this._ProtocolStatus = CacheValidationStatus.DoNotUseCache;
                    return this._ProtocolStatus;
                }
                this._Validator.FetchRequest(cacheUri, request);
                switch ((this._ProtocolStatus = this.ValidateRequest()))
                {
                    case CacheValidationStatus.DoNotUseCache:
                    case CacheValidationStatus.DoNotTakeFromCache:
                    case CacheValidationStatus.Continue:
                        break;

                    case CacheValidationStatus.Fail:
                        this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_fail", new object[] { "ValidateRequest" }));
                        break;

                    default:
                        this._ProtocolStatus = CacheValidationStatus.Fail;
                        this._ProtocolException = new InvalidOperationException(SR.GetString("net_cache_validator_result", new object[] { "ValidateRequest", this._Validator.ValidationStatus.ToString() }));
                        if (Logging.On)
                        {
                            Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_unexpected_status", new object[] { "ValidateRequest()", this._Validator.ValidationStatus.ToString() }));
                        }
                        break;
                }
                if (this._ProtocolStatus != CacheValidationStatus.Continue)
                {
                    return this._ProtocolStatus;
                }
                this.CheckRetrieveBeforeSubmit();
            }
            catch (Exception exception)
            {
                this._ProtocolException = exception;
                this._ProtocolStatus = CacheValidationStatus.Fail;
                if (((exception is ThreadAbortException) || (exception is StackOverflowException)) || (exception is OutOfMemoryException))
                {
                    throw;
                }
                if (Logging.On)
                {
                    Logging.PrintError(Logging.RequestCache, SR.GetString("net_log_cache_object_and_exception", new object[] { "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), (exception is WebException) ? exception.Message : exception.ToString() }));
                }
            }
            finally
            {
                if (Logging.On)
                {
                    Logging.Exit(Logging.RequestCache, this, "GetRetrieveStatus", "result = " + this._ProtocolStatus.ToString());
                }
            }
            return this._ProtocolStatus;
        }