Browse Source

* FileWebRequest.cs: finished implementation of async methods.
* FileWebResponse.cs: improved disposable routines.

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

Lawrence Pit 23 years ago
parent
commit
cf155c00a2

+ 2 - 0
mcs/class/System/System.Net/ChangeLog

@@ -1,5 +1,7 @@
 2002-05-19  Lawrence Pit <[email protected]>
 
+	* FileWebRequest.cs: finished implementation of async methods.
+	* FileWebResponse.cs: improved disposable routines.
 	* IPEndPoint.cs: fixed bug #24666 in Serialize and Create methods, 
 	byte ordering of address was backwards.
 

+ 117 - 57
mcs/class/System/System.Net/FileWebRequest.cs

@@ -10,6 +10,7 @@ using System.Collections;
 using System.IO;
 using System.Runtime.Serialization;
 using System.Runtime.Remoting.Messaging;
+using System.Threading;
 
 namespace System.Net 
 {
@@ -23,7 +24,12 @@ namespace System.Net
 		private string connectionGroup;
 		private string method;
 		private int timeout;
-		private bool open = false;
+		
+		private Stream requestStream = null;
+		private FileWebResponse webResponse = null;
+		private AutoResetEvent requestEndEvent = null;
+		private bool requesting = false;
+		private bool asyncResponding = false;
 		
 		// Constructors
 		
@@ -114,78 +120,129 @@ namespace System.Net
 		private delegate Stream GetRequestStreamCallback ();
 		private delegate WebResponse GetResponseCallback ();
 
-// TODO: bit simplistic this, need to add code to check for exceptions..
-// TODO: use Timeout value
-// TODO: as the spec says GetResponse can throw an exception on timeout, 
-// and because in theory one could start an async GetResponse, change 
-// properties, and start a sync GetResponse it seems best that GetResponse 
-// actually works via the async methods and the async delegates delegate 
-// to a private get response method. timeout value probably isn't an 
-// issue here, but it is in HttpWebRequest.
-
 		public override IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state) 
 		{		
-			GetRequestStreamCallback c = new GetRequestStreamCallback (this.GetRequestStream);
-			return c.BeginInvoke (callback, state);
+			if (method == null || (!method.Equals ("PUT") && !method.Equals ("POST")))
+				throw new ProtocolViolationException ("Cannot send file when method is: " + this.method + ". Method must be PUT.");
+			// workaround for bug 24943
+			Exception e = null;
+			lock (this) {
+				if (asyncResponding || webResponse != null)
+					e = new InvalidOperationException ("This operation cannot be performed after the request has been submitted.");
+				else if (requesting)
+					e = new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");
+				else
+					requesting = true;
+			}
+			if (e != null)
+				throw e;
+			/*
+			lock (this) {
+				if (asyncResponding)
+					throw new InvalidOperationException ("This operation cannot be performed after the request has been submitted.");
+				if (requesting)
+					throw new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");
+				requesting = true;
+			}
+			*/
+			GetRequestStreamCallback c = new GetRequestStreamCallback (this.GetRequestStreamInternal);
+			return c.BeginInvoke (callback, state);			
 		}
 		
-		public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state)
-		{
-			GetResponseCallback c = new GetResponseCallback (this.GetResponse);
-			return c.BeginInvoke (callback, state);
-		}
-
 		public override Stream EndGetRequestStream (IAsyncResult asyncResult)
 		{
 			if (asyncResult == null)
 				throw new ArgumentNullException ("asyncResult");
+			if (!asyncResult.IsCompleted)
+				asyncResult.AsyncWaitHandle.WaitOne ();				
 			AsyncResult async = (AsyncResult) asyncResult;
 			GetRequestStreamCallback cb = (GetRequestStreamCallback) async.AsyncDelegate;
-			asyncResult.AsyncWaitHandle.WaitOne ();
-			return cb.EndInvoke(asyncResult);
+			return cb.EndInvoke (asyncResult);
+		}
+
+		public override Stream GetRequestStream()
+		{
+			IAsyncResult asyncResult = BeginGetRequestStream (null, null);
+			if (!(asyncResult.AsyncWaitHandle.WaitOne (timeout, false))) {
+				throw new WebException("The request timed out", WebExceptionStatus.Timeout);
+			}
+			return EndGetRequestStream (asyncResult);
 		}
 		
