2004-11-29 Gonzalo Paniagua Javier <gonzalo@ximian.com>
authorGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Mon, 29 Nov 2004 05:46:49 +0000 (05:46 -0000)
committerGonzalo Paniagua Javier <gonzalo.mono@gmail.com>
Mon, 29 Nov 2004 05:46:49 +0000 (05:46 -0000)
* System.Web.dll.sources: added ReusableMemoryStream.

* System.Web/ReusableMemoryStream.cs: copied from System.IO.MemoryStream
and slightly modified to allow expanding the buffer for cases on which
the regular MemoryStream don't allow it.

* System.Web/HttpWriter.cs: use the new ReusableMemoryStream and fix
bug #19841. Otherwise we would have to allocate a new MemoryStream...

svn path=/trunk/mcs/; revision=36757

mcs/class/System.Web/ChangeLog
mcs/class/System.Web/System.Web.dll.sources
mcs/class/System.Web/System.Web/ChangeLog
mcs/class/System.Web/System.Web/HttpWriter.cs
mcs/class/System.Web/System.Web/ReusableMemoryStream.cs [new file with mode: 0644]

index c4a73254524d9d57c2bf0a6f8a485f86d6f46454..d462da03df17c4dcdc35a645b2e08dee408dd1fb 100644 (file)
@@ -1,3 +1,7 @@
+2004-11-29 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+       * System.Web.dll.sources: added ReusableMemoryStream.
+
 2004-11-26  Lluis Sanchez Gual <lluis@novell.com>
 
        * System.Web.dll.sources: Added new file:
index 3bf0f8547815ba64b53c206c52ed66d2097bc28f..ceae02569fca9299ff9efd273625e0d8fb5160b7 100755 (executable)
@@ -786,6 +786,7 @@ System.Web/ProcessModelInfo.cs
 System.Web/ProcessShutdownReason.cs
 System.Web/ProcessStatus.cs
 System.Web/QueueManager.cs
+System.Web/ReusableMemoryStream.cs
 System.Web/ServerVariablesCollection.cs
 System.Web/SiteMap.cs
 System.Web/SiteMapNode.cs
index 937ce46fb4730eb7548dee9f33741fdf11699e3c..7f146c58175d4f968bb78e17f8b5b7ee88deb392 100644 (file)
@@ -1,6 +1,15 @@
+2004-11-29 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+       * ReusableMemoryStream.cs: copied from System.IO.MemoryStream and
+       slightly modified to allow expanding the buffer for cases on which the
+       regular MemoryStream don't allow it.
+
+       * HttpWriter.cs: use the new ReusableMemoryStream and fix bug #19841.
+       Otherwise we would have to allocate a new MemoryStream...
+
 2004-11-28 Gonzalo Paniagua Javier <gonzalo@ximian.com>
 
-       * HttpApplication.cs: Create() is not GetInstance().
+       * HttpApplication.cs: Create() is now GetInstance().
 
 2004-11-18 Lluis Sanchez Gual <lluis@novell.com>
 
index 3366a45d753a4c057091aa7499da1db433c0b597..30a2e80bdb9206b09ee8aff58b91613d5e261a7a 100644 (file)
@@ -40,7 +40,7 @@ namespace System.Web
 
                HttpResponseStream _ResponseStream;
 
-               MemoryStream _OutputStream;
+               ReusableMemoryStream _OutputStream;
                StreamWriter _OutputHelper;
                Encoding _Encoding;     
 
@@ -52,7 +52,7 @@ namespace System.Web
                        _Response = Response;
 
                        _Encoding = _Response.ContentEncoding;
-                       _OutputStream = new MemoryStream (MaxBufferSize);
+                       _OutputStream = new ReusableMemoryStream (MaxBufferSize);
                        _OutputHelper = new StreamWriter (_OutputStream, _Response.ContentEncoding);
                        _ResponseStream = new HttpResponseStream (this);
                }  
