WebClient.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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. [MonoTODO]
  143. public byte[] UploadFile (string address, string method, string fileName)
  144. {
  145. throw new NotImplementedException ();
  146. }
  147. public byte[] UploadValues (string address, NameValueCollection data)
  148. {
  149. return UploadValues (address, "POST", data);
  150. }
  151. public byte[] UploadValues (string address, string method, NameValueCollection data)
  152. {
  153. if (data == null)
  154. throw new ArgumentNullException ("data"); // MS throws a nullref
  155. string cType = Headers ["Content-Type"];
  156. if (cType != null && String.Compare (cType, urlEncodedCType, true) != 0)
  157. throw new WebException ("Content-Type header cannot be changed from its default " +
  158. "value for this request.");
  159. Headers ["Content-Type"] = urlEncodedCType;
  160. WebRequest request = SetupRequest (address, method);
  161. Stream rqStream = request.GetRequestStream ();
  162. MemoryStream tmpStream = new MemoryStream ();
  163. foreach (string key in data) {
  164. byte [] bytes = Encoding.ASCII.GetBytes (key);
  165. UrlEncodeAndWrite (tmpStream, bytes);
  166. tmpStream.WriteByte ((byte) '=');
  167. bytes = Encoding.ASCII.GetBytes (data [key]);
  168. UrlEncodeAndWrite (tmpStream, bytes);
  169. tmpStream.WriteByte ((byte) '&');
  170. }
  171. int length = (int) tmpStream.Length;
  172. if (length > 0)
  173. tmpStream.SetLength (--length); // remove trailing '&'
  174. tmpStream.WriteByte ((byte) '\r');
  175. tmpStream.WriteByte ((byte) '\n');
  176. byte [] bytes = tmpStream.GetBuffer ();
  177. rqStream.Write (bytes, 0, length + 2);
  178. rqStream.Close ();
  179. tmpStream.Close ();
  180. WebResponse response = request.GetResponse ();
  181. Stream st = ProcessResponse (response);
  182. return ReadAll (st, (int) response.ContentLength);
  183. }
  184. Uri MakeUri (string path)
  185. {
  186. string query = null;
  187. if (queryString != null && queryString.Count != 0) {
  188. // This is not the same as UploadValues, because these 'keys' are not
  189. // urlencoded here.
  190. StringBuilder sb = new StringBuilder ();
  191. sb.Append ('?');
  192. foreach (string key in queryString)
  193. sb.AppendFormat ("{0}={1}&", key, queryString [key]);
  194. if (sb.Length != 0) {
  195. sb.Length--; // remove trailing '&'
  196. query = sb.ToString ();
  197. }
  198. }
  199. if (baseAddress == null && query == null)
  200. return new Uri (path);
  201. if (baseAddress == null)
  202. return new Uri (path + query);
  203. if (query == null)
  204. return new Uri (baseAddress, path);
  205. return new Uri (baseAddress, path + query);
  206. }
  207. WebRequest SetupRequest (string address)
  208. {
  209. Uri uri = MakeUri (address);
  210. WebRequest request = WebRequest.Create (uri);
  211. request.Credentials = credentials;
  212. // Special headers. These are properties of HttpWebRequest.
  213. // What do we do with other requests differnt from HttpWebRequest?
  214. if (headers != null && headers.Count != 0 && (request is HttpWebRequest)) {
  215. HttpWebRequest req = (HttpWebRequest) request;
  216. string val = headers ["Expect"];
  217. if (val != null && val != "") {
  218. req.Expect = val;
  219. headers.RemoveInternal ("Expect");
  220. }
  221. val = headers ["Accept"];
  222. if (val != null && val != "") {
  223. req.Accept = val;
  224. headers.RemoveInternal ("Accept");
  225. }
  226. val = headers ["Content-Type"];
  227. if (val != null && val != "") {
  228. req.ContentType = val;
  229. headers.RemoveInternal ("Content-Type");
  230. }
  231. val = headers ["Connection"];
  232. if (val != null && val != "") {
  233. req.Connection = val;
  234. headers.RemoveInternal ("Connection");
  235. }
  236. val = headers ["User-Agent"];
  237. if (val != null && val != "") {
  238. req.UserAgent = val;
  239. headers.RemoveInternal ("User-Agent");
  240. }
  241. val = headers ["Referer"];
  242. if (val != null && val != "") {
  243. req.Referer = val;
  244. headers.RemoveInternal ("Referer");
  245. }
  246. request.Headers = headers;
  247. }
  248. responseHeaders = null;
  249. return request;
  250. }
  251. WebRequest SetupRequest (string address, string method)
  252. {
  253. WebRequest request = SetupRequest (address);
  254. request.Method = method;
  255. return request;
  256. }
  257. WebRequest SetupRequest (string address, string method, int contentLength)
  258. {
  259. WebRequest request = SetupRequest (address, method);
  260. request.ContentLength = contentLength;
  261. return request;
  262. }
  263. Stream ProcessResponse (WebResponse response)
  264. {
  265. responseHeaders = response.Headers;
  266. return response.GetResponseStream ();
  267. }
  268. static byte [] ReadAll (Stream stream, int length)
  269. {
  270. MemoryStream ms = null;
  271. bool nolength = (length == -1);
  272. int size = ((nolength) ? 8192 : length);
  273. if (nolength)
  274. ms = new MemoryStream ();
  275. int nread = 0;
  276. int offset = 0;
  277. byte [] buffer = new byte [size];
  278. while ((nread = stream.Read (buffer, offset, size)) != 0) {
  279. if (nolength) {
  280. ms.Write (buffer, 0, nread);
  281. } else {
  282. offset += nread;
  283. size -= nread;
  284. }
  285. }
  286. if (nolength)
  287. return ms.ToArray ();
  288. return buffer;
  289. }
  290. static void UrlEncodeAndWrite (Stream stream, byte [] bytes)
  291. {
  292. if (bytes == null)
  293. return;
  294. int len = bytes.Length;
  295. if (len == 0)
  296. return;
  297. for (int i = 0; i < len; i++) {
  298. char c = (char) bytes [i];
  299. if (c == ' ')
  300. stream.WriteByte ((byte) '+');
  301. else if ((c < '0' && c != '-' && c != '.') ||
  302. (c < 'A' && c > '9') ||
  303. (c > 'Z' && c < 'a' && c != '_') ||
  304. (c > 'z')) {
  305. stream.WriteByte ((byte) '%');
  306. int idx = ((int) c) >> 4;
  307. stream.WriteByte (hexBytes [idx]);
  308. idx = ((int) c) & 0x0F;
  309. stream.WriteByte (hexBytes [idx]);
  310. } else {
  311. stream.WriteByte ((byte) c);
  312. }
  313. }
  314. }
  315. }
  316. }