Ver Fonte

2008-10-08 Gonzalo Paniagua Javier <[email protected]>

	* WebConnection.cs:
	* ServicePoint.cs:
	* WebConnectionGroup.cs:
	* HttpWebRequest.cs:
	* WebConnectionStream.cs: reuse the same connection when doing NTLM
	authentication. Fixes bug #323375.
	Implemented support for UnsafeAuthenticatedConnectionSharing.


svn path=/trunk/mcs/; revision=115265
Gonzalo Paniagua Javier há 17 anos atrás
pai
commit
61bbe5b41b

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

@@ -1,3 +1,13 @@
+2008-10-08 Gonzalo Paniagua Javier <[email protected]>
+
+	* WebConnection.cs:
+	* ServicePoint.cs:
+	* WebConnectionGroup.cs:
+	* HttpWebRequest.cs:
+	* WebConnectionStream.cs: reuse the same connection when doing NTLM
+	authentication. Fixes bug #323375.
+	Implemented support for UnsafeAuthenticatedConnectionSharing.
+
 2008-10-08 Gonzalo Paniagua Javier <[email protected]>
 
 	* HttpConnection.cs:

+ 42 - 6
mcs/class/System/System.Net/HttpWebRequest.cs

@@ -96,6 +96,7 @@ namespace System.Net
 		bool getResponseCalled;
 		Exception saved_exc;
 		object locker = new object ();
+		bool is_ntlm_auth;
 #if NET_1_1
 		int maxResponseHeadersLength;
 		static int defaultMaxResponseHeadersLength;
@@ -157,7 +158,11 @@ namespace System.Net
 		}
 		
 		// Properties
-		
+
+		internal bool UsesNtlmAuthentication {
+			get { return is_ntlm_auth; }
+		}
+
 		public string Accept {
 			get { return webHeaders ["Accept"]; }
 			set {
@@ -552,7 +557,6 @@ namespace System.Net
 
 #if NET_1_1
 		bool unsafe_auth_blah;
-		[MonoTODO]
 		public bool UnsafeAuthenticatedConnectionSharing
 		{
 			get { return unsafe_auth_blah; }
@@ -717,7 +721,7 @@ namespace System.Net
 				asyncResult = BeginGetRequestStream (null, null);
 				asyncWrite = (WebAsyncResult) asyncResult;
 			}
-		
+
 			if (!asyncResult.AsyncWaitHandle.WaitOne (timeout, false)) {
 				Abort ();
 				throw new WebException ("The request timed out", WebExceptionStatus.Timeout);
@@ -1144,6 +1148,27 @@ namespace System.Net
 			}
 		}
 
+		void HandleNtlmAuth (WebAsyncResult r)
+		{
+			WebConnectionStream wce = webResponse.GetResponseStream () as WebConnectionStream;
+			if (wce != null) {
+				WebConnection cnc = wce.Connection;
+				cnc.PriorityRequest = this;
+				bool isProxy = (proxy != null && !proxy.IsBypassed (actualUri));
+				ICredentials creds = (!isProxy) ? credentials : proxy.Credentials;
+				if (creds != null) {
+					cnc.NtlmCredential = creds.GetCredential (requestUri, "NTLM");
+#if NET_1_1
+					cnc.UnsafeAuthenticatedConnectionSharing = unsafe_auth_blah;
+#endif
+				}
+			}
+			r.Reset ();
+			haveResponse = false;
+			webResponse.ReadAll ();
+			webResponse = null;
+		}
+
 		internal void SetResponseData (WebConnectionData data)
 		{
 			if (aborted) {
@@ -1182,6 +1207,15 @@ namespace System.Net
 				try {
 					redirected = CheckFinalStatus (r);
 					if (!redirected) {
+						if (is_ntlm_auth && authCompleted && webResponse != null
+							&& (int)webResponse.StatusCode < 400) {
+							WebConnectionStream wce = webResponse.GetResponseStream () as WebConnectionStream;
+							if (wce != null) {
+								WebConnection cnc = wce.Connection;
+								cnc.NtlmAuthenticated = true;
+							}
+						}
+
 						// clear internal buffer so that it does not
 						// hold possible big buffer (bug #397627)
 						if (writeStream != null)
@@ -1191,8 +1225,11 @@ namespace System.Net
 						r.DoCallback ();
 					} else {
 						if (webResponse != null) {
+							if (is_ntlm_auth) {
+								HandleNtlmAuth (r);
+								return;
+							}
 							webResponse.Close ();
-							webResponse = null;
 						}
 						haveResponse = false;
 						webResponse = null;
@@ -1234,6 +1271,7 @@ namespace System.Net
 
 			webHeaders [(isProxy) ? "Proxy-Authorization" : "Authorization"] = auth.Message;
 			authCompleted = auth.Complete;
+			is_ntlm_auth = (auth.Module.AuthenticationType == "NTLM");
 			return true;
 		}
 
@@ -1258,10 +1296,8 @@ namespace System.Net
 						if (InternalAllowBuffering) {
 							bodyBuffer = writeStream.WriteBuffer;
 							bodyBufferLength = writeStream.WriteBufferLength;
-							webResponse.Close ();
 							return true;
 						} else if (method != "PUT" && method != "POST") {
-							webResponse.Close ();
 							return true;
 						}
 						

+ 1 - 1
mcs/class/System/System.Net/ServicePoint.cs

@@ -292,7 +292,7 @@ namespace System.Net
 			
 			lock (locker) {
 				WebConnectionGroup cncGroup = GetConnectionGroup (groupName);
-				cnc = cncGroup.GetConnection ();
+				cnc = cncGroup.GetConnection (request);
 			}
 			
 			return cnc.SendRequest (request);

+ 42 - 1
mcs/class/System/System.Net/WebConnection.cs

@@ -66,6 +66,12 @@ namespace System.Net
 		bool reused;
 		int position;
 		bool busy;
+		HttpWebRequest priority_request;
+		NetworkCredential ntlm_credentials;
+		bool ntlm_authenticated;
+#if NET_1_1
+		bool unsafe_sharing;
+#endif
 
 		bool ssl;
 		bool certsAvailable;
@@ -640,7 +646,12 @@ namespace System.Net
 				}
 
 				busy = false;
-				SendNext ();
+				if (priority_request != null) {
+					SendRequest (priority_request);
+					priority_request = null;
+				} else {
+					SendNext ();
+				}
 			}
 		}
 		
@@ -941,6 +952,13 @@ namespace System.Net
 			}
 		}
 
