2 // System.Net.WebClient
5 // Lawrence Pit (loz@cable.a2000.nl)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Atsushi Enomoto (atsushi@ximian.com)
8 // Miguel de Icaza (miguel@ximian.com)
9 // Martin Baulig (martin.baulig@googlemail.com)
10 // Marek Safar (marek.safar@gmail.com)
12 // Copyright 2003 Ximian, Inc. (http://www.ximian.com)
13 // Copyright 2006, 2010 Novell, Inc. (http://www.novell.com)
14 // Copyright 2012 Xamarin Inc. (http://www.xamarin.com)
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 // Notes on CancelAsync and Async methods:
39 // WebClient.CancelAsync is implemented by calling Thread.Interrupt
40 // in our helper thread. The various async methods have to cancel
41 // any ongoing requests by calling request.Abort () at that point.
42 // In a few places (UploadDataCore, UploadValuesCore,
43 // UploadFileCore) we catch the ThreadInterruptedException and
44 // abort the request there.
46 // Higher level routines (the async callbacks) also need to catch
47 // the exception and raise the OnXXXXCompleted events there with
48 // the "canceled" flag set to true.
50 // In a few other places where these helper routines are not used
51 // (OpenReadAsync for example) catching the ThreadAbortException
52 // also must abort the request.
54 // The Async methods currently differ in their implementation from
55 // the .NET implementation in that we manually catch any other
56 // exceptions and correctly raise the OnXXXXCompleted passing the
57 // Exception that caused the problem. The .NET implementation
58 // does not seem to have a mechanism to flag errors that happen
59 // during downloads though. We do this because we still need to
60 // catch the exception on these helper threads, or we would
61 // otherwise kill the application (on the 2.x profile, uncaught
62 // exceptions in threads terminate the application).
65 using System.Collections.Specialized;
66 using System.ComponentModel;
68 using System.Runtime.InteropServices;
69 using System.Runtime.Serialization;
71 using System.Threading;
72 using System.Net.Cache;
74 using System.Threading.Tasks;
80 public class WebClient : Component
82 int socketBufferSize = 4096;
83 static readonly string urlEncodedCType = "application/x-www-form-urlencoded";
84 static byte [] hexBytes;
85 ICredentials credentials;
86 WebHeaderCollection headers;
87 WebHeaderCollection responseHeaders;
90 NameValueCollection queryString;
93 bool proxySet = false;
95 Encoding encoding = Encoding.Default;
97 // RequestCachePolicy cache_policy;
99 CancellationTokenSource cts;
105 hexBytes = new byte [16];
107 for (int i = '0'; i <= '9'; i++, index++)
108 hexBytes [index] = (byte) i;
110 for (int i = 'a'; i <= 'f'; i++, index++)
111 hexBytes [index] = (byte) i;
120 public string BaseAddress {
122 if (baseString == null) {
123 if (baseAddress == null)
127 baseString = baseAddress.ToString ();
132 if (value == null || value.Length == 0) {
135 baseAddress = new Uri (value);
140 static Exception GetMustImplement ()
142 return new NotImplementedException ();
145 [MonoTODO ("Value can be set but is currently ignored")]
146 public RequestCachePolicy CachePolicy
149 throw GetMustImplement ();
151 set { /*cache_policy = value;*/ }
154 [MonoTODO ("Value can be set but is ignored")]
155 public bool UseDefaultCredentials
158 throw GetMustImplement ();
161 // This makes no sense in mono
165 public ICredentials Credentials {
166 get { return credentials; }
167 set { credentials = value; }
170 public WebHeaderCollection Headers {
173 headers = new WebHeaderCollection ();
177 set { headers = value; }
180 public NameValueCollection QueryString {
182 if (queryString == null)
183 queryString = new NameValueCollection ();
187 set { queryString = value; }
190 public WebHeaderCollection ResponseHeaders {
191 get { return responseHeaders; }
194 public Encoding Encoding {
195 get { return encoding; }
198 throw new ArgumentNullException ("Encoding");
203 public IWebProxy Proxy {
206 return WebRequest.DefaultWebProxy;
219 return is_busy || (cts != null);
230 throw new NotSupportedException ("WebClient does not support concurrent I/O operations.");
243 public byte [] DownloadData (string address)
246 throw new ArgumentNullException ("address");
248 return DownloadData (CreateUri (address));
251 public byte [] DownloadData (Uri address)
254 throw new ArgumentNullException ("address");
259 return DownloadDataCore (address, null);
265 byte [] DownloadDataCore (Uri address, object userToken)
267 WebRequest request = null;
270 request = SetupRequest (address);
271 return ReadAll (request, userToken);
272 } catch (ThreadInterruptedException){
275 throw new WebException ("User canceled the request", WebExceptionStatus.RequestCanceled);
276 } catch (WebException) {
278 } catch (Exception ex) {
279 throw new WebException ("An error occurred performing a WebClient request.", ex);
285 public void DownloadFile (string address, string fileName)
288 throw new ArgumentNullException ("address");
290 DownloadFile (CreateUri (address), fileName);
293 public void DownloadFile (Uri address, string fileName)
296 throw new ArgumentNullException ("address");
297 if (fileName == null)
298 throw new ArgumentNullException ("fileName");
303 DownloadFileCore (address, fileName, null);
304 } catch (WebException) {
306 } catch (Exception ex) {
307 throw new WebException ("An error occurred " +
308 "performing a WebClient request.", ex);
314 void DownloadFileCore (Uri address, string fileName, object userToken)
316 WebRequest request = null;
318 using (FileStream f = new FileStream (fileName, FileMode.Create)) {
320 request = SetupRequest (address);
321 WebResponse response = GetWebResponse (request);
322 Stream st = response.GetResponseStream ();
324 int cLength = (int) response.ContentLength;
325 int length = (cLength <= -1 || cLength > 32*1024) ? 32*1024 : cLength;
326 byte [] buffer = new byte [length];
329 long notify_total = 0;
330 while ((nread = st.Read (buffer, 0, length)) != 0) {
331 notify_total += nread;
333 OnDownloadProgressChanged (
334 new DownloadProgressChangedEventArgs (notify_total, response.ContentLength, userToken));
335 f.Write (buffer, 0, nread);
338 if (cLength > 0 && notify_total < cLength)
339 throw new WebException ("Download aborted prematurely.", WebExceptionStatus.ReceiveFailure);
340 } catch (ThreadInterruptedException){
350 public Stream OpenRead (string address)
353 throw new ArgumentNullException ("address");
354 return OpenRead (CreateUri (address));
357 public Stream OpenRead (Uri address)
360 throw new ArgumentNullException ("address");
362 WebRequest request = null;
366 request = SetupRequest (address);
367 WebResponse response = GetWebResponse (request);
368 return response.GetResponseStream ();
369 } catch (WebException) {
371 } catch (Exception ex) {
372 throw new WebException ("An error occurred " +
373 "performing a WebClient request.", ex);
381 public Stream OpenWrite (string address)
384 throw new ArgumentNullException ("address");
386 return OpenWrite (CreateUri (address));
389 public Stream OpenWrite (string address, string method)
392 throw new ArgumentNullException ("address");
394 return OpenWrite (CreateUri (address), method);
397 public Stream OpenWrite (Uri address)
399 return OpenWrite (address, (string) null);
402 public Stream OpenWrite (Uri address, string method)
405 throw new ArgumentNullException ("address");
410 WebRequest request = SetupRequest (address, method, true);
411 return OpenWriteStream (request);
412 } catch (WebException) {
414 } catch (Exception ex) {
415 throw new WebException ("An error occurred " +
416 "performing a WebClient request.", ex);
422 Stream OpenWriteStream (WebRequest request)
424 var stream = request.GetRequestStream ();
425 var wcs = stream as WebConnectionStream;
427 wcs.GetResponseOnClose = true;
431 private string DetermineMethod (Uri address, string method, bool is_upload)
436 if (address.Scheme == Uri.UriSchemeFtp)
437 return (is_upload) ? "STOR" : "RETR";
439 return (is_upload) ? "POST" : "GET";
444 public byte [] UploadData (string address, byte [] data)
447 throw new ArgumentNullException ("address");
449 return UploadData (CreateUri (address), data);
452 public byte [] UploadData (string address, string method, byte [] data)
455 throw new ArgumentNullException ("address");
457 return UploadData (CreateUri (address), method, data);
460 public byte [] UploadData (Uri address, byte [] data)
462 return UploadData (address, (string) null, data);
465 public byte [] UploadData (Uri address, string method, byte [] data)
468 throw new ArgumentNullException ("address");
470 throw new ArgumentNullException ("data");
475 return UploadDataCore (address, method, data, null);
476 } catch (WebException) {
478 } catch (Exception ex) {
479 throw new WebException ("An error occurred " +
480 "performing a WebClient request.", ex);
486 byte [] UploadDataCore (Uri address, string method, byte [] data, object userToken)
488 WebRequest request = SetupRequest (address, method, true);
490 int contentLength = data.Length;
491 request.ContentLength = contentLength;
492 using (Stream stream = request.GetRequestStream ()) {
494 while (offset < contentLength) {
495 var size = Math.Min (contentLength - offset, socketBufferSize);
496 stream.Write (data, offset, size);
500 if (contentLength > 0)
501 percent = (int) ((long)offset * 100 / contentLength);
502 var args = new UploadProgressChangedEventArgs (0, 0, offset, contentLength, percent, userToken);
503 OnUploadProgressChanged (args);
507 return ReadAll (request, userToken);
508 } catch (ThreadInterruptedException){
517 public byte [] UploadFile (string address, string fileName)
520 throw new ArgumentNullException ("address");
522 return UploadFile (CreateUri (address), fileName);
525 public byte [] UploadFile (Uri address, string fileName)
527 return UploadFile (address, (string) null, fileName);
530 public byte [] UploadFile (string address, string method, string fileName)
532 return UploadFile (CreateUri (address), method, fileName);
535 public byte [] UploadFile (Uri address, string method, string fileName)
538 throw new ArgumentNullException ("address");
539 if (fileName == null)
540 throw new ArgumentNullException ("fileName");
545 return UploadFileCore (address, method, fileName, null);
546 } catch (WebException) {
548 } catch (Exception ex) {
549 throw new WebException ("An error occurred " +
550 "performing a WebClient request.", ex);
556 byte [] UploadFileCore (Uri address, string method, string fileName, object userToken)
558 string fileCType = Headers ["Content-Type"];
559 if (fileCType != null) {
560 string lower = fileCType.ToLower ();
561 if (lower.StartsWith ("multipart/"))
562 throw new WebException ("Content-Type cannot be set to a multipart" +
563 " type for this request.");
565 fileCType = "application/octet-stream";
568 bool needs_boundary = (method != "PUT"); // only verified case so far
569 string boundary = null;
570 if (needs_boundary) {
571 boundary = "------------" + DateTime.Now.Ticks.ToString ("x");
572 Headers ["Content-Type"] = String.Format ("multipart/form-data; boundary={0}", boundary);
574 Stream reqStream = null;
575 Stream fStream = null;
576 byte [] resultBytes = null;
578 fileName = Path.GetFullPath (fileName);
580 WebRequest request = null;
582 fStream = File.OpenRead (fileName);
583 request = SetupRequest (address, method, true);
584 reqStream = request.GetRequestStream ();
585 byte [] bytes_boundary = null;
586 if (needs_boundary) {
587 bytes_boundary = Encoding.ASCII.GetBytes (boundary);
588 reqStream.WriteByte ((byte) '-');
589 reqStream.WriteByte ((byte) '-');
590 reqStream.Write (bytes_boundary, 0, bytes_boundary.Length);
591 reqStream.WriteByte ((byte) '\r');
592 reqStream.WriteByte ((byte) '\n');
593 string partHeaders = String.Format ("Content-Disposition: form-data; " +
594 "name=\"file\"; filename=\"{0}\"\r\n" +
595 "Content-Type: {1}\r\n\r\n",
596 Path.GetFileName (fileName), fileCType);
598 byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders);
599 reqStream.Write (partHeadersBytes, 0, partHeadersBytes.Length);
604 long step = 16384; // every 16kB
605 if (fStream.CanSeek) {
606 file_size = fStream.Length;
607 step = file_size / 100;
609 var upload_args = new UploadProgressChangedEventArgs (0, 0, bytes_sent, file_size, 0, userToken);
610 OnUploadProgressChanged (upload_args);
611 byte [] buffer = new byte [4096];
613 while ((nread = fStream.Read (buffer, 0, 4096)) > 0) {
614 reqStream.Write (buffer, 0, nread);
617 if (sum >= step || nread < 4096) {
620 percent = (int) (bytes_sent * 100 / file_size);
621 upload_args = new UploadProgressChangedEventArgs (0, 0, bytes_sent, file_size, percent, userToken);
622 OnUploadProgressChanged (upload_args);
627 if (needs_boundary) {
628 reqStream.WriteByte ((byte) '\r');
629 reqStream.WriteByte ((byte) '\n');
630 reqStream.WriteByte ((byte) '-');
631 reqStream.WriteByte ((byte) '-');
632 reqStream.Write (bytes_boundary, 0, bytes_boundary.Length);
633 reqStream.WriteByte ((byte) '-');
634 reqStream.WriteByte ((byte) '-');
635 reqStream.WriteByte ((byte) '\r');
636 reqStream.WriteByte ((byte) '\n');
640 resultBytes = ReadAll (request, userToken);
641 } catch (ThreadInterruptedException){
649 if (reqStream != null)
656 public byte[] UploadValues (string address, NameValueCollection data)
659 throw new ArgumentNullException ("address");
661 return UploadValues (CreateUri (address), data);
664 public byte[] UploadValues (string address, string method, NameValueCollection data)
667 throw new ArgumentNullException ("address");
668 return UploadValues (CreateUri (address), method, data);
671 public byte[] UploadValues (Uri address, NameValueCollection data)
673 return UploadValues (address, (string) null, data);
676 public byte[] UploadValues (Uri address, string method, NameValueCollection data)
679 throw new ArgumentNullException ("address");
681 throw new ArgumentNullException ("data");
686 return UploadValuesCore (address, method, data, null);
687 } catch (WebException) {
689 } catch (Exception ex) {
690 throw new WebException ("An error occurred " +
691 "performing a WebClient request.", ex);
697 byte[] UploadValuesCore (Uri uri, string method, NameValueCollection data, object userToken)
699 string cType = Headers ["Content-Type"];
700 if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0)
701 throw new WebException ("Content-Type header cannot be changed from its default " +
702 "value for this request.");
704 Headers ["Content-Type"] = urlEncodedCType;
705 WebRequest request = SetupRequest (uri, method, true);
707 MemoryStream tmpStream = new MemoryStream ();
708 foreach (string key in data) {
709 byte [] bytes = Encoding.UTF8.GetBytes (key);
710 UrlEncodeAndWrite (tmpStream, bytes);
711 tmpStream.WriteByte ((byte) '=');
712 bytes = Encoding.UTF8.GetBytes (data [key]);
713 UrlEncodeAndWrite (tmpStream, bytes);
714 tmpStream.WriteByte ((byte) '&');
717 int length = (int) tmpStream.Length;
719 tmpStream.SetLength (--length); // remove trailing '&'
721 byte [] buf = tmpStream.GetBuffer ();
722 request.ContentLength = length;
723 using (Stream rqStream = request.GetRequestStream ()) {
724 rqStream.Write (buf, 0, length);
728 return ReadAll (request, userToken);
729 } catch (ThreadInterruptedException) {
735 public string DownloadString (string address)
738 throw new ArgumentNullException ("address");
740 return ConvertDataToString (DownloadData (CreateUri (address)));
743 public string DownloadString (Uri address)
746 throw new ArgumentNullException ("address");
748 return ConvertDataToString (DownloadData (CreateUri (address)));
751 string ConvertDataToString (byte[] data)
753 int preambleLength = 0;
754 var enc = GetEncodingFromBuffer (data, data.Length, ref preambleLength) ?? encoding;
755 return enc.GetString (data, preambleLength, data.Length - preambleLength);
758 internal static Encoding GetEncodingFromBuffer (byte[] buffer, int length, ref int preambleLength)
760 var encodings_with_preamble = new [] { Encoding.UTF8, Encoding.UTF32, Encoding.Unicode };
761 foreach (var enc in encodings_with_preamble) {
762 if ((preambleLength = StartsWith (buffer, length, enc.GetPreamble ())) > 0)
769 static int StartsWith (byte[] array, int length, byte[] value)
771 if (length < value.Length)
774 for (int i = 0; i < value.Length; ++i) {
775 if (array [i] != value [i])
782 public string UploadString (string address, string data)
785 throw new ArgumentNullException ("address");
787 throw new ArgumentNullException ("data");
789 byte [] resp = UploadData (address, encoding.GetBytes (data));
790 return encoding.GetString (resp);
793 public string UploadString (string address, string method, string data)
796 throw new ArgumentNullException ("address");
798 throw new ArgumentNullException ("data");
800 byte [] resp = UploadData (address, method, encoding.GetBytes (data));
801 return encoding.GetString (resp);
804 public string UploadString (Uri address, string data)
807 throw new ArgumentNullException ("address");
809 throw new ArgumentNullException ("data");
811 byte [] resp = UploadData (address, encoding.GetBytes (data));
812 return encoding.GetString (resp);
815 public string UploadString (Uri address, string method, string data)
818 throw new ArgumentNullException ("address");
820 throw new ArgumentNullException ("data");
822 byte [] resp = UploadData (address, method, encoding.GetBytes (data));
823 return encoding.GetString (resp);
826 public event DownloadDataCompletedEventHandler DownloadDataCompleted;
827 public event AsyncCompletedEventHandler DownloadFileCompleted;
828 public event DownloadProgressChangedEventHandler DownloadProgressChanged;
829 public event DownloadStringCompletedEventHandler DownloadStringCompleted;
830 public event OpenReadCompletedEventHandler OpenReadCompleted;
831 public event OpenWriteCompletedEventHandler OpenWriteCompleted;
832 public event UploadDataCompletedEventHandler UploadDataCompleted;
833 public event UploadFileCompletedEventHandler UploadFileCompleted;
834 public event UploadProgressChangedEventHandler UploadProgressChanged;
835 public event UploadStringCompletedEventHandler UploadStringCompleted;
836 public event UploadValuesCompletedEventHandler UploadValuesCompleted;
838 Uri CreateUri (string address)
842 if (baseAddress == null)
843 uri = new Uri (address);
845 uri = new Uri (baseAddress, address);
846 return CreateUri (uri);
849 return new Uri (Path.GetFullPath (address));
852 Uri CreateUri (Uri address)
854 Uri result = address;
855 if (baseAddress != null && !result.IsAbsoluteUri) {
857 result = new Uri (baseAddress, result.OriginalString);
859 return result; // Not much we can do here.
863 string query = result.Query;
864 if (String.IsNullOrEmpty (query))
865 query = GetQueryString (true);
866 UriBuilder builder = new UriBuilder (address);
867 if (!String.IsNullOrEmpty (query))
868 builder.Query = query.Substring (1);
872 string GetQueryString (bool add_qmark)
874 if (queryString == null || queryString.Count == 0)
877 StringBuilder sb = new StringBuilder ();
881 foreach (string key in queryString)
882 sb.AppendFormat ("{0}={1}&", key, UrlEncode (queryString [key]));
885 sb.Length--; // removes last '&' or the '?' if empty.
890 return sb.ToString ();
893 WebRequest SetupRequest (Uri uri)
895 WebRequest request = GetWebRequest (uri);
897 request.Proxy = Proxy;
898 if (credentials != null)
899 request.Credentials = credentials;
900 else if (!String.IsNullOrEmpty (uri.UserInfo)) {
901 // Perhaps this should be done by the underlying URI handler?
902 ICredentials creds = GetCredentials (uri.UserInfo);
904 request.Credentials = creds;
907 // Special headers. These are properties of HttpWebRequest.
908 // What do we do with other requests differnt from HttpWebRequest?
909 if (headers != null && headers.Count != 0 && (request is HttpWebRequest)) {
910 HttpWebRequest req = (HttpWebRequest) request;
911 string expect = headers ["Expect"];
912 string contentType = headers ["Content-Type"];
913 string accept = headers ["Accept"];
914 string connection = headers ["Connection"];
915 string userAgent = headers ["User-Agent"];
916 string referer = headers ["Referer"];
917 headers.RemoveInternal ("Expect");
918 headers.RemoveInternal ("Content-Type");
919 headers.RemoveInternal ("Accept");
920 headers.RemoveInternal ("Connection");
921 headers.RemoveInternal ("Referer");
922 headers.RemoveInternal ("User-Agent");
923 request.Headers = headers;
925 if (expect != null && expect.Length > 0)
928 if (accept != null && accept.Length > 0)
931 if (contentType != null && contentType.Length > 0)
932 req.ContentType = contentType;
934 if (connection != null && connection.Length > 0)
935 req.Connection = connection;
937 if (userAgent != null && userAgent.Length > 0)
938 req.UserAgent = userAgent;
940 if (referer != null && referer.Length > 0)
941 req.Referer = referer;
944 responseHeaders = null;
948 WebRequest SetupRequest (Uri uri, string method, bool is_upload)
950 WebRequest request = SetupRequest (uri);
951 request.Method = DetermineMethod (uri, method, is_upload);
955 static NetworkCredential GetCredentials (string user_info)
957 string [] creds = user_info.Split (':');
958 if (creds.Length != 2)
961 if (creds [0].IndexOf ('\\') != -1) {
962 string [] user = creds [0].Split ('\\');
963 if (user.Length != 2)
965 return new NetworkCredential (user [1], creds [1], user [0]);
967 return new NetworkCredential (creds [0], creds [1]);
970 byte [] ReadAll (WebRequest request, object userToken)
972 WebResponse response = GetWebResponse (request);
973 Stream stream = response.GetResponseStream ();
974 int length = (int) response.ContentLength;
975 HttpWebRequest wreq = request as HttpWebRequest;
977 if (length > -1 && wreq != null && (int) wreq.AutomaticDecompression != 0) {
978 string content_encoding = ((HttpWebResponse) response).ContentEncoding;
979 if (((content_encoding == "gzip" && (wreq.AutomaticDecompression & DecompressionMethods.GZip) != 0)) ||
980 ((content_encoding == "deflate" && (wreq.AutomaticDecompression & DecompressionMethods.Deflate) != 0)))
984 MemoryStream ms = null;
985 bool nolength = (length == -1);
986 int size = ((nolength) ? 8192 : length);
988 ms = new MemoryStream ();
993 byte [] buffer = new byte [size];
994 while ((nread = stream.Read (buffer, offset, size)) != 0) {
996 ms.Write (buffer, 0, nread);
1003 OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (total, length, userToken));
1008 return ms.ToArray ();
1013 string UrlEncode (string str)
1015 StringBuilder result = new StringBuilder ();
1017 int len = str.Length;
1018 for (int i = 0; i < len; i++) {
1021 result.Append ('+');
1022 else if ((c < '0' && c != '-' && c != '.') ||
1023 (c < 'A' && c > '9') ||
1024 (c > 'Z' && c < 'a' && c != '_') ||
1026 result.Append ('%');
1027 int idx = ((int) c) >> 4;
1028 result.Append ((char) hexBytes [idx]);
1029 idx = ((int) c) & 0x0F;
1030 result.Append ((char) hexBytes [idx]);
1036 return result.ToString ();
1039 static void UrlEncodeAndWrite (Stream stream, byte [] bytes)
1044 int len = bytes.Length;
1048 for (int i = 0; i < len; i++) {
1049 char c = (char) bytes [i];
1051 stream.WriteByte ((byte) '+');
1052 else if ((c < '0' && c != '-' && c != '.') ||
1053 (c < 'A' && c > '9') ||
1054 (c > 'Z' && c < 'a' && c != '_') ||
1056 stream.WriteByte ((byte) '%');
1057 int idx = ((int) c) >> 4;
1058 stream.WriteByte (hexBytes [idx]);
1059 idx = ((int) c) & 0x0F;
1060 stream.WriteByte (hexBytes [idx]);
1062 stream.WriteByte ((byte) c);
1067 public void CancelAsync ()
1077 if (async_thread == null)
1081 // We first flag things as done, in case the Interrupt hangs
1082 // or the thread decides to hang in some other way inside the
1083 // event handlers, or if we are stuck somewhere else. This
1084 // ensures that the WebClient object is reusable immediately
1086 Thread t = async_thread;
1092 void CompleteAsync ()
1096 async_thread = null;
1105 // DownloadDataAsync
1107 public void DownloadDataAsync (Uri address)
1109 DownloadDataAsync (address, null);
1112 public void DownloadDataAsync (Uri address, object userToken)
1114 if (address == null)
1115 throw new ArgumentNullException ("address");
1121 async_thread = new Thread (delegate (object state) {
1122 object [] args = (object []) state;
1124 byte [] data = DownloadDataCore ((Uri) args [0], args [1]);
1125 OnDownloadDataCompleted (
1126 new DownloadDataCompletedEventArgs (data, null, false, args [1]));
1127 } catch (Exception e){
1128 bool canceled = false;
1129 WebException we = e as WebException;
1131 canceled = we.Status == WebExceptionStatus.RequestCanceled;
1132 OnDownloadDataCompleted (
1133 new DownloadDataCompletedEventArgs (null, e, canceled, args [1]));
1136 object [] cb_args = new object [] { CreateUri (address), userToken };
1137 async_thread.IsBackground = true;
1138 async_thread.Start (cb_args);
1142 // DownloadFileAsync
1144 public void DownloadFileAsync (Uri address, string fileName)
1146 DownloadFileAsync (address, fileName, null);
1149 public void DownloadFileAsync (Uri address, string fileName, object userToken)
1151 if (address == null)
1152 throw new ArgumentNullException ("address");
1153 if (fileName == null)
1154 throw new ArgumentNullException ("fileName");
1160 async_thread = new Thread (delegate (object state) {
1161 object [] args = (object []) state;
1163 DownloadFileCore ((Uri) args [0], (string) args [1], args [2]);
1164 OnDownloadFileCompleted (
1165 new AsyncCompletedEventArgs (null, false, args [2]));
1166 } catch (ThreadInterruptedException){
1167 OnDownloadFileCompleted (
1168 new AsyncCompletedEventArgs (null, true, args [2]));
1169 } catch (Exception e){
1170 OnDownloadFileCompleted (
1171 new AsyncCompletedEventArgs (e, false, args [2]));
1173 object [] cb_args = new object [] { CreateUri (address), fileName, userToken };
1174 async_thread.IsBackground = true;
1175 async_thread.Start (cb_args);
1179 // DownloadStringAsync
1181 public void DownloadStringAsync (Uri address)
1183 DownloadStringAsync (address, null);
1186 public void DownloadStringAsync (Uri address, object userToken)
1188 if (address == null)
1189 throw new ArgumentNullException ("address");
1195 async_thread = new Thread (delegate (object state) {
1196 object [] args = (object []) state;
1198 string data = ConvertDataToString (DownloadDataCore ((Uri) args [0], args [1]));
1199 OnDownloadStringCompleted (
1200 new DownloadStringCompletedEventArgs (data, null, false, args [1]));
1201 } catch (Exception e){
1202 bool canceled = false;
1203 WebException we = e as WebException;
1205 canceled = we.Status == WebExceptionStatus.RequestCanceled;
1206 OnDownloadStringCompleted (
1207 new DownloadStringCompletedEventArgs (null, e, canceled, args [1]));
1209 object [] cb_args = new object [] { CreateUri (address), userToken };
1210 async_thread.IsBackground = true;
1211 async_thread.Start (cb_args);
1217 public void OpenReadAsync (Uri address)
1219 OpenReadAsync (address, null);
1222 public void OpenReadAsync (Uri address, object userToken)
1224 if (address == null)
1225 throw new ArgumentNullException ("address");
1231 async_thread = new Thread (delegate (object state) {
1232 object [] args = (object []) state;
1233 WebRequest request = null;
1235 request = SetupRequest ((Uri) args [0]);
1236 WebResponse response = GetWebResponse (request);
1237 Stream stream = response.GetResponseStream ();
1238 OnOpenReadCompleted (
1239 new OpenReadCompletedEventArgs (stream, null, false, args [1]));
1240 } catch (ThreadInterruptedException){
1241 if (request != null)
1244 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, null, true, args [1]));
1245 } catch (Exception e){
1246 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, e, false, args [1]));
1248 object [] cb_args = new object [] { CreateUri (address), userToken };
1249 async_thread.IsBackground = true;
1250 async_thread.Start (cb_args);
1256 public void OpenWriteAsync (Uri address)
1258 OpenWriteAsync (address, null);
1261 public void OpenWriteAsync (Uri address, string method)
1263 OpenWriteAsync (address, method, null);
1266 public void OpenWriteAsync (Uri address, string method, object userToken)
1268 if (address == null)
1269 throw new ArgumentNullException ("address");
1275 async_thread = new Thread (delegate (object state) {
1276 object [] args = (object []) state;
1277 WebRequest request = null;
1279 request = SetupRequest ((Uri) args [0], (string) args [1], true);
1280 var stream = OpenWriteStream (request);
1281 OnOpenWriteCompleted (
1282 new OpenWriteCompletedEventArgs (stream, null, false, args [2]));
1283 } catch (ThreadInterruptedException){
1284 if (request != null)
1286 OnOpenWriteCompleted (
1287 new OpenWriteCompletedEventArgs (null, null, true, args [2]));
1288 } catch (Exception e){
1289 OnOpenWriteCompleted (
1290 new OpenWriteCompletedEventArgs (null, e, false, args [2]));
1292 object [] cb_args = new object [] { CreateUri (address), method, userToken };
1293 async_thread.IsBackground = true;
1294 async_thread.Start (cb_args);
1300 public void UploadDataAsync (Uri address, byte [] data)
1302 UploadDataAsync (address, null, data);
1305 public void UploadDataAsync (Uri address, string method, byte [] data)
1307 UploadDataAsync (address, method, data, null);
1310 public void UploadDataAsync (Uri address, string method, byte [] data, object userToken)
1312 if (address == null)
1313 throw new ArgumentNullException ("address");
1315 throw new ArgumentNullException ("data");
1321 async_thread = new Thread (delegate (object state) {
1322 object [] args = (object []) state;
1326 data2 = UploadDataCore ((Uri) args [0], (string) args [1], (byte []) args [2], args [3]);
1328 OnUploadDataCompleted (
1329 new UploadDataCompletedEventArgs (data2, null, false, args [3]));
1330 } catch (ThreadInterruptedException){
1331 OnUploadDataCompleted (
1332 new UploadDataCompletedEventArgs (null, null, true, args [3]));
1333 } catch (Exception e){
1334 OnUploadDataCompleted (
1335 new UploadDataCompletedEventArgs (null, e, false, args [3]));
1337 object [] cb_args = new object [] { CreateUri (address), method, data, userToken };
1338 async_thread.IsBackground = true;
1339 async_thread.Start (cb_args);
1345 public void UploadFileAsync (Uri address, string fileName)
1347 UploadFileAsync (address, null, fileName);
1350 public void UploadFileAsync (Uri address, string method, string fileName)
1352 UploadFileAsync (address, method, fileName, null);
1355 public void UploadFileAsync (Uri address, string method, string fileName, object userToken)
1357 if (address == null)
1358 throw new ArgumentNullException ("address");
1359 if (fileName == null)
1360 throw new ArgumentNullException ("fileName");
1366 async_thread = new Thread (delegate (object state) {
1367 object [] args = (object []) state;
1371 data = UploadFileCore ((Uri) args [0], (string) args [1], (string) args [2], args [3]);
1372 OnUploadFileCompleted (
1373 new UploadFileCompletedEventArgs (data, null, false, args [3]));
1374 } catch (ThreadInterruptedException){
1375 OnUploadFileCompleted (
1376 new UploadFileCompletedEventArgs (null, null, true, args [3]));
1377 } catch (Exception e){
1378 OnUploadFileCompleted (
1379 new UploadFileCompletedEventArgs (null, e, false, args [3]));
1381 object [] cb_args = new object [] { CreateUri (address), method, fileName, userToken };
1382 async_thread.IsBackground = true;
1383 async_thread.Start (cb_args);
1387 // UploadStringAsync
1389 public void UploadStringAsync (Uri address, string data)
1391 UploadStringAsync (address, null, data);
1394 public void UploadStringAsync (Uri address, string method, string data)
1396 UploadStringAsync (address, method, data, null);
1399 public void UploadStringAsync (Uri address, string method, string data, object userToken)
1401 if (address == null)
1402 throw new ArgumentNullException ("address");
1404 throw new ArgumentNullException ("data");
1410 async_thread = new Thread (delegate (object state) {
1411 object [] args = (object []) state;
1414 string data2 = UploadString ((Uri) args [0], (string) args [1], (string) args [2]);
1415 OnUploadStringCompleted (
1416 new UploadStringCompletedEventArgs (data2, null, false, args [3]));
1417 } catch (Exception e){
1418 if (e is ThreadInterruptedException || e.InnerException is ThreadInterruptedException) {
1419 OnUploadStringCompleted (
1420 new UploadStringCompletedEventArgs (null, null, true, args [3]));
1423 OnUploadStringCompleted (
1424 new UploadStringCompletedEventArgs (null, e, false, args [3]));
1426 object [] cb_args = new object [] { CreateUri (address), method, data, userToken };
1427 async_thread.IsBackground = true;
1428 async_thread.Start (cb_args);
1432 // UploadValuesAsync
1434 public void UploadValuesAsync (Uri address, NameValueCollection data)
1436 UploadValuesAsync (address, null, data);
1439 public void UploadValuesAsync (Uri address, string method, NameValueCollection data)
1441 UploadValuesAsync (address, method, data, null);
1444 public void UploadValuesAsync (Uri address, string method, NameValueCollection data, object userToken)
1446 if (address == null)
1447 throw new ArgumentNullException ("address");
1449 throw new ArgumentNullException ("data");
1455 async_thread = new Thread (delegate (object state) {
1456 object [] args = (object []) state;
1458 byte [] values = UploadValuesCore ((Uri) args [0], (string) args [1], (NameValueCollection) args [2], args [3]);
1459 OnUploadValuesCompleted (
1460 new UploadValuesCompletedEventArgs (values, null, false, args [3]));
1461 } catch (ThreadInterruptedException){
1462 OnUploadValuesCompleted (
1463 new UploadValuesCompletedEventArgs (null, null, true, args [3]));
1464 } catch (Exception e){
1465 OnUploadValuesCompleted (
1466 new UploadValuesCompletedEventArgs (null, e, false, args [3]));
1468 object [] cb_args = new object [] { CreateUri (address), method, data, userToken };
1469 async_thread.IsBackground = true;
1470 async_thread.Start (cb_args);
1474 protected virtual void OnDownloadDataCompleted (DownloadDataCompletedEventArgs e)
1477 if (DownloadDataCompleted != null)
1478 DownloadDataCompleted (this, e);
1481 protected virtual void OnDownloadFileCompleted (AsyncCompletedEventArgs e)
1484 if (DownloadFileCompleted != null)
1485 DownloadFileCompleted (this, e);
1488 protected virtual void OnDownloadProgressChanged (DownloadProgressChangedEventArgs e)
1490 if (DownloadProgressChanged != null)
1491 DownloadProgressChanged (this, e);
1494 protected virtual void OnDownloadStringCompleted (DownloadStringCompletedEventArgs e)
1497 if (DownloadStringCompleted != null)
1498 DownloadStringCompleted (this, e);
1501 protected virtual void OnOpenReadCompleted (OpenReadCompletedEventArgs e)
1504 if (OpenReadCompleted != null)
1505 OpenReadCompleted (this, e);
1508 protected virtual void OnOpenWriteCompleted (OpenWriteCompletedEventArgs e)
1511 if (OpenWriteCompleted != null)
1512 OpenWriteCompleted (this, e);
1515 protected virtual void OnUploadDataCompleted (UploadDataCompletedEventArgs e)
1518 if (UploadDataCompleted != null)
1519 UploadDataCompleted (this, e);
1522 protected virtual void OnUploadFileCompleted (UploadFileCompletedEventArgs e)
1525 if (UploadFileCompleted != null)
1526 UploadFileCompleted (this, e);
1529 protected virtual void OnUploadProgressChanged (UploadProgressChangedEventArgs e)
1531 if (UploadProgressChanged != null)
1532 UploadProgressChanged (this, e);
1535 protected virtual void OnUploadStringCompleted (UploadStringCompletedEventArgs e)
1538 if (UploadStringCompleted != null)
1539 UploadStringCompleted (this, e);
1542 protected virtual void OnUploadValuesCompleted (UploadValuesCompletedEventArgs e)
1545 if (UploadValuesCompleted != null)
1546 UploadValuesCompleted (this, e);
1549 protected virtual WebResponse GetWebResponse (WebRequest request, IAsyncResult result)
1551 WebResponse response = request.EndGetResponse (result);
1552 responseHeaders = response.Headers;
1556 protected virtual WebRequest GetWebRequest (Uri address)
1558 return WebRequest.Create (address);
1561 protected virtual WebResponse GetWebResponse (WebRequest request)
1563 WebResponse response = request.GetResponse ();
1564 responseHeaders = response.Headers;
1570 // DownloadDataTaskAsync
1572 public Task<byte[]> DownloadDataTaskAsync (string address)
1574 return DownloadDataTaskAsync (CreateUri (address));
1577 public async Task<byte[]> DownloadDataTaskAsync (Uri address)
1579 WebRequest request = null;
1580 WebResponse response = null;
1583 cts = new CancellationTokenSource ();
1584 request = await SetupRequestAsync (address);
1585 response = await GetWebResponseTaskAsync (request, cts.Token);
1586 var result = await ReadAllTaskAsync (request, response, cts.Token);
1588 // Has to run on original context
1589 OnDownloadDataCompleted (new DownloadDataCompletedEventArgs (result, null, false, null));
1591 } catch (WebException ex) {
1592 OnDownloadDataCompleted (new DownloadDataCompletedEventArgs (null, ex, false, null));
1594 } catch (OperationCanceledException) {
1595 if (request != null)
1597 OnDownloadDataCompleted (new DownloadDataCompletedEventArgs (null, null, true, null));
1599 } catch (Exception ex) {
1600 OnDownloadDataCompleted (new DownloadDataCompletedEventArgs (null, ex, true, null));
1601 throw new WebException ("An error occurred performing a WebClient request.", ex);
1603 if (response != null)
1608 Task<WebRequest> SetupRequestAsync (Uri address)
1610 return Task.Factory.StartNew (() => SetupRequest (address));
1613 async Task<WebRequest> SetupRequestAsync (Uri address, string method, bool is_upload)
1615 WebRequest request = await SetupRequestAsync (address).ConfigureAwait (false);
1616 request.Method = DetermineMethod (address, method, is_upload);
1620 async Task<WebResponse> GetWebResponseTaskAsync (WebRequest request, CancellationToken token)
1622 token.ThrowIfCancellationRequested ();
1623 WebResponse response = await request.GetResponseAsync ().ConfigureAwait (false);
1624 token.ThrowIfCancellationRequested ();
1625 responseHeaders = response.Headers;
1629 async Task<byte[]> ReadAllTaskAsync (WebRequest request, WebResponse response, CancellationToken token)
1631 Stream stream = response.GetResponseStream ();
1632 int length = (int)response.ContentLength;
1633 HttpWebRequest wreq = request as HttpWebRequest;
1635 if (length > -1 && wreq != null && (int)wreq.AutomaticDecompression != 0) {
1636 string content_encoding = ((HttpWebResponse)response).ContentEncoding;
1637 if (((content_encoding == "gzip" && (wreq.AutomaticDecompression & DecompressionMethods.GZip) != 0)) ||
1638 ((content_encoding == "deflate" && (wreq.AutomaticDecompression & DecompressionMethods.Deflate) != 0)))
1642 MemoryStream ms = null;
1643 bool nolength = (length == -1);
1644 int size = ((nolength) ? 8192 : length);
1646 ms = new MemoryStream ();
1651 byte [] buffer = new byte [size];
1652 token.ThrowIfCancellationRequested ();
1653 while ((nread = await stream.ReadAsync (buffer, offset, size, token)) != 0) {
1655 ms.Write (buffer, 0, nread);
1661 OnDownloadProgressChanged (new DownloadProgressChangedEventArgs (total, length, null));
1662 token.ThrowIfCancellationRequested ();
1665 return nolength ? ms.ToArray () : buffer;
1668 // DownloadFileTaskAsync
1670 public Task DownloadFileTaskAsync (string address, string fileName)
1672 if (address == null)
1673 throw new ArgumentNullException ("address");
1675 return DownloadFileTaskAsync (CreateUri (address), fileName);
1678 public async Task DownloadFileTaskAsync (Uri address, string fileName)
1680 if (address == null)
1681 throw new ArgumentNullException ("address");
1682 if (fileName == null)
1683 throw new ArgumentNullException ("fileName");
1685 WebRequest request = null;
1686 WebResponse response = null;
1690 cts = new CancellationTokenSource ();
1691 request = await SetupRequestAsync (address);
1692 response = await GetWebResponseTaskAsync (request, cts.Token);
1693 await DownloadFileTaskAsyncCore (request, response, fileName, cts.Token);
1694 OnDownloadFileCompleted (new AsyncCompletedEventArgs (null, false, null));
1695 } catch (WebException ex) {
1696 OnDownloadFileCompleted (new AsyncCompletedEventArgs (ex, false, null));
1698 } catch (OperationCanceledException) {
1699 if (request != null)
1701 OnDownloadFileCompleted (new AsyncCompletedEventArgs (null, true, null));
1703 } catch (Exception ex) {
1704 OnDownloadFileCompleted (new AsyncCompletedEventArgs (ex, false, null));
1705 throw new WebException ("An error occurred " +
1706 "performing a WebClient request.", ex);
1708 if (response != null)
1713 async Task DownloadFileTaskAsyncCore (WebRequest request, WebResponse response,
1714 string fileName, CancellationToken token)
1716 using (FileStream f = new FileStream (fileName, FileMode.Create)) {
1717 Stream st = response.GetResponseStream ();
1719 int cLength = (int)response.ContentLength;
1720 int length = (cLength <= -1 || cLength > 32 * 1024) ? 32 * 1024 : cLength;
1721 byte [] buffer = new byte [length];
1724 long notify_total = 0;
1725 token.ThrowIfCancellationRequested ();
1726 while ((nread = await st.ReadAsync (buffer, 0, length, token)) != 0) {
1727 notify_total += nread;
1728 OnDownloadProgressChanged (
1729 new DownloadProgressChangedEventArgs (notify_total, response.ContentLength, null));
1730 token.ThrowIfCancellationRequested ();
1731 await f.WriteAsync (buffer, 0, nread, token);
1732 token.ThrowIfCancellationRequested ();
1737 // OpenReadTaskAsync
1739 public Task<Stream> OpenReadTaskAsync (string address)
1741 if (address == null)
1742 throw new ArgumentNullException ("address");
1743 return OpenReadTaskAsync (CreateUri (address));
1746 public async Task<Stream> OpenReadTaskAsync (Uri address)
1748 if (address == null)
1749 throw new ArgumentNullException ("address");
1751 WebRequest request = null;
1754 cts = new CancellationTokenSource ();
1755 request = await SetupRequestAsync (address);
1756 WebResponse response = await GetWebResponseTaskAsync (request, cts.Token);
1757 var result = response.GetResponseStream ();
1758 cts.Token.ThrowIfCancellationRequested ();
1759 OnOpenReadCompleted (new OpenReadCompletedEventArgs (result, null, false, null));
1761 } catch (WebException ex) {
1762 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, ex, false, null));
1764 } catch (OperationCanceledException) {
1765 if (request != null)
1767 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, null, true, null));
1769 } catch (Exception ex) {
1770 OnOpenReadCompleted (new OpenReadCompletedEventArgs (null, ex, false, null));
1771 throw new WebException ("An error occurred " +
1772 "performing a WebClient request.", ex);
1776 // DownloadStringTaskAsync
1778 public Task<string> DownloadStringTaskAsync (string address)
1780 if (address == null)
1781 throw new ArgumentNullException ("address");
1783 return DownloadStringTaskAsync (CreateUri (address));
1786 public async Task<string> DownloadStringTaskAsync (Uri address)
1788 if (address == null)
1789 throw new ArgumentNullException ("address");
1791 WebRequest request = null;
1792 WebResponse response = null;
1796 cts = new CancellationTokenSource ();
1797 request = await SetupRequestAsync (address);
1798 response = await GetWebResponseTaskAsync (request, cts.Token);
1799 var data = await ReadAllTaskAsync (request, response, cts.Token);
1800 cts.Token.ThrowIfCancellationRequested ();
1801 var text = ConvertDataToString (data);
1802 OnDownloadStringCompleted (new DownloadStringCompletedEventArgs (text, null, false, null));
1804 } catch (WebException ex) {
1805 OnDownloadStringCompleted (new DownloadStringCompletedEventArgs (null, ex, false, null));
1807 } catch (OperationCanceledException) {
1808 if (request != null)
1810 OnDownloadStringCompleted (new DownloadStringCompletedEventArgs (null, null, true, null));
1812 } catch (Exception ex) {
1813 OnDownloadStringCompleted (new DownloadStringCompletedEventArgs (null, ex, true, null));
1814 throw new WebException ("An error occurred performing a WebClient request.", ex);
1816 if (response != null)
1821 // OpenWriteTaskAsync
1823 public Task<Stream> OpenWriteTaskAsync (string address)
1825 if (address == null)
1826 throw new ArgumentNullException ("address");
1828 return OpenWriteTaskAsync (CreateUri (address));
1831 public Task<Stream> OpenWriteTaskAsync (string address, string method)
1833 if (address == null)
1834 throw new ArgumentNullException ("address");
1836 return OpenWriteTaskAsync (CreateUri (address), method);
1839 public Task<Stream> OpenWriteTaskAsync (Uri address)
1841 return OpenWriteTaskAsync (address, (string) null);
1844 public async Task<Stream> OpenWriteTaskAsync (Uri address, string method)
1846 if (address == null)
1847 throw new ArgumentNullException ("address");
1849 WebRequest request = null;
1852 cts = new CancellationTokenSource ();
1853 request = await SetupRequestAsync (address, method, true).ConfigureAwait (false);
1854 var stream = await request.GetRequestStreamAsync ();
1855 var wcs = stream as WebConnectionStream;
1857 wcs.GetResponseOnClose = true;
1859 } catch (WebException) {
1861 } catch (OperationCanceledException) {
1862 if (request != null)
1865 } catch (Exception ex) {
1866 throw new WebException ("An error occurred " +
1867 "performing a WebClient request.", ex);
1873 // UploadDataTaskAsync
1875 public Task<byte[]> UploadDataTaskAsync (string address, byte [] data)
1877 if (address == null)
1878 throw new ArgumentNullException ("address");
1880 return UploadDataTaskAsync (CreateUri (address), data);
1883 public Task<byte[]> UploadDataTaskAsync (string address, string method, byte [] data)
1885 if (address == null)
1886 throw new ArgumentNullException ("address");
1888 return UploadDataTaskAsync (CreateUri (address), method, data);
1891 public Task<byte[]> UploadDataTaskAsync (Uri address, byte [] data)
1893 return UploadDataTaskAsync (address, (string) null, data);
1896 public async Task<byte[]> UploadDataTaskAsync (Uri address, string method, byte [] data)
1898 if (address == null)
1899 throw new ArgumentNullException ("address");
1901 throw new ArgumentNullException ("data");
1903 WebRequest request = null;
1906 cts = new CancellationTokenSource ();
1907 request = await SetupRequestAsync (address, method, true).ConfigureAwait (false);
1908 var result = await UploadDataTaskAsyncCore (request, data, cts.Token).ConfigureAwait (false);
1909 OnUploadDataCompleted (new UploadDataCompletedEventArgs (result, null, false, null));
1911 } catch (WebException ex) {
1912 OnUploadDataCompleted (new UploadDataCompletedEventArgs (null, ex, false, null));
1914 } catch (OperationCanceledException) {
1915 if (request != null)
1917 OnUploadDataCompleted (new UploadDataCompletedEventArgs (null, null, true, null));
1919 } catch (Exception ex) {
1920 OnUploadDataCompleted (new UploadDataCompletedEventArgs (null, ex, true, null));
1921 throw new WebException ("An error occurred performing a WebClient request.", ex);
1925 async Task<byte[]> UploadDataTaskAsyncCore (WebRequest request, byte[] data, CancellationToken token)
1927 token.ThrowIfCancellationRequested ();
1929 int contentLength = data.Length;
1930 request.ContentLength = contentLength;
1931 using (Stream stream = await request.GetRequestStreamAsync ().ConfigureAwait (false)) {
1932 token.ThrowIfCancellationRequested ();
1933 await stream.WriteAsync (data, 0, contentLength, token).ConfigureAwait (false);
1934 token.ThrowIfCancellationRequested ();
1937 WebResponse response = null;
1940 response = await GetWebResponseTaskAsync (request, token).ConfigureAwait (false);
1941 return await ReadAllTaskAsync (request, response, token).ConfigureAwait (false);
1943 if (response != null)
1948 // UploadFileTaskAsync
1950 public Task<byte[]> UploadFileTaskAsync (string address, string fileName)
1952 if (address == null)
1953 throw new ArgumentNullException ("address");
1955 return UploadFileTaskAsync (CreateUri (address), fileName);
1958 public Task<byte[]> UploadFileTaskAsync (Uri address, string fileName)
1960 return UploadFileTaskAsync (address, (string) null, fileName);
1963 public Task<byte[]> UploadFileTaskAsync (string address, string method, string fileName)
1965 return UploadFileTaskAsync (CreateUri (address), method, fileName);
1968 public async Task<byte[]> UploadFileTaskAsync (Uri address, string method, string fileName)
1970 if (address == null)
1971 throw new ArgumentNullException ("address");
1972 if (fileName == null)
1973 throw new ArgumentNullException ("fileName");
1977 cts = new CancellationTokenSource ();
1979 var result = await UploadFileTaskAsyncCore (address, method, fileName, cts.Token).ConfigureAwait (false);
1980 OnUploadFileCompleted (new UploadFileCompletedEventArgs (result, null, false, null));
1982 } catch (WebException ex) {
1983 OnUploadFileCompleted (new UploadFileCompletedEventArgs (null, ex, false, null));
1985 } catch (OperationCanceledException) {
1986 OnUploadFileCompleted (new UploadFileCompletedEventArgs (null, null, true, null));
1988 } catch (Exception ex) {
1989 OnUploadFileCompleted (new UploadFileCompletedEventArgs (null, ex, true, null));
1990 throw new WebException ("An error occurred performing a WebClient request.", ex);
1994 async Task<byte[]> UploadFileTaskAsyncCore (Uri address, string method, string fileName, CancellationToken token)
1996 token.ThrowIfCancellationRequested ();
1998 string fileCType = Headers ["Content-Type"];
1999 if (fileCType != null) {
2000 string lower = fileCType.ToLower ();
2001 if (lower.StartsWith ("multipart/"))
2002 throw new WebException ("Content-Type cannot be set to a multipart" +
2003 " type for this request.");
2005 fileCType = "application/octet-stream";
2008 bool needs_boundary = (method != "PUT"); // only verified case so far
2009 string boundary = null;
2010 if (needs_boundary) {
2011 boundary = "------------" + DateTime.Now.Ticks.ToString ("x");
2012 Headers ["Content-Type"] = String.Format ("multipart/form-data; boundary={0}", boundary);
2014 Stream reqStream = null;
2015 Stream fStream = null;
2016 WebResponse response = null;
2017 WebRequest request = null;
2019 fileName = Path.GetFullPath (fileName);
2022 request = await SetupRequestAsync (address, method, true).ConfigureAwait (false);
2023 } catch (OperationCanceledException) {
2027 fStream = File.OpenRead (fileName);
2028 token.ThrowIfCancellationRequested ();
2029 reqStream = await request.GetRequestStreamAsync ().ConfigureAwait (false);
2030 token.ThrowIfCancellationRequested ();
2031 byte [] bytes_boundary = null;
2032 if (needs_boundary) {
2033 bytes_boundary = Encoding.ASCII.GetBytes (boundary);
2034 using (MemoryStream ms = new MemoryStream ()) {
2035 ms.WriteByte ((byte) '-');
2036 ms.WriteByte ((byte) '-');
2037 ms.Write (bytes_boundary, 0, bytes_boundary.Length);
2038 ms.WriteByte ((byte) '\r');
2039 ms.WriteByte ((byte) '\n');
2040 string partHeaders = String.Format (
2041 "Content-Disposition: form-data; " +
2042 "name=\"file\"; filename=\"{0}\"\r\n" +
2043 "Content-Type: {1}\r\n\r\n",
2044 Path.GetFileName (fileName), fileCType);
2045 byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders);
2046 ms.Write (partHeadersBytes, 0, partHeadersBytes.Length);
2047 var msLength = (int)ms.Position;
2048 ms.Seek (0, SeekOrigin.Begin);
2049 await ms.CopyToAsync (reqStream, msLength, token).ConfigureAwait (false);
2053 long bytes_sent = 0;
2054 long file_size = -1;
2055 long step = 16384; // every 16kB
2056 if (fStream.CanSeek) {
2057 file_size = fStream.Length;
2058 step = file_size / 100;
2060 var upload_args = new UploadProgressChangedEventArgs (0, 0, bytes_sent, file_size, 0, null);
2061 OnUploadProgressChanged (upload_args);
2062 byte [] buffer = new byte [4096];
2064 token.ThrowIfCancellationRequested ();
2065 while ((nread = await fStream.ReadAsync (buffer, 0, 4096, token).ConfigureAwait (false)) > 0) {
2066 token.ThrowIfCancellationRequested ();
2067 await reqStream.WriteAsync (buffer, 0, nread, token).ConfigureAwait (false);
2068 bytes_sent += nread;
2070 if (sum >= step || nread < 4096) {
2073 percent = (int) (bytes_sent * 100 / file_size);
2074 upload_args = new UploadProgressChangedEventArgs (0, 0, bytes_sent, file_size, percent, null);
2075 OnUploadProgressChanged (upload_args);
2080 if (needs_boundary) {
2081 using (MemoryStream ms = new MemoryStream ()) {
2082 ms.WriteByte ((byte) '\r');
2083 ms.WriteByte ((byte) '\n');
2084 ms.WriteByte ((byte) '-');
2085 ms.WriteByte ((byte) '-');
2086 ms.Write (bytes_boundary, 0, bytes_boundary.Length);
2087 ms.WriteByte ((byte) '-');
2088 ms.WriteByte ((byte) '-');
2089 ms.WriteByte ((byte) '\r');
2090 ms.WriteByte ((byte) '\n');
2091 var msLength = (int)ms.Position;
2092 ms.Seek (0, SeekOrigin.Begin);
2093 await ms.CopyToAsync (reqStream, msLength, token).ConfigureAwait (false);
2099 response = await GetWebResponseTaskAsync (request, token).ConfigureAwait (false);
2100 return await ReadAllTaskAsync (request, response, token).ConfigureAwait (false);
2102 if (fStream != null)
2105 if (reqStream != null)
2108 if (response != null)
2113 // UploadStringTaskAsync
2115 public Task<string> UploadStringTaskAsync (string address, string data)
2117 if (address == null)
2118 throw new ArgumentNullException ("address");
2120 throw new ArgumentNullException ("data");
2122 return UploadStringTaskAsync (CreateUri (address), null, data);
2125 public Task<string> UploadStringTaskAsync (string address, string method, string data)
2127 if (address == null)
2128 throw new ArgumentNullException ("address");
2130 throw new ArgumentNullException ("data");
2132 return UploadStringTaskAsync (CreateUri (address), method, data);
2135 public Task<string> UploadStringTaskAsync (Uri address, string data)
2137 if (address == null)
2138 throw new ArgumentNullException ("address");
2140 throw new ArgumentNullException ("data");
2142 return UploadStringTaskAsync (address, null, data);
2145 public async Task<string> UploadStringTaskAsync (Uri address, string method, string data)
2147 if (address == null)
2148 throw new ArgumentNullException ("address");
2150 throw new ArgumentNullException ("data");
2152 WebRequest request = null;
2155 cts = new CancellationTokenSource ();
2156 request = await SetupRequestAsync (address, method, true).ConfigureAwait (false);
2157 var result = await UploadDataTaskAsyncCore (request, encoding.GetBytes (data), cts.Token).ConfigureAwait (false);
2158 var result_str = encoding.GetString (result);
2159 OnUploadStringCompleted (new UploadStringCompletedEventArgs (result_str, null, false, null));
2161 } catch (WebException ex) {
2162 OnUploadStringCompleted (new UploadStringCompletedEventArgs (null, ex, false, null));
2164 } catch (OperationCanceledException) {
2165 if (request != null)
2167 OnUploadStringCompleted (new UploadStringCompletedEventArgs (null, null, true, null));
2169 } catch (Exception ex) {
2170 OnUploadStringCompleted (new UploadStringCompletedEventArgs (null, ex, true, null));
2171 throw new WebException ("An error occurred performing a WebClient request.", ex);
2175 // UploadValuesTaskAsync
2177 public Task<byte[]> UploadValuesTaskAsync (string address, NameValueCollection data)
2179 if (address == null)
2180 throw new ArgumentNullException ("address");
2182 return UploadValuesTaskAsync (CreateUri (address), data);
2185 public Task<byte[]> UploadValuesTaskAsync (string address, string method, NameValueCollection data)
2187 if (address == null)
2188 throw new ArgumentNullException ("address");
2190 return UploadValuesTaskAsync (CreateUri (address), method, data);
2193 public Task<byte[]> UploadValuesTaskAsync (Uri address, NameValueCollection data)
2195 return UploadValuesTaskAsync (address, (string) null, data);
2198 public async Task<byte[]> UploadValuesTaskAsync (Uri address, string method, NameValueCollection data)
2200 if (address == null)
2201 throw new ArgumentNullException ("address");
2203 throw new ArgumentNullException ("data");
2205 string cType = Headers ["Content-Type"];
2206 if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0)
2207 throw new WebException ("Content-Type header cannot be changed from its default " +
2208 "value for this request.");
2209 Headers ["Content-Type"] = urlEncodedCType;
2211 WebRequest request = null;
2214 cts = new CancellationTokenSource ();
2215 request = await SetupRequestAsync (address, method, true).ConfigureAwait (false);
2216 var result = await UploadValuesTaskAsyncCore (request, data, cts.Token).ConfigureAwait (false);
2217 OnUploadValuesCompleted (new UploadValuesCompletedEventArgs (result, null, false, null));
2219 } catch (WebException ex) {
2220 OnUploadValuesCompleted (new UploadValuesCompletedEventArgs (null, ex, false, null));
2222 } catch (OperationCanceledException) {
2223 if (request != null)
2225 OnUploadValuesCompleted (new UploadValuesCompletedEventArgs (null, null, true, null));
2227 } catch (Exception ex) {
2228 OnUploadValuesCompleted (new UploadValuesCompletedEventArgs (null, ex, true, null));
2229 throw new WebException ("An error occurred performing a WebClient request.", ex);
2233 async Task<byte[]> UploadValuesTaskAsyncCore (WebRequest request, NameValueCollection data,
2234 CancellationToken token)
2236 token.ThrowIfCancellationRequested ();
2238 WebResponse response = null;
2240 MemoryStream tmpStream = new MemoryStream ();
2241 foreach (string key in data) {
2242 byte [] bytes = Encoding.UTF8.GetBytes (key);
2243 UrlEncodeAndWrite (tmpStream, bytes);
2244 tmpStream.WriteByte ((byte) '=');
2245 bytes = Encoding.UTF8.GetBytes (data [key]);
2246 UrlEncodeAndWrite (tmpStream, bytes);
2247 tmpStream.WriteByte ((byte) '&');
2250 token.ThrowIfCancellationRequested ();
2252 int length = (int) tmpStream.Length;
2254 tmpStream.SetLength (--length); // remove trailing '&'
2256 byte [] buf = tmpStream.GetBuffer ();
2257 request.ContentLength = length;
2258 using (Stream rqStream = await request.GetRequestStreamAsync ().ConfigureAwait (false)) {
2259 await rqStream.WriteAsync (buf, 0, length, token).ConfigureAwait (false);
2263 response = await GetWebResponseTaskAsync (request, token).ConfigureAwait (false);
2264 return await ReadAllTaskAsync (request, response, token).ConfigureAwait (false);
2266 if (response != null)