+		internal Stream GetRequestStreamInternal ()
+		{
+			this.requestStream = new FileWebStream (
+						this,
+						FileMode.CreateNew,
+						FileAccess.Write, 
+						FileShare.Read);
+			return this.requestStream;
+		}
+		
+		public override IAsyncResult BeginGetResponse (AsyncCallback callback, object state)
+		{
+			// workaround for bug 24943
+			Exception e = null;
+			lock (this) {
+				if (asyncResponding)
+					e = new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");
+				else 
+					asyncResponding = true;
+			}
+			if (e != null)
+				throw e;
+			/*
+			lock (this) {
+				if (asyncResponding)
+					throw new InvalidOperationException ("Cannot re-call start of asynchronous method while a previous call is still in progress.");
+				asyncResponding = true;
+			}
+			*/
+			GetResponseCallback c = new GetResponseCallback (this.GetResponseInternal);
+			return c.BeginInvoke (callback, state);
+		}
+
 		public override WebResponse EndGetResponse (IAsyncResult asyncResult)
 		{
 			if (asyncResult == null)
 				throw new ArgumentNullException ("asyncResult");
+			if (!asyncResult.IsCompleted)
+				asyncResult.AsyncWaitHandle.WaitOne ();			
 			AsyncResult async = (AsyncResult) asyncResult;
 			GetResponseCallback cb = (GetResponseCallback) async.AsyncDelegate;
-			asyncResult.AsyncWaitHandle.WaitOne ();
-			return cb.EndInvoke(asyncResult);		
+			WebResponse webResponse = cb.EndInvoke(asyncResult);
+			asyncResponding = false;
+			return webResponse;
 		}
-		
-		public override Stream GetRequestStream()
+				
+		public override WebResponse GetResponse ()
 		{
-			if (method == null || (!method.Equals ("PUT") && !method.Equals ("POST")))
-				throw new ProtocolViolationException ("Cannot send file when method is: " + this.method + ". Method must be PUT.");
-			if (open)
-				throw new WebException ("Stream already open");
-			open = true;
-			FileStream fileStream = new FileWebStream (
-							this,
-						     	FileMode.CreateNew, 
-							FileAccess.Write, 
-							FileShare.Read,
-							4096,
-							false);
-			return fileStream;					
+			IAsyncResult asyncResult = BeginGetResponse (null, null);
+			if (!(asyncResult.AsyncWaitHandle.WaitOne (timeout, false))) {
+				throw new WebException("The request timed out", WebExceptionStatus.Timeout);
+			}
+			return EndGetResponse (asyncResult);
 		}
-		
-		public override WebResponse GetResponse()
+			
+		public WebResponse GetResponseInternal ()
 		{
-			if (method == null || !method.Equals ("GET"))
-				throw new ProtocolViolationException ("Cannot retrieve file when method is: " + this.method + ". Method must be GET.");
-			if (open)
-				throw new WebException ("Stream already open");
+			if (webResponse != null)
+				return webResponse;			
+			lock (this) {
+				if (requesting) {
+					requestEndEvent = new AutoResetEvent (false);
+				}
+			}
+			if (requestEndEvent != null) {
+				requestEndEvent.WaitOne ();
+			}
 			FileStream fileStream = new FileWebStream (
 							this,
 						     	FileMode.Open, 
 							FileAccess.Read, 
-							FileShare.Read,
-							4096,
-							false);
- 			return new FileWebResponse (this, fileStream);
+							FileShare.Read);
+ 			this.webResponse = new FileWebResponse (this.uri, fileStream);
+ 			return (WebResponse) this.webResponse;
 		}
 		
 		[MonoTODO]
