HttpWebResponse.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. //
  2. // System.Net.HttpWebResponse
  3. //
  4. // Authors:
  5. // Lawrence Pit ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. //
  8. // (c) 2002 Lawrence Pit
  9. // (c) 2003 Ximian, Inc. (http://www.ximian.com)
  10. //
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System;
  32. using System.Globalization;
  33. using System.IO;
  34. using System.Net.Sockets;
  35. using System.Runtime.Serialization;
  36. using System.Text;
  37. namespace System.Net
  38. {
  39. [Serializable]
  40. public class HttpWebResponse : WebResponse, ISerializable, IDisposable
  41. {
  42. Uri uri;
  43. WebHeaderCollection webHeaders;
  44. CookieCollection cookieCollection;
  45. string method;
  46. Version version;
  47. HttpStatusCode statusCode;
  48. string statusDescription;
  49. long contentLength = -1;
  50. string contentType;
  51. bool disposed = false;
  52. Stream stream;
  53. // Constructors
  54. internal HttpWebResponse (Uri uri, string method, WebConnectionData data, bool cookiesSet)
  55. {
  56. this.uri = uri;
  57. this.method = method;
  58. webHeaders = data.Headers;
  59. version = data.Version;
  60. statusCode = (HttpStatusCode) data.StatusCode;
  61. statusDescription = data.StatusDescription;
  62. stream = data.stream;
  63. if (cookiesSet) {
  64. FillCookies ();
  65. } else if (webHeaders != null) {
  66. webHeaders.RemoveInternal ("Set-Cookie");
  67. webHeaders.RemoveInternal ("Set-Cookie2");
  68. }
  69. }
  70. protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
  71. {
  72. SerializationInfo info = serializationInfo;
  73. uri = (Uri) info.GetValue ("uri", typeof (Uri));
  74. contentLength = info.GetInt64 ("contentLength");
  75. contentType = info.GetString ("contentType");
  76. method = info.GetString ("method");
  77. statusDescription = info.GetString ("statusDescription");
  78. cookieCollection = (CookieCollection) info.GetValue ("cookieCollection", typeof (CookieCollection));
  79. version = (Version) info.GetValue ("version", typeof (Version));
  80. statusCode = (HttpStatusCode) info.GetValue ("statusCode", typeof (HttpStatusCode));
  81. }
  82. // Properties
  83. public string CharacterSet {
  84. // Content-Type = "Content-Type" ":" media-type
  85. // media-type = type "/" subtype *( ";" parameter )
  86. // parameter = attribute "=" value
  87. // 3.7.1. default is ISO-8859-1
  88. get {
  89. CheckDisposed ();
  90. string contentType = ContentType;
  91. if (contentType == null)
  92. return "ISO-8859-1";
  93. string val = contentType.ToLower ();
  94. int pos = val.IndexOf ("charset=");
  95. if (pos == -1)
  96. return "ISO-8859-1";
  97. pos += 8;
  98. int pos2 = val.IndexOf (';', pos);
  99. return (pos2 == -1)
  100. ? contentType.Substring (pos)
  101. : contentType.Substring (pos, pos2 - pos);
  102. }
  103. }
  104. public string ContentEncoding {
  105. get {
  106. CheckDisposed ();
  107. return webHeaders ["Content-Encoding"];
  108. }
  109. }
  110. public override long ContentLength {
  111. get {
  112. CheckDisposed ();
  113. if (contentLength != -1)
  114. return contentLength;
  115. try {
  116. contentLength = (long) UInt64.Parse (webHeaders ["Content-Length"]);
  117. } catch (Exception) {
  118. return -1;
  119. }
  120. return contentLength;
  121. }
  122. }
  123. public override string ContentType {
  124. get {
  125. CheckDisposed ();
  126. if (contentType == null)
  127. contentType = webHeaders ["Content-Type"];
  128. return contentType;
  129. }
  130. }
  131. public CookieCollection Cookies {
  132. get {
  133. CheckDisposed ();
  134. if (cookieCollection == null)
  135. cookieCollection = new CookieCollection ();
  136. return cookieCollection;
  137. }
  138. set {
  139. CheckDisposed ();
  140. cookieCollection = value;
  141. }
  142. }
  143. public override WebHeaderCollection Headers {
  144. get {
  145. CheckDisposed ();
  146. return webHeaders;
  147. }
  148. }
  149. public DateTime LastModified {
  150. get {
  151. CheckDisposed ();
  152. try {
  153. string dtStr = webHeaders ["Last-Modified"];
  154. return MonoHttpDate.Parse (dtStr);
  155. } catch (Exception) {
  156. return DateTime.Now;
  157. }
  158. }
  159. }
  160. public string Method {
  161. get {
  162. CheckDisposed ();
  163. return method;
  164. }
  165. }
  166. public Version ProtocolVersion {
  167. get {
  168. CheckDisposed ();
  169. return version;
  170. }
  171. }
  172. public override Uri ResponseUri {
  173. get {
  174. CheckDisposed ();
  175. return uri;
  176. }
  177. }
  178. public string Server {
  179. get {
  180. CheckDisposed ();
  181. return webHeaders ["Server"];
  182. }
  183. }
  184. public HttpStatusCode StatusCode {
  185. get {
  186. CheckDisposed ();
  187. return statusCode;
  188. }
  189. }
  190. public string StatusDescription {
  191. get {
  192. CheckDisposed ();
  193. return statusDescription;
  194. }
  195. }
  196. // Methods
  197. public override int GetHashCode ()
  198. {
  199. CheckDisposed ();
  200. return base.GetHashCode ();
  201. }
  202. public string GetResponseHeader (string headerName)
  203. {
  204. CheckDisposed ();
  205. string value = webHeaders [headerName];
  206. return (value != null) ? value : "";
  207. }
  208. internal void ReadAll ()
  209. {
  210. WebConnectionStream wce = stream as WebConnectionStream;
  211. if (wce == null)
  212. return;
  213. try {
  214. wce.ReadAll ();
  215. } catch {}
  216. }
  217. public override Stream GetResponseStream ()
  218. {
  219. CheckDisposed ();
  220. if (stream == null)
  221. return Stream.Null;
  222. if (0 == String.Compare (method, "HEAD", true)) // see par 4.3 & 9.4
  223. return Stream.Null;
  224. return stream;
  225. }
  226. void ISerializable.GetObjectData (SerializationInfo serializationInfo,
  227. StreamingContext streamingContext)
  228. {
  229. SerializationInfo info = serializationInfo;
  230. info.AddValue ("uri", uri);
  231. info.AddValue ("contentLength", contentLength);
  232. info.AddValue ("contentType", contentType);
  233. info.AddValue ("method", method);
  234. info.AddValue ("statusDescription", statusDescription);
  235. info.AddValue ("cookieCollection", cookieCollection);
  236. info.AddValue ("version", version);
  237. info.AddValue ("statusCode", statusCode);
  238. }
  239. // Cleaning up stuff
  240. public override void Close ()
  241. {
  242. ((IDisposable) this).Dispose ();
  243. }
  244. void IDisposable.Dispose ()
  245. {
  246. Dispose (true);
  247. GC.SuppressFinalize (this);
  248. }
  249. protected virtual void Dispose (bool disposing)
  250. {
  251. if (this.disposed)
  252. return;
  253. this.disposed = true;
  254. if (disposing) {
  255. // release managed resources
  256. uri = null;
  257. webHeaders = null;
  258. cookieCollection = null;
  259. method = null;
  260. version = null;
  261. statusDescription = null;
  262. }
  263. // release unmanaged resources
  264. Stream st = stream;
  265. stream = null;
  266. if (st != null) {
  267. WebConnectionStream wce = st as WebConnectionStream;
  268. if (wce != null) {
  269. try {
  270. wce.ReadAll ();
  271. } catch {}
  272. }
  273. st.Close ();
  274. }
  275. }
  276. private void CheckDisposed ()
  277. {
  278. if (disposed)
  279. throw new ObjectDisposedException (GetType ().FullName);
  280. }
  281. void FillCookies ()
  282. {
  283. if (webHeaders == null)
  284. return;
  285. string [] values = webHeaders.GetValues ("Set-Cookie");
  286. if (values != null) {
  287. foreach (string va in values)
  288. SetCookie (va);
  289. }
  290. values = webHeaders.GetValues ("Set-Cookie2");
  291. if (values != null) {
  292. foreach (string va in values)
  293. SetCookie2 (va);
  294. }
  295. }
  296. void SetCookie (string header)
  297. {
  298. string [] name_values = header.Trim ().Split (';');
  299. int length = name_values.Length;
  300. Cookie cookie = null;
  301. int pos;
  302. for (int i = 0; i < length; i++) {
  303. pos = 0;
  304. string name_value = name_values [i].Trim ();
  305. if (name_value == "")
  306. continue;
  307. string name = GetCookieName (name_value, name_value.Length, ref pos);
  308. string value = GetCookieValue (name_value, name_value.Length, ref pos);
  309. if (cookie == null) {
  310. cookie = new Cookie (name, value);
  311. continue;
  312. }
  313. name = name.ToUpper ();
  314. switch (name) {
  315. case "COMMENT":
  316. if (cookie.Comment == null)
  317. cookie.Comment = value;
  318. break;
  319. case "COMMENTURL":
  320. if (cookie.CommentUri == null)
  321. cookie.CommentUri = new Uri (value);
  322. break;
  323. case "DISCARD":
  324. cookie.Discard = true;
  325. break;
  326. case "DOMAIN":
  327. if (cookie.Domain == "")
  328. cookie.Domain = value;
  329. break;
  330. case "MAX-AGE": // RFC Style Set-Cookie2
  331. if (cookie.Expires == DateTime.MinValue)
  332. cookie.Expires = cookie.TimeStamp.AddSeconds (Int32.Parse (value));
  333. break;
  334. case "EXPIRES": // Netscape Style Set-Cookie
  335. if (cookie.Expires != DateTime.MinValue)
  336. break;
  337. try {
  338. cookie.Expires = DateTime.ParseExact (value, "r", CultureInfo.InvariantCulture);
  339. } catch {
  340. try {
  341. cookie.Expires = DateTime.ParseExact (value,
  342. "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
  343. CultureInfo.InvariantCulture);
  344. } catch {
  345. cookie.Expires = DateTime.Now.AddDays (1);
  346. }
  347. }
  348. break;
  349. case "PATH":
  350. cookie.Path = value;
  351. break;
  352. case "PORT":
  353. if (cookie.Port == null)
  354. cookie.Port = value;
  355. break;
  356. case "SECURE":
  357. cookie.Secure = true;
  358. break;
  359. case "VERSION":
  360. cookie.Version = Int32.Parse (value);
  361. break;
  362. }
  363. }
  364. if (cookieCollection == null)
  365. cookieCollection = new CookieCollection ();
  366. if (cookie.Domain == "")
  367. cookie.Domain = uri.Host;
  368. cookieCollection.Add (cookie);
  369. }
  370. void SetCookie2 (string cookies_str)
  371. {
  372. string [] cookies = cookies_str.Split (',');
  373. foreach (string cookie_str in cookies)
  374. SetCookie (cookie_str);
  375. }
  376. static string GetCookieValue (string str, int length, ref int i)
  377. {
  378. if (i >= length)
  379. return null;
  380. int k = i;
  381. while (k < length && Char.IsWhiteSpace (str [k]))
  382. k++;
  383. int begin = k;
  384. while (k < length && str [k] != ';')
  385. k++;
  386. i = k;
  387. return str.Substring (begin, i - begin).Trim ();
  388. }
  389. static string GetCookieName (string str, int length, ref int i)
  390. {
  391. if (i >= length)
  392. return null;
  393. int k = i;
  394. while (k < length && Char.IsWhiteSpace (str [k]))
  395. k++;
  396. int begin = k;
  397. while (k < length && str [k] != ';' && str [k] != '=')
  398. k++;
  399. i = k + 1;
  400. return str.Substring (begin, k - begin).Trim ();
  401. }
  402. }
  403. }