2003-04-24 Miguel de Icaza <miguel@ximian.com>
authorMiguel de Icaza <miguel@gnome.org>
Thu, 24 Apr 2003 22:50:29 +0000 (22:50 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Thu, 24 Apr 2003 22:50:29 +0000 (22:50 -0000)
* WebClient.cs (DownloadData): Instead of using a MemoryStream,
keep track of all the small chunks in an ArrayList.  The
MemoryStream had the property of reallocating itself, and the
problem was that MemoryStream.GetBuffer would return the buffer
(correctly), but not something of the right size.  So clients of
DownloadData would get the extra unused bytes as part of the
result.

The solution would have been to make another copy at this point,
instead, we only keep the small allocations around in the
ArrayList, and we only do one large allocation at the end.

* HttpWebResponse.cs: If there is a Content-Length header, pass
this information to our HttpWebResponseStream, so it knows when to
stop, instead of waiting for the stream to be shut down by the
other end.

* HttpWebRequest.cs: Only set the `delay-header-writing' mode on
the underlying stream if the method will do a content transfer and
no Content-Length was provided. If not (HEAD and GET or
Content-Length provided), keep going.

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

mcs/class/System/System.Net/ChangeLog
mcs/class/System/System.Net/HttpWebRequest.cs
mcs/class/System/System.Net/HttpWebResponse.cs
mcs/class/System/System.Net/WebClient.cs

index d624cf24635bd90b5024545290e4c939dffdc65f..280adc9f3c5dc79833a69d4cd7da7b7327fe6149 100644 (file)
@@ -1,3 +1,27 @@
+2003-04-24  Miguel de Icaza  <miguel@ximian.com>
+
+       * WebClient.cs (DownloadData): Instead of using a MemoryStream,
+       keep track of all the small chunks in an ArrayList.  The
+       MemoryStream had the property of reallocating itself, and the
+       problem was that MemoryStream.GetBuffer would return the buffer
+       (correctly), but not something of the right size.  So clients of
+       DownloadData would get the extra unused bytes as part of the
+       result.
+
+       The solution would have been to make another copy at this point,
+       instead, we only keep the small allocations around in the
+       ArrayList, and we only do one large allocation at the end.
+
+       * HttpWebResponse.cs: If there is a Content-Length header, pass
+       this information to our HttpWebResponseStream, so it knows when to
+       stop, instead of waiting for the stream to be shut down by the
+       other end.
+
+       * HttpWebRequest.cs: Only set the `delay-header-writing' mode on
+       the underlying stream if the method will do a content transfer and
+       no Content-Length was provided. If not (HEAD and GET or
+       Content-Length provided), keep going.
+       
 2003-04-23  Miguel de Icaza  <miguel@ximian.com>
 
        * HttpWebRequest.cs: .NET Allows the HttpWebRequest to not have
index db5cc10ef9056937e8dbf70b9e13fcfbee89199a..b89fed128d3531c85546f292c2b2505f8c252262 100644 (file)
@@ -652,15 +652,23 @@ namespace System.Net
                        {
                                this.onClose = onClose;
                                this.webRequest = webRequest;
-                               
-                               long content_length = webRequest.ContentLength;
-                               if (content_length != -1)
-                                       WriteHeaders (content_length, false);
-                               else
-                                       AccumulateOutput = new ArrayList ();
 
-                               if (!socket.Poll (webRequest.Timeout, SelectMode.SelectWrite))
-                                       throw new WebException("The request timed out", WebExceptionStatus.Timeout);
+                               bool need_content_length = false;
+                               if (webRequest.method == "POST" || webRequest.method == "HEAD")
+                                       need_content_length = true;
+
+                               long content_length = webRequest.ContentLength;                         
+                               if (need_content_length && content_length == -1){
+                                       //
+                                       // Turn on accumulation mode
+                                       //
+                                       AccumulateOutput = new ArrayList ();
+                               } else {
+                                       if (!socket.Poll (webRequest.Timeout, SelectMode.SelectWrite))
+                                               throw new WebException("The request timed out", WebExceptionStatus.Timeout);
+                                       WriteHeaders (content_length, false);
+                               }
+                               
 
                                // FIXME: write cookie headers (CookieContainer not yet implemented)
                        }
index 701766a094b0758762abdef0489094fbfc991173..bdeca0171e9acc70e8fb38268dfef604f909d99f 100644 (file)
@@ -96,6 +96,8 @@ namespace System.Net
                        
                        responseStream.Chunked = chunked;
                        this.webHeaders[last] = value.ToString(); // otherwise we miss the last header
+
+                       responseStream.BytesLeft = ContentLength;
                }
                
                protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
