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