+		internal void ResetNtlm ()
+		{
+			ntlm_authenticated = false;
+			ntlm_credentials = null;
+			unsafe_sharing = false;
+		}
+
 		internal bool Busy {
 			get { lock (this) return busy; }
 		}
@@ -952,6 +970,29 @@ namespace System.Net
 				}
 			}
 		}
+
+		// -Used for NTLM authentication
+		internal HttpWebRequest PriorityRequest {
+			set { priority_request = value; }
+		}
+
+		internal bool NtlmAuthenticated {
+			get { return ntlm_authenticated; }
+			set { ntlm_authenticated = value; }
+		}
+
+		internal NetworkCredential NtlmCredential {
+			get { return ntlm_credentials; }
+			set { ntlm_credentials = value; }
+		}
+
+#if NET_1_1
+		internal bool UnsafeAuthenticatedConnectionSharing {
+			get { return unsafe_sharing; }
+			set { unsafe_sharing = value; }
+		}
+#endif
+		// -
 	}
 }
 

+ 29 - 3
mcs/class/System/System.Net/WebConnectionGroup.cs

@@ -51,7 +51,7 @@ namespace System.Net
 			queue = new Queue ();
 		}
 
-		public WebConnection GetConnection ()
+		public WebConnection GetConnection (HttpWebRequest request)
 		{
 			WebConnection cnc = null;
 			lock (connections) {
@@ -76,13 +76,38 @@ namespace System.Net
 						connections.RemoveAt ((int) removed [i]);
 				}
 
-				cnc = CreateOrReuseConnection ();
+				cnc = CreateOrReuseConnection (request);
 			}
 
 			return cnc;
 		}
 
-		WebConnection CreateOrReuseConnection ()
+		static void PrepareSharingNtlm (WebConnection cnc, HttpWebRequest request)
+		{
+			if (!cnc.NtlmAuthenticated)
+				return;
+
+			bool needs_reset = false;
+			NetworkCredential cnc_cred = cnc.NtlmCredential;
+			NetworkCredential req_cred = request.Credentials.GetCredential (request.RequestUri, "NTLM");
+			if (cnc_cred.Domain != req_cred.Domain || cnc_cred.UserName != req_cred.UserName ||
+				cnc_cred.Password != req_cred.Password) {
+				needs_reset = true;
+			}
+#if NET_1_1
+			if (!needs_reset) {
+				bool req_sharing = request.UnsafeAuthenticatedConnectionSharing;
+				bool cnc_sharing = cnc.UnsafeAuthenticatedConnectionSharing;
+				needs_reset = (req_sharing == false || req_sharing != cnc_sharing);
+			}
+#endif
+			if (needs_reset) {
+				cnc.Close (false); // closes the authenticated connection
+				cnc.ResetNtlm ();
+			}
+		}
+
+		WebConnection CreateOrReuseConnection (HttpWebRequest request)
 		{
 			// lock is up there.
 			WebConnection cnc;
@@ -102,6 +127,7 @@ namespace System.Net
 				if (cnc.Busy)
 					continue;
 
+				PrepareSharingNtlm (cnc, request);
 				return cnc;
 			}
 

+ 4 - 0
mcs/class/System/System.Net/WebConnectionStream.cs

@@ -104,6 +104,10 @@ namespace System.Net
 			if (sendChunked)
 				pending = new ManualResetEvent (true);
 		}
+
+		internal WebConnection Connection {
+			get { return cnc; }
+		}
 #if NET_2_0
 		public override bool CanTimeout {
 			get { return true; }