@@ -425,6 +427,10 @@ namespace System.Net
                        int chunkLeft;
                        bool readingChunkSize;
                        EventHandler onClose;
+                       //
+                       // If ContentLength provided, the number of bytes left to read
+                       //
+                       internal long BytesLeft = -1;
 
                        public HttpWebResponseStream (Socket socket, EventHandler onClose)
                                : base (socket, FileAccess.Read, false)
@@ -557,11 +563,16 @@ namespace System.Net
                                CheckDisposed ();
                                int res;
 
+                               if (BytesLeft == 0)
+                                       return 0;
+                               
                                if (ar == null)
                                        throw new ArgumentNullException ("async result is null");
 
                                try {
                                        res = base.EndRead (ar);
+                                       if (BytesLeft != -1)
+                                               BytesLeft -= res;
                                } catch (Exception e) {
                                        throw new IOException ("EndRead failure", e);
                                }
@@ -574,7 +585,6 @@ namespace System.Net
                        {
                                CheckDisposed ();
                                int res;
-
                                if (buffer == null)
                                        throw new ArgumentNullException ("buffer is null");
 
@@ -588,7 +598,12 @@ namespace System.Net
                                        size = GetMaxSizeFromChunkLeft (size);
 
                                try {
+                                       if (BytesLeft == 0)
+                                               return 0;
+                               
                                        res = base.Read (buffer, offset, size);
+                                       if (BytesLeft != -1)
+                                               BytesLeft -= res;
                                } catch (Exception e) {
                                        throw new IOException ("Read failure", e);
                                }
index 6fcf6b3defd67057904b89b7a1ad02af98262728..1e9a8cb87f6345b47764e449efc1e2149312859e 100644 (file)
@@ -62,17 +62,29 @@ namespace System.Net
                [MonoTODO("depends on OpenRead")]\r
                public byte [] DownloadData (string address)\r
                {\r
-                       const int readSize = 4096;\r
+                       const int readSize = 8192;\r
                        Stream networkStream = OpenRead (address);\r
-                       MemoryStream ms = new MemoryStream ();\r
+                       ArrayList chunks = new ArrayList ();\r
                        byte[] buf = new byte [readSize];\r
                        int size = 0;\r
+                       int total_size = 0;\r
                        do {\r
                                size = networkStream.Read (buf, 0, readSize);\r
-                               ms.Write (buf, 0, size);\r
-                       } while (size == readSize);\r
+                               byte [] copy = new byte [size];\r
+                               Array.Copy (buf, 0, copy,0, size);\r
+                               chunks.Add (copy);\r
+                               total_size += size;\r
+                       } while (size != 0);\r
+\r
+                       byte [] result = new byte [total_size];\r
+                       int target = 0;\r
+                       foreach (byte [] block in chunks){\r
+                               int len = block.Length;\r
+                               Array.Copy (block, 0, result, target, len);\r
+                               target += len;\r
+                       }\r
                        networkStream.Close ();\r
-                       return ms.GetBuffer ();\r
+                       return result;\r
                }\r
                \r
                [MonoTODO("depends on DownloadData")]\r