New tests.
[mono.git] / mcs / class / System.Net / System.Net / WebClient_2_1.cs
index 699bd42509bf60f71077e8bf5a40e39d00ae7051..1487adc40b62382f791f2bfd94b73d82e2829099 100644 (file)
@@ -9,7 +9,7 @@
 //     Stephane Delcroix (sdelcroix@novell.com)
 //
 // Copyright 2003 Ximian, Inc. (http://www.ximian.com)
-// Copyright 2006, 2008 Novell, Inc. (http://www.novell.com)
+// Copyright 2006, 2008, 2009-2010 Novell, Inc. (http://www.novell.com)
 //
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-//
-// Notes on CancelAsync and Async methods:
-//
-//    WebClient.CancelAsync is implemented by calling Thread.Interrupt
-//    in our helper thread.   The various async methods have to cancel
-//    any ongoing requests by calling request.Abort () at that point.
-//    In a few places (UploadDataCore, UploadValuesCore,
-//    UploadFileCore) we catch the ThreadInterruptedException and
-//    abort the request there.
-//
-//    Higher level routines (the async callbacks) also need to catch
-//    the exception and raise the OnXXXXCompleted events there with
-//    the "canceled" flag set to true. 
-//
-//    In a few other places where these helper routines are not used
-//    (OpenReadAsync for example) catching the ThreadAbortException
-//    also must abort the request.
-//
-//    The Async methods currently differ in their implementation from
-//    the .NET implementation in that we manually catch any other
-//    exceptions and correctly raise the OnXXXXCompleted passing the
-//    Exception that caused the problem.   The .NET implementation
-//    does not seem to have a mechanism to flag errors that happen
-//    during downloads though.    We do this because we still need to
-//    catch the exception on these helper threads, or we would
-//    otherwise kill the application (on the 2.x profile, uncaught
-//    exceptions in threads terminate the application).
-//
-using System;
-using System.Collections.Specialized;
-using System.ComponentModel;
+
 using System.IO;
-using System.Runtime.InteropServices;
-using System.Runtime.Serialization;
 using System.Text;
 using System.Threading;
