Merge pull request #495 from nicolas-raoul/fix-for-issue2907-with-no-formatting-changes
[mono.git] / mcs / class / System / System.Net / WebConnection.cs
index 9b20b7546d81bfbe21d30557f5534a8c1e93a62b..4922fb3291c34bbeac6e02b87b7e9720e0995a86 100644 (file)
@@ -35,6 +35,9 @@ using System.Reflection;
 using System.Security.Cryptography.X509Certificates;
 using System.Text;
 using System.Threading;
+#if SECURITY_DEP
+using Mono.Security.Protocol.Tls;
+#endif
 
 namespace System.Net
 {
@@ -43,7 +46,8 @@ namespace System.Net
                None,
                Status,
                Headers,
-               Content
+               Content,
+               Aborted
        }
 
        class WebConnection
@@ -59,20 +63,26 @@ namespace System.Net
                static AsyncCallback readDoneDelegate = new AsyncCallback (ReadDone);
                EventHandler abortHandler;
                AbortHelper abortHelper;
-               ReadState readState;
                internal WebConnectionData Data;
                bool chunkedRead;
                ChunkStream chunkStream;
                Queue queue;
                bool reused;
                int position;
-               bool busy;
-               HttpWebRequest priority_request;
+               bool busy;              
+               HttpWebRequest priority_request;                
                NetworkCredential ntlm_credentials;
                bool ntlm_authenticated;
-#if NET_1_1
                bool unsafe_sharing;
-#endif
+
+               enum NtlmAuthState
+               {
+                       None,
+                       Challenge,
+                       Response
+               }
+               NtlmAuthState connect_ntlm_auth_state;
+               HttpWebRequest connect_request;
 
                bool ssl;
                bool certsAvailable;
@@ -89,7 +99,8 @@ namespace System.Net
                 static WebConnection ()
                 {
                         Type type = Type.GetType ("MonoTouch.ObjCRuntime.Runtime, monotouch");
-                        start_wwan = type.GetMethod ("StartWWAN");
+                       if (type != null)
+                               start_wwan = type.GetMethod ("StartWWAN", new Type [] { typeof (System.Uri) });
                 }
 #endif
 
@@ -97,9 +108,12 @@ namespace System.Net
                {
                        this.sPoint = sPoint;
                        buffer = new byte [4096];
-                       readState = ReadState.None;
                        Data = new WebConnectionData ();
-                       initConn = new WaitCallback (InitConnection);
+                       initConn = new WaitCallback (state => {
+                               try {
+                                       InitConnection (state);
+                               } catch {}
+                               });
                        queue = group.Queue;
                        abortHelper = new AbortHelper ();
                        abortHelper.Connection = this;
@@ -161,21 +175,30 @@ namespace System.Net
 #endif
                                }
 
-                               WebConnectionData data = Data;
+                               //WebConnectionData data = Data;
                                foreach (IPAddress address in hostEntry.AddressList) {
-                                       socket = new Socket (address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+                                       try {
+                                               socket = new Socket (address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+                                       } catch (Exception se) {
+                                               // The Socket ctor can throw if we run out of FD's
+                                               if (!request.Aborted)
+                                                               status = WebExceptionStatus.ConnectFailure;
+                                               connect_exception = se;
+                                               return;
+                                       }
                                        IPEndPoint remote = new IPEndPoint (address, sPoint.Address.Port);
-#if NET_1_1
-                                       socket.SetSocketOption (SocketOptionLevel.Tcp, SocketOptionName.NoDelay, sPoint.UseNagleAlgorithm ? 0 : 1);
-#endif
-#if NET_2_0
                                        socket.NoDelay = !sPoint.UseNagleAlgorithm;
+                                       try {
+                                               sPoint.KeepAliveSetup (socket);
+                                       } catch {
+                                               // Ignore. Not supported in all platforms.
+                                       }
+
                                        if (!sPoint.CallEndPointDelegate (socket, remote)) {
                                                socket.Close ();
                                                socket = null;
                                                status = WebExceptionStatus.ConnectFailure;
                                        } else {
-#endif
                                                try {
                                                        if (request.Aborted)
                                                                return;
@@ -189,7 +212,7 @@ namespace System.Net
                                                        if (s != null)
                                                                s.Close ();
                                                        return;
-                                               } catch (ObjectDisposedException exc) {
+                                               } catch (ObjectDisposedException) {
                                                        // socket closed from another thread
                                                        return;
                                                } catch (Exception exc) {
@@ -201,9 +224,7 @@ namespace System.Net
                                                                status = WebExceptionStatus.ConnectFailure;
                                                        connect_exception = exc;
                                                }
-#if NET_2_0
                                        }
-#endif
                                }
                        }
                }
