The Labs \ Source Viewer \ SSCLI \ System.Net.Cache \ CombinedReadStream

  1. //------------------------------------------------------------------------------
  2. // <copyright file="_CacheStreams.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. /*++   
  16. Abstract:
  17.     The file contains two streams used in conjunction with caching.
  18.     The first class will combine two streams for reading into just one continued stream.
  19.     The second class will forward (as writes) to external stream all reads issued on a "this" stream.
  20. Author:
  21.     Alexei Vopilov    21-Dec-2002
  22. Revision History:
  23. --*/
  24. namespace System.Net.Cache
  25. {
  26.     using System;
  27.     using System.Net;
  28.     using System.IO;
  29.     using System.Threading;
  30.     using System.Collections.Specialized;
  31.    
  32.    
  33.     //
  34.     // This stream will take two Streams (head and tail) and combine them into a single stream
  35.     // Only read IO is supported!
  36.     //
  37.     internal class CombinedReadStream : Stream, ICloseEx
  38.     {
  39.         private Stream m_HeadStream;
  40.         private Stream m_TailStream;
  41.         private bool m_HeadEOF;
  42.         private long m_HeadLength;
  43.         private int m_ReadNesting;
  44.         private AsyncCallback m_ReadCallback;
  45.         //lazy initialized
  46.        
  47.         internal CombinedReadStream(Stream headStream, Stream tailStream)
  48.         {
  49.             m_HeadStream = headStream;
  50.             m_TailStream = tailStream;
  51.             m_HeadEOF = headStream == Stream.Null;
  52.         }
  53.        
  54.         public override bool CanRead {
  55.             get { return m_HeadEOF ? m_TailStream.CanRead : m_HeadStream.CanRead; }
  56.         }
  57.        
  58.         // If CanSeek is false, Position, Seek, Length, and SetLength should throw.
  59.         public override bool CanSeek {
  60.             get { return false; }
  61.         }
  62.        
  63.         public override bool CanWrite {
  64.             get { return false; }
  65.         }
  66.        
  67.         public override long Length {
  68.             get { return m_TailStream.Length + (m_HeadEOF ? m_HeadLength : m_HeadStream.Length); }
  69.         }
  70.        
  71.         public override long Position {
  72.             get { return m_TailStream.Position + (m_HeadEOF ? m_HeadLength : m_HeadStream.Position); }
  73.            
  74.             set {
  75.                 throw new NotSupportedException(SR.GetString(SR.net_noseek));
  76.             }
  77.         }
  78.        
  79.         public override long Seek(long offset, SeekOrigin origin)
  80.         {
  81.             throw new NotSupportedException(SR.GetString(SR.net_noseek));
  82.         }
  83.        
  84.         public override void SetLength(long value)
  85.         {
  86.             throw new NotSupportedException(SR.GetString(SR.net_noseek));
  87.         }
  88.        
  89.         public override void Write(byte[] buffer, int offset, int count)
  90.         {
  91.             throw new NotSupportedException(SR.GetString(SR.net_noseek));
  92.         }
  93.        
  94.         public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
  95.         {
  96.             throw new NotSupportedException(SR.GetString(SR.net_noseek));
  97.         }
  98.        
  99.         public override void EndWrite(IAsyncResult asyncResult)
  100.         {
  101.             throw new NotSupportedException(SR.GetString(SR.net_noseek));
  102.         }
  103.        
  104.         public override void Flush()
  105.         {
  106.         }
  107.        
  108.         public override int Read(byte[] buffer, int offset, int count)
  109.         {
  110.            
  111.             try {
  112.                 if (Interlocked.Increment(ref m_ReadNesting) != 1) {
  113.                     throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, "Read", "read"));
  114.                 }
  115.                
  116.                 if (m_HeadEOF) {
  117.                     return m_TailStream.Read(buffer, offset, count);
  118.                 }
  119.                 else {
  120.                     int result = m_HeadStream.Read(buffer, offset, count);
  121.                     m_HeadLength += result;
  122.                     if (result == 0 && count != 0) {
  123.                         m_HeadEOF = true;
  124.                         m_HeadStream.Close();
  125.                         result = m_TailStream.Read(buffer, offset, count);
  126.                     }
  127.                     return result;
  128.                 }
  129.             }
  130.             finally {
  131.                 Interlocked.Decrement(ref m_ReadNesting);
  132.             }
  133.            
  134.         }
  135.        
  136.        
  137.         //
  138.         // This is a wrapper result used to substitue the AsyncResult returned from m_HeadStream IO
  139.         // Note that once seen a EOF on m_HeadStream we will stop using this wrapper.
  140.         //
  141.         private class InnerAsyncResult : LazyAsyncResult
  142.         {
  143.             public byte[] Buffer;
  144.             public int Offset;
  145.             public int Count;
  146.            
  147.             public InnerAsyncResult(object userState, AsyncCallback userCallback, byte[] buffer, int offset, int count) : base(null, userState, userCallback)
  148.             {
  149.                
  150.                 Buffer = buffer;
  151.                 Offset = offset;
  152.                 Count = count;
  153.             }
  154.            
  155.         }
  156.        
  157.         private void ReadCallback(IAsyncResult transportResult)
  158.         {
  159.             GlobalLog.Assert(transportResult.AsyncState is InnerAsyncResult, "InnerAsyncResult::ReadCallback|The state expected to be of type InnerAsyncResult, received {0}.", transportResult.GetType().FullName);
  160.             if (transportResult.CompletedSynchronously) {
  161.                 return;
  162.             }
  163.            
  164.             InnerAsyncResult userResult = transportResult.AsyncState as InnerAsyncResult;
  165.             try {
  166.                 // Complete transport IO, in this callback that is always the head stream
  167.                 int count;
  168.                 if (!m_HeadEOF) {
  169.                     count = m_HeadStream.EndRead(transportResult);
  170.                     m_HeadLength += count;
  171.                 }
  172.                 else {
  173.                     count = m_TailStream.EndRead(transportResult);
  174.                 }
  175.                
  176.                
  177.                 //check on EOF condition
  178.                 if (!m_HeadEOF && count == 0 && userResult.Count != 0) {
  179.                     //Got a first stream EOF
  180.                     m_HeadEOF = true;
  181.                     m_HeadStream.Close();
  182.                     IAsyncResult ar = m_TailStream.BeginRead(userResult.Buffer, userResult.Offset, userResult.Count, m_ReadCallback, userResult);
  183.                     if (!ar.CompletedSynchronously) {
  184.                         return;
  185.                     }
  186.                     count = m_TailStream.EndRead(ar);
  187.                 }
  188.                 // just complete user IO
  189.                 userResult.Buffer = null;
  190.                 userResult.InvokeCallback(count);
  191.             }
  192.             catch (Exception e) {
  193.                 //ASYNC: try to swallow even serious exceptions (nothing to loose?)
  194.                 if (userResult.InternalPeekCompleted)
  195.                     throw;
  196.                
  197.                 userResult.InvokeCallback(e);
  198.             }
  199.             catch {
  200.                 //ASYNC: try to swallow even serious exceptions (nothing to loose?)
  201.                 if (userResult.InternalPeekCompleted)
  202.                     throw;
  203.                
  204.                 userResult.InvokeCallback(new Exception(SR.GetString(SR.net_nonClsCompliantException)));
  205.             }
  206.         }
  207.        
  208.         public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
  209.         {
  210.             try {
  211.                 if (Interlocked.Increment(ref m_ReadNesting) != 1) {
  212.                     throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, "BeginRead", "read"));
  213.                 }
  214.                
  215.                 if (m_ReadCallback == null) {
  216.                     m_ReadCallback = new AsyncCallback(ReadCallback);
  217.                 }
  218.                
  219.                 if (m_HeadEOF) {
  220.                     return m_TailStream.BeginRead(buffer, offset, count, callback, state);
  221.                 }
  222.                 else {
  223.                     InnerAsyncResult userResult = new InnerAsyncResult(state, callback, buffer, offset, count);
  224.                     IAsyncResult ar = m_HeadStream.BeginRead(buffer, offset, count, m_ReadCallback, userResult);
  225.                    
  226.                     if (!ar.CompletedSynchronously) {
  227.                         return userResult;
  228.                     }
  229.                    
  230.                     int bytes = m_HeadStream.EndRead(ar);
  231.                     m_HeadLength += bytes;
  232.                    
  233.                     //check on EOF condition
  234.                     if (bytes == 0 && userResult.Count != 0) {
  235.                         //Got a first stream EOF
  236.                         m_HeadEOF = true;
  237.                         m_HeadStream.Close();
  238.                         return m_TailStream.BeginRead(buffer, offset, count, callback, state);
  239.                     }
  240.                     else {
  241.                         // just complete user IO
  242.                         userResult.Buffer = null;
  243.                         userResult.InvokeCallback(count);
  244.                         return userResult;
  245.                     }
  246.                    
  247.                 }
  248.             }
  249.             catch {
  250.                 Interlocked.Decrement(ref m_ReadNesting);
  251.                 throw;
  252.             }
  253.         }
  254.        
  255.         public override int EndRead(IAsyncResult asyncResult)
  256.         {
  257.            
  258.             if (Interlocked.Decrement(ref m_ReadNesting) != 0) {
  259.                 Interlocked.Increment(ref m_ReadNesting);
  260.                 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndRead"));
  261.             }
  262.            
  263.             if (asyncResult == null) {
  264.                 throw new ArgumentNullException("asyncResult");
  265.             }
  266.            
  267.             InnerAsyncResult myResult = asyncResult as InnerAsyncResult;
  268.            
  269.             if (myResult == null) {
  270.                 // We are just passing IO down, although m_HeadEOF should be always true here.
  271.                 GlobalLog.Assert(m_HeadEOF, "CombinedReadStream::EndRead|m_HeadEOF is false and asyncResult is not of InnerAsyncResult type {0).", asyncResult.GetType().FullName);
  272.                 return m_HeadEOF ? m_TailStream.EndRead(asyncResult) : m_HeadStream.EndRead(asyncResult);
  273.             }
  274.            
  275.             // this is our wrapped AsyncResult
  276.             myResult.InternalWaitForCompletion();
  277.            
  278.             // Exception?
  279.             if (myResult.Result is Exception) {
  280.                 throw (Exception)(myResult.Result);
  281.             }
  282.            
  283.             // Report the count read
  284.             return (int)myResult.Result;
  285.         }
  286.        
  287.         // Subclasses should use Dispose(bool, CloseExState)
  288.         protected override sealed void Dispose(bool disposing)
  289.         {
  290.             Dispose(disposing, CloseExState.Normal);
  291.             GC.SuppressFinalize(this);
  292.         }
  293.        
  294.         void ICloseEx.CloseEx(CloseExState closeState)
  295.         {
  296.             Dispose(true, closeState);
  297.             GC.SuppressFinalize(this);
  298.         }
  299.        
  300.         protected virtual void Dispose(bool disposing, CloseExState closeState)
  301.         {
  302.            
  303.             // All below calls should already be idempotent
  304.            
  305.             try {
  306.                 if (!m_HeadEOF) {
  307.                     ICloseEx icloseEx = m_HeadStream as ICloseEx;
  308.                     if (icloseEx != null) {
  309.                         icloseEx.CloseEx(closeState);
  310.                     }
  311.                     else {
  312.                         m_HeadStream.Close();
  313.                     }
  314.                 }
  315.             }
  316.             finally {
  317.                 ICloseEx icloseEx = m_TailStream as ICloseEx;
  318.                 if (icloseEx != null) {
  319.                     icloseEx.CloseEx(closeState);
  320.                 }
  321.                 else {
  322.                     m_TailStream.Close();
  323.                 }
  324.             }
  325.            
  326.             if (!disposing) {
  327.                 m_HeadStream = null;
  328.                 m_TailStream = null;
  329.             }
  330.         }
  331.        
  332.         public override bool CanTimeout {
  333.             get { return m_TailStream.CanTimeout && m_HeadStream.CanTimeout; }
  334.         }
  335.        
  336.         public override int ReadTimeout {
  337.             get { return (m_HeadEOF) ? m_TailStream.ReadTimeout : m_HeadStream.ReadTimeout; }
  338.             set { m_TailStream.ReadTimeout = m_HeadStream.ReadTimeout = value; }
  339.         }
  340.        
  341.         public override int WriteTimeout {
  342.             get { return (m_HeadEOF) ? m_TailStream.WriteTimeout : m_HeadStream.WriteTimeout; }
  343.             set { m_TailStream.WriteTimeout = m_HeadStream.WriteTimeout = value; }
  344.         }
  345.     }
  346.    
  347.     //
  348.     // This stream will plug into a stream and listen for all reads on it
  349.     // It is also constructed with yet another stream used for multiplexing IO to
  350.     //
  351.     // When it sees a read on this stream the result gets forwarded as write to a shadow stream.
  352.     // ONLY READ IO is supported!
  353.     //
  354.     internal class ForwardingReadStream : Stream, ICloseEx
  355.     {
  356.         private Stream m_OriginalStream;
  357.         private Stream m_ShadowStream;
  358.         private int m_ReadNesting;
  359.         private bool m_ShadowStreamIsDead;
  360.         private AsyncCallback m_ReadCallback;
  361.         // lazy initialized
  362.         private long m_BytesToSkip;
  363.         // suppress from the read first number of bytes
  364.         private bool m_ThrowOnWriteError;
  365.         private bool m_SeenReadEOF;
  366.        
  367.        
  368.         internal ForwardingReadStream(Stream originalStream, Stream shadowStream, long bytesToSkip, bool throwOnWriteError)
  369.         {
  370.             if (!shadowStream.CanWrite) {
  371.                 throw new ArgumentException(SR.GetString(SR.net_cache_shadowstream_not_writable), "shadowStream");
  372.             }
  373.             m_OriginalStream = originalStream;
  374.             m_ShadowStream = shadowStream;
  375.             m_BytesToSkip = bytesToSkip;
  376.             m_ThrowOnWriteError = throwOnWriteError;
  377.         }
  378.        
  379.         public override bool CanRead {
  380.             get { return m_OriginalStream.CanRead; }
  381.         }
  382.        
  383.         // If CanSeek is false, Position, Seek, Length, and SetLength should throw.
  384.         public override bool CanSeek {
  385.             get { return false; }
  386.         }
  387.        
  388.         public override bool CanWrite {
  389.             get { return false; }
  390.         }
  391.        
  392.         public override long Length {
  393.             get { return m_OriginalStream.Length - m_BytesToSkip; }
  394.         }
  395.        
  396.         public override long Position {
  397.             get { return m_OriginalStream.Position - m_BytesToSkip; }
  398.            
  399.             set {
  400.                 throw new NotSupportedException(SR.GetString(SR.net_noseek));
  401.             }
  402.         }
  403.        
  404.         public override long Seek(long offset, SeekOrigin origin)
  405.         {
  406.             throw new NotSupportedException(SR.GetString(SR.net_noseek));
  407.         }
  408.        
  409.         public override void SetLength(long value)
  410.         {
  411.             throw new NotSupportedException(SR.GetString(SR.net_noseek));
  412.         }
  413.        
  414.         public override void Write(byte[] buffer, int offset, int count)
  415.         {
  416.             throw new NotSupportedException(SR.GetString(SR.net_noseek));
  417.         }
  418.        
  419.         public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
  420.         {
  421.             throw new NotSupportedException(SR.GetString(SR.net_noseek));
  422.         }
  423.        
  424.         public override void EndWrite(IAsyncResult asyncResult)
  425.         {
  426.             throw new NotSupportedException(SR.GetString(SR.net_noseek));
  427.         }
  428.        
  429.         public override void Flush()
  430.         {
  431.         }
  432.        
  433.         public override int Read(byte[] buffer, int offset, int count)
  434.         {
  435.            
  436.             bool isDoingWrite = false;
  437.             int result = -1;
  438.             if (Interlocked.Increment(ref m_ReadNesting) != 1) {
  439.                 throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, "Read", "read"));
  440.             }
  441.            
  442.             try {
  443.                
  444.                 if (m_BytesToSkip != 0l) {
  445.                     // Sometime we want to combine cached + live stream AND the user requested explicit range starts from not 0
  446.                     byte[] tempBuffer = new byte[4096];
  447.                     while (m_BytesToSkip != 0l) {
  448.                         int bytes = m_OriginalStream.Read(tempBuffer, 0, (m_BytesToSkip < (long)tempBuffer.Length ? (int)m_BytesToSkip : tempBuffer.Length));
  449.                         if (bytes == 0)
  450.                             m_SeenReadEOF = true;
  451.                        
  452.                         m_BytesToSkip -= bytes;
  453.                         if (!m_ShadowStreamIsDead)
  454.                             m_ShadowStream.Write(tempBuffer, 0, bytes);
  455.                     }
  456.                 }
  457.                
  458.                 result = m_OriginalStream.Read(buffer, offset, count);
  459.                 if (result == 0)
  460.                     m_SeenReadEOF = true;
  461.                
  462.                 if (m_ShadowStreamIsDead) {
  463.                     return result;
  464.                 }
  465.                 isDoingWrite = true;
  466.                 m_ShadowStream.Write(buffer, offset, result);
  467.                 return result;
  468.             }
  469.             catch (Exception e) {
  470.                 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
  471.                     throw;
  472.                
  473.                 GlobalLog.Print("ShadowReadStream::Read() Got Exception, disabling the shadow stream, stack trace = " + e.ToString());
  474.                 if (!m_ShadowStreamIsDead) {
  475.                     // try to swallow even serious exception, since got nothing to loose?
  476.                     m_ShadowStreamIsDead = true;
  477.                     try {
  478.                         if (m_ShadowStream is ICloseEx)
  479.                             ((ICloseEx)m_ShadowStream).CloseEx(CloseExState.Abort | CloseExState.Silent);
  480.                         else
  481.                             m_ShadowStream.Close();
  482.                     }
  483.                     catch (Exception ee) {
  484.                         if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
  485.                             throw;
  486.                         GlobalLog.Print("ShadowReadStream::Read() Got (ignoring) Exception, on shadow stream.Close, stack trace = " + ee.ToString());
  487.                     }
  488.                     catch {
  489.                         GlobalLog.Print("ShadowReadStream::Read() Got (ignoring) Exception, on shadow stream.Close, stack trace = Non-CLS Compliant Exception");
  490.                     }
  491.                 }
  492.                 if (!isDoingWrite || m_ThrowOnWriteError)
  493.                     throw;
  494.                
  495.                 return result;
  496.             }
  497.             catch {
  498.                 GlobalLog.Print("ShadowReadStream::Read() Got Exception, disabling the shadow stream, stack trace = Non-CLS Compliant Exception");
  499.                 if (!m_ShadowStreamIsDead) {
  500.                     // try to swallow even serious exception, since got nothing to loose?
  501.                     m_ShadowStreamIsDead = true;
  502.                     try {
  503.                         if (m_ShadowStream is ICloseEx)
  504.                             ((ICloseEx)m_ShadowStream).CloseEx(CloseExState.Abort | CloseExState.Silent);
  505.                         else
  506.                             m_ShadowStream.Close();
  507.                     }
  508.                     catch (Exception ee) {
  509.                         if (NclUtilities.IsFatal(ee))
  510.                             throw;
  511.                         GlobalLog.Print("ShadowReadStream::Read() Got (ignoring) Exception, on shadow stream.Close, stack trace = " + ee.ToString());
  512.                     }
  513.                     catch {
  514.                         GlobalLog.Print("ShadowReadStream::Read() Got (ignoring) Exception, on shadow stream.Close, stack trace = Non-CLS Compliant Exception");
  515.                     }
  516.                 }
  517.                 if (!isDoingWrite || m_ThrowOnWriteError)
  518.                     throw;
  519.                
  520.                 return result;
  521.             }
  522.             finally {
  523.                 Interlocked.Decrement(ref m_ReadNesting);
  524.             }
  525.         }
  526.        
  527.        
  528.         //
  529.         // This is a wrapper result used to substitue the AsyncResult returned from m_OriginalStream IO
  530.         // Note that once seen a m_ShadowStream error we will stop using this wrapper.
  531.         //
  532.         private class InnerAsyncResult : LazyAsyncResult
  533.         {
  534.             public byte[] Buffer;
  535.             public int Offset;
  536.             public int Count;
  537.             public bool IsWriteCompletion;
  538.            
  539.             public InnerAsyncResult(object userState, AsyncCallback userCallback, byte[] buffer, int offset, int count) : base(null, userState, userCallback)
  540.             {
  541.                
  542.                 Buffer = buffer;
  543.                 Offset = offset;
  544.                 Count = count;
  545.             }
  546.            
  547.         }
  548.        
  549.         private void ReadCallback(IAsyncResult transportResult)
  550.         {
  551.             GlobalLog.Assert(transportResult.AsyncState is InnerAsyncResult, "InnerAsyncResult::ReadCallback|The state expected to be of type InnerAsyncResult, received {0}.", transportResult.GetType().FullName);
  552.             if (transportResult.CompletedSynchronously) {
  553.                 return;
  554.             }
  555.            
  556.             // Recover our asyncResult
  557.             InnerAsyncResult userResult = transportResult.AsyncState as InnerAsyncResult;
  558.            
  559.             ReadComplete(transportResult);
  560.         }
  561.        
  562.         private void ReadComplete(IAsyncResult transportResult)
  563.         {
  564.             while (true) {
  565.                 // Recover our asyncResult
  566.                 InnerAsyncResult userResult = transportResult.AsyncState as InnerAsyncResult;
  567.                
  568.                 try {
  569.                     if (!userResult.IsWriteCompletion) {
  570.                         userResult.Count = m_OriginalStream.EndRead(transportResult);
  571.                         if (userResult.Count == 0)
  572.                             m_SeenReadEOF = true;
  573.                        
  574.                        
  575.                         if (!m_ShadowStreamIsDead) {
  576.                             userResult.IsWriteCompletion = true;
  577.                             //Optionally charge notification write IO
  578.                             transportResult = m_ShadowStream.BeginWrite(userResult.Buffer, userResult.Offset, userResult.Count, m_ReadCallback, userResult);
  579.                             if (transportResult.CompletedSynchronously) {
  580.                                 continue;
  581.                             }
  582.                             return;
  583.                         }
  584.                     }
  585.                     else {
  586.                         GlobalLog.Assert(!m_ShadowStreamIsDead, "ForwardingReadStream::ReadComplete|ERROR: IsWriteCompletion && m_ShadowStreamIsDead");
  587.                        
  588.                         m_ShadowStream.EndWrite(transportResult);
  589.                         userResult.IsWriteCompletion = false;
  590.                     }
  591.                 }
  592.                 catch (Exception e) {
  593.                     //ASYNC: try to swallow even serious exceptions (nothing to loose?)
  594.                     if (userResult.InternalPeekCompleted) {
  595.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Rethrowing Exception (end), userResult.IsCompleted, stack trace = " + e.ToString());
  596.                         throw;
  597.                     }
  598.                    
  599.                     try {
  600.                         m_ShadowStreamIsDead = true;
  601.                         if (m_ShadowStream is ICloseEx)
  602.                             ((ICloseEx)m_ShadowStream).CloseEx(CloseExState.Abort | CloseExState.Silent);
  603.                         else
  604.                             m_ShadowStream.Close();
  605.                     }
  606.                     catch (Exception ee) {
  607.                         //ASYNC: Again try to swallow even serious exceptions
  608.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Got (ignoring) Exception, on shadow stream.Close, stack trace = " + ee.ToString());
  609.                     }
  610.                     catch {
  611.                         //ASYNC: Again try to swallow even serious exceptions
  612.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Got (ignoring) Exception, on shadow stream.Close, stack trace = Non-CLS Compliant Exception");
  613.                     }
  614.                    
  615.                     if (!userResult.IsWriteCompletion || m_ThrowOnWriteError) {
  616.                         if (transportResult.CompletedSynchronously) {
  617.                             throw;
  618.                         }
  619.                        
  620.                         userResult.InvokeCallback(e);
  621.                         return;
  622.                     }
  623.                 }
  624.                 catch {
  625.                     //ASYNC: try to swallow even serious exceptions (nothing to loose?)
  626.                     if (userResult.InternalPeekCompleted) {
  627.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Rethrowing Exception (end), userResult.IsCompleted, stack trace = Non-CLS Compliant Exception");
  628.                         throw;
  629.                     }
  630.                    
  631.                     try {
  632.                         m_ShadowStreamIsDead = true;
  633.                         if (m_ShadowStream is ICloseEx)
  634.                             ((ICloseEx)m_ShadowStream).CloseEx(CloseExState.Abort | CloseExState.Silent);
  635.                         else
  636.                             m_ShadowStream.Close();
  637.                     }
  638.                     catch (Exception ee) {
  639.                         //ASYNC: Again try to swallow even serious exceptions
  640.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Got (ignoring) Exception, on shadow stream.Close, stack trace = " + ee.ToString());
  641.                     }
  642.                     catch {
  643.                         //ASYNC: Again try to swallow even serious exceptions
  644.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Got (ignoring) Exception, on shadow stream.Close, stack trace = Non-CLS Compliant Exception");
  645.                     }
  646.                    
  647.                     if (!userResult.IsWriteCompletion || m_ThrowOnWriteError) {
  648.                         if (transportResult.CompletedSynchronously) {
  649.                             throw;
  650.                         }
  651.                        
  652.                         userResult.InvokeCallback(new Exception(SR.GetString(SR.net_nonClsCompliantException)));
  653.                         return;
  654.                     }
  655.                 }
  656.                
  657.                 // Need to process, re-issue the read.
  658.                 try {
  659.                     if (m_BytesToSkip != 0l) {
  660.                         m_BytesToSkip -= userResult.Count;
  661.                         userResult.Count = m_BytesToSkip < (long)userResult.Buffer.Length ? (int)m_BytesToSkip : userResult.Buffer.Length;
  662.                         if (m_BytesToSkip == 0l) {
  663.                             // we did hide the original IO request in the outer iaresult state.
  664.                             // charge the real user operation now
  665.                             transportResult = userResult;
  666.                             userResult = userResult.AsyncState as InnerAsyncResult;
  667.                             GlobalLog.Assert(userResult != null, "ForwardingReadStream::ReadComplete|ERROR: Inner IAResult is null after stream FastForwarding.");
  668.                         }
  669.                         transportResult = m_OriginalStream.BeginRead(userResult.Buffer, userResult.Offset, userResult.Count, m_ReadCallback, userResult);
  670.                         if (transportResult.CompletedSynchronously) {
  671.                             continue;
  672.                         }
  673.                         return;
  674.                     }
  675.                     //if came to here, complete original user IO
  676.                     userResult.InvokeCallback(userResult.Count);
  677.                     return;
  678.                 }
  679.                 catch (Exception e) {
  680.                     //ASYNC: try to swallow even serious exceptions (nothing to loose?)
  681.                     if (userResult.InternalPeekCompleted) {
  682.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Rethrowing Exception (begin), userResult.IsCompleted, stack trace = " + e.ToString());
  683.                         throw;
  684.                     }
  685.                    
  686.                     try {
  687.                         m_ShadowStreamIsDead = true;
  688.                         if (m_ShadowStream is ICloseEx)
  689.                             ((ICloseEx)m_ShadowStream).CloseEx(CloseExState.Abort | CloseExState.Silent);
  690.                         else
  691.                             m_ShadowStream.Close();
  692.                     }
  693.                     catch (Exception ee) {
  694.                         //ASYNC: Again try to swallow even serious exceptions
  695.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Got (ignoring) Exception, on shadow stream.Close (after begin), stack trace = " + ee.ToString());
  696.                     }
  697.                     catch {
  698.                         //ASYNC: Again try to swallow even serious exceptions
  699.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Got (ignoring) Exception, on shadow stream.Close (after begin), stack trace = Non-CLS Compliant Exception");
  700.                     }
  701.                    
  702.                     if (transportResult.CompletedSynchronously) {
  703.                         throw;
  704.                     }
  705.                    
  706.                     // This will set the exception result first then try to execute a user callback
  707.                     userResult.InvokeCallback(e);
  708.                     return;
  709.                 }
  710.                 catch {
  711.                     //ASYNC: try to swallow even serious exceptions (nothing to loose?)
  712.                     if (userResult.InternalPeekCompleted) {
  713.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Rethrowing Exception (begin), userResult.IsCompleted, stack trace = Non-CLS Compliant Exception");
  714.                         throw;
  715.                     }
  716.                    
  717.                     try {
  718.                         m_ShadowStreamIsDead = true;
  719.                         if (m_ShadowStream is ICloseEx)
  720.                             ((ICloseEx)m_ShadowStream).CloseEx(CloseExState.Abort | CloseExState.Silent);
  721.                         else
  722.                             m_ShadowStream.Close();
  723.                     }
  724.                     catch (Exception ee) {
  725.                         //ASYNC: Again try to swallow even serious exceptions
  726.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Got (ignoring) Exception, on shadow stream.Close (after begin), stack trace = " + ee.ToString());
  727.                     }
  728.                     catch {
  729.                         //ASYNC: Again try to swallow even serious exceptions
  730.                         GlobalLog.Print("ShadowReadStream::ReadComplete() Got (ignoring) Exception, on shadow stream.Close (after begin), stack trace = Non-CLS Compliant Exception");
  731.                     }
  732.                    
  733.                     if (transportResult.CompletedSynchronously) {
  734.                         throw;
  735.                     }
  736.                    
  737.                     // This will set the exception result first then try to execute a user callback
  738.                     userResult.InvokeCallback(new Exception(SR.GetString(SR.net_nonClsCompliantException)));
  739.                     return;
  740.                 }
  741.             }
  742.         }
  743.        
  744.         public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
  745.         {
  746.             if (Interlocked.Increment(ref m_ReadNesting) != 1) {
  747.                 throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, "BeginRead", "read"));
  748.             }
  749.            
  750.             try {
  751.                
  752.                 if (m_ReadCallback == null) {
  753.                     m_ReadCallback = new AsyncCallback(ReadCallback);
  754.                 }
  755.                
  756.                 if (m_ShadowStreamIsDead && m_BytesToSkip == 0l) {
  757.                     return m_OriginalStream.BeginRead(buffer, offset, count, callback, state);
  758.                 }
  759.                 else {
  760.                     InnerAsyncResult userResult = new InnerAsyncResult(state, callback, buffer, offset, count);
  761.                     if (m_BytesToSkip != 0l) {
  762.                         InnerAsyncResult temp = userResult;
  763.                         userResult = new InnerAsyncResult(temp, null, new byte[4096], 0, m_BytesToSkip < (long)buffer.Length ? (int)m_BytesToSkip : buffer.Length);
  764.                     }
  765.                     IAsyncResult result = m_OriginalStream.BeginRead(userResult.Buffer, userResult.Offset, userResult.Count, m_ReadCallback, userResult);
  766.                     if (result.CompletedSynchronously) {
  767.                         ReadComplete(result);
  768.                     }
  769.                     return userResult;
  770.                 }
  771.             }
  772.             catch {
  773.                 Interlocked.Decrement(ref m_ReadNesting);
  774.                 throw;
  775.             }
  776.         }
  777.        
  778.         public override int EndRead(IAsyncResult asyncResult)
  779.         {
  780.            
  781.             if (Interlocked.Decrement(ref m_ReadNesting) != 0) {
  782.                 Interlocked.Increment(ref m_ReadNesting);
  783.                 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndRead"));
  784.             }
  785.            
  786.             if (asyncResult == null) {
  787.                 throw new ArgumentNullException("asyncResult");
  788.             }
  789.            
  790.             InnerAsyncResult myResult = asyncResult as InnerAsyncResult;
  791.            
  792.             if (myResult == null) {
  793.                 // We are just passing IO down, although the shadow stream should be dead for now.
  794.                 GlobalLog.Assert(m_ShadowStreamIsDead, "ForwardingReadStream::EndRead|m_ShadowStreamIsDead is false and asyncResult is not of InnerAsyncResult type {0}.", asyncResult.GetType().FullName);
  795.                 int bytes = m_OriginalStream.EndRead(asyncResult);
  796.                 if (bytes == 0)
  797.                     m_SeenReadEOF = true;
  798.             }
  799.            
  800.             // this is our wrapped AsyncResult
  801.             bool suceess = false;
  802.             try {
  803.                 myResult.InternalWaitForCompletion();
  804.                 // Exception?
  805.                 if (myResult.Result is Exception)
  806.                     throw (Exception)(myResult.Result);
  807.                 suceess = true;
  808.             }
  809.             finally {
  810.                 if (!suceess && !m_ShadowStreamIsDead) {
  811.                     m_ShadowStreamIsDead = true;
  812.                     if (m_ShadowStream is ICloseEx)
  813.                         ((ICloseEx)m_ShadowStream).CloseEx(CloseExState.Abort | CloseExState.Silent);
  814.                     else
  815.                         m_ShadowStream.Close();
  816.                 }
  817.             }
  818.            
  819.             // Report the read count
  820.             return (int)myResult.Result;
  821.         }
  822.        
  823.         // Subclasses should use Dispose(bool, CloseExState)
  824.         protected override sealed void Dispose(bool disposing)
  825.         {
  826.             Dispose(disposing, CloseExState.Normal);
  827.             GC.SuppressFinalize(this);
  828.         }
  829.        
  830.         private int _Disposed;
  831.         void ICloseEx.CloseEx(CloseExState closeState)
  832.         {
  833.            
  834.             if (Interlocked.Increment(ref _Disposed) == 1) {
  835.                 // This would allow us to cache the response stream that user throws away
  836.                 // Next time the cached version could save us from an extra roundtrip
  837.                 if (closeState == CloseExState.Silent) {
  838.                     try {
  839.                         int total = 0;
  840.                         int bytesRead;
  841.                         while (total < ConnectStream.s_DrainingBuffer.Length && (bytesRead = Read(ConnectStream.s_DrainingBuffer, 0, ConnectStream.s_DrainingBuffer.Length)) > 0) {
  842.                             total += bytesRead;
  843.                         }
  844.                     }
  845.                     catch (Exception exception) {
  846.                         //ATTN: this path will swalow errors regardless of m_IsThrowOnWriteError setting
  847.                         // A "Silent" close is for an intermediate response that is to be ignored anyway
  848.                         if (exception is ThreadAbortException || exception is StackOverflowException || exception is OutOfMemoryException) {
  849.                             throw;
  850.                         }
  851.                     }
  852.                     catch {
  853.                         //ATTN: this path will swalow errors regardless of m_IsThrowOnWriteError setting
  854.                         // A "Silent" close is for an intermediate response that is to be ignored anyway
  855.                     }
  856.                 }
  857.                
  858.                 Dispose(true, closeState);
  859.                 GC.SuppressFinalize(this);
  860.             }
  861.         }
  862.        
  863.         protected virtual void Dispose(bool disposing, CloseExState closeState)
  864.         {
  865.            
  866.             // All below calls should already be idempotent
  867.            
  868.             try {
  869.                 ICloseEx icloseEx = m_OriginalStream as ICloseEx;
  870.                 if (icloseEx != null) {
  871.                     icloseEx.CloseEx(closeState);
  872.                 }
  873.                 else {
  874.                     m_OriginalStream.Close();
  875.                 }
  876.             }
  877.             finally {
  878.                
  879.                 // Notify the wirte stream on a partial response if did not see EOF on read
  880.                 if (!m_SeenReadEOF)
  881.                     closeState |= CloseExState.Abort;
  882.                
  883.                 //
  884.                 // We don't want to touch m_ShadowStreamIsDead because Close() can be called from other thread while IO is in progress.
  885.                 // We assume that all streams used by this class are thread safe on Close().
  886.                 // m_ShadowStreamIsDead = true;
  887.                
  888.                 if (m_ShadowStream is ICloseEx)
  889.                     ((ICloseEx)m_ShadowStream).CloseEx(closeState);
  890.                 else
  891.                     m_ShadowStream.Close();
  892.             }
  893.            
  894.             if (!disposing) {
  895.                 // no IO can be in progress because it a GC thread.
  896.                 m_OriginalStream = null;
  897.                 m_ShadowStream = null;
  898.             }
  899.             base.Dispose(disposing);
  900.         }
  901.        
  902.         public override bool CanTimeout {
  903.             get { return m_OriginalStream.CanTimeout && m_ShadowStream.CanTimeout; }
  904.         }
  905.        
  906.         public override int ReadTimeout {
  907.             get { return m_OriginalStream.ReadTimeout; }
  908.             set { m_OriginalStream.ReadTimeout = m_ShadowStream.ReadTimeout = value; }
  909.         }
  910.        
  911.         public override int WriteTimeout {
  912.             get { return m_ShadowStream.WriteTimeout; }
  913.             set { m_OriginalStream.WriteTimeout = m_ShadowStream.WriteTimeout = value; }
  914.         }
  915.     }
  916.    
  917.     //
  918.     // This stream will listen on the parent stream Close.
  919.     // Assuming the parent stream represents a READ stream such as CombinedReadStream or a response stream.
  920.     // When the paretn stream is closed this wrapper will update the metadata associated with the entry.
  921.     internal class MetadataUpdateStream : Stream, ICloseEx
  922.     {
  923.         private Stream m_ParentStream;
  924.         private RequestCache m_Cache;
  925.         private string m_Key;
  926.         private DateTime m_Expires;
  927.         private DateTime m_LastModified;
  928.         private DateTime m_LastSynchronized;
  929.         private TimeSpan m_MaxStale;
  930.         private StringCollection m_EntryMetadata;
  931.         private StringCollection m_SystemMetadata;
  932.         private bool m_CacheDestroy;
  933.         private bool m_IsStrictCacheErrors;
  934.        
  935.        
  936.         internal MetadataUpdateStream(Stream parentStream, RequestCache cache, string key, DateTime expiresGMT, DateTime lastModifiedGMT, DateTime lastSynchronizedGMT, TimeSpan maxStale, StringCollection entryMetadata, StringCollection systemMetadata, bool isStrictCacheErrors
  937.         ) : base()
  938.         {
  939.             if (parentStream == null)
  940.                 throw new ArgumentNullException("parentStream");
  941.            
  942.             m_ParentStream = parentStream;
  943.             m_Cache = cache;
  944.             m_Key = key;
  945.             m_Expires = expiresGMT;
  946.             m_LastModified = lastModifiedGMT;
  947.             m_LastSynchronized = lastSynchronizedGMT;
  948.             m_MaxStale = maxStale;
  949.             m_EntryMetadata = entryMetadata;
  950.             m_SystemMetadata = systemMetadata;
  951.             m_IsStrictCacheErrors = isStrictCacheErrors;
  952.         }
  953.        
  954.         //
  955.         // This constructor will result in removing a cache entry upon closure
  956.         //
  957.         private MetadataUpdateStream(Stream parentStream, RequestCache cache, string key, bool isStrictCacheErrors) : base()
  958.         {
  959.             if (parentStream == null)
  960.                 throw new ArgumentNullException("parentStream");
  961.            
  962.             m_ParentStream = parentStream;
  963.             m_Cache = cache;
  964.             m_Key = key;
  965.             m_CacheDestroy = true;
  966.             m_IsStrictCacheErrors = isStrictCacheErrors;
  967.         }
  968.         //
  969.         //
  970.         //
  971. /*
  972.         //                                   
  973.         public static Stream CreateEntryRemovalStream(  Stream parentStream, RequestCache cache, string key, bool isStrictCacheErrors)
  974.         {
  975.             return new MetadataUpdateStream(parentStream, cache, key, isStrictCacheErrors);
  976.         }
  977.         */       
  978.         //
  979.         public override bool CanRead {
  980.             get { return m_ParentStream.CanRead; }
  981.         }
  982.         //
  983.         // If CanSeek is false, Position, Seek, Length, and SetLength should throw.
  984.         public override bool CanSeek {
  985.             get { return m_ParentStream.CanSeek; }
  986.         }
  987.         //
  988.         public override bool CanWrite {
  989.             get { return m_ParentStream.CanWrite; }
  990.         }
  991.         //
  992.         public override long Length {
  993.             get { return m_ParentStream.Length; }
  994.         }
  995.         //
  996.         public override long Position {
  997.             get { return m_ParentStream.Position; }
  998.            
  999.             set { m_ParentStream.Position = value; }
  1000.         }
  1001.        
  1002.         public override long Seek(long offset, SeekOrigin origin)
  1003.         {
  1004.             return m_ParentStream.Seek(offset, origin);
  1005.         }
  1006.        
  1007.         public override void SetLength(long value)
  1008.         {
  1009.             m_ParentStream.SetLength(value);
  1010.         }
  1011.        
  1012.         public override void Write(byte[] buffer, int offset, int count)
  1013.         {
  1014.             m_ParentStream.Write(buffer, offset, count);
  1015.         }
  1016.        
  1017.         public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
  1018.         {
  1019.             return m_ParentStream.BeginWrite(buffer, offset, count, callback, state);
  1020.         }
  1021.        
  1022.         public override void EndWrite(IAsyncResult asyncResult)
  1023.         {
  1024.             m_ParentStream.EndWrite(asyncResult);
  1025.         }
  1026.        
  1027.         public override void Flush()
  1028.         {
  1029.             m_ParentStream.Flush();
  1030.         }
  1031.        
  1032.         public override int Read(byte[] buffer, int offset, int count)
  1033.         {
  1034.             return m_ParentStream.Read(buffer, offset, count);
  1035.         }
  1036.        
  1037.         public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
  1038.         {
  1039.             return m_ParentStream.BeginRead(buffer, offset, count, callback, state);
  1040.         }
  1041.        
  1042.         public override int EndRead(IAsyncResult asyncResult)
  1043.         {
  1044.             return m_ParentStream.EndRead(asyncResult);
  1045.         }
  1046.        
  1047.         // Subclasses should use Dispose(bool, CloseExState)
  1048.         protected override sealed void Dispose(bool disposing)
  1049.         {
  1050.             Dispose(disposing, CloseExState.Normal);
  1051.             GC.SuppressFinalize(this);
  1052.         }
  1053.        
  1054.         void ICloseEx.CloseEx(CloseExState closeState)
  1055.         {
  1056.             Dispose(true, closeState);
  1057.         }
  1058.        
  1059.         public override bool CanTimeout {
  1060.             get { return m_ParentStream.CanTimeout; }
  1061.         }
  1062.        
  1063.         public override int ReadTimeout {
  1064.             get { return m_ParentStream.ReadTimeout; }
  1065.             set { m_ParentStream.ReadTimeout = value; }
  1066.         }
  1067.        
  1068.         public override int WriteTimeout {
  1069.             get { return m_ParentStream.WriteTimeout; }
  1070.             set { m_ParentStream.WriteTimeout = value; }
  1071.         }
  1072.        
  1073.         private int _Disposed;
  1074.         protected virtual void Dispose(bool disposing, CloseExState closeState)
  1075.         {
  1076.            
  1077.             if (Interlocked.Increment(ref _Disposed) == 1) {
  1078.                 ICloseEx icloseEx = m_ParentStream as ICloseEx;
  1079.                
  1080.                 if (icloseEx != null) {
  1081.                     icloseEx.CloseEx(closeState);
  1082.                 }
  1083.                 else {
  1084.                     m_ParentStream.Close();
  1085.                 }
  1086.                
  1087.                 if (m_CacheDestroy) {
  1088.                     if (m_IsStrictCacheErrors) {
  1089.                         m_Cache.Remove(m_Key);
  1090.                     }
  1091.                     else {
  1092.                         m_Cache.TryRemove(m_Key);
  1093.                     }
  1094.                 }
  1095.                 else {
  1096.                     if (m_IsStrictCacheErrors) {
  1097.                         m_Cache.Update(m_Key, m_Expires, m_LastModified, m_LastSynchronized, m_MaxStale, m_EntryMetadata, m_SystemMetadata);
  1098.                     }
  1099.                     else {
  1100.                         m_Cache.TryUpdate(m_Key, m_Expires, m_LastModified, m_LastSynchronized, m_MaxStale, m_EntryMetadata, m_SystemMetadata);
  1101.                     }
  1102.                    
  1103.                 }
  1104.                
  1105.                 if (!disposing) {
  1106.                     m_Cache = null;
  1107.                     m_Key = null;
  1108.                     m_EntryMetadata = null;
  1109.                     m_SystemMetadata = null;
  1110.                 }
  1111.             }
  1112.             base.Dispose(disposing);
  1113.         }
  1114.     }
  1115.    
  1116.     //
  1117.     // This stream is for Partial responses.
  1118.     // It will scroll to the given position and limit the original stream windows to given size
  1119.     internal class RangeStream : Stream, ICloseEx
  1120.     {
  1121.         private Stream m_ParentStream;
  1122.         long m_Offset;
  1123.         long m_Size;
  1124.         long m_Position;
  1125.        
  1126.         internal RangeStream(Stream parentStream, long offset, long size) : base()
  1127.         {
  1128.             m_ParentStream = parentStream;
  1129.             m_Offset = offset;
  1130.             m_Size = size;
  1131.             if (m_ParentStream.CanSeek) {
  1132.                 m_ParentStream.Position = offset;
  1133.                 m_Position = offset;
  1134.             }
  1135.             else {
  1136.                 // for now we expect a FileStream that is seekable.
  1137.                 throw new NotSupportedException(SR.GetString(SR.net_cache_non_seekable_stream_not_supported));
  1138.             }
  1139.         }
  1140.        
  1141.         public override bool CanRead {
  1142.             get { return m_ParentStream.CanRead; }
  1143.         }
  1144.        
  1145.         // If CanSeek is false, Position, Seek, Length, and SetLength should throw.
  1146.         public override bool CanSeek {
  1147.             get { return m_ParentStream.CanSeek; }
  1148.         }
  1149.        
  1150.         public override bool CanWrite {
  1151.             get { return m_ParentStream.CanWrite; }
  1152.         }
  1153.        
  1154.         public override long Length {
  1155.             get {
  1156.                 long dummy = m_ParentStream.Length;
  1157.                 return m_Size;
  1158.             }
  1159.         }
  1160.        
  1161.         public override long Position {
  1162.             get { return m_ParentStream.Position - m_Offset; }
  1163.            
  1164.             set {
  1165.                 value += m_Offset;
  1166.                 if (value > m_Offset + m_Size) {
  1167.                     value = m_Offset + m_Size;
  1168.                 }
  1169.                 m_ParentStream.Position = value;
  1170.             }
  1171.         }
  1172.        
  1173.         public override long Seek(long offset, SeekOrigin origin)
  1174.         {
  1175.             switch (origin) {
  1176.                 case SeekOrigin.Begin:
  1177.                     offset += m_Offset;
  1178.                     if (offset > m_Offset + m_Size) {
  1179.                         offset = m_Offset + m_Size;
  1180.                     }
  1181.                     if (offset < m_Offset) {
  1182.                         offset = m_Offset;
  1183.                     }
  1184.                     break;
  1185.                 case SeekOrigin.End:
  1186.                     offset -= (m_Offset + m_Size);
  1187.                     if (offset > 0) {
  1188.                         offset = 0;
  1189.                     }
  1190.                     if (offset < -m_Size) {
  1191.                         offset = -m_Size;
  1192.                     }
  1193.                     break;
  1194.                 default:
  1195.                     if (m_Position + offset > m_Offset + m_Size) {
  1196.                         offset = (m_Offset + m_Size) - m_Position;
  1197.                     }
  1198.                     if (m_Position + offset < m_Offset) {
  1199.                         offset = m_Offset - m_Position;
  1200.                     }
  1201.                     break;
  1202.             }
  1203.             m_Position = m_ParentStream.Seek(offset, origin);
  1204.             return m_Position - m_Offset;
  1205.         }
  1206.        
  1207.         public override void SetLength(long value)
  1208.         {
  1209.             throw new NotSupportedException(SR.GetString(SR.net_cache_unsupported_partial_stream));
  1210.         }
  1211.        
  1212.         public override void Write(byte[] buffer, int offset, int count)
  1213.         {
  1214.             if (m_Position + count > m_Offset + m_Size) {
  1215.                 throw new NotSupportedException(SR.GetString(SR.net_cache_unsupported_partial_stream));
  1216.             }
  1217.             m_ParentStream.Write(buffer, offset, count);
  1218.             m_Position += count;
  1219.         }
  1220.        
  1221.         public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
  1222.         {
  1223.             if (m_Position + offset > m_Offset + m_Size) {
  1224.                 throw new NotSupportedException(SR.GetString(SR.net_cache_unsupported_partial_stream));
  1225.             }
  1226.             return m_ParentStream.BeginWrite(buffer, offset, count, callback, state);
  1227.         }
  1228.        
  1229.         public override void EndWrite(IAsyncResult asyncResult)
  1230.         {
  1231.             m_ParentStream.EndWrite(asyncResult);
  1232.             m_Position = m_ParentStream.Position;
  1233.         }
  1234.        
  1235.         public override void Flush()
  1236.         {
  1237.             m_ParentStream.Flush();
  1238.         }
  1239.        
  1240.         public override int Read(byte[] buffer, int offset, int count)
  1241.         {
  1242.             if (m_Position >= m_Offset + m_Size) {
  1243.                 return 0;
  1244.             }
  1245.             if (m_Position + count > m_Offset + m_Size) {
  1246.                 count = (int)(m_Offset + m_Size - m_Position);
  1247.             }
  1248.             int result = m_ParentStream.Read(buffer, offset, count);
  1249.             m_Position += result;
  1250.             return result;
  1251.         }
  1252.        
  1253.         public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
  1254.         {
  1255.             if (m_Position >= m_Offset + m_Size) {
  1256.                 count = 0;
  1257.             }
  1258.             else if (m_Position + count > m_Offset + m_Size) {
  1259.                 count = (int)(m_Offset + m_Size - m_Position);
  1260.             }
  1261.             return m_ParentStream.BeginRead(buffer, offset, count, callback, state);
  1262.         }
  1263.        
  1264.         public override int EndRead(IAsyncResult asyncResult)
  1265.         {
  1266.             int result = m_ParentStream.EndRead(asyncResult);
  1267.             m_Position += result;
  1268.             return result;
  1269.         }
  1270.        
  1271.         // Subclasses should use Dispose(bool, CloseExState)
  1272.         protected override sealed void Dispose(bool disposing)
  1273.         {
  1274.             Dispose(disposing, CloseExState.Normal);
  1275.             GC.SuppressFinalize(this);
  1276.         }
  1277.        
  1278.         void ICloseEx.CloseEx(CloseExState closeState)
  1279.         {
  1280.             Dispose(true, closeState);
  1281.             GC.SuppressFinalize(this);
  1282.         }
  1283.        
  1284.         public override bool CanTimeout {
  1285.             get { return m_ParentStream.CanTimeout; }
  1286.         }
  1287.        
  1288.         public override int ReadTimeout {
  1289.             get { return m_ParentStream.ReadTimeout; }
  1290.             set { m_ParentStream.ReadTimeout = value; }
  1291.         }
  1292.        
  1293.         public override int WriteTimeout {
  1294.             get { return m_ParentStream.WriteTimeout; }
  1295.             set { m_ParentStream.WriteTimeout = value; }
  1296.         }
  1297.        
  1298.         protected virtual void Dispose(bool disposing, CloseExState closeState)
  1299.         {
  1300.            
  1301.             // All calls below should already be idempotent.
  1302.            
  1303.             ICloseEx icloseEx = m_ParentStream as ICloseEx;
  1304.            
  1305.             if (icloseEx != null) {
  1306.                 icloseEx.CloseEx(closeState);
  1307.             }
  1308.             else {
  1309.                 m_ParentStream.Close();
  1310.             }
  1311.             base.Dispose(disposing);
  1312.         }
  1313.     }
  1314.    
  1315. }

Developer Fusion