Multiple fixes for WebClient (from NCL tests)
authorSebastien Pouliot <sebastien@ximian.com>
Tue, 31 Aug 2010 17:16:21 +0000 (13:16 -0400)
committerSebastien Pouliot <sebastien@ximian.com>
Tue, 31 Aug 2010 17:17:22 +0000 (13:17 -0400)
* mcs/class/System.Net/System.Net/InternalWebRequestStreamWrapper.cs:
Ensure WebClient.WriteStreamClosedCallback is never called more than
once (even if the stream was closed by the caller). Supply the length
of the data that was written to the stream to WebClient.

* mcs/class/System.Net/System.Net/WebClient_2_1.cs: Keep an Uri of
BaseAddress handy since we'll need it later. Ensure OnWriteStreamClosed
is at least called once (inside finally). Emit UploadProgressChanged
(instead of Download*) when uploading.

* mcs/class/System.Net/System.Net/WebRequest_2_1.cs: Change text for
InvalidOperationException when the URI is not absolute (some MS tests
check for, case-sensitive, "URI").

mcs/class/System.Net/System.Net/InternalWebRequestStreamWrapper.cs
mcs/class/System.Net/System.Net/WebClient_2_1.cs
mcs/class/System.Net/System.Net/WebRequest_2_1.cs

index bd05bc4d5666d1e73c6604c2965418c4867927c2..003684ddbc553d2feded3a3ae5a0049c0859bede 100644 (file)
@@ -72,8 +72,10 @@ namespace System.Net {
                        }
                        finally {
                                // if used from WebClient then notify that the stream was closed
-                               if (WebClient != null)
-                                       WebClient.WriteStreamClosedCallback (WebClientData);
+                               if (WebClient != null) {
+                                       WebClient.WriteStreamClosedCallback (WebClientData, data.Length);
+                                       WebClient = null; // notify only once
+                               }
                        }
                }
 
