2008-11-04 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mcs / class / System / System.Net / HttpWebRequest.cs
index e575f8e1f71a652e9fc55b27d6adb6488e6e5639..0bb5fb7948f7af94574b3e357d6b5df3dc016c4e 100644 (file)
@@ -42,6 +42,10 @@ using System.Security.Cryptography.X509Certificates;
 using System.Text;
 using System.Threading;
 
+#if NET_2_0
+using System.Net.Cache;
+#endif
+
 namespace System.Net 
 {
        [Serializable]
@@ -92,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;
@@ -111,14 +116,22 @@ namespace System.Net
                        }
                }
 #endif
-               
-               internal HttpWebRequest (Uri uri) 
+
+#if NET_2_1
+               public
+#else
+               internal
+#endif
+               HttpWebRequest (Uri uri) 
                {
                        this.requestUri = uri;
                        this.actualUri = uri;
                        this.proxy = GlobalProxySelection.Select;
                }               
                
+#if NET_2_0
+               [Obsolete ("Serialization is obsoleted for this type", false)]
+#endif
                protected HttpWebRequest (SerializationInfo serializationInfo, StreamingContext streamingContext) 
                {
                        SerializationInfo info = serializationInfo;
@@ -145,7 +158,11 @@ namespace System.Net
                }
                
                // Properties
-               
+
+               internal bool UsesNtlmAuthentication {
+                       get { return is_ntlm_auth; }
+               }
+
                public string Accept {
                        get { return webHeaders ["Accept"]; }
                        set {
@@ -167,11 +184,30 @@ namespace System.Net
                        get { return allowBuffering; }
                        set { allowBuffering = value; }
                }
+
+#if NET_2_0
+               static Exception GetMustImplement ()
+               {
+                       return new NotImplementedException ();
+               }
+               
+               [MonoTODO]
+               public DecompressionMethods AutomaticDecompression
+               {
+                       get {
+                               throw GetMustImplement ();
+                       }
+                       set {
+                               throw GetMustImplement ();
+                       }
+               }
+#endif
                
                internal bool InternalAllowBuffering {
                        get {
                                return (allowBuffering && (method != "HEAD" && method != "GET" &&
-                                                       method != "MKCOL" && method != "CONNECT"));
+                                                       method != "MKCOL" && method != "CONNECT" &&
+                                                       method != "DELETE" && method != "TRACE"));
                        }
                }
                
@@ -182,6 +218,12 @@ namespace System.Net
 
                                return certificates;
                        }
+#if NET_2_0
+                       [MonoTODO]
+                       set {
+                               throw GetMustImplement ();
+                       }
+#endif
                }
                
                public string Connection {
@@ -252,6 +294,30 @@ namespace System.Net
                        get { return credentials; }
                        set { credentials = value; }
                }
+
+#if NET_2_0
+               [MonoTODO]
+               public static new RequestCachePolicy DefaultCachePolicy
+               {
+                       get {
+                               throw GetMustImplement ();
+                       }
+                       set {
+                               throw GetMustImplement ();
+                       }
+               }
+               
+               [MonoTODO]
+               public static int DefaultMaximumErrorResponseLength
+               {
+                       get {
+                               throw GetMustImplement ();
+                       }
+                       set {
+                               throw GetMustImplement ();
+                       }
+               }
+#endif
                
                public string Expect {
                        get { return webHeaders ["Expect"]; }
@@ -400,8 +466,10 @@ namespace System.Net
                        get { return proxy; }
                        set { 
                                CheckRequestStarted ();
+#if ONLY_1_1
                                if (value == null)
                                        throw new ArgumentNullException ("value");
+#endif
 
                                proxy = value;
                                servicePoint = null; // we may need a new one
@@ -468,6 +536,19 @@ namespace System.Net
                                webHeaders.RemoveAndAdd ("Transfer-Encoding", value);
                        }
                }
