Browse Source

2004-02-17 Gonzalo Paniagua Javier <[email protected]>

	* HttpWebRequest.cs: on second and sucesive tries when authenticating,
	don't use chunked encoding for POST, as we know the content length and
	have the body. Nullify bodyBuffer always in CheckFinalStatus.

	* WebAsyncResult.cs: added ChunkAsyncResult property. It holds the
	IAsyncResult when writing CRLF at the end of a chunk.

	* WebConnectionStream.cs: support sending chunked data.

svn path=/trunk/mcs/; revision=23153
Gonzalo Paniagua Javier 22 years ago
parent
commit
7caef67a07

+ 15 - 3
mcs/class/System/System.Net/ChangeLog

@@ -1,8 +1,20 @@
+2004-02-17  Gonzalo Paniagua Javier <[email protected]>
+
+	* HttpWebRequest.cs: on second and sucesive tries when authenticating,
+	don't use chunked encoding for POST, as we know the content length and
+	have the body. Nullify bodyBuffer always in CheckFinalStatus.
+
+	* WebAsyncResult.cs: added ChunkAsyncResult property. It holds the
+	IAsyncResult when writing CRLF at the end of a chunk.
+
+	* WebConnectionStream.cs: support sending chunked data.
+
 2004-01-24  Lluis Sanchez Gual <[email protected]>
 
-	* HttpWebRequest.cs: When retrying a POST request after an authentication
-	failure, resend the body. This fixes bug #51841.
-	* WebConnectionStream.cs: Added properties for getting what's been written.
+	* HttpWebRequest.cs: When retrying a POST request after an
+	authentication failure, resend the body. This fixes bug #51841.
+	* WebConnectionStream.cs: Added properties for getting what's been
+	written.
 
 2004-02-12  Gonzalo Paniagua Javier <[email protected]>
 

+ 10 - 1
mcs/class/System/System.Net/HttpWebRequest.cs

@@ -852,6 +852,12 @@ namespace System.Net
 				return;
 			
 			writeStream = stream;
+			if (bodyBuffer != null) {
+				webHeaders.RemoveInternal ("Transfer-Encoding");
+				contentLength = bodyBuffer.Length;
+				writeStream.SendChunked = false;
+			}
+			
 			SendRequestHeaders ();
 
 			haveRequest = true;
@@ -935,6 +941,7 @@ namespace System.Net
 				throw result.Exception;
 
 			Exception throwMe = result.Exception;
+			bodyBuffer = null;
 
 			HttpWebResponse resp = result.Response;
 			WebExceptionStatus protoError = WebExceptionStatus.ProtocolError;
@@ -954,7 +961,9 @@ namespace System.Net
 						writeStream.InternalClose ();
 						writeStream = null;
 						webResponse = null;
-						throw new WebException ("This request requires buffering of data for authentication or redirection to be sucessful.");
+						throw new WebException ("This request requires buffering " +
+									"of data for authentication or " +
+									"redirection to be sucessful.");
 					}
 				}
 

+ 6 - 0
mcs/class/System/System.Net/WebAsyncResult.cs

@@ -21,6 +21,7 @@ namespace System.Net
 		object state;
 		int nbytes;
 		IAsyncResult innerAsyncResult;
+		IAsyncResult chunkAsyncResult;
 		bool callbackDone;
 		Exception exc;
 		HttpWebRequest request;
@@ -162,6 +163,11 @@ namespace System.Net
 			set { nbytes = value; }
 		}
 
