Fix null sessions in HttpContextWrapper.Session
[mono.git] / mcs / class / corlib / System.IO / Stream.cs
index 17c8cc457eb82bc3b2733a00659fb5546c423e09..803220306ed47e4dfc99212fb80497a51b9d2191 100644 (file)
@@ -5,13 +5,11 @@
 //   Dietmar Maurer (dietmar@ximian.com)
 //   Miguel de Icaza (miguel@ximian.com)
 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//   Marek Safar (marek.safar@gmail.com)
 //
 // (C) 2001, 2002 Ximian, Inc.  http://www.ximian.com
 // (c) 2004 Novell, Inc. (http://www.novell.com)
-//
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -36,6 +34,9 @@
 using System.Threading;
 using System.Runtime.Remoting.Messaging;
 using System.Runtime.InteropServices;
+#if NET_4_5
+using System.Threading.Tasks;
+#endif
 
 namespace System.IO
 {
@@ -49,6 +50,13 @@ namespace System.IO
        {
                public static readonly Stream Null = new NullStream ();
 
+               [NonSerialized]
+               Func<byte[], int, int, int> async_read;
+               [NonSerialized]
+               Action<byte[], int, int> async_write;
+               [NonSerialized]
+               AutoResetEvent async_event;
+
                protected Stream ()
                {
                }
@@ -87,24 +95,23 @@ namespace System.IO
                }
 
 
-               // 2.0 version of Dispose.
                public void Dispose ()
                {
                        Close ();
                }
 
-               // 2.0 version of Dispose.
                protected virtual void Dispose (bool disposing)
                {
-                       // nothing.
+                       if (async_event != null && disposing) {
+                               async_event.Close ();
+                               async_event = null;
+                       }
                }
 
-               //
-               // 2.0 version of Close (): calls Dispose (true)
-               //
                public virtual void Close ()
                {
                        Dispose (true);
+                       GC.SuppressFinalize (this);
                }
 
                [ComVisible (false)]
@@ -167,62 +174,38 @@ namespace System.IO
                        Write (buffer, 0, 1);
                }
 
-               public virtual IAsyncResult
-               BeginRead (byte [] buffer, int offset, int count, AsyncCallback callback, object state)
+               public virtual IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback callback, object state)
                {
                        if (!CanRead)
                                throw new NotSupportedException ("This stream does not support reading");
 
-                       // Creating a class derived from Stream that doesn't override BeginRead
-                       // shows that it actually calls Read and does everything synchronously.
-                       // Just put this in the Read override:
-                       //      Console.WriteLine ("Read");
-                       //      Console.WriteLine (Environment.StackTrace);
-                       //      Thread.Sleep (10000);
-                       //      return 10;
-
-                       StreamAsyncResult result = new StreamAsyncResult (state);
-                       try {
-                               int nbytes = Read (buffer, offset, count);
-                               result.SetComplete (null, nbytes);
-                       } catch (Exception e) {
-                               result.SetComplete (e, 0);
+                       if (async_event == null) {
+                               lock (this) {
+                                       if (async_event == null)
+                                               async_event = new AutoResetEvent (true);
+                               }
                        }
 
-                       if (callback != null)
-                               callback (result);
-
-                       return result;
+                       async_event.WaitOne ();
+                       async_read = Read;
+                       return async_read.BeginInvoke (buffer, offset, count, callback, state);
                }
 
-//             delegate void WriteDelegate (byte [] buffer, int offset, int count);
-
-               public virtual IAsyncResult
-               BeginWrite (byte [] buffer, int offset, int count, AsyncCallback callback, object state)
+               public virtual IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback callback, object state)
                {
                        if (!CanWrite)
                                throw new NotSupportedException ("This stream does not support writing");
-       
-                       // Creating a class derived from Stream that doesn't override BeginWrite
-                       // shows that it actually calls Write and does everything synchronously except
-                       // when invoking the callback, which is done from the ThreadPool.
-                       // Just put this in the Write override:
-                       //      Console.WriteLine ("Write");
-                       //      Console.WriteLine (Environment.StackTrace);
-                       //      Thread.Sleep (10000);
-
-                       StreamAsyncResult result = new StreamAsyncResult (state);
-                       try {
-                               Write (buffer, offset, count);
-                               result.SetComplete (null);
-                       } catch (Exception e) {
-                               result.SetComplete (e);
-                       }
 
-                       if (callback != null)
-                               callback.BeginInvoke (result, null, null);
+                       if (async_event == null) {
+                               lock (this) {
+                                       if (async_event == null)
+                                               async_event = new AutoResetEvent (true);
+                               }
+                       }
 
-                       return result;
+                       async_event.WaitOne ();
+                       async_write = Write;
+                       return async_write.BeginInvoke (buffer, offset, count, callback, state);
                }
                
                public virtual int EndRead (IAsyncResult asyncResult)