+
+#if NET_2_0
+               [MonoTODO]
+               public override bool UseDefaultCredentials
+               {
+                       get {
+                               throw GetMustImplement ();
+                       }
+                       set {
+                               throw GetMustImplement ();
+                       }
+               }
+#endif
                
                public string UserAgent {
                        get { return webHeaders ["User-Agent"]; }
@@ -476,7 +557,6 @@ namespace System.Net
 
 #if NET_1_1
                bool unsafe_auth_blah;
-               [MonoTODO]
                public bool UnsafeAuthenticatedConnectionSharing
                {
                        get { return unsafe_auth_blah; }
@@ -579,7 +659,8 @@ namespace System.Net
                        if (aborted)
                                throw new WebException ("The request was previosly aborted.");
 
-                       bool send = !(method == "GET" || method == "CONNECT" || method == "HEAD");
+                       bool send = !(method == "GET" || method == "CONNECT" || method == "HEAD" ||
+                                       method == "TRACE" || method == "DELETE");
                        if (method == null || !send)
                                throw new ProtocolViolationException ("Cannot send data when method is: " + method);
 
@@ -635,8 +716,12 @@ namespace System.Net
                
                public override Stream GetRequestStream()
                {
-                       IAsyncResult asyncResult = BeginGetRequestStream (null, null);
-                       asyncWrite = (WebAsyncResult) asyncResult;
+                       IAsyncResult asyncResult = asyncWrite;
+                       if (asyncResult == null) {
+                               asyncResult = BeginGetRequestStream (null, null);
+                               asyncWrite = (WebAsyncResult) asyncResult;
+                       }
+
                        if (!asyncResult.AsyncWaitHandle.WaitOne (timeout, false)) {
                                Abort ();
                                throw new WebException ("The request timed out", WebExceptionStatus.Timeout);
@@ -772,6 +857,15 @@ namespace System.Net
                
                void ISerializable.GetObjectData (SerializationInfo serializationInfo,
                                                  StreamingContext streamingContext)
+               {
+                       GetObjectData (serializationInfo, streamingContext);
+               }
+
+#if NET_2_0
+               protected override
+#endif
+               void GetObjectData (SerializationInfo serializationInfo,
+                                   StreamingContext streamingContext)
                {
                        SerializationInfo info = serializationInfo;
 
@@ -826,6 +920,10 @@ namespace System.Net
                                        return false;
                                */
 
+                               contentLength = 0;
+                               bodyBufferLength = 0;
+                               bodyBuffer = null;
+                               method = "GET";
                                uriString = webResponse.Headers ["Location"];
                                break;
                        case HttpStatusCode.SeeOther: //303
@@ -887,10 +985,11 @@ namespace System.Net
                                expectContinue = false;
                        }
 
-                       string connectionHeader = (ProxyQuery) ? "Proxy-Connection" : "Connection";
-                       webHeaders.RemoveInternal ((!ProxyQuery) ? "Proxy-Connection" : "Connection");
-                       bool spoint10 = (servicePoint.ProtocolVersion == null ||
-                                        servicePoint.ProtocolVersion == HttpVersion.Version10);
+                       bool proxy_query = ProxyQuery;
+                       string connectionHeader = (proxy_query) ? "Proxy-Connection" : "Connection";
+                       webHeaders.RemoveInternal ((!proxy_query) ? "Proxy-Connection" : "Connection");
+                       Version proto_version = servicePoint.ProtocolVersion;
+                       bool spoint10 = (proto_version == null || proto_version == HttpVersion.Version10);
 
                        if (keepAlive && (version == HttpVersion.Version10 || spoint10)) {
                                webHeaders.RemoveAndAdd (connectionHeader, "keep-alive");
@@ -900,7 +999,7 @@ namespace System.Net
 
                        webHeaders.SetInternal ("Host", actualUri.Authority);
                        if (cookieContainer != null) {
-                               string cookieHeader = cookieContainer.GetCookieHeader (requestUri);
+                               string cookieHeader = cookieContainer.GetCookieHeader (actualUri);
                                if (cookieHeader != "")
                                        webHeaders.SetInternal ("Cookie", cookieHeader);
                        }
@@ -973,7 +1072,7 @@ namespace System.Net
                                writeStream.SetHeaders (bytes, 0, bytes.Length);
                        } catch (WebException wexc) {
                                SetWriteStreamError (wexc.Status);
-                       } catch (Exception e) {
+                       } catch (Exception) {
                                SetWriteStreamError (WebExceptionStatus.SendFailure);
                        }
                }
@@ -1000,7 +1099,7 @@ namespace System.Net
                                writeStream.Write (bodyBuffer, 0, bodyBufferLength);
                                bodyBuffer = null;
                                writeStream.Close ();
-                       } else if (method == "PUT" || method == "POST") {
+                       } else if (method == "PUT" || method == "POST" || method == "OPTIONS") {
                                if (getResponseCalled && !writeStream.RequestWritten)
                                        writeStream.WriteRequest ();
                        }
@@ -1050,6 +1149,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) {
@@ -1088,12 +1208,29 @@ 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)
+                                                       writeStream.KillBuffer ();
+
                                                r.SetCompleted (false, webResponse);
                                                r.DoCallback ();
                                        } else {
                                                if (webResponse != null) {
+                                                       if (is_ntlm_auth) {
+                                                               HandleNtlmAuth (r);
+                                                               return;
+                                                       }
                                                        webResponse.Close ();
-                                                       webResponse = null;
                                                }
                                                haveResponse = false;
                                                webResponse = null;
@@ -1135,6 +1272,7 @@ namespace System.Net
 
                        webHeaders [(isProxy) ? "Proxy-Authorization" : "Authorization"] = auth.Message;
                        authCompleted = auth.Complete;
+                       is_ntlm_auth = (auth.Module.AuthenticationType == "NTLM");
                        return true;
                }
 
@@ -1159,10 +1297,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;
                                                }
                                                
@@ -1186,7 +1322,7 @@ namespace System.Net
                                        string err = String.Format ("The remote server returned an error: ({0}) {1}.",
                                                                    (int) code, webResponse.StatusDescription);
                                        throwMe = new WebException (err, null, protoError, webResponse);
-                               } else if ((int) code >= 300 && allowAutoRedirect && redirects > maxAutoRedirect) {
+                               } else if ((int) code >= 300 && allowAutoRedirect && redirects >= maxAutoRedirect) {
                                        throwMe = new WebException ("Max. redirections exceeded.", null,
                                                                    protoError, webResponse);
                                        webResponse.ReadAll ();