index 7c964871e284d20558c17ee06858f1244db9cf10..eadb8b55f0c455092fd8e9135d87a63d8da8db4e 100644 (file)
@@ -45,6 +45,7 @@ namespace System.Net {
                WebHeaderCollection headers;
                WebHeaderCollection responseHeaders;
                string baseAddress;
+               Uri base_address_uri;
                bool is_busy;
                Encoding encoding = Encoding.UTF8;
                bool allow_read_buffering = true;
@@ -52,6 +53,7 @@ namespace System.Net {
                WebRequest request;
                object locker;
                CallbackData callback_data;
+               long upload_length;
 
                public WebClient ()
                {
@@ -59,7 +61,7 @@ namespace System.Net {
                        // but without adding dependency on System.Windows.dll. GetData is [SecurityCritical]
                        // this makes the default .ctor [SecuritySafeCritical] which would be a problem (inheritance)
                        // but it happens that MS SL2 also has this default .ctor as SSC :-)
-                       baseAddress = (AppDomain.CurrentDomain.GetData ("xap_uri") as string);
+                       BaseAddress = (AppDomain.CurrentDomain.GetData ("xap_uri") as string);
                        locker = new object ();
                        UseDefaultCredentials = true;
                }
@@ -71,12 +73,12 @@ namespace System.Net {
                        set {
                                if (String.IsNullOrEmpty (value)) {
                                        baseAddress = String.Empty;
+                                       base_address_uri = null;
                                } else {
-                                       Uri uri = null;
-                                       if (!Uri.TryCreate (value, UriKind.Absolute, out uri))
+                                       if (!Uri.TryCreate (value, UriKind.Absolute, out base_address_uri))
                                                throw new ArgumentException ("Invalid URI");
 
-                                       baseAddress = Uri.UnescapeDataString (uri.AbsoluteUri);
+                                       baseAddress = Uri.UnescapeDataString (base_address_uri.AbsoluteUri);
                                }
                        }
                }
@@ -167,7 +169,8 @@ namespace System.Net {
                {
                        callback_data = callbackData;
                        WebRequest request = GetWebRequest (uri);
-                       request.Method = DetermineMethod (uri, method);
+                       // do not send a relative URI to Determine method
+                       request.Method = DetermineMethod (request.RequestUri, method);
                        // copy headers to the request - some needs special treatments
                        foreach (string header in Headers) {
                                switch (header.ToLowerInvariant ()) {
@@ -219,11 +222,13 @@ namespace System.Net {
                {
                        if (request != null)
                                request.Abort ();
+                       upload_length = 0;
                }
 
                void CompleteAsync ()
                {
                        is_busy = false;
+                       upload_length = 0;
                }
 
                internal class CallbackData {
@@ -412,7 +417,7 @@ namespace System.Net {
                        }
                }
 
-               internal void WriteStreamClosedCallback (object WebClientData)
+               internal void WriteStreamClosedCallback (object WebClientData, long length)
                {
                        try {
                                request.BeginGetResponse (OpenWriteAsyncResponseCallback, WebClientData);
@@ -422,17 +427,31 @@ namespace System.Net {
                                        OnWriteStreamClosed (new WriteStreamClosedEventArgs (e));
                                }, null);
                        }
+                       finally {
+                               // kind of dummy, 0% progress, that is always emitted
+                               upload_length = length;
+                               OnUploadProgressChanged (
+                                       new UploadProgressChangedEventArgs (0, -1, length, -1, 0, callback_data.user_token));
+                       }
                }
 
                private void OpenWriteAsyncResponseCallback (IAsyncResult result)
                {
+                       Exception ex = null;
                        try {
                                WebResponse response = request.EndGetResponse (result);
                                ProcessResponse (response);
                        }
+                       catch (SecurityException se) {
+                               // SecurityException inside a SecurityException (not a WebException) for SL compatibility
+                               ex = new SecurityException (String.Empty, se);
+                       }
                        catch (Exception e) {
+                               ex = new WebException ("Could not complete operation.", e, WebExceptionStatus.UnknownError, null);
+                       }
+                       finally {
                                callback_data.sync_context.Post (delegate (object sender) {
-                                       OnWriteStreamClosed (new WriteStreamClosedEventArgs (e));
+                                       OnWriteStreamClosed (new WriteStreamClosedEventArgs (ex));
                                }, null);
                        }
                }
@@ -483,6 +502,12 @@ namespace System.Net {
                                request.Abort ();
                                throw;
                        }
+                       finally {
+                               // kind of dummy, 0% progress, that is always emitted
+                               upload_length = callback_data.data.Length;
+                               OnUploadProgressChanged (
+                                       new UploadProgressChangedEventArgs (0, -1, upload_length, -1, 0, callback_data.user_token));
+                       }
                }
 
                private void UploadStringResponseAsyncCallback (IAsyncResult result)
@@ -576,7 +601,7 @@ namespace System.Net {
                                throw new ArgumentNullException ("address");
 
                        // if the URI is relative then we use our base address URI to make an absolute one
-                       Uri uri = address.IsAbsoluteUri ? address : new Uri (new Uri (baseAddress), address);
+                       Uri uri = address.IsAbsoluteUri || base_address_uri == null ? address : new Uri (base_address_uri, address);
 
                        HttpWebRequest request = (HttpWebRequest) WebRequest.Create (uri);
                        request.AllowReadStreamBuffering = AllowReadStreamBuffering;
@@ -585,9 +610,15 @@ namespace System.Net {
 
                        request.progress = delegate (long read, long length) {
                                callback_data.sync_context.Post (delegate (object sender) {
-                                       OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (read, length, callback_data.user_token));
+                                       if (upload_length > 0) {
+                                               // always emitted as 50% with an unknown (-1) TotalBytesToSend
+                                               OnUploadProgressChanged (new UploadProgressChangedEventArgs (read, length, 
+                                                       upload_length, -1, 50, callback_data.user_token));
+                                       } else {
+                                               OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (read, length, 
+                                                       callback_data.user_token));
+                                       }
                                }, null);
-
                        };
                        return request;
                }
index 8edf07bc1be57dcf25f8c4eaf639f5a8118612e3..8900a19f5dcf535aabac6cfe5bc20cd0b19d006a 100644 (file)
@@ -107,7 +107,7 @@ namespace System.Net {
                        if (uri == null)
                                throw new ArgumentNullException ("uri");
                        if (!uri.IsAbsoluteUri)
-                               throw new InvalidOperationException ("Uri is not absolute.");
+                               throw new InvalidOperationException ("This operation is not supported for a relative URI.");
 
                        IWebRequestCreate creator = null;