WebClient.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. //
  2. // System.Net.WebClient
  3. //
  4. // Authors:
  5. // Lawrence Pit ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. // Atsushi Enomoto ([email protected])
  8. //
  9. // (c) 2003 Ximian, Inc. (http://www.ximian.com)
  10. // (C) 2006 Novell, Inc. (http://www.novell.com)
  11. //
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining
  14. // a copy of this software and associated documentation files (the
  15. // "Software"), to deal in the Software without restriction, including
  16. // without limitation the rights to use, copy, modify, merge, publish,
  17. // distribute, sublicense, and/or sell copies of the Software, and to
  18. // permit persons to whom the Software is furnished to do so, subject to
  19. // the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  28. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  29. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. //
  32. using System;
  33. using System.Collections.Specialized;
  34. using System.ComponentModel;
  35. using System.IO;
  36. using System.Runtime.InteropServices;
  37. using System.Runtime.Serialization;
  38. using System.Text;
  39. #if NET_2_0
  40. using System.Collections.Generic;
  41. using System.Threading;
  42. #endif
  43. namespace System.Net
  44. {
  45. [ComVisible(true)]
  46. public
  47. #if !NET_2_0
  48. sealed
  49. #endif
  50. class WebClient : Component
  51. {
  52. static readonly string urlEncodedCType = "application/x-www-form-urlencoded";
  53. static byte [] hexBytes;
  54. ICredentials credentials;
  55. WebHeaderCollection headers;
  56. WebHeaderCollection responseHeaders;
  57. Uri baseAddress;
  58. string baseString;
  59. NameValueCollection queryString;
  60. bool isBusy;
  61. #if NET_2_0
  62. Encoding encoding = Encoding.Default;
  63. IWebProxy proxy;
  64. #endif
  65. // Constructors
  66. static WebClient ()
  67. {
  68. hexBytes = new byte [16];
  69. int index = 0;
  70. for (int i = '0'; i <= '9'; i++, index++)
  71. hexBytes [index] = (byte) i;
  72. for (int i = 'A'; i <= 'F'; i++, index++)
  73. hexBytes [index] = (byte) i;
  74. }
  75. public WebClient ()
  76. {
  77. }
  78. // Properties
  79. public string BaseAddress {
  80. get {
  81. if (baseString == null) {
  82. if (baseAddress == null)
  83. return "";
  84. }
  85. baseString = baseAddress.ToString ();
  86. return baseString;
  87. }
  88. set {
  89. if (value == null || value == "") {
  90. baseAddress = null;
  91. } else {
  92. baseAddress = new Uri (value);
  93. }
  94. }
  95. }
  96. public ICredentials Credentials {
  97. get { return credentials; }
  98. set { credentials = value; }
  99. }
  100. public WebHeaderCollection Headers {
  101. get {
  102. if (headers == null)
  103. headers = new WebHeaderCollection ();
  104. return headers;
  105. }
  106. set { headers = value; }
  107. }
  108. public NameValueCollection QueryString {
  109. get {
  110. if (queryString == null)
  111. queryString = new NameValueCollection ();
  112. return queryString;
  113. }
  114. set { queryString = value; }
  115. }
  116. public WebHeaderCollection ResponseHeaders {
  117. get { return responseHeaders; }
  118. }
  119. #if NET_2_0
  120. public Encoding Encoding {
  121. get { return encoding; }
  122. set {
  123. if (value == null)
  124. throw new ArgumentNullException ("value");
  125. encoding = value;
  126. }
  127. }
  128. public IWebProxy Proxy {
  129. get { return proxy; }
  130. set { proxy = value; }
  131. }
  132. #endif
  133. #if NET_2_0
  134. public bool IsBusy {
  135. get { return isBusy || wait_handles != null && wait_handles.Count > 0; }
  136. }
  137. #else
  138. bool IsBusy {
  139. get { return isBusy; }
  140. }
  141. #endif
  142. // Methods
  143. void CheckBusy ()
  144. {
  145. if (IsBusy)
  146. throw new NotSupportedException ("WebClient does not support conccurent I/O operations.");
  147. }
  148. void SetBusy ()
  149. {
  150. lock (this) {
  151. CheckBusy ();
  152. isBusy = true;
  153. }
  154. }
  155. // DownloadData
  156. public byte [] DownloadData (string address)
  157. {
  158. return DownloadData (MakeUri (address));
  159. }
  160. #if NET_2_0
  161. public
  162. #endif
  163. byte [] DownloadData (Uri address)
  164. {
  165. try {
  166. SetBusy ();
  167. return DownloadDataCore (address);
  168. } finally {
  169. isBusy = false;
  170. }
  171. }
  172. byte [] DownloadDataCore (Uri address)
  173. {
  174. WebRequest request = SetupRequest (address, "GET");
  175. WebResponse response = request.GetResponse ();
  176. Stream st = ProcessResponse (response);
  177. return ReadAll (st, (int) response.ContentLength);
  178. }
  179. // DownloadFile
  180. public void DownloadFile (string address, string fileName)
  181. {
  182. DownloadFile (MakeUri (address), fileName);
  183. }
  184. #if NET_2_0
  185. public
  186. #endif
  187. void DownloadFile (Uri address, string fileName)
  188. {
  189. try {
  190. SetBusy ();
  191. DownloadFileCore (address, fileName);
  192. } finally {
  193. isBusy = false;
  194. }
  195. }
  196. void DownloadFileCore (Uri address, string fileName)
  197. {
  198. WebRequest request = SetupRequest (address);
  199. WebResponse response = request.GetResponse ();
  200. Stream st = ProcessResponse (response);
  201. int cLength = (int) response.ContentLength;
  202. int length = (cLength <= -1 || cLength > 8192) ? 8192 : cLength;
  203. byte [] buffer = new byte [length];
  204. FileStream f = new FileStream (fileName, FileMode.Create);
  205. int nread = 0;
  206. while ((nread = st.Read (buffer, 0, length)) != 0)
  207. f.Write (buffer, 0, nread);
  208. f.Close ();
  209. }
  210. // OpenRead
  211. public Stream OpenRead (string address)
  212. {
  213. return OpenRead (MakeUri (address));
  214. }
  215. #if NET_2_0
  216. public
  217. #endif
  218. Stream OpenRead (Uri address)
  219. {
  220. try {
  221. SetBusy ();
  222. WebRequest request = SetupRequest (address);
  223. WebResponse response = request.GetResponse ();
  224. return ProcessResponse (response);
  225. } finally {
  226. isBusy = false;
  227. }
  228. }
  229. // OpenWrite
  230. public Stream OpenWrite (string address)
  231. {
  232. return OpenWrite (MakeUri (address));
  233. }
  234. public Stream OpenWrite (string address, string method)
  235. {
  236. return OpenWrite (MakeUri (address), method);
  237. }
  238. #if NET_2_0
  239. public
  240. #endif
  241. Stream OpenWrite (Uri address)
  242. {
  243. return OpenWrite (address, DetermineMethod (address));
  244. }
  245. #if NET_2_0
  246. public
  247. #endif
  248. Stream OpenWrite (Uri address, string method)
  249. {
  250. try {
  251. SetBusy ();
  252. WebRequest request = SetupRequest (address, method);
  253. return request.GetRequestStream ();
  254. } finally {
  255. isBusy = false;
  256. }
  257. }
  258. private string DetermineMethod (Uri address)
  259. {
  260. if (address == null)
  261. throw new ArgumentNullException ("address");
  262. #if NET_2_0
  263. if (address.Scheme == Uri.UriSchemeFtp)
  264. return "RETR";
  265. #endif
  266. return "POST";
  267. }
  268. // UploadData
  269. public byte [] UploadData (string address, byte [] data)
  270. {
  271. return UploadData (MakeUri (address), data);
  272. }
  273. public byte [] UploadData (string address, string method, byte [] data)
  274. {
  275. return UploadData (MakeUri (address), method, data);
  276. }
  277. #if NET_2_0
  278. public
  279. #endif
  280. byte [] UploadData (Uri address, byte [] data)
  281. {
  282. return UploadData (address, DetermineMethod (address), data);
  283. }
  284. #if NET_2_0
  285. public
  286. #endif
  287. byte [] UploadData (Uri address, string method, byte [] data)
  288. {
  289. try {
  290. SetBusy ();
  291. return UploadDataCore (address, method, data);
  292. } finally {
  293. isBusy = false;
  294. }
  295. }
  296. byte [] UploadDataCore (Uri address, string method, byte [] data)
  297. {
  298. if (data == null)
  299. throw new ArgumentNullException ("data");
  300. int contentLength = data.Length;
  301. WebRequest request = SetupRequest (address, method, contentLength);
  302. using (Stream stream = request.GetRequestStream ()) {
  303. stream.Write (data, 0, contentLength);
  304. }
  305. WebResponse response = request.GetResponse ();
  306. Stream st = ProcessResponse (response);
  307. return ReadAll (st, (int) response.ContentLength);
  308. }
  309. // UploadFile
  310. public byte [] UploadFile (string address, string fileName)
  311. {
  312. return UploadFile (MakeUri (address), fileName);
  313. }
  314. #if NET_2_0
  315. public
  316. #endif
  317. byte [] UploadFile (Uri address, string fileName)
  318. {
  319. return UploadFile (address, DetermineMethod (address), fileName);
  320. }
  321. public byte [] UploadFile (string address, string method, string fileName)
  322. {
  323. return UploadFile (MakeUri (address), method, fileName);
  324. }
  325. #if NET_2_0
  326. public
  327. #endif
  328. byte [] UploadFile (Uri address, string method, string fileName)
  329. {
  330. try {
  331. SetBusy ();
  332. return UploadFileCore (address, method, fileName);
  333. } finally {
  334. isBusy = false;
  335. }
  336. }
  337. byte [] UploadFileCore (Uri address, string method, string fileName)
  338. {
  339. string fileCType = Headers ["Content-Type"];
  340. if (fileCType != null) {
  341. string lower = fileCType.ToLower ();
  342. if (lower.StartsWith ("multipart/"))
  343. throw new WebException ("Content-Type cannot be set to a multipart" +
  344. " type for this request.");
  345. } else {
  346. fileCType = "application/octet-stream";
  347. }
  348. string boundary = "------------" + DateTime.Now.Ticks.ToString ("x");
  349. Headers ["Content-Type"] = String.Format ("multipart/form-data; boundary={0}", boundary);
  350. WebRequest request = SetupRequest (address, method);
  351. Stream reqStream = null;
  352. Stream fStream = null;
  353. byte [] resultBytes = null;
  354. try {
  355. fStream = File.OpenRead (fileName);
  356. reqStream = request.GetRequestStream ();
  357. byte [] realBoundary = Encoding.ASCII.GetBytes ("--" + boundary + "\r\n");
  358. reqStream.Write (realBoundary, 0, realBoundary.Length);
  359. string partHeaders = String.Format ("Content-Disposition: form-data; " +
  360. "name=\"file\"; filename=\"{0}\"\r\n" +
  361. "Content-Type: {1}\r\n\r\n",
  362. Path.GetFileName (fileName), fileCType);
  363. byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders);
  364. reqStream.Write (partHeadersBytes, 0, partHeadersBytes.Length);
  365. int nread;
  366. byte [] buffer = new byte [4096];
  367. while ((nread = fStream.Read (buffer, 0, 4096)) != 0)
  368. reqStream.Write (buffer, 0, nread);
  369. reqStream.WriteByte ((byte) '\r');
  370. reqStream.WriteByte ((byte) '\n');
  371. reqStream.Write (realBoundary, 0, realBoundary.Length);
  372. reqStream.Close ();
  373. reqStream = null;
  374. WebResponse response = request.GetResponse ();
  375. Stream st = ProcessResponse (response);
  376. resultBytes = ReadAll (st, (int) response.ContentLength);
  377. } catch (WebException) {
  378. throw;
  379. } catch (Exception e) {
  380. throw new WebException ("Error uploading file.", e);
  381. } finally {
  382. if (fStream != null)
  383. fStream.Close ();
  384. if (reqStream != null)
  385. reqStream.Close ();
  386. }
  387. return resultBytes;
  388. }
  389. public byte[] UploadValues (string address, NameValueCollection data)
  390. {
  391. return UploadValues (MakeUri (address), data);
  392. }
  393. public byte[] UploadValues (string address, string method, NameValueCollection data)
  394. {
  395. return UploadValues (MakeUri (address), method, data);
  396. }
  397. #if NET_2_0
  398. public
  399. #endif
  400. byte[] UploadValues (Uri address, NameValueCollection data)
  401. {
  402. return UploadValues (address, DetermineMethod (address), data);
  403. }
  404. #if NET_2_0
  405. public
  406. #endif
  407. byte[] UploadValues (Uri uri, string method, NameValueCollection data)
  408. {
  409. try {
  410. SetBusy ();
  411. return UploadValuesCore (uri, method, data);
  412. } finally {
  413. isBusy = false;
  414. }
  415. }
  416. byte[] UploadValuesCore (Uri uri, string method, NameValueCollection data)
  417. {
  418. if (data == null)
  419. throw new ArgumentNullException ("data"); // MS throws a nullref
  420. string cType = Headers ["Content-Type"];
  421. if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0)
  422. throw new WebException ("Content-Type header cannot be changed from its default " +
  423. "value for this request.");
  424. Headers ["Content-Type"] = urlEncodedCType;
  425. WebRequest request = SetupRequest (uri, method);
  426. Stream rqStream = request.GetRequestStream ();
  427. MemoryStream tmpStream = new MemoryStream ();
  428. foreach (string key in data) {
  429. byte [] bytes = Encoding.ASCII.GetBytes (key);
  430. UrlEncodeAndWrite (tmpStream, bytes);
  431. tmpStream.WriteByte ((byte) '=');
  432. bytes = Encoding.ASCII.GetBytes (data [key]);
  433. UrlEncodeAndWrite (tmpStream, bytes);
  434. tmpStream.WriteByte ((byte) '&');
  435. }
  436. int length = (int) tmpStream.Length;
  437. if (length > 0)
  438. tmpStream.SetLength (--length); // remove trailing '&'
  439. tmpStream.WriteByte ((byte) '\r');
  440. tmpStream.WriteByte ((byte) '\n');
  441. byte [] buf = tmpStream.GetBuffer ();
  442. rqStream.Write (buf, 0, length + 2);
  443. rqStream.Close ();
  444. tmpStream.Close ();
  445. WebResponse response = request.GetResponse ();
  446. Stream st = ProcessResponse (response);
  447. return ReadAll (st, (int) response.ContentLength);
  448. }
  449. #if NET_2_0
  450. public string DownloadString (string address)
  451. {
  452. return encoding.GetString (DownloadData (address));
  453. }
  454. public string DownloadString (Uri address)
  455. {
  456. return encoding.GetString (DownloadData (address));
  457. }
  458. public string UploadString (string address, string data)
  459. {
  460. byte [] resp = UploadData (address, encoding.GetBytes (data));
  461. return encoding.GetString (resp);
  462. }
  463. public string UploadString (string address, string method, string data)
  464. {
  465. byte [] resp = UploadData (address, method, encoding.GetBytes (data));
  466. return encoding.GetString (resp);
  467. }
  468. public string UploadString (Uri address, string data)
  469. {
  470. byte [] resp = UploadData (address, encoding.GetBytes (data));
  471. return encoding.GetString (resp);
  472. }
  473. public string UploadString (Uri address, string method, string data)
  474. {
  475. byte [] resp = UploadData (address, method, encoding.GetBytes (data));
  476. return encoding.GetString (resp);
  477. }
  478. public event DownloadDataCompletedEventHandler DownloadDataCompleted;
  479. public event AsyncCompletedEventHandler DownloadFileCompleted;
  480. public event DownloadProgressChangedEventHandler DownloadProgressChanged;
  481. public event DownloadStringCompletedEventHandler DownloadStringCompleted;
  482. public event OpenReadCompletedEventHandler OpenReadCompleted;
  483. public event OpenWriteCompletedEventHandler OpenWriteCompleted;
  484. public event UploadDataCompletedEventHandler UploadDataCompleted;
  485. public event UploadFileCompletedEventHandler UploadFileCompleted;
  486. public event UploadProgressChangedEventHandler UploadProgressChanged;
  487. public event UploadStringCompletedEventHandler UploadStringCompleted;
  488. public event UploadValuesCompletedEventHandler UploadValuesCompleted;
  489. #endif
  490. Uri MakeUri (string path)
  491. {
  492. string query = null;
  493. if (queryString != null && queryString.Count != 0) {
  494. // This is not the same as UploadValues, because these 'keys' are not
  495. // urlencoded here.
  496. StringBuilder sb = new StringBuilder ();
  497. sb.Append ('?');
  498. foreach (string key in queryString)
  499. sb.AppendFormat ("{0}={1}&", key, UrlEncode (queryString [key]));
  500. if (sb.Length != 0) {
  501. sb.Length--; // remove trailing '&'
  502. query = sb.ToString ();
  503. }
  504. }
  505. if (baseAddress == null && query == null) {
  506. try {
  507. return new Uri (path);
  508. }
  509. catch (System.UriFormatException) {
  510. if ((path[0] == Path.DirectorySeparatorChar) || (path[1] == ':' && Char.ToLower(path[0]) > 'a' && Char.ToLower(path[0]) < 'z')) {
  511. return new Uri ("file://" + path);
  512. }
  513. else {
  514. return new Uri ("file://" + Environment.CurrentDirectory + Path.DirectorySeparatorChar + path);
  515. }
  516. }
  517. }
  518. if (baseAddress == null)
  519. return new Uri (path + query, (query != null));
  520. if (query == null)
  521. return new Uri (baseAddress, path);
  522. return new Uri (baseAddress, path + query, (query != null));
  523. }
  524. WebRequest SetupRequest (Uri uri)
  525. {
  526. WebRequest request = WebRequest.Create (uri);
  527. #if NET_2_0
  528. if (Proxy != null)
  529. request.Proxy = Proxy;
  530. #endif
  531. request.Credentials = credentials;
  532. // Special headers. These are properties of HttpWebRequest.
  533. // What do we do with other requests differnt from HttpWebRequest?
  534. if (headers != null && headers.Count != 0 && (request is HttpWebRequest)) {
  535. HttpWebRequest req = (HttpWebRequest) request;
  536. string expect = headers ["Expect"];
  537. string contentType = headers ["Content-Type"];
  538. string accept = headers ["Accept"];
  539. string connection = headers ["Connection"];
  540. string userAgent = headers ["User-Agent"];
  541. string referer = headers ["Referer"];
  542. headers.RemoveInternal ("Expect");
  543. headers.RemoveInternal ("Content-Type");
  544. headers.RemoveInternal ("Accept");
  545. headers.RemoveInternal ("Connection");
  546. headers.RemoveInternal ("Referer");
  547. headers.RemoveInternal ("User-Agent");
  548. request.Headers = headers;
  549. if (expect != null && expect != "")
  550. req.Expect = expect;
  551. if (accept != null && accept != "")
  552. req.Accept = accept;
  553. if (contentType != null && contentType != "")
  554. req.ContentType = contentType;
  555. if (connection != null && connection != "")
  556. req.Connection = connection;
  557. if (userAgent != null && userAgent != "")
  558. req.UserAgent = userAgent;
  559. if (referer != null && referer != "")
  560. req.Referer = referer;
  561. }
  562. responseHeaders = null;
  563. return request;
  564. }
  565. WebRequest SetupRequest (Uri uri, string method)
  566. {
  567. WebRequest request = SetupRequest (uri);
  568. request.Method = method;
  569. return request;
  570. }
  571. WebRequest SetupRequest (Uri uri, string method, int contentLength)
  572. {
  573. WebRequest request = SetupRequest (uri, method);
  574. request.ContentLength = contentLength;
  575. return request;
  576. }
  577. Stream ProcessResponse (WebResponse response)
  578. {
  579. responseHeaders = response.Headers;
  580. return response.GetResponseStream ();
  581. }
  582. static byte [] ReadAll (Stream stream, int length)
  583. {
  584. MemoryStream ms = null;
  585. bool nolength = (length == -1);
  586. int size = ((nolength) ? 8192 : length);
  587. if (nolength)
  588. ms = new MemoryStream ();
  589. int nread = 0;
  590. int offset = 0;
  591. byte [] buffer = new byte [size];
  592. while ((nread = stream.Read (buffer, offset, size)) != 0) {
  593. if (nolength) {
  594. ms.Write (buffer, 0, nread);
  595. } else {
  596. offset += nread;
  597. size -= nread;
  598. }
  599. }
  600. if (nolength)
  601. return ms.ToArray ();
  602. return buffer;
  603. }
  604. string UrlEncode (string str)
  605. {
  606. StringBuilder result = new StringBuilder ();
  607. int len = str.Length;
  608. for (int i = 0; i < len; i++) {
  609. char c = str [i];
  610. if (c == ' ')
  611. result.Append ('+');
  612. else if ((c < '0' && c != '-' && c != '.') ||
  613. (c < 'A' && c > '9') ||
  614. (c > 'Z' && c < 'a' && c != '_') ||
  615. (c > 'z')) {
  616. result.Append ('%');
  617. int idx = ((int) c) >> 4;
  618. result.Append ((char) hexBytes [idx]);
  619. idx = ((int) c) & 0x0F;
  620. result.Append ((char) hexBytes [idx]);
  621. } else {
  622. result.Append (c);
  623. }
  624. }
  625. return result.ToString ();
  626. }
  627. static void UrlEncodeAndWrite (Stream stream, byte [] bytes)
  628. {
  629. if (bytes == null)
  630. return;
  631. int len = bytes.Length;
  632. if (len == 0)
  633. return;
  634. for (int i = 0; i < len; i++) {
  635. char c = (char) bytes [i];
  636. if (c == ' ')
  637. stream.WriteByte ((byte) '+');
  638. else if ((c < '0' && c != '-' && c != '.') ||
  639. (c < 'A' && c > '9') ||
  640. (c > 'Z' && c < 'a' && c != '_') ||
  641. (c > 'z')) {
  642. stream.WriteByte ((byte) '%');
  643. int idx = ((int) c) >> 4;
  644. stream.WriteByte (hexBytes [idx]);
  645. idx = ((int) c) & 0x0F;
  646. stream.WriteByte (hexBytes [idx]);
  647. } else {
  648. stream.WriteByte ((byte) c);
  649. }
  650. }
  651. }
  652. #if NET_2_0
  653. List<RegisteredWaitHandle> wait_handles;
  654. List<RegisteredWaitHandle> WaitHandles {
  655. get {
  656. if (wait_handles == null)
  657. wait_handles = new List<RegisteredWaitHandle> ();
  658. return wait_handles;
  659. }
  660. }
  661. [MonoTODO ("Is it enough to just unregister wait handles from ThreadPool?")]
  662. public void CancelAsync ()
  663. {
  664. if (wait_handles == null)
  665. return;
  666. lock (wait_handles) {
  667. foreach (RegisteredWaitHandle handle in wait_handles)
  668. handle.Unregister (null);
  669. wait_handles.Clear ();
  670. }
  671. }
  672. // DownloadDataAsync
  673. public void DownloadDataAsync (Uri uri)
  674. {
  675. DownloadDataAsync (uri, null);
  676. }
  677. public void DownloadDataAsync (Uri uri, object asyncState)
  678. {
  679. lock (this) {
  680. CheckBusy ();
  681. object [] cbArgs = new object [] {uri, asyncState};
  682. WaitOrTimerCallback cb = delegate (object state, bool timedOut) {
  683. object [] args = (object []) state;
  684. byte [] data = timedOut ? null : DownloadData ((Uri) args [0]);
  685. OnDownloadDataCompleted (
  686. new DownloadDataCompletedEventArgs (data, null, timedOut, args [1]));
  687. };
  688. AutoResetEvent ev = new AutoResetEvent (true);
  689. WaitHandles.Add (ThreadPool.RegisterWaitForSingleObject (ev, cb, cbArgs, -1, true));
  690. }
  691. }
  692. // DownloadFileAsync
  693. public void DownloadFileAsync (Uri uri, string method)
  694. {
  695. DownloadFileAsync (uri, method, null);
  696. }
  697. public void DownloadFileAsync (Uri uri, string method, object asyncState)
  698. {
  699. lock (this) {
  700. CheckBusy ();
  701. object [] cbArgs = new object [] {uri, method, asyncState};
  702. WaitOrTimerCallback cb = delegate (object innerState, bool timedOut) {
  703. object [] args = (object []) innerState;
  704. if (!timedOut)
  705. DownloadFile ((Uri) args [0], (string) args [1]);
  706. OnDownloadFileCompleted (
  707. new AsyncCompletedEventArgs (null, timedOut, args [2]));
  708. };
  709. AutoResetEvent ev = new AutoResetEvent (true);
  710. WaitHandles.Add (ThreadPool.RegisterWaitForSingleObject (ev, cb, cbArgs, -1, true));
  711. }
  712. }
  713. // DownloadStringAsync
  714. public void DownloadStringAsync (Uri uri)
  715. {
  716. DownloadStringAsync (uri, null);
  717. }
  718. public void DownloadStringAsync (Uri uri, object asyncState)
  719. {
  720. lock (this) {
  721. CheckBusy ();
  722. object [] cbArgs = new object [] {uri, asyncState};
  723. WaitOrTimerCallback cb = delegate (object innerState, bool timedOut) {
  724. object [] args = (object []) innerState;
  725. string data = timedOut ? null : DownloadString ((Uri) args [0]);
  726. OnDownloadStringCompleted (
  727. new DownloadStringCompletedEventArgs (data, null, timedOut, args [1]));
  728. };
  729. AutoResetEvent ev = new AutoResetEvent (true);
  730. WaitHandles.Add (ThreadPool.RegisterWaitForSingleObject (ev, cb, cbArgs, -1, true));
  731. }
  732. }
  733. // OpenReadAsync
  734. public void OpenReadAsync (Uri uri)
  735. {
  736. OpenReadAsync (uri, null);
  737. }
  738. public void OpenReadAsync (Uri uri, object asyncState)
  739. {
  740. lock (this) {
  741. CheckBusy ();
  742. object [] cbArgs = new object [] {uri, asyncState};
  743. WaitOrTimerCallback cb = delegate (object innerState, bool timedOut) {
  744. object [] args = (object []) innerState;
  745. Stream stream = timedOut ? null : OpenRead ((Uri) args [0]);
  746. OnOpenReadCompleted (
  747. new OpenReadCompletedEventArgs (stream, null, timedOut, args [1]));
  748. };
  749. AutoResetEvent ev = new AutoResetEvent (true);
  750. WaitHandles.Add (ThreadPool.RegisterWaitForSingleObject (ev, cb, cbArgs, -1, true));
  751. }
  752. }
  753. // OpenWriteAsync
  754. public void OpenWriteAsync (Uri uri)
  755. {
  756. OpenWriteAsync (uri, null);
  757. }
  758. public void OpenWriteAsync (Uri uri, string method)
  759. {
  760. OpenWriteAsync (uri, method, null);
  761. }
  762. public void OpenWriteAsync (Uri uri, string method, object asyncState)
  763. {
  764. lock (this) {
  765. CheckBusy ();
  766. object [] cbArgs = new object [] {uri, method, asyncState};
  767. WaitOrTimerCallback cb = delegate (object innerState, bool timedOut) {
  768. object [] args = (object []) innerState;
  769. Stream stream = timedOut ? null : OpenWrite ((Uri) args [0], (string) args [1]);
  770. OnOpenWriteCompleted (
  771. new OpenWriteCompletedEventArgs (stream, null, timedOut, args [2]));
  772. };
  773. AutoResetEvent ev = new AutoResetEvent (true);
  774. WaitHandles.Add (ThreadPool.RegisterWaitForSingleObject (ev, cb, cbArgs, -1, true));
  775. }
  776. }
  777. // UploadDataAsync
  778. public void UploadDataAsync (Uri uri, byte [] data)
  779. {
  780. UploadDataAsync (uri, null, data);
  781. }
  782. public void UploadDataAsync (Uri uri, string method, byte [] data)
  783. {
  784. UploadDataAsync (uri, method, data, null);
  785. }
  786. public void UploadDataAsync (Uri uri, string method, byte [] data, object asyncState)
  787. {
  788. lock (this) {
  789. CheckBusy ();
  790. object [] cbArgs = new object [] {uri, method, data, asyncState};
  791. WaitOrTimerCallback cb = delegate (object innerState, bool timedOut) {
  792. object [] args = (object []) innerState;
  793. byte [] data2 = timedOut ? null : UploadData ((Uri) args [0], (string) args [1], (byte []) args [2]);
  794. OnUploadDataCompleted (
  795. new UploadDataCompletedEventArgs (data2, null, timedOut, args [3]));
  796. };
  797. AutoResetEvent ev = new AutoResetEvent (true);
  798. WaitHandles.Add (ThreadPool.RegisterWaitForSingleObject (ev, cb, cbArgs, -1, true));
  799. }
  800. }
  801. // UploadFileAsync
  802. public void UploadFileAsync (Uri uri, string file)
  803. {
  804. UploadFileAsync (uri, null, file);
  805. }
  806. public void UploadFileAsync (Uri uri, string method, string file)
  807. {
  808. UploadFileAsync (uri, method, file, null);
  809. }
  810. public void UploadFileAsync (Uri uri, string method, string file, object asyncState)
  811. {
  812. lock (this) {
  813. CheckBusy ();
  814. object [] cbArgs = new object [] {uri, method, file, asyncState};
  815. WaitOrTimerCallback cb = delegate (object innerState, bool timedOut) {
  816. object [] args = (object []) innerState;
  817. byte [] data = timedOut ? null : UploadFile ((Uri) args [0], (string) args [1], (string) args [2]);
  818. OnUploadFileCompleted (
  819. new UploadFileCompletedEventArgs (data, null, timedOut, args [3]));
  820. };
  821. AutoResetEvent ev = new AutoResetEvent (true);
  822. WaitHandles.Add (ThreadPool.RegisterWaitForSingleObject (ev, cb, cbArgs, -1, true));
  823. }
  824. }
  825. // UploadStringAsync
  826. public void UploadStringAsync (Uri uri, string data)
  827. {
  828. UploadStringAsync (uri, null, data);
  829. }
  830. public void UploadStringAsync (Uri uri, string method, string data)
  831. {
  832. UploadStringAsync (uri, method, data, null);
  833. }
  834. public void UploadStringAsync (Uri uri, string method, string data, object asyncState)
  835. {
  836. lock (this) {
  837. CheckBusy ();
  838. object [] cbArgs = new object [] {uri, method, data, asyncState};
  839. WaitOrTimerCallback cb = delegate (object innerState, bool timedOut) {
  840. object [] args = (object []) innerState;
  841. string data2 = timedOut ? null : UploadString ((Uri) args [0], (string) args [1], (string) args [2]);
  842. OnUploadStringCompleted (
  843. new UploadStringCompletedEventArgs (data2, null, timedOut, args [3]));
  844. };
  845. AutoResetEvent ev = new AutoResetEvent (true);
  846. WaitHandles.Add (ThreadPool.RegisterWaitForSingleObject (ev, cb, cbArgs, -1, true));
  847. }
  848. }
  849. // UploadValuesAsync
  850. public void UploadValuesAsync (Uri uri, NameValueCollection values)
  851. {
  852. UploadValuesAsync (uri, null, values);
  853. }
  854. public void UploadValuesAsync (Uri uri, string method, NameValueCollection values)
  855. {
  856. UploadValuesAsync (uri, method, values, null);
  857. }
  858. public void UploadValuesAsync (Uri uri, string method, NameValueCollection values, object asyncState)
  859. {
  860. lock (this) {
  861. CheckBusy ();
  862. object [] cbArgs = new object [] {uri, method, values, asyncState};
  863. WaitOrTimerCallback cb = delegate (object innerState, bool timedOut) {
  864. object [] args = (object []) innerState;
  865. byte [] data = timedOut ? null : UploadValues ((Uri) args [0], (string) args [1], (NameValueCollection) args [2]);
  866. OnUploadValuesCompleted (
  867. new UploadValuesCompletedEventArgs (data, null, timedOut, args [3]));
  868. };
  869. AutoResetEvent ev = new AutoResetEvent (true);
  870. WaitHandles.Add (ThreadPool.RegisterWaitForSingleObject (ev, cb, cbArgs, -1, true));
  871. }
  872. }
  873. protected virtual void OnDownloadDataCompleted (
  874. DownloadDataCompletedEventArgs args)
  875. {
  876. if (DownloadDataCompleted != null)
  877. DownloadDataCompleted (this, args);
  878. }
  879. protected virtual void OnDownloadFileCompleted (
  880. AsyncCompletedEventArgs args)
  881. {
  882. if (DownloadFileCompleted != null)
  883. DownloadFileCompleted (this, args);
  884. }
  885. protected virtual void OnDownloadProgressChanged (DownloadProgressChangedEventArgs e)
  886. {
  887. if (DownloadProgressChanged != null)
  888. DownloadProgressChanged (this, e);
  889. }
  890. protected virtual void OnDownloadStringCompleted (
  891. DownloadStringCompletedEventArgs args)
  892. {
  893. if (DownloadStringCompleted != null)
  894. DownloadStringCompleted (this, args);
  895. }
  896. protected virtual void OnOpenReadCompleted (
  897. OpenReadCompletedEventArgs args)
  898. {
  899. if (OpenReadCompleted != null)
  900. OpenReadCompleted (this, args);
  901. }
  902. protected virtual void OnOpenWriteCompleted (
  903. OpenWriteCompletedEventArgs args)
  904. {
  905. if (OpenWriteCompleted != null)
  906. OpenWriteCompleted (this, args);
  907. }
  908. protected virtual void OnUploadDataCompleted (
  909. UploadDataCompletedEventArgs args)
  910. {
  911. if (UploadDataCompleted != null)
  912. UploadDataCompleted (this, args);
  913. }
  914. protected virtual void OnUploadFileCompleted (
  915. UploadFileCompletedEventArgs args)
  916. {
  917. if (UploadFileCompleted != null)
  918. UploadFileCompleted (this, args);
  919. }
  920. protected virtual void OnUploadProgressChanged (UploadProgressChangedEventArgs e)
  921. {
  922. if (UploadProgressChanged != null)
  923. UploadProgressChanged (this, e);
  924. }
  925. protected virtual void OnUploadStringCompleted (
  926. UploadStringCompletedEventArgs args)
  927. {
  928. if (UploadStringCompleted != null)
  929. UploadStringCompleted (this, args);
  930. }
  931. protected virtual void OnUploadValuesCompleted (
  932. UploadValuesCompletedEventArgs args)
  933. {
  934. if (UploadValuesCompleted != null)
  935. UploadValuesCompleted (this, args);
  936. }
  937. [MonoNotSupported("")]
  938. protected virtual WebRequest GetWebRequest (Uri address)
  939. {
  940. throw new NotImplementedException ();
  941. }
  942. protected virtual WebResponse GetWebResponse (WebRequest request)
  943. {
  944. return request.GetResponse ();
  945. }
  946. protected virtual WebResponse GetWebResponse (WebRequest request, IAsyncResult result)
  947. {
  948. return request.EndGetResponse (result);
  949. }
  950. #endif
  951. }
  952. }