@@ -214,7 +235,7 @@ namespace System.Net
                                if (sslStream != null)
                                        return;
 
-#if MONOTOUCH && SECURITY_DEP
+#if NET_2_1 && SECURITY_DEP
                                sslStream = typeof (Mono.Security.Protocol.Tls.HttpsClientStream);
 #else
                                // HttpsClientStream is an internal glue class in Mono.Security.dll
@@ -234,7 +255,8 @@ namespace System.Net
                        }
                }
 
-               bool CreateTunnel (HttpWebRequest request, Stream stream, out byte [] buffer)
+               bool CreateTunnel (HttpWebRequest request, Uri connectUri,
+                                  Stream stream, out byte[] buffer)
                {
                        StringBuilder sb = new StringBuilder ();
                        sb.Append ("CONNECT ");
@@ -249,21 +271,44 @@ namespace System.Net
 
                        sb.Append ("\r\nHost: ");
                        sb.Append (request.Address.Authority);
-                       string challenge = Data.Challenge;
+
+                       bool ntlm = false;
+                       var challenge = Data.Challenge;
                        Data.Challenge = null;
-                       bool have_auth = (request.Headers ["Proxy-Authorization"] != null);
+                       var auth_header = request.Headers ["Proxy-Authorization"];
+                       bool have_auth = auth_header != null;
                        if (have_auth) {
                                sb.Append ("\r\nProxy-Authorization: ");
-                               sb.Append (request.Headers ["Proxy-Authorization"]);
+                               sb.Append (auth_header);
+                               ntlm = auth_header.ToUpper ().Contains ("NTLM");
                        } else if (challenge != null && Data.StatusCode == 407) {
-                               have_auth = true;
                                ICredentials creds = request.Proxy.Credentials;
-                               Authorization auth = AuthenticationManager.Authenticate (challenge, request, creds);
-                               if (auth != null) {
+                               have_auth = true;
+
+                               if (connect_request == null) {
+                                       // create a CONNECT request to use with Authenticate
+                                       connect_request = (HttpWebRequest)WebRequest.Create (
+                                               connectUri.Scheme + "://" + connectUri.Host + ":" + connectUri.Port + "/");
+                                       connect_request.Method = "CONNECT";
+                                       connect_request.Credentials = creds;
+                               }
+
+                               for (int i = 0; i < challenge.Length; i++) {
+                                       var auth = AuthenticationManager.Authenticate (challenge [i], connect_request, creds);
+                                       if (auth == null)
+                                               continue;
+                                       ntlm = (auth.Module.AuthenticationType == "NTLM");
                                        sb.Append ("\r\nProxy-Authorization: ");
                                        sb.Append (auth.Message);
+                                       break;
                                }
                        }
+
+                       if (ntlm) {
+                               sb.Append ("\r\nProxy-Connection: keep-alive");
+                               connect_ntlm_auth_state++;
+                       }
+
                        sb.Append ("\r\n\r\n");
 
                        Data.StatusCode = 0;
@@ -271,10 +316,19 @@ namespace System.Net
                        stream.Write (connectBytes, 0, connectBytes.Length);
 
                        int status;
-                       WebHeaderCollection result = ReadHeaders (request, stream, out buffer, out status);
-                       if (!have_auth && result != null && status == 407) { // Needs proxy auth
+                       WebHeaderCollection result = ReadHeaders (stream, out buffer, out status);
+                       if ((!have_auth || connect_ntlm_auth_state == NtlmAuthState.Challenge) &&
+                           result != null && status == 407) { // Needs proxy auth
+                               var connectionHeader = result ["Connection"];
+                               if (socket != null && !string.IsNullOrEmpty (connectionHeader) &&
+                                   connectionHeader.ToLower() == "close") {
+                                       // The server is requesting that this connection be closed
+                                       socket.Close();
+                                       socket = null;
+                               }
+
                                Data.StatusCode = status;
-                               Data.Challenge = result ["Proxy-Authenticate"];
+                               Data.Challenge = result.GetValues_internal ("Proxy-Authenticate", false);
                                return false;
                        } else if (status != 200) {
                                string msg = String.Format ("The remote server returned a {0} status code.", status);
@@ -285,7 +339,7 @@ namespace System.Net
                        return (result != null);
                }
 
-               WebHeaderCollection ReadHeaders (HttpWebRequest request, Stream stream, out byte [] retBuffer, out int status)
+               WebHeaderCollection ReadHeaders (Stream stream, out byte [] retBuffer, out int status)
                {
                        retBuffer = null;
                        status = 200;
@@ -308,10 +362,25 @@ namespace System.Net
                                headers = new WebHeaderCollection ();
                                while (ReadLine (ms.GetBuffer (), ref start, (int) ms.Length, ref str)) {
                                        if (str == null) {
-                                               if (ms.Length - start > 0) {
-                                                       retBuffer = new byte [ms.Length - start];
-                                                       Buffer.BlockCopy (ms.GetBuffer (), start, retBuffer, 0, retBuffer.Length);
+                                               int contentLen = 0;
+                                               try     {
+                                                       contentLen = int.Parse(headers["Content-Length"]);
+                                               }
+                                               catch {
+                                                       contentLen = 0;
                                                }
+
+                                               if (ms.Length - start - contentLen > 0) {
+                                                       // we've read more data than the response header and conents,
+                                                       // give back extra data to the caller
+                                                       retBuffer = new byte[ms.Length - start - contentLen];
+                                                       Buffer.BlockCopy(ms.GetBuffer(), start + contentLen, retBuffer, 0, retBuffer.Length);
+                                               }
+                                               else {
+                                                       // haven't read in some or all of the contents for the response, do so now
+                                                       FlushContents(stream, contentLen - (int)(ms.Length - start));
+                                               }
+
                                                return headers;
                                        }
 
@@ -332,6 +401,20 @@ namespace System.Net
                        }
                }
 
+               void FlushContents(Stream stream, int contentLength)
+               {
+                       while (contentLength > 0) {
+                               byte[] contentBuffer = new byte[contentLength];
+                               int bytesRead = stream.Read(contentBuffer, 0, contentLength);
+                               if (bytesRead > 0) {
+                                       contentLength -= bytesRead;
+                               }
+                               else {
+                                       break;
+                               }
+                       }
+               }
+
                bool CreateStream (HttpWebRequest request)
                {
                        try {
@@ -343,7 +426,7 @@ namespace System.Net
                                        if (!reused || nstream == null || nstream.GetType () != sslStream) {
                                                byte [] buffer = null;
                                                if (sPoint.UseConnect) {
-                                                       bool ok = CreateTunnel (request, serverStream, out buffer);
+                                                       bool ok = CreateTunnel (request, sPoint.Address, serverStream, out buffer);
                                                        if (!ok)
                                                                return false;
                                                }
@@ -352,6 +435,11 @@ namespace System.Net
                                                                                request.ClientCertificates,
                                                                                request, buffer};
                                                nstream = (Stream) Activator.CreateInstance (sslStream, args);
+#if SECURITY_DEP
+                                               SslClientStream scs = (SslClientStream) nstream;
+                                               var helper = new ServicePointManager.ChainValidationHelper (request);
+                                               scs.ServerCertValidation2 += new CertificateValidationCallback2 (helper.ValidateChain);
+#endif
                                                certsAvailable = false;
                                        }
                                        // we also need to set ServicePoint.Certificate 
@@ -404,7 +492,7 @@ namespace System.Net
                
                static void ReadDone (IAsyncResult result)
                {
-                       WebConnection cnc = (WebConnection) result.AsyncState;
+                       WebConnection cnc = (WebConnection)result.AsyncState;
                        WebConnectionData data = cnc.Data;
                        Stream ns = cnc.nstream;
                        if (ns == null) {
@@ -415,7 +503,12 @@ namespace System.Net
                        int nread = -1;
                        try {
                                nread = ns.EndRead (result);
+                       } catch (ObjectDisposedException) {
+                               return;
                        } catch (Exception e) {
+                               if (e.InnerException is ObjectDisposedException)
+                                       return;
+
                                cnc.HandleError (WebExceptionStatus.ReceiveFailure, e, "ReadDone1");
                                return;
                        }
@@ -432,28 +525,33 @@ namespace System.Net
 
                        int pos = -1;
                        nread += cnc.position;
-                       if (cnc.readState == ReadState.None) { 
+                       if (data.ReadState == ReadState.None) { 
                                Exception exc = null;
                                try {
-                                       pos = cnc.GetResponse (cnc.buffer, nread);
+                                       pos = GetResponse (data, cnc.sPoint, cnc.buffer, nread);
                                } catch (Exception e) {
                                        exc = e;
                                }
 
-                               if (exc != null) {
+                               if (exc != null || pos == -1) {
                                        cnc.HandleError (WebExceptionStatus.ServerProtocolViolation, exc, "ReadDone4");
                                        return;
                                }
                        }
 
-                       if (cnc.readState != ReadState.Content) {
+                       if (data.ReadState == ReadState.Aborted) {
+                               cnc.HandleError (WebExceptionStatus.RequestCanceled, null, "ReadDone");
+                               return;
+                       }
+
+                       if (data.ReadState != ReadState.Content) {
                                int est = nread * 2;
                                int max = (est < cnc.buffer.Length) ? cnc.buffer.Length : est;
                                byte [] newBuffer = new byte [max];
                                Buffer.BlockCopy (cnc.buffer, 0, newBuffer, 0, nread);
                                cnc.buffer = newBuffer;
                                cnc.position = nread;
-                               cnc.readState = ReadState.None;
+                               data.ReadState = ReadState.None;
                                InitRead (cnc);
                                return;
                        }
@@ -461,14 +559,21 @@ namespace System.Net
                        cnc.position = 0;
 
                        WebConnectionStream stream = new WebConnectionStream (cnc);
+                       bool expect_content = ExpectContent (data.StatusCode, data.request.Method);
+                       string tencoding = null;
+                       if (expect_content)
+                               tencoding = data.Headers ["Transfer-Encoding"];
 
-                       string contentType = data.Headers ["Transfer-Encoding"];
-                       cnc.chunkedRead = (contentType != null && contentType.ToLower ().IndexOf ("chunked") != -1);
+                       cnc.chunkedRead = (tencoding != null && tencoding.IndexOf ("chunked", StringComparison.OrdinalIgnoreCase) != -1);
                        if (!cnc.chunkedRead) {
                                stream.ReadBuffer = cnc.buffer;
                                stream.ReadBufferOffset = pos;
                                stream.ReadBufferSize = nread;
-                               stream.CheckResponseInBuffer ();
+                               try {
+                                       stream.CheckResponseInBuffer ();
+                               } catch (Exception e) {
+                                       cnc.HandleError (WebExceptionStatus.ReceiveFailure, e, "ReadDone7");
+                               }
                        } else if (cnc.chunkStream == null) {
                                try {
                                        cnc.chunkStream = new ChunkStream (cnc.buffer, pos, nread, data.Headers);
@@ -488,14 +593,16 @@ namespace System.Net
 
                        data.stream = stream;
                        
-                       if (!ExpectContent (data.StatusCode) || data.request.Method == "HEAD")
+                       if (!expect_content)
                                stream.ForceCompletion ();
 
                        data.request.SetResponseData (data);
                }
 
-               static bool ExpectContent (int statusCode)
+               static bool ExpectContent (int statusCode, string method)
                {
+                       if (method == "HEAD")
+                               return false;
                        return (statusCode >= 200 && statusCode != 204 && statusCode != 304);
                }
 
@@ -521,7 +628,8 @@ namespace System.Net
                        }
                }
                
-               int GetResponse (byte [] buffer, int max)
+               static int GetResponse (WebConnectionData data, ServicePoint sPoint,
+                                       byte [] buffer, int max)
                {
                        int pos = 0;
                        string line = null;
@@ -529,45 +637,47 @@ namespace System.Net
                        bool isContinue = false;
                        bool emptyFirstLine = false;
                        do {
-                               if (readState == ReadState.None) {
+                               if (data.ReadState == ReadState.Aborted)
+                                       return -1;
+
+                               if (data.ReadState == ReadState.None) {
                                        lineok = ReadLine (buffer, ref pos, max, ref line);
                                        if (!lineok)
-                                               return -1;
+                                               return 0;
 
                                        if (line == null) {
                                                emptyFirstLine = true;
                                                continue;
                                        }
                                        emptyFirstLine = false;
-
-                                       readState = ReadState.Status;
+                                       data.ReadState = ReadState.Status;
 
                                        string [] parts = line.Split (' ');
                                        if (parts.Length < 2)
                                                return -1;
 
                                        if (String.Compare (parts [0], "HTTP/1.1", true) == 0) {
-                                               Data.Version = HttpVersion.Version11;
+                                               data.Version = HttpVersion.Version11;
                                                sPoint.SetVersion (HttpVersion.Version11);
                                        } else {
-                                               Data.Version = HttpVersion.Version10;
+                                               data.Version = HttpVersion.Version10;
                                                sPoint.SetVersion (HttpVersion.Version10);
                                        }
 
-                                       Data.StatusCode = (int) UInt32.Parse (parts [1]);
+                                       data.StatusCode = (int) UInt32.Parse (parts [1]);
                                        if (parts.Length >= 3)
-                                               Data.StatusDescription = String.Join (" ", parts, 2, parts.Length - 2);
+                                               data.StatusDescription = String.Join (" ", parts, 2, parts.Length - 2);
                                        else
-                                               Data.StatusDescription = "";
+                                               data.StatusDescription = "";
 
                                        if (pos >= max)
                                                return pos;
                                }
 
                                emptyFirstLine = false;
-                               if (readState == ReadState.Status) {
-                                       readState = ReadState.Headers;
-                                       Data.Headers = new WebHeaderCollection ();
+                               if (data.ReadState == ReadState.Status) {
+                                       data.ReadState = ReadState.Headers;
+                                       data.Headers = new WebHeaderCollection ();
                                        ArrayList headers = new ArrayList ();
                                        bool finished = false;
                                        while (!finished) {
@@ -593,28 +703,28 @@ namespace System.Net
                                        }
 
                                        if (!finished)
-                                               return -1;
+                                               return 0;
 
                                        foreach (string s in headers)
-                                               Data.Headers.SetInternal (s);
+                                               data.Headers.SetInternal (s);
 
-                                       if (Data.StatusCode == (int) HttpStatusCode.Continue) {
+                                       if (data.StatusCode == (int) HttpStatusCode.Continue) {
                                                sPoint.SendContinue = true;
                                                if (pos >= max)
                                                        return pos;
 
-                                               if (Data.request.ExpectContinue) {
-                                                       Data.request.DoContinueDelegate (Data.StatusCode, Data.Headers);
+                                               if (data.request.ExpectContinue) {
+                                                       data.request.DoContinueDelegate (data.StatusCode, data.Headers);
                                                        // Prevent double calls when getting the
                                                        // headers in several packets.
-                                                       Data.request.ExpectContinue = false;
+                                                       data.request.ExpectContinue = false;
                                                }
 
-                                               readState = ReadState.None;
+                                               data.ReadState = ReadState.None;
                                                isContinue = true;
                                        }
                                        else {
-                                               readState = ReadState.Content;
+                                               data.ReadState = ReadState.Content;
                                                return pos;
                                        }
                                }
@@ -632,8 +742,7 @@ namespace System.Net
                                return;
 
                        keepAlive = request.KeepAlive;
-                       Data = new WebConnectionData ();
-                       Data.request = request;
+                       Data = new WebConnectionData (request);
                retry:
                        Connect (request);
                        if (request.Aborted)
@@ -662,10 +771,13 @@ namespace System.Net
                                return;
                        }
 
-                       readState = ReadState.None;
                        request.SetWriteStream (new WebConnectionStream (this, request));
                }
-               
+
+#if MONOTOUCH
+               static bool warned_about_queue = false;
+#endif
+
                internal EventHandler SendRequest (HttpWebRequest request)
                {
                        if (request.Aborted)
@@ -678,6 +790,12 @@ namespace System.Net
                                        ThreadPool.QueueUserWorkItem (initConn, request);
                                } else {
                                        lock (queue) {
+#if MONOTOUCH
+                                               if (!warned_about_queue) {
+                                                       warned_about_queue = true;
+                                                       Console.WriteLine ("WARNING: An HttpWebRequest was added to the ConnectionGroup queue because the connection limit was reached.");
+                                               }
+#endif
                                                queue.Enqueue (request);
                                        }
                                }
@@ -698,17 +816,18 @@ namespace System.Net
                internal void NextRead ()
                {
                        lock (this) {
-                               Data.request.FinishedReading = true;
+                               if (Data.request != null)
+                                       Data.request.FinishedReading = true;
                                string header = (sPoint.UsesProxy) ? "Proxy-Connection" : "Connection";
                                string cncHeader = (Data.Headers != null) ? Data.Headers [header] : null;
                                bool keepAlive = (Data.Version == HttpVersion.Version11 && this.keepAlive);
                                if (cncHeader != null) {
                                        cncHeader = cncHeader.ToLower ();
-                                       keepAlive = (this.keepAlive && cncHeader.IndexOf ("keep-alive") != -1);
+                                       keepAlive = (this.keepAlive && cncHeader.IndexOf ("keep-alive", StringComparison.Ordinal) != -1);
                                }
 
                                if ((socket != null && !socket.Connected) ||
-                                  (!keepAlive || (cncHeader != null && cncHeader.IndexOf ("close") != -1))) {
+                                  (!keepAlive || (cncHeader != null && cncHeader.IndexOf ("close", StringComparison.Ordinal) != -1))) {
                                        Close (false);
                                }
 
@@ -767,17 +886,19 @@ namespace System.Net
 
                internal IAsyncResult BeginRead (HttpWebRequest request, byte [] buffer, int offset, int size, AsyncCallback cb, object state)
                {
+                       Stream s = null;
                        lock (this) {
                                if (Data.request != request)
                                        throw new ObjectDisposedException (typeof (NetworkStream).FullName);
                                if (nstream == null)
                                        return null;
+                               s = nstream;
                        }
 
                        IAsyncResult result = null;
-                       if (!chunkedRead || chunkStream.WantMore) {
+                       if (!chunkedRead || (!chunkStream.DataAvailable && chunkStream.WantMore)) {
                                try {
-                                       result = nstream.BeginRead (buffer, offset, size, cb, state);
+                                       result = s.BeginRead (buffer, offset, size, cb, state);
                                        cb = null;
                                } catch (Exception) {
                                        HandleError (WebExceptionStatus.ReceiveFailure, null, "chunked BeginRead");
@@ -801,11 +922,13 @@ namespace System.Net
                
                internal int EndRead (HttpWebRequest request, IAsyncResult result)
                {
+                       Stream s = null;
                        lock (this) {
                                if (Data.request != request)
                                        throw new ObjectDisposedException (typeof (NetworkStream).FullName);
                                if (nstream == null)
                                        throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+                               s = nstream;
                        }
 
                        int nbytes = 0;
@@ -815,9 +938,9 @@ namespace System.Net
                                wr = (WebAsyncResult) nsAsync;
                                IAsyncResult inner = wr.InnerAsyncResult;
                                if (inner != null && !(inner is WebAsyncResult))
-                                       nbytes = nstream.EndRead (inner);
+                                       nbytes = s.EndRead (inner);
                        } else if (!(nsAsync is WebAsyncResult)) {
-                               nbytes = nstream.EndRead (nsAsync);
+                               nbytes = s.EndRead (nsAsync);
                                wr = (WebAsyncResult) result;
                        }
 
@@ -888,16 +1011,18 @@ namespace System.Net
 
                internal IAsyncResult BeginWrite (HttpWebRequest request, byte [] buffer, int offset, int size, AsyncCallback cb, object state)
                {
+                       Stream s = null;
                        lock (this) {
                                if (Data.request != request)
                                        throw new ObjectDisposedException (typeof (NetworkStream).FullName);
                                if (nstream == null)
                                        return null;
+                               s = nstream;
                        }
 
                        IAsyncResult result = null;
                        try {
-                               result = nstream.BeginWrite (buffer, offset, size, cb, state);
+                               result = s.BeginWrite (buffer, offset, size, cb, state);
                        } catch (Exception) {
                                status = WebExceptionStatus.SendFailure;
                                throw;
@@ -911,15 +1036,17 @@ namespace System.Net
                        if (request.FinishedReading)
                                return;
 
+                       Stream s = null;
                        lock (this) {
                                if (Data.request != request)
                                        throw new ObjectDisposedException (typeof (NetworkStream).FullName);
                                if (nstream == null)
                                        throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+                               s = nstream;
                        }
 
                        try {
-                               nstream.EndWrite (result);
+                               s.EndWrite (result);
                        } catch (Exception exc) {
                                status = WebExceptionStatus.SendFailure;
                                if (exc.InnerException != null)
@@ -933,15 +1060,17 @@ namespace System.Net
                        if (request.FinishedReading)
                                return true;
 
+                       Stream s = null;
                        lock (this) {
                                if (Data.request != request)
                                        throw new ObjectDisposedException (typeof (NetworkStream).FullName);
                                if (nstream == null)
                                        throw new ObjectDisposedException (typeof (NetworkStream).FullName);
+                               s = nstream;
                        }
 
                        try {
-                               nstream.EndWrite (result);
+                               s.EndWrite (result);
                                return true;
                        } catch {
                                status = WebExceptionStatus.SendFailure;
@@ -951,18 +1080,20 @@ namespace System.Net
 
                internal int Read (HttpWebRequest request, byte [] buffer, int offset, int size)
                {
+                       Stream s = null;
                        lock (this) {
                                if (Data.request != request)
                                        throw new ObjectDisposedException (typeof (NetworkStream).FullName);
                                if (nstream == null)
                                        return 0;
+                               s = nstream;
                        }
 
                        int result = 0;
                        try {
                                bool done = false;
                                if (!chunkedRead) {
-                                       result = nstream.Read (buffer, offset, size);
+                                       result = s.Read (buffer, offset, size);
                                        done = (result == 0);
                                }
 
@@ -991,15 +1122,17 @@ namespace System.Net
                internal bool Write (HttpWebRequest request, byte [] buffer, int offset, int size, ref string err_msg)
                {
                        err_msg = null;
+                       Stream s = null;
                        lock (this) {
                                if (Data.request != request)
                                        throw new ObjectDisposedException (typeof (NetworkStream).FullName);
                                if (nstream == null)
                                        return false;
+                               s = nstream;
                        }
 
                        try {
-                               nstream.Write (buffer, offset, size);
+                               s.Write (buffer, offset, size);
                                // here SSL handshake should have been done
                                if (ssl && !certsAvailable)
                                        GetCertificates ();
@@ -1041,10 +1174,20 @@ namespace System.Net
                                        socket = null;
                                }
 
+                               if (ntlm_authenticated)
+                                       ResetNtlm ();
+                               if (Data != null) {
+                                       lock (Data) {
+                                               Data.ReadState = ReadState.Aborted;
+                                       }
+                               }
                                busy = false;
                                Data = new WebConnectionData ();
                                if (sendNext)
                                        SendNext ();
+                               
+                               connect_request = null;
+                               connect_ntlm_auth_state = NtlmAuthState.None;
                        }
                }
 
@@ -1053,7 +1196,7 @@ namespace System.Net
                        lock (this) {
                                lock (queue) {
                                        HttpWebRequest req = (HttpWebRequest) sender;
-                                       if (Data.request == req) {
+                                       if (Data.request == req || Data.request == null) {
                                                if (!req.FinishedReading) {
                                                        status = WebExceptionStatus.RequestCanceled;
                                                        Close (false);
@@ -1115,12 +1258,10 @@ namespace System.Net
                        set { ntlm_credentials = value; }
                }
 
-#if NET_1_1
                internal bool UnsafeAuthenticatedConnectionSharing {
                        get { return unsafe_sharing; }
                        set { unsafe_sharing = value; }
                }
-#endif
                // -
        }
 }