Merge pull request #1991 from esdrubal/seq_test_fix
[mono.git] / mcs / class / System / System.Net / WebConnectionStream.cs
index 5a34a3d812440a647546ec0c26ff3a876834f376..3862b3e4eff56284f11f2d1f768ce139c75e2c02 100644 (file)
@@ -234,7 +234,8 @@ namespace System.Net
                                return;
                        }
 
-                       pending.WaitOne ();
+                       if (!pending.WaitOne (ReadTimeout))
+                               throw new WebException ("The operation has timed out.", WebExceptionStatus.Timeout);
                        lock (locker) {
                                if (totalRead >= contentLength)
                                        return;
@@ -592,6 +593,14 @@ namespace System.Net
                        if (result.EndCalled)
                                return;
 
+                       if (sendChunked) {
+                               lock (locker) {
+                                       pendingWrites--;
+                                       if (pendingWrites <= 0)
+                                               pending.Set ();
+                               }
+                       }
+
                        result.EndCalled = true;
                        if (result.AsyncWriteAll) {
                                result.WaitUntilComplete ();
@@ -605,14 +614,6 @@ namespace System.Net
 
                        if (result.GotException)
                                throw result.Exception;
-
-                       if (sendChunked) {
-                               lock (locker) {
-                                       pendingWrites--;
-                                       if (pendingWrites == 0)
-                                               pending.Set ();
-                               }
-                       }
                }
                
                public override void Write (byte [] buffer, int offset, int size)
@@ -633,10 +634,15 @@ namespace System.Net
                {
                }
 
-               internal WebAsyncResult SetHeadersAsync (bool setInternalLength, AsyncCallback callback, object state)
+               internal void SetHeadersAsync (bool setInternalLength, SimpleAsyncCallback callback)
+               {
+                       SimpleAsyncResult.Run (r => SetHeadersAsync (r, setInternalLength), callback);
+               }
+
+               bool SetHeadersAsync (SimpleAsyncResult result, bool setInternalLength)
                {
                        if (headersSent)
-                               return null;
+                               return false;
 
                        string method = request.Method;
                        bool no_writestream = (method == "GET" || method == "CONNECT" || method == "HEAD" ||
@@ -648,59 +654,62 @@ namespace System.Net
                        if (setInternalLength && !no_writestream && writeBuffer != null)
                                request.InternalContentLength = writeBuffer.Length;
 
-                       if (sendChunked || request.ContentLength > -1 || no_writestream || webdav) {
-                               headersSent = true;
-                               headers = request.GetRequestHeaders ();
+                       bool has_content = !no_writestream && (writeBuffer == null || request.ContentLength > -1);
+                       if (!(sendChunked || has_content || no_writestream || webdav))
+                               return false;
 
-                               var result = new WebAsyncResult (callback, state);
-                               result.InnerAsyncResult = cnc.BeginWrite (request, headers, 0, headers.Length, new AsyncCallback (SetHeadersCB), result);
-                               if (result.InnerAsyncResult != null)
-                                       return result;
-                       }
-
-                       return null;
-               }
+                       headersSent = true;
+                       headers = request.GetRequestHeaders ();
 
-               void SetHeadersCB (IAsyncResult r)
-               {
-                       WebAsyncResult result = (WebAsyncResult) r.AsyncState;
-                       result.InnerAsyncResult = null;
-                       try {
-                               cnc.EndWrite (request, true, r);
-                               result.SetCompleted (false, 0);
-                               if (!initRead) {
-                                       initRead = true;
-                                       WebConnection.InitRead (cnc);
+                       var innerResult = cnc.BeginWrite (request, headers, 0, headers.Length, r => {
+                               try {
+                                       cnc.EndWrite (request, true, r);
+                                       if (!initRead) {
+                                               initRead = true;
+                                               WebConnection.InitRead (cnc);
+                                       }
+                                       var cl = request.ContentLength;
+                                       if (!sendChunked && cl == 0)
+                                               requestWritten = true;
+                                       result.SetCompleted (false);
+                               } catch (WebException e) {
+                                       result.SetCompleted (false, e);
+                               } catch (Exception e) {
+                                       result.SetCompleted (false, new WebException ("Error writing headers", e, WebExceptionStatus.SendFailure));
                                }
-                               long cl = request.ContentLength;
-                               if (!sendChunked && cl == 0)
-                                       requestWritten = true;
-                       } catch (WebException e) {
-                               result.SetCompleted (false, e);
-                       } catch (Exception e) {
-                               result.SetCompleted (false, new WebException ("Error writing headers", e, WebExceptionStatus.SendFailure));
-                       }
-                       result.DoCallback ();
+                       }, null);
+
+                       return innerResult != null;
                }
 
                internal bool RequestWritten {
                        get { return requestWritten; }
                }
 
-               internal WebAsyncResult WriteRequestAsync (AsyncCallback callback, object state)
+               internal SimpleAsyncResult WriteRequestAsync (SimpleAsyncCallback callback)
+               {
+                       var result = WriteRequestAsync (callback);
+                       try {
+                               if (!WriteRequestAsync (result))
+                                       result.SetCompleted (true);
+                       } catch (Exception ex) {
+                               result.SetCompleted (true, ex);
+                       }
+                       return result;
+               }
+
+               internal bool WriteRequestAsync (SimpleAsyncResult result)
                {
                        if (requestWritten)
-                               return null;
+                               return false;
 
                        requestWritten = true;
-                       if (sendChunked)
-                               return null;
-
-                       if (!allowBuffering || writeBuffer == null)
-                               return null;
+                       if (sendChunked || !allowBuffering || writeBuffer == null)
+                               return false;
 
-                       byte[] bytes = writeBuffer.GetBuffer ();
-                       int length = (int)writeBuffer.Length;
+                       // Keep the call for a potential side-effect of GetBuffer
+                       var bytes = writeBuffer.GetBuffer ();
+                       var length = (int)writeBuffer.Length;
                        if (request.ContentLength != -1 && request.ContentLength < length) {
                                nextReadCalled = true;
                                cnc.Close (true);
@@ -708,63 +717,39 @@ namespace System.Net
                                        WebExceptionStatus.ServerProtocolViolation, null);
                        }
 
-                       var result = new WebAsyncResult (callback, state);
-                       result.InnerAsyncResult = SetHeadersAsync (true, WriteRequestAsyncCB, result);
-                       if (result.InnerAsyncResult == null)
-                               WriteRequestAsyncCB (result);
-                       return result;
-               }
-
-               void WriteRequestAsyncCB (IAsyncResult ar)
-               {
-                       var result = (WebAsyncResult)ar;
-                       var innerResult = (WebAsyncResult)result.InnerAsyncResult;
-                       result.InnerAsyncResult = null;
-
-                       if (innerResult != null && innerResult.GotException) {
-                               result.SetCompleted (false, innerResult.Exception);
-                               result.DoCallback ();
-                               return;
-                       }
-
-                       if (cnc.Data.StatusCode != 0 && cnc.Data.StatusCode != 100) {
-                               result.SetCompleted (false, 0);
-                               result.DoCallback ();
-                               return;
-                       }
-
-                       byte[] bytes = writeBuffer.GetBuffer ();
-                       int length = (int)writeBuffer.Length;
+                       SetHeadersAsync (true, inner => {
+                               if (inner.GotException) {
+                                       result.SetCompleted (inner.CompletedSynchronously, inner.Exception);
+                                       return;
+                               }
 
-                       if (length > 0)
-                               result.InnerAsyncResult = cnc.BeginWrite (request, bytes, 0, length, WriteRequestAsyncCB2, result);
+                               if (cnc.Data.StatusCode != 0 && cnc.Data.StatusCode != 100) {
+                                       result.SetCompleted (inner.CompletedSynchronously);
+                                       return;
+                               }
 
-                       if (!initRead) {
-                               initRead = true;
-                               WebConnection.InitRead (cnc);
-                       }
+                               if (!initRead) {
+                                       initRead = true;
+                                       WebConnection.InitRead (cnc);
+                               }
 
-                       if (length == 0) {
-                               result.SetCompleted (false, 0);
-                               result.DoCallback ();
-                               complete_request_written = true;
-                       }
-               }
+                               if (length == 0) {
+                                       complete_request_written = true;
+                                       result.SetCompleted (inner.CompletedSynchronously);
+                                       return;
+                               }
 
-               void WriteRequestAsyncCB2 (IAsyncResult ar)
-               {
-                       var result = (WebAsyncResult)ar.AsyncState;
-                       var innerResult = result.InnerAsyncResult;
-                       result.InnerAsyncResult = null;
+                               cnc.BeginWrite (request, bytes, 0, length, r => {
+                                       try {
+                                               complete_request_written = cnc.EndWrite (request, false, r);
+                                               result.SetCompleted (false);
+                                       } catch (Exception exc) {
+                                               result.SetCompleted (false, exc);
+                                       }
+                               }, null);
+                       });
 
-                       try {
-                               complete_request_written = cnc.EndWrite (request, false, innerResult);
-                               result.SetCompleted (false, 0);
-                       } catch (Exception exc) {
-                               result.SetCompleted (false, exc);
-                       } finally {
-                               result.DoCallback ();
-                       }
+                       return true;
                }
 
                internal void InternalClose ()
@@ -772,13 +757,29 @@ namespace System.Net
                        disposed = true;
                }
 
+               internal bool GetResponseOnClose {
+                       get; set;
+               }
+
                public override void Close ()
                {
+                       if (GetResponseOnClose) {
+                               if (disposed)
+                                       return;
+                               disposed = true;
+                               var response = (HttpWebResponse)request.GetResponse ();
+                               response.ReadAll ();
+                               response.Close ();
+                               return;
+                       }
+
                        if (sendChunked) {
                                if (disposed)
                                        return;
                                disposed = true;
-                               pending.WaitOne ();
+                               if (!pending.WaitOne (WriteTimeout)) {
+                                       throw new WebException ("The operation has timed out.", WebExceptionStatus.Timeout);
+                               }
                                byte [] chunk = Encoding.ASCII.GetBytes ("0\r\n\r\n");
                                string err_msg = null;
                                cnc.Write (request, chunk, 0, chunk.Length, ref err_msg);