@@ -230,18 +213,15 @@ namespace System.IO
                        if (asyncResult == null)
                                throw new ArgumentNullException ("asyncResult");
 
-                       StreamAsyncResult result = asyncResult as StreamAsyncResult;
-                       if (result == null || result.NBytes == -1)
-                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+                       if (async_read == null)
+                               throw new ArgumentException ("EndRead cannot be called multiple times");
 
-                       if (result.Done)
-                               throw new InvalidOperationException ("EndRead already called.");
-
-                       result.Done = true;
-                       if (result.Exception != null)
-                               throw result.Exception;
-
-                       return result.NBytes;
+                       try {
+                               return async_read.EndInvoke (asyncResult);
+                       } finally {
+                               async_read = null;
+                               async_event.Set ();
+                       }
                }
 
                public virtual void EndWrite (IAsyncResult asyncResult)
@@ -249,19 +229,18 @@ namespace System.IO
                        if (asyncResult == null)
                                throw new ArgumentNullException ("asyncResult");
 
-                       StreamAsyncResult result = asyncResult as StreamAsyncResult;
-                       if (result == null || result.NBytes != -1)
-                               throw new ArgumentException ("Invalid IAsyncResult", "asyncResult");
+                       if (async_write == null)
+                               throw new ArgumentException ("EndWrite cannot be called multiple times");
 
-                       if (result.Done)
-                               throw new InvalidOperationException ("EndWrite already called.");
-
-                       result.Done = true;
-                       if (result.Exception != null)
-                               throw result.Exception;
+                       try {
+                               async_write.EndInvoke (asyncResult);
+                       } finally {
+                               async_write = null;
+                               async_event.Set ();
+                       }
                }
 
-#if MOONLIGHT || NET_4_0
+#if MOONLIGHT || NET_4_0 || MOBILE
                public void CopyTo (Stream destination)
                {
                        CopyTo (destination, 16*1024);
@@ -284,10 +263,86 @@ namespace System.IO
                                destination.Write (buffer, 0, nread);
                }
 
+#if NET_4_5
+               [ObsoleteAttribute("Do not call or override this method")]
+#endif
                protected virtual void ObjectInvariant ()
                {
                }
 #endif
+               
+#if NET_4_5
+
+               public Task CopyToAsync (Stream destination)
+               {
+                       return CopyToAsync (destination, 16 * 1024, CancellationToken.None);
+               }
+
+               public Task CopyToAsync (Stream destination, int bufferSize)
+               {
+                       return CopyToAsync (destination, bufferSize, CancellationToken.None);
+               }
+
+               public virtual Task CopyToAsync (Stream destination, int bufferSize, CancellationToken cancellationToken)
+               {
+                       if (destination == null)
+                               throw new ArgumentNullException ("destination");
+                       if (!CanRead)
+                               throw new NotSupportedException ("This stream does not support reading");
+                       if (!destination.CanWrite)
+                               throw new NotSupportedException ("This destination stream does not support writing");
+                       if (bufferSize <= 0)
+                               throw new ArgumentOutOfRangeException ("bufferSize");
+
+                       if (cancellationToken.IsCancellationRequested)
+                               return TaskConstants.Canceled;
+
+                       return CopyToAsync (destination, new byte[bufferSize], cancellationToken);
+               }
+
+               async Task CopyToAsync (Stream destination, byte[] buffer, CancellationToken cancellationToken)
+               {
+                       int nread;
+                       while ((nread = await ReadAsync (buffer, 0, buffer.Length).ConfigureAwait (false)) != 0)
+                               await destination.WriteAsync (buffer, 0, nread, cancellationToken).ConfigureAwait (false);
+               }
+
+               public Task FlushAsync ()
+               {
+                       return FlushAsync (CancellationToken.None);
+               }
+
+               public virtual Task FlushAsync (CancellationToken cancellationToken)
+               {
+                       if (cancellationToken.IsCancellationRequested)
+                               return TaskConstants.Canceled;
+
+                       return Task.Factory.StartNew (l => ((Stream) l).Flush (), this, cancellationToken);
+               }
+
+               public Task<int> ReadAsync (byte[] buffer, int offset, int count)
+               {
+                       return ReadAsync (buffer, offset, count, CancellationToken.None);
+               }
+
+               public virtual Task<int> ReadAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+               {
+                       if (cancellationToken.IsCancellationRequested)
+                               return TaskConstants<int>.Canceled;
+
+                       return Task<int>.Factory.FromAsync (BeginRead, EndRead, buffer, offset, count, null);
+               }
+
+               public Task WriteAsync (byte[] buffer, int offset, int count)
+               {
+                       return WriteAsync (buffer, offset, count, CancellationToken.None);
+               }
+
+               public virtual Task WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+               {
+                       return Task.Factory.FromAsync (BeginWrite, EndWrite, buffer, offset, count, null);
+               }
+#endif
        }
 
        class NullStream : Stream