IERequestCache.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Net / System / Net / Cache / IERequestCache.cs / 1 / IERequestCache.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace Microsoft.Win32 { 
    using System; 
    using System.Net;
    using System.Net.Cache; 
    using System.Globalization;
    using System.IO;
    using System.Threading;
    using System.Collections.Specialized; 
    using System.Security.Permissions;
    using System.Security.Principal; 
    using System.ComponentModel; 
    using System.Text;
    using System.Runtime.Versioning; 

    // The class implements a RequestCache class contract on top of WinInet provider
    // Author: Alexei Vopilov    21-Dec-2002
    // 
    // Revision History:
    // 
    // Jan 25 2004  - Changed the visibility of the class from public to internal. 

    internal class WinInetCache: RequestCache { 
        private  static int _MaximumResponseHeadersLength;
        private bool async;
        internal const string c_SPARSE_ENTRY_HACK = "~SPARSE_ENTRY:";
 
        private  readonly static DateTime   s_MinDateTimeUtcForFileTimeUtc = DateTime.FromFileTimeUtc(0L);
        internal readonly static TimeSpan   s_MaxTimeSpanForInt32 = TimeSpan.FromSeconds((double)int.MaxValue); 
 
//        private  static readonly RequestCachePermission s_ReadPermission      = new RequestCachePermission(RequestCacheActions.CacheRead);
//        private  static readonly RequestCachePermission s_ReadWritePermission = new RequestCachePermission(RequestCacheActions.CacheReadWrite); 

        ///  A public constructor that demands CacheReadWrite flag for RequestCachePermission  
        internal WinInetCache(bool isPrivateCache, bool canWrite, bool async): base (isPrivateCache, canWrite)
        { 
            /***********
            if (canWrite) { 
                s_ReadWritePermission.Demand(); 
            }
            else 
            {
                s_ReadPermission.Demand();
            }
            ***********/ 

            // Per VsWhidbey#88276 it was decided to not enforce any cache metadata limits for WinInet cache provider. 
            _MaximumResponseHeadersLength = Int32.MaxValue; 
            this.async = async;
 
            /********
            if (_MaximumResponseHeadersLength == 0) {
                NetConfiguration config = (NetConfiguration)System.Configuration.ConfigurationManager.GetSection("system.net/settings");
                if (config != null) { 
                    if (config.maximumResponseHeadersLength < 0 && config.maximumResponseHeadersLength != -1) {
                        throw new ArgumentOutOfRangeException(SR.GetString(SR.net_toosmall)); 
                    } 
                    _MaximumResponseHeadersLength = config.maximumResponseHeadersLength * 1024;
                } 
                else {
                    _MaximumResponseHeadersLength = 64 * 1024;
                }
            } 
            ********/
        } 
 
        /// 
        ///  
        /// Gets the data stream and the metadata associated with a IE cache entry.
        /// Returns Stream.Null if there is no entry found.
        /// 
        ///  
        internal override Stream Retrieve(string key, out RequestCacheEntry cacheEntry)
        { 
            return Lookup(key, out cacheEntry, true); 
        }
        // 
        internal override bool TryRetrieve(string key, out RequestCacheEntry cacheEntry, out Stream  readStream)
        {
            readStream = Lookup(key, out cacheEntry, false);
            if (readStream == null) 
            {
                return false; 
            } 
            return true;
        } 
        // Returns a write stream associated with the IE cache string Key.
        // Passed parameters allow cache to update an entry metadata accordingly.
        //   The commit operation will happen upon the stream closure. 
        internal override Stream Store(string key, long contentLength, DateTime expiresUtc, DateTime lastModifiedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata) 
        {
            return GetWriteStream(key, contentLength, expiresUtc, lastModifiedUtc, maxStale, entryMetadata, systemMetadata, true); 
        } 
        // Does not throw on an error
        internal override bool TryStore(string key, long contentLength, DateTime expiresUtc, DateTime lastModifiedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata, out Stream writeStream) 
        {
            writeStream = GetWriteStream(key, contentLength, expiresUtc, lastModifiedUtc, maxStale, entryMetadata, systemMetadata, false);
            if (writeStream == null)
            { 
                return false;
            } 
            return true; 
        }
        ///  
        /// 
        /// Removes an item from the IE cache. Throws Win32Excpetion if failed
        /// 
        ///  
        internal override void Remove(string key) {
 
            if (key == null) { 
                throw new ArgumentNullException("key");
            } 

            if (!CanWrite)
            {
                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_operation_failed_with_error, "WinInetCache.Remove()", SR.GetString(SR.net_cache_access_denied, "Write"))); 
                return ;
            } 
 
            _WinInetCache.Entry entry = new _WinInetCache.Entry(key, _MaximumResponseHeadersLength);
 
            if (_WinInetCache.Remove(entry) != _WinInetCache.Status.Success && entry.Error != _WinInetCache.Status.FileNotFound) {
                Win32Exception win32Exception = new Win32Exception((int)entry.Error);
                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_cannot_remove, "WinInetCache.Remove()", key, win32Exception.Message));
                throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception); 
            }
 
            if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_key_status, "WinInetCache.Remove(), ", key, entry.Error.ToString())); 
        }
        // 
        //  Tries to remove an item from the cache, possible by applying unsafe entry unlocking.
        //  Returns true if successful, false otherwise
        internal override bool TryRemove(string key)
        { 
            return TryRemove(key, false);
 
        } 
        //
        // Purges Wininet Cache Entry by Unlocking it's file until zero count (if forceRemove is set). 
        //
        internal bool TryRemove(string key, bool forceRemove) {

            if (key == null) { 
                throw new ArgumentNullException("key");
            } 
 
            if (!CanWrite)
            { 
                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_operation_failed_with_error, "WinInetCache.TryRemove()", SR.GetString(SR.net_cache_access_denied, "Write")));
                return false;
            }
 
            _WinInetCache.Entry entry = new _WinInetCache.Entry(key, _MaximumResponseHeadersLength);
 
            if (_WinInetCache.Remove(entry) == _WinInetCache.Status.Success || entry.Error == _WinInetCache.Status.FileNotFound) { 
                if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_key_status, "WinInetCache.TryRemove()", key, entry.Error.ToString()));
                return true; 
            }
            else if (!forceRemove) {
                if(Logging.On)Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_key_remove_failed_status, "WinInetCache.TryRemove()", key, entry.Error.ToString()));
                return false; 
            }
 
            _WinInetCache.Status status = _WinInetCache.LookupInfo(entry); 
            if (status == _WinInetCache.Status.Success) {
                while (entry.Info.UseCount != 0) { 
                    if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_key_status, "WinInetCache.TryRemove()", key, entry.Error.ToString()));
                    if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_usecount_file, "WinInetCache.TryRemove()", entry.Info.UseCount, entry.Filename));
                    if (!UnsafeNclNativeMethods.UnsafeWinInetCache.UnlockUrlCacheEntryFileW(key, 0)) {
                        break; 
                    }
                    status = _WinInetCache.LookupInfo(entry); 
                } 
            }
            _WinInetCache.Remove(entry); 
            if (entry.Error != _WinInetCache.Status.Success && _WinInetCache.LookupInfo(entry) == _WinInetCache.Status.FileNotFound) {
                entry.Error = _WinInetCache.Status.Success;
            }
            if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_key_status, "WinInetCache.TryRemove()", key, entry.Error.ToString())); 
            return entry.Error == _WinInetCache.Status.Success;
        } 
        ///  
        /// 
        /// Updates only the metadata associated with IE cached entry. 
        /// 
        /// 
        internal override void Update(string key, DateTime expiresUtc, DateTime lastModifiedUtc, DateTime lastSynchronizedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata)
        { 
            UpdateInfo(key, expiresUtc, lastModifiedUtc, lastSynchronizedUtc, maxStale, entryMetadata, systemMetadata, true);
 
        } 
        // Does not throw on an error
        internal override bool TryUpdate(string key, DateTime expiresUtc, DateTime lastModifiedUtc, DateTime lastSynchronizedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata) 
        {
            return UpdateInfo(key, expiresUtc, lastModifiedUtc, lastSynchronizedUtc, maxStale, entryMetadata, systemMetadata, false);
        }
        // 
        // Once the entry is unlocked it must not be updated
        // There is a design flaw in current RequestCache contract, it should allow detection of already replaced entry when updating one. 
        // 
        internal override void UnlockEntry(Stream stream)
        { 
            ReadStream readStream = stream as ReadStream;

            if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_stream, "WinInetCache.UnlockEntry",  (stream == null ? "" : stream.GetType().FullName)));
 
            // could be wrapped by some other stream, that's ok because the entry is unlocked on stream.Close anyway
            if (readStream == null) 
                return; 
            readStream.UnlockEntry();
        } 
        //
        //
        //
        private Stream Lookup(string key, out RequestCacheEntry cacheEntry, bool isThrow) 
        {
            if(Logging.On) Logging.Enter(Logging.RequestCache, "WinInetCache.Retrieve", "key = " + key); 
 
            if (key == null) {
                throw new ArgumentNullException("key"); 
            }

            Stream result = Stream.Null;
            SafeUnlockUrlCacheEntryFile handle = null; 
            _WinInetCache.Entry entry = new _WinInetCache.Entry(key, _MaximumResponseHeadersLength);
            try { 
                handle = _WinInetCache.LookupFile(entry); 

                if (entry.Error == _WinInetCache.Status.Success) { 
                    if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_filename, "WinInetCache.Retrieve()", entry.Filename, entry.Error));

                    cacheEntry = new RequestCacheEntry(entry, IsPrivateCache);
 
                    if (entry.MetaInfo != null && entry.MetaInfo.Length != 0)
                    { 
                        // convert metadata to upto two string collections 
                        unsafe
                        { 
                            int start = 0;
                            int length = entry.MetaInfo.Length;
                            StringCollection sc = new StringCollection();
                            fixed (char * ch = entry.MetaInfo) 
                            {
                                int i; 
                                for (i = 0; i < length; ++i) 
                                {
                                    // WinInet specific block!! 
                                    // The point here is that wininet scans for ~U: throughly with no regard to \r\n so we mimic the same behavior
                                    if (i == start && i+2 < length)
                                    {
                                        if (ch[i] == '~' && (ch[i+1] == 'U' || ch[i+1] == 'u') && ch[i+2] == ':') 
                                        {
                                            //Security: don't report what the username is 
                                            while(i < length && ch[++i] != '\n') {;} 
                                            start = i+1;
                                            continue; 
                                        }

                                    }
 
                                    // note a metadata entry must terminate with \r\n
 
                                    if ((i+1 == length) || (ch[i] == '\n')) 
                                    {
                                        string value = entry.MetaInfo.Substring(start, (ch[i-1] == '\r'? (i-1):(i+1)) - start); 

                                        if (value.Length == 0 && cacheEntry.EntryMetadata == null)
                                        {
                                            // done with headers, prepare for system metadata 
                                            cacheEntry.EntryMetadata = sc;
                                            sc = new StringCollection(); 
                                        } 
                                        else
                                        { 
                                            //WinInet specific block!!
                                            // HACK: if we are parsing system metadata and have found our hack,
                                            // then convert it to a sparse entry type (entry.Info.EntryType & _WinInetCache.EntryType.Sparse)
                                            if (cacheEntry.EntryMetadata != null && value.StartsWith(c_SPARSE_ENTRY_HACK, StringComparison.Ordinal)) 
                                                cacheEntry.IsPartialEntry = true;
                                            else 
                                                sc.Add(value); 
                                        }
                                        start = i+1; 
                                    }
                                }
                            }
                            if (cacheEntry.EntryMetadata == null ) 
                                {cacheEntry.EntryMetadata = sc;}
                            else 
                                {cacheEntry.SystemMetadata = sc;} 
                        }
                    } 

                    result = new ReadStream(entry, handle, async);

                } 
                else {
                    if (handle != null) { 
                        handle.Close(); 
                    }
 
                    cacheEntry = new RequestCacheEntry();
                    cacheEntry.IsPrivateEntry = IsPrivateCache;

                    if (entry.Error != _WinInetCache.Status.FileNotFound) 
                    {
                        if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_lookup_failed, "WinInetCache.Retrieve()", new Win32Exception((int)entry.Error).Message)); 
                        if(Logging.On)Logging.Exit(Logging.RequestCache, "WinInetCache.Retrieve()"); 
                        if(isThrow)
                        { 
                            Win32Exception win32Exception = new Win32Exception((int)entry.Error);
                            throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception);
                        }
                        return null; 
                    }
                } 
            } 
            catch (Exception exception) {
                if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { 
                    throw;
                }

                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_exception, "WinInetCache.Retrieve()", exception.ToString())); 
                if(Logging.On)Logging.Exit(Logging.RequestCache, "WinInetCache.Retrieve()");
 
                if (handle != null) { 
                    handle.Close();
                } 
                result.Close();
                result = Stream.Null;
                cacheEntry = new RequestCacheEntry();
                cacheEntry.IsPrivateEntry = IsPrivateCache; 
                if (isThrow)
                { 
                    throw; 
                }
                return null; 
            }
            if(Logging.On)Logging.Exit(Logging.RequestCache, "WinInetCache.Retrieve()", "Status = " + entry.Error.ToString());
            return result;
        } 
        //
        // 
        // 
        private string CombineMetaInfo(StringCollection entryMetadata, StringCollection systemMetadata)
        { 
            if ((entryMetadata == null || entryMetadata.Count == 0) && (systemMetadata == null || systemMetadata.Count == 0))
                return string.Empty;

            StringBuilder sb = new StringBuilder(100); 
            int i;
            if (entryMetadata != null && entryMetadata.Count != 0) 
                for (i = 0; i < entryMetadata.Count; ++i) 
                {
                    if (entryMetadata[i] == null || entryMetadata[i].Length == 0) 
                        continue;
                    sb.Append(entryMetadata[i]).Append("\r\n");
                }
 
            if (systemMetadata != null && systemMetadata.Count != 0)
            { 
                // mark a start for system metadata 
                sb.Append("\r\n");
                for (i = 0; i < systemMetadata.Count; ++i) 
                {
                    if (systemMetadata[i] == null || systemMetadata[i].Length == 0)
                        continue;
                    sb.Append(systemMetadata[i]).Append("\r\n");} 
            }
 
            return sb.ToString(); 
        }
        // 
        //
        private Stream GetWriteStream(string key, long contentLength, DateTime expiresUtc, DateTime lastModifiedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata, bool isThrow)
        {
            if(Logging.On) Logging.Enter(Logging.RequestCache, "WinInetCache.Store()", "Key = " + key); 

            if (key == null) { 
                throw new ArgumentNullException("key"); 
            }
 
            if (!CanWrite)
            {
                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_operation_failed_with_error, "WinInetCache.Store()", SR.GetString(SR.net_cache_access_denied, "Write")));
                if(Logging.On) Logging.Exit(Logging.RequestCache, "WinInetCache.Store"); 
                if(isThrow)
                { 
                    throw new InvalidOperationException(SR.GetString(SR.net_cache_access_denied, "Write")); 
                }
                return null; 
            }


            _WinInetCache.Entry entry = new _WinInetCache.Entry(key, _MaximumResponseHeadersLength); 

            entry.Key = key; 
            entry.OptionalLength = (contentLength < 0L)? 0: contentLength > Int32.MaxValue? Int32.MaxValue: (int)(contentLength); 

            entry.Info.ExpireTime = _WinInetCache.FILETIME.Zero; 
            if (expiresUtc != DateTime.MinValue && expiresUtc > s_MinDateTimeUtcForFileTimeUtc) {
                entry.Info.ExpireTime  = new _WinInetCache.FILETIME(expiresUtc.ToFileTimeUtc());
            }
 
            entry.Info.LastModifiedTime = _WinInetCache.FILETIME.Zero;
            if (lastModifiedUtc != DateTime.MinValue && lastModifiedUtc > s_MinDateTimeUtcForFileTimeUtc) { 
                entry.Info.LastModifiedTime = new _WinInetCache.FILETIME(lastModifiedUtc.ToFileTimeUtc()); 
            }
 
            entry.Info.EntryType = _WinInetCache.EntryType.NormalEntry;
            if (maxStale > TimeSpan.Zero) {
                if (maxStale >= s_MaxTimeSpanForInt32) {
                    maxStale = s_MaxTimeSpanForInt32; 
                }
                entry.Info.U.ExemptDelta = (int)maxStale.TotalSeconds; 
                entry.Info.EntryType = _WinInetCache.EntryType.StickyEntry; 
            }
 

            entry.MetaInfo = CombineMetaInfo(entryMetadata, systemMetadata);

            entry.FileExt = "cache"; 
            if(Logging.On) {
                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_expected_length, entry.OptionalLength)); 
                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_last_modified, (entry.Info.LastModifiedTime.IsNull? "0": DateTime.FromFileTimeUtc(entry.Info.LastModifiedTime.ToLong()).ToString("r")))); 
                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_expires, (entry.Info.ExpireTime.IsNull? "0": DateTime.FromFileTimeUtc(entry.Info.ExpireTime.ToLong()).ToString("r"))));
                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_max_stale, (maxStale > TimeSpan.Zero? ((int)maxStale.TotalSeconds).ToString():"n/a"))); 
                if (Logging.IsVerbose(Logging.RequestCache)) {
                    Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_dumping_metadata));
                    if (entry.MetaInfo.Length == 0) {
                        Logging.PrintInfo(Logging.RequestCache, ""); 
                    }
                    else { 
                        if (entryMetadata != null) { 
                            foreach (string s in entryMetadata)
                            { 
                                Logging.PrintInfo(Logging.RequestCache, s.TrimEnd(LineSplits));
                            }
                        }
                        Logging.PrintInfo(Logging.RequestCache, "------"); 
                        if (systemMetadata != null) {
                            foreach (string s in systemMetadata) 
                            { 
                                Logging.PrintInfo(Logging.RequestCache, s.TrimEnd(LineSplits));
                            } 
                        }
                    }
                }
            } 

            _WinInetCache.CreateFileName(entry); 
 
            Stream result = Stream.Null;
            if (entry.Error != _WinInetCache.Status.Success) { 
                if(Logging.On)
                {
                    Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_create_failed, new Win32Exception((int)entry.Error).Message));
                    Logging.Exit(Logging.RequestCache, "WinInetCache.Store"); 
                }
                if (isThrow) 
                { 
                    Win32Exception win32Exception = new Win32Exception((int)entry.Error);
                    throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception); 
                }
                return null;
            }
 

            try { 
                result = new WriteStream(entry, isThrow, contentLength, async); 
            }
            catch (Exception exception) { 
                if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
                    throw;
                }
 
                if(Logging.On)
                { 
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_exception, "WinInetCache.Store()", exception)); 
                    Logging.Exit(Logging.RequestCache, "WinInetCache.Store");
                } 
                if (isThrow)
                {
                    throw;
                } 
                return null;
            } 
 
            if(Logging.On) Logging.Exit(Logging.RequestCache, "WinInetCache.Store", "Filename = " + entry.Filename);
            return result; 
        }
        //
        //
        private bool UpdateInfo(string key, DateTime expiresUtc, DateTime lastModifiedUtc, DateTime lastSynchronizedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata, bool isThrow) 
        {
            if (key == null) { 
                throw new ArgumentNullException("key"); 
            }
 
            if(Logging.On) Logging.Enter(Logging.RequestCache, "WinInetCache.Update", "Key = "+ key);

            if (!CanWrite)
            { 
                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_operation_failed_with_error, "WinInetCache.Update()", SR.GetString(SR.net_cache_access_denied, "Write")));
                if(Logging.On) Logging.Exit(Logging.RequestCache, "WinInetCache.Update()"); 
                if(isThrow) 
                {
                    throw new InvalidOperationException(SR.GetString(SR.net_cache_access_denied, "Write")); 
                }
                return false;
            }
 
            _WinInetCache.Entry entry = new _WinInetCache.Entry(key, _MaximumResponseHeadersLength);
            _WinInetCache.Entry_FC attributes =  _WinInetCache.Entry_FC.None; 
 
            if (expiresUtc != DateTime.MinValue && expiresUtc > s_MinDateTimeUtcForFileTimeUtc) {
                attributes |= _WinInetCache.Entry_FC.Exptime; 
                entry.Info.ExpireTime = new _WinInetCache.FILETIME(expiresUtc.ToFileTimeUtc());
                if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_set_expires, expiresUtc.ToString("r")));
            }
 
            if (lastModifiedUtc != DateTime.MinValue && lastModifiedUtc > s_MinDateTimeUtcForFileTimeUtc) {
                attributes |= _WinInetCache.Entry_FC.Modtime; 
                entry.Info.LastModifiedTime = new _WinInetCache.FILETIME(lastModifiedUtc.ToFileTimeUtc()); 
                if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_set_last_modified, lastModifiedUtc.ToString("r")));
            } 

            if (lastSynchronizedUtc != DateTime.MinValue && lastSynchronizedUtc > s_MinDateTimeUtcForFileTimeUtc) {
                attributes |= _WinInetCache.Entry_FC.Synctime;
                entry.Info.LastSyncTime = new _WinInetCache.FILETIME(lastSynchronizedUtc.ToFileTimeUtc()); 
                if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_set_last_synchronized, lastSynchronizedUtc.ToString("r")));
            } 
 
            if (maxStale != TimeSpan.MinValue) {
                attributes |= _WinInetCache.Entry_FC.ExemptDelta|_WinInetCache.Entry_FC.Attribute; 
                entry.Info.EntryType = _WinInetCache.EntryType.NormalEntry;
                if (maxStale >= TimeSpan.Zero) {
                    if (maxStale >= s_MaxTimeSpanForInt32) {
                        maxStale = s_MaxTimeSpanForInt32; 
                    }
                    entry.Info.EntryType = _WinInetCache.EntryType.StickyEntry; 
                    entry.Info.U.ExemptDelta = (int)maxStale.TotalSeconds; 
                    if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_enable_max_stale, ((int)maxStale.TotalSeconds).ToString()));
                } 
                else {
                    entry.Info.U.ExemptDelta = 0;
                    if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_disable_max_stale));
                } 
            }
 
            entry.MetaInfo = CombineMetaInfo(entryMetadata, systemMetadata); 
            if (entry.MetaInfo.Length != 0) {
                attributes |= _WinInetCache.Entry_FC.Headerinfo; 

                if(Logging.On) {
                    Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_dumping));
                    if (Logging.IsVerbose(Logging.RequestCache)) { 
                        Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_dumping));
                        if (entryMetadata != null) { 
                            foreach (string s in entryMetadata) 
                            {
                                Logging.PrintInfo(Logging.RequestCache, s.TrimEnd(LineSplits)); 
                            }
                        }
                        Logging.PrintInfo(Logging.RequestCache, "------");
                        if (systemMetadata != null) { 
                            foreach (string s in systemMetadata)
                            { 
                                Logging.PrintInfo(Logging.RequestCache, s.TrimEnd(LineSplits)); 
                            }
                        } 
                    }
                }
            }
 
            _WinInetCache.Update(entry, attributes) ;
 
            if (entry.Error != _WinInetCache.Status.Success) { 
                if(Logging.On)
                { 
                    Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_update_failed, "WinInetCache.Update()", entry.Key, new Win32Exception((int)entry.Error).Message));
                    Logging.Exit(Logging.RequestCache, "WinInetCache.Update()");
                }
                if (isThrow) 
                {
                    Win32Exception win32Exception = new Win32Exception((int)entry.Error); 
                    throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception); 
                }
                return false; 
            }

            if(Logging.On) Logging.Exit(Logging.RequestCache, "WinInetCache.Update()", "Status = " + entry.Error.ToString());
            return true; 
        }
 
        ///  
        ///    
        ///         This is a FileStream wrapper on top of WinInet cache entry. 
        //          The Close method will unlock the cached entry.
        ///    
        ///
        private class ReadStream: FileStream, ICloseEx { 
            private string m_Key;
            private int m_ReadTimeout; 
            private int m_WriteTimeout; 
            private SafeUnlockUrlCacheEntryFile m_Handle;
            private int m_Disposed; 
            private int m_CallNesting;
            private ManualResetEvent m_Event;
            private bool m_Aborted;
 
            //
            // Construct a read stream out of WinInet given handle 
            // 
            [FileIOPermission(SecurityAction.Assert, Unrestricted=true)]
            [ResourceExposure(ResourceScope.Machine)] 
            [ResourceConsumption(ResourceScope.Machine)]
            internal ReadStream(_WinInetCache.Entry entry, SafeUnlockUrlCacheEntryFile handle, bool async)
                    : base(entry.Filename, FileMode.Open, FileAccess.Read, ComNetOS.IsWinNt? FileShare.Read | FileShare.Delete : FileShare.Read, 4096, async)
            { 
                m_Key = entry.Key;
                m_Handle = handle; 
                m_ReadTimeout = m_WriteTimeout = System.Threading.Timeout.Infinite; 
            }
            // 
            // The stream will remain valid but after that call the entry can be replaced.
            // If the entry has been replaced then the physical file that this stream points to may be deleted on stream.Close()
            //
            internal void UnlockEntry() 
            {
                m_Handle.Close(); 
            } 

            public override int Read(byte[] buffer, int offset, int count) 
            {
                lock (m_Handle)
                {
                    try { 
                        if (m_CallNesting != 0)
                            throw new NotSupportedException(SR.GetString(SR.net_no_concurrent_io_allowed)); 
                        if (m_Aborted) 
                            throw ExceptionHelper.RequestAbortedException;
                        if (m_Event != null) 
                            throw new ObjectDisposedException(GetType().FullName);

                        m_CallNesting = 1;
                        return base.Read(buffer, offset, count); 
                    }
                    finally { 
                        if (m_Event != null) 
                            m_Event.Set();
                        m_CallNesting = 0; 
                    }
                }
            }
 
            public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, Object state)
            { 
                lock (m_Handle) 
                {
                    if (m_CallNesting != 0) 
                        throw new NotSupportedException(SR.GetString(SR.net_no_concurrent_io_allowed));
                    if (m_Aborted)
                        throw ExceptionHelper.RequestAbortedException;
                    if (m_Event != null) 
                        throw new ObjectDisposedException(GetType().FullName);
 
                    m_CallNesting = 1; 

                    return base.BeginRead(buffer, offset, count, callback, state); 
                }
            }

            public override int EndRead(IAsyncResult asyncResult) 
            {
                lock (m_Handle) 
                { 
                    try {
                        return base.EndRead(asyncResult); 
                    }
                    finally {
                            if (m_Event != null)
                                try {m_Event.Set();} catch {}   // the problem is he WaitHandle cannot tell if it is disposed or not 
                            m_CallNesting = 0;
                    } 
                } 
            }
 
            public void CloseEx(CloseExState closeState)
            {
                if ((closeState & CloseExState.Abort) != 0)
                    m_Aborted = true; 

                try { 
                    Close(); 
                }
                catch { 
                    if ((closeState & CloseExState.Silent) == 0)
                        throw;
                }
            } 

            protected override void Dispose(bool disposing) { 
                //if m_key is null, it means that the base constructor failed 
                if (Interlocked.Exchange(ref m_Disposed, 1) == 0 && m_Key != null)
                { 
                    try {
                        lock (m_Handle)
                        {
                            if (m_CallNesting == 0) 
                                base.Dispose(disposing);
                            else 
                                m_Event = new ManualResetEvent(false); 
                        }
 
                        if (disposing && m_Event != null)
                        {
                            using (m_Event)
                            { 
                                // This assumes that FileStream will never hang on read
                                m_Event.WaitOne(); 
                            } 
                            base.Dispose(disposing);
                        } 
                    }
                    finally {
                        if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_key, "WinInetReadStream.Close()", m_Key));
                        // note, the handle may have been closed earlier if CacheProtocol knew that cache metadata update will not happen. 
                        m_Handle.Close();
                    } 
                } 
            }
 
            public override bool CanTimeout {
                get {
                    return true;
                } 
            }
            public override int ReadTimeout { 
                get { 
                    return m_ReadTimeout;
                } 
                set {
                    m_ReadTimeout = value;
                }
            } 
            public override int WriteTimeout {
                get { 
                    return m_WriteTimeout; 
                }
                set { 
                    m_WriteTimeout = value;
                }
            }
        } 
        //
        // 
        // 
        private class WriteStream: FileStream, ICloseEx {
            private _WinInetCache.Entry m_Entry; 
            private bool m_IsThrow;
            private long m_StreamSize;
            private bool m_Aborted;
            private int m_ReadTimeout; 
            private int m_WriteTimeout;
            private int m_Disposed; 
            private int m_CallNesting; 
            private ManualResetEvent m_Event;
            private bool m_OneWriteSucceeded; 


            [FileIOPermission(SecurityAction.Assert, Unrestricted=true)]
            [ResourceExposure(ResourceScope.Machine)] 
            [ResourceConsumption(ResourceScope.Machine)]
            internal WriteStream(_WinInetCache.Entry entry, bool isThrow, long streamSize, bool async): 
                    base(entry.Filename, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, async) { 

                m_Entry = entry; 
                m_IsThrow = isThrow;
                m_StreamSize = streamSize;
                m_OneWriteSucceeded = streamSize == 0; //if 0 is expected or the lenght is unknonw we will commit even an emtpy stream.
                m_ReadTimeout = m_WriteTimeout = System.Threading.Timeout.Infinite; 
            }
            // 
            public override bool CanTimeout { 
                get {
                    return true; 
                }
            }
            public override int ReadTimeout {
                get { 
                    return m_ReadTimeout;
                } 
                set { 
                    m_ReadTimeout = value;
                } 
            }
            public override int WriteTimeout {
                get {
                    return m_WriteTimeout; 
                }
                set { 
                    m_WriteTimeout = value; 
                }
            } 
            //
            public override void Write(byte[] buffer, int offset, int count)
            {
                lock (m_Entry) 
                {
                    if (m_Aborted) 
                        throw ExceptionHelper.RequestAbortedException; 
                    if (m_Event != null)
                        throw new ObjectDisposedException(GetType().FullName); 

                    try {
                        base.Write(buffer, offset, count);
                        if (m_StreamSize > 0) 
                            m_StreamSize -= count;
                        if (!m_OneWriteSucceeded && count != 0) 
                            m_OneWriteSucceeded = true; 
                    }
                    catch { 
                        m_Aborted = true;
                        throw;
                    }
                    finally { 
                        if (m_Event != null)
                            m_Event.Set(); 
                    } 
                }
            } 
            //
            public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, Object state)
            {
                lock (m_Entry) 
                {
                    if (m_CallNesting != 0) 
                        throw new NotSupportedException(SR.GetString(SR.net_no_concurrent_io_allowed)); 
                    if (m_Aborted)
                        throw ExceptionHelper.RequestAbortedException; 
                    if (m_Event != null)
                        throw new ObjectDisposedException(GetType().FullName);

                    m_CallNesting = 1; 

                    try { 
                        if (m_StreamSize > 0) 
                            m_StreamSize -= count;
                        return base.BeginWrite(buffer, offset, count, callback, state); 
                    }
                    catch {
                        m_Aborted = true;
                        throw; 
                    }
                } 
 
            }
            // 
            public override void EndWrite(IAsyncResult asyncResult)
            {
                lock (m_Entry)
                { 
                    try {
                        base.EndWrite(asyncResult); 
                        if (!m_OneWriteSucceeded) 
                            m_OneWriteSucceeded = true;
                    } 
                    catch {
                        m_Aborted = true;
                        throw;
                    } 
                    finally {
                        if (m_Event != null) 
                            try {m_Event.Set();} catch {}   // the problem is he WaitHandle cannot tell if it is disposed or not 
                        m_CallNesting = 0;
                    } 
                }
            }
            //
            public void CloseEx(CloseExState closeState) 
            {
                // For abnormal stream termination we will commit a partial cache entry 
                if ((closeState & CloseExState.Abort) != 0) 
                    m_Aborted = true;
 
                try {
                    Close();
                }
                catch { 
                    if ((closeState & CloseExState.Silent) == 0)
                        throw; 
                } 
            }
            // 
            [ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
            protected override void Dispose(bool disposing)
            { 
                //if m_Entry is null, it means that the base constructor failed
                if (Interlocked.Exchange(ref m_Disposed, 1) == 0 && m_Entry != null) { 
 
                    lock (m_Entry)
                    { 
                        if (m_CallNesting == 0)
                            base.Dispose(disposing);
                        else
                            m_Event = new ManualResetEvent(false); 
                    }
 
                    // 
                    // This assumes the FileStream will never hang on write
                    // 
                    if (disposing && m_Event != null)
                    {
                        using (m_Event)
                        { 
                            m_Event.WaitOne();
                        } 
                        base.Dispose(disposing); 
                    }
 
                    // We use TriState to indicate:
                    //     False:   Delete
                    //     Unknown: Partial
                    //     True:    Full 
                    TriState cacheCommitAction;
                    if (m_StreamSize < 0) 
                    { 
                        if (m_Aborted)
                        { 
                            if (m_OneWriteSucceeded)
                                cacheCommitAction = TriState.Unspecified; // Partial
                            else
                                cacheCommitAction = TriState.False; // Delete 
                        }
                        else 
                        { 
                            cacheCommitAction = TriState.True; // Full
                        } 
                    }
                    else
                    {
                        if (!m_OneWriteSucceeded) 
                        {
                            cacheCommitAction = TriState.False; // Delete 
                        } 
                        else
                        { 
                            if (m_StreamSize > 0)
                                cacheCommitAction = TriState.Unspecified; // Partial
                            else
                                cacheCommitAction = TriState.True; // Full 
                        }
                    } 
 
                    if (cacheCommitAction == TriState.False)
                    { 
                        try
                        {
                            if(Logging.On)Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_no_commit, "WinInetWriteStream.Close()"));
                            // Delete temp cache file 
                            File.Delete(m_Entry.Filename);
                        } 
                        catch (Exception exception) 
                        {
                            if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { 
                                throw;
                            }
                            if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_error_deleting_filename, "WinInetWriteStream.Close()", m_Entry.Filename));
                        } 
                        finally {
                            //Delete an old entry if there was one 
                            _WinInetCache.Status errorStatus = _WinInetCache.Remove(m_Entry); 
                            if (errorStatus != _WinInetCache.Status.Success && errorStatus != _WinInetCache.Status.FileNotFound)
                            { 
                                if(Logging.On)Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_delete_failed, "WinInetWriteStream.Close()", m_Entry.Key, new Win32Exception((int)m_Entry.Error).Message));
                            }

                            m_Entry = null; 
                        }
                        return; 
                    } 

                    m_Entry.OriginalUrl = null; 

                    //
                    // ATTN: WinIent currently does NOT support _WinInetCache.EntryType.Sparse
                    // USING a workaround 
                    //
                    if (cacheCommitAction == TriState.Unspecified) 
                    { 
    // WinInet will not report this entry back we set this flag
    //                    m_Entry.Info.EntryType |= _WinInetCache.EntryType.Sparse;  // does not work for now 

                        // HACK: WinInet does not support SPARSE_ENTRY bit
                        // We want to add c_SPARSE_ENTRY_HACK into the systemmetadata i.e. to the second block of strings separated by an empty line (\r\n).
                        if (m_Entry.MetaInfo == null || m_Entry.MetaInfo.Length == 0 || 
                            (m_Entry.MetaInfo != "\r\n" && m_Entry.MetaInfo.IndexOf("\r\n\r\n", StringComparison.Ordinal) == -1))
                        { 
                            m_Entry.MetaInfo = "\r\n"+ WinInetCache.c_SPARSE_ENTRY_HACK+"\r\n"; 
                        }
                        else 
                        {
                            m_Entry.MetaInfo += WinInetCache.c_SPARSE_ENTRY_HACK+"\r\n";
                        }
                    } 

                    if (_WinInetCache.Commit(m_Entry) != _WinInetCache.Status.Success) 
                    { 
                        if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_commit_failed, "WinInetWriteStream.Close()", m_Entry.Key, new Win32Exception((int)m_Entry.Error).Message));
                        try 
                        {
                            // Delete temp cache file
                            File.Delete(m_Entry.Filename);
                        } 
                        catch (Exception exception)
                        { 
                            if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { 
                                throw;
                            } 
                            if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_error_deleting_filename, "WinInetWriteStream.Close()", m_Entry.Filename));
                        }

                        if (m_IsThrow) 
                        {
                            Win32Exception win32Exception = new Win32Exception((int)m_Entry.Error); 
                            throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception); 
                        }
                        return; 
                    }

                    if(Logging.On)
                    { 
                        if (m_StreamSize > 0 || (m_StreamSize < 0 && m_Aborted))
                            Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_committed_as_partial, "WinInetWriteStream.Close()", m_Entry.Key, (m_StreamSize > 0 ? m_StreamSize.ToString(CultureInfo.CurrentCulture) : SR.GetString(SR.net_log_unknown)))); 
                        Logging.PrintInfo(Logging.RequestCache, "WinInetWriteStream.Close(), Key = " + m_Entry.Key + ", Commit Status = " + m_Entry.Error.ToString()); 
                    }
 

                    if ((m_Entry.Info.EntryType & _WinInetCache.EntryType.StickyEntry) == _WinInetCache.EntryType.StickyEntry)
                    {
                        if (_WinInetCache.Update(m_Entry, _WinInetCache.Entry_FC.ExemptDelta) != _WinInetCache.Status.Success) 
                        {
                            if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_update_failed, "WinInetWriteStream.Close(), Key = " + m_Entry.Key, new Win32Exception((int)m_Entry.Error).Message)); 
                            if (m_IsThrow) 
                            {
                                Win32Exception win32Exception = new Win32Exception((int)m_Entry.Error); 
                                throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception);
                            }
                            return;
                        } 
                        if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_max_stale_and_update_status, "WinInetWriteFile.Close()", m_Entry.Info.U.ExemptDelta, m_Entry.Error.ToString()));
                    } 
 
                    base.Dispose(disposing);
                } 
            }
        }
    }
} 

 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace Microsoft.Win32 { 
    using System; 
    using System.Net;
    using System.Net.Cache; 
    using System.Globalization;
    using System.IO;
    using System.Threading;
    using System.Collections.Specialized; 
    using System.Security.Permissions;
    using System.Security.Principal; 
    using System.ComponentModel; 
    using System.Text;
    using System.Runtime.Versioning; 

    // The class implements a RequestCache class contract on top of WinInet provider
    // Author: Alexei Vopilov    21-Dec-2002
    // 
    // Revision History:
    // 
    // Jan 25 2004  - Changed the visibility of the class from public to internal. 

    internal class WinInetCache: RequestCache { 
        private  static int _MaximumResponseHeadersLength;
        private bool async;
        internal const string c_SPARSE_ENTRY_HACK = "~SPARSE_ENTRY:";
 
        private  readonly static DateTime   s_MinDateTimeUtcForFileTimeUtc = DateTime.FromFileTimeUtc(0L);
        internal readonly static TimeSpan   s_MaxTimeSpanForInt32 = TimeSpan.FromSeconds((double)int.MaxValue); 
 
//        private  static readonly RequestCachePermission s_ReadPermission      = new RequestCachePermission(RequestCacheActions.CacheRead);
//        private  static readonly RequestCachePermission s_ReadWritePermission = new RequestCachePermission(RequestCacheActions.CacheReadWrite); 

        ///  A public constructor that demands CacheReadWrite flag for RequestCachePermission  
        internal WinInetCache(bool isPrivateCache, bool canWrite, bool async): base (isPrivateCache, canWrite)
        { 
            /***********
            if (canWrite) { 
                s_ReadWritePermission.Demand(); 
            }
            else 
            {
                s_ReadPermission.Demand();
            }
            ***********/ 

            // Per VsWhidbey#88276 it was decided to not enforce any cache metadata limits for WinInet cache provider. 
            _MaximumResponseHeadersLength = Int32.MaxValue; 
            this.async = async;
 
            /********
            if (_MaximumResponseHeadersLength == 0) {
                NetConfiguration config = (NetConfiguration)System.Configuration.ConfigurationManager.GetSection("system.net/settings");
                if (config != null) { 
                    if (config.maximumResponseHeadersLength < 0 && config.maximumResponseHeadersLength != -1) {
                        throw new ArgumentOutOfRangeException(SR.GetString(SR.net_toosmall)); 
                    } 
                    _MaximumResponseHeadersLength = config.maximumResponseHeadersLength * 1024;
                } 
                else {
                    _MaximumResponseHeadersLength = 64 * 1024;
                }
            } 
            ********/
        } 
 
        /// 
        ///  
        /// Gets the data stream and the metadata associated with a IE cache entry.
        /// Returns Stream.Null if there is no entry found.
        /// 
        ///  
        internal override Stream Retrieve(string key, out RequestCacheEntry cacheEntry)
        { 
            return Lookup(key, out cacheEntry, true); 
        }
        // 
        internal override bool TryRetrieve(string key, out RequestCacheEntry cacheEntry, out Stream  readStream)
        {
            readStream = Lookup(key, out cacheEntry, false);
            if (readStream == null) 
            {
                return false; 
            } 
            return true;
        } 
        // Returns a write stream associated with the IE cache string Key.
        // Passed parameters allow cache to update an entry metadata accordingly.
        //   The commit operation will happen upon the stream closure. 
        internal override Stream Store(string key, long contentLength, DateTime expiresUtc, DateTime lastModifiedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata) 
        {
            return GetWriteStream(key, contentLength, expiresUtc, lastModifiedUtc, maxStale, entryMetadata, systemMetadata, true); 
        } 
        // Does not throw on an error
        internal override bool TryStore(string key, long contentLength, DateTime expiresUtc, DateTime lastModifiedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata, out Stream writeStream) 
        {
            writeStream = GetWriteStream(key, contentLength, expiresUtc, lastModifiedUtc, maxStale, entryMetadata, systemMetadata, false);
            if (writeStream == null)
            { 
                return false;
            } 
            return true; 
        }
        ///  
        /// 
        /// Removes an item from the IE cache. Throws Win32Excpetion if failed
        /// 
        ///  
        internal override void Remove(string key) {
 
            if (key == null) { 
                throw new ArgumentNullException("key");
            } 

            if (!CanWrite)
            {
                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_operation_failed_with_error, "WinInetCache.Remove()", SR.GetString(SR.net_cache_access_denied, "Write"))); 
                return ;
            } 
 
            _WinInetCache.Entry entry = new _WinInetCache.Entry(key, _MaximumResponseHeadersLength);
 
            if (_WinInetCache.Remove(entry) != _WinInetCache.Status.Success && entry.Error != _WinInetCache.Status.FileNotFound) {
                Win32Exception win32Exception = new Win32Exception((int)entry.Error);
                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_cannot_remove, "WinInetCache.Remove()", key, win32Exception.Message));
                throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception); 
            }
 
            if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_key_status, "WinInetCache.Remove(), ", key, entry.Error.ToString())); 
        }
        // 
        //  Tries to remove an item from the cache, possible by applying unsafe entry unlocking.
        //  Returns true if successful, false otherwise
        internal override bool TryRemove(string key)
        { 
            return TryRemove(key, false);
 
        } 
        //
        // Purges Wininet Cache Entry by Unlocking it's file until zero count (if forceRemove is set). 
        //
        internal bool TryRemove(string key, bool forceRemove) {

            if (key == null) { 
                throw new ArgumentNullException("key");
            } 
 
            if (!CanWrite)
            { 
                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_operation_failed_with_error, "WinInetCache.TryRemove()", SR.GetString(SR.net_cache_access_denied, "Write")));
                return false;
            }
 
            _WinInetCache.Entry entry = new _WinInetCache.Entry(key, _MaximumResponseHeadersLength);
 
            if (_WinInetCache.Remove(entry) == _WinInetCache.Status.Success || entry.Error == _WinInetCache.Status.FileNotFound) { 
                if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_key_status, "WinInetCache.TryRemove()", key, entry.Error.ToString()));
                return true; 
            }
            else if (!forceRemove) {
                if(Logging.On)Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_key_remove_failed_status, "WinInetCache.TryRemove()", key, entry.Error.ToString()));
                return false; 
            }
 
            _WinInetCache.Status status = _WinInetCache.LookupInfo(entry); 
            if (status == _WinInetCache.Status.Success) {
                while (entry.Info.UseCount != 0) { 
                    if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_key_status, "WinInetCache.TryRemove()", key, entry.Error.ToString()));
                    if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_usecount_file, "WinInetCache.TryRemove()", entry.Info.UseCount, entry.Filename));
                    if (!UnsafeNclNativeMethods.UnsafeWinInetCache.UnlockUrlCacheEntryFileW(key, 0)) {
                        break; 
                    }
                    status = _WinInetCache.LookupInfo(entry); 
                } 
            }
            _WinInetCache.Remove(entry); 
            if (entry.Error != _WinInetCache.Status.Success && _WinInetCache.LookupInfo(entry) == _WinInetCache.Status.FileNotFound) {
                entry.Error = _WinInetCache.Status.Success;
            }
            if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_key_status, "WinInetCache.TryRemove()", key, entry.Error.ToString())); 
            return entry.Error == _WinInetCache.Status.Success;
        } 
        ///  
        /// 
        /// Updates only the metadata associated with IE cached entry. 
        /// 
        /// 
        internal override void Update(string key, DateTime expiresUtc, DateTime lastModifiedUtc, DateTime lastSynchronizedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata)
        { 
            UpdateInfo(key, expiresUtc, lastModifiedUtc, lastSynchronizedUtc, maxStale, entryMetadata, systemMetadata, true);
 
        } 
        // Does not throw on an error
        internal override bool TryUpdate(string key, DateTime expiresUtc, DateTime lastModifiedUtc, DateTime lastSynchronizedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata) 
        {
            return UpdateInfo(key, expiresUtc, lastModifiedUtc, lastSynchronizedUtc, maxStale, entryMetadata, systemMetadata, false);
        }
        // 
        // Once the entry is unlocked it must not be updated
        // There is a design flaw in current RequestCache contract, it should allow detection of already replaced entry when updating one. 
        // 
        internal override void UnlockEntry(Stream stream)
        { 
            ReadStream readStream = stream as ReadStream;

            if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_stream, "WinInetCache.UnlockEntry",  (stream == null ? "" : stream.GetType().FullName)));
 
            // could be wrapped by some other stream, that's ok because the entry is unlocked on stream.Close anyway
            if (readStream == null) 
                return; 
            readStream.UnlockEntry();
        } 
        //
        //
        //
        private Stream Lookup(string key, out RequestCacheEntry cacheEntry, bool isThrow) 
        {
            if(Logging.On) Logging.Enter(Logging.RequestCache, "WinInetCache.Retrieve", "key = " + key); 
 
            if (key == null) {
                throw new ArgumentNullException("key"); 
            }

            Stream result = Stream.Null;
            SafeUnlockUrlCacheEntryFile handle = null; 
            _WinInetCache.Entry entry = new _WinInetCache.Entry(key, _MaximumResponseHeadersLength);
            try { 
                handle = _WinInetCache.LookupFile(entry); 

                if (entry.Error == _WinInetCache.Status.Success) { 
                    if(Logging.On) Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_filename, "WinInetCache.Retrieve()", entry.Filename, entry.Error));

                    cacheEntry = new RequestCacheEntry(entry, IsPrivateCache);
 
                    if (entry.MetaInfo != null && entry.MetaInfo.Length != 0)
                    { 
                        // convert metadata to upto two string collections 
                        unsafe
                        { 
                            int start = 0;
                            int length = entry.MetaInfo.Length;
                            StringCollection sc = new StringCollection();
                            fixed (char * ch = entry.MetaInfo) 
                            {
                                int i; 
                                for (i = 0; i < length; ++i) 
                                {
                                    // WinInet specific block!! 
                                    // The point here is that wininet scans for ~U: throughly with no regard to \r\n so we mimic the same behavior
                                    if (i == start && i+2 < length)
                                    {
                                        if (ch[i] == '~' && (ch[i+1] == 'U' || ch[i+1] == 'u') && ch[i+2] == ':') 
                                        {
                                            //Security: don't report what the username is 
                                            while(i < length && ch[++i] != '\n') {;} 
                                            start = i+1;
                                            continue; 
                                        }

                                    }
 
                                    // note a metadata entry must terminate with \r\n
 
                                    if ((i+1 == length) || (ch[i] == '\n')) 
                                    {
                                        string value = entry.MetaInfo.Substring(start, (ch[i-1] == '\r'? (i-1):(i+1)) - start); 

                                        if (value.Length == 0 && cacheEntry.EntryMetadata == null)
                                        {
                                            // done with headers, prepare for system metadata 
                                            cacheEntry.EntryMetadata = sc;
                                            sc = new StringCollection(); 
                                        } 
                                        else
                                        { 
                                            //WinInet specific block!!
                                            // HACK: if we are parsing system metadata and have found our hack,
                                            // then convert it to a sparse entry type (entry.Info.EntryType & _WinInetCache.EntryType.Sparse)
                                            if (cacheEntry.EntryMetadata != null && value.StartsWith(c_SPARSE_ENTRY_HACK, StringComparison.Ordinal)) 
                                                cacheEntry.IsPartialEntry = true;
                                            else 
                                                sc.Add(value); 
                                        }
                                        start = i+1; 
                                    }
                                }
                            }
                            if (cacheEntry.EntryMetadata == null ) 
                                {cacheEntry.EntryMetadata = sc;}
                            else 
                                {cacheEntry.SystemMetadata = sc;} 
                        }
                    } 

                    result = new ReadStream(entry, handle, async);

                } 
                else {
                    if (handle != null) { 
                        handle.Close(); 
                    }
 
                    cacheEntry = new RequestCacheEntry();
                    cacheEntry.IsPrivateEntry = IsPrivateCache;

                    if (entry.Error != _WinInetCache.Status.FileNotFound) 
                    {
                        if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_lookup_failed, "WinInetCache.Retrieve()", new Win32Exception((int)entry.Error).Message)); 
                        if(Logging.On)Logging.Exit(Logging.RequestCache, "WinInetCache.Retrieve()"); 
                        if(isThrow)
                        { 
                            Win32Exception win32Exception = new Win32Exception((int)entry.Error);
                            throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception);
                        }
                        return null; 
                    }
                } 
            } 
            catch (Exception exception) {
                if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { 
                    throw;
                }

                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_exception, "WinInetCache.Retrieve()", exception.ToString())); 
                if(Logging.On)Logging.Exit(Logging.RequestCache, "WinInetCache.Retrieve()");
 
                if (handle != null) { 
                    handle.Close();
                } 
                result.Close();
                result = Stream.Null;
                cacheEntry = new RequestCacheEntry();
                cacheEntry.IsPrivateEntry = IsPrivateCache; 
                if (isThrow)
                { 
                    throw; 
                }
                return null; 
            }
            if(Logging.On)Logging.Exit(Logging.RequestCache, "WinInetCache.Retrieve()", "Status = " + entry.Error.ToString());
            return result;
        } 
        //
        // 
        // 
        private string CombineMetaInfo(StringCollection entryMetadata, StringCollection systemMetadata)
        { 
            if ((entryMetadata == null || entryMetadata.Count == 0) && (systemMetadata == null || systemMetadata.Count == 0))
                return string.Empty;

            StringBuilder sb = new StringBuilder(100); 
            int i;
            if (entryMetadata != null && entryMetadata.Count != 0) 
                for (i = 0; i < entryMetadata.Count; ++i) 
                {
                    if (entryMetadata[i] == null || entryMetadata[i].Length == 0) 
                        continue;
                    sb.Append(entryMetadata[i]).Append("\r\n");
                }
 
            if (systemMetadata != null && systemMetadata.Count != 0)
            { 
                // mark a start for system metadata 
                sb.Append("\r\n");
                for (i = 0; i < systemMetadata.Count; ++i) 
                {
                    if (systemMetadata[i] == null || systemMetadata[i].Length == 0)
                        continue;
                    sb.Append(systemMetadata[i]).Append("\r\n");} 
            }
 
            return sb.ToString(); 
        }
        // 
        //
        private Stream GetWriteStream(string key, long contentLength, DateTime expiresUtc, DateTime lastModifiedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata, bool isThrow)
        {
            if(Logging.On) Logging.Enter(Logging.RequestCache, "WinInetCache.Store()", "Key = " + key); 

            if (key == null) { 
                throw new ArgumentNullException("key"); 
            }
 
            if (!CanWrite)
            {
                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_operation_failed_with_error, "WinInetCache.Store()", SR.GetString(SR.net_cache_access_denied, "Write")));
                if(Logging.On) Logging.Exit(Logging.RequestCache, "WinInetCache.Store"); 
                if(isThrow)
                { 
                    throw new InvalidOperationException(SR.GetString(SR.net_cache_access_denied, "Write")); 
                }
                return null; 
            }


            _WinInetCache.Entry entry = new _WinInetCache.Entry(key, _MaximumResponseHeadersLength); 

            entry.Key = key; 
            entry.OptionalLength = (contentLength < 0L)? 0: contentLength > Int32.MaxValue? Int32.MaxValue: (int)(contentLength); 

            entry.Info.ExpireTime = _WinInetCache.FILETIME.Zero; 
            if (expiresUtc != DateTime.MinValue && expiresUtc > s_MinDateTimeUtcForFileTimeUtc) {
                entry.Info.ExpireTime  = new _WinInetCache.FILETIME(expiresUtc.ToFileTimeUtc());
            }
 
            entry.Info.LastModifiedTime = _WinInetCache.FILETIME.Zero;
            if (lastModifiedUtc != DateTime.MinValue && lastModifiedUtc > s_MinDateTimeUtcForFileTimeUtc) { 
                entry.Info.LastModifiedTime = new _WinInetCache.FILETIME(lastModifiedUtc.ToFileTimeUtc()); 
            }
 
            entry.Info.EntryType = _WinInetCache.EntryType.NormalEntry;
            if (maxStale > TimeSpan.Zero) {
                if (maxStale >= s_MaxTimeSpanForInt32) {
                    maxStale = s_MaxTimeSpanForInt32; 
                }
                entry.Info.U.ExemptDelta = (int)maxStale.TotalSeconds; 
                entry.Info.EntryType = _WinInetCache.EntryType.StickyEntry; 
            }
 

            entry.MetaInfo = CombineMetaInfo(entryMetadata, systemMetadata);

            entry.FileExt = "cache"; 
            if(Logging.On) {
                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_expected_length, entry.OptionalLength)); 
                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_last_modified, (entry.Info.LastModifiedTime.IsNull? "0": DateTime.FromFileTimeUtc(entry.Info.LastModifiedTime.ToLong()).ToString("r")))); 
                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_expires, (entry.Info.ExpireTime.IsNull? "0": DateTime.FromFileTimeUtc(entry.Info.ExpireTime.ToLong()).ToString("r"))));
                Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_max_stale, (maxStale > TimeSpan.Zero? ((int)maxStale.TotalSeconds).ToString():"n/a"))); 
                if (Logging.IsVerbose(Logging.RequestCache)) {
                    Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_dumping_metadata));
                    if (entry.MetaInfo.Length == 0) {
                        Logging.PrintInfo(Logging.RequestCache, ""); 
                    }
                    else { 
                        if (entryMetadata != null) { 
                            foreach (string s in entryMetadata)
                            { 
                                Logging.PrintInfo(Logging.RequestCache, s.TrimEnd(LineSplits));
                            }
                        }
                        Logging.PrintInfo(Logging.RequestCache, "------"); 
                        if (systemMetadata != null) {
                            foreach (string s in systemMetadata) 
                            { 
                                Logging.PrintInfo(Logging.RequestCache, s.TrimEnd(LineSplits));
                            } 
                        }
                    }
                }
            } 

            _WinInetCache.CreateFileName(entry); 
 
            Stream result = Stream.Null;
            if (entry.Error != _WinInetCache.Status.Success) { 
                if(Logging.On)
                {
                    Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_create_failed, new Win32Exception((int)entry.Error).Message));
                    Logging.Exit(Logging.RequestCache, "WinInetCache.Store"); 
                }
                if (isThrow) 
                { 
                    Win32Exception win32Exception = new Win32Exception((int)entry.Error);
                    throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception); 
                }
                return null;
            }
 

            try { 
                result = new WriteStream(entry, isThrow, contentLength, async); 
            }
            catch (Exception exception) { 
                if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
                    throw;
                }
 
                if(Logging.On)
                { 
                    Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_exception, "WinInetCache.Store()", exception)); 
                    Logging.Exit(Logging.RequestCache, "WinInetCache.Store");
                } 
                if (isThrow)
                {
                    throw;
                } 
                return null;
            } 
 
            if(Logging.On) Logging.Exit(Logging.RequestCache, "WinInetCache.Store", "Filename = " + entry.Filename);
            return result; 
        }
        //
        //
        private bool UpdateInfo(string key, DateTime expiresUtc, DateTime lastModifiedUtc, DateTime lastSynchronizedUtc, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata, bool isThrow) 
        {
            if (key == null) { 
                throw new ArgumentNullException("key"); 
            }
 
            if(Logging.On) Logging.Enter(Logging.RequestCache, "WinInetCache.Update", "Key = "+ key);

            if (!CanWrite)
            { 
                if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_operation_failed_with_error, "WinInetCache.Update()", SR.GetString(SR.net_cache_access_denied, "Write")));
                if(Logging.On) Logging.Exit(Logging.RequestCache, "WinInetCache.Update()"); 
                if(isThrow) 
                {
                    throw new InvalidOperationException(SR.GetString(SR.net_cache_access_denied, "Write")); 
                }
                return false;
            }
 
            _WinInetCache.Entry entry = new _WinInetCache.Entry(key, _MaximumResponseHeadersLength);
            _WinInetCache.Entry_FC attributes =  _WinInetCache.Entry_FC.None; 
 
            if (expiresUtc != DateTime.MinValue && expiresUtc > s_MinDateTimeUtcForFileTimeUtc) {
                attributes |= _WinInetCache.Entry_FC.Exptime; 
                entry.Info.ExpireTime = new _WinInetCache.FILETIME(expiresUtc.ToFileTimeUtc());
                if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_set_expires, expiresUtc.ToString("r")));
            }
 
            if (lastModifiedUtc != DateTime.MinValue && lastModifiedUtc > s_MinDateTimeUtcForFileTimeUtc) {
                attributes |= _WinInetCache.Entry_FC.Modtime; 
                entry.Info.LastModifiedTime = new _WinInetCache.FILETIME(lastModifiedUtc.ToFileTimeUtc()); 
                if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_set_last_modified, lastModifiedUtc.ToString("r")));
            } 

            if (lastSynchronizedUtc != DateTime.MinValue && lastSynchronizedUtc > s_MinDateTimeUtcForFileTimeUtc) {
                attributes |= _WinInetCache.Entry_FC.Synctime;
                entry.Info.LastSyncTime = new _WinInetCache.FILETIME(lastSynchronizedUtc.ToFileTimeUtc()); 
                if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_set_last_synchronized, lastSynchronizedUtc.ToString("r")));
            } 
 
            if (maxStale != TimeSpan.MinValue) {
                attributes |= _WinInetCache.Entry_FC.ExemptDelta|_WinInetCache.Entry_FC.Attribute; 
                entry.Info.EntryType = _WinInetCache.EntryType.NormalEntry;
                if (maxStale >= TimeSpan.Zero) {
                    if (maxStale >= s_MaxTimeSpanForInt32) {
                        maxStale = s_MaxTimeSpanForInt32; 
                    }
                    entry.Info.EntryType = _WinInetCache.EntryType.StickyEntry; 
                    entry.Info.U.ExemptDelta = (int)maxStale.TotalSeconds; 
                    if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_enable_max_stale, ((int)maxStale.TotalSeconds).ToString()));
                } 
                else {
                    entry.Info.U.ExemptDelta = 0;
                    if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_disable_max_stale));
                } 
            }
 
            entry.MetaInfo = CombineMetaInfo(entryMetadata, systemMetadata); 
            if (entry.MetaInfo.Length != 0) {
                attributes |= _WinInetCache.Entry_FC.Headerinfo; 

                if(Logging.On) {
                    Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_dumping));
                    if (Logging.IsVerbose(Logging.RequestCache)) { 
                        Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_dumping));
                        if (entryMetadata != null) { 
                            foreach (string s in entryMetadata) 
                            {
                                Logging.PrintInfo(Logging.RequestCache, s.TrimEnd(LineSplits)); 
                            }
                        }
                        Logging.PrintInfo(Logging.RequestCache, "------");
                        if (systemMetadata != null) { 
                            foreach (string s in systemMetadata)
                            { 
                                Logging.PrintInfo(Logging.RequestCache, s.TrimEnd(LineSplits)); 
                            }
                        } 
                    }
                }
            }
 
            _WinInetCache.Update(entry, attributes) ;
 
            if (entry.Error != _WinInetCache.Status.Success) { 
                if(Logging.On)
                { 
                    Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_update_failed, "WinInetCache.Update()", entry.Key, new Win32Exception((int)entry.Error).Message));
                    Logging.Exit(Logging.RequestCache, "WinInetCache.Update()");
                }
                if (isThrow) 
                {
                    Win32Exception win32Exception = new Win32Exception((int)entry.Error); 
                    throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception); 
                }
                return false; 
            }

            if(Logging.On) Logging.Exit(Logging.RequestCache, "WinInetCache.Update()", "Status = " + entry.Error.ToString());
            return true; 
        }
 
        ///  
        ///    
        ///         This is a FileStream wrapper on top of WinInet cache entry. 
        //          The Close method will unlock the cached entry.
        ///    
        ///
        private class ReadStream: FileStream, ICloseEx { 
            private string m_Key;
            private int m_ReadTimeout; 
            private int m_WriteTimeout; 
            private SafeUnlockUrlCacheEntryFile m_Handle;
            private int m_Disposed; 
            private int m_CallNesting;
            private ManualResetEvent m_Event;
            private bool m_Aborted;
 
            //
            // Construct a read stream out of WinInet given handle 
            // 
            [FileIOPermission(SecurityAction.Assert, Unrestricted=true)]
            [ResourceExposure(ResourceScope.Machine)] 
            [ResourceConsumption(ResourceScope.Machine)]
            internal ReadStream(_WinInetCache.Entry entry, SafeUnlockUrlCacheEntryFile handle, bool async)
                    : base(entry.Filename, FileMode.Open, FileAccess.Read, ComNetOS.IsWinNt? FileShare.Read | FileShare.Delete : FileShare.Read, 4096, async)
            { 
                m_Key = entry.Key;
                m_Handle = handle; 
                m_ReadTimeout = m_WriteTimeout = System.Threading.Timeout.Infinite; 
            }
            // 
            // The stream will remain valid but after that call the entry can be replaced.
            // If the entry has been replaced then the physical file that this stream points to may be deleted on stream.Close()
            //
            internal void UnlockEntry() 
            {
                m_Handle.Close(); 
            } 

            public override int Read(byte[] buffer, int offset, int count) 
            {
                lock (m_Handle)
                {
                    try { 
                        if (m_CallNesting != 0)
                            throw new NotSupportedException(SR.GetString(SR.net_no_concurrent_io_allowed)); 
                        if (m_Aborted) 
                            throw ExceptionHelper.RequestAbortedException;
                        if (m_Event != null) 
                            throw new ObjectDisposedException(GetType().FullName);

                        m_CallNesting = 1;
                        return base.Read(buffer, offset, count); 
                    }
                    finally { 
                        if (m_Event != null) 
                            m_Event.Set();
                        m_CallNesting = 0; 
                    }
                }
            }
 
            public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, Object state)
            { 
                lock (m_Handle) 
                {
                    if (m_CallNesting != 0) 
                        throw new NotSupportedException(SR.GetString(SR.net_no_concurrent_io_allowed));
                    if (m_Aborted)
                        throw ExceptionHelper.RequestAbortedException;
                    if (m_Event != null) 
                        throw new ObjectDisposedException(GetType().FullName);
 
                    m_CallNesting = 1; 

                    return base.BeginRead(buffer, offset, count, callback, state); 
                }
            }

            public override int EndRead(IAsyncResult asyncResult) 
            {
                lock (m_Handle) 
                { 
                    try {
                        return base.EndRead(asyncResult); 
                    }
                    finally {
                            if (m_Event != null)
                                try {m_Event.Set();} catch {}   // the problem is he WaitHandle cannot tell if it is disposed or not 
                            m_CallNesting = 0;
                    } 
                } 
            }
 
            public void CloseEx(CloseExState closeState)
            {
                if ((closeState & CloseExState.Abort) != 0)
                    m_Aborted = true; 

                try { 
                    Close(); 
                }
                catch { 
                    if ((closeState & CloseExState.Silent) == 0)
                        throw;
                }
            } 

            protected override void Dispose(bool disposing) { 
                //if m_key is null, it means that the base constructor failed 
                if (Interlocked.Exchange(ref m_Disposed, 1) == 0 && m_Key != null)
                { 
                    try {
                        lock (m_Handle)
                        {
                            if (m_CallNesting == 0) 
                                base.Dispose(disposing);
                            else 
                                m_Event = new ManualResetEvent(false); 
                        }
 
                        if (disposing && m_Event != null)
                        {
                            using (m_Event)
                            { 
                                // This assumes that FileStream will never hang on read
                                m_Event.WaitOne(); 
                            } 
                            base.Dispose(disposing);
                        } 
                    }
                    finally {
                        if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_key, "WinInetReadStream.Close()", m_Key));
                        // note, the handle may have been closed earlier if CacheProtocol knew that cache metadata update will not happen. 
                        m_Handle.Close();
                    } 
                } 
            }
 
            public override bool CanTimeout {
                get {
                    return true;
                } 
            }
            public override int ReadTimeout { 
                get { 
                    return m_ReadTimeout;
                } 
                set {
                    m_ReadTimeout = value;
                }
            } 
            public override int WriteTimeout {
                get { 
                    return m_WriteTimeout; 
                }
                set { 
                    m_WriteTimeout = value;
                }
            }
        } 
        //
        // 
        // 
        private class WriteStream: FileStream, ICloseEx {
            private _WinInetCache.Entry m_Entry; 
            private bool m_IsThrow;
            private long m_StreamSize;
            private bool m_Aborted;
            private int m_ReadTimeout; 
            private int m_WriteTimeout;
            private int m_Disposed; 
            private int m_CallNesting; 
            private ManualResetEvent m_Event;
            private bool m_OneWriteSucceeded; 


            [FileIOPermission(SecurityAction.Assert, Unrestricted=true)]
            [ResourceExposure(ResourceScope.Machine)] 
            [ResourceConsumption(ResourceScope.Machine)]
            internal WriteStream(_WinInetCache.Entry entry, bool isThrow, long streamSize, bool async): 
                    base(entry.Filename, FileMode.Create, FileAccess.ReadWrite, FileShare.None, 4096, async) { 

                m_Entry = entry; 
                m_IsThrow = isThrow;
                m_StreamSize = streamSize;
                m_OneWriteSucceeded = streamSize == 0; //if 0 is expected or the lenght is unknonw we will commit even an emtpy stream.
                m_ReadTimeout = m_WriteTimeout = System.Threading.Timeout.Infinite; 
            }
            // 
            public override bool CanTimeout { 
                get {
                    return true; 
                }
            }
            public override int ReadTimeout {
                get { 
                    return m_ReadTimeout;
                } 
                set { 
                    m_ReadTimeout = value;
                } 
            }
            public override int WriteTimeout {
                get {
                    return m_WriteTimeout; 
                }
                set { 
                    m_WriteTimeout = value; 
                }
            } 
            //
            public override void Write(byte[] buffer, int offset, int count)
            {
                lock (m_Entry) 
                {
                    if (m_Aborted) 
                        throw ExceptionHelper.RequestAbortedException; 
                    if (m_Event != null)
                        throw new ObjectDisposedException(GetType().FullName); 

                    try {
                        base.Write(buffer, offset, count);
                        if (m_StreamSize > 0) 
                            m_StreamSize -= count;
                        if (!m_OneWriteSucceeded && count != 0) 
                            m_OneWriteSucceeded = true; 
                    }
                    catch { 
                        m_Aborted = true;
                        throw;
                    }
                    finally { 
                        if (m_Event != null)
                            m_Event.Set(); 
                    } 
                }
            } 
            //
            public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, Object state)
            {
                lock (m_Entry) 
                {
                    if (m_CallNesting != 0) 
                        throw new NotSupportedException(SR.GetString(SR.net_no_concurrent_io_allowed)); 
                    if (m_Aborted)
                        throw ExceptionHelper.RequestAbortedException; 
                    if (m_Event != null)
                        throw new ObjectDisposedException(GetType().FullName);

                    m_CallNesting = 1; 

                    try { 
                        if (m_StreamSize > 0) 
                            m_StreamSize -= count;
                        return base.BeginWrite(buffer, offset, count, callback, state); 
                    }
                    catch {
                        m_Aborted = true;
                        throw; 
                    }
                } 
 
            }
            // 
            public override void EndWrite(IAsyncResult asyncResult)
            {
                lock (m_Entry)
                { 
                    try {
                        base.EndWrite(asyncResult); 
                        if (!m_OneWriteSucceeded) 
                            m_OneWriteSucceeded = true;
                    } 
                    catch {
                        m_Aborted = true;
                        throw;
                    } 
                    finally {
                        if (m_Event != null) 
                            try {m_Event.Set();} catch {}   // the problem is he WaitHandle cannot tell if it is disposed or not 
                        m_CallNesting = 0;
                    } 
                }
            }
            //
            public void CloseEx(CloseExState closeState) 
            {
                // For abnormal stream termination we will commit a partial cache entry 
                if ((closeState & CloseExState.Abort) != 0) 
                    m_Aborted = true;
 
                try {
                    Close();
                }
                catch { 
                    if ((closeState & CloseExState.Silent) == 0)
                        throw; 
                } 
            }
            // 
            [ResourceExposure(ResourceScope.None)]
            [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
            protected override void Dispose(bool disposing)
            { 
                //if m_Entry is null, it means that the base constructor failed
                if (Interlocked.Exchange(ref m_Disposed, 1) == 0 && m_Entry != null) { 
 
                    lock (m_Entry)
                    { 
                        if (m_CallNesting == 0)
                            base.Dispose(disposing);
                        else
                            m_Event = new ManualResetEvent(false); 
                    }
 
                    // 
                    // This assumes the FileStream will never hang on write
                    // 
                    if (disposing && m_Event != null)
                    {
                        using (m_Event)
                        { 
                            m_Event.WaitOne();
                        } 
                        base.Dispose(disposing); 
                    }
 
                    // We use TriState to indicate:
                    //     False:   Delete
                    //     Unknown: Partial
                    //     True:    Full 
                    TriState cacheCommitAction;
                    if (m_StreamSize < 0) 
                    { 
                        if (m_Aborted)
                        { 
                            if (m_OneWriteSucceeded)
                                cacheCommitAction = TriState.Unspecified; // Partial
                            else
                                cacheCommitAction = TriState.False; // Delete 
                        }
                        else 
                        { 
                            cacheCommitAction = TriState.True; // Full
                        } 
                    }
                    else
                    {
                        if (!m_OneWriteSucceeded) 
                        {
                            cacheCommitAction = TriState.False; // Delete 
                        } 
                        else
                        { 
                            if (m_StreamSize > 0)
                                cacheCommitAction = TriState.Unspecified; // Partial
                            else
                                cacheCommitAction = TriState.True; // Full 
                        }
                    } 
 
                    if (cacheCommitAction == TriState.False)
                    { 
                        try
                        {
                            if(Logging.On)Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_no_commit, "WinInetWriteStream.Close()"));
                            // Delete temp cache file 
                            File.Delete(m_Entry.Filename);
                        } 
                        catch (Exception exception) 
                        {
                            if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { 
                                throw;
                            }
                            if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_error_deleting_filename, "WinInetWriteStream.Close()", m_Entry.Filename));
                        } 
                        finally {
                            //Delete an old entry if there was one 
                            _WinInetCache.Status errorStatus = _WinInetCache.Remove(m_Entry); 
                            if (errorStatus != _WinInetCache.Status.Success && errorStatus != _WinInetCache.Status.FileNotFound)
                            { 
                                if(Logging.On)Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_delete_failed, "WinInetWriteStream.Close()", m_Entry.Key, new Win32Exception((int)m_Entry.Error).Message));
                            }

                            m_Entry = null; 
                        }
                        return; 
                    } 

                    m_Entry.OriginalUrl = null; 

                    //
                    // ATTN: WinIent currently does NOT support _WinInetCache.EntryType.Sparse
                    // USING a workaround 
                    //
                    if (cacheCommitAction == TriState.Unspecified) 
                    { 
    // WinInet will not report this entry back we set this flag
    //                    m_Entry.Info.EntryType |= _WinInetCache.EntryType.Sparse;  // does not work for now 

                        // HACK: WinInet does not support SPARSE_ENTRY bit
                        // We want to add c_SPARSE_ENTRY_HACK into the systemmetadata i.e. to the second block of strings separated by an empty line (\r\n).
                        if (m_Entry.MetaInfo == null || m_Entry.MetaInfo.Length == 0 || 
                            (m_Entry.MetaInfo != "\r\n" && m_Entry.MetaInfo.IndexOf("\r\n\r\n", StringComparison.Ordinal) == -1))
                        { 
                            m_Entry.MetaInfo = "\r\n"+ WinInetCache.c_SPARSE_ENTRY_HACK+"\r\n"; 
                        }
                        else 
                        {
                            m_Entry.MetaInfo += WinInetCache.c_SPARSE_ENTRY_HACK+"\r\n";
                        }
                    } 

                    if (_WinInetCache.Commit(m_Entry) != _WinInetCache.Status.Success) 
                    { 
                        if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_commit_failed, "WinInetWriteStream.Close()", m_Entry.Key, new Win32Exception((int)m_Entry.Error).Message));
                        try 
                        {
                            // Delete temp cache file
                            File.Delete(m_Entry.Filename);
                        } 
                        catch (Exception exception)
                        { 
                            if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) { 
                                throw;
                            } 
                            if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_error_deleting_filename, "WinInetWriteStream.Close()", m_Entry.Filename));
                        }

                        if (m_IsThrow) 
                        {
                            Win32Exception win32Exception = new Win32Exception((int)m_Entry.Error); 
                            throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception); 
                        }
                        return; 
                    }

                    if(Logging.On)
                    { 
                        if (m_StreamSize > 0 || (m_StreamSize < 0 && m_Aborted))
                            Logging.PrintWarning(Logging.RequestCache, SR.GetString(SR.net_log_cache_committed_as_partial, "WinInetWriteStream.Close()", m_Entry.Key, (m_StreamSize > 0 ? m_StreamSize.ToString(CultureInfo.CurrentCulture) : SR.GetString(SR.net_log_unknown)))); 
                        Logging.PrintInfo(Logging.RequestCache, "WinInetWriteStream.Close(), Key = " + m_Entry.Key + ", Commit Status = " + m_Entry.Error.ToString()); 
                    }
 

                    if ((m_Entry.Info.EntryType & _WinInetCache.EntryType.StickyEntry) == _WinInetCache.EntryType.StickyEntry)
                    {
                        if (_WinInetCache.Update(m_Entry, _WinInetCache.Entry_FC.ExemptDelta) != _WinInetCache.Status.Success) 
                        {
                            if(Logging.On)Logging.PrintError(Logging.RequestCache, SR.GetString(SR.net_log_cache_update_failed, "WinInetWriteStream.Close(), Key = " + m_Entry.Key, new Win32Exception((int)m_Entry.Error).Message)); 
                            if (m_IsThrow) 
                            {
                                Win32Exception win32Exception = new Win32Exception((int)m_Entry.Error); 
                                throw new IOException(SR.GetString(SR.net_cache_retrieve_failure, win32Exception.Message), win32Exception);
                            }
                            return;
                        } 
                        if(Logging.On)Logging.PrintInfo(Logging.RequestCache, SR.GetString(SR.net_log_cache_max_stale_and_update_status, "WinInetWriteFile.Close()", m_Entry.Info.U.ExemptDelta, m_Entry.Error.ToString()));
                    } 
 
                    base.Dispose(disposing);
                } 
            }
        }
    }
} 

 
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK