Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / System / System.Net / WebClient.cs
1 //
2 // System.Net.WebClient
3 //
4 // Authors:
5 //      Lawrence Pit (loz@cable.a2000.nl)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //      Atsushi Enomoto (atsushi@ximian.com)
8 //      Miguel de Icaza (miguel@ximian.com)
9 //      Martin Baulig (martin.baulig@googlemail.com)
10 //
11 // Copyright 2003 Ximian, Inc. (http://www.ximian.com)
12 // Copyright 2006, 2010 Novell, Inc. (http://www.novell.com)
13 // Copyright 2012 Xamarin Inc. (http://www.xamarin.com)
14 //
15 //
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
23 // 
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
26 // 
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 //
35 //
36 // Notes on CancelAsync and Async methods:
37 //
38 //    WebClient.CancelAsync is implemented by calling Thread.Interrupt
39 //    in our helper thread.   The various async methods have to cancel
40 //    any ongoing requests by calling request.Abort () at that point.
41 //    In a few places (UploadDataCore, UploadValuesCore,
42 //    UploadFileCore) we catch the ThreadInterruptedException and
43 //    abort the request there.
44 //
45 //    Higher level routines (the async callbacks) also need to catch
46 //    the exception and raise the OnXXXXCompleted events there with
47 //    the "canceled" flag set to true. 
48 //
49 //    In a few other places where these helper routines are not used
50 //    (OpenReadAsync for example) catching the ThreadAbortException
51 //    also must abort the request.
52 //
53 //    The Async methods currently differ in their implementation from
54 //    the .NET implementation in that we manually catch any other
55 //    exceptions and correctly raise the OnXXXXCompleted passing the
56 //    Exception that caused the problem.   The .NET implementation
57 //    does not seem to have a mechanism to flag errors that happen
58 //    during downloads though.    We do this because we still need to
59 //    catch the exception on these helper threads, or we would
60 //    otherwise kill the application (on the 2.x profile, uncaught
61 //    exceptions in threads terminate the application).
62 //
63 using System;
64 using System.Collections.Specialized;
65 using System.ComponentModel;
66 using System.IO;
67 using System.Runtime.InteropServices;
68 using System.Runtime.Serialization;
69 using System.Text;
70 using System.Threading;
71 using System.Net.Cache;
72 #if NET_4_5
73 using System.Threading.Tasks;
74 #endif
75
76 namespace System.Net 
77 {
78         [ComVisible(true)]
79         public class WebClient : Component
80         {
81                 static readonly string urlEncodedCType = "application/x-www-form-urlencoded";
82                 static byte [] hexBytes;
83                 ICredentials credentials;
84                 WebHeaderCollection headers;
85                 WebHeaderCollection responseHeaders;
86                 Uri baseAddress;
87                 string baseString;
88                 NameValueCollection queryString;
89                 bool is_busy;
90                 bool async;
91                 bool proxySet = false;
92                 Thread async_thread;
93                 Encoding encoding = Encoding.Default;
94                 IWebProxy proxy;
95 //              RequestCachePolicy cache_policy;
96 #if NET_4_5
97                 CancellationTokenSource cts;
98 #endif
99
100                 // Constructors
101                 static WebClient ()
102                 {
103                         hexBytes = new byte [16];
104                         int index = 0;
105                         for (int i = '0'; i <= '9'; i++, index++)
106                                 hexBytes [index] = (byte) i;
107
108                         for (int i = 'a'; i <= 'f'; i++, index++)
109                                 hexBytes [index] = (byte) i;
110                 }
111                 
112                 public WebClient ()
113                 {
114                 }
115                 
116                 // Properties
117                 
118                 public string BaseAddress {
119                         get {
120                                 if (baseString == null) {
121                                         if (baseAddress == null)
122                                                 return string.Empty;
123                                 }
124
125                                 baseString = baseAddress.ToString ();
126                                 return baseString;
127                         }
128                         
129                         set {
130                                 if (value == null || value.Length == 0) {
131                                         baseAddress = null;
132                                 } else {
133                                         baseAddress = new Uri (value);
134                                 }
135                         }
136                 }
137
138                 static Exception GetMustImplement ()
139                 {
140                         return new NotImplementedException ();
141                 }
142                 
143                 [MonoTODO ("Value can be set but is currently ignored")]
144                 public RequestCachePolicy CachePolicy
145                 {
146                         get {
147                                 throw GetMustImplement ();
148                         }
149                         set { /*cache_policy = value;*/ }
150                 }
151
152                 [MonoTODO ("Value can be set but is ignored")]
153                 public bool UseDefaultCredentials
154                 {
155                         get {
156                                 throw GetMustImplement ();
157                         }
158                         set {
159                                 // This makes no sense in mono
160                         }
161                 }
162                 
163                 public ICredentials Credentials {
164                         get { return credentials; }
165                         set { credentials = value; }
166                 }
167
168                 public WebHeaderCollection Headers {
169                         get {
170                                 if (headers == null)
171                                         headers = new WebHeaderCollection ();
172
173                                 return headers;
174                         }
175                         set { headers = value; }
176                 }
177                 
178                 public NameValueCollection QueryString {
179                         get {
180                                 if (queryString == null)
181                                         queryString = new NameValueCollection ();
182
183                                 return queryString;
184                         }
185                         set { queryString = value; }
186                 }
187                 
188                 public WebHeaderCollection ResponseHeaders {
189                         get { return responseHeaders; }
190                 }
191
192                 public Encoding Encoding {
193                         get { return encoding; }
194                         set {
195                                 if (value == null)
196                                         throw new ArgumentNullException ("Encoding");
197                                 encoding = value;
198                         }
199                 }
200
201                 public IWebProxy Proxy {
202                         get {
203                                 if (!proxySet)
204                                         return WebRequest.DefaultWebProxy;
205
206                                 return proxy;
207                         }
208                         set {
209                                 proxy = value;
210                                 proxySet = true;
211                         }
212                 }
213
214                 public bool IsBusy {
215                         get {
216 #if NET_4_5
217                                 return is_busy || (cts != null);
218 #else
219                                 return is_busy;
220 #endif
221                         }
222                 }
223                 // Methods
224
225                 void CheckBusy ()
226                 {
227                         if (IsBusy)
228                                 throw new NotSupportedException ("WebClient does not support concurrent I/O operations.");
229                 }
230
231                 void SetBusy ()
232                 {
233                         lock (this) {
234                                 CheckBusy ();
235                                 is_busy = true;
236                         }
237                 }
238
239                 //   DownloadData
240
241                 public byte [] DownloadData (string address)
242                 {
243                         if (address == null)
244                                 throw new ArgumentNullException ("address");
245
246                         return DownloadData (CreateUri (address));
247                 }
248
249                 public byte [] DownloadData (Uri address)
250                 {
251                         if (address == null)
252                                 throw new ArgumentNullException ("address");
253
254                         try {
255                                 SetBusy ();
256                                 async = false;
257                                 return DownloadDataCore (address, null);
258                         } finally {
259                                 is_busy = false;
260                         }
261                 }
262
263                 byte [] DownloadDataCore (Uri address, object userToken)
264                 {
265                         WebRequest request = null;
266                         
267                         try {
268                                 request = SetupRequest (address);
269                                 return ReadAll (request, userToken);
270                         } catch (ThreadInterruptedException){
271                                 if (request != null)
272                                         request.Abort ();
273                                 throw new WebException ("User canceled the request", WebExceptionStatus.RequestCanceled);
274                         } catch (WebException) {
275                                 throw;
276                         } catch (Exception ex) {
277                                 throw new WebException ("An error occurred performing a WebClient request.", ex);
278                         }
279                 }
280
281                 //   DownloadFile
282
283                 public void DownloadFile (string address, string fileName)
284                 {
285                         if (address == null)
286                                 throw new ArgumentNullException ("address");
287
288                         DownloadFile (CreateUri (address), fileName);
289                 }
290
291                 public void DownloadFile (Uri address, string fileName)
292                 {
293                         if (address == null)
294                                 throw new ArgumentNullException ("address");
295                         if (fileName == null)
296                                 throw new ArgumentNullException ("fileName");
297
298                         try {
299                                 SetBusy ();
300                                 async = false;
301                                 DownloadFileCore (address, fileName, null);
302                         } catch (WebException) {
303                                 throw;
304                         } catch (Exception ex) {
305                                 throw new WebException ("An error occurred " +
306                                         "performing a WebClient request.", ex);
307                         } finally {
308                                 is_busy = false;
309                         }
310                 }
311
312                 void DownloadFileCore (Uri address, string fileName, object userToken)
313                 {
314                         WebRequest request = null;
315                         
316                         using (FileStream f = new FileStream (fileName, FileMode.Create)) {
317                                 try {
318                                         request = SetupRequest (address);
319                                         WebResponse response = GetWebResponse (request);
320                                         Stream st = response.GetResponseStream ();
321                                         
322                                         int cLength = (int) response.ContentLength;
323                                         int length = (cLength <= -1 || cLength > 32*1024) ? 32*1024 : cLength;
324                                         byte [] buffer = new byte [length];
325                                         
326                                         int nread = 0;
327                                         long notify_total = 0;
328                                         while ((nread = st.Read (buffer, 0, length)) != 0){
329                                                 if (async){
330                                                         notify_total += nread;
331                                                         OnDownloadProgressChanged (
332                                                                 new DownloadProgressChangedEventArgs (notify_total, response.ContentLength, userToken));
333                                                                                                       
334                                                 }
335                                                 f.Write (buffer, 0, nread);
336                                         }
337                                 } catch (ThreadInterruptedException){
338                                         if (request != null)
339                                                 request.Abort ();
340                                         throw;
341                                 }
342                         }
343                 }
344
345                 //   OpenRead
346
347                 public Stream OpenRead (string address)
348                 {
349                         if (address == null)
350                                 throw new ArgumentNullException ("address");
351                         return OpenRead (CreateUri (address));
352                 }
353
354                 public Stream OpenRead (Uri address)
355                 {
356                         if (address == null)
357                                 throw new ArgumentNullException ("address");
358
359                         WebRequest request = null;
360                         try {
361                                 SetBusy ();
362                                 async = false;
363                                 request = SetupRequest (address);
364                                 WebResponse response = GetWebResponse (request);
365                                 return response.GetResponseStream ();
366                         } catch (WebException) {
367                                 throw;
368                         } catch (Exception ex) {
369                                 throw new WebException ("An error occurred " +
370                                         "performing a WebClient request.", ex);
371                         } finally {
372                                 is_busy = false;
373                         }
374                 }
375
376                 //   OpenWrite
377
378                 public Stream OpenWrite (string address)
379                 {
380                         if (address == null)
381                                 throw new ArgumentNullException ("address");
382
383                         return OpenWrite (CreateUri (address));
384                 }
385                 
386                 public Stream OpenWrite (string address, string method)
387                 {
388                         if (address == null)
389                                 throw new ArgumentNullException ("address");
390
391                         return OpenWrite (CreateUri (address), method);
392                 }
393
394                 public Stream OpenWrite (Uri address)
395                 {
396                         return OpenWrite (address, (string) null);
397                 }
398
399                 public Stream OpenWrite (Uri address, string method)
400                 {
401                         if (address == null)
402                                 throw new ArgumentNullException ("address");
403
404                         try {
405                                 SetBusy ();
406                                 async = false;
407                                 WebRequest request = SetupRequest (address, method, true);
408                                 return request.GetRequestStream ();
409                         } catch (WebException) {
410                                 throw;
411                         } catch (Exception ex) {
412                                 throw new WebException ("An error occurred " +
413                                         "performing a WebClient request.", ex);
414                         } finally {
415                                 is_busy = false;
416                         }
417                 }
418
419                 private string DetermineMethod (Uri address, string method, bool is_upload)
420                 {
421                         if (method != null)
422                                 return method;
423
424                         if (address.Scheme == Uri.UriSchemeFtp)
425                                 return (is_upload) ? "STOR" : "RETR";
426
427                         return (is_upload) ? "POST" : "GET";
428                 }
429
430                 //   UploadData
431
432                 public byte [] UploadData (string address, byte [] data)
433                 {
434                         if (address == null)
435                                 throw new ArgumentNullException ("address");
436
437                         return UploadData (CreateUri (address), data);
438                 }
439                 
440                 public byte [] UploadData (string address, string method, byte [] data)
441                 {
442                         if (address == null)
443                                 throw new ArgumentNullException ("address");
444
445                         return UploadData (CreateUri (address), method, data);
446                 }
447
448                 public byte [] UploadData (Uri address, byte [] data)
449                 {
450                         return UploadData (address, (string) null, data);
451                 }
452
453                 public byte [] UploadData (Uri address, string method, byte [] data)
454                 {
455                         if (address == null)
456                                 throw new ArgumentNullException ("address");
457                         if (data == null)
458                                 throw new ArgumentNullException ("data");
459
460                         try {
461                                 SetBusy ();
462                                 async = false;
463                                 return UploadDataCore (address, method, data, null);
464                         } catch (WebException) {
465                                 throw;
466                         } catch (Exception ex) {
467                                 throw new WebException ("An error occurred " +
468                                         "performing a WebClient request.", ex);
469                         } finally {
470                                 is_busy = false;
471                         }
472                 }
473
474                 byte [] UploadDataCore (Uri address, string method, byte [] data, object userToken)
475                 {
476                         WebRequest request = SetupRequest (address, method, true);
477                         try {
478                                 int contentLength = data.Length;
479                                 request.ContentLength = contentLength;
480                                 using (Stream stream = request.GetRequestStream ()) {
481                                         stream.Write (data, 0, contentLength);
482                                 }
483                                 
484                                 return ReadAll (request, userToken);
485                         } catch (ThreadInterruptedException){
486                                 if (request != null)
487                                         request.Abort ();
488                                 throw;
489                         }
490                 }
491
492                 //   UploadFile
493
494                 public byte [] UploadFile (string address, string fileName)
495                 {
496                         if (address == null)
497                                 throw new ArgumentNullException ("address");
498
499                         return UploadFile (CreateUri (address), fileName);
500                 }
501
502                 public byte [] UploadFile (Uri address, string fileName)
503                 {
504                         return UploadFile (address, (string) null, fileName);
505                 }
506                 
507                 public byte [] UploadFile (string address, string method, string fileName)
508                 {
509                         return UploadFile (CreateUri (address), method, fileName);
510                 }
511
512                 public byte [] UploadFile (Uri address, string method, string fileName)
513                 {
514                         if (address == null)
515                                 throw new ArgumentNullException ("address");
516                         if (fileName == null)
517                                 throw new ArgumentNullException ("fileName");
518
519                         try {
520                                 SetBusy ();
521                                 async = false;
522                                 return UploadFileCore (address, method, fileName, null);
523                         } catch (WebException) {
524                                 throw;
525                         } catch (Exception ex) {
526                                 throw new WebException ("An error occurred " +
527                                         "performing a WebClient request.", ex);
528                         } finally {
529                                 is_busy = false;
530                         }
531                 }
532
533                 byte [] UploadFileCore (Uri address, string method, string fileName, object userToken)
534                 {
535                         string fileCType = Headers ["Content-Type"];
536                         if (fileCType != null) {
537                                 string lower = fileCType.ToLower ();
538                                 if (lower.StartsWith ("multipart/"))
539                                         throw new WebException ("Content-Type cannot be set to a multipart" +
540                                                                 " type for this request.");
541                         } else {
542                                 fileCType = "application/octet-stream";
543                         }
544
545                         bool needs_boundary = (method != "PUT"); // only verified case so far
546                         string boundary = null;
547                         if (needs_boundary) {
548                                 boundary = "------------" + DateTime.Now.Ticks.ToString ("x");
549                                 Headers ["Content-Type"] = String.Format ("multipart/form-data; boundary={0}", boundary);
550                         }
551                         Stream reqStream = null;
552                         Stream fStream = null;
553                         byte [] resultBytes = null;
554
555                         fileName = Path.GetFullPath (fileName);
556
557                         WebRequest request = null;
558                         try {
559                                 fStream = File.OpenRead (fileName);
560                                 request = SetupRequest (address, method, true);
561                                 reqStream = request.GetRequestStream ();
562                                 byte [] bytes_boundary = null;
563                                 if (needs_boundary) {
564                                         bytes_boundary = Encoding.ASCII.GetBytes (boundary);
565                                         reqStream.WriteByte ((byte) '-');
566                                         reqStream.WriteByte ((byte) '-');
567                                         reqStream.Write (bytes_boundary, 0, bytes_boundary.Length);
568                                         reqStream.WriteByte ((byte) '\r');
569                                         reqStream.WriteByte ((byte) '\n');
570                                         string partHeaders = String.Format ("Content-Disposition: form-data; " +
571                                                                             "name=\"file\"; filename=\"{0}\"\r\n" +
572                                                                             "Content-Type: {1}\r\n\r\n",
573                                                                             Path.GetFileName (fileName), fileCType);
574
575                                         byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders);
576                                         reqStream.Write (partHeadersBytes, 0, partHeadersBytes.Length);
577                                 }
578                                 int nread;
579                                 long bytes_sent = 0;
580                                 long file_size = -1;
581                                 long step = 16384; // every 16kB
582                                 if (fStream.CanSeek) {
583                                         file_size = fStream.Length;
584                                         step = file_size / 100;
585                                 }
586                                 var upload_args = new UploadProgressChangedEventArgs (0, 0, bytes_sent, file_size, 0, userToken);
587                                 OnUploadProgressChanged (upload_args);
588                                 byte [] buffer = new byte [4096];
589                                 long sum = 0;
590                                 while ((nread = fStream.Read (buffer, 0, 4096)) > 0) {
591                                         reqStream.Write (buffer, 0, nread);
592                                         bytes_sent += nread;
593                                         sum += nread;
594                                         if (sum >= step || nread < 4096) {
595                                                 int percent = 0;
596                                                 if (file_size > 0)
597                                                         percent = (int) (bytes_sent * 100 / file_size);
598                                                 upload_args = new UploadProgressChangedEventArgs (0, 0, bytes_sent, file_size, percent, userToken);
599                                                 OnUploadProgressChanged (upload_args);
600                                                 sum = 0;
601                                         }
602                                 }
603
604                                 if (needs_boundary) {
605                                         reqStream.WriteByte ((byte) '\r');
606                                         reqStream.WriteByte ((byte) '\n');
607                                         reqStream.WriteByte ((byte) '-');
608                                         reqStream.WriteByte ((byte) '-');
609                                         reqStream.Write (bytes_boundary, 0, bytes_boundary.Length);
610                                         reqStream.WriteByte ((byte) '-');
611                                         reqStream.WriteByte ((byte) '-');
612                                         reqStream.WriteByte ((byte) '\r');
613                                         reqStream.WriteByte ((byte) '\n');
614                                 }
615                                 reqStream.Close ();
616                                 reqStream = null;
617                                 resultBytes = ReadAll (request, userToken);
618                         } catch (ThreadInterruptedException){
619                                 if (request != null)
620                                         request.Abort ();
621                                 throw;
622                         } finally {
623                                 if (fStream != null)
624                                         fStream.Close ();
625
626                                 if (reqStream != null)
627                                         reqStream.Close ();
628                         }
629                         
630                         return resultBytes;
631                 }
632                 
633                 public byte[] UploadValues (string address, NameValueCollection data)
634                 {
635                         if (address == null)
636                                 throw new ArgumentNullException ("address");
637
638                         return UploadValues (CreateUri (address), data);
639                 }
640                 
641                 public byte[] UploadValues (string address, string method, NameValueCollection data)
642                 {
643                         if (address == null)
644                                 throw new ArgumentNullException ("address");
645                         return UploadValues (CreateUri (address), method, data);
646                 }
647
648                 public byte[] UploadValues (Uri address, NameValueCollection data)
649                 {
650                         return UploadValues (address, (string) null, data);
651                 }
652
653                 public byte[] UploadValues (Uri address, string method, NameValueCollection data)
654                 {
655                         if (address == null)
656                                 throw new ArgumentNullException ("address");
657                         if (data == null)
658                                 throw new ArgumentNullException ("data");
659
660                         try {
661                                 SetBusy ();
662                                 async = false;
663                                 return UploadValuesCore (address, method, data, null);
664                         } catch (WebException) {
665                                 throw;
666                         } catch (Exception ex) {
667                                 throw new WebException ("An error occurred " +
668                                         "performing a WebClient request.", ex);
669                         } finally {
670                                 is_busy = false;
671                         }
672                 }
673
674                 byte[] UploadValuesCore (Uri uri, string method, NameValueCollection data, object userToken)
675                 {
676                         string cType = Headers ["Content-Type"];
677                         if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0)
678                                 throw new WebException ("Content-Type header cannot be changed from its default " +
679                                                         "value for this request.");
680
681                         Headers ["Content-Type"] = urlEncodedCType;
682                         WebRequest request = SetupRequest (uri, method, true);
683                         try {
684                                 MemoryStream tmpStream = new MemoryStream ();
685                                 foreach (string key in data) {
686                                         byte [] bytes = Encoding.UTF8.GetBytes (key);
687                                         UrlEncodeAndWrite (tmpStream, bytes);
688                                         tmpStream.WriteByte ((byte) '=');
689                                         bytes = Encoding.UTF8.GetBytes (data [key]);
690                                         UrlEncodeAndWrite (tmpStream, bytes);
691                                         tmpStream.WriteByte ((byte) '&');
692                                 }
693                                 
694                                 int length = (int) tmpStream.Length;
695                                 if (length > 0)
696                                         tmpStream.SetLength (--length); // remove trailing '&'
697                                 
698                                 byte [] buf = tmpStream.GetBuffer ();
699                                 request.ContentLength = length;
700                                 using (Stream rqStream = request.GetRequestStream ()) {
701                                         rqStream.Write (buf, 0, length);
702                                 }
703                                 tmpStream.Close ();
704                                 
705                                 return ReadAll (request, userToken);
706                         } catch (ThreadInterruptedException) {
707                                 request.Abort ();
708                                 throw;
709                         }
710                 }
711
712                 public string DownloadString (string address)
713                 {
714                         if (address == null)
715                                 throw new ArgumentNullException ("address");
716
717                         return encoding.GetString (DownloadData (CreateUri (address)));
718                 }
719
720                 public string DownloadString (Uri address)
721                 {
722                         if (address == null)
723                                 throw new ArgumentNullException ("address");
724
725                         return encoding.GetString (DownloadData (CreateUri (address)));
726                 }
727
728                 public string UploadString (string address, string data)
729                 {
730                         if (address == null)
731                                 throw new ArgumentNullException ("address");
732                         if (data == null)
733                                 throw new ArgumentNullException ("data");
734
735                         byte [] resp = UploadData (address, encoding.GetBytes (data));
736                         return encoding.GetString (resp);
737                 }
738
739                 public string UploadString (string address, string method, string data)
740                 {
741                         if (address == null)
742                                 throw new ArgumentNullException ("address");
743                         if (data == null)
744                                 throw new ArgumentNullException ("data");
745
746                         byte [] resp = UploadData (address, method, encoding.GetBytes (data));
747                         return encoding.GetString (resp);
748                 }
749
750                 public string UploadString (Uri address, string data)
751                 {
752                         if (address == null)
753                                 throw new ArgumentNullException ("address");
754                         if (data == null)
755                                 throw new ArgumentNullException ("data");
756
757                         byte [] resp = UploadData (address, encoding.GetBytes (data));
758                         return encoding.GetString (resp);
759                 }
760
761                 public string UploadString (Uri address, string method, string data)
762                 {
763                         if (address == null)
764                                 throw new ArgumentNullException ("address");
765                         if (data == null)
766                                 throw new ArgumentNullException ("data");
767
768                         byte [] resp = UploadData (address, method, encoding.GetBytes (data));
769                         return encoding.GetString (resp);
770                 }
771
772                 public event DownloadDataCompletedEventHandler DownloadDataCompleted;
773                 public event AsyncCompletedEventHandler DownloadFileCompleted;
774                 public event DownloadProgressChangedEventHandler DownloadProgressChanged;
775                 public event DownloadStringCompletedEventHandler DownloadStringCompleted;
776                 public event OpenReadCompletedEventHandler OpenReadCompleted;
777                 public event OpenWriteCompletedEventHandler OpenWriteCompleted;
778                 public event UploadDataCompletedEventHandler UploadDataCompleted;
779                 public event UploadFileCompletedEventHandler UploadFileCompleted;
780                 public event UploadProgressChangedEventHandler UploadProgressChanged;
781                 public event UploadStringCompletedEventHandler UploadStringCompleted;
782                 public event UploadValuesCompletedEventHandler UploadValuesCompleted;
783
784                 Uri CreateUri (string address)
785                 {
786                         Uri uri;
787                         try {
788                                 if (baseAddress == null)
789                                         uri = new Uri (address);
790                                 else
791                                         uri = new Uri (baseAddress, address);
792                                 return CreateUri (uri);
793                         } catch {
794                         }
795                         return new Uri (Path.GetFullPath (address));
796                 }
797
798                 Uri CreateUri (Uri address)
799                 {
800                         Uri result = address;
801                         if (baseAddress != null && !result.IsAbsoluteUri) {
802                                 try {
803                                         result = new Uri (baseAddress, result.OriginalString);
804                                 } catch {
805                                         return result; // Not much we can do here.
806                                 }
807                         }
808
809                         string query = result.Query;
810                         if (String.IsNullOrEmpty (query))
811                                 query = GetQueryString (true);
812                         UriBuilder builder = new UriBuilder (address);
813                         if (!String.IsNullOrEmpty (query))
814                                 builder.Query = query.Substring (1);
815                         return builder.Uri;
816                 }
817
818                 string GetQueryString (bool add_qmark)
819                 {
820                         if (queryString == null || queryString.Count == 0)
821                                 return null;
822
823                         StringBuilder sb = new StringBuilder ();
824                         if (add_qmark)
825                                 sb.Append ('?');
826
827                         foreach (string key in queryString)
828                                 sb.AppendFormat ("{0}={1}&", key, UrlEncode (queryString [key]));
829
830                         if (sb.Length != 0)
831                                 sb.Length--; // removes last '&' or the '?' if empty.
832
833                         if (sb.Length == 0)
834                                 return null;
835
836                         return sb.ToString ();
837                 }
838
839                 WebRequest SetupRequest (Uri uri)
840                 {
841                         WebRequest request = GetWebRequest (uri);
842                         if (proxySet)
843                                 request.Proxy = Proxy;
844                         if (credentials != null)
845                                 request.Credentials = credentials;
846                         else if (!String.IsNullOrEmpty (uri.UserInfo)) {
847                                 // Perhaps this should be done by the underlying URI handler?
848                                 ICredentials creds = GetCredentials (uri.UserInfo);
849                                 if (creds != null)
850                                         request.Credentials = creds;
851                         }
852
853                         // Special headers. These are properties of HttpWebRequest.
854                         // What do we do with other requests differnt from HttpWebRequest?
855                         if (headers != null && headers.Count != 0 && (request is HttpWebRequest)) {
856                                 HttpWebRequest req = (HttpWebRequest) request;
857                                 string expect = headers ["Expect"];
858                                 string contentType = headers ["Content-Type"];
859                                 string accept = headers ["Accept"];
860                                 string connection = headers ["Connection"];
861                                 string userAgent = headers ["User-Agent"];
862                                 string referer = headers ["Referer"];
863                                 headers.RemoveInternal ("Expect");
864                                 headers.RemoveInternal ("Content-Type");
865                                 headers.RemoveInternal ("Accept");
866                                 headers.RemoveInternal ("Connection");
867                                 headers.RemoveInternal ("Referer");
868                                 headers.RemoveInternal ("User-Agent");
869                                 request.Headers = headers;
870
871                                 if (expect != null && expect.Length > 0)
872                                         req.Expect = expect;
873
874                                 if (accept != null && accept.Length > 0)
875                                         req.Accept = accept;
876
877                                 if (contentType != null && contentType.Length > 0)
878                                         req.ContentType = contentType;
879
880                                 if (connection != null && connection.Length > 0)
881                                         req.Connection = connection;
882
883                                 if (userAgent != null && userAgent.Length > 0)
884                                         req.UserAgent = userAgent;
885
886                                 if (referer != null && referer.Length > 0)
887                                         req.Referer = referer;
888                         }
889
890                         responseHeaders = null;
891                         return request;
892                 }
893
894                 WebRequest SetupRequest (Uri uri, string method, bool is_upload)
895                 {
896                         WebRequest request = SetupRequest (uri);
897                         request.Method = DetermineMethod (uri, method, is_upload);
898                         return request;
899                 }
900
901                 static NetworkCredential GetCredentials (string user_info)
902                 {
903                         string [] creds = user_info.Split (':');
904                         if (creds.Length != 2)
905                                 return null;
906
907                         if (creds [0].IndexOf ('\\') != -1) {
908                                 string [] user = creds [0].Split ('\\');
909                                 if (user.Length != 2)
910                                         return null;
911                                 return new NetworkCredential (user [1], creds [1], user [0]);
912                         }
913                         return new NetworkCredential (creds [0], creds [1]);
914                 }
915
916                 byte [] ReadAll (WebRequest request, object userToken)
917                 {
918                         WebResponse response = GetWebResponse (request);
919                         Stream stream = response.GetResponseStream ();
920                         int length = (int) response.ContentLength;
921                         HttpWebRequest wreq = request as HttpWebRequest;
922
923                         if (length > -1 && wreq != null && (int) wreq.AutomaticDecompression != 0) {
924                                 string content_encoding = ((HttpWebResponse) response).ContentEncoding;
925                                 if (((content_encoding == "gzip" && (wreq.AutomaticDecompression & DecompressionMethods.GZip) != 0)) ||
926                                         ((content_encoding == "deflate" && (wreq.AutomaticDecompression & DecompressionMethods.Deflate) != 0)))
927                                         length = -1;
928                         }
929
930                         MemoryStream ms = null;
931                         bool nolength = (length == -1);
932                         int size = ((nolength) ? 8192 : length);
933                         if (nolength)
934                                 ms = new MemoryStream ();
935
936                         long total = 0;
937                         int nread = 0;
938                         int offset = 0;
939                         byte [] buffer = new byte [size];
940                         while ((nread = stream.Read (buffer, offset, size)) != 0) {
941                                 if (nolength) {
942                                         ms.Write (buffer, 0, nread);
943                                 } else {
944                                         offset += nread;
945                                         size -= nread;
946                                 }
947                                 if (async){
948                                         total += nread;
949                                         OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (total, length, userToken));
950                                 }
951                         }
952
953                         if (nolength)
954                                 return ms.ToArray ();
955
956                         return buffer;
957                 }
958
959                 string UrlEncode (string str)
960                 {
961                         StringBuilder result = new StringBuilder ();
962
963                         int len = str.Length;
964                         for (int i = 0; i < len; i++) {
965                                 char c = str [i];
966                                 if (c == ' ')
967                                         result.Append ('+');
968                                 else if ((c < '0' && c != '-' && c != '.') ||
969                                          (c < 'A' && c > '9') ||
970                                          (c > 'Z' && c < 'a' && c != '_') ||
971                                          (c > 'z')) {
972                                         result.Append ('%');
973                                         int idx = ((int) c) >> 4;
974                                         result.Append ((char) hexBytes [idx]);
975                                         idx = ((int) c) & 0x0F;
976                                         result.Append ((char) hexBytes [idx]);
977                                 } else {
978                                         result.Append (c);
979                                 }
980                         }
981
982                         return result.ToString ();
983                 }
984
985                 static void UrlEncodeAndWrite (Stream stream, byte [] bytes)
986                 {
987                         if (bytes == null)
988                                 return;
989
990                         int len = bytes.Length;
991                         if (len == 0)
992                                 return;
993
994                         for (int i = 0; i < len; i++) {
995                                 char c = (char) bytes [i];
996                                 if (c == ' ')
997                                         stream.WriteByte ((byte) '+');
998                                 else if ((c < '0' && c != '-' && c != '.') ||
999                                          (c < 'A' && c > '9') ||
1000                                          (c > 'Z' && c < 'a' && c != '_') ||
1001                                          (c > 'z')) {
1002                                         stream.WriteByte ((byte) '%');
1003                                         int idx = ((int) c) >> 4;
1004                                         stream.WriteByte (hexBytes [idx]);
1005                                         idx = ((int) c) & 0x0F;
1006                                         stream.WriteByte (hexBytes [idx]);
1007                                 } else {
1008                                         stream.WriteByte ((byte) c);
1009                                 }
1010                         }
1011                 }
1012
1013                 public void CancelAsync ()
1014                 {
1015                         lock (this){
1016 #if NET_4_5
1017                                 if (cts != null) {
1018                                         cts.Cancel ();
1019                                         return;
1020                                 }
1021 #endif
1022
1023                                 if (async_thread == null)
1024                                         return;
1025
1026                                 //
1027                                 // We first flag things as done, in case the Interrupt hangs
1028                                 // or the thread decides to hang in some other way inside the
1029                                 // event handlers, or if we are stuck somewhere else.  This
1030                                 // ensures that the WebClient object is reusable immediately
1031                                 //
1032                                 Thread t = async_thread;
1033                                 CompleteAsync ();
1034                                 t.Interrupt ();
1035                         }
1036                 }
1037
1038                 void CompleteAsync ()
1039                 {
1040                         lock (this) {
1041                                 is_busy = false;
1042                                 async_thread = null;
1043 #if NET_4_5
1044                                 if (cts != null)
1045                                         cts.Dispose ();
1046                                 cts = null;
1047 #endif
1048                         }
1049                 }
1050
1051                 //    DownloadDataAsync
1052
1053                 public void DownloadDataAsync (Uri address)
1054                 {
1055                         DownloadDataAsync (address, null);
1056                 }
1057
1058                 public void DownloadDataAsync (Uri address, object userToken)
1059                 {
1060                         if (address == null)
1061                                 throw new ArgumentNullException ("address");
1062                         
1063                         lock (this) {
1064                                 SetBusy ();
1065                                 async = true;
1066                                 
1067                                 async_thread = new Thread (delegate (object state) {
1068                                         object [] args = (object []) state;
1069                                         try {
1070                                                 byte [] data = DownloadDataCore ((Uri) args [0], args [1]);
1071                                                 OnDownloadDataCompleted (
1072                                                         new DownloadDataCompletedEventArgs (data, null, false, args [1]));
1073                                         } catch (Exception e){
1074                                                 bool canceled = false;
1075                                                 WebException we = e as WebException;
1076                                                 if (we != null)
1077                                                         canceled = we.Status == WebExceptionStatus.RequestCanceled;
1078                                                 OnDownloadDataCompleted (
1079                                                         new DownloadDataCompletedEventArgs (null, e, canceled, args [1]));
1080                                         }
1081                                 });
1082                                 object [] cb_args = new object [] {address, userToken};
1083                                 async_thread.Start (cb_args);
1084                         }
1085                 }
1086
1087                 //    DownloadFileAsync
1088
1089                 public void DownloadFileAsync (Uri address, string fileName)
1090                 {
1091                         DownloadFileAsync (address, fileName, null);
1092                 }
1093
1094                 public void DownloadFileAsync (Uri address, string fileName, object userToken)
1095                 {
1096                         if (address == null)
1097                                 throw new ArgumentNullException ("address");
1098                         if (fileName == null)
1099                                 throw new ArgumentNullException ("fileName");
1100                         
1101                         lock (this) {
1102                                 SetBusy ();
1103                                 async = true;
1104
1105                                 async_thread = new Thread (delegate (object state) {
1106                                         object [] args = (object []) state;
1107                                         try {
1108                                                 DownloadFileCore ((Uri) args [0], (string) args [1], args [2]);
1109                                                 OnDownloadFileCompleted (
1110                                                         new AsyncCompletedEventArgs (null, false, args [2]));
1111                                         } catch (ThreadInterruptedException){
1112                                                 OnDownloadFileCompleted (
1113                                                         new AsyncCompletedEventArgs (null, true, args [2]));
1114                                         } catch (Exception e){
1115                                                 OnDownloadFileCompleted (
1116                                                         new AsyncCompletedEventArgs (e, false, args [2]));
1117                                         }});
1118                                 object [] cb_args = new object [] {address, fileName, userToken};
1119                                 async_thread.Start (cb_args);
1120                         }
1121                 }
1122
1123                 //    DownloadStringAsync
1124
1125                 public void DownloadStringAsync (Uri address)
1126                 {
1127                         DownloadStringAsync (address, null);
1128                 }
1129
1130                 public void DownloadStringAsync (Uri address, object userToken)
1131                 {
1132                         if (address == null)
1133                                 throw new ArgumentNullException ("address");
1134                         
1135                         lock (this) {
1136                                 SetBusy ();
1137                                 async = true;
1138
1139                                 async_thread = new Thread (delegate (object state) {
1140                                         object [] args = (object []) state;
1141                                         try {
1142                                                 string data = encoding.GetString (DownloadDataCore ((Uri) args [0], args [1]));
1143                                                 OnDownloadStringCompleted (
1144                                                         new DownloadStringCompletedEventArgs (data, null, false, args [1]));
1145                                         } catch (Exception e){
1146                                                 bool canceled = false;
1147                                                 WebException we = e as WebException;
1148                                                 if (we != null)
1149                                                         canceled = we.Status == WebExceptionStatus.RequestCanceled;
1150                                                 OnDownloadStringCompleted (
1151                                                         new DownloadStringCompletedEventArgs (null, e, canceled, args [1]));
1152                                         }});
1153                                 object [] cb_args = new object [] {address, userToken};
1154                                 async_thread.Start (cb_args);
1155                         }
1156                 }
1157
1158                 //    OpenReadAsync
1159
1160                 public void OpenReadAsync (Uri address)
1161                 {
1162                         OpenReadAsync (address, null);
1163                 }
1164
1165                 public void OpenReadAsync (Uri address, object userToken)
1166                 {
1167                         if (address == null)
1168                                 throw new ArgumentNullException ("address");
1169                         
1170                         lock (this) {
1171                                 SetBusy ();
1172                                 async = true;
1173
1174                                 async_thread = new Thread (delegate (object state) {
1175                                         object [] args = (object []) state;
1176                                         WebRequest request = null;
1177                                         try {
1178                                                 request = SetupRequest ((Uri) args [0]);
1179                                                 WebResponse response = GetWebResponse (request);
1180                                                 Stream stream = response.GetResponseStream ();
1181                                                 OnOpenReadCompleted (
1182                                                         new OpenReadCompletedEventArgs (stream, null, false, args [1]));
1183                                         } catch (ThreadInterruptedException){
1184                                                 if (request != null)
1185                                                         request.Abort ();
1186                                                 
1187                                                 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, null, true, args [1]));
1188                                         } catch (Exception e){
1189                                                 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, e, false, args [1]));
1190                                         } });
1191                                 object [] cb_args = new object [] {address, userToken};
1192                                 async_thread.Start (cb_args);
1193                         }
1194                 }
1195
1196                 //    OpenWriteAsync
1197
1198                 public void OpenWriteAsync (Uri address)
1199                 {
1200                         OpenWriteAsync (address, null);
1201                 }
1202
1203                 public void OpenWriteAsync (Uri address, string method)
1204                 {
1205                         OpenWriteAsync (address, method, null);
1206                 }
1207
1208                 public void OpenWriteAsync (Uri address, string method, object userToken)
1209                 {
1210                         if (address == null)
1211                                 throw new ArgumentNullException ("address");
1212
1213                         lock (this) {
1214                                 SetBusy ();
1215                                 async = true;
1216
1217                                 async_thread = new Thread (delegate (object state) {
1218                                         object [] args = (object []) state;
1219                                         WebRequest request = null;
1220                                         try {
1221                                                 request = SetupRequest ((Uri) args [0], (string) args [1], true);
1222                                                 Stream stream = request.GetRequestStream ();
1223                                                 OnOpenWriteCompleted (
1224                                                         new OpenWriteCompletedEventArgs (stream, null, false, args [2]));
1225                                         } catch (ThreadInterruptedException){
1226                                                 if (request != null)
1227                                                         request.Abort ();
1228                                                 OnOpenWriteCompleted (
1229                                                         new OpenWriteCompletedEventArgs (null, null, true, args [2]));
1230                                         } catch (Exception e){
1231                                                 OnOpenWriteCompleted (
1232                                                         new OpenWriteCompletedEventArgs (null, e, false, args [2]));
1233                                         }});
1234                                 object [] cb_args = new object [] {address, method, userToken};
1235                                 async_thread.Start (cb_args);
1236                         }
1237                 }
1238
1239                 //    UploadDataAsync
1240
1241                 public void UploadDataAsync (Uri address, byte [] data)
1242                 {
1243                         UploadDataAsync (address, null, data);
1244                 }
1245
1246                 public void UploadDataAsync (Uri address, string method, byte [] data)
1247                 {
1248                         UploadDataAsync (address, method, data, null);
1249                 }
1250
1251                 public void UploadDataAsync (Uri address, string method, byte [] data, object userToken)
1252                 {
1253                         if (address == null)
1254                                 throw new ArgumentNullException ("address");
1255                         if (data == null)
1256                                 throw new ArgumentNullException ("data");
1257                         
1258                         lock (this) {
1259                                 SetBusy ();
1260                                 async = true;
1261
1262                                 async_thread = new Thread (delegate (object state) {
1263                                         object [] args = (object []) state;
1264                                         byte [] data2;
1265
1266                                         try {
1267                                                 data2 = UploadDataCore ((Uri) args [0], (string) args [1], (byte []) args [2], args [3]);
1268                                         
1269                                                 OnUploadDataCompleted (
1270                                                         new UploadDataCompletedEventArgs (data2, null, false, args [3]));
1271                                         } catch (ThreadInterruptedException){
1272                                                 OnUploadDataCompleted (
1273                                                         new UploadDataCompletedEventArgs (null, null, true, args [3]));
1274                                         } catch (Exception e){
1275                                                 OnUploadDataCompleted (
1276                                                         new UploadDataCompletedEventArgs (null, e, false, args [3]));
1277                                         }});
1278                                 object [] cb_args = new object [] {address, method, data,  userToken};
1279                                 async_thread.Start (cb_args);
1280                         }
1281                 }
1282
1283                 //    UploadFileAsync
1284
1285                 public void UploadFileAsync (Uri address, string fileName)
1286                 {
1287                         UploadFileAsync (address, null, fileName);
1288                 }
1289
1290                 public void UploadFileAsync (Uri address, string method, string fileName)
1291                 {
1292                         UploadFileAsync (address, method, fileName, null);
1293                 }
1294
1295                 public void UploadFileAsync (Uri address, string method, string fileName, object userToken)
1296                 {
1297                         if (address == null)
1298                                 throw new ArgumentNullException ("address");
1299                         if (fileName == null)
1300                                 throw new ArgumentNullException ("fileName");
1301
1302                         lock (this) {
1303                                 SetBusy ();
1304                                 async = true;
1305
1306                                 async_thread = new Thread (delegate (object state) {
1307                                         object [] args = (object []) state;
1308                                         byte [] data;
1309
1310                                         try {
1311                                                 data = UploadFileCore ((Uri) args [0], (string) args [1], (string) args [2], args [3]);
1312                                                 OnUploadFileCompleted (
1313                                                         new UploadFileCompletedEventArgs (data, null, false, args [3]));
1314                                         } catch (ThreadInterruptedException){
1315                                                 OnUploadFileCompleted (
1316                                                         new UploadFileCompletedEventArgs (null, null, true, args [3]));
1317                                         } catch (Exception e){
1318                                                 OnUploadFileCompleted (
1319                                                         new UploadFileCompletedEventArgs (null, e, false, args [3]));
1320                                         }});
1321                                 object [] cb_args = new object [] {address, method, fileName,  userToken};
1322                                 async_thread.Start (cb_args);
1323                         }
1324                 }
1325
1326                 //    UploadStringAsync
1327
1328                 public void UploadStringAsync (Uri address, string data)
1329                 {
1330                         UploadStringAsync (address, null, data);
1331                 }
1332
1333                 public void UploadStringAsync (Uri address, string method, string data)
1334                 {
1335                         UploadStringAsync (address, method, data, null);
1336                 }
1337
1338                 public void UploadStringAsync (Uri address, string method, string data, object userToken)
1339                 {
1340                         if (address == null)
1341                                 throw new ArgumentNullException ("address");
1342                         if (data == null)
1343                                 throw new ArgumentNullException ("data");
1344                         
1345                         lock (this) {
1346                                 CheckBusy ();
1347                                 async = true;
1348                                 
1349                                 async_thread = new Thread (delegate (object state) {
1350                                         object [] args = (object []) state;
1351
1352                                         try {
1353                                                 string data2 = UploadString ((Uri) args [0], (string) args [1], (string) args [2]);
1354                                                 OnUploadStringCompleted (
1355                                                         new UploadStringCompletedEventArgs (data2, null, false, args [3]));
1356                                         } catch (ThreadInterruptedException){
1357                                                 OnUploadStringCompleted (
1358                                                         new UploadStringCompletedEventArgs (null, null, true, args [3]));
1359                                         } catch (Exception e){
1360                                                 OnUploadStringCompleted (
1361                                                         new UploadStringCompletedEventArgs (null, e, false, args [3]));
1362                                         }});
1363                                 object [] cb_args = new object [] {address, method, data, userToken};
1364                                 async_thread.Start (cb_args);
1365                         }
1366                 }
1367
1368                 //    UploadValuesAsync
1369
1370                 public void UploadValuesAsync (Uri address, NameValueCollection data)
1371                 {
1372                         UploadValuesAsync (address, null, data);
1373                 }
1374
1375                 public void UploadValuesAsync (Uri address, string method, NameValueCollection data)
1376                 {
1377                         UploadValuesAsync (address, method, data, null);
1378                 }
1379
1380                 public void UploadValuesAsync (Uri address, string method, NameValueCollection data, object userToken)
1381                 {
1382                         if (address == null)
1383                                 throw new ArgumentNullException ("address");
1384                         if (data == null)
1385                                 throw new ArgumentNullException ("data");
1386
1387                         lock (this) {
1388                                 CheckBusy ();
1389                                 async = true;
1390
1391                                 async_thread = new Thread (delegate (object state) {
1392                                         object [] args = (object []) state;
1393                                         try {
1394                                                 byte [] values = UploadValuesCore ((Uri) args [0], (string) args [1], (NameValueCollection) args [2], args [3]);
1395                                                 OnUploadValuesCompleted (
1396                                                         new UploadValuesCompletedEventArgs (values, null, false, args [3]));
1397                                         } catch (ThreadInterruptedException){
1398                                                 OnUploadValuesCompleted (
1399                                                         new UploadValuesCompletedEventArgs (null, null, true, args [3]));
1400                                         } catch (Exception e){
1401                                                 OnUploadValuesCompleted (
1402                                                         new UploadValuesCompletedEventArgs (null, e, false, args [3]));
1403                                         }});
1404                                 object [] cb_args = new object [] {address, method, data,  userToken};
1405                                 async_thread.Start (cb_args);
1406                         }
1407                 }
1408
1409                 protected virtual void OnDownloadDataCompleted (DownloadDataCompletedEventArgs e)
1410                 {
1411                         CompleteAsync ();
1412                         if (DownloadDataCompleted != null)
1413                                 DownloadDataCompleted (this, e);
1414                 }
1415
1416                 protected virtual void OnDownloadFileCompleted (AsyncCompletedEventArgs e)
1417                 {
1418                         CompleteAsync ();
1419                         if (DownloadFileCompleted != null)
1420                                 DownloadFileCompleted (this, e);
1421                 }
1422
1423                 protected virtual void OnDownloadProgressChanged (DownloadProgressChangedEventArgs e)
1424                 {
1425                         if (DownloadProgressChanged != null)
1426                                 DownloadProgressChanged (this, e);
1427                 }
1428
1429                 protected virtual void OnDownloadStringCompleted (DownloadStringCompletedEventArgs e)
1430                 {
1431                         CompleteAsync ();
1432                         if (DownloadStringCompleted != null)
1433                                 DownloadStringCompleted (this, e);
1434                 }
1435
1436                 protected virtual void OnOpenReadCompleted (OpenReadCompletedEventArgs e)
1437                 {
1438                         CompleteAsync ();
1439                         if (OpenReadCompleted != null)
1440                                 OpenReadCompleted (this, e);
1441                 }
1442
1443                 protected virtual void OnOpenWriteCompleted (OpenWriteCompletedEventArgs e)
1444                 {
1445                         CompleteAsync ();
1446                         if (OpenWriteCompleted != null)
1447                                 OpenWriteCompleted (this, e);
1448                 }
1449
1450                 protected virtual void OnUploadDataCompleted (UploadDataCompletedEventArgs e)
1451                 {
1452                         CompleteAsync ();
1453                         if (UploadDataCompleted != null)
1454                                 UploadDataCompleted (this, e);
1455                 }
1456
1457                 protected virtual void OnUploadFileCompleted (UploadFileCompletedEventArgs e)
1458                 {
1459                         CompleteAsync ();
1460                         if (UploadFileCompleted != null)
1461                                 UploadFileCompleted (this, e);
1462                 }
1463
1464                 protected virtual void OnUploadProgressChanged (UploadProgressChangedEventArgs e)
1465                 {
1466                         if (UploadProgressChanged != null)
1467                                 UploadProgressChanged (this, e);
1468                 }
1469
1470                 protected virtual void OnUploadStringCompleted (UploadStringCompletedEventArgs e)
1471                 {
1472                         CompleteAsync ();
1473                         if (UploadStringCompleted != null)
1474                                 UploadStringCompleted (this, e);
1475                 }
1476
1477                 protected virtual void OnUploadValuesCompleted (UploadValuesCompletedEventArgs e)
1478                 {
1479                         CompleteAsync ();
1480                         if (UploadValuesCompleted != null)
1481                                 UploadValuesCompleted (this, e);
1482                 }
1483
1484                 protected virtual WebResponse GetWebResponse (WebRequest request, IAsyncResult result)
1485                 {
1486                         WebResponse response = request.EndGetResponse (result);
1487                         responseHeaders = response.Headers;
1488                         return response;
1489                 }
1490
1491                 protected virtual WebRequest GetWebRequest (Uri address)
1492                 {
1493                         return WebRequest.Create (address);
1494                 }
1495
1496                 protected virtual WebResponse GetWebResponse (WebRequest request)
1497                 {
1498                         WebResponse response = request.GetResponse ();
1499                         responseHeaders = response.Headers;
1500                         return response;
1501                 }
1502                 
1503 #if NET_4_5
1504
1505                 // DownloadDataTaskAsync
1506                 
1507                 public Task<byte[]> DownloadDataTaskAsync (string address)
1508                 {
1509                         return DownloadDataTaskAsync (CreateUri (address));
1510                 }
1511
1512                 public async Task<byte[]> DownloadDataTaskAsync (Uri address)
1513                 {
1514                         WebRequest request = null;
1515                         WebResponse response = null;
1516                         try {
1517                                 SetBusy ();
1518                                 cts = new CancellationTokenSource ();
1519                                 request = await SetupRequestAsync (address);
1520                                 response = await GetWebResponseTaskAsync (request, cts.Token);
1521                                 var result = await ReadAllTaskAsync (request, response, cts.Token);
1522                                 OnDownloadDataCompleted (new DownloadDataCompletedEventArgs (result, null, false, null));
1523                                 return result;
1524                         } catch (WebException ex) {
1525                                 OnDownloadDataCompleted (new DownloadDataCompletedEventArgs (null, ex, false, null));
1526                                 throw;
1527                         } catch (OperationCanceledException) {
1528                                 if (request != null)
1529                                         request.Abort ();
1530                                 OnDownloadDataCompleted (new DownloadDataCompletedEventArgs (null, null, true, null));
1531                                 throw;
1532                         } catch (Exception ex) {
1533                                 OnDownloadDataCompleted (new DownloadDataCompletedEventArgs (null, ex, true, null));
1534                                 throw new WebException ("An error occurred performing a WebClient request.", ex);
1535                         } finally {
1536                                 if (response != null)
1537                                         response.Close ();
1538                         }
1539                 }
1540
1541                 Task<WebRequest> SetupRequestAsync (Uri address)
1542                 {
1543                         return Task.Factory.StartNew (() => SetupRequest (address));
1544                 }
1545
1546                 async Task<WebRequest> SetupRequestAsync (Uri address, string method, bool is_upload)
1547                 {
1548                         WebRequest request = await SetupRequestAsync (address);
1549                         request.Method = DetermineMethod (address, method, is_upload);
1550                         return request;
1551                 }
1552                 
1553                 async Task<WebResponse> GetWebResponseTaskAsync (WebRequest request, CancellationToken token)
1554                 {
1555                         token.ThrowIfCancellationRequested ();
1556                         WebResponse response = await request.GetResponseAsync ();
1557                         token.ThrowIfCancellationRequested ();
1558                         responseHeaders = response.Headers;
1559                         return response;
1560                 }
1561                 
1562                 async Task<byte[]> ReadAllTaskAsync (WebRequest request, WebResponse response, CancellationToken token)
1563                 {
1564                         Stream stream = response.GetResponseStream ();
1565                         int length = (int)response.ContentLength;
1566                         HttpWebRequest wreq = request as HttpWebRequest;
1567
1568                         if (length > -1 && wreq != null && (int)wreq.AutomaticDecompression != 0) {
1569                                 string content_encoding = ((HttpWebResponse)response).ContentEncoding;
1570                                 if (((content_encoding == "gzip" && (wreq.AutomaticDecompression & DecompressionMethods.GZip) != 0)) ||
1571                                         ((content_encoding == "deflate" && (wreq.AutomaticDecompression & DecompressionMethods.Deflate) != 0)))
1572                                         length = -1;
1573                         }
1574
1575                         MemoryStream ms = null;
1576                         bool nolength = (length == -1);
1577                         int size = ((nolength) ? 8192 : length);
1578                         if (nolength)
1579                                 ms = new MemoryStream ();
1580
1581                         long total = 0;
1582                         int nread = 0;
1583                         int offset = 0;
1584                         byte [] buffer = new byte [size];
1585                         token.ThrowIfCancellationRequested ();
1586                         while ((nread = await stream.ReadAsync (buffer, offset, size, token)) != 0) {
1587                                 if (nolength) {
1588                                         ms.Write (buffer, 0, nread);
1589                                 } else {
1590                                         offset += nread;
1591                                         size -= nread;
1592                                 }
1593                                 total += nread;
1594                                 OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (total, length, null));
1595                                 token.ThrowIfCancellationRequested ();
1596                         }
1597                         
1598                         return nolength ? ms.ToArray () : buffer;
1599                 }
1600                 
1601                 // DownloadFileTaskAsync
1602                 
1603                 public Task DownloadFileTaskAsync (string address, string fileName)
1604                 {
1605                         if (address == null)
1606                                 throw new ArgumentNullException ("address");
1607
1608                         return DownloadFileTaskAsync (CreateUri (address), fileName);
1609                 }
1610
1611                 public async Task DownloadFileTaskAsync (Uri address, string fileName)
1612                 {
1613                         if (address == null)
1614                                 throw new ArgumentNullException ("address");
1615                         if (fileName == null)
1616                                 throw new ArgumentNullException ("fileName");
1617                         
1618                         WebRequest request = null;
1619                         WebResponse response = null;
1620
1621                         try {
1622                                 SetBusy ();
1623                                 cts = new CancellationTokenSource ();
1624                                 request = await SetupRequestAsync (address);
1625                                 response = await GetWebResponseTaskAsync (request, cts.Token);
1626                                 await DownloadFileTaskAsyncCore (request, response, fileName, cts.Token);
1627                                 OnDownloadFileCompleted (new AsyncCompletedEventArgs (null, false, null));
1628                         } catch (WebException ex) {
1629                                 OnDownloadFileCompleted (new AsyncCompletedEventArgs (ex, false, null));
1630                                 throw;
1631                         } catch (OperationCanceledException) {
1632                                 if (request != null)
1633                                         request.Abort ();
1634                                 OnDownloadFileCompleted (new AsyncCompletedEventArgs (null, true, null));
1635                                 throw;
1636                         } catch (Exception ex) {
1637                                 OnDownloadFileCompleted (new AsyncCompletedEventArgs (ex, false, null));
1638                                 throw new WebException ("An error occurred " +
1639                                         "performing a WebClient request.", ex);
1640                         } finally {
1641                                 if (response != null)
1642                                         response.Close ();
1643                         }
1644                 }
1645
1646                 async Task DownloadFileTaskAsyncCore (WebRequest request, WebResponse response,
1647                                                       string fileName, CancellationToken token)
1648                 {
1649                         using (FileStream f = new FileStream (fileName, FileMode.Create)) {
1650                                 Stream st = response.GetResponseStream ();
1651                                         
1652                                 int cLength = (int)response.ContentLength;
1653                                 int length = (cLength <= -1 || cLength > 32 * 1024) ? 32 * 1024 : cLength;
1654                                 byte [] buffer = new byte [length];
1655                                         
1656                                 int nread = 0;
1657                                 long notify_total = 0;
1658                                 token.ThrowIfCancellationRequested ();
1659                                 while ((nread = await st.ReadAsync (buffer, 0, length, token)) != 0) {
1660                                         notify_total += nread;
1661                                         OnDownloadProgressChanged (
1662                                                 new DownloadProgressChangedEventArgs (notify_total, response.ContentLength, null));
1663                                         token.ThrowIfCancellationRequested ();
1664                                         await f.WriteAsync (buffer, 0, nread, token);
1665                                         token.ThrowIfCancellationRequested ();
1666                                 }
1667                         }
1668                 }
1669                 
1670                 // OpenReadTaskAsync
1671                 
1672                 public Task<Stream> OpenReadTaskAsync (string address)
1673                 {
1674                         if (address == null)
1675                                 throw new ArgumentNullException ("address");
1676                         return OpenReadTaskAsync (CreateUri (address));
1677                 }
1678
1679                 public async Task<Stream> OpenReadTaskAsync (Uri address)
1680                 {
1681                         if (address == null)
1682                                 throw new ArgumentNullException ("address");
1683
1684                         WebRequest request = null;
1685                         try {
1686                                 SetBusy ();
1687                                 cts = new CancellationTokenSource ();
1688                                 request = await SetupRequestAsync (address);
1689                                 WebResponse response = await GetWebResponseTaskAsync (request, cts.Token);
1690                                 var result = response.GetResponseStream ();
1691                                 cts.Token.ThrowIfCancellationRequested ();
1692                                 OnOpenReadCompleted (new OpenReadCompletedEventArgs (result, null, false, null));
1693                                 return result;
1694                         } catch (WebException ex) {
1695                                 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, ex, false, null));
1696                                 throw;
1697                         } catch (OperationCanceledException) {
1698                                 if (request != null)
1699                                         request.Abort ();
1700                                 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, null, true, null));
1701                                 throw;
1702                         } catch (Exception ex) {
1703                                 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, ex, false, null));
1704                                 throw new WebException ("An error occurred " +
1705                                         "performing a WebClient request.", ex);
1706                         }
1707                 }
1708                 
1709                 // DownloadStringTaskAsync
1710                 
1711                 public Task<string> DownloadStringTaskAsync (string address)
1712                 {
1713                         if (address == null)
1714                                 throw new ArgumentNullException ("address");
1715
1716                         return DownloadStringTaskAsync (CreateUri (address));
1717                 }
1718
1719                 public async Task<string> DownloadStringTaskAsync (Uri address)
1720                 {
1721                         if (address == null)
1722                                 throw new ArgumentNullException ("address");
1723
1724                         WebRequest request = null;
1725                         WebResponse response = null;
1726
1727                         try {
1728                                 SetBusy ();
1729                                 cts = new CancellationTokenSource ();
1730                                 request = await SetupRequestAsync (address);
1731                                 response = await GetWebResponseTaskAsync (request, cts.Token);
1732                                 var data = await ReadAllTaskAsync (request, response, cts.Token);
1733                                 cts.Token.ThrowIfCancellationRequested ();
1734                                 var text = encoding.GetString (data);
1735                                 OnDownloadStringCompleted (new DownloadStringCompletedEventArgs (text, null, false, null));
1736                                 return text;
1737                         } catch (WebException ex) {
1738                                 OnDownloadStringCompleted (new DownloadStringCompletedEventArgs (null, ex, false, null));
1739                                 throw;
1740                         } catch (OperationCanceledException) {
1741                                 if (request != null)
1742                                         request.Abort ();
1743                                 OnDownloadStringCompleted (new DownloadStringCompletedEventArgs (null, null, true, null));
1744                                 throw;
1745                         } catch (Exception ex) {
1746                                 OnDownloadStringCompleted (new DownloadStringCompletedEventArgs (null, ex, true, null));
1747                                 throw new WebException ("An error occurred performing a WebClient request.", ex);
1748                         } finally {
1749                                 if (response != null)
1750                                         response.Close ();
1751                         }
1752                 }
1753
1754                 // OpenWriteTaskAsync
1755                 
1756                 public Task<Stream> OpenWriteTaskAsync (string address)
1757                 {
1758                         if (address == null)
1759                                 throw new ArgumentNullException ("address");
1760
1761                         return OpenWriteTaskAsync (CreateUri (address));
1762                 }
1763                 
1764                 public Task<Stream> OpenWriteTaskAsync (string address, string method)
1765                 {
1766                         if (address == null)
1767                                 throw new ArgumentNullException ("address");
1768
1769                         return OpenWriteTaskAsync (CreateUri (address), method);
1770                 }
1771
1772                 public Task<Stream> OpenWriteTaskAsync (Uri address)
1773                 {
1774                         return OpenWriteTaskAsync (address, (string) null);
1775                 }
1776
1777                 public async Task<Stream> OpenWriteTaskAsync (Uri address, string method)
1778                 {
1779                         if (address == null)
1780                                 throw new ArgumentNullException ("address");
1781
1782                         WebRequest request = null;
1783                         try {
1784                                 SetBusy ();
1785                                 cts = new CancellationTokenSource ();
1786                                 request = SetupRequest (address);
1787                                 return await request.GetRequestStreamAsync ();
1788                         } catch (WebException) {
1789                                 throw;
1790                         } catch (OperationCanceledException) {
1791                                 if (request != null)
1792                                         request.Abort ();
1793                                 throw;
1794                         } catch (Exception ex) {
1795                                 throw new WebException ("An error occurred " +
1796                                         "performing a WebClient request.", ex);
1797                         } finally {
1798                                 CompleteAsync ();
1799                         }
1800                 }
1801
1802                 // UploadDataTaskAsync
1803                 
1804                 public Task<byte[]> UploadDataTaskAsync (string address, byte [] data)
1805                 {
1806                         if (address == null)
1807                                 throw new ArgumentNullException ("address");
1808
1809                         return UploadDataTaskAsync (CreateUri (address), data);
1810                 }
1811                 
1812                 public Task<byte[]> UploadDataTaskAsync (string address, string method, byte [] data)
1813                 {
1814                         if (address == null)
1815                                 throw new ArgumentNullException ("address");
1816
1817                         return UploadDataTaskAsync (CreateUri (address), method, data);
1818                 }
1819
1820                 public Task<byte[]> UploadDataTaskAsync (Uri address, byte [] data)
1821                 {
1822                         return UploadDataTaskAsync (address, (string) null, data);
1823                 }
1824
1825                 public async Task<byte[]> UploadDataTaskAsync (Uri address, string method, byte [] data)
1826                 {
1827                         if (address == null)
1828                                 throw new ArgumentNullException ("address");
1829                         if (data == null)
1830                                 throw new ArgumentNullException ("data");
1831
1832                         WebRequest request = null;
1833                         try {
1834                                 SetBusy ();
1835                                 cts = new CancellationTokenSource ();
1836                                 request = await SetupRequestAsync (address, method, true);
1837                                 var result = await UploadDataTaskAsyncCore (request, data, cts.Token);
1838                                 OnUploadDataCompleted (new UploadDataCompletedEventArgs (result, null, false, null));
1839                                 return result;
1840                         } catch (WebException ex) {
1841                                 OnUploadDataCompleted (new UploadDataCompletedEventArgs (null, ex, false, null));
1842                                 throw;
1843                         } catch (OperationCanceledException) {
1844                                 if (request != null)
1845                                         request.Abort ();
1846                                 OnUploadDataCompleted (new UploadDataCompletedEventArgs (null, null, true, null));
1847                                 throw;
1848                         } catch (Exception ex) {
1849                                 OnUploadDataCompleted (new UploadDataCompletedEventArgs (null, ex, true, null));
1850                                 throw new WebException ("An error occurred performing a WebClient request.", ex);
1851                         }
1852                 }
1853
1854                 async Task<byte[]> UploadDataTaskAsyncCore (WebRequest request, byte[] data, CancellationToken token)
1855                 {
1856                         token.ThrowIfCancellationRequested ();
1857
1858                         int contentLength = data.Length;
1859                         request.ContentLength = contentLength;
1860                         using (Stream stream = await request.GetRequestStreamAsync ()) {
1861                                 token.ThrowIfCancellationRequested ();
1862                                 await stream.WriteAsync (data, 0, contentLength, token);
1863                                 token.ThrowIfCancellationRequested ();
1864                         }
1865
1866                         WebResponse response = null;
1867
1868                         try {
1869                                 response = await GetWebResponseTaskAsync (request, token);
1870                                 return await ReadAllTaskAsync (request, response, token);
1871                         } finally {
1872                                 if (response != null)
1873                                         response.Close ();
1874                         }
1875                 }
1876
1877                 // UploadFileTaskAsync
1878
1879                 public Task<byte[]> UploadFileTaskAsync (string address, string fileName)
1880                 {
1881                         if (address == null)
1882                                 throw new ArgumentNullException ("address");
1883
1884                         return UploadFileTaskAsync (CreateUri (address), fileName);
1885                 }
1886
1887                 public Task<byte[]> UploadFileTaskAsync (Uri address, string fileName)
1888                 {
1889                         return UploadFileTaskAsync (address, (string) null, fileName);
1890                 }
1891                 
1892                 public Task<byte[]> UploadFileTaskAsync (string address, string method, string fileName)
1893                 {
1894                         return UploadFileTaskAsync (CreateUri (address), method, fileName);
1895                 }
1896
1897                 public async Task<byte[]> UploadFileTaskAsync (Uri address, string method, string fileName)
1898                 {
1899                         if (address == null)
1900                                 throw new ArgumentNullException ("address");
1901                         if (fileName == null)
1902                                 throw new ArgumentNullException ("fileName");
1903
1904                         WebRequest request = null;
1905                         try {
1906                                 SetBusy ();
1907                                 cts = new CancellationTokenSource ();
1908                                 request = await SetupRequestAsync (address, method, true);
1909                                 var result = await UploadFileTaskAsyncCore (request, method, fileName, cts.Token);
1910                                 OnUploadFileCompleted (new UploadFileCompletedEventArgs (result, null, false, null));
1911                                 return result;
1912                         } catch (WebException ex) {
1913                                 OnUploadFileCompleted (new UploadFileCompletedEventArgs (null, ex, false, null));
1914                                 throw;
1915                         } catch (OperationCanceledException) {
1916                                 if (request != null)
1917                                         request.Abort ();
1918                                 OnUploadFileCompleted (new UploadFileCompletedEventArgs (null, null, true, null));
1919                                 throw;
1920                         } catch (Exception ex) {
1921                                 OnUploadFileCompleted (new UploadFileCompletedEventArgs (null, ex, true, null));
1922                                 throw new WebException ("An error occurred performing a WebClient request.", ex);
1923                         }
1924                 }
1925
1926                 async Task<byte[]> UploadFileTaskAsyncCore (WebRequest request, string method,
1927                                                             string fileName, CancellationToken token)
1928                 {
1929                         token.ThrowIfCancellationRequested ();
1930
1931                         string fileCType = Headers ["Content-Type"];
1932                         if (fileCType != null) {
1933                                 string lower = fileCType.ToLower ();
1934                                 if (lower.StartsWith ("multipart/"))
1935                                         throw new WebException ("Content-Type cannot be set to a multipart" +
1936                                                                 " type for this request.");
1937                         } else {
1938                                 fileCType = "application/octet-stream";
1939                         }
1940
1941                         bool needs_boundary = (method != "PUT"); // only verified case so far
1942                         string boundary = null;
1943                         if (needs_boundary) {
1944                                 boundary = "------------" + DateTime.Now.Ticks.ToString ("x");
1945                                 Headers ["Content-Type"] = String.Format ("multipart/form-data; boundary={0}", boundary);
1946                         }
1947                         Stream reqStream = null;
1948                         Stream fStream = null;
1949                         WebResponse response = null;
1950
1951                         fileName = Path.GetFullPath (fileName);
1952
1953                         try {
1954                                 fStream = File.OpenRead (fileName);
1955                                 token.ThrowIfCancellationRequested ();
1956                                 reqStream = await request.GetRequestStreamAsync ();
1957                                 token.ThrowIfCancellationRequested ();
1958                                 byte [] bytes_boundary = null;
1959                                 if (needs_boundary) {
1960                                         bytes_boundary = Encoding.ASCII.GetBytes (boundary);
1961                                         using (MemoryStream ms = new MemoryStream ()) {
1962                                                 ms.WriteByte ((byte) '-');
1963                                                 ms.WriteByte ((byte) '-');
1964                                                 ms.Write (bytes_boundary, 0, bytes_boundary.Length);
1965                                                 ms.WriteByte ((byte) '\r');
1966                                                 ms.WriteByte ((byte) '\n');
1967                                                 string partHeaders = String.Format (
1968                                                         "Content-Disposition: form-data; " +
1969                                                         "name=\"file\"; filename=\"{0}\"\r\n" +
1970                                                         "Content-Type: {1}\r\n\r\n",
1971                                                         Path.GetFileName (fileName), fileCType);
1972                                                 byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders);
1973                                                 ms.Write (partHeadersBytes, 0, partHeadersBytes.Length);
1974                                                 await ms.CopyToAsync (reqStream, (int)ms.Position, token);
1975                                         }
1976                                 }
1977                                 int nread;
1978                                 long bytes_sent = 0;
1979                                 long file_size = -1;
1980                                 long step = 16384; // every 16kB
1981                                 if (fStream.CanSeek) {
1982                                         file_size = fStream.Length;
1983                                         step = file_size / 100;
1984                                 }
1985                                 var upload_args = new UploadProgressChangedEventArgs (0, 0, bytes_sent, file_size, 0, null);
1986                                 OnUploadProgressChanged (upload_args);
1987                                 byte [] buffer = new byte [4096];
1988                                 long sum = 0;
1989                                 token.ThrowIfCancellationRequested ();
1990                                 while ((nread = await fStream.ReadAsync (buffer, 0, 4096, token)) > 0) {
1991                                         token.ThrowIfCancellationRequested ();
1992                                         await reqStream.WriteAsync (buffer, 0, nread, token);
1993                                         bytes_sent += nread;
1994                                         sum += nread;
1995                                         if (sum >= step || nread < 4096) {
1996                                                 int percent = 0;
1997                                                 if (file_size > 0)
1998                                                         percent = (int) (bytes_sent * 100 / file_size);
1999                                                 upload_args = new UploadProgressChangedEventArgs (0, 0, bytes_sent, file_size, percent, null);
2000                                                 OnUploadProgressChanged (upload_args);
2001                                                 sum = 0;
2002                                         }
2003                                 }
2004
2005                                 if (needs_boundary) {
2006                                         using (MemoryStream ms = new MemoryStream ()) {
2007                                                 ms.WriteByte ((byte) '\r');
2008                                                 ms.WriteByte ((byte) '\n');
2009                                                 ms.WriteByte ((byte) '-');
2010                                                 ms.WriteByte ((byte) '-');
2011                                                 ms.Write (bytes_boundary, 0, bytes_boundary.Length);
2012                                                 ms.WriteByte ((byte) '-');
2013                                                 ms.WriteByte ((byte) '-');
2014                                                 ms.WriteByte ((byte) '\r');
2015                                                 ms.WriteByte ((byte) '\n');
2016                                                 await ms.CopyToAsync (reqStream, (int)ms.Position, token);
2017                                         }
2018                                 }
2019                                 reqStream.Close ();
2020                                 reqStream = null;
2021
2022                                 response = await GetWebResponseTaskAsync (request, token);
2023                                 return await ReadAllTaskAsync (request, response, token);
2024                         } finally {
2025                                 if (fStream != null)
2026                                         fStream.Close ();
2027
2028                                 if (reqStream != null)
2029                                         reqStream.Close ();
2030
2031                                 if (response != null)
2032                                         response.Close ();
2033                         }
2034                 }
2035
2036                 // UploadStringTaskAsync
2037
2038                 public Task<string> UploadStringTaskAsync (string address, string data)
2039                 {
2040                         if (address == null)
2041                                 throw new ArgumentNullException ("address");
2042                         if (data == null)
2043                                 throw new ArgumentNullException ("data");
2044
2045                         return UploadStringTaskAsync (CreateUri (address), null, data);
2046                 }
2047
2048                 public Task<string> UploadStringTaskAsync (string address, string method, string data)
2049                 {
2050                         if (address == null)
2051                                 throw new ArgumentNullException ("address");
2052                         if (data == null)
2053                                 throw new ArgumentNullException ("data");
2054
2055                         return UploadStringTaskAsync (CreateUri (address), method, data);
2056                 }
2057
2058                 public Task<string> UploadStringTaskAsync (Uri address, string data)
2059                 {
2060                         if (address == null)
2061                                 throw new ArgumentNullException ("address");
2062                         if (data == null)
2063                                 throw new ArgumentNullException ("data");
2064
2065                         return UploadStringTaskAsync (address, null, data);
2066                 }
2067
2068                 public async Task<string> UploadStringTaskAsync (Uri address, string method, string data)
2069                 {
2070                         if (address == null)
2071                                 throw new ArgumentNullException ("address");
2072                         if (data == null)
2073                                 throw new ArgumentNullException ("data");
2074
2075                         WebRequest request = null;
2076                         try {
2077                                 SetBusy ();
2078                                 cts = new CancellationTokenSource ();
2079                                 request = await SetupRequestAsync (address, method, true);
2080                                 var result = await UploadDataTaskAsyncCore (request, encoding.GetBytes (data), cts.Token);
2081                                 var result_str = encoding.GetString (result);
2082                                 OnUploadStringCompleted (new UploadStringCompletedEventArgs (result_str, null, false, null));
2083                                 return result_str;
2084                         } catch (WebException ex) {
2085                                 OnUploadStringCompleted (new UploadStringCompletedEventArgs (null, ex, false, null));
2086                                 throw;
2087                         } catch (OperationCanceledException) {
2088                                 if (request != null)
2089                                         request.Abort ();
2090                                 OnUploadStringCompleted (new UploadStringCompletedEventArgs (null, null, true, null));
2091                                 throw;
2092                         } catch (Exception ex) {
2093                                 OnUploadStringCompleted (new UploadStringCompletedEventArgs (null, ex, true, null));
2094                                 throw new WebException ("An error occurred performing a WebClient request.", ex);
2095                         }
2096                 }
2097
2098                 // UploadValuesTaskAsync
2099
2100                 public Task<byte[]> UploadValuesTaskAsync (string address, NameValueCollection data)
2101                 {
2102                         if (address == null)
2103                                 throw new ArgumentNullException ("address");
2104
2105                         return UploadValuesTaskAsync (CreateUri (address), data);
2106                 }
2107                 
2108                 public Task<byte[]> UploadValuesTaskAsync (string address, string method, NameValueCollection data)
2109                 {
2110                         if (address == null)
2111                                 throw new ArgumentNullException ("address");
2112
2113                         return UploadValuesTaskAsync (CreateUri (address), method, data);
2114                 }
2115
2116                 public Task<byte[]> UploadValuesTaskAsync (Uri address, NameValueCollection data)
2117                 {
2118                         return UploadValuesTaskAsync (address, (string) null, data);
2119                 }
2120
2121                 public async Task<byte[]> UploadValuesTaskAsync (Uri address, string method, NameValueCollection data)
2122                 {
2123                         if (address == null)
2124                                 throw new ArgumentNullException ("address");
2125                         if (data == null)
2126                                 throw new ArgumentNullException ("data");
2127
2128                         WebRequest request = null;
2129                         try {
2130                                 SetBusy ();
2131                                 cts = new CancellationTokenSource ();
2132                                 request = await SetupRequestAsync (address, method, true);
2133                                 var result = await UploadValuesTaskAsyncCore (request, data, cts.Token);
2134                                 OnUploadValuesCompleted (new UploadValuesCompletedEventArgs (result, null, false, null));
2135                                 return result;
2136                         } catch (WebException ex) {
2137                                 OnUploadValuesCompleted (new UploadValuesCompletedEventArgs (null, ex, false, null));
2138                                 throw;
2139                         } catch (OperationCanceledException) {
2140                                 if (request != null)
2141                                         request.Abort ();
2142                                 OnUploadValuesCompleted (new UploadValuesCompletedEventArgs (null, null, true, null));
2143                                 throw;
2144                         } catch (Exception ex) {
2145                                 OnUploadValuesCompleted (new UploadValuesCompletedEventArgs (null, ex, true, null));
2146                                 throw new WebException ("An error occurred performing a WebClient request.", ex);
2147                         }
2148                 }
2149
2150                 async Task<byte[]> UploadValuesTaskAsyncCore (WebRequest request, NameValueCollection data,
2151                                                               CancellationToken token)
2152                 {
2153                         token.ThrowIfCancellationRequested ();
2154                         string cType = Headers ["Content-Type"];
2155                         if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0)
2156                                 throw new WebException ("Content-Type header cannot be changed from its default " +
2157                                                         "value for this request.");
2158
2159                         WebResponse response = null;
2160
2161                         Headers ["Content-Type"] = urlEncodedCType;
2162                         try {
2163                                 MemoryStream tmpStream = new MemoryStream ();
2164                                 foreach (string key in data) {
2165                                         byte [] bytes = Encoding.UTF8.GetBytes (key);
2166                                         UrlEncodeAndWrite (tmpStream, bytes);
2167                                         tmpStream.WriteByte ((byte) '=');
2168                                         bytes = Encoding.UTF8.GetBytes (data [key]);
2169                                         UrlEncodeAndWrite (tmpStream, bytes);
2170                                         tmpStream.WriteByte ((byte) '&');
2171                                 }
2172
2173                                 token.ThrowIfCancellationRequested ();
2174                                 
2175                                 int length = (int) tmpStream.Length;
2176                                 if (length > 0)
2177                                         tmpStream.SetLength (--length); // remove trailing '&'
2178                                 
2179                                 byte [] buf = tmpStream.GetBuffer ();
2180                                 request.ContentLength = length;
2181                                 using (Stream rqStream = await request.GetRequestStreamAsync ()) {
2182                                         await rqStream.WriteAsync (buf, 0, length, token);
2183                                 }
2184                                 tmpStream.Close ();
2185
2186                                 response = await GetWebResponseTaskAsync (request, token);
2187                                 return await ReadAllTaskAsync (request, response, token);
2188                         } finally {
2189                                 if (response != null)
2190                                         response.Close ();
2191                         }
2192                 }
2193
2194 #endif
2195
2196         }
2197 }
2198