WebClient.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. //
  2. // System.Net.WebClient
  3. //
  4. // Authors:
  5. // Lawrence Pit ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. //
  8. // (c) 2003 Ximian, Inc. (http://www.ximian.com)
  9. //
  10. using System;
  11. using System.Collections.Specialized;
  12. using System.ComponentModel;
  13. using System.IO;
  14. using System.Runtime.InteropServices;
  15. using System.Runtime.Serialization;
  16. using System.Text;
  17. namespace System.Net
  18. {
  19. [ComVisible(true)]
  20. public sealed class WebClient : Component
  21. {
  22. static readonly string urlEncodedCType = "application/x-www-form-urlencoded";
  23. static byte [] hexBytes;
  24. ICredentials credentials;
  25. WebHeaderCollection headers;
  26. WebHeaderCollection responseHeaders;
  27. Uri baseAddress;
  28. string baseString;
  29. NameValueCollection queryString;
  30. // Constructors
  31. static WebClient ()
  32. {
  33. hexBytes = new byte [16];
  34. int index = 0;
  35. for (int i = '0'; i <= '9'; i++, index++)
  36. hexBytes [index] = (byte) i;
  37. for (int i = 'A'; i <= 'F'; i++, index++)
  38. hexBytes [index] = (byte) i;
  39. }
  40. public WebClient ()
  41. {
  42. }
  43. // Properties
  44. public string BaseAddress {
  45. get {
  46. if (baseString == null) {
  47. if (baseAddress == null)
  48. return "";
  49. }
  50. baseString = baseAddress.ToString ();
  51. return baseString;
  52. }
  53. set {
  54. if (value == null || value == "") {
  55. baseAddress = null;
  56. } else {
  57. baseAddress = new Uri (value);
  58. }
  59. }
  60. }
  61. public ICredentials Credentials {
  62. get { return credentials; }
  63. set { credentials = value; }
  64. }
  65. public WebHeaderCollection Headers {
  66. get {
  67. if (headers == null)
  68. headers = new WebHeaderCollection ();
  69. return headers;
  70. }
  71. set { headers = value; }
  72. }
  73. public NameValueCollection QueryString {
  74. get {
  75. if (queryString == null)
  76. queryString = new NameValueCollection ();
  77. return queryString;
  78. }
  79. set { queryString = value; }
  80. }
  81. public WebHeaderCollection ResponseHeaders {
  82. get { return responseHeaders; }
  83. }
  84. // Methods
  85. public byte [] DownloadData (string address)
  86. {
  87. WebRequest request = SetupRequest (address);
  88. WebResponse response = request.GetResponse ();
  89. Stream st = ProcessResponse (response);
  90. return ReadAll (st, (int) response.ContentLength);
  91. }
  92. public void DownloadFile (string address, string fileName)
  93. {
  94. WebRequest request = SetupRequest (address);
  95. WebResponse response = request.GetResponse ();
  96. Stream st = ProcessResponse (response);
  97. int cLength = (int) response.ContentLength;
  98. int length = (cLength <= -1 || cLength > 8192) ? 8192 : cLength;
  99. byte [] buffer = new byte [length];
  100. FileStream f = new FileStream (fileName, FileMode.CreateNew);
  101. int nread = 0;
  102. while ((nread = st.Read (buffer, 0, length)) != 0)
  103. f.Write (buffer, 0, nread);
  104. f.Close ();
  105. }
  106. public Stream OpenRead (string address)
  107. {
  108. WebRequest request = SetupRequest (address);
  109. WebResponse response = request.GetResponse ();
  110. return ProcessResponse (response);
  111. }
  112. public Stream OpenWrite (string address)
  113. {
  114. return OpenWrite (address, "POST");
  115. }
  116. public Stream OpenWrite (string address, string method)
  117. {
  118. WebRequest request = SetupRequest (address, method);
  119. return request.GetRequestStream ();
  120. }
  121. public byte [] UploadData (string address, byte [] data)
  122. {
  123. return UploadData (address, "POST", data);
  124. }
  125. public byte [] UploadData (string address, string method, byte [] data)
  126. {
  127. if (data == null)
  128. throw new ArgumentNullException ("data");
  129. int contentLength = data.Length;
  130. WebRequest request = SetupRequest (address, method, contentLength);
  131. using (Stream stream = request.GetRequestStream ()) {
  132. stream.Write (data, 0, contentLength);
  133. }
  134. WebResponse response = request.GetResponse ();
  135. Stream st = ProcessResponse (response);
  136. return ReadAll (st, (int) response.ContentLength);
  137. }
  138. public byte [] UploadFile (string address, string fileName)
  139. {
  140. return UploadFile (address, "POST", fileName);
  141. }
  142. public byte [] UploadFile (string address, string method, string fileName)
  143. {
  144. string fileCType = Headers ["Content-Type"];
  145. if (fileCType != null) {
  146. string lower = fileCType.ToLower ();
  147. if (lower.StartsWith ("multipart/"))
  148. throw new WebException ("Content-Type cannot be set to a multipart" +
  149. " type for this request.");
  150. } else {
  151. fileCType = "application/octet-stream";
  152. }
  153. string boundary = "------------" + DateTime.Now.Ticks.ToString ("x");
  154. Headers ["Content-Type"] = String.Format ("multipart/form-data; boundary={0}", boundary);
  155. WebRequest request = SetupRequest (address, method);
  156. Stream reqStream = null;
  157. Stream fStream = null;
  158. byte [] resultBytes = null;
  159. try {
  160. fStream = File.OpenRead (fileName);
  161. reqStream = request.GetRequestStream ();
  162. byte [] realBoundary = Encoding.ASCII.GetBytes ("--" + boundary + "\r\n");
  163. reqStream.Write (realBoundary, 0, realBoundary.Length);
  164. string partHeaders = String.Format ("Content-Disposition: form-data; " +
  165. "name=\"file\"; filename=\"{0}\"\r\n" +
  166. "Content-Type: {1}\r\n\r\n",
  167. Path.GetFileName (fileName), fileCType);
  168. byte [] partHeadersBytes = Encoding.UTF8.GetBytes (partHeaders);
  169. reqStream.Write (partHeadersBytes, 0, partHeadersBytes.Length);
  170. int nread;
  171. byte [] buffer = new byte [4096];
  172. while ((nread = fStream.Read (buffer, 0, 4096)) != 0)
  173. reqStream.Write (buffer, 0, nread);
  174. reqStream.WriteByte ((byte) '\r');
  175. reqStream.WriteByte ((byte) '\n');
  176. reqStream.Write (realBoundary, 0, realBoundary.Length);
  177. reqStream.Close ();
  178. reqStream = null;
  179. WebResponse response = request.GetResponse ();
  180. Stream st = ProcessResponse (response);
  181. resultBytes = ReadAll (st, (int) response.ContentLength);
  182. } catch (WebException) {
  183. throw;
  184. } catch (Exception e) {
  185. throw new WebException ("Error uploading file.", e);
  186. } finally {
  187. if (fStream != null)
  188. fStream.Close ();
  189. if (reqStream != null)
  190. reqStream.Close ();
  191. }
  192. return resultBytes;
  193. }
  194. public byte[] UploadValues (string address, NameValueCollection data)
  195. {
  196. return UploadValues (address, "POST", data);
  197. }
  198. public byte[] UploadValues (string address, string method, NameValueCollection data)
  199. {
  200. if (data == null)
  201. throw new ArgumentNullException ("data"); // MS throws a nullref
  202. string cType = Headers ["Content-Type"];
  203. if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0)
  204. throw new WebException ("Content-Type header cannot be changed from its default " +
  205. "value for this request.");
  206. Headers ["Content-Type"] = urlEncodedCType;
  207. WebRequest request = SetupRequest (address, method);
  208. Stream rqStream = request.GetRequestStream ();
  209. MemoryStream tmpStream = new MemoryStream ();
  210. foreach (string key in data) {
  211. byte [] bytes = Encoding.ASCII.GetBytes (key);
  212. UrlEncodeAndWrite (tmpStream, bytes);
  213. tmpStream.WriteByte ((byte) '=');
  214. bytes = Encoding.ASCII.GetBytes (data [key]);
  215. UrlEncodeAndWrite (tmpStream, bytes);
  216. tmpStream.WriteByte ((byte) '&');
  217. }
  218. int length = (int) tmpStream.Length;
  219. if (length > 0)
  220. tmpStream.SetLength (--length); // remove trailing '&'
  221. tmpStream.WriteByte ((byte) '\r');
  222. tmpStream.WriteByte ((byte) '\n');
  223. byte [] buf = tmpStream.GetBuffer ();
  224. rqStream.Write (buf, 0, length + 2);
  225. rqStream.Close ();
  226. tmpStream.Close ();
  227. WebResponse response = request.GetResponse ();
  228. Stream st = ProcessResponse (response);
  229. return ReadAll (st, (int) response.ContentLength);
  230. }
  231. Uri MakeUri (string path)
  232. {
  233. string query = null;
  234. if (queryString != null && queryString.Count != 0) {
  235. // This is not the same as UploadValues, because these 'keys' are not
  236. // urlencoded here.
  237. StringBuilder sb = new StringBuilder ();
  238. sb.Append ('?');
  239. foreach (string key in queryString)
  240. sb.AppendFormat ("{0}={1}&", key, UrlEncode (queryString [key]));
  241. if (sb.Length != 0) {
  242. sb.Length--; // remove trailing '&'
  243. query = sb.ToString ();
  244. }
  245. }
  246. if (baseAddress == null && query == null) {
  247. try {
  248. return new Uri (path);
  249. }
  250. catch (System.UriFormatException) {
  251. if ((path[0] == Path.DirectorySeparatorChar) || (path[1] == ':' && Char.ToLower(path[0]) > 'a' && Char.ToLower(path[0]) < 'z')) {
  252. return new Uri ("file://" + path);
  253. }
  254. else {
  255. return new Uri ("file://" + Environment.CurrentDirectory + Path.DirectorySeparatorChar + path);
  256. }
  257. }
  258. }
  259. if (baseAddress == null)
  260. return new Uri (path + query, (query != null));
  261. if (query == null)
  262. return new Uri (baseAddress, path);
  263. return new Uri (baseAddress, path + query, (query != null));
  264. }
  265. WebRequest SetupRequest (string address)
  266. {
  267. Uri uri = MakeUri (address);
  268. WebRequest request = WebRequest.Create (uri);
  269. request.Credentials = credentials;
  270. // Special headers. These are properties of HttpWebRequest.
  271. // What do we do with other requests differnt from HttpWebRequest?
  272. if (headers != null && headers.Count != 0 && (request is HttpWebRequest)) {
  273. HttpWebRequest req = (HttpWebRequest) request;
  274. string expect = headers ["Expect"];
  275. string contentType = headers ["Content-Type"];
  276. string accept = headers ["Accept"];
  277. string connection = headers ["Connection"];
  278. string userAgent = headers ["User-Agent"];
  279. string referer = headers ["Referer"];
  280. headers.RemoveInternal ("Expect");
  281. headers.RemoveInternal ("Content-Type");
  282. headers.RemoveInternal ("Accept");
  283. headers.RemoveInternal ("Connection");
  284. headers.RemoveInternal ("Referer");
  285. headers.RemoveInternal ("User-Agent");
  286. request.Headers = headers;
  287. if (expect != null && expect != "")
  288. req.Expect = expect;
  289. if (accept != null && accept != "")
  290. req.Accept = accept;
  291. if (contentType != null && contentType != "")
  292. req.ContentType = contentType;
  293. if (connection != null && connection != "")
  294. req.Connection = connection;
  295. if (userAgent != null && userAgent != "")
  296. req.UserAgent = userAgent;
  297. if (referer != null && referer != "")
  298. req.Referer = referer;
  299. }
  300. responseHeaders = null;
  301. return request;
  302. }
  303. WebRequest SetupRequest (string address, string method)
  304. {
  305. WebRequest request = SetupRequest (address);
  306. request.Method = method;
  307. return request;
  308. }
  309. WebRequest SetupRequest (string address, string method, int contentLength)
  310. {
  311. WebRequest request = SetupRequest (address, method);
  312. request.ContentLength = contentLength;
  313. return request;
  314. }
  315. Stream ProcessResponse (WebResponse response)
  316. {
  317. responseHeaders = response.Headers;
  318. return response.GetResponseStream ();
  319. }
  320. static byte [] ReadAll (Stream stream, int length)
  321. {
  322. MemoryStream ms = null;
  323. bool nolength = (length == -1);
  324. int size = ((nolength) ? 8192 : length);
  325. if (nolength)
  326. ms = new MemoryStream ();
  327. int nread = 0;
  328. int offset = 0;
  329. byte [] buffer = new byte [size];
  330. while ((nread = stream.Read (buffer, offset, size)) != 0) {
  331. if (nolength) {
  332. ms.Write (buffer, 0, nread);
  333. } else {
  334. offset += nread;
  335. size -= nread;
  336. }
  337. }
  338. if (nolength)
  339. return ms.ToArray ();
  340. return buffer;
  341. }
  342. string UrlEncode (string str)
  343. {
  344. StringBuilder result = new StringBuilder ();
  345. int len = str.Length;
  346. for (int i = 0; i < len; i++) {
  347. char c = str [i];
  348. if (c == ' ')
  349. result.Append ('+');
  350. else if ((c < '0' && c != '-' && c != '.') ||
  351. (c < 'A' && c > '9') ||
  352. (c > 'Z' && c < 'a' && c != '_') ||
  353. (c > 'z')) {
  354. result.Append ('%');
  355. int idx = ((int) c) >> 4;
  356. result.Append ((char) hexBytes [idx]);
  357. idx = ((int) c) & 0x0F;
  358. result.Append ((char) hexBytes [idx]);
  359. } else {
  360. result.Append (c);
  361. }
  362. }
  363. return result.ToString ();
  364. }
  365. static void UrlEncodeAndWrite (Stream stream, byte [] bytes)
  366. {
  367. if (bytes == null)
  368. return;
  369. int len = bytes.Length;
  370. if (len == 0)
  371. return;
  372. for (int i = 0; i < len; i++) {
  373. char c = (char) bytes [i];
  374. if (c == ' ')
  375. stream.WriteByte ((byte) '+');
  376. else if ((c < '0' && c != '-' && c != '.') ||
  377. (c < 'A' && c > '9') ||
  378. (c > 'Z' && c < 'a' && c != '_') ||
  379. (c > 'z')) {
  380. stream.WriteByte ((byte) '%');
  381. int idx = ((int) c) >> 4;
  382. stream.WriteByte (hexBytes [idx]);
  383. idx = ((int) c) & 0x0F;
  384. stream.WriteByte (hexBytes [idx]);
  385. } else {
  386. stream.WriteByte ((byte) c);
  387. }
  388. }
  389. }
  390. }
  391. }