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