2009-07-11 Michael Barker <mike@middlesoft.co.uk>
[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 //
10 // Copyright 2003 Ximian, Inc. (http://www.ximian.com)
11 // Copyright 2006, 2007 Novell, Inc. (http://www.novell.com)
12 //
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33 //
34 // Notes on CancelAsync and Async methods:
35 //
36 //    WebClient.CancelAsync is implemented by calling Thread.Interrupt
37 //    in our helper thread.   The various async methods have to cancel
38 //    any ongoing requests by calling request.Abort () at that point.
39 //    In a few places (UploadDataCore, UploadValuesCore,
40 //    UploadFileCore) we catch the ThreadInterruptedException and
41 //    abort the request there.
42 //
43 //    Higher level routines (the async callbacks) also need to catch
44 //    the exception and raise the OnXXXXCompleted events there with
45 //    the "canceled" flag set to true. 
46 //
47 //    In a few other places where these helper routines are not used
48 //    (OpenReadAsync for example) catching the ThreadAbortException
49 //    also must abort the request.
50 //
51 //    The Async methods currently differ in their implementation from
52 //    the .NET implementation in that we manually catch any other
53 //    exceptions and correctly raise the OnXXXXCompleted passing the
54 //    Exception that caused the problem.   The .NET implementation
55 //    does not seem to have a mechanism to flag errors that happen
56 //    during downloads though.    We do this because we still need to
57 //    catch the exception on these helper threads, or we would
58 //    otherwise kill the application (on the 2.x profile, uncaught
59 //    exceptions in threads terminate the application).
60 //
61 using System;
62 using System.Collections.Specialized;
63 using System.ComponentModel;
64 using System.IO;
65 using System.Runtime.InteropServices;
66 using System.Runtime.Serialization;
67 using System.Text;
68 using System.Threading;
69 #if NET_2_0
70 using System.Net.Cache;
71 #endif
72
73 namespace System.Net 
74 {
75         [ComVisible(true)]
76         public
77 #if !NET_2_0
78         sealed
79 #endif
80         class WebClient : Component
81         {
82                 static readonly string urlEncodedCType = "application/x-www-form-urlencoded";
83                 static byte [] hexBytes;
84                 ICredentials credentials;
85                 WebHeaderCollection headers;
86                 WebHeaderCollection responseHeaders;
87                 Uri baseAddress;
88                 string baseString;
89                 NameValueCollection queryString;
90                 bool is_busy;
91 #if NET_2_0
92                 bool async;
93                 Thread async_thread;
94                 Encoding encoding = Encoding.Default;
95                 IWebProxy proxy;
96 #endif
97
98                 // Constructors
99                 static WebClient ()
100                 {
101                         hexBytes = new byte [16];
102                         int index = 0;
103                         for (int i = '0'; i <= '9'; i++, index++)
104                                 hexBytes [index] = (byte) i;
105
106                         for (int i = 'a'; i <= 'f'; i++, index++)
107                                 hexBytes [index] = (byte) i;
108                 }
109                 
110                 public WebClient ()
111                 {
112                 }
113                 
114                 // Properties
115                 
116                 public string BaseAddress {
117                         get {
118                                 if (baseString == null) {
119                                         if (baseAddress == null)
120                                                 return string.Empty;
121                                 }
122
123                                 baseString = baseAddress.ToString ();
124                                 return baseString;
125                         }
126                         
127                         set {
128                                 if (value == null || value.Length == 0) {
129                                         baseAddress = null;
130                                 } else {
131                                         baseAddress = new Uri (value);
132                                 }
133                         }
134                 }
135
136 #if NET_2_0
137                 static Exception GetMustImplement ()
138                 {
139                         return new NotImplementedException ();
140                 }
141                 
142                 [MonoTODO]
143                 public RequestCachePolicy CachePolicy
144                 {
145                         get {
146                                 throw GetMustImplement ();
147                         }
148                         set {
149                                 throw GetMustImplement ();
150                         }
151                 }
152
153                 [MonoTODO]
154                 public bool UseDefaultCredentials
155                 {
156                         get {
157                                 throw GetMustImplement ();
158                         }
159                         set {
160                                 throw GetMustImplement ();
161                         }
162                 }
163 #endif
164                 
165                 public ICredentials Credentials {
166                         get { return credentials; }
167                         set { credentials = value; }
168                 }
169
170                 public WebHeaderCollection Headers {
171                         get {
172                                 if (headers == null)
173                                         headers = new WebHeaderCollection ();
174
175                                 return headers;
176                         }
177                         set { headers = value; }
178                 }
179                 
180                 public NameValueCollection QueryString {
181                         get {
182                                 if (queryString == null)
183                                         queryString = new NameValueCollection ();
184
185                                 return queryString;
186                         }
187                         set { queryString = value; }
188                 }
189                 
190                 public WebHeaderCollection ResponseHeaders {
191                         get { return responseHeaders; }
192                 }
193
194 #if NET_2_0
195                 public Encoding Encoding {
196                         get { return encoding; }
197                         set {
198                                 if (value == null)
199                                         throw new ArgumentNullException ("Encoding");
200                                 encoding = value;
201                         }
202                 }
203
204                 public IWebProxy Proxy {
205                         get { return proxy; }
206                         set { proxy = value; }
207                 }
208 #endif
209
210 #if NET_2_0
211                 public bool IsBusy {
212                         get { return is_busy; } 
213                 }
214 #else
215                 bool IsBusy {
216                         get { return is_busy; }
217                 }
218 #endif
219
220                 // Methods
221
222                 void CheckBusy ()
223                 {
224                         if (IsBusy)
225                                 throw new NotSupportedException ("WebClient does not support conccurent I/O operations.");
226                 }
227
228                 void SetBusy ()
229                 {
230                         lock (this) {
231                                 CheckBusy ();
232                                 is_busy = true;
233                         }
234                 }
235
236                 //   DownloadData
237
238                 public byte [] DownloadData (string address)
239                 {
240 #if NET_2_0
241                         if (address == null)
242                                 throw new ArgumentNullException ("address");
243 #endif
244
245                         return DownloadData (CreateUri (address));
246                 }
247
248 #if NET_2_0
249                 public
250 #endif
251                 byte [] DownloadData (Uri address)
252                 {
253 #if NET_2_0
254                         if (address == null)
255                                 throw new ArgumentNullException ("address");
256 #endif
257
258                         try {
259                                 SetBusy ();
260 #if NET_2_0                             
261                                 async = false;
262 #endif                          
263                                 return DownloadDataCore (address, null);
264                         } finally {
265                                 is_busy = false;
266                         }
267                 }
268
269                 byte [] DownloadDataCore (Uri address, object userToken)
270                 {
271                         WebRequest request = null;
272                         
273                         try {
274                                 request = SetupRequest (address);
275                                 WebResponse response = GetWebResponse (request);
276                                 Stream st = response.GetResponseStream ();
277                                 return ReadAll (st, (int) response.ContentLength, userToken);
278                         } catch (ThreadInterruptedException){
279                                 if (request != null)
280                                         request.Abort ();
281                                 throw;
282                         } catch (Exception ex) {
283                                 throw new WebException ("An error occurred " +
284                                         "performing a WebClient request.", ex);
285                         }
286                 }
287
288                 //   DownloadFile
289
290                 public void DownloadFile (string address, string fileName)
291                 {
292 #if NET_2_0
293                         if (address == null)
294                                 throw new ArgumentNullException ("address");
295 #endif
296
297                         DownloadFile (CreateUri (address), fileName);
298                 }
299
300 #if NET_2_0
301                 public
302 #endif
303                 void DownloadFile (Uri address, string fileName)
304                 {
305 #if NET_2_0
306                         if (address == null)
307                                 throw new ArgumentNullException ("address");
308                         if (fileName == null)
309                                 throw new ArgumentNullException ("fileName");
310 #endif
311
312                         try {
313                                 SetBusy ();
314 #if NET_2_0                             
315                                 async = false;
316 #endif                          
317                                 DownloadFileCore (address, fileName, null);
318                         } catch (Exception ex) {
319                                 throw new WebException ("An error occurred " +
320                                         "performing a WebClient request.", ex);
321                         } finally {
322                                 is_busy = false;
323                         }
324                 }
325
326                 void DownloadFileCore (Uri address, string fileName, object userToken)
327                 {
328                         WebRequest request = null;
329                         
330                         using (FileStream f = new FileStream (fileName, FileMode.Create)) {
331                                 try {
332                                         request = SetupRequest (address);
333                                         WebResponse response = GetWebResponse (request);
334                                         Stream st = response.GetResponseStream ();
335                                         
336                                         int cLength = (int) response.ContentLength;
337                                         int length = (cLength <= -1 || cLength > 32*1024) ? 32*1024 : cLength;
338                                         byte [] buffer = new byte [length];
339                                         
340                                         int nread = 0;
341 #if NET_2_0
342                                         long notify_total = 0;
343 #endif                                  
344                                         while ((nread = st.Read (buffer, 0, length)) != 0){
345 #if NET_2_0
346                                                 if (async){
347                                                         notify_total += nread;
348                                                         OnDownloadProgressChanged (
349                                                                 new DownloadProgressChangedEventArgs (notify_total, response.ContentLength, userToken));
350                                                                                                       
351                                                 }
352 #endif
353                                                 f.Write (buffer, 0, nread);
354                                         }
355                                 } catch (ThreadInterruptedException){
356                                         if (request != null)
357                                                 request.Abort ();
358                                         throw;
359                                 }
360                         }
361                 }
362
363                 //   OpenRead
364
365                 public Stream OpenRead (string address)
366                 {
367 #if NET_2_0
368                         if (address == null)
369                                 throw new ArgumentNullException ("address");
370 #endif
371
372                         return OpenRead (CreateUri (address));
373                 }
374
375 #if NET_2_0
376                 public
377 #endif
378                 Stream OpenRead (Uri address)
379                 {
380 #if NET_2_0
381                         if (address == null)
382                                 throw new ArgumentNullException ("address");
383 #endif
384
385                         WebRequest request = null;
386                         try {
387                                 SetBusy ();
388 #if NET_2_0                             
389                                 async = false;
390 #endif                          
391                                 request = SetupRequest (address);
392                                 WebResponse response = GetWebResponse (request);
393                                 return response.GetResponseStream ();
394                         } catch (Exception ex) {
395                                 throw new WebException ("An error occurred " +
396                                         "performing a WebClient request.", ex);
397                         } finally {
398                                 is_busy = false;
399                         }
400                 }
401
402                 //   OpenWrite
403
404                 public Stream OpenWrite (string address)
405                 {
406 #if NET_2_0
407                         if (address == null)
408                                 throw new ArgumentNullException ("address");
409 #endif
410
411                         return OpenWrite (CreateUri (address));
412                 }
413                 
414                 public Stream OpenWrite (string address, string method)
415                 {
416 #if NET_2_0
417                         if (address == null)
418                                 throw new ArgumentNullException ("address");
419 #endif
420
421                         return OpenWrite (CreateUri (address), method);
422                 }
423
424 #if NET_2_0
425                 public
426 #endif
427                 Stream OpenWrite (Uri address)
428                 {
429                         return OpenWrite (address, (string) null);
430                 }
431
432 #if NET_2_0
433                 public
434 #endif
435                 Stream OpenWrite (Uri address, string method)
436                 {
437 #if NET_2_0
438                         if (address == null)
439                                 throw new ArgumentNullException ("address");
440 #endif
441
442                         try {
443                                 SetBusy ();
444 #if NET_2_0                             
445                                 async = false;
446 #endif                          
447                                 WebRequest request = SetupRequest (address, method, true);
448                                 return request.GetRequestStream ();
449                         } catch (Exception ex) {
450                                 throw new WebException ("An error occurred " +
451                                         "performing a WebClient request.", ex);
452                         } finally {
453                                 is_busy = false;
454                         }
455                 }
456
457                 private string DetermineMethod (Uri address, string method, bool is_upload)
458                 {
459                         if (method != null)
460                                 return method;
461
462 #if NET_2_0
463                         if (address.Scheme == Uri.UriSchemeFtp)
464                                 return (is_upload) ? "STOR" : "RETR";
465 #endif
466                         return (is_upload) ? "POST" : "GET";
467                 }
468
469                 //   UploadData
470
471                 public byte [] UploadData (string address, byte [] data)
472                 {
473 #if NET_2_0
474                         if (address == null)
475                                 throw new ArgumentNullException ("address");
476 #endif
477
478                         return UploadData (CreateUri (address), data);
479                 }
480                 
481                 public byte [] UploadData (string address, string method, byte [] data)
482                 {
483 #if NET_2_0
484                         if (address == null)
485                                 throw new ArgumentNullException ("address");
486 #endif
487
488                         return UploadData (CreateUri (address), method, data);
489                 }
490
491 #if NET_2_0
492                 public
493 #endif
494                 byte [] UploadData (Uri address, byte [] data)
495                 {
496                         return UploadData (address, (string) null, data);
497                 }
498
499 #if NET_2_0
500                 public
501 #endif
502                 byte [] UploadData (Uri address, string method, byte [] data)
503                 {
504 #if NET_2_0
505                         if (address == null)
506                                 throw new ArgumentNullException ("address");
507                         if (data == null)
508                                 throw new ArgumentNullException ("data");
509 #endif
510
511                         try {
512                                 SetBusy ();
513 #if NET_2_0                             
514                                 async = false;
515 #endif                          
516                                 return UploadDataCore (address, method, data, null);
517                         } catch (WebException) {
518                                 throw;
519                         } catch (Exception ex) {
520                                 throw new WebException ("An error occurred " +
521                                         "performing a WebClient request.", ex);
522                         } finally {
523                                 is_busy = false;
524                         }
525                 }
526
527                 byte [] UploadDataCore (Uri address, string method, byte [] data, object userToken)
528                 {
529 #if ONLY_1_1
530                         if (address == null)
531                                 throw new ArgumentNullException ("address");
532                         if (data == null)
533                                 throw new ArgumentNullException ("data");
534 #endif
535
536                         WebRequest request = SetupRequest (address, method, true);
537                         try {
538                                 int contentLength = data.Length;
539                                 request.ContentLength = contentLength;
540                                 using (Stream stream = request.GetRequestStream ()) {
541                                         stream.Write (data, 0, contentLength);
542                                 }
543                                 
544                                 WebResponse response = GetWebResponse (request);
545                                 Stream st = response.GetResponseStream ();
546                                 return ReadAll (st, (int) response.ContentLength, userToken);
547                         } catch (ThreadInterruptedException){
548                                 if (request != null)
549                                         request.Abort ();
550                                 throw;
551                         }
552                 }
553
554                 //   UploadFile
555
556                 public byte [] UploadFile (string address, string fileName)
557                 {
558 #if NET_2_0
559                         if (address == null)
560                                 throw new ArgumentNullException ("address");
561 #endif
562
563                         return UploadFile (CreateUri (address), fileName);
564                 }
565
566 #if NET_2_0
567                 public
568 #endif
569                 byte [] UploadFile (Uri address, string fileName)
570                 {
571                         return UploadFile (address, (string) null, fileName);
572                 }
573                 
574                 public byte [] UploadFile (string address, string method, string fileName)
575                 {
576                         return UploadFile (CreateUri (address), method, fileName);
577                 }
578
579 #if NET_2_0
580                 public
581 #endif
582                 byte [] UploadFile (Uri address, string method, string fileName)
583                 {
584 #if NET_2_0
585                         if (address == null)
586                                 throw new ArgumentNullException ("address");
587                         if (fileName == null)
588                                 throw new ArgumentNullException ("fileName");
589 #endif
590
591                         try {
592                                 SetBusy ();
593 #if NET_2_0                             
594                                 async = false;
595 #endif                          
596                                 return UploadFileCore (address, method, fileName, null);
597                         } catch (Exception ex) {
598                                 throw new WebException ("An error occurred " +
599                                         "performing a WebClient request.", ex);
600                         } finally {
601                                 is_busy = false;
602                         }
603                 }
604
605                 byte [] UploadFileCore (Uri address, string method, string fileName, object userToken)
606                 {
607 #if ONLY_1_1
608                         if (address == null)
609                                 throw new ArgumentNullException ("address");
610 #endif
611
612                         string fileCType = Headers ["Content-Type"];
613                         if (fileCType != null) {
614                                 string lower = fileCType.ToLower ();
615                                 if (lower.StartsWith ("multipart/"))
616                                         throw new WebException ("Content-Type cannot be set to a multipart" +
617                                                                 " type for this request.");
618                         } else {
619                                 fileCType = "application/octet-stream";
620                         }
621
622                         string boundary = "------------" + DateTime.Now.Ticks.ToString ("x");
623                         Headers ["Content-Type"] = String.Format ("multipart/form-data; boundary={0}", boundary);
624                         Stream reqStream = null;
625                         Stream fStream = null;
626                         byte [] resultBytes = null;
627
628                         fileName = Path.GetFullPath (fileName);
629
630                         WebRequest request = null;
631                         try {
632                                 fStream = File.OpenRead (fileName);
633                                 request = SetupRequest (address, method, true);
634                                 reqStream = request.GetRequestStream ();
635                                 byte [] realBoundary = Encoding.ASCII.GetBytes ("--" + boundary + "\r\n");
636                                 reqStream.Write (realBoundary, 0, realBoundary.Length);
637                                 string partHeaders = String.Format ("Content-Disposition: form-data; " +
638                                                                     "name=\"file\"; filename=\"{0}\"\r\n" +
639                                                                     "Content-Type: {1}\r\n\r\n",
640                                                                     Path.GetFileName (fileName), fileCType);
641
642                                 byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders);
643                                 reqStream.Write (partHeadersBytes, 0, partHeadersBytes.Length);
644                                 int nread;
645                                 byte [] buffer = new byte [4096];
646                                 while ((nread = fStream.Read (buffer, 0, 4096)) != 0)
647                                         reqStream.Write (buffer, 0, nread);
648
649                                 reqStream.WriteByte ((byte) '\r');
650                                 reqStream.WriteByte ((byte) '\n');
651                                 reqStream.Write (realBoundary, 0, realBoundary.Length);
652                                 reqStream.Close ();
653                                 reqStream = null;
654                                 WebResponse response = GetWebResponse (request);
655                                 Stream st = response.GetResponseStream ();
656                                 resultBytes = ReadAll (st, (int) response.ContentLength, userToken);
657                         } catch (ThreadInterruptedException){
658                                 if (request != null)
659                                         request.Abort ();
660                                 throw;
661                         } finally {
662                                 if (fStream != null)
663                                         fStream.Close ();
664
665                                 if (reqStream != null)
666                                         reqStream.Close ();
667                         }
668                         
669                         return resultBytes;
670                 }
671                 
672                 public byte[] UploadValues (string address, NameValueCollection data)
673                 {
674 #if NET_2_0
675                         if (address == null)
676                                 throw new ArgumentNullException ("address");
677 #endif
678
679                         return UploadValues (CreateUri (address), data);
680                 }
681                 
682                 public byte[] UploadValues (string address, string method, NameValueCollection data)
683                 {
684 #if NET_2_0
685                         if (address == null)
686                                 throw new ArgumentNullException ("address");
687 #endif
688
689                         return UploadValues (CreateUri (address), method, data);
690                 }
691
692 #if NET_2_0
693                 public
694 #endif
695                 byte[] UploadValues (Uri address, NameValueCollection data)
696                 {
697                         return UploadValues (address, (string) null, data);
698                 }
699
700 #if NET_2_0
701                 public
702 #endif
703                 byte[] UploadValues (Uri address, string method, NameValueCollection data)
704                 {
705 #if NET_2_0
706                         if (address == null)
707                                 throw new ArgumentNullException ("address");
708                         if (data == null)
709                                 throw new ArgumentNullException ("data");
710 #endif
711
712                         try {
713                                 SetBusy ();
714 #if NET_2_0                             
715                                 async = false;
716 #endif                          
717                                 return UploadValuesCore (address, method, data, null);
718                         } catch (Exception ex) {
719                                 throw new WebException ("An error occurred " +
720                                         "performing a WebClient request.", ex);
721                         } finally {
722                                 is_busy = false;
723                         }
724                 }
725
726                 byte[] UploadValuesCore (Uri uri, string method, NameValueCollection data, object userToken)
727                 {
728 #if ONLY_1_1
729                         if (data == null)
730                                 throw new ArgumentNullException ("data");
731 #endif
732
733                         string cType = Headers ["Content-Type"];
734                         if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0)
735                                 throw new WebException ("Content-Type header cannot be changed from its default " +
736                                                         "value for this request.");
737
738                         Headers ["Content-Type"] = urlEncodedCType;
739                         WebRequest request = SetupRequest (uri, method, true);
740                         try {
741                                 MemoryStream tmpStream = new MemoryStream ();
742                                 foreach (string key in data) {
743                                         byte [] bytes = Encoding.UTF8.GetBytes (key);
744                                         UrlEncodeAndWrite (tmpStream, bytes);
745                                         tmpStream.WriteByte ((byte) '=');
746                                         bytes = Encoding.UTF8.GetBytes (data [key]);
747                                         UrlEncodeAndWrite (tmpStream, bytes);
748                                         tmpStream.WriteByte ((byte) '&');
749                                 }
750                                 
751                                 int length = (int) tmpStream.Length;
752                                 if (length > 0)
753                                         tmpStream.SetLength (--length); // remove trailing '&'
754                                 
755                                 byte [] buf = tmpStream.GetBuffer ();
756                                 request.ContentLength = length;
757                                 using (Stream rqStream = request.GetRequestStream ()) {
758                                         rqStream.Write (buf, 0, length);
759                                 }
760                                 tmpStream.Close ();
761                                 
762                                 WebResponse response = GetWebResponse (request);
763                                 Stream st = response.GetResponseStream ();
764                                 return ReadAll (st, (int) response.ContentLength, userToken);
765                         } catch (ThreadInterruptedException) {
766                                 request.Abort ();
767                                 throw;
768                         }
769                 }
770
771 #if NET_2_0
772                 public string DownloadString (string address)
773                 {
774                         if (address == null)
775                                 throw new ArgumentNullException ("address");
776
777                         return encoding.GetString (DownloadData (CreateUri (address)));
778                 }
779
780                 public string DownloadString (Uri address)
781                 {
782                         if (address == null)
783                                 throw new ArgumentNullException ("address");
784
785                         return encoding.GetString (DownloadData (CreateUri (address)));
786                 }
787
788                 public string UploadString (string address, string data)
789                 {
790                         if (address == null)
791                                 throw new ArgumentNullException ("address");
792                         if (data == null)
793                                 throw new ArgumentNullException ("data");
794
795                         byte [] resp = UploadData (address, encoding.GetBytes (data));
796                         return encoding.GetString (resp);
797                 }
798
799                 public string UploadString (string address, string method, string data)
800                 {
801                         if (address == null)
802                                 throw new ArgumentNullException ("address");
803                         if (data == null)
804                                 throw new ArgumentNullException ("data");
805
806                         byte [] resp = UploadData (address, method, encoding.GetBytes (data));
807                         return encoding.GetString (resp);
808                 }
809
810                 public string UploadString (Uri address, string data)
811                 {
812                         if (address == null)
813                                 throw new ArgumentNullException ("address");
814                         if (data == null)
815                                 throw new ArgumentNullException ("data");
816
817                         byte [] resp = UploadData (address, encoding.GetBytes (data));
818                         return encoding.GetString (resp);
819                 }
820
821                 public string UploadString (Uri address, string method, string data)
822                 {
823                         if (address == null)
824                                 throw new ArgumentNullException ("address");
825                         if (data == null)
826                                 throw new ArgumentNullException ("data");
827
828                         byte [] resp = UploadData (address, method, encoding.GetBytes (data));
829                         return encoding.GetString (resp);
830                 }
831
832                 public event DownloadDataCompletedEventHandler DownloadDataCompleted;
833                 public event AsyncCompletedEventHandler DownloadFileCompleted;
834                 public event DownloadProgressChangedEventHandler DownloadProgressChanged;
835                 public event DownloadStringCompletedEventHandler DownloadStringCompleted;
836                 public event OpenReadCompletedEventHandler OpenReadCompleted;
837                 public event OpenWriteCompletedEventHandler OpenWriteCompleted;
838                 public event UploadDataCompletedEventHandler UploadDataCompleted;
839                 public event UploadFileCompletedEventHandler UploadFileCompleted;
840                 public event UploadProgressChangedEventHandler UploadProgressChanged;
841                 public event UploadStringCompletedEventHandler UploadStringCompleted;
842                 public event UploadValuesCompletedEventHandler UploadValuesCompleted;
843 #endif
844
845                 Uri CreateUri (string address)
846                 {
847 #if ONLY_1_1
848                         try {
849                                 return MakeUri (address);
850                         } catch (Exception ex) {
851                                 throw new WebException ("An error occurred " +
852                                         "performing a WebClient request.", ex);
853                         }
854 #else
855                         return MakeUri (address);
856 #endif
857                 }
858
859 #if NET_2_0
860                 Uri CreateUri (Uri address)
861                 {
862                         string query = address.Query;
863                         if (String.IsNullOrEmpty (query))
864                                 query = GetQueryString (true);
865
866                         if (baseAddress == null && query == null)
867                                 return address;
868
869                         if (baseAddress == null)
870                                 return new Uri (address.ToString () + query, (query != null));
871
872                         if (query == null)
873                                 return new Uri (baseAddress, address.ToString ());
874
875                         return new Uri (baseAddress, address.ToString () + query, (query != null));
876
877                 }
878 #endif
879
880                 string GetQueryString (bool add_qmark)
881                 {
882                         if (queryString == null || queryString.Count == 0)
883                                 return null;
884
885                         StringBuilder sb = new StringBuilder ();
886                         if (add_qmark)
887                                 sb.Append ('?');
888
889                         foreach (string key in queryString)
890                                 sb.AppendFormat ("{0}={1}&", key, UrlEncode (queryString [key]));
891
892                         if (sb.Length != 0)
893                                 sb.Length--; // removes last '&' or the '?' if empty.
894
895                         if (sb.Length == 0)
896                                 return null;
897
898                         return sb.ToString ();
899                 }
900
901                 Uri MakeUri (string path)
902                 {
903                         string query = GetQueryString (true);
904                         if (baseAddress == null && query == null) {
905                                 try {
906                                         return new Uri (path);
907 #if NET_2_0
908                                 } catch (ArgumentNullException) {
909                                         path = Path.GetFullPath (path);
910                                         return new Uri ("file://" + path);
911 #endif
912                                 } catch (UriFormatException) {
913                                         path = Path.GetFullPath (path);
914                                         return new Uri ("file://" + path);
915                                 }
916                         }
917
918                         if (baseAddress == null)
919                                 return new Uri (path + query, (query != null));
920
921                         if (query == null)
922                                 return new Uri (baseAddress, path);
923
924                         return new Uri (baseAddress, path + query, (query != null));
925                 }
926                 
927                 WebRequest SetupRequest (Uri uri)
928                 {
929                         WebRequest request = WebRequest.Create (uri);
930 #if NET_2_0
931                         if (Proxy != null)
932                                 request.Proxy = Proxy;
933 #endif
934                         request.Credentials = credentials;
935
936                         // Special headers. These are properties of HttpWebRequest.
937                         // What do we do with other requests differnt from HttpWebRequest?
938                         if (headers != null && headers.Count != 0 && (request is HttpWebRequest)) {
939                                 HttpWebRequest req = (HttpWebRequest) request;
940                                 string expect = headers ["Expect"];
941                                 string contentType = headers ["Content-Type"];
942                                 string accept = headers ["Accept"];
943                                 string connection = headers ["Connection"];
944                                 string userAgent = headers ["User-Agent"];
945                                 string referer = headers ["Referer"];
946                                 headers.RemoveInternal ("Expect");
947                                 headers.RemoveInternal ("Content-Type");
948                                 headers.RemoveInternal ("Accept");
949                                 headers.RemoveInternal ("Connection");
950                                 headers.RemoveInternal ("Referer");
951                                 headers.RemoveInternal ("User-Agent");
952                                 request.Headers = headers;
953
954                                 if (expect != null && expect.Length > 0)
955                                         req.Expect = expect;
956
957                                 if (accept != null && accept.Length > 0)
958                                         req.Accept = accept;
959
960                                 if (contentType != null && contentType.Length > 0)
961                                         req.ContentType = contentType;
962
963                                 if (connection != null && connection.Length > 0)
964                                         req.Connection = connection;
965
966                                 if (userAgent != null && userAgent.Length > 0)
967                                         req.UserAgent = userAgent;
968
969                                 if (referer != null && referer.Length > 0)
970                                         req.Referer = referer;
971                         }
972
973                         responseHeaders = null;
974                         return request;
975                 }
976
977                 WebRequest SetupRequest (Uri uri, string method, bool is_upload)
978                 {
979                         WebRequest request = SetupRequest (uri);
980                         request.Method = DetermineMethod (uri, method, is_upload);
981                         return request;
982                 }
983
984                 byte [] ReadAll (Stream stream, int length, object userToken)
985                 {
986                         MemoryStream ms = null;
987                         
988                         bool nolength = (length == -1);
989                         int size = ((nolength) ? 8192 : length);
990                         if (nolength)
991                                 ms = new MemoryStream ();
992
993 //                      long total = 0;
994                         int nread = 0;
995                         int offset = 0;
996                         byte [] buffer = new byte [size];
997                         while ((nread = stream.Read (buffer, offset, size)) != 0) {
998                                 if (nolength) {
999                                         ms.Write (buffer, 0, nread);
1000                                 } else {
1001                                         offset += nread;
1002                                         size -= nread;
1003                                 }
1004 #if NET_2_0
1005                                 if (async){
1006 //                                      total += nread;
1007                                         OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (nread, length, userToken));
1008                                 }
1009 #endif
1010                         }
1011
1012                         if (nolength)
1013                                 return ms.ToArray ();
1014
1015                         return buffer;
1016                 }
1017
1018                 string UrlEncode (string str)
1019                 {
1020                         StringBuilder result = new StringBuilder ();
1021
1022                         int len = str.Length;
1023                         for (int i = 0; i < len; i++) {
1024                                 char c = str [i];
1025                                 if (c == ' ')
1026                                         result.Append ('+');
1027                                 else if ((c < '0' && c != '-' && c != '.') ||
1028                                          (c < 'A' && c > '9') ||
1029                                          (c > 'Z' && c < 'a' && c != '_') ||
1030                                          (c > 'z')) {
1031                                         result.Append ('%');
1032                                         int idx = ((int) c) >> 4;
1033                                         result.Append ((char) hexBytes [idx]);
1034                                         idx = ((int) c) & 0x0F;
1035                                         result.Append ((char) hexBytes [idx]);
1036                                 } else {
1037                                         result.Append (c);
1038                                 }
1039                         }
1040
1041                         return result.ToString ();
1042                 }
1043
1044                 static void UrlEncodeAndWrite (Stream stream, byte [] bytes)
1045                 {
1046                         if (bytes == null)
1047                                 return;
1048
1049                         int len = bytes.Length;
1050                         if (len == 0)
1051                                 return;
1052
1053                         for (int i = 0; i < len; i++) {
1054                                 char c = (char) bytes [i];
1055                                 if (c == ' ')
1056                                         stream.WriteByte ((byte) '+');
1057                                 else if ((c < '0' && c != '-' && c != '.') ||
1058                                          (c < 'A' && c > '9') ||
1059                                          (c > 'Z' && c < 'a' && c != '_') ||
1060                                          (c > 'z')) {
1061                                         stream.WriteByte ((byte) '%');
1062                                         int idx = ((int) c) >> 4;
1063                                         stream.WriteByte (hexBytes [idx]);
1064                                         idx = ((int) c) & 0x0F;
1065                                         stream.WriteByte (hexBytes [idx]);
1066                                 } else {
1067                                         stream.WriteByte ((byte) c);
1068                                 }
1069                         }
1070                 }
1071
1072 #if NET_2_0
1073                 public void CancelAsync ()
1074                 {
1075                         lock (this){
1076                                 if (async_thread == null)
1077                                         return;
1078
1079                                 //
1080                                 // We first flag things as done, in case the Interrupt hangs
1081                                 // or the thread decides to hang in some other way inside the
1082                                 // event handlers, or if we are stuck somewhere else.  This
1083                                 // ensures that the WebClient object is reusable immediately
1084                                 //
1085                                 Thread t = async_thread;
1086                                 CompleteAsync ();
1087                                 t.Interrupt ();
1088                         }
1089                 }
1090
1091                 void CompleteAsync ()
1092                 {
1093                         lock (this){
1094                                 is_busy = false;
1095                                 async_thread = null;
1096                         }
1097                 }
1098
1099                 //    DownloadDataAsync
1100
1101                 public void DownloadDataAsync (Uri address)
1102                 {
1103                         DownloadDataAsync (address, null);
1104                 }
1105
1106                 public void DownloadDataAsync (Uri address, object userToken)
1107                 {
1108                         if (address == null)
1109                                 throw new ArgumentNullException ("address");
1110                         
1111                         lock (this) {
1112                                 SetBusy ();
1113                                 async = true;
1114                                 
1115                                 async_thread = new Thread (delegate (object state) {
1116                                         object [] args = (object []) state;
1117                                         try {
1118                                                 byte [] data = DownloadDataCore ((Uri) args [0], args [1]);
1119                                                 OnDownloadDataCompleted (
1120                                                         new DownloadDataCompletedEventArgs (data, null, false, args [1]));
1121                                         } catch (ThreadInterruptedException){
1122                                                 OnDownloadDataCompleted (
1123                                                         new DownloadDataCompletedEventArgs (null, null, true, args [1]));
1124                                                 throw;
1125                                         } catch (Exception e){
1126                                                 OnDownloadDataCompleted (
1127                                                         new DownloadDataCompletedEventArgs (null, e, false, args [1]));
1128                                         }
1129                                 });
1130                                 object [] cb_args = new object [] {address, userToken};
1131                                 async_thread.Start (cb_args);
1132                         }
1133                 }
1134
1135                 //    DownloadFileAsync
1136
1137                 public void DownloadFileAsync (Uri address, string fileName)
1138                 {
1139                         DownloadFileAsync (address, fileName, null);
1140                 }
1141
1142                 public void DownloadFileAsync (Uri address, string fileName, object userToken)
1143                 {
1144                         if (address == null)
1145                                 throw new ArgumentNullException ("address");
1146                         if (fileName == null)
1147                                 throw new ArgumentNullException ("fileName");
1148                         
1149                         lock (this) {
1150                                 SetBusy ();
1151                                 async = true;
1152
1153                                 async_thread = new Thread (delegate (object state) {
1154                                         object [] args = (object []) state;
1155                                         try {
1156                                                 DownloadFileCore ((Uri) args [0], (string) args [1], args [2]);
1157                                                 OnDownloadFileCompleted (
1158                                                         new AsyncCompletedEventArgs (null, false, args [2]));
1159                                         } catch (ThreadInterruptedException){
1160                                                 OnDownloadFileCompleted (
1161                                                         new AsyncCompletedEventArgs (null, true, args [2]));
1162                                         } catch (Exception e){
1163                                                 OnDownloadFileCompleted (
1164                                                         new AsyncCompletedEventArgs (e, false, args [2]));
1165                                         }});
1166                                 object [] cb_args = new object [] {address, fileName, userToken};
1167                                 async_thread.Start (cb_args);
1168                         }
1169                 }
1170
1171                 //    DownloadStringAsync
1172
1173                 public void DownloadStringAsync (Uri address)
1174                 {
1175                         DownloadStringAsync (address, null);
1176                 }
1177
1178                 public void DownloadStringAsync (Uri address, object userToken)
1179                 {
1180                         if (address == null)
1181                                 throw new ArgumentNullException ("address");
1182                         
1183                         lock (this) {
1184                                 SetBusy ();
1185                                 async = true;
1186
1187                                 async_thread = new Thread (delegate (object state) {
1188                                         object [] args = (object []) state;
1189                                         try {
1190                                                 string data = encoding.GetString (DownloadDataCore ((Uri) args [0], args [1]));
1191                                                 OnDownloadStringCompleted (
1192                                                         new DownloadStringCompletedEventArgs (data, null, false, args [1]));
1193                                         } catch (ThreadInterruptedException){
1194                                                 OnDownloadStringCompleted (
1195                                                         new DownloadStringCompletedEventArgs (null, null, true, args [1]));
1196                                         } catch (Exception e){
1197                                                 OnDownloadStringCompleted (
1198                                                         new DownloadStringCompletedEventArgs (null, e, false, args [1]));
1199                                         }});
1200                                 object [] cb_args = new object [] {address, userToken};
1201                                 async_thread.Start (cb_args);
1202                         }
1203                 }
1204
1205                 //    OpenReadAsync
1206
1207                 public void OpenReadAsync (Uri address)
1208                 {
1209                         OpenReadAsync (address, null);
1210                 }
1211
1212                 public void OpenReadAsync (Uri address, object userToken)
1213                 {
1214                         if (address == null)
1215                                 throw new ArgumentNullException ("address");
1216                         
1217                         lock (this) {
1218                                 SetBusy ();
1219                                 async = true;
1220
1221                                 async_thread = new Thread (delegate (object state) {
1222                                         object [] args = (object []) state;
1223                                         WebRequest request = null;
1224                                         try {
1225                                                 request = SetupRequest ((Uri) args [0]);
1226                                                 WebResponse response = GetWebResponse (request);
1227                                                 Stream stream = response.GetResponseStream ();
1228                                                 OnOpenReadCompleted (
1229                                                         new OpenReadCompletedEventArgs (stream, null, false, args [1]));
1230                                         } catch (ThreadInterruptedException){
1231                                                 if (request != null)
1232                                                         request.Abort ();
1233                                                 
1234                                                 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, null, true, args [1]));
1235                                         } catch (Exception e){
1236                                                 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, e, false, args [1]));
1237                                         } });
1238                                 object [] cb_args = new object [] {address, userToken};
1239                                 async_thread.Start (cb_args);
1240                         }
1241                 }
1242
1243                 //    OpenWriteAsync
1244
1245                 public void OpenWriteAsync (Uri address)
1246                 {
1247                         OpenWriteAsync (address, null);
1248                 }
1249
1250                 public void OpenWriteAsync (Uri address, string method)
1251                 {
1252                         OpenWriteAsync (address, method, null);
1253                 }
1254
1255                 public void OpenWriteAsync (Uri address, string method, object userToken)
1256                 {
1257                         if (address == null)
1258                                 throw new ArgumentNullException ("address");
1259
1260                         lock (this) {
1261                                 SetBusy ();
1262                                 async = true;
1263
1264                                 async_thread = new Thread (delegate (object state) {
1265                                         object [] args = (object []) state;
1266                                         WebRequest request = null;
1267                                         try {
1268                                                 request = SetupRequest ((Uri) args [0], (string) args [1], true);
1269                                                 Stream stream = request.GetRequestStream ();
1270                                                 OnOpenWriteCompleted (
1271                                                         new OpenWriteCompletedEventArgs (stream, null, false, args [2]));
1272                                         } catch (ThreadInterruptedException){
1273                                                 if (request != null)
1274                                                         request.Abort ();
1275                                                 OnOpenWriteCompleted (
1276                                                         new OpenWriteCompletedEventArgs (null, null, true, args [2]));
1277                                         } catch (Exception e){
1278                                                 OnOpenWriteCompleted (
1279                                                         new OpenWriteCompletedEventArgs (null, e, false, args [2]));
1280                                         }});
1281                                 object [] cb_args = new object [] {address, method, userToken};
1282                                 async_thread.Start (cb_args);
1283                         }
1284                 }
1285
1286                 //    UploadDataAsync
1287
1288                 public void UploadDataAsync (Uri address, byte [] data)
1289                 {
1290                         UploadDataAsync (address, null, data);
1291                 }
1292
1293                 public void UploadDataAsync (Uri address, string method, byte [] data)
1294                 {
1295                         UploadDataAsync (address, method, data, null);
1296                 }
1297
1298                 public void UploadDataAsync (Uri address, string method, byte [] data, object userToken)
1299                 {
1300                         if (address == null)
1301                                 throw new ArgumentNullException ("address");
1302                         if (data == null)
1303                                 throw new ArgumentNullException ("data");
1304                         
1305                         lock (this) {
1306                                 SetBusy ();
1307                                 async = true;
1308
1309                                 async_thread = new Thread (delegate (object state) {
1310                                         object [] args = (object []) state;
1311                                         byte [] data2;
1312
1313                                         try {
1314                                                 data2 = UploadDataCore ((Uri) args [0], (string) args [1], (byte []) args [2], args [3]);
1315                                         
1316                                                 OnUploadDataCompleted (
1317                                                         new UploadDataCompletedEventArgs (data2, null, false, args [3]));
1318                                         } catch (ThreadInterruptedException){
1319                                                 OnUploadDataCompleted (
1320                                                         new UploadDataCompletedEventArgs (null, null, true, args [3]));
1321                                         } catch (Exception e){
1322                                                 OnUploadDataCompleted (
1323                                                         new UploadDataCompletedEventArgs (null, e, false, args [3]));
1324                                         }});
1325                                 object [] cb_args = new object [] {address, method, data,  userToken};
1326                                 async_thread.Start (cb_args);
1327                         }
1328                 }
1329
1330                 //    UploadFileAsync
1331
1332                 public void UploadFileAsync (Uri address, string fileName)
1333                 {
1334                         UploadFileAsync (address, null, fileName);
1335                 }
1336
1337                 public void UploadFileAsync (Uri address, string method, string fileName)
1338                 {
1339                         UploadFileAsync (address, method, fileName, null);
1340                 }
1341
1342                 public void UploadFileAsync (Uri address, string method, string fileName, object userToken)
1343                 {
1344                         if (address == null)
1345                                 throw new ArgumentNullException ("address");
1346                         if (fileName == null)
1347                                 throw new ArgumentNullException ("fileName");
1348
1349                         lock (this) {
1350                                 SetBusy ();
1351                                 async = true;
1352
1353                                 async_thread = new Thread (delegate (object state) {
1354                                         object [] args = (object []) state;
1355                                         byte [] data;
1356
1357                                         try {
1358                                                 data = UploadFileCore ((Uri) args [0], (string) args [1], (string) args [2], args [3]);
1359                                                 OnUploadFileCompleted (
1360                                                         new UploadFileCompletedEventArgs (data, null, false, args [3]));
1361                                         } catch (ThreadInterruptedException){
1362                                                 OnUploadFileCompleted (
1363                                                         new UploadFileCompletedEventArgs (null, null, true, args [3]));
1364                                         } catch (Exception e){
1365                                                 OnUploadFileCompleted (
1366                                                         new UploadFileCompletedEventArgs (null, e, false, args [3]));
1367                                         }});
1368                                 object [] cb_args = new object [] {address, method, fileName,  userToken};
1369                                 async_thread.Start (cb_args);
1370                         }
1371                 }
1372
1373                 //    UploadStringAsync
1374
1375                 public void UploadStringAsync (Uri address, string data)
1376                 {
1377                         UploadStringAsync (address, null, data);
1378                 }
1379
1380                 public void UploadStringAsync (Uri address, string method, string data)
1381                 {
1382                         UploadStringAsync (address, method, data, null);
1383                 }
1384
1385                 public void UploadStringAsync (Uri address, string method, string data, object userToken)
1386                 {
1387                         if (address == null)
1388                                 throw new ArgumentNullException ("address");
1389                         if (data == null)
1390                                 throw new ArgumentNullException ("data");
1391                         
1392                         lock (this) {
1393                                 SetBusy ();
1394                                 async = true;
1395                                 
1396                                 async_thread = new Thread (delegate (object state) {
1397                                         object [] args = (object []) state;
1398
1399                                         try {
1400                                                 string data2 = UploadString ((Uri) args [0], (string) args [1], (string) args [2]);
1401                                                 OnUploadStringCompleted (
1402                                                         new UploadStringCompletedEventArgs (data2, null, false, args [3]));
1403                                         } catch (ThreadInterruptedException){
1404                                                 OnUploadStringCompleted (
1405                                                         new UploadStringCompletedEventArgs (null, null, true, args [3]));
1406                                         } catch (Exception e){
1407                                                 OnUploadStringCompleted (
1408                                                         new UploadStringCompletedEventArgs (null, e, false, args [3]));
1409                                         }});
1410                                 object [] cb_args = new object [] {address, method, data, userToken};
1411                                 async_thread.Start (cb_args);
1412                         }
1413                 }
1414
1415                 //    UploadValuesAsync
1416
1417                 public void UploadValuesAsync (Uri address, NameValueCollection values)
1418                 {
1419                         UploadValuesAsync (address, null, values);
1420                 }
1421
1422                 public void UploadValuesAsync (Uri address, string method, NameValueCollection values)
1423                 {
1424                         UploadValuesAsync (address, method, values, null);
1425                 }
1426
1427                 public void UploadValuesAsync (Uri address, string method, NameValueCollection values, object userToken)
1428                 {
1429                         if (address == null)
1430                                 throw new ArgumentNullException ("address");
1431                         if (values == null)
1432                                 throw new ArgumentNullException ("values");
1433
1434                         lock (this) {
1435                                 CheckBusy ();
1436                                 async = true;
1437
1438                                 async_thread = new Thread (delegate (object state) {
1439                                         object [] args = (object []) state;
1440                                         try {
1441                                                 byte [] data = UploadValuesCore ((Uri) args [0], (string) args [1], (NameValueCollection) args [2], args [3]);
1442                                                 OnUploadValuesCompleted (
1443                                                         new UploadValuesCompletedEventArgs (data, null, false, args [3]));
1444                                         } catch (ThreadInterruptedException){
1445                                                 OnUploadValuesCompleted (
1446                                                         new UploadValuesCompletedEventArgs (null, null, true, args [3]));
1447                                         } catch (Exception e){
1448                                                 OnUploadValuesCompleted (
1449                                                         new UploadValuesCompletedEventArgs (null, e, false, args [3]));
1450                                         }});
1451                                 object [] cb_args = new object [] {address, method, values,  userToken};
1452                                 async_thread.Start (cb_args);
1453                         }
1454                 }
1455
1456                 protected virtual void OnDownloadDataCompleted (DownloadDataCompletedEventArgs args)
1457                 {
1458                         CompleteAsync ();
1459                         if (DownloadDataCompleted != null)
1460                                 DownloadDataCompleted (this, args);
1461                 }
1462
1463                 protected virtual void OnDownloadFileCompleted (AsyncCompletedEventArgs args)
1464                 {
1465                         CompleteAsync ();
1466                         if (DownloadFileCompleted != null)
1467                                 DownloadFileCompleted (this, args);
1468                 }
1469
1470                 protected virtual void OnDownloadProgressChanged (DownloadProgressChangedEventArgs e)
1471                 {
1472                         if (DownloadProgressChanged != null)
1473                                 DownloadProgressChanged (this, e);
1474                 }
1475
1476                 protected virtual void OnDownloadStringCompleted (DownloadStringCompletedEventArgs args)
1477                 {
1478                         CompleteAsync ();
1479                         if (DownloadStringCompleted != null)
1480                                 DownloadStringCompleted (this, args);
1481                 }
1482
1483                 protected virtual void OnOpenReadCompleted (OpenReadCompletedEventArgs args)
1484                 {
1485                         CompleteAsync ();
1486                         if (OpenReadCompleted != null)
1487                                 OpenReadCompleted (this, args);
1488                 }
1489
1490                 protected virtual void OnOpenWriteCompleted (OpenWriteCompletedEventArgs args)
1491                 {
1492                         CompleteAsync ();
1493                         if (OpenWriteCompleted != null)
1494                                 OpenWriteCompleted (this, args);
1495                 }
1496
1497                 protected virtual void OnUploadDataCompleted (UploadDataCompletedEventArgs args)
1498                 {
1499                         CompleteAsync ();
1500                         if (UploadDataCompleted != null)
1501                                 UploadDataCompleted (this, args);
1502                 }
1503
1504                 protected virtual void OnUploadFileCompleted (UploadFileCompletedEventArgs args)
1505                 {
1506                         CompleteAsync ();
1507                         if (UploadFileCompleted != null)
1508                                 UploadFileCompleted (this, args);
1509                 }
1510
1511                 protected virtual void OnUploadProgressChanged (UploadProgressChangedEventArgs e)
1512                 {
1513                         if (UploadProgressChanged != null)
1514                                 UploadProgressChanged (this, e);
1515                 }
1516
1517                 protected virtual void OnUploadStringCompleted (UploadStringCompletedEventArgs args)
1518                 {
1519                         CompleteAsync ();
1520                         if (UploadStringCompleted != null)
1521                                 UploadStringCompleted (this, args);
1522                 }
1523
1524                 protected virtual void OnUploadValuesCompleted (UploadValuesCompletedEventArgs args)
1525                 {
1526                         CompleteAsync ();
1527                         if (UploadValuesCompleted != null)
1528                                 UploadValuesCompleted (this, args);
1529                 }
1530
1531                 protected virtual WebResponse GetWebResponse (WebRequest request, IAsyncResult result)
1532                 {
1533                         WebResponse response = request.EndGetResponse (result);
1534                         responseHeaders = response.Headers;
1535                         return response;
1536                 }
1537 #endif
1538
1539 #if NET_2_0
1540                 protected virtual
1541 #endif
1542                 WebRequest GetWebRequest (Uri address)
1543                 {
1544                         return SetupRequest (address);
1545                 }
1546
1547 #if NET_2_0
1548                 protected virtual
1549 #endif
1550                 WebResponse GetWebResponse (WebRequest request)
1551                 {
1552                         WebResponse response = request.GetResponse ();
1553                         responseHeaders = response.Headers;
1554                         return response;
1555                 }
1556
1557         }
1558 }
1559