-using System.Net.Cache;
-
-namespace System.Net 
-{
-#if NET_2_1
-       public class WebClient
-       {
-//             static readonly string urlEncodedCType = "application/x-www-form-urlencoded";
-//             static byte [] hexBytes;
-//             ICredentials credentials;
-//             WebHeaderCollection headers;
-//             WebHeaderCollection responseHeaders;
-//             Uri baseAddress;
-//             string baseString;
-//             NameValueCollection queryString;
-               bool is_busy, async;
-               Thread async_thread;
-//             Encoding encoding = Encoding.Default;
-//             IWebProxy proxy;
-//
-//             // Constructors
-//             static WebClient ()
-//             {
-//                     hexBytes = new byte [16];
-//                     int index = 0;
-//                     for (int i = '0'; i <= '9'; i++, index++)
-//                             hexBytes [index] = (byte) i;
-//
-//                     for (int i = 'A'; i <= 'F'; i++, index++)
-//                             hexBytes [index] = (byte) i;
-//             }
-//             
-//             public WebClient ()
-//             {
-//             }
-//             
-//             // Properties
-//             
-//             public string BaseAddress {
-//                     get {
-//                             if (baseString == null) {
-//                                     if (baseAddress == null)
-//                                             return "";
-//                             }
-//
-//                             baseString = baseAddress.ToString ();
-//                             return baseString;
-//                     }
-//                     
-//                     set {
-//                             if (value == null || value == "") {
-//                                     baseAddress = null;
-//                             } else {
-//                                     baseAddress = new Uri (value);
-//                             }
-//                     }
-//             }
-//
-//#if NET_2_0
-//             static Exception GetMustImplement ()
-//             {
-//                     return new NotImplementedException ();
-//             }
-//             
-//             [MonoTODO]
-//             public RequestCachePolicy CachePolicy
-//             {
-//                     get {
-//                             throw GetMustImplement ();
-//                     }
-//                     set {
-//                             throw GetMustImplement ();
-//                     }
-//             }
-//
-//             [MonoTODO]
-//             public bool UseDefaultCredentials
-//             {
-//                     get {
-//                             throw GetMustImplement ();
-//                     }
-//                     set {
-//                             throw GetMustImplement ();
-//                     }
-//             }
-//#endif
-//             
-//             public ICredentials Credentials {
-//                     get { return credentials; }
-//                     set { credentials = value; }
-//             }
-//
-//             public WebHeaderCollection Headers {
-//                     get {
-//                             if (headers == null)
-//                                     headers = new WebHeaderCollection ();
-//
-//                             return headers;
-//                     }
-//                     set { headers = value; }
-//             }
-//             
-//             public NameValueCollection QueryString {
-//                     get {
-//                             if (queryString == null)
-//                                     queryString = new NameValueCollection ();
-//
-//                             return queryString;
-//                     }
-//                     set { queryString = value; }
-//             }
-//             
-//             public WebHeaderCollection ResponseHeaders {
-//                     get { return responseHeaders; }
-//             }
-//
-//#if NET_2_0
-//             public Encoding Encoding {
-//                     get { return encoding; }
-//                     set {
-//                             if (value == null)
-//                                     throw new ArgumentNullException ("value");
-//                             encoding = value;
-//                     }
-//             }
-//
-//             public IWebProxy Proxy {
-//                     get { return proxy; }
-//                     set { proxy = value; }
-//             }
-//#endif
-//
+
+namespace System.Net {
+
+       // note: this type is effectively sealed to transparent code since it's default .ctor is marked with [SecuritySafeCritical]
+       public class WebClient {
+
+               WebHeaderCollection headers;
+               WebHeaderCollection responseHeaders;
+               string baseAddress;
+               bool is_busy;
+               Encoding encoding = Encoding.UTF8;
+               bool allow_read_buffering = true;
+               bool allow_write_buffering = true;
+               WebRequest request;
+               object locker;
+               CallbackData callback_data;
+
+               public WebClient ()
+               {
+                       // kind of calling NativeMethods.plugin_instance_get_source_location (PluginHost.Handle)
+                       // 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);
+                       locker = new object ();
+                       UseDefaultCredentials = true;
+               }
+               
+               // Properties
+               
+               public string BaseAddress {
+                       get { return baseAddress; }
+                       set {
+                               if (String.IsNullOrEmpty (value)) {
+                                       baseAddress = String.Empty;
+                               } else {
+                                       Uri uri = null;
+                                       if (!Uri.TryCreate (value, UriKind.Absolute, out uri))
+                                               throw new ArgumentException ("Invalid URI");
+
+                                       baseAddress = Uri.UnescapeDataString (uri.AbsoluteUri);
+                               }
+                       }
+               }
+
+               [MonoTODO ("provide credentials to the client stack")]
+               public ICredentials Credentials { get; set; }
+
+               // this is an unvalidated collection, HttpWebRequest is responsable to validate it
+               public WebHeaderCollection Headers {
+                       get {
+                               if (headers == null)
+                                       headers = new WebHeaderCollection ();
+
+                               return headers;
+                       }
+                       set { headers = value; }
+               }
+
+               public WebHeaderCollection ResponseHeaders {
+                       get { return responseHeaders; }
+               }
+
+               public Encoding Encoding {
+                       get { return encoding; }
+                       set {
+                               if (value == null)
+                                       throw new ArgumentNullException ("value");
+                               encoding = value;
+                       }
+               }
+
                public bool IsBusy {
                        get { return is_busy; }
                }
 
+               [MonoTODO ("value is unused, current implementation always works like it's true (default)")]
+               public bool AllowReadStreamBuffering {
+                       get { return allow_read_buffering; }
+                       set { allow_read_buffering = value; }
+               }
+
+               // new in SL4 RC
+               [MonoTODO ("value is unused, current implementation always works like it's true (default)")]
+               public bool AllowWriteStreamBuffering {
+                       get { return allow_write_buffering; }
+                       set { allow_write_buffering = value; }
+               }
+
+               public bool UseDefaultCredentials {
+                       get; set;
+               }
+
                // Methods
 
                void CheckBusy ()
@@ -213,934 +138,144 @@ namespace System.Net
 
                void SetBusy ()
                {
-                       lock (this) {
+                       lock (locker) {
                                CheckBusy ();
                                is_busy = true;
                        }
                }
 
-//             //   DownloadData
-//
-//             public byte [] DownloadData (string address)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     return DownloadData (CreateUri (address));
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             byte [] DownloadData (Uri address)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     try {
-//                             SetBusy ();
-//                             async = false;
-//                             return DownloadDataCore (address, null);
-//                     } finally {
-//                             is_busy = false;
-//                     }
-//             }
-//
-//             byte [] DownloadDataCore (Uri address, object userToken)
-//             {
-//                     WebRequest request = null;
-//                     
-//                     try {
-//                             request = SetupRequest (address, "GET");
-//                             WebResponse response = request.GetResponse ();
-//                             Stream st = ProcessResponse (response);
-//                             return ReadAll (st, (int) response.ContentLength, userToken);
-//                     } catch (ThreadInterruptedException){
-//                             if (request != null)
-//                                     request.Abort ();
-//                             throw;
-//                     } catch (Exception ex) {
-//                             throw new WebException ("An error occurred " +
-//                                     "performing a WebClient request.", ex);
-//                     }
-//             }
-//
-//             //   DownloadFile
-//
-//             public void DownloadFile (string address, string fileName)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     DownloadFile (CreateUri (address), fileName);
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             void DownloadFile (Uri address, string fileName)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (fileName == null)
-//                             throw new ArgumentNullException ("fileName");
-//#endif
-//
-//                     try {
-//                             SetBusy ();
-//                             async = false;
-//                             DownloadFileCore (address, fileName, null);
-//                     } catch (Exception ex) {
-//                             throw new WebException ("An error occurred " +
-//                                     "performing a WebClient request.", ex);
-//                     } finally {
-//                             is_busy = false;
-//                     }
-//             }
-//
-//             void DownloadFileCore (Uri address, string fileName, object userToken)
-//             {
-//                     WebRequest request = null;
-//                     
-//                     using (FileStream f = new FileStream (fileName, FileMode.Create)) {
-//                             try {
-//                                     request = SetupRequest (address);
-//                                     WebResponse response = request.GetResponse ();
-//                                     Stream st = ProcessResponse (response);
-//                                     
-//                                     int cLength = (int) response.ContentLength;
-//                                     int length = (cLength <= -1 || cLength > 32*1024) ? 32*1024 : cLength;
-//                                     byte [] buffer = new byte [length];
-//                                     
-//                                     int nread = 0;
-//#if NET_2_0
-//                                     long notify_total = 0;
-//#endif                                       
-//                                     while ((nread = st.Read (buffer, 0, length)) != 0){
-//#if NET_2_0
-//                                             if (async){
-//                                                     notify_total += nread;
-//                                                     OnDownloadProgressChanged (
-//                                                             new DownloadProgressChangedEventArgs (notify_total, response.ContentLength, userToken));
-//                                                                                                   
-//                                             }
-//#endif
-//                                             f.Write (buffer, 0, nread);
-//                                     }
-//                             } catch (ThreadInterruptedException){
-//                                     if (request != null)
-//                                             request.Abort ();
-//                                     throw;
-//                             }
-//                     }
-//             }
-//
-//             //   OpenRead
-//
-//             public Stream OpenRead (string address)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     return OpenRead (CreateUri (address));
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             Stream OpenRead (Uri address)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     WebRequest request = null;
-//                     try {
-//                             SetBusy ();
-//                             async = false;
-//                             request = SetupRequest (address);
-//                             WebResponse response = request.GetResponse ();
-//                             return ProcessResponse (response);
-//                     } catch (Exception ex) {
-//                             throw new WebException ("An error occurred " +
-//                                     "performing a WebClient request.", ex);
-//                     } finally {
-//                             is_busy = false;
-//                     }
-//             }
-//
-//             //   OpenWrite
-//
-//             public Stream OpenWrite (string address)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     return OpenWrite (CreateUri (address));
-//             }
-//             
-//             public Stream OpenWrite (string address, string method)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     return OpenWrite (CreateUri (address), method);
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             Stream OpenWrite (Uri address)
-//             {
-//                     return OpenWrite (address, (string) null);
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             Stream OpenWrite (Uri address, string method)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     try {
-//                             SetBusy ();
-//                             async = false;
-//                             WebRequest request = SetupRequest (address, method);
-//                             return request.GetRequestStream ();
-//                     } catch (Exception ex) {
-//                             throw new WebException ("An error occurred " +
-//                                     "performing a WebClient request.", ex);
-//                     } finally {
-//                             is_busy = false;
-//                     }
-//             }
-//
-//             private string DetermineMethod (Uri address, string method)
-//             {
-//                     if (method != null)
-//                             return method;
-//
-//#if NET_2_0
-//                     if (address.Scheme == Uri.UriSchemeFtp)
-//                             return "RETR";
-//#endif
-//                     return "POST";
-//             }
-//
-//             //   UploadData
-//
-//             public byte [] UploadData (string address, byte [] data)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     return UploadData (CreateUri (address), data);
-//             }
-//             
-//             public byte [] UploadData (string address, string method, byte [] data)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     return UploadData (CreateUri (address), method, data);
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             byte [] UploadData (Uri address, byte [] data)
-//             {
-//                     return UploadData (address, (string) null, data);
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             byte [] UploadData (Uri address, string method, byte [] data)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (data == null)
-//                             throw new ArgumentNullException ("data");
-//#endif
-//
-//                     try {
-//                             SetBusy ();
-//                             async = false;
-//                             return UploadDataCore (address, method, data, null);
-//                     } catch (Exception ex) {
-//                             throw new WebException ("An error occurred " +
-//                                     "performing a WebClient request.", ex);
-//                     } finally {
-//                             is_busy = false;
-//                     }
-//             }
-//
-//             byte [] UploadDataCore (Uri address, string method, byte [] data, object userToken)
-//             {
-//#if ONLY_1_1
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (data == null)
-//                             throw new ArgumentNullException ("data");
-//#endif
-//
-//                     WebRequest request = SetupRequest (address, method);
-//                     try {
-//                             int contentLength = data.Length;
-//                             request.ContentLength = contentLength;
-//                             using (Stream stream = request.GetRequestStream ()) {
-//                                     stream.Write (data, 0, contentLength);
-//                             }
-//                             
-//                             WebResponse response = request.GetResponse ();
-//                             Stream st = ProcessResponse (response);
-//                             return ReadAll (st, (int) response.ContentLength, userToken);
-//                     } catch (ThreadInterruptedException){
-//                             if (request != null)
-//                                     request.Abort ();
-//                             throw;
-//                     }
-//             }
-//
-//             //   UploadFile
-//
-//             public byte [] UploadFile (string address, string fileName)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     return UploadFile (CreateUri (address), fileName);
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             byte [] UploadFile (Uri address, string fileName)
-//             {
-//                     return UploadFile (address, (string) null, fileName);
-//             }
-//             
-//             public byte [] UploadFile (string address, string method, string fileName)
-//             {
-//                     return UploadFile (CreateUri (address), method, fileName);
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             byte [] UploadFile (Uri address, string method, string fileName)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (fileName == null)
-//                             throw new ArgumentNullException ("fileName");
-//#endif
-//
-//                     try {
-//                             SetBusy ();
-//                             async = false;
-//                             return UploadFileCore (address, method, fileName, null);
-//                     } catch (Exception ex) {
-//                             throw new WebException ("An error occurred " +
-//                                     "performing a WebClient request.", ex);
-//                     } finally {
-//                             is_busy = false;
-//                     }
-//             }
-//
-//             byte [] UploadFileCore (Uri address, string method, string fileName, object userToken)
-//             {
-//#if ONLY_1_1
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     string fileCType = Headers ["Content-Type"];
-//                     if (fileCType != null) {
-//                             string lower = fileCType.ToLower ();
-//                             if (lower.StartsWith ("multipart/"))
-//                                     throw new WebException ("Content-Type cannot be set to a multipart" +
-//                                                             " type for this request.");
-//                     } else {
-//                             fileCType = "application/octet-stream";
-//                     }
-//
-//                     string boundary = "------------" + DateTime.Now.Ticks.ToString ("x");
-//                     Headers ["Content-Type"] = String.Format ("multipart/form-data; boundary={0}", boundary);
-//                     Stream reqStream = null;
-//                     Stream fStream = null;
-//                     byte [] resultBytes = null;
-//
-//                     fileName = Path.GetFullPath (fileName);
-//
-//                     WebRequest request = null;
-//                     try {
-//                             fStream = File.OpenRead (fileName);
-//                             request = SetupRequest (address, method);
-//                             reqStream = request.GetRequestStream ();
-//                             byte [] realBoundary = Encoding.ASCII.GetBytes ("--" + boundary + "\r\n");
-//                             reqStream.Write (realBoundary, 0, realBoundary.Length);
-//                             string partHeaders = String.Format ("Content-Disposition: form-data; " +
-//                                                                 "name=\"file\"; filename=\"{0}\"\r\n" +
-//                                                                 "Content-Type: {1}\r\n\r\n",
-//                                                                 Path.GetFileName (fileName), fileCType);
-//
-//                             byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders);
-//                             reqStream.Write (partHeadersBytes, 0, partHeadersBytes.Length);
-//                             int nread;
-//                             byte [] buffer = new byte [4096];
-//                             while ((nread = fStream.Read (buffer, 0, 4096)) != 0)
-//                                     reqStream.Write (buffer, 0, nread);
-//
-//                             reqStream.WriteByte ((byte) '\r');
-//                             reqStream.WriteByte ((byte) '\n');
-//                             reqStream.Write (realBoundary, 0, realBoundary.Length);
-//                             reqStream.Close ();
-//                             reqStream = null;
-//                             WebResponse response = request.GetResponse ();
-//                             Stream st = ProcessResponse (response);
-//                             resultBytes = ReadAll (st, (int) response.ContentLength, userToken);
-//                     } catch (ThreadInterruptedException){
-//                             if (request != null)
-//                                     request.Abort ();
-//                             throw;
-//                     } finally {
-//                             if (fStream != null)
-//                                     fStream.Close ();
-//
-//                             if (reqStream != null)
-//                                     reqStream.Close ();
-//                     }
-//                     
-//                     return resultBytes;
-//             }
-//             
-//             public byte[] UploadValues (string address, NameValueCollection data)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     return UploadValues (CreateUri (address), data);
-//             }
-//             
-//             public byte[] UploadValues (string address, string method, NameValueCollection data)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//#endif
-//
-//                     return UploadValues (CreateUri (address), method, data);
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             byte[] UploadValues (Uri address, NameValueCollection data)
-//             {
-//                     return UploadValues (address, (string) null, data);
-//             }
-//
-//#if NET_2_0
-//             public
-//#endif
-//             byte[] UploadValues (Uri address, string method, NameValueCollection data)
-//             {
-//#if NET_2_0
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (data == null)
-//                             throw new ArgumentNullException ("data");
-//#endif
-//
-//                     try {
-//                             SetBusy ();
-//                             async = false;
-//                             return UploadValuesCore (address, method, data, null);
-//                     } catch (Exception ex) {
-//                             throw new WebException ("An error occurred " +
-//                                     "performing a WebClient request.", ex);
-//                     } finally {
-//                             is_busy = false;
-//                     }
-//             }
-//
-//             byte[] UploadValuesCore (Uri uri, string method, NameValueCollection data, object userToken)
-//             {
-//#if ONLY_1_1
-//                     if (data == null)
-//                             throw new ArgumentNullException ("data");
-//#endif
-//
-//                     string cType = Headers ["Content-Type"];
-//                     if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0)
-//                             throw new WebException ("Content-Type header cannot be changed from its default " +
-//                                                     "value for this request.");
-//
-//                     Headers ["Content-Type"] = urlEncodedCType;
-//                     WebRequest request = SetupRequest (uri, method);
-//                     try {
-//                             Stream rqStream = request.GetRequestStream ();
-//                             MemoryStream tmpStream = new MemoryStream ();
-//                             foreach (string key in data) {
-//                                     byte [] bytes = Encoding.ASCII.GetBytes (key);
-//                                     UrlEncodeAndWrite (tmpStream, bytes);
-//                                     tmpStream.WriteByte ((byte) '=');
-//                                     bytes = Encoding.ASCII.GetBytes (data [key]);
-//                                     UrlEncodeAndWrite (tmpStream, bytes);
-//                                     tmpStream.WriteByte ((byte) '&');
-//                             }
-//                             
-//                             int length = (int) tmpStream.Length;
-//                             if (length > 0)
-//                                     tmpStream.SetLength (--length); // remove trailing '&'
-//                             
-//                             byte [] buf = tmpStream.GetBuffer ();
-//                             rqStream.Write (buf, 0, length);
-//                             rqStream.Close ();
-//                             tmpStream.Close ();
-//                             
-//                             WebResponse response = request.GetResponse ();
-//                             Stream st = ProcessResponse (response);
-//                             return ReadAll (st, (int) response.ContentLength, userToken);
-//                     } catch (ThreadInterruptedException) {
-//                             request.Abort ();
-//                             throw;
-//                     }
-//             }
-//
-//#if NET_2_0
-//             public string DownloadString (string address)
-//             {
-//                     return encoding.GetString (DownloadData (address));
-//             }
-//
-//             public string DownloadString (Uri address)
-//             {
-//                     return encoding.GetString (DownloadData (address));
-//             }
-//
-//             public string UploadString (string address, string data)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (data == null)
-//                             throw new ArgumentNullException ("data");
-//
-//                     byte [] resp = UploadData (address, encoding.GetBytes (data));
-//                     return encoding.GetString (resp);
-//             }
-//
-//             public string UploadString (string address, string method, string data)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (data == null)
-//                             throw new ArgumentNullException ("data");
-//
-//                     byte [] resp = UploadData (address, method, encoding.GetBytes (data));
-//                     return encoding.GetString (resp);
-//             }
-//
-//             public string UploadString (Uri address, string data)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (data == null)
-//                             throw new ArgumentNullException ("data");
-//
-//                     byte [] resp = UploadData (address, encoding.GetBytes (data));
-//                     return encoding.GetString (resp);
-//             }
-//
-//             public string UploadString (Uri address, string method, string data)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (data == null)
-//                             throw new ArgumentNullException ("data");
-//
-//                     byte [] resp = UploadData (address, method, encoding.GetBytes (data));
-//                     return encoding.GetString (resp);
-//             }
-//
-//             public event DownloadDataCompletedEventHandler DownloadDataCompleted;
-//             public event AsyncCompletedEventHandler DownloadFileCompleted;
+               private string DetermineMethod (Uri address, string method)
+               {
+                       if (method != null)
+                               return method;
+
+                       if (address.Scheme == Uri.UriSchemeFtp)
+                               return "RETR";
+                       return "POST";
+               }
+
                public event DownloadProgressChangedEventHandler DownloadProgressChanged;
-//             public event DownloadStringCompletedEventHandler DownloadStringCompleted;
+               public event DownloadStringCompletedEventHandler DownloadStringCompleted;
                public event OpenReadCompletedEventHandler OpenReadCompleted;
-//             public event OpenWriteCompletedEventHandler OpenWriteCompleted;
-//             public event UploadDataCompletedEventHandler UploadDataCompleted;
-//             public event UploadFileCompletedEventHandler UploadFileCompleted;
-//             public event UploadProgressChangedEventHandler UploadProgressChanged;
-//             public event UploadStringCompletedEventHandler UploadStringCompleted;
-//             public event UploadValuesCompletedEventHandler UploadValuesCompleted;
-//#endif
-//
-//             Uri CreateUri (string address)
-//             {
-//#if ONLY_1_1
-//                     try {
-//                             return MakeUri (address);
-//                     } catch (Exception ex) {
-//                             throw new WebException ("An error occurred " +
-//                                     "performing a WebClient request.", ex);
-//                     }
-//#else
-//                     return MakeUri (address);
-//#endif
-//             }
-//
-//             Uri MakeUri (string path)
-//             {
-//                     string query = null;
-//                     if (queryString != null && queryString.Count != 0) {
-//                             // This is not the same as UploadValues, because these 'keys' are not
-//                             // urlencoded here.
-//                             StringBuilder sb = new StringBuilder ();
-//                             sb.Append ('?');
-//                             foreach (string key in queryString)
-//                                     sb.AppendFormat ("{0}={1}&", key, UrlEncode (queryString [key]));
-//
-//                             if (sb.Length != 0) {
-//                                     sb.Length--; // remove trailing '&'
-//                                     query = sb.ToString ();
-//                             }
-//                     }
-//
-//                     if (baseAddress == null && query == null) {
-//                             try {
-//                                     return new Uri (path);
-//#if NET_2_0
-//                             } catch (ArgumentNullException) {
-//                                     path = Path.GetFullPath (path);
-//                                     return new Uri ("file://" + path);
-//#endif
-//                             } catch (UriFormatException) {
-//                                     path = Path.GetFullPath (path);
-//                                     return new Uri ("file://" + path);
-//                             }
-//                     }
-//
-//                     if (baseAddress == null)
-//                             return new Uri (path + query, (query != null));
-//
-//                     if (query == null)
-//                             return new Uri (baseAddress, path);
-//
-//                     return new Uri (baseAddress, path + query, (query != null));
-//             }
-//             
-               WebRequest SetupRequest (Uri uri)
+               public event OpenWriteCompletedEventHandler OpenWriteCompleted;
+               public event UploadProgressChangedEventHandler UploadProgressChanged;
+               public event UploadStringCompletedEventHandler UploadStringCompleted;
+               public event WriteStreamClosedEventHandler WriteStreamClosed;
+
+               WebRequest SetupRequest (Uri uri, string method, CallbackData callbackData)
                {
-                       WebRequest request = WebRequest.Create (uri);
-//                     if (Proxy != null)
-//                             request.Proxy = Proxy;
-//                     request.Credentials = credentials;
-
-                       // Special headers. These are properties of HttpWebRequest.
-                       // What do we do with other requests differnt from HttpWebRequest?
-//                     if (headers != null && headers.Count != 0 && (request is HttpWebRequest)) {
-//                             HttpWebRequest req = (HttpWebRequest) request;
-//                             string expect = headers ["Expect"];
-//                             string contentType = headers ["Content-Type"];
-//                             string accept = headers ["Accept"];
-//                             string connection = headers ["Connection"];
-//                             string userAgent = headers ["User-Agent"];
-//                             string referer = headers ["Referer"];
-//                             headers.RemoveInternal ("Expect");
-//                             headers.RemoveInternal ("Content-Type");
-//                             headers.RemoveInternal ("Accept");
-//                             headers.RemoveInternal ("Connection");
-//                             headers.RemoveInternal ("Referer");
-//                             headers.RemoveInternal ("User-Agent");
-//                             request.Headers = headers;
-//
-//                             if (expect != null && expect.Length > 0)
-//                                     req.Expect = expect;
-//
-//                             if (accept != null && accept.Length > 0)
-//                                     req.Accept = accept;
-//
-//                             if (contentType != null && contentType.Length > 0)
-//                                     req.ContentType = contentType;
-//
-//                             if (connection != null && connection.Length > 0)
-//                                     req.Connection = connection;
-//
-//                             if (userAgent != null && userAgent.Length > 0)
-//                                     req.UserAgent = userAgent;
-//
-//                             if (referer != null && referer.Length > 0)
-//                                     req.Referer = referer;
-//                     }
-//
-//                     responseHeaders = null;
+                       callback_data = callbackData;
+                       WebRequest request = GetWebRequest (uri);
+                       request.Method = DetermineMethod (uri, method);
+                       foreach (string header in Headers.AllKeys)
+                               request.Headers.SetHeader (header, Headers [header]);
                        return request;
                }
 
-//             WebRequest SetupRequest (Uri uri, string method)
-//             {
-//                     WebRequest request = SetupRequest (uri);
-//                     request.Method = DetermineMethod (uri, method);
-//                     return request;
-//             }
-
                Stream ProcessResponse (WebResponse response)
                {
-//                     responseHeaders = response.Headers;
-                       return response.GetResponseStream ();
+                       responseHeaders = response.Headers;
+                       HttpWebResponse hwr = (response as HttpWebResponse);
+                       if (hwr == null)
+                               throw new NotSupportedException ();
+
+                       HttpStatusCode status_code = HttpStatusCode.NotFound;
+                       Stream s = null;
+                       try {
+                               status_code = hwr.StatusCode;
+                               if (status_code == HttpStatusCode.OK)
+                                       s = response.GetResponseStream ();
+                       }
+                       catch (Exception e) {
+                               throw new WebException ("NotFound", e, WebExceptionStatus.UnknownError, response);
+                       }
+                       finally {
+                               if (status_code != HttpStatusCode.OK)
+                                       throw new WebException ("NotFound", null, WebExceptionStatus.UnknownError, response);
+                       }
+                       return s;
+               }
+
+               public void CancelAsync ()
+               {
+                       if (request != null)
+                               request.Abort ();
                }
 
-//             byte [] ReadAll (Stream stream, int length, object userToken)
-//             {
-//                     MemoryStream ms = null;
-//                     
-//                     bool nolength = (length == -1);
-//                     int size = ((nolength) ? 8192 : length);
-//                     if (nolength)
-//                             ms = new MemoryStream ();
-//
-////                   long total = 0;
-//                     int nread = 0;
-//                     int offset = 0;
-//                     byte [] buffer = new byte [size];
-//                     while ((nread = stream.Read (buffer, offset, size)) != 0) {
-//                             if (nolength) {
-//                                     ms.Write (buffer, 0, nread);
-//                             } else {
-//                                     offset += nread;
-//                                     size -= nread;
-//                             }
-//#if NET_2_0
-//                             if (async){
-////                                   total += nread;
-//                                     OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (nread, length, userToken));
-//                             }
-//#endif
-//                     }
-//
-//                     if (nolength)
-//                             return ms.ToArray ();
-//
-//                     return buffer;
-//             }
-//
-//             string UrlEncode (string str)
-//             {
-//                     StringBuilder result = new StringBuilder ();
-//
-//                     int len = str.Length;
-//                     for (int i = 0; i < len; i++) {
-//                             char c = str [i];
-//                             if (c == ' ')
-//                                     result.Append ('+');
-//                             else if ((c < '0' && c != '-' && c != '.') ||
-//                                      (c < 'A' && c > '9') ||
-//                                      (c > 'Z' && c < 'a' && c != '_') ||
-//                                      (c > 'z')) {
-//                                     result.Append ('%');
-//                                     int idx = ((int) c) >> 4;
-//                                     result.Append ((char) hexBytes [idx]);
-//                                     idx = ((int) c) & 0x0F;
-//                                     result.Append ((char) hexBytes [idx]);
-//                             } else {
-//                                     result.Append (c);
-//                             }
-//                     }
-//
-//                     return result.ToString ();
-//             }
-//
-//             static void UrlEncodeAndWrite (Stream stream, byte [] bytes)
-//             {
-//                     if (bytes == null)
-//                             return;
-//
-//                     int len = bytes.Length;
-//                     if (len == 0)
-//                             return;
-//
-//                     for (int i = 0; i < len; i++) {
-//                             char c = (char) bytes [i];
-//                             if (c == ' ')
-//                                     stream.WriteByte ((byte) '+');
-//                             else if ((c < '0' && c != '-' && c != '.') ||
-//                                      (c < 'A' && c > '9') ||
-//                                      (c > 'Z' && c < 'a' && c != '_') ||
-//                                      (c > 'z')) {
-//                                     stream.WriteByte ((byte) '%');
-//                                     int idx = ((int) c) >> 4;
-//                                     stream.WriteByte (hexBytes [idx]);
-//                                     idx = ((int) c) & 0x0F;
-//                                     stream.WriteByte (hexBytes [idx]);
-//                             } else {
-//                                     stream.WriteByte ((byte) c);
-//                             }
-//                     }
-//             }
-//
-//#if NET_2_0
-//             public void CancelAsync ()
-//             {
-//                     lock (this){
-//                             if (async_thread == null)
-//                                     return;
-//
-//                             //
-//                             // We first flag things as done, in case the Interrupt hangs
-//                             // or the thread decides to hang in some other way inside the
-//                             // event handlers, or if we are stuck somewhere else.  This
-//                             // ensures that the WebClient object is reusable immediately
-//                             //
-//                             Thread t = async_thread;
-//                             CompleteAsync ();
-//                             t.Interrupt ();
-//                     }
-//             }
-//
                void CompleteAsync ()
                {
-                       lock (this){
-                               is_busy = false;
-                               async_thread = null;
+                       is_busy = false;
+               }
+
+               class CallbackData {
+                       public object user_token;
+                       public SynchronizationContext sync_context;
+                       public byte [] data;
+                       public CallbackData (object user_token, byte [] data)
+                       {
+                               this.user_token = user_token;
+                               this.data = data;
+                               this.sync_context = SynchronizationContext.Current ?? new SynchronizationContext ();
+                       }
+                       public CallbackData (object user_token) : this (user_token, null)
+                       {
+                       }
+               }
+
+               //    DownloadStringAsync
+
+               public void DownloadStringAsync (Uri address)
+               {
+                       DownloadStringAsync (address, null);
+               }
+
+               public void DownloadStringAsync (Uri address, object userToken)
+               {
+                       if (address == null)
+                               throw new ArgumentNullException ("address");
+
+                       lock (locker) {
+                               SetBusy ();
+
+                               try {
+                                       request = SetupRequest (address, "GET", new CallbackData (userToken));
+                                       request.BeginGetResponse (new AsyncCallback (DownloadStringAsyncCallback), null);
+                               }
+                               catch (Exception e) {
+                                       WebException wex = new WebException ("Could not start operation.", e);
+                                       OnDownloadStringCompleted (
+                                               new DownloadStringCompletedEventArgs (null, wex, false, userToken));
+                               }
+                       }
+               }
+
+               private void DownloadStringAsyncCallback (IAsyncResult result)
+               {
+                       string data = null;
+                       Exception ex = null;
+                       bool cancel = false;
+                       try {
+                               WebResponse response = request.EndGetResponse (result);
+                               Stream stream = ProcessResponse (response);
+
+                               using (StreamReader sr = new StreamReader (stream, encoding, true)) {
+                                       data = sr.ReadToEnd ();
+                               }
+                       }
+                       catch (WebException web) {
+                               cancel = (web.Status == WebExceptionStatus.RequestCanceled);
+                               ex = web;
+                       }
+                       catch (Exception e) {
+                               ex = e;
+                       }
+                       finally {
+                               callback_data.sync_context.Post (delegate (object sender) {
+                                       OnDownloadStringCompleted (new DownloadStringCompletedEventArgs (data, ex, cancel, callback_data.user_token));
+                               }, null);
                        }
                }
 
-//             //    DownloadDataAsync
-//
-//             public void DownloadDataAsync (Uri address)
-//             {
-//                     DownloadDataAsync (address, null);
-//             }
-//
-//             public void DownloadDataAsync (Uri address, object userToken)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     
-//                     lock (this) {
-//                             SetBusy ();
-//                             async = true;
-//                             
-//                             async_thread = new Thread (delegate (object state) {
-//                                     object [] args = (object []) state;
-//                                     try {
-//                                             byte [] data = DownloadDataCore ((Uri) args [0], args [1]);
-//                                             OnDownloadDataCompleted (
-//                                                     new DownloadDataCompletedEventArgs (data, null, false, args [1]));
-//                                     } catch (ThreadInterruptedException){
-//                                             OnDownloadDataCompleted (
-//                                                     new DownloadDataCompletedEventArgs (null, null, true, args [1]));
-//                                             throw;
-//                                     } catch (Exception e){
-//                                             OnDownloadDataCompleted (
-//                                                     new DownloadDataCompletedEventArgs (null, e, false, args [1]));
-//                                     }
-//                             });
-//                             object [] cb_args = new object [] {address, userToken};
-//                             async_thread.Start (cb_args);
-//                     }
-//             }
-//
-//             //    DownloadFileAsync
-//
-//             public void DownloadFileAsync (Uri address, string fileName)
-//             {
-//                     DownloadFileAsync (address, fileName, null);
-//             }
-//
-//             public void DownloadFileAsync (Uri address, string fileName, object userToken)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (fileName == null)
-//                             throw new ArgumentNullException ("fileName");
-//                     
-//                     lock (this) {
-//                             SetBusy ();
-//                             async = true;
-//
-//                             async_thread = new Thread (delegate (object state) {
-//                                     object [] args = (object []) state;
-//                                     try {
-//                                             DownloadFileCore ((Uri) args [0], (string) args [1], args [2]);
-//                                             OnDownloadFileCompleted (
-//                                                     new AsyncCompletedEventArgs (null, false, args [2]));
-//                                     } catch (ThreadInterruptedException){
-//                                             OnDownloadFileCompleted (
-//                                                     new AsyncCompletedEventArgs (null, true, args [2]));
-//                                     } catch (Exception e){
-//                                             OnDownloadFileCompleted (
-//                                                     new AsyncCompletedEventArgs (e, false, args [2]));
-//                                     }});
-//                             object [] cb_args = new object [] {address, fileName, userToken};
-//                             async_thread.Start (cb_args);
-//                     }
-//             }
-//
-//             //    DownloadStringAsync
-//
-//             public void DownloadStringAsync (Uri address)
-//             {
-//                     DownloadStringAsync (address, null);
-//             }
-//
-//             public void DownloadStringAsync (Uri address, object userToken)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     
-//                     lock (this) {
-//                             SetBusy ();
-//                             async = true;
-//
-//                             async_thread = new Thread (delegate (object state) {
-//                                     object [] args = (object []) state;
-//                                     try {
-//                                             string data = encoding.GetString (DownloadDataCore ((Uri) args [0], args [1]));
-//                                             OnDownloadStringCompleted (
-//                                                     new DownloadStringCompletedEventArgs (data, null, false, args [1]));
-//                                     } catch (ThreadInterruptedException){
-//                                             OnDownloadStringCompleted (
-//                                                     new DownloadStringCompletedEventArgs (null, null, true, args [1]));
-//                                     } catch (Exception e){
-//                                             OnDownloadStringCompleted (
-//                                                     new DownloadStringCompletedEventArgs (null, e, false, args [1]));
-//                                     }});
-//                             object [] cb_args = new object [] {address, userToken};
-//                             async_thread.Start (cb_args);
-//                     }
-//             }
-//
                //    OpenReadAsync
 
                public void OpenReadAsync (Uri address)
@@ -1153,341 +288,285 @@ namespace System.Net
                        if (address == null)
                                throw new ArgumentNullException ("address");
 
-                       lock (this) {
+                       lock (locker) {
                                SetBusy ();
-                               async = true;
-
-                               async_thread = new Thread (delegate (object state) {
-                                       object [] args = (object []) state;
-                                       WebRequest request = null;
-                                       try {
-                                               request = SetupRequest ((Uri) args [0]);
-                                               //WebResponse response = request.GetResponse ();
-                                               IAsyncResult asyncresult = request.BeginGetResponse (null, userToken);
-                                               asyncresult.AsyncWaitHandle.WaitOne ();
-                                               WebResponse response = request.EndGetResponse (asyncresult);
-                                               Stream stream = ProcessResponse (response);
-                                               OnOpenReadCompleted (
-                                                       new OpenReadCompletedEventArgs (stream, null, false, args [1]));
-                                       } catch (ThreadInterruptedException){
-                                               if (request != null)
-                                                       request.Abort ();
-
-                                               OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, null, true, args [1]));
-                                       } catch (Exception e){
-                                               OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, e, false, args [1]));
-                                       } });
-                               object [] cb_args = new object [] {address, userToken};
-                               async_thread.Start (cb_args);
+
+                               try {
+                                       request = SetupRequest (address, "GET", new CallbackData (userToken));
+                                       request.BeginGetResponse (new AsyncCallback (OpenReadAsyncCallback), null);
+                               }
+                               catch (Exception e) {
+                                       WebException wex = new WebException ("Could not start operation.", e);
+                                       OnOpenReadCompleted (
+                                               new OpenReadCompletedEventArgs (null, wex, false, userToken));
+                               }
                        }
                }
 
-//             //    OpenWriteAsync
-//
-//             public void OpenWriteAsync (Uri address)
-//             {
-//                     OpenWriteAsync (address, null);
-//             }
-//
-//             public void OpenWriteAsync (Uri address, string method)
-//             {
-//                     OpenWriteAsync (address, method, null);
-//             }
-//
-//             public void OpenWriteAsync (Uri address, string method, object userToken)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//
-//                     lock (this) {
-//                             SetBusy ();
-//                             async = true;
-//
-//                             async_thread = new Thread (delegate (object state) {
-//                                     object [] args = (object []) state;
-//                                     WebRequest request = null;
-//                                     try {
-//                                             request = SetupRequest ((Uri) args [0], (string) args [1]);
-//                                             Stream stream = request.GetRequestStream ();
-//                                             OnOpenWriteCompleted (
-//                                                     new OpenWriteCompletedEventArgs (stream, null, false, args [2]));
-//                                     } catch (ThreadInterruptedException){
-//                                             if (request != null)
-//                                                     request.Abort ();
-//                                             OnOpenWriteCompleted (
-//                                                     new OpenWriteCompletedEventArgs (null, null, true, args [2]));
-//                                     } catch (Exception e){
-//                                             OnOpenWriteCompleted (
-//                                                     new OpenWriteCompletedEventArgs (null, e, false, args [2]));
-//                                     }});
-//                             object [] cb_args = new object [] {address, method, userToken};
-//                             async_thread.Start (cb_args);
-//                     }
-//             }
-//
-//             //    UploadDataAsync
-//
-//             public void UploadDataAsync (Uri address, byte [] data)
-//             {
-//                     UploadDataAsync (address, null, data);
-//             }
-//
-//             public void UploadDataAsync (Uri address, string method, byte [] data)
-//             {
-//                     UploadDataAsync (address, method, data, null);
-//             }
-//
-//             public void UploadDataAsync (Uri address, string method, byte [] data, object userToken)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (data == null)
-//                             throw new ArgumentNullException ("data");
-//                     
-//                     lock (this) {
-//                             SetBusy ();
-//                             async = true;
-//
-//                             async_thread = new Thread (delegate (object state) {
-//                                     object [] args = (object []) state;
-//                                     byte [] data2;
-//
-//                                     try {
-//                                             data2 = UploadDataCore ((Uri) args [0], (string) args [1], (byte []) args [2], args [3]);
-//                                     
-//                                             OnUploadDataCompleted (
-//                                                     new UploadDataCompletedEventArgs (data2, null, false, args [3]));
-//                                     } catch (ThreadInterruptedException){
-//                                             OnUploadDataCompleted (
-//                                                     new UploadDataCompletedEventArgs (null, null, true, args [3]));
-//                                     } catch (Exception e){
-//                                             OnUploadDataCompleted (
-//                                                     new UploadDataCompletedEventArgs (null, e, false, args [3]));
-//                                     }});
-//                             object [] cb_args = new object [] {address, method, data,  userToken};
-//                             async_thread.Start (cb_args);
-//                     }
-//             }
-//
-//             //    UploadFileAsync
-//
-//             public void UploadFileAsync (Uri address, string fileName)
-//             {
-//                     UploadFileAsync (address, null, fileName);
-//             }
-//
-//             public void UploadFileAsync (Uri address, string method, string fileName)
-//             {
-//                     UploadFileAsync (address, method, fileName, null);
-//             }
-//
-//             public void UploadFileAsync (Uri address, string method, string fileName, object userToken)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (fileName == null)
-//                             throw new ArgumentNullException ("fileName");
-//
-//                     lock (this) {
-//                             SetBusy ();
-//                             async = true;
-//
-//                             async_thread = new Thread (delegate (object state) {
-//                                     object [] args = (object []) state;
-//                                     byte [] data;
-//
-//                                     try {
-//                                             data = UploadFileCore ((Uri) args [0], (string) args [1], (string) args [2], args [3]);
-//                                             OnUploadFileCompleted (
-//                                                     new UploadFileCompletedEventArgs (data, null, false, args [3]));
-//                                     } catch (ThreadInterruptedException){
-//                                             OnUploadFileCompleted (
-//                                                     new UploadFileCompletedEventArgs (null, null, true, args [3]));
-//                                     } catch (Exception e){
-//                                             OnUploadFileCompleted (
-//                                                     new UploadFileCompletedEventArgs (null, e, false, args [3]));
-//                                     }});
-//                             object [] cb_args = new object [] {address, method, fileName,  userToken};
-//                             async_thread.Start (cb_args);
-//                     }
-//             }
-//
-//             //    UploadStringAsync
-//
-//             public void UploadStringAsync (Uri address, string data)
-//             {
-//                     UploadStringAsync (address, null, data);
-//             }
-//
-//             public void UploadStringAsync (Uri address, string method, string data)
-//             {
-//                     UploadStringAsync (address, method, data, null);
-//             }
-//
-//             public void UploadStringAsync (Uri address, string method, string data, object userToken)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (data == null)
-//                             throw new ArgumentNullException ("data");
-//                     
-//                     lock (this) {
-//                             SetBusy ();
-//                             async = true;
-//                             
-//                             async_thread = new Thread (delegate (object state) {
-//                                     object [] args = (object []) state;
-//
-//                                     try {
-//                                             string data2 = UploadString ((Uri) args [0], (string) args [1], (string) args [2]);
-//                                             OnUploadStringCompleted (
-//                                                     new UploadStringCompletedEventArgs (data2, null, false, args [3]));
-//                                     } catch (ThreadInterruptedException){
-//                                             OnUploadStringCompleted (
-//                                                     new UploadStringCompletedEventArgs (null, null, true, args [3]));
-//                                     } catch (Exception e){
-//                                             OnUploadStringCompleted (
-//                                                     new UploadStringCompletedEventArgs (null, e, false, args [3]));
-//                                     }});
-//                             object [] cb_args = new object [] {address, method, data, userToken};
-//                             async_thread.Start (cb_args);
-//                     }
-//             }
-//
-//             //    UploadValuesAsync
-//
-//             public void UploadValuesAsync (Uri address, NameValueCollection values)
-//             {
-//                     UploadValuesAsync (address, null, values);
-//             }
-//
-//             public void UploadValuesAsync (Uri address, string method, NameValueCollection values)
-//             {
-//                     UploadValuesAsync (address, method, values, null);
-//             }
-//
-//             public void UploadValuesAsync (Uri address, string method, NameValueCollection values, object userToken)
-//             {
-//                     if (address == null)
-//                             throw new ArgumentNullException ("address");
-//                     if (values == null)
-//                             throw new ArgumentNullException ("values");
-//
-//                     lock (this) {
-//                             CheckBusy ();
-//                             async = true;
-//
-//                             async_thread = new Thread (delegate (object state) {
-//                                     object [] args = (object []) state;
-//                                     try {
-//                                             byte [] data = UploadValuesCore ((Uri) args [0], (string) args [1], (NameValueCollection) args [2], args [3]);
-//                                             OnUploadValuesCompleted (
-//                                                     new UploadValuesCompletedEventArgs (data, null, false, args [3]));
-//                                     } catch (ThreadInterruptedException){
-//                                             OnUploadValuesCompleted (
-//                                                     new UploadValuesCompletedEventArgs (null, null, true, args [3]));
-//                                     } catch (Exception e){
-//                                             OnUploadValuesCompleted (
-//                                                     new UploadValuesCompletedEventArgs (null, e, false, args [3]));
-//                                     }});
-//                             object [] cb_args = new object [] {address, method, values,  userToken};
-//                             async_thread.Start (cb_args);
-//                     }
-//             }
-//
-//             protected virtual void OnDownloadDataCompleted (DownloadDataCompletedEventArgs args)
-//             {
-//                     CompleteAsync ();
-//                     if (DownloadDataCompleted != null)
-//                             DownloadDataCompleted (this, args);
-//             }
-//
-//             protected virtual void OnDownloadFileCompleted (AsyncCompletedEventArgs args)
-//             {
-//                     CompleteAsync ();
-//                     if (DownloadFileCompleted != null)
-//                             DownloadFileCompleted (this, args);
-//             }
-//
-               protected virtual void OnDownloadProgressChanged (DownloadProgressChangedEventArgs e)
+               private void OpenReadAsyncCallback (IAsyncResult result)
                {
-                       if (DownloadProgressChanged != null)
-                               DownloadProgressChanged (this, e);
+                       Stream stream = null;
+                       Exception ex = null;
+                       bool cancel = false;
+                       try {
+                               WebResponse response = request.EndGetResponse (result);
+                               stream = ProcessResponse (response);
+                       }
+                       catch (WebException web) {
+                               cancel = (web.Status == WebExceptionStatus.RequestCanceled);
+                               ex = web;
+                       }
+                       catch (Exception e) {
+                               ex = e;
+                       }
+                       finally {
+                               callback_data.sync_context.Post (delegate (object sender) {
+                                       OnOpenReadCompleted (new OpenReadCompletedEventArgs (stream, ex, cancel, callback_data.user_token));
+                               }, null);
+                       }
                }
 
-//             protected virtual void OnDownloadStringCompleted (DownloadStringCompletedEventArgs args)
-//             {
-//                     CompleteAsync ();
-//                     if (DownloadStringCompleted != null)
-//                             DownloadStringCompleted (this, args);
-//             }
-//
+               //    OpenWriteAsync
+
+               public void OpenWriteAsync (Uri address)
+               {
+                       OpenWriteAsync (address, null);
+               }
+
+               public void OpenWriteAsync (Uri address, string method)
+               {
+                       OpenWriteAsync (address, method, null);
+               }
+
+               public void OpenWriteAsync (Uri address, string method, object userToken)
+               {
+                       if (address == null)
+                               throw new ArgumentNullException ("address");
+
+                       lock (locker) {
+                               SetBusy ();
+
+                               try {
+                                       request = SetupRequest (address, method, new CallbackData (userToken));
+                                       request.BeginGetRequestStream (new AsyncCallback (OpenWriteAsyncCallback), null);
+                               }
+                               catch (Exception e) {
+                                       WebException wex = new WebException ("Could not start operation.", e);
+                                       OnOpenWriteCompleted (
+                                               new OpenWriteCompletedEventArgs (null, wex, false, userToken));
+                               }
+                       }
+               }
+
+               private void OpenWriteAsyncCallback (IAsyncResult result)
+               {
+                       Stream stream = null;
+                       Exception ex = null;
+                       bool cancel = false;
+                       InternalWebRequestStreamWrapper internal_stream;
+
+                       try {
+                               stream = request.EndGetRequestStream (result);
+                               internal_stream = (InternalWebRequestStreamWrapper) stream;
+                               internal_stream.WebClient = this;
+                               internal_stream.WebClientData = callback_data;
+                       }
+                       catch (WebException web) {
+                               cancel = (web.Status == WebExceptionStatus.RequestCanceled);
+                               ex = web;
+                       }
+                       catch (Exception e) {
+                               ex = e;
+                       }
+                       finally {
+                               callback_data.sync_context.Post (delegate (object sender) {
+                                       OnOpenWriteCompleted (new OpenWriteCompletedEventArgs (stream, ex, cancel, callback_data.user_token));
+                               }, null);
+                       }
+               }
+
+               internal void WriteStreamClosedCallback (object WebClientData)
+               {
+                       try {
+                               request.BeginGetResponse (OpenWriteAsyncResponseCallback, WebClientData);
+                       }
+                       catch (Exception e) {
+                               callback_data.sync_context.Post (delegate (object sender) {
+                                       OnWriteStreamClosed (new WriteStreamClosedEventArgs (e));
+                               }, null);
+                       }
+               }
+
+               private void OpenWriteAsyncResponseCallback (IAsyncResult result)
+               {
+                       try {
+                               WebResponse response = request.EndGetResponse (result);
+                               ProcessResponse (response);
+                       }
+                       catch (Exception e) {
+                               callback_data.sync_context.Post (delegate (object sender) {
+                                       OnWriteStreamClosed (new WriteStreamClosedEventArgs (e));
+                               }, null);
+                       }
+               }
+
+               //    UploadStringAsync
+
+               public void UploadStringAsync (Uri address, string data)
+               {
+                       UploadStringAsync (address, null, data);
+               }
+
+               public void UploadStringAsync (Uri address, string method, string data)
+               {
+                       UploadStringAsync (address, method, data, null);
+               }
+
+               public void UploadStringAsync (Uri address, string method, string data, object userToken)
+               {
+                       if (address == null)
+                               throw new ArgumentNullException ("address");
+                       if (data == null)
+                               throw new ArgumentNullException ("data");
+
+                       lock (locker) {
+                               SetBusy ();
+
+                               try {
+                                       request = SetupRequest (address, method, new CallbackData (userToken, encoding.GetBytes (data)));
+                                       request.BeginGetRequestStream (new AsyncCallback (UploadStringRequestAsyncCallback), null);
+                               }
+                               catch (Exception e) {
+                                       WebException wex = new WebException ("Could not start operation.", e);
+                                       OnUploadStringCompleted (
+                                               new UploadStringCompletedEventArgs (null, wex, false, userToken));
+                               }
+                       }
+               }
+
+               private void UploadStringRequestAsyncCallback (IAsyncResult result)
+               {
+                       try {
+                               Stream stream = request.EndGetRequestStream (result);
+                               stream.Write (callback_data.data, 0, callback_data.data.Length);
+                               request.BeginGetResponse (new AsyncCallback (UploadStringResponseAsyncCallback), null);
+                       }
+                       catch {
+                               request.Abort ();
+                               throw;
+                       }
+               }
+
+               private void UploadStringResponseAsyncCallback (IAsyncResult result)
+               {
+                       string data = null;
+                       Exception ex = null;
+                       bool cancel = false;
+                       try {
+                               WebResponse response = request.EndGetResponse (result);
+                               Stream stream = ProcessResponse (response);
+
+                               using (StreamReader sr = new StreamReader (stream, encoding, true)) {
+                                       data = sr.ReadToEnd ();
+                               }
+                       }
+                       catch (WebException web) {
+                               cancel = (web.Status == WebExceptionStatus.RequestCanceled);
+                               ex = web;
+                       }
+                       catch (InvalidOperationException ioe) {
+                               ex = new WebException ("An exception occurred during a WebClient request", ioe);
+                       }
+                       catch (Exception e) {
+                               ex = e;
+                       }
+                       finally {
+                               callback_data.sync_context.Post (delegate (object sender) {
+                                       OnUploadStringCompleted (new UploadStringCompletedEventArgs (data, ex, cancel, callback_data.user_token));
+                               }, null);
+                       }
+               }
+
+               protected virtual void OnDownloadProgressChanged (DownloadProgressChangedEventArgs e)
+               {
+                       DownloadProgressChangedEventHandler handler = DownloadProgressChanged;
+                       if (handler != null)
+                               handler (this, e);
+               }
+               
                protected virtual void OnOpenReadCompleted (OpenReadCompletedEventArgs args)
                {
                        CompleteAsync ();
-                       if (OpenReadCompleted != null)
-                               OpenReadCompleted (this, args);
+                       OpenReadCompletedEventHandler handler = OpenReadCompleted;
+                       if (handler != null)
+                               handler (this, args);
                }
 
-//             protected virtual void OnOpenWriteCompleted (OpenWriteCompletedEventArgs args)
-//             {
-//                     CompleteAsync ();
-//                     if (OpenWriteCompleted != null)
-//                             OpenWriteCompleted (this, args);
-//             }
-//
-//             protected virtual void OnUploadDataCompleted (UploadDataCompletedEventArgs args)
-//             {
-//                     CompleteAsync ();
-//                     if (UploadDataCompleted != null)
-//                             UploadDataCompleted (this, args);
-//             }
-//
-//             protected virtual void OnUploadFileCompleted (UploadFileCompletedEventArgs args)
-//             {
-//                     CompleteAsync ();
-//                     if (UploadFileCompleted != null)
-//                             UploadFileCompleted (this, args);
-//             }
-//
-//             protected virtual void OnUploadProgressChanged (UploadProgressChangedEventArgs e)
-//             {
-//                     if (UploadProgressChanged != null)
-//                             UploadProgressChanged (this, e);
-//             }
-//
-//             protected virtual void OnUploadStringCompleted (UploadStringCompletedEventArgs args)
-//             {
-//                     CompleteAsync ();
-//                     if (UploadStringCompleted != null)
-//                             UploadStringCompleted (this, args);
-//             }
-//
-//             protected virtual void OnUploadValuesCompleted (UploadValuesCompletedEventArgs args)
-//             {
-//                     CompleteAsync ();
-//                     if (UploadValuesCompleted != null)
-//                             UploadValuesCompleted (this, args);
-//             }
-//
-//             [MonoNotSupported("")]
-//             protected virtual WebRequest GetWebRequest (Uri address)
-//             {
-//                     throw new NotImplementedException ();
-//             }
-//
-//             protected virtual WebResponse GetWebResponse (WebRequest request)
-//             {
-//                     return request.GetResponse ();
-//             }
-//
-//             protected virtual WebResponse GetWebResponse (WebRequest request, IAsyncResult result)
-//             {
-//                     return request.EndGetResponse (result);
-//             }
-//#endif
-#endif
+               protected virtual void OnDownloadStringCompleted (DownloadStringCompletedEventArgs args)
+               {
+                       CompleteAsync ();
+                       DownloadStringCompletedEventHandler handler = DownloadStringCompleted;
+                       if (handler != null)
+                               handler (this, args);
+               }
+
+               protected virtual void OnOpenWriteCompleted (OpenWriteCompletedEventArgs args)
+               {
+                       CompleteAsync ();
+                       OpenWriteCompletedEventHandler handler = OpenWriteCompleted;
+                       if (handler != null)
+                               handler (this, args);
+               }
+
+               protected virtual void OnUploadProgressChanged (UploadProgressChangedEventArgs e)
+               {
+                       UploadProgressChangedEventHandler handler = UploadProgressChanged;
+                       if (handler != null)
+                               handler (this, e);
+               }
+
+               protected virtual void OnUploadStringCompleted (UploadStringCompletedEventArgs args)
+               {
+                       CompleteAsync ();
+                       UploadStringCompletedEventHandler handler = UploadStringCompleted;
+                       if (handler != null)
+                               handler (this, args);
+               }
+
+               protected virtual void OnWriteStreamClosed (WriteStreamClosedEventArgs e)
+               {
+                       CompleteAsync ();
+                       WriteStreamClosedEventHandler handler = WriteStreamClosed;
+                       if (handler != null)
+                               handler (this, e);
+               }
+
+               protected virtual WebRequest GetWebRequest (Uri address)
+               {
+                       if (address == null)
+                               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);
+
+                       HttpWebRequest request = (HttpWebRequest) WebRequest.Create (uri);
+                       request.AllowReadStreamBuffering = AllowReadStreamBuffering;
+                       request.AllowWriteStreamBuffering = AllowWriteStreamBuffering;
+                       request.UseDefaultCredentials = UseDefaultCredentials;
+
+                       request.progress = delegate (long read, long length) {
+                               callback_data.sync_context.Post (delegate (object sender) {
+                                       OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (read, length, callback_data.user_token));
+                               }, null);
+
+                       };
+                       return request;
+               }
+
+               protected virtual WebResponse GetWebResponse (WebRequest request, IAsyncResult result)
+               {
+                       return request.EndGetResponse (result);
+               }
        }
 }
 
-