+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
{
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)
}
responseStream.Chunked = chunked;
this.webHeaders[last] = value.ToString(); // otherwise we miss the last header
+
+ responseStream.BytesLeft = ContentLength;
}
protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
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)
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);
}
{
CheckDisposed ();
int res;
-
if (buffer == null)
throw new ArgumentNullException ("buffer is null");
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);
}
[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