@@ -116,9 +116,9 @@ namespace System.Web
 
                internal void Clear ()
                {
-                       // This clears all the buffers that are around
-                       _OutputHelper.Flush ();
-                       _OutputStream.SetLength (0);
+                       _OutputHelper.Close ();
+                       _OutputStream = new ReusableMemoryStream (_OutputStream.GetBuffer ());
+                       _OutputHelper = new StreamWriter (_OutputStream, _Response.ContentEncoding);
                }
 
                internal void SendContent (HttpWorkerRequest Handler)
diff --git a/mcs/class/System.Web/System.Web/ReusableMemoryStream.cs b/mcs/class/System.Web/System.Web/ReusableMemoryStream.cs
new file mode 100644 (file)
index 0000000..e52e96e
--- /dev/null
@@ -0,0 +1,277 @@
+//
+// System.Web.ReusableMemoryStream
+// Trimmed down copy of System.IO.MemoryStream used by HttpWriter.
+//
+// Authors:    Marcin Szczepanski (marcins@zipworld.com.au)
+//             Patrik Torstensson
+//             Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//
+// (c) 2001,2002 Marcin Szczepanski, Patrik Torstensson
+// (c) 2003 Ximian, Inc. (http://www.ximian.com)
+// Copyright (C) 2004 Novell (http://www.novell.com)
+//
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace System.Web
+{
+       [Serializable]
+       class ReusableMemoryStream : Stream
+       {
+               int capacity;
+               int length;
+               byte [] internalBuffer;
+               bool streamClosed;
+               int position;
+
+               public ReusableMemoryStream (int capacity)
+               {
+                       if (capacity < 0)
+                               throw new ArgumentOutOfRangeException ("capacity");
+
+                       this.capacity = capacity;
+                       internalBuffer = new byte [capacity];
+               }
+
+               public ReusableMemoryStream (byte [] buffer)
+               {
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+                       
+                       capacity = buffer.Length;
+                       internalBuffer = buffer;
+               }
+
+               void CheckIfClosedThrowDisposed ()
+               {
+                       if (streamClosed)
+                               throw new ObjectDisposedException (GetType ().ToString ());
+               }
+               
+               public override bool CanRead {
+                       get { return !streamClosed; }
+               }
+
+               public override bool CanSeek {
+                       get { return !streamClosed; }
+               }
+
+               public override bool CanWrite {
+                       get { return !streamClosed; }
+               }
+
+               int Capacity {
+                       get {
+                               CheckIfClosedThrowDisposed ();
+                               return capacity;
+                       }
+
+                       set {
+                               CheckIfClosedThrowDisposed ();
+                               if (value == capacity)
+                                       return; // LAMENESS: see MemoryStreamTest.ConstructorFive
+
+                               if (value < 0 || value < length)
+                                       throw new ArgumentOutOfRangeException ("value",
+                                       "New capacity cannot be negative or less than the current capacity " + value + " " + capacity);
+
+                               byte [] newBuffer = null;
+                               if (value != 0) {
+                                       newBuffer = new byte [value];
+                                       Buffer.BlockCopy (internalBuffer, 0, newBuffer, 0, length);
+                               }
+
+                               internalBuffer = newBuffer; // It's null when capacity is set to 0
+                               capacity = value;
+                       }
+               }
+
+               public override long Length {
+                       get {
+                               CheckIfClosedThrowDisposed ();
+                               return length;
+                       }
+               }
+
+               public override long Position {
+                       get {
+                               CheckIfClosedThrowDisposed ();
+                               return position;
+                       }
+
+                       set {
+                               CheckIfClosedThrowDisposed ();
+                               if (value < 0)
+                                       throw new ArgumentOutOfRangeException ("value",
+                                                               "Position cannot be negative" );
+
+                               if (value > Int32.MaxValue)
+                                       throw new ArgumentOutOfRangeException ("value",
+                                       "Position must be non-negative and less than 2^31 - 1 - origin");
+
+                               position = (int) value;
+                       }
+               }
+
+               public override void Close ()
+               {
+                       streamClosed = true;
+               }
+
+               public override void Flush ()
+               {
+               }
+
+               public byte [] GetBuffer ()
+               {
+                       return internalBuffer;
+               }
+
+               public override int Read ([In,Out] byte [] buffer, int offset, int count)
+               {
+                       CheckIfClosedThrowDisposed ();
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+
+                       if (position >= length || count == 0)
+                               return 0;
+
+                       if (position > length - count)
+                               count = length - position;
+
+                       Buffer.BlockCopy (internalBuffer, position, buffer, offset, count);
+                       position += count;
+                       return count;
+               }
+
+               public override int ReadByte ()
+               {
+                       CheckIfClosedThrowDisposed ();
+                       if (position >= length)
+                               return -1;
+
+                       return internalBuffer [position++];
+               }
+
+               public override long Seek (long offset, SeekOrigin loc)
+               {
+                       CheckIfClosedThrowDisposed ();
+
+                       if (offset > (long) Int32.MaxValue)
+                               throw new ArgumentOutOfRangeException ("Offset out of range. " + offset);
+
+                       int refPoint;
+                       switch (loc) {
+                       case SeekOrigin.Begin:
+                               if (offset < 0)
+                                       throw new IOException ("Attempted to seek before start of MemoryStream.");
+                               refPoint = 0;
+                               break;
+                       case SeekOrigin.Current:
+                               refPoint = position;
+                               break;
+                       case SeekOrigin.End:
+                               refPoint = length;
+                               break;
+                       default:
+                               throw new ArgumentException ("loc", "Invalid SeekOrigin");
+                       }
+
+                       refPoint += (int) offset;
+                       if (refPoint < 0)
+                               throw new IOException ("Attempted to seek before start of MemoryStream.");
+
+                       position = refPoint;
+                       return position;
+               }
+
+               int CalculateNewCapacity (int minimum)
+               {
+                       if (minimum < 256)
+                               minimum = 256;
+
+                       if (minimum < capacity * 2)
+                               minimum = capacity * 2;
+
+                       return minimum;
+               }
+
+               public override void SetLength (long value)
+               {
+                       CheckIfClosedThrowDisposed ();
+
+                       if (value < 0 || value > (long) Int32.MaxValue)
+                               throw new ArgumentOutOfRangeException ();
+
+                       int newSize = (int) value;
+                       if (newSize > capacity)
+                               Capacity = CalculateNewCapacity (newSize);
+                       else if (newSize < length)
+                               Array.Clear (internalBuffer, newSize, length - newSize);
+
+                       length = newSize;
+                       if (position > length)
+                               position = length;
+               }
+
+               public override void Write (byte [] buffer, int offset, int count)
+               {
+                       CheckIfClosedThrowDisposed ();
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+                       
+                       if (offset < 0 || count < 0)
+                               throw new ArgumentOutOfRangeException ();
+
+                       if (buffer.Length - offset < count)
+                               throw new ArgumentException ("offset+count",
+                                                            "The size of the buffer is less than offset + count.");
+
+                       // reordered to avoid possible integer overflow
+                       if (position > capacity - count)
+                               Capacity = CalculateNewCapacity (position + count);
+
+                       Buffer.BlockCopy (buffer, offset, internalBuffer, position, count);
+                       position += count;
+                       if (position >= length)
+                               length = position;
+               }
+
+               public override void WriteByte (byte value)
+               {
+                       CheckIfClosedThrowDisposed ();
+                       if (position >= capacity)
+                               Capacity = CalculateNewCapacity (position + 1);
+
+                       if (position >= length)
+                               length = position + 1;
+
+                       internalBuffer [position++] = value;
+               }
+       }               
+}
+