2009-08-03 Gonzalo Paniagua Javier <gonzalo@novell.com>
[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 (WebException wexc) {
283                                 throw;
284                         } catch (Exception ex) {
285                                 throw new WebException ("An error occurred " +
286                                         "performing a WebClient request.", ex);
287                         }
288                 }
289
290                 //   DownloadFile
291
292                 public void DownloadFile (string address, string fileName)
293                 {
294 #if NET_2_0
295                         if (address == null)
296                                 throw new ArgumentNullException ("address");
297 #endif
298
299                         DownloadFile (CreateUri (address), fileName);
300                 }
301
302 #if NET_2_0
303                 public
304 #endif
305                 void DownloadFile (Uri address, string fileName)
306                 {
307 #if NET_2_0
308                         if (address == null)
309                                 throw new ArgumentNullException ("address");
310                         if (fileName == null)
311                                 throw new ArgumentNullException ("fileName");
312 #endif
313
314                         try {
315                                 SetBusy ();
316 #if NET_2_0                             
317                                 async = false;
318 #endif                          
319                                 DownloadFileCore (address, fileName, null);
320                         } catch (WebException wexc) {
321                                 throw;
322                         } catch (Exception ex) {
323                                 throw new WebException ("An error occurred " +
324                                         "performing a WebClient request.", ex);
325                         } finally {
326                                 is_busy = false;
327                         }
328                 }
329
330                 void DownloadFileCore (Uri address, string fileName, object userToken)
331                 {
332                         WebRequest request = null;
333                         
334                         using (FileStream f = new FileStream (fileName, FileMode.Create)) {
335                                 try {
336                                         request = SetupRequest (address);
337                                         WebResponse response = GetWebResponse (request);
338                                         Stream st = response.GetResponseStream ();
339                                         
340                                         int cLength = (int) response.ContentLength;
341                                         int length = (cLength <= -1 || cLength > 32*1024) ? 32*1024 : cLength;
342                                         byte [] buffer = new byte [length];
343                                         
344                                         int nread = 0;
345 #if NET_2_0
346                                         long notify_total = 0;
347 #endif                                  
348                                         while ((nread = st.Read (buffer, 0, length)) != 0){
349 #if NET_2_0
350                                                 if (async){
351                                                         notify_total += nread;
352                                                         OnDownloadProgressChanged (
353                                                                 new DownloadProgressChangedEventArgs (notify_total, response.ContentLength, userToken));
354                                                                                                       
355                                                 }
356 #endif
357                                                 f.Write (buffer, 0, nread);
358                                         }
359                                 } catch (ThreadInterruptedException){
360                                         if (request != null)
361                                                 request.Abort ();
362                                         throw;
363                                 }
364                         }
365                 }
366
367                 //   OpenRead
368
369                 public Stream OpenRead (string address)
370                 {
371 #if NET_2_0
372                         if (address == null)
373                                 throw new ArgumentNullException ("address");
374 #endif
375
376                         return OpenRead (CreateUri (address));
377                 }
378
379 #if NET_2_0
380                 public
381 #endif
382                 Stream OpenRead (Uri address)
383                 {
384 #if NET_2_0
385                         if (address == null)
386                                 throw new ArgumentNullException ("address");
387 #endif
388
389                         WebRequest request = null;
390                         try {
391                                 SetBusy ();
392 #if NET_2_0                             
393                                 async = false;
394 #endif                          
395                                 request = SetupRequest (address);
396                                 WebResponse response = GetWebResponse (request);
397                                 return response.GetResponseStream ();
398                         } catch (WebException wexc) {
399                                 throw;
400                         } catch (Exception ex) {
401                                 throw new WebException ("An error occurred " +
402                                         "performing a WebClient request.", ex);
403                         } finally {
404                                 is_busy = false;
405                         }
406                 }
407
408                 //   OpenWrite
409
410                 public Stream OpenWrite (string address)
411                 {
412 #if NET_2_0
413                         if (address == null)
414                                 throw new ArgumentNullException ("address");
415 #endif
416
417                         return OpenWrite (CreateUri (address));
418                 }
419                 
420                 public Stream OpenWrite (string address, string method)
421                 {
422 #if NET_2_0
423                         if (address == null)
424                                 throw new ArgumentNullException ("address");
425 #endif
426
427                         return OpenWrite (CreateUri (address), method);
428                 }
429
430 #if NET_2_0
431                 public
432 #endif
433                 Stream OpenWrite (Uri address)
434                 {
435                         return OpenWrite (address, (string) null);
436                 }
437
438 #if NET_2_0
439                 public
440 #endif
441                 Stream OpenWrite (Uri address, string method)
442                 {
443 #if NET_2_0
444                         if (address == null)
445                                 throw new ArgumentNullException ("address");
446 #endif
447
448                         try {
449                                 SetBusy ();
450 #if NET_2_0                             
451                                 async = false;
452 #endif                          
453                                 WebRequest request = SetupRequest (address, method, true);
454                                 return request.GetRequestStream ();
455                         } catch (WebException wexc) {
456                                 throw;
457                         } catch (Exception ex) {
458                                 throw new WebException ("An error occurred " +
459                                         "performing a WebClient request.", ex);
460                         } finally {
461                                 is_busy = false;
462                         }
463                 }
464
465                 private string DetermineMethod (Uri address, string method, bool is_upload)
466                 {
467                         if (method != null)
468                                 return method;
469
470 #if NET_2_0
471                         if (address.Scheme == Uri.UriSchemeFtp)
472                                 return (is_upload) ? "STOR" : "RETR";
473 #endif
474                         return (is_upload) ? "POST" : "GET";
475                 }
476
477                 //   UploadData
478
479                 public byte [] UploadData (string address, byte [] data)
480                 {
481 #if NET_2_0
482                         if (address == null)
483                                 throw new ArgumentNullException ("address");
484 #endif
485
486                         return UploadData (CreateUri (address), data);
487                 }
488                 
489                 public byte [] UploadData (string address, string method, byte [] data)
490                 {
491 #if NET_2_0
492                         if (address == null)
493                                 throw new ArgumentNullException ("address");
494 #endif
495
496                         return UploadData (CreateUri (address), method, data);
497                 }
498
499 #if NET_2_0
500                 public
501 #endif
502                 byte [] UploadData (Uri address, byte [] data)
503                 {
504                         return UploadData (address, (string) null, data);
505                 }
506
507 #if NET_2_0
508                 public
509 #endif
510                 byte [] UploadData (Uri address, string method, byte [] data)
511                 {
512 #if NET_2_0
513                         if (address == null)
514                                 throw new ArgumentNullException ("address");
515                         if (data == null)
516                                 throw new ArgumentNullException ("data");
517 #endif
518
519                         try {
520                                 SetBusy ();
521 #if NET_2_0                             
522                                 async = false;
523 #endif                          
524                                 return UploadDataCore (address, method, data, null);
525                         } catch (WebException) {
526                                 throw;
527                         } catch (Exception ex) {
528                                 throw new WebException ("An error occurred " +
529                                         "performing a WebClient request.", ex);
530                         } finally {
531                                 is_busy = false;
532                         }
533                 }
534
535                 byte [] UploadDataCore (Uri address, string method, byte [] data, object userToken)
536                 {
537 #if ONLY_1_1
538                         if (address == null)
539                                 throw new ArgumentNullException ("address");
540                         if (data == null)
541                                 throw new ArgumentNullException ("data");
542 #endif
543
544                         WebRequest request = SetupRequest (address, method, true);
545                         try {
546                                 int contentLength = data.Length;
547                                 request.ContentLength = contentLength;
548                                 using (Stream stream = request.GetRequestStream ()) {
549                                         stream.Write (data, 0, contentLength);
550                                 }
551                                 
552                                 WebResponse response = GetWebResponse (request);
553                                 Stream st = response.GetResponseStream ();
554                                 return ReadAll (st, (int) response.ContentLength, userToken);
555                         } catch (ThreadInterruptedException){
556                                 if (request != null)
557                                         request.Abort ();
558                                 throw;
559                         }
560                 }
561
562                 //   UploadFile
563
564                 public byte [] UploadFile (string address, string fileName)
565                 {
566 #if NET_2_0
567                         if (address == null)
568                                 throw new ArgumentNullException ("address");
569 #endif
570
571                         return UploadFile (CreateUri (address), fileName);
572                 }
573
574 #if NET_2_0
575                 public
576 #endif
577                 byte [] UploadFile (Uri address, string fileName)
578                 {
579                         return UploadFile (address, (string) null, fileName);
580                 }
581                 
582                 public byte [] UploadFile (string address, string method, string fileName)
583                 {
584                         return UploadFile (CreateUri (address), method, fileName);
585                 }
586
587 #if NET_2_0
588                 public
589 #endif
590                 byte [] UploadFile (Uri address, string method, string fileName)
591                 {
592 #if NET_2_0
593                         if (address == null)
594                                 throw new ArgumentNullException ("address");
595                         if (fileName == null)
596                                 throw new ArgumentNullException ("fileName");
597 #endif
598
599                         try {
600                                 SetBusy ();
601 #if NET_2_0                             
602                                 async = false;
603 #endif                          
604                                 return UploadFileCore (address, method, fileName, null);
605                         } catch (WebException wexc) {
606                                 throw;
607                         } catch (Exception ex) {
608                                 throw new WebException ("An error occurred " +
609                                         "performing a WebClient request.", ex);
610                         } finally {
611                                 is_busy = false;
612                         }
613                 }
614
615                 byte [] UploadFileCore (Uri address, string method, string fileName, object userToken)
616                 {
617 #if ONLY_1_1
618                         if (address == null)
619                                 throw new ArgumentNullException ("address");
620 #endif
621
622                         string fileCType = Headers ["Content-Type"];
623                         if (fileCType != null) {
624                                 string lower = fileCType.ToLower ();
625                                 if (lower.StartsWith ("multipart/"))
626                                         throw new WebException ("Content-Type cannot be set to a multipart" +
627                                                                 " type for this request.");
628                         } else {
629                                 fileCType = "application/octet-stream";
630                         }
631
632                         string boundary = "------------" + DateTime.Now.Ticks.ToString ("x");
633                         Headers ["Content-Type"] = String.Format ("multipart/form-data; boundary={0}", boundary);
634                         Stream reqStream = null;
635                         Stream fStream = null;
636                         byte [] resultBytes = null;
637
638                         fileName = Path.GetFullPath (fileName);
639
640                         WebRequest request = null;
641                         try {
642                                 fStream = File.OpenRead (fileName);
643                                 request = SetupRequest (address, method, true);
644                                 reqStream = request.GetRequestStream ();
645                                 byte [] realBoundary = Encoding.ASCII.GetBytes ("--" + boundary + "\r\n");
646                                 reqStream.Write (realBoundary, 0, realBoundary.Length);
647                                 string partHeaders = String.Format ("Content-Disposition: form-data; " +
648                                                                     "name=\"file\"; filename=\"{0}\"\r\n" +
649                                                                     "Content-Type: {1}\r\n\r\n",
650                                                                     Path.GetFileName (fileName), fileCType);
651
652                                 byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders);
653                                 reqStream.Write (partHeadersBytes, 0, partHeadersBytes.Length);
654                                 int nread;
655                                 byte [] buffer = new byte [4096];
656                                 while ((nread = fStream.Read (buffer, 0, 4096)) != 0)
657                                         reqStream.Write (buffer, 0, nread);
658
659                                 reqStream.WriteByte ((byte) '\r');
660                                 reqStream.WriteByte ((byte) '\n');
661                                 reqStream.Write (realBoundary, 0, realBoundary.Length);
662                                 reqStream.Close ();
663                                 reqStream = null;
664                                 WebResponse response = GetWebResponse (request);
665                                 Stream st = response.GetResponseStream ();
666                                 resultBytes = ReadAll (st, (int) response.ContentLength, userToken);
667                         } catch (ThreadInterruptedException){
668                                 if (request != null)
669                                         request.Abort ();
670                                 throw;
671                         } finally {
672                                 if (fStream != null)
673                                         fStream.Close ();
674
675                                 if (reqStream != null)
676                                         reqStream.Close ();
677                         }
678                         
679                         return resultBytes;
680                 }
681                 
682                 public byte[] UploadValues (string address, 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), data);
690                 }
691                 
692                 public byte[] UploadValues (string address, string method, NameValueCollection data)
693                 {
694 #if NET_2_0
695                         if (address == null)
696                                 throw new ArgumentNullException ("address");
697 #endif
698
699                         return UploadValues (CreateUri (address), method, data);
700                 }
701
702 #if NET_2_0
703                 public
704 #endif
705                 byte[] UploadValues (Uri address, NameValueCollection data)
706                 {
707                         return UploadValues (address, (string) null, data);
708                 }
709
710 #if NET_2_0
711                 public
712 #endif
713                 byte[] UploadValues (Uri address, string method, NameValueCollection data)
714                 {
715 #if NET_2_0
716                         if (address == null)
717                                 throw new ArgumentNullException ("address");
718                         if (data == null)
719                                 throw new ArgumentNullException ("data");
720 #endif
721
722                         try {
723                                 SetBusy ();
724 #if NET_2_0                             
725                                 async = false;
726 #endif                          
727                                 return UploadValuesCore (address, method, data, null);
728                         } catch (WebException wexc) {
729                                 throw;
730                         } catch (Exception ex) {
731                                 throw new WebException ("An error occurred " +
732                                         "performing a WebClient request.", ex);
733                         } finally {
734                                 is_busy = false;
735                         }
736                 }
737
738                 byte[] UploadValuesCore (Uri uri, string method, NameValueCollection data, object userToken)
739                 {
740 #if ONLY_1_1
741                         if (data == null)
742                                 throw new ArgumentNullException ("data");
743 #endif
744
745                         string cType = Headers ["Content-Type"];
746                         if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0)
747                                 throw new WebException ("Content-Type header cannot be changed from its default " +
748                                                         "value for this request.");
749
750                         Headers ["Content-Type"] = urlEncodedCType;
751                         WebRequest request = SetupRequest (uri, method, true);
752                         try {
753                                 MemoryStream tmpStream = new MemoryStream ();
754                                 foreach (string key in data) {
755                                         byte [] bytes = Encoding.UTF8.GetBytes (key);
756                                         UrlEncodeAndWrite (tmpStream, bytes);
757                                         tmpStream.WriteByte ((byte) '=');
758                                         bytes = Encoding.UTF8.GetBytes (data [key]);
759                                         UrlEncodeAndWrite (tmpStream, bytes);
760                                         tmpStream.WriteByte ((byte) '&');
761                                 }
762                                 
763                                 int length = (int) tmpStream.Length;
764                                 if (length > 0)
765                                         tmpStream.SetLength (--length); // remove trailing '&'
766                                 
767                                 byte [] buf = tmpStream.GetBuffer ();
768                                 request.ContentLength = length;
769                                 using (Stream rqStream = request.GetRequestStream ()) {
770                                         rqStream.Write (buf, 0, length);
771                                 }
772                                 tmpStream.Close ();
773                                 
774                                 WebResponse response = GetWebResponse (request);
775                                 Stream st = response.GetResponseStream ();
776                                 return ReadAll (st, (int) response.ContentLength, userToken);
777                         } catch (ThreadInterruptedException) {
778                                 request.Abort ();
779                                 throw;
780                         }
781                 }
782
783 #if NET_2_0
784                 public string DownloadString (string address)
785                 {
786                         if (address == null)
787                                 throw new ArgumentNullException ("address");
788
789                         return encoding.GetString (DownloadData (CreateUri (address)));
790                 }
791
792                 public string DownloadString (Uri address)
793                 {
794                         if (address == null)
795                                 throw new ArgumentNullException ("address");
796
797                         return encoding.GetString (DownloadData (CreateUri (address)));
798                 }
799
800                 public string UploadString (string address, string data)
801                 {
802                         if (address == null)
803                                 throw new ArgumentNullException ("address");
804                         if (data == null)
805                                 throw new ArgumentNullException ("data");
806
807                         byte [] resp = UploadData (address, encoding.GetBytes (data));
808                         return encoding.GetString (resp);
809                 }
810
811                 public string UploadString (string address, string method, string data)
812                 {
813                         if (address == null)
814                                 throw new ArgumentNullException ("address");
815                         if (data == null)
816                                 throw new ArgumentNullException ("data");
817
818                         byte [] resp = UploadData (address, method, encoding.GetBytes (data));
819                         return encoding.GetString (resp);
820                 }
821
822                 public string UploadString (Uri address, string data)
823                 {
824                         if (address == null)
825                                 throw new ArgumentNullException ("address");
826                         if (data == null)
827                                 throw new ArgumentNullException ("data");
828
829                         byte [] resp = UploadData (address, encoding.GetBytes (data));
830                         return encoding.GetString (resp);
831                 }
832
833                 public string UploadString (Uri address, string method, string data)
834                 {
835                         if (address == null)
836                                 throw new ArgumentNullException ("address");
837                         if (data == null)
838                                 throw new ArgumentNullException ("data");
839
840                         byte [] resp = UploadData (address, method, encoding.GetBytes (data));
841                         return encoding.GetString (resp);
842                 }
843
844                 public event DownloadDataCompletedEventHandler DownloadDataCompleted;
845                 public event AsyncCompletedEventHandler DownloadFileCompleted;
846                 public event DownloadProgressChangedEventHandler DownloadProgressChanged;
847                 public event DownloadStringCompletedEventHandler DownloadStringCompleted;
848                 public event OpenReadCompletedEventHandler OpenReadCompleted;
849                 public event OpenWriteCompletedEventHandler OpenWriteCompleted;
850                 public event UploadDataCompletedEventHandler UploadDataCompleted;
851                 public event UploadFileCompletedEventHandler UploadFileCompleted;
852                 public event UploadProgressChangedEventHandler UploadProgressChanged;
853                 public event UploadStringCompletedEventHandler UploadStringCompleted;
854                 public event UploadValuesCompletedEventHandler UploadValuesCompleted;
855 #endif
856
857                 Uri CreateUri (string address)
858                 {
859 #if ONLY_1_1
860                         try {
861                                 return MakeUri (address);
862                         } catch (Exception ex) {
863                                 throw new WebException ("An error occurred " +
864                                         "performing a WebClient request.", ex);
865                         }
866 #else
867                         return MakeUri (address);
868 #endif
869                 }
870
871 #if NET_2_0
872                 Uri CreateUri (Uri address)
873                 {
874                         string query = address.Query;
875                         if (String.IsNullOrEmpty (query))
876                                 query = GetQueryString (true);
877
878                         if (baseAddress == null && query == null)
879                                 return address;
880
881                         if (baseAddress == null)
882                                 return new Uri (address.ToString () + query, (query != null));
883
884                         if (query == null)
885                                 return new Uri (baseAddress, address.ToString ());
886
887                         return new Uri (baseAddress, address.ToString () + query, (query != null));
888
889                 }
890 #endif
891
892                 string GetQueryString (bool add_qmark)
893                 {
894                         if (queryString == null || queryString.Count == 0)
895                                 return null;
896
897                         StringBuilder sb = new StringBuilder ();
898                         if (add_qmark)
899                                 sb.Append ('?');
900
901                         foreach (string key in queryString)
902                                 sb.AppendFormat ("{0}={1}&", key, UrlEncode (queryString [key]));
903
904                         if (sb.Length != 0)
905                                 sb.Length--; // removes last '&' or the '?' if empty.
906
907                         if (sb.Length == 0)
908                                 return null;
909
910                         return sb.ToString ();
911                 }
912
913                 Uri MakeUri (string path)
914                 {
915                         string query = GetQueryString (true);
916                         if (baseAddress == null && query == null) {
917                                 try {
918                                         return new Uri (path);
919 #if NET_2_0
920                                 } catch (ArgumentNullException) {
921                                         path = Path.GetFullPath (path);
922                                         return new Uri ("file://" + path);
923 #endif
924                                 } catch (UriFormatException) {
925                                         path = Path.GetFullPath (path);
926                                         return new Uri ("file://" + path);
927                                 }
928                         }
929
930                         if (baseAddress == null)
931                                 return new Uri (path + query, (query != null));
932
933                         if (query == null)
934                                 return new Uri (baseAddress, path);
935
936                         return new Uri (baseAddress, path + query, (query != null));
937                 }
938                 
939                 WebRequest SetupRequest (Uri uri)
940                 {
941                         WebRequest request = WebRequest.Create (uri);
942 #if NET_2_0
943                         if (Proxy != null)
944                                 request.Proxy = Proxy;
945 #endif
946                         request.Credentials = credentials;
947
948                         // Special headers. These are properties of HttpWebRequest.
949                         // What do we do with other requests differnt from HttpWebRequest?
950                         if (headers != null && headers.Count != 0 && (request is HttpWebRequest)) {
951                                 HttpWebRequest req = (HttpWebRequest) request;
952                                 string expect = headers ["Expect"];
953                                 string contentType = headers ["Content-Type"];
954                                 string accept = headers ["Accept"];
955                                 string connection = headers ["Connection"];
956                                 string userAgent = headers ["User-Agent"];
957                                 string referer = headers ["Referer"];
958                                 headers.RemoveInternal ("Expect");
959                                 headers.RemoveInternal ("Content-Type");
960                                 headers.RemoveInternal ("Accept");
961                                 headers.RemoveInternal ("Connection");
962                                 headers.RemoveInternal ("Referer");
963                                 headers.RemoveInternal ("User-Agent");
964                                 request.Headers = headers;
965
966                                 if (expect != null && expect.Length > 0)
967                                         req.Expect = expect;
968
969                                 if (accept != null && accept.Length > 0)
970                                         req.Accept = accept;
971
972                                 if (contentType != null && contentType.Length > 0)
973                                         req.ContentType = contentType;
974
975                                 if (connection != null && connection.Length > 0)
976                                         req.Connection = connection;
977
978                                 if (userAgent != null && userAgent.Length > 0)
979                                         req.UserAgent = userAgent;
980
981                                 if (referer != null && referer.Length > 0)
982                                         req.Referer = referer;
983                         }
984
985                         responseHeaders = null;
986                         return request;
987                 }
988
989                 WebRequest SetupRequest (Uri uri, string method, bool is_upload)
990                 {
991                         WebRequest request = SetupRequest (uri);
992                         request.Method = DetermineMethod (uri, method, is_upload);
993                         return request;
994                 }
995
996                 byte [] ReadAll (Stream stream, int length, object userToken)
997                 {
998                         MemoryStream ms = null;
999                         
1000                         bool nolength = (length == -1);
1001                         int size = ((nolength) ? 8192 : length);
1002                         if (nolength)
1003                                 ms = new MemoryStream ();
1004
1005 //                      long total = 0;
1006                         int nread = 0;
1007                         int offset = 0;
1008                         byte [] buffer = new byte [size];
1009                         while ((nread = stream.Read (buffer, offset, size)) != 0) {
1010                                 if (nolength) {
1011                                         ms.Write (buffer, 0, nread);
1012                                 } else {
1013                                         offset += nread;
1014                                         size -= nread;
1015                                 }
1016 #if NET_2_0
1017                                 if (async){
1018 //                                      total += nread;
1019                                         OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (nread, length, userToken));
1020                                 }
1021 #endif
1022                         }
1023
1024                         if (nolength)
1025                                 return ms.ToArray ();
1026
1027                         return buffer;
1028                 }
1029
1030                 string UrlEncode (string str)
1031                 {
1032                         StringBuilder result = new StringBuilder ();
1033
1034                         int len = str.Length;
1035                         for (int i = 0; i < len; i++) {
1036                                 char c = str [i];
1037                                 if (c == ' ')
1038                                         result.Append ('+');
1039                                 else if ((c < '0' && c != '-' && c != '.') ||
1040                                          (c < 'A' && c > '9') ||
1041                                          (c > 'Z' && c < 'a' && c != '_') ||
1042                                          (c > 'z')) {
1043                                         result.Append ('%');
1044                                         int idx = ((int) c) >> 4;
1045                                         result.Append ((char) hexBytes [idx]);
1046                                         idx = ((int) c) & 0x0F;
1047                                         result.Append ((char) hexBytes [idx]);
1048                                 } else {
1049                                         result.Append (c);
1050                                 }
1051                         }
1052
1053                         return result.ToString ();
1054                 }
1055
1056                 static void UrlEncodeAndWrite (Stream stream, byte [] bytes)
1057                 {
1058                         if (bytes == null)
1059                                 return;
1060
1061                         int len = bytes.Length;
1062                         if (len == 0)
1063                                 return;
1064
1065                         for (int i = 0; i < len; i++) {
1066                                 char c = (char) bytes [i];
1067                                 if (c == ' ')
1068                                         stream.WriteByte ((byte) '+');
1069                                 else if ((c < '0' && c != '-' && c != '.') ||
1070                                          (c < 'A' && c > '9') ||
1071                                          (c > 'Z' && c < 'a' && c != '_') ||
1072                                          (c > 'z')) {
1073                                         stream.WriteByte ((byte) '%');
1074                                         int idx = ((int) c) >> 4;
1075                                         stream.WriteByte (hexBytes [idx]);
1076                                         idx = ((int) c) & 0x0F;
1077                                         stream.WriteByte (hexBytes [idx]);
1078                                 } else {
1079                                         stream.WriteByte ((byte) c);
1080                                 }
1081                         }
1082                 }
1083
1084 #if NET_2_0
1085                 public void CancelAsync ()
1086                 {
1087                         lock (this){
1088                                 if (async_thread == null)
1089                                         return;
1090
1091                                 //
1092                                 // We first flag things as done, in case the Interrupt hangs
1093                                 // or the thread decides to hang in some other way inside the
1094                                 // event handlers, or if we are stuck somewhere else.  This
1095                                 // ensures that the WebClient object is reusable immediately
1096                                 //
1097                                 Thread t = async_thread;
1098                                 CompleteAsync ();
1099                                 t.Interrupt ();
1100                         }
1101                 }
1102
1103                 void CompleteAsync ()
1104                 {
1105                         lock (this){
1106                                 is_busy = false;
1107                                 async_thread = null;
1108                         }
1109                 }
1110
1111                 //    DownloadDataAsync
1112
1113                 public void DownloadDataAsync (Uri address)
1114                 {
1115                         DownloadDataAsync (address, null);
1116                 }
1117
1118                 public void DownloadDataAsync (Uri address, object userToken)
1119                 {
1120                         if (address == null)
1121                                 throw new ArgumentNullException ("address");
1122                         
1123                         lock (this) {
1124                                 SetBusy ();
1125                                 async = true;
1126                                 
1127                                 async_thread = new Thread (delegate (object state) {
1128                                         object [] args = (object []) state;
1129                                         try {
1130                                                 byte [] data = DownloadDataCore ((Uri) args [0], args [1]);
1131                                                 OnDownloadDataCompleted (
1132                                                         new DownloadDataCompletedEventArgs (data, null, false, args [1]));
1133                                         } catch (ThreadInterruptedException){
1134                                                 OnDownloadDataCompleted (
1135                                                         new DownloadDataCompletedEventArgs (null, null, true, args [1]));
1136                                                 throw;
1137                                         } catch (Exception e){
1138                                                 OnDownloadDataCompleted (
1139                                                         new DownloadDataCompletedEventArgs (null, e, false, args [1]));
1140                                         }
1141                                 });
1142                                 object [] cb_args = new object [] {address, userToken};
1143                                 async_thread.Start (cb_args);
1144                         }
1145                 }
1146
1147                 //    DownloadFileAsync
1148
1149                 public void DownloadFileAsync (Uri address, string fileName)
1150                 {
1151                         DownloadFileAsync (address, fileName, null);
1152                 }
1153
1154                 public void DownloadFileAsync (Uri address, string fileName, object userToken)
1155                 {
1156                         if (address == null)
1157                                 throw new ArgumentNullException ("address");
1158                         if (fileName == null)
1159                                 throw new ArgumentNullException ("fileName");
1160                         
1161                         lock (this) {
1162                                 SetBusy ();
1163                                 async = true;
1164
1165                                 async_thread = new Thread (delegate (object state) {
1166                                         object [] args = (object []) state;
1167                                         try {
1168                                                 DownloadFileCore ((Uri) args [0], (string) args [1], args [2]);
1169                                                 OnDownloadFileCompleted (
1170                                                         new AsyncCompletedEventArgs (null, false, args [2]));
1171                                         } catch (ThreadInterruptedException){
1172                                                 OnDownloadFileCompleted (
1173                                                         new AsyncCompletedEventArgs (null, true, args [2]));
1174                                         } catch (Exception e){
1175                                                 OnDownloadFileCompleted (
1176                                                         new AsyncCompletedEventArgs (e, false, args [2]));
1177                                         }});
1178                                 object [] cb_args = new object [] {address, fileName, userToken};
1179                                 async_thread.Start (cb_args);
1180                         }
1181                 }
1182
1183                 //    DownloadStringAsync
1184
1185                 public void DownloadStringAsync (Uri address)
1186                 {
1187                         DownloadStringAsync (address, null);
1188                 }
1189
1190                 public void DownloadStringAsync (Uri address, object userToken)
1191                 {
1192                         if (address == null)
1193                                 throw new ArgumentNullException ("address");
1194                         
1195                         lock (this) {
1196                                 SetBusy ();
1197                                 async = true;
1198
1199                                 async_thread = new Thread (delegate (object state) {
1200                                         object [] args = (object []) state;
1201                                         try {
1202                                                 string data = encoding.GetString (DownloadDataCore ((Uri) args [0], args [1]));
1203                                                 OnDownloadStringCompleted (
1204                                                         new DownloadStringCompletedEventArgs (data, null, false, args [1]));
1205                                         } catch (ThreadInterruptedException){
1206                                                 OnDownloadStringCompleted (
1207                                                         new DownloadStringCompletedEventArgs (null, null, true, args [1]));
1208                                         } catch (Exception e){
1209                                                 OnDownloadStringCompleted (
1210                                                         new DownloadStringCompletedEventArgs (null, e, false, args [1]));
1211                                         }});
1212                                 object [] cb_args = new object [] {address, userToken};
1213                                 async_thread.Start (cb_args);
1214                         }
1215                 }
1216
1217                 //    OpenReadAsync
1218
1219                 public void OpenReadAsync (Uri address)
1220                 {
1221                         OpenReadAsync (address, null);
1222                 }
1223
1224                 public void OpenReadAsync (Uri address, object userToken)
1225                 {
1226                         if (address == null)
1227                                 throw new ArgumentNullException ("address");
1228                         
1229                         lock (this) {
1230                                 SetBusy ();
1231                                 async = true;
1232
1233                                 async_thread = new Thread (delegate (object state) {
1234                                         object [] args = (object []) state;
1235                                         WebRequest request = null;
1236                                         try {
1237                                                 request = SetupRequest ((Uri) args [0]);
1238                                                 WebResponse response = GetWebResponse (request);
1239                                                 Stream stream = response.GetResponseStream ();
1240                                                 OnOpenReadCompleted (
1241                                                         new OpenReadCompletedEventArgs (stream, null, false, args [1]));
1242                                         } catch (ThreadInterruptedException){
1243                                                 if (request != null)
1244                                                         request.Abort ();
1245                                                 
1246                                                 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, null, true, args [1]));
1247                                         } catch (Exception e){
1248                                                 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, e, false, args [1]));
1249                                         } });
1250                                 object [] cb_args = new object [] {address, userToken};
1251                                 async_thread.Start (cb_args);
1252                         }
1253                 }
1254
1255                 //    OpenWriteAsync
1256
1257                 public void OpenWriteAsync (Uri address)
1258                 {
1259                         OpenWriteAsync (address, null);
1260                 }
1261
1262                 public void OpenWriteAsync (Uri address, string method)
1263                 {
1264                         OpenWriteAsync (address, method, null);
1265                 }
1266
1267                 public void OpenWriteAsync (Uri address, string method, object userToken)
1268                 {
1269                         if (address == null)
1270                                 throw new ArgumentNullException ("address");
1271
1272                         lock (this) {
1273                                 SetBusy ();
1274                                 async = true;
1275
1276                                 async_thread = new Thread (delegate (object state) {
1277                                         object [] args = (object []) state;
1278                                         WebRequest request = null;
1279                                         try {
1280                                                 request = SetupRequest ((Uri) args [0], (string) args [1], true);
1281                                                 Stream stream = request.GetRequestStream ();
1282                                                 OnOpenWriteCompleted (
1283                                                         new OpenWriteCompletedEventArgs (stream, null, false, args [2]));
1284                                         } catch (ThreadInterruptedException){
1285                                                 if (request != null)
1286                                                         request.Abort ();
1287                                                 OnOpenWriteCompleted (
1288                                                         new OpenWriteCompletedEventArgs (null, null, true, args [2]));
1289                                         } catch (Exception e){
1290                                                 OnOpenWriteCompleted (
1291                                                         new OpenWriteCompletedEventArgs (null, e, false, args [2]));
1292                                         }});
1293                                 object [] cb_args = new object [] {address, method, userToken};
1294                                 async_thread.Start (cb_args);
1295                         }
1296                 }
1297
1298                 //    UploadDataAsync
1299
1300                 public void UploadDataAsync (Uri address, byte [] data)
1301                 {
1302                         UploadDataAsync (address, null, data);
1303                 }
1304
1305                 public void UploadDataAsync (Uri address, string method, byte [] data)
1306                 {
1307                         UploadDataAsync (address, method, data, null);
1308                 }
1309
1310                 public void UploadDataAsync (Uri address, string method, byte [] data, object userToken)
1311                 {
1312                         if (address == null)
1313                                 throw new ArgumentNullException ("address");
1314                         if (data == null)
1315                                 throw new ArgumentNullException ("data");
1316                         
1317                         lock (this) {
1318                                 SetBusy ();
1319                                 async = true;
1320
1321                                 async_thread = new Thread (delegate (object state) {
1322                                         object [] args = (object []) state;
1323                                         byte [] data2;
1324
1325                                         try {
1326                                                 data2 = UploadDataCore ((Uri) args [0], (string) args [1], (byte []) args [2], args [3]);
1327                                         
1328                                                 OnUploadDataCompleted (
1329                                                         new UploadDataCompletedEventArgs (data2, null, false, args [3]));
1330                                         } catch (ThreadInterruptedException){
1331                                                 OnUploadDataCompleted (
1332                                                         new UploadDataCompletedEventArgs (null, null, true, args [3]));
1333                                         } catch (Exception e){
1334                                                 OnUploadDataCompleted (
1335                                                         new UploadDataCompletedEventArgs (null, e, false, args [3]));
1336                                         }});
1337                                 object [] cb_args = new object [] {address, method, data,  userToken};
1338                                 async_thread.Start (cb_args);
1339                         }
1340                 }
1341
1342                 //    UploadFileAsync
1343
1344                 public void UploadFileAsync (Uri address, string fileName)
1345                 {
1346                         UploadFileAsync (address, null, fileName);
1347                 }
1348
1349                 public void UploadFileAsync (Uri address, string method, string fileName)
1350                 {
1351                         UploadFileAsync (address, method, fileName, null);
1352                 }
1353
1354                 public void UploadFileAsync (Uri address, string method, string fileName, object userToken)
1355                 {
1356                         if (address == null)
1357                                 throw new ArgumentNullException ("address");
1358                         if (fileName == null)
1359                                 throw new ArgumentNullException ("fileName");
1360
1361                         lock (this) {
1362                                 SetBusy ();
1363                                 async = true;
1364
1365                                 async_thread = new Thread (delegate (object state) {
1366                                         object [] args = (object []) state;
1367                                         byte [] data;
1368
1369                                         try {
1370                                                 data = UploadFileCore ((Uri) args [0], (string) args [1], (string) args [2], args [3]);
1371                                                 OnUploadFileCompleted (
1372                                                         new UploadFileCompletedEventArgs (data, null, false, args [3]));
1373                                         } catch (ThreadInterruptedException){
1374                                                 OnUploadFileCompleted (
1375                                                         new UploadFileCompletedEventArgs (null, null, true, args [3]));
1376                                         } catch (Exception e){
1377                                                 OnUploadFileCompleted (
1378                                                         new UploadFileCompletedEventArgs (null, e, false, args [3]));
1379                                         }});
1380                                 object [] cb_args = new object [] {address, method, fileName,  userToken};
1381                                 async_thread.Start (cb_args);
1382                         }
1383                 }
1384
1385                 //    UploadStringAsync
1386
1387                 public void UploadStringAsync (Uri address, string data)
1388                 {
1389                         UploadStringAsync (address, null, data);
1390                 }
1391
1392                 public void UploadStringAsync (Uri address, string method, string data)
1393                 {
1394                         UploadStringAsync (address, method, data, null);
1395                 }
1396
1397                 public void UploadStringAsync (Uri address, string method, string data, object userToken)
1398                 {
1399                         if (address == null)
1400                                 throw new ArgumentNullException ("address");
1401                         if (data == null)
1402                                 throw new ArgumentNullException ("data");
1403                         
1404                         lock (this) {
1405                                 SetBusy ();
1406                                 async = true;
1407                                 
1408                                 async_thread = new Thread (delegate (object state) {
1409                                         object [] args = (object []) state;
1410
1411                                         try {
1412                                                 string data2 = UploadString ((Uri) args [0], (string) args [1], (string) args [2]);
1413                                                 OnUploadStringCompleted (
1414                                                         new UploadStringCompletedEventArgs (data2, null, false, args [3]));
1415                                         } catch (ThreadInterruptedException){
1416                                                 OnUploadStringCompleted (
1417                                                         new UploadStringCompletedEventArgs (null, null, true, args [3]));
1418                                         } catch (Exception e){
1419                                                 OnUploadStringCompleted (
1420                                                         new UploadStringCompletedEventArgs (null, e, false, args [3]));
1421                                         }});
1422                                 object [] cb_args = new object [] {address, method, data, userToken};
1423                                 async_thread.Start (cb_args);
1424                         }
1425                 }
1426
1427                 //    UploadValuesAsync
1428
1429                 public void UploadValuesAsync (Uri address, NameValueCollection values)
1430                 {
1431                         UploadValuesAsync (address, null, values);
1432                 }
1433
1434                 public void UploadValuesAsync (Uri address, string method, NameValueCollection values)
1435                 {
1436                         UploadValuesAsync (address, method, values, null);
1437                 }
1438
1439                 public void UploadValuesAsync (Uri address, string method, NameValueCollection values, object userToken)
1440                 {
1441                         if (address == null)
1442                                 throw new ArgumentNullException ("address");
1443                         if (values == null)
1444                                 throw new ArgumentNullException ("values");
1445
1446                         lock (this) {
1447                                 CheckBusy ();
1448                                 async = true;
1449
1450                                 async_thread = new Thread (delegate (object state) {
1451                                         object [] args = (object []) state;
1452                                         try {
1453                                                 byte [] data = UploadValuesCore ((Uri) args [0], (string) args [1], (NameValueCollection) args [2], args [3]);
1454                                                 OnUploadValuesCompleted (
1455                                                         new UploadValuesCompletedEventArgs (data, null, false, args [3]));
1456                                         } catch (ThreadInterruptedException){
1457                                                 OnUploadValuesCompleted (
1458                                                         new UploadValuesCompletedEventArgs (null, null, true, args [3]));
1459                                         } catch (Exception e){
1460                                                 OnUploadValuesCompleted (
1461                                                         new UploadValuesCompletedEventArgs (null, e, false, args [3]));
1462                                         }});
1463                                 object [] cb_args = new object [] {address, method, values,  userToken};
1464                                 async_thread.Start (cb_args);
1465                         }
1466                 }
1467
1468                 protected virtual void OnDownloadDataCompleted (DownloadDataCompletedEventArgs args)
1469                 {
1470                         CompleteAsync ();
1471                         if (DownloadDataCompleted != null)
1472                                 DownloadDataCompleted (this, args);
1473                 }
1474
1475                 protected virtual void OnDownloadFileCompleted (AsyncCompletedEventArgs args)
1476                 {
1477                         CompleteAsync ();
1478                         if (DownloadFileCompleted != null)
1479                                 DownloadFileCompleted (this, args);
1480                 }
1481
1482                 protected virtual void OnDownloadProgressChanged (DownloadProgressChangedEventArgs e)
1483                 {
1484                         if (DownloadProgressChanged != null)
1485                                 DownloadProgressChanged (this, e);
1486                 }
1487
1488                 protected virtual void OnDownloadStringCompleted (DownloadStringCompletedEventArgs args)
1489                 {
1490                         CompleteAsync ();
1491                         if (DownloadStringCompleted != null)
1492                                 DownloadStringCompleted (this, args);
1493                 }
1494
1495                 protected virtual void OnOpenReadCompleted (OpenReadCompletedEventArgs args)
1496                 {
1497                         CompleteAsync ();
1498                         if (OpenReadCompleted != null)
1499                                 OpenReadCompleted (this, args);
1500                 }
1501
1502                 protected virtual void OnOpenWriteCompleted (OpenWriteCompletedEventArgs args)
1503                 {
1504                         CompleteAsync ();
1505                         if (OpenWriteCompleted != null)
1506                                 OpenWriteCompleted (this, args);
1507                 }
1508
1509                 protected virtual void OnUploadDataCompleted (UploadDataCompletedEventArgs args)
1510                 {
1511                         CompleteAsync ();
1512                         if (UploadDataCompleted != null)
1513                                 UploadDataCompleted (this, args);
1514                 }
1515
1516                 protected virtual void OnUploadFileCompleted (UploadFileCompletedEventArgs args)
1517                 {
1518                         CompleteAsync ();
1519                         if (UploadFileCompleted != null)
1520                                 UploadFileCompleted (this, args);
1521                 }
1522
1523                 protected virtual void OnUploadProgressChanged (UploadProgressChangedEventArgs e)
1524                 {
1525                         if (UploadProgressChanged != null)
1526                                 UploadProgressChanged (this, e);
1527                 }
1528
1529                 protected virtual void OnUploadStringCompleted (UploadStringCompletedEventArgs args)
1530                 {
1531                         CompleteAsync ();
1532                         if (UploadStringCompleted != null)
1533                                 UploadStringCompleted (this, args);
1534                 }
1535
1536                 protected virtual void OnUploadValuesCompleted (UploadValuesCompletedEventArgs args)
1537                 {
1538                         CompleteAsync ();
1539                         if (UploadValuesCompleted != null)
1540                                 UploadValuesCompleted (this, args);
1541                 }
1542
1543                 protected virtual WebResponse GetWebResponse (WebRequest request, IAsyncResult result)
1544                 {
1545                         WebResponse response = request.EndGetResponse (result);
1546                         responseHeaders = response.Headers;
1547                         return response;
1548                 }
1549 #endif
1550
1551 #if NET_2_0
1552                 protected virtual
1553 #endif
1554                 WebRequest GetWebRequest (Uri address)
1555                 {
1556                         return SetupRequest (address);
1557                 }
1558
1559 #if NET_2_0
1560                 protected virtual
1561 #endif
1562                 WebResponse GetWebResponse (WebRequest request)
1563                 {
1564                         WebResponse response = request.GetResponse ();
1565                         responseHeaders = response.Headers;
1566                         return response;
1567                 }
1568
1569         }
1570 }
1571