Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / Cache / _RequestCacheProtocol.cs / 1305376 / _RequestCacheProtocol.cs
/*++ Copyright (c) Microsoft Corporation Module Name: _RequestCacheProtocol.cs Abstract: The class is a cache protocol engine. An application protocol such as HttpWebRequest or FtpWebRequest gets all cache-related answers by talking to this class Sometime in the future it will become public. Author: Alexei Vopilov 21-Dec-2002 Revision History: Aug 25 2003 - moved into separate file and revised as per Whidbey-M3 spec. --*/ namespace System.Net.Cache { using System; using System.Diagnostics; using System.Text; using System.IO; using System.Collections.Specialized; using System.Threading; using System.Globalization; // // // internal class RequestCacheProtocol { private CacheValidationStatus _ProtocolStatus; private Exception _ProtocolException; private Stream _ResponseStream; private long _ResponseStreamLength; private RequestCacheValidator _Validator; private RequestCache _RequestCache; private bool _IsCacheFresh; private bool _CanTakeNewRequest; // private string[] _ResponseMetadata; // private string _CacheRetrieveKey; // private string _CacheStoreKey; // // Public properties // internal CacheValidationStatus ProtocolStatus {get {return _ProtocolStatus;}} internal Exception ProtocolException {get {return _ProtocolException;}} internal Stream ResponseStream {get {return _ResponseStream;}} internal long ResponseStreamLength {get {return _ResponseStreamLength;}} internal RequestCacheValidator Validator {get {return _Validator;}} internal bool IsCacheFresh {get {return _Validator != null && _Validator.CacheFreshnessStatus == CacheFreshnessStatus.Fresh;}} // internal string[] ResponseMetadata {get {return _ResponseMetadata;}} // internal string CacheRetrieveKey {get {return _CacheRetrieveKey;}} // internal string CacheStoreKey {get {return _CacheStoreKey;}} // // Public methods // internal RequestCacheProtocol(RequestCache cache, RequestCacheValidator defaultValidator) { _RequestCache = cache; _Validator = defaultValidator; _CanTakeNewRequest = true; } // 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; } // // 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; } // // 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; } // // This must be the last call before starting a new request on this protocol instance // internal void Reset() { _CanTakeNewRequest = true; } // internal void Abort() { // if _CanTakeNewRequest==true we should not be holding any cache stream // Also we check on Abort() reentrancy this way. if (_CanTakeNewRequest) return; // in case of abnormal termination this will release cache entry sooner than does it's finalizer Stream stream = _ResponseStream; if (stream != null) { try { if(Logging.On) Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_closing_cache_stream, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), "Abort()", stream.GetType().FullName, _Validator.CacheKey)); ICloseEx closeEx = stream as ICloseEx; if (closeEx != null) closeEx.CloseEx(CloseExState.Abort | CloseExState.Silent); else stream.Close(); } catch(Exception e) { if (NclUtilities.IsFatal(e)) throw; if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_exception_ignored, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), "stream.Close()", e.ToString())); } } Reset(); } // // 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; } } } // 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; } } } // // 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 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; } // // // private void ValidateFreshness(RequestCacheEntry fetchEntry) { _Validator.FetchCacheEntry(fetchEntry); if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null) { if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_entry_not_found_freshness_undefined, "ValidateFreshness()")); _Validator.SetFreshnessStatus(CacheFreshnessStatus.Undefined); return; } if(Logging.On) { if (Logging.IsVerbose(Logging.RequestCache)) { Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_dumping_cache_context)); if (fetchEntry == null) { Logging.PrintInfo(Logging.RequestCache, ""); } else { string[] context = fetchEntry.ToString(Logging.IsVerbose(Logging.RequestCache)).Split(RequestCache.LineSplits); for (int i = 0; i< context.Length; ++i) { if (context[i].Length != 0) { Logging.PrintInfo(Logging.RequestCache, context[i]); } } } } } CacheFreshnessStatus result = _Validator.ValidateFreshness(); _Validator.SetFreshnessStatus(result); _IsCacheFresh = result == CacheFreshnessStatus.Fresh; if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_result, "ValidateFreshness()", result.ToString())); } // // // private CacheValidationStatus ValidateCache() { CacheValidationStatus result = _Validator.ValidateCache(); _Validator.SetValidationStatus(result); if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_result, "ValidateCache()", result.ToString())); return result; } // private CacheValidationStatus RevalidateCache() { CacheValidationStatus result = _Validator.RevalidateCache(); _Validator.SetValidationStatus(result); if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_result, "RevalidateCache()", result.ToString())); return result; } // 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 UpdateCache() { CacheValidationStatus result = _Validator.UpdateCache(); _Validator.SetValidationStatus(result); return result; } // private void EnsureCacheRemoval(string retrieveKey) { // The entry can now be replaced as we are not going for cache entry metadata-only update _RequestCache.UnlockEntry(_Validator.CacheStream); if (_Validator.StrictCacheErrors) {_RequestCache.Remove(retrieveKey);} else {_RequestCache.TryRemove(retrieveKey);} // We may need to remove yet another reference from the cache if (retrieveKey != _Validator.CacheKey) { if (_Validator.StrictCacheErrors) {_RequestCache.Remove(_Validator.CacheKey);} else {_RequestCache.TryRemove(_Validator.CacheKey);} } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. /*++ Copyright (c) Microsoft Corporation Module Name: _RequestCacheProtocol.cs Abstract: The class is a cache protocol engine. An application protocol such as HttpWebRequest or FtpWebRequest gets all cache-related answers by talking to this class Sometime in the future it will become public. Author: Alexei Vopilov 21-Dec-2002 Revision History: Aug 25 2003 - moved into separate file and revised as per Whidbey-M3 spec. --*/ namespace System.Net.Cache { using System; using System.Diagnostics; using System.Text; using System.IO; using System.Collections.Specialized; using System.Threading; using System.Globalization; // // // internal class RequestCacheProtocol { private CacheValidationStatus _ProtocolStatus; private Exception _ProtocolException; private Stream _ResponseStream; private long _ResponseStreamLength; private RequestCacheValidator _Validator; private RequestCache _RequestCache; private bool _IsCacheFresh; private bool _CanTakeNewRequest; // private string[] _ResponseMetadata; // private string _CacheRetrieveKey; // private string _CacheStoreKey; // // Public properties // internal CacheValidationStatus ProtocolStatus {get {return _ProtocolStatus;}} internal Exception ProtocolException {get {return _ProtocolException;}} internal Stream ResponseStream {get {return _ResponseStream;}} internal long ResponseStreamLength {get {return _ResponseStreamLength;}} internal RequestCacheValidator Validator {get {return _Validator;}} internal bool IsCacheFresh {get {return _Validator != null && _Validator.CacheFreshnessStatus == CacheFreshnessStatus.Fresh;}} // internal string[] ResponseMetadata {get {return _ResponseMetadata;}} // internal string CacheRetrieveKey {get {return _CacheRetrieveKey;}} // internal string CacheStoreKey {get {return _CacheStoreKey;}} // // Public methods // internal RequestCacheProtocol(RequestCache cache, RequestCacheValidator defaultValidator) { _RequestCache = cache; _Validator = defaultValidator; _CanTakeNewRequest = true; } // 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; } // // 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; } // // 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; } // // This must be the last call before starting a new request on this protocol instance // internal void Reset() { _CanTakeNewRequest = true; } // internal void Abort() { // if _CanTakeNewRequest==true we should not be holding any cache stream // Also we check on Abort() reentrancy this way. if (_CanTakeNewRequest) return; // in case of abnormal termination this will release cache entry sooner than does it's finalizer Stream stream = _ResponseStream; if (stream != null) { try { if(Logging.On) Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_closing_cache_stream, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), "Abort()", stream.GetType().FullName, _Validator.CacheKey)); ICloseEx closeEx = stream as ICloseEx; if (closeEx != null) closeEx.CloseEx(CloseExState.Abort | CloseExState.Silent); else stream.Close(); } catch(Exception e) { if (NclUtilities.IsFatal(e)) throw; if(Logging.On) Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_exception_ignored, "CacheProtocol#" + this.GetHashCode().ToString(NumberFormatInfo.InvariantInfo), "stream.Close()", e.ToString())); } } Reset(); } // // 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; } } } // 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; } } } // // 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 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; } // // // private void ValidateFreshness(RequestCacheEntry fetchEntry) { _Validator.FetchCacheEntry(fetchEntry); if (_Validator.CacheStream == null || _Validator.CacheStream == Stream.Null) { if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_entry_not_found_freshness_undefined, "ValidateFreshness()")); _Validator.SetFreshnessStatus(CacheFreshnessStatus.Undefined); return; } if(Logging.On) { if (Logging.IsVerbose(Logging.RequestCache)) { Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_dumping_cache_context)); if (fetchEntry == null) { Logging.PrintInfo(Logging.RequestCache, " "); } else { string[] context = fetchEntry.ToString(Logging.IsVerbose(Logging.RequestCache)).Split(RequestCache.LineSplits); for (int i = 0; i< context.Length; ++i) { if (context[i].Length != 0) { Logging.PrintInfo(Logging.RequestCache, context[i]); } } } } } CacheFreshnessStatus result = _Validator.ValidateFreshness(); _Validator.SetFreshnessStatus(result); _IsCacheFresh = result == CacheFreshnessStatus.Fresh; if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_result, "ValidateFreshness()", result.ToString())); } // // // private CacheValidationStatus ValidateCache() { CacheValidationStatus result = _Validator.ValidateCache(); _Validator.SetValidationStatus(result); if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_result, "ValidateCache()", result.ToString())); return result; } // private CacheValidationStatus RevalidateCache() { CacheValidationStatus result = _Validator.RevalidateCache(); _Validator.SetValidationStatus(result); if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_result, "RevalidateCache()", result.ToString())); return result; } // 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 UpdateCache() { CacheValidationStatus result = _Validator.UpdateCache(); _Validator.SetValidationStatus(result); return result; } // private void EnsureCacheRemoval(string retrieveKey) { // The entry can now be replaced as we are not going for cache entry metadata-only update _RequestCache.UnlockEntry(_Validator.CacheStream); if (_Validator.StrictCacheErrors) {_RequestCache.Remove(retrieveKey);} else {_RequestCache.TryRemove(retrieveKey);} // We may need to remove yet another reference from the cache if (retrieveKey != _Validator.CacheKey) { if (_Validator.StrictCacheErrors) {_RequestCache.Remove(_Validator.CacheKey);} else {_RequestCache.TryRemove(_Validator.CacheKey);} } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WebColorConverter.cs
- XmlQueryType.cs
- UrlPath.cs
- AttachedPropertyBrowsableAttribute.cs
- ValueConversionAttribute.cs
- DrawToolTipEventArgs.cs
- DataStreams.cs
- ResXResourceSet.cs
- ImportCatalogPart.cs
- InvalidDataContractException.cs
- RSAOAEPKeyExchangeFormatter.cs
- KeysConverter.cs
- SQLMoneyStorage.cs
- OleDbConnectionFactory.cs
- WebPartTransformerAttribute.cs
- XmlParserContext.cs
- IteratorFilter.cs
- datacache.cs
- InfoCard.cs
- SoapServerProtocol.cs
- ZipFileInfo.cs
- DbMetaDataFactory.cs
- EntityCommandDefinition.cs
- LogWriteRestartAreaAsyncResult.cs
- BitmapCacheBrush.cs
- BitVector32.cs
- DatatypeImplementation.cs
- SafeWaitHandle.cs
- InstanceKeyCollisionException.cs
- ObservableCollectionDefaultValueFactory.cs
- Control.cs
- RangeBase.cs
- StateDesigner.LayoutSelectionGlyph.cs
- EUCJPEncoding.cs
- WrappingXamlSchemaContext.cs
- PopupRootAutomationPeer.cs
- Column.cs
- StringUtil.cs
- _NestedMultipleAsyncResult.cs
- DataRelation.cs
- DbConnectionClosed.cs
- AccessText.cs
- DataGridHelper.cs
- ExpressionEditorAttribute.cs
- TrustManager.cs
- SessionStateSection.cs
- HtmlElementCollection.cs
- PageStatePersister.cs
- NamedObject.cs
- XmlCDATASection.cs
- LocationFactory.cs
- DataGridViewHeaderCell.cs
- FileChangesMonitor.cs
- DataControlLinkButton.cs
- GeometryValueSerializer.cs
- safesecurityhelperavalon.cs
- Accessors.cs
- DataBoundControlDesigner.cs
- MouseButtonEventArgs.cs
- HtmlAnchor.cs
- SHA384Managed.cs
- ListBox.cs
- ConstructorBuilder.cs
- InputScopeConverter.cs
- ExeContext.cs
- X509ClientCertificateAuthenticationElement.cs
- PrintPageEvent.cs
- CollectionExtensions.cs
- DocumentViewer.cs
- EventLogInformation.cs
- ConfigurationManagerInternalFactory.cs
- PointCollectionValueSerializer.cs
- InputMethodStateTypeInfo.cs
- TagMapCollection.cs
- CompressStream.cs
- TreeView.cs
- OdbcConnectionHandle.cs
- RC2.cs
- XmlSerializer.cs
- CultureInfo.cs
- CodeExpressionRuleDeclaration.cs
- StorageModelBuildProvider.cs
- ImageListUtils.cs
- DictionaryMarkupSerializer.cs
- XPathException.cs
- WebPartMinimizeVerb.cs
- DateTime.cs
- RootBrowserWindow.cs
- XhtmlTextWriter.cs
- SplineKeyFrames.cs
- FilterQuery.cs
- TextSegment.cs
- WebPartActionVerb.cs
- CellPartitioner.cs
- TreeNodeBinding.cs
- ConstrainedDataObject.cs
- SecUtil.cs
- WebPartPersonalization.cs
- NonBatchDirectoryCompiler.cs
- bidPrivateBase.cs