@@ -197,12 +254,17 @@ namespace System.Net
 		
 		internal void Close ()
 		{
-			open = false;
-		}
-		
-		internal bool IsClosed ()
-		{
-			return !open;
+			// already done in class below
+			// if (requestStream != null) {
+			// 	requestStream.Close ();
+			// }
+
+			lock (this) {			
+				requesting = false;
+				if (requestEndEvent != null) 
+					requestEndEvent.Set ();
+				// requestEndEvent = null;
+			}
 		}
 		
 		// to catch the Close called on the FileStream
@@ -213,11 +275,9 @@ namespace System.Net
 			internal FileWebStream (FileWebRequest webRequest,    
 					   	FileMode mode,
 					   	FileAccess access,
-					   	FileShare share,
-					   	int bufferSize,
-					   	bool useAsync)
+					   	FileShare share)
 				: base (webRequest.RequestUri.LocalPath, 
-					mode, access, share, bufferSize, useAsync)					   	
+					mode, access, share)
 			{
 				this.webRequest = webRequest;
 			}

+ 20 - 20
mcs/class/System/System.Net/FileWebResponse.cs

@@ -14,7 +14,7 @@ namespace System.Net
 	[Serializable]
 	public class FileWebResponse : WebResponse, ISerializable, IDisposable
 	{
-		private FileWebRequest webRequest;
+		private Uri responseUri;
 		private FileStream fileStream;
 		private long contentLength;
 		private WebHeaderCollection webHeaders;
@@ -24,10 +24,10 @@ namespace System.Net
 		
 		protected FileWebResponse () { }
 		
-		internal FileWebResponse (FileWebRequest webRequest, FileStream fileStream)
+		internal FileWebResponse (Uri responseUri, FileStream fileStream)
 		{
 			try {
-				this.webRequest = webRequest;
+				this.responseUri = responseUri;
 				this.fileStream = fileStream;
 				this.contentLength = fileStream.Length;
 				this.webHeaders = new WebHeaderCollection ();
@@ -48,29 +48,29 @@ namespace System.Net
 		
 		public override long ContentLength {		
 			get {
-				CheckDisposed ();
-				return this.contentLength; 
+				try { return this.contentLength; }
+				finally { CheckDisposed (); }
 			}
 		}
 		
 		public override string ContentType {		
 			get {
-				CheckDisposed ();
-				return "binary/octet-stream"; 
+				try { return "binary/octet-stream"; }
+				finally { CheckDisposed (); }
 			}
 		}
 		
 		public override WebHeaderCollection Headers {		
 			get {
-				CheckDisposed ();
-				return this.webHeaders;	
+				try { return this.webHeaders; }
+				finally { CheckDisposed (); }
 			}
 		}
 		
 		public override Uri ResponseUri {		
 			get {
-				CheckDisposed ();
-				return this.webRequest.RequestUri;
+				try { return this.responseUri; }
+				finally { CheckDisposed (); }
 			}
 		}		
 
@@ -80,14 +80,15 @@ namespace System.Net
 		void ISerializable.GetObjectData (SerializationInfo serializationInfo,
 		   				  StreamingContext streamingContext)
 		{
-			CheckDisposed ();
-			throw new NotImplementedException ();
+			try {
+				throw new NotImplementedException ();
+			} finally { CheckDisposed (); }
 		}		
 
 		public override Stream GetResponseStream()
 		{
-			CheckDisposed ();
-			return this.fileStream;
+			try { return this.fileStream; }
+			finally { CheckDisposed (); }
 		}
 				
 		// Cleaning up stuff
@@ -118,22 +119,21 @@ namespace System.Net
 			
 			if (disposing) {
 				// release managed resources
-				this.disposed = true;
-				this.webRequest = null;
+				this.responseUri = null;
 				this.webHeaders = null;
 			}
 			
 			// release unmanaged resources
-			Stream stream = fileStream;
+			FileStream stream = fileStream;
 			fileStream = null;
 			if (stream != null)
-				stream.Close ();	
+				stream.Close (); // also closes webRequest
 		}
 		
 		private void CheckDisposed ()
 		{
 			if (disposed)
-				throw new ObjectDisposedException ("stream");
+				throw new ObjectDisposedException (GetType().FullName);
 		}		
 	}
 }