+		internal IAsyncResult ChunkAsyncResult {
+			get { return chunkAsyncResult; }
+			set { chunkAsyncResult = value; }
+		}
+
 		internal IAsyncResult InnerAsyncResult {
 			get { return innerAsyncResult; }
 			set { innerAsyncResult = value; }

+ 75 - 15
mcs/class/System/System.Net/WebConnectionStream.cs

@@ -5,15 +5,18 @@
 //	Gonzalo Paniagua Javier ([email protected])
 //
 // (C) 2003 Ximian, Inc (http://www.ximian.com)
+// (C) 2004 Novell, Inc (http://www.novell.com)
 //
 
 using System.IO;
+using System.Text;
 using System.Threading;
 
 namespace System.Net
 {
 	class WebConnectionStream : Stream
 	{
+		static byte [] crlf = new byte [] { 13, 10 };
 		bool isRead;
 		WebConnection cnc;
 		HttpWebRequest request;
@@ -24,6 +27,7 @@ namespace System.Net
 		int totalRead;
 		bool nextReadCalled;
 		int pendingReads;
+		int pendingWrites;
 		ManualResetEvent pending;
 		bool allowBuffering;
 		bool sendChunked;
@@ -31,6 +35,7 @@ namespace System.Net
 		bool requestWritten;
 		byte [] headers;
 		bool disposed;
+		bool headersSent;
 
 		public WebConnectionStream (WebConnection cnc)
 		{
@@ -53,6 +58,13 @@ namespace System.Net
 			sendChunked = request.SendChunked;
 			if (allowBuffering)
 				writeBuffer = new MemoryStream ();
+
+			if (sendChunked)
+				pending = new ManualResetEvent (true);
+		}
+
+		internal bool SendChunked {
+			set { sendChunked = value; }
 		}
 
 		internal byte [] ReadBuffer {
@@ -248,18 +260,35 @@ namespace System.Net
 			if (size < 0 || offset < 0 || length < offset || length - offset < size)
 				throw new ArgumentOutOfRangeException ();
 
+			lock (this) {
+				pendingWrites++;
+				pending.Reset ();
+			}
+
 			WebAsyncResult result = new WebAsyncResult (cb, state);
 			if (allowBuffering) {
 				writeBuffer.Write (buffer, offset, size);
-				result.SetCompleted (true, 0);
-				result.DoCallback ();
-			} else {
-				if (cb != null)
-					cb = new AsyncCallback (CallbackWrapper);
+			}
+
+			AsyncCallback chunkcb = null;
+			if (sendChunked) {
+				WriteRequest ();
+				string cSize = String.Format ("{0:X}\r\n", size);
+				byte [] chunk = Encoding.ASCII.GetBytes (cSize);
+				chunkcb = new AsyncCallback (cnc.EndWrite);
+				result = new WebAsyncResult (null, result);
+				cnc.BeginWrite (chunk, 0, chunk.Length, chunkcb, result);
+			}
+
+			if (cb != null)
+				cb = new AsyncCallback (CallbackWrapper);
+
+			result.InnerAsyncResult = cnc.BeginWrite (buffer, offset, size, cb, result);
+			if (result.InnerAsyncResult == null)
+				throw new WebException ("Aborted");
 
-				result.InnerAsyncResult = cnc.BeginWrite (buffer, offset, size, cb, result);
-				if (result.InnerAsyncResult == null)
-					throw new WebException ("Aborted");
+			if (sendChunked) {
+				result.ChunkAsyncResult = cnc.BeginWrite (crlf, 0, crlf.Length, null, null);
 			}
 
 			return result;
@@ -270,21 +299,31 @@ namespace System.Net
 			if (r == null)
 				throw new ArgumentNullException ("r");
 
-			if (allowBuffering)
+			if (allowBuffering && !sendChunked)
 				return;
 
 			WebAsyncResult result = r as WebAsyncResult;
 			if (result == null)
 				throw new ArgumentException ("Invalid IAsyncResult");
 
+			if (result.GotException)
+				throw result.Exception;
+
 			cnc.EndWrite (result.InnerAsyncResult);
-			return;
+			if (sendChunked)
+				cnc.EndWrite (result.ChunkAsyncResult);
+
+			lock (this) {
+				pendingWrites--;
+				if (pendingWrites == 0)
+					pending.Set ();
+			}
 		}
 		
 		public override void Write (byte [] buffer, int offset, int size)
 		{
 			if (isRead)
-				throw new NotSupportedException ("this stream does not allow writing");
+				throw new NotSupportedException ("This stream does not allow writing");
 
 			IAsyncResult res = BeginWrite (buffer, offset, size, null, null);
 			EndWrite (res);
@@ -296,9 +335,13 @@ namespace System.Net
 
 		internal void SetHeaders (byte [] buffer, int offset, int size)
 		{
-			if (!allowBuffering) {
+			if (headersSent)
+				return;
+
+			headersSent = true;
+			if (!allowBuffering || sendChunked) {
 				try {
-					Write (buffer, offset, size);
+					cnc.Write (buffer, offset, size);
 				} catch (IOException) {
 					if (cnc.Connected)
 						throw;
@@ -306,7 +349,7 @@ namespace System.Net
 					if (!cnc.TryReconnect ())
 						throw;
 
-					Write (buffer, offset, size);
+					cnc.Write (buffer, offset, size);
 				}
 			} else {
 				headers = new byte [size];
@@ -316,7 +359,16 @@ namespace System.Net
 
 		internal void WriteRequest ()
 		{
-			if (!allowBuffering || writeBuffer == null || requestWritten)
+			if (requestWritten)
+				return;
+
+			if (sendChunked) {
+				request.SendRequestHeaders ();
+				requestWritten = true;
+				return;
+			}
+
+			if (!allowBuffering || writeBuffer == null)
 				return;
 
 			byte [] bytes = writeBuffer.GetBuffer ();
@@ -356,6 +408,13 @@ namespace System.Net
 		
 		public override void Close ()
 		{
+			if (sendChunked) {
+				pending.WaitOne ();
+				byte [] chunk = Encoding.ASCII.GetBytes ("0\r\n\r\n");
+				cnc.Write (chunk, 0, chunk.Length);
+				return;
+			}
+
 			if (isRead || !allowBuffering || disposed)
 				return;
 
@@ -375,6 +434,7 @@ namespace System.Net
 
 			writeBuffer = new MemoryStream ();
 			requestWritten = false;
+			headersSent = false;
 		}
 		
 		public override long Seek (long a, SeekOrigin b)