PageRenderTime 99ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/RestSharp/Http.cs

https://github.com/Subv/RestSharp
C# | 369 lines | 253 code | 30 blank | 86 comment | 45 complexity | 9a5a76560eeb7ad1f41f4606706fc6c9 MD5 | raw file
  1. #region License
  2. // Copyright 2010 John Sheehan
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. #endregion
  16. using System;
  17. using System.Collections.Generic;
  18. using System.IO;
  19. using System.Linq;
  20. using System.Net;
  21. using System.Text;
  22. using RestSharp.Extensions;
  23. namespace RestSharp
  24. {
  25. /// <summary>
  26. /// HttpWebRequest wrapper
  27. /// </summary>
  28. public partial class Http : IHttp, IHttpFactory
  29. {
  30. public IHttp Create()
  31. {
  32. return new Http();
  33. }
  34. /// <summary>
  35. /// True if this HTTP request has any HTTP parameters
  36. /// </summary>
  37. protected bool HasParameters
  38. {
  39. get
  40. {
  41. return Parameters.Any();
  42. }
  43. }
  44. /// <summary>
  45. /// True if this HTTP request has any HTTP cookies
  46. /// </summary>
  47. protected bool HasCookies
  48. {
  49. get
  50. {
  51. return Cookies.Any();
  52. }
  53. }
  54. /// <summary>
  55. /// True if a request body has been specified
  56. /// </summary>
  57. protected bool HasBody
  58. {
  59. get
  60. {
  61. return !string.IsNullOrEmpty(RequestBody);
  62. }
  63. }
  64. /// <summary>
  65. /// True if files have been set to be uploaded
  66. /// </summary>
  67. protected bool HasFiles
  68. {
  69. get
  70. {
  71. return Files.Any();
  72. }
  73. }
  74. /// <summary>
  75. /// UserAgent to be sent with request
  76. /// </summary>
  77. public string UserAgent { get; set; }
  78. /// <summary>
  79. /// Timeout in milliseconds to be used for the request
  80. /// </summary>
  81. public int Timeout { get; set; }
  82. /// <summary>
  83. /// System.Net.ICredentials to be sent with request
  84. /// </summary>
  85. public ICredentials Credentials { get; set; }
  86. /// <summary>
  87. /// Collection of files to be sent with request
  88. /// </summary>
  89. public IList<HttpFile> Files { get; private set; }
  90. #if !SILVERLIGHT
  91. /// <summary>
  92. /// Whether or not HTTP 3xx response redirects should be automatically followed
  93. /// </summary>
  94. public bool FollowRedirects { get; set; }
  95. #endif
  96. #if FRAMEWORK
  97. /// <summary>
  98. /// Maximum number of automatic redirects to follow if FollowRedirects is true
  99. /// </summary>
  100. public int? MaxRedirects { get; set; }
  101. #endif
  102. /// <summary>
  103. /// HTTP headers to be sent with request
  104. /// </summary>
  105. public IList<HttpHeader> Headers { get; private set; }
  106. /// <summary>
  107. /// HTTP parameters (QueryString or Form values) to be sent with request
  108. /// </summary>
  109. public IList<HttpParameter> Parameters { get; private set; }
  110. /// <summary>
  111. /// HTTP cookies to be sent with request
  112. /// </summary>
  113. public IList<HttpCookie> Cookies { get; private set; }
  114. /// <summary>
  115. /// Request body to be sent with request
  116. /// </summary>
  117. public string RequestBody { get; set; }
  118. /// <summary>
  119. /// Content type of the request body.
  120. /// </summary>
  121. public string RequestContentType { get; set; }
  122. /// <summary>
  123. /// URL to call for this request
  124. /// </summary>
  125. public Uri Url { get; set; }
  126. #if FRAMEWORK
  127. /// <summary>
  128. /// Proxy info to be sent with request
  129. /// </summary>
  130. public IWebProxy Proxy { get; set; }
  131. #endif
  132. /// <summary>
  133. /// Default constructor
  134. /// </summary>
  135. public Http()
  136. {
  137. Headers = new List<HttpHeader>();
  138. Files = new List<HttpFile>();
  139. Parameters = new List<HttpParameter>();
  140. Cookies = new List<HttpCookie>();
  141. _restrictedHeaderActions = new Dictionary<string, Action<HttpWebRequest, string>>(StringComparer.OrdinalIgnoreCase);
  142. AddSharedHeaderActions();
  143. AddSyncHeaderActions();
  144. }
  145. partial void AddSyncHeaderActions();
  146. partial void AddAsyncHeaderActions();
  147. private void AddSharedHeaderActions()
  148. {
  149. _restrictedHeaderActions.Add("Accept", (r, v) => r.Accept = v);
  150. _restrictedHeaderActions.Add("Content-Type", (r, v) => r.ContentType = v);
  151. _restrictedHeaderActions.Add("Date", (r, v) => { /* Set by system */ });
  152. _restrictedHeaderActions.Add("Host", (r, v) => { /* Set by system */ });
  153. _restrictedHeaderActions.Add("Range", (r, v) => { /* Ignore */ });
  154. }
  155. private const string FormBoundary = "-----------------------------28947758029299";
  156. private string GetMultipartFormContentType()
  157. {
  158. return string.Format("multipart/form-data; boundary={0}", FormBoundary);
  159. }
  160. private string GetMultipartFileHeader (HttpFile file)
  161. {
  162. return string.Format ("--{0}{4}Content-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"{4}Content-Type: {3}{4}{4}",
  163. FormBoundary, file.Name, file.FileName, file.ContentType ?? "application/octet-stream", Environment.NewLine);
  164. }
  165. private string GetMultipartFormData (HttpParameter param)
  166. {
  167. return string.Format ("--{0}{3}Content-Disposition: form-data; name=\"{1}\"{3}{3}{2}{3}",
  168. FormBoundary, param.Name, param.Value, Environment.NewLine);
  169. }
  170. private string GetMultipartFooter ()
  171. {
  172. return string.Format ("--{0}--{1}", FormBoundary, Environment.NewLine);
  173. }
  174. private readonly IDictionary<string, Action<HttpWebRequest, string>> _restrictedHeaderActions;
  175. // handle restricted headers the .NET way - thanks @dimebrain!
  176. // http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.headers.aspx
  177. private void AppendHeaders(HttpWebRequest webRequest)
  178. {
  179. foreach (var header in Headers)
  180. {
  181. if (_restrictedHeaderActions.ContainsKey(header.Name))
  182. {
  183. _restrictedHeaderActions[header.Name].Invoke(webRequest, header.Value);
  184. }
  185. else
  186. {
  187. #if FRAMEWORK
  188. webRequest.Headers.Add(header.Name, header.Value);
  189. #else
  190. webRequest.Headers[header.Name] = header.Value;
  191. #endif
  192. }
  193. }
  194. }
  195. private void AppendCookies(HttpWebRequest webRequest)
  196. {
  197. webRequest.CookieContainer = new CookieContainer();
  198. foreach (var httpCookie in Cookies)
  199. {
  200. var cookie = new Cookie
  201. {
  202. Name = httpCookie.Name,
  203. Value = httpCookie.Value,
  204. Domain = webRequest.RequestUri.Host
  205. };
  206. #if FRAMEWORK
  207. webRequest.CookieContainer.Add(cookie);
  208. #else
  209. var uri = webRequest.RequestUri;
  210. webRequest.CookieContainer.Add(new Uri(string.Format("{0}://{1}", uri.Scheme, uri.Host)), cookie);
  211. #endif
  212. }
  213. }
  214. private string EncodeParameters()
  215. {
  216. var querystring = new StringBuilder();
  217. foreach (var p in Parameters)
  218. {
  219. if (querystring.Length > 1)
  220. querystring.Append("&");
  221. querystring.AppendFormat("{0}={1}", p.Name.UrlEncode(), ((string)p.Value).UrlEncode());
  222. }
  223. return querystring.ToString();
  224. }
  225. private void PreparePostBody (HttpWebRequest webRequest)
  226. {
  227. if (HasFiles)
  228. {
  229. webRequest.ContentType = GetMultipartFormContentType();
  230. }
  231. else if (HasParameters)
  232. {
  233. webRequest.ContentType = "application/x-www-form-urlencoded";
  234. RequestBody = EncodeParameters();
  235. }
  236. else if (HasBody)
  237. {
  238. webRequest.ContentType = RequestContentType;
  239. }
  240. }
  241. private void ExtractResponseData(HttpResponse response, HttpWebResponse webResponse)
  242. {
  243. using (webResponse)
  244. {
  245. #if FRAMEWORK
  246. response.ContentEncoding = webResponse.ContentEncoding;
  247. response.Server = webResponse.Server;
  248. #endif
  249. response.ContentType = webResponse.ContentType;
  250. response.ContentLength = webResponse.ContentLength;
  251. response.RawBytes = webResponse.GetResponseStream().ReadAsBytes();
  252. response.Content = GetString(response.RawBytes);
  253. response.StatusCode = webResponse.StatusCode;
  254. response.StatusDescription = webResponse.StatusDescription;
  255. response.ResponseUri = webResponse.ResponseUri;
  256. response.ResponseStatus = ResponseStatus.Completed;
  257. if (webResponse.Cookies != null)
  258. {
  259. foreach (Cookie cookie in webResponse.Cookies)
  260. {
  261. response.Cookies.Add(new HttpCookie {
  262. Comment = cookie.Comment,
  263. CommentUri = cookie.CommentUri,
  264. Discard = cookie.Discard,
  265. Domain = cookie.Domain,
  266. Expired = cookie.Expired,
  267. Expires = cookie.Expires,
  268. HttpOnly = cookie.HttpOnly,
  269. Name = cookie.Name,
  270. Path = cookie.Path,
  271. Port = cookie.Port,
  272. Secure = cookie.Secure,
  273. TimeStamp = cookie.TimeStamp,
  274. Value = cookie.Value,
  275. Version = cookie.Version
  276. });
  277. }
  278. }
  279. foreach (var headerName in webResponse.Headers.AllKeys)
  280. {
  281. var headerValue = webResponse.Headers[headerName];
  282. response.Headers.Add(new HttpHeader { Name = headerName, Value = headerValue });
  283. }
  284. webResponse.Close();
  285. }
  286. }
  287. /// <summary>
  288. /// Converts a byte array to a string, using its byte order mark to convert it to the right encoding.
  289. /// http://www.shrinkrays.net/code-snippets/csharp/an-extension-method-for-converting-a-byte-array-to-a-string.aspx
  290. /// </summary>
  291. /// <param name="buffer">An array of bytes to convert</param>
  292. /// <returns>The byte as a string.</returns>
  293. public string GetString(byte[] buffer)
  294. {
  295. if (buffer == null || buffer.Length == 0)
  296. return "";
  297. // Ansi as default
  298. Encoding encoding = Encoding.UTF8;
  299. /*
  300. EF BB BF UTF-8
  301. FF FE UTF-16 little endian
  302. FE FF UTF-16 big endian
  303. FF FE 00 00 UTF-32, little endian
  304. 00 00 FE FF UTF-32, big-endian
  305. */
  306. if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
  307. {
  308. encoding = Encoding.UTF8;
  309. }
  310. else if (buffer[0] == 0xfe && buffer[1] == 0xff)
  311. {
  312. encoding = Encoding.Unicode;
  313. }
  314. else if (buffer[0] == 0xfe && buffer[1] == 0xff)
  315. {
  316. encoding = Encoding.BigEndianUnicode; // utf-16be
  317. }
  318. #if FRAMEWORK
  319. else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
  320. {
  321. encoding = Encoding.UTF32;
  322. }
  323. else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
  324. {
  325. encoding = Encoding.UTF7;
  326. }
  327. #endif
  328. using (MemoryStream stream = new MemoryStream())
  329. {
  330. stream.Write(buffer, 0, buffer.Length);
  331. stream.Seek(0, SeekOrigin.Begin);
  332. using (StreamReader reader = new StreamReader(stream, encoding))
  333. {
  334. return reader.ReadToEnd();
  335. }
  336. }
  337. }
  338. }
  339. }