HttpWebResponse.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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.IO;
  33. using System.Net.Sockets;
  34. using System.Runtime.Serialization;
  35. using System.Text;
  36. namespace System.Net
  37. {
  38. [Serializable]
  39. public class HttpWebResponse : WebResponse, ISerializable, IDisposable
  40. {
  41. Uri uri;
  42. WebHeaderCollection webHeaders;
  43. CookieCollection cookieCollection;
  44. string method;
  45. Version version;
  46. HttpStatusCode statusCode;
  47. string statusDescription;
  48. long contentLength = -1;
  49. string contentType;
  50. bool disposed = false;
  51. Stream stream;
  52. // Constructors
  53. internal HttpWebResponse (Uri uri, string method, WebConnectionData data, bool cookiesSet)
  54. {
  55. this.uri = uri;
  56. this.method = method;
  57. webHeaders = data.Headers;
  58. version = data.Version;
  59. statusCode = (HttpStatusCode) data.StatusCode;
  60. statusDescription = data.StatusDescription;
  61. stream = data.stream;
  62. if (cookiesSet) {
  63. FillCookies ();
  64. } else if (webHeaders != null) {
  65. webHeaders.RemoveInternal ("Set-Cookie");
  66. webHeaders.RemoveInternal ("Set-Cookie2");
  67. }
  68. }
  69. protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
  70. {
  71. SerializationInfo info = serializationInfo;
  72. uri = (Uri) info.GetValue ("uri", typeof (Uri));
  73. contentLength = info.GetInt64 ("contentLength");
  74. contentType = info.GetString ("contentType");
  75. method = info.GetString ("method");
  76. statusDescription = info.GetString ("statusDescription");
  77. cookieCollection = (CookieCollection) info.GetValue ("cookieCollection", typeof (CookieCollection));
  78. version = (Version) info.GetValue ("version", typeof (Version));
  79. statusCode = (HttpStatusCode) info.GetValue ("statusCode", typeof (HttpStatusCode));
  80. }
  81. // Properties
  82. public string CharacterSet {
  83. // Content-Type = "Content-Type" ":" media-type
  84. // media-type = type "/" subtype *( ";" parameter )
  85. // parameter = attribute "=" value
  86. // 3.7.1. default is ISO-8859-1
  87. get {
  88. CheckDisposed ();
  89. string contentType = ContentType;
  90. if (contentType == null)
  91. return "ISO-8859-1";
  92. string val = contentType.ToLower ();
  93. int pos = val.IndexOf ("charset=");
  94. if (pos == -1)
  95. return "ISO-8859-1";
  96. pos += 8;
  97. int pos2 = val.IndexOf (';', pos);
  98. return (pos2 == -1)
  99. ? contentType.Substring (pos)
  100. : contentType.Substring (pos, pos2 - pos);
  101. }
  102. }
  103. public string ContentEncoding {
  104. get {
  105. CheckDisposed ();
  106. return webHeaders ["Content-Encoding"];
  107. }
  108. }
  109. public override long ContentLength {
  110. get {
  111. CheckDisposed ();
  112. if (contentLength != -1)
  113. return contentLength;
  114. try {
  115. contentLength = (long) UInt64.Parse (webHeaders ["Content-Length"]);
  116. } catch (Exception) {
  117. return -1;
  118. }
  119. return contentLength;
  120. }
  121. }
  122. public override string ContentType {
  123. get {
  124. CheckDisposed ();
  125. if (contentType == null)
  126. contentType = webHeaders ["Content-Type"];
  127. return contentType;
  128. }
  129. }
  130. public CookieCollection Cookies {
  131. get {
  132. CheckDisposed ();
  133. if (cookieCollection == null)
  134. cookieCollection = new CookieCollection ();
  135. return cookieCollection;
  136. }
  137. set {
  138. CheckDisposed ();
  139. cookieCollection = value;
  140. }
  141. }
  142. public override WebHeaderCollection Headers {
  143. get {
  144. CheckDisposed ();
  145. return webHeaders;
  146. }
  147. }
  148. public DateTime LastModified {
  149. get {
  150. CheckDisposed ();
  151. try {
  152. string dtStr = webHeaders ["Last-Modified"];
  153. return MonoHttpDate.Parse (dtStr);
  154. } catch (Exception) {
  155. return DateTime.Now;
  156. }
  157. }
  158. }
  159. public string Method {
  160. get {
  161. CheckDisposed ();
  162. return method;
  163. }
  164. }
  165. public Version ProtocolVersion {
  166. get {
  167. CheckDisposed ();
  168. return version;
  169. }
  170. }
  171. public override Uri ResponseUri {
  172. get {
  173. CheckDisposed ();
  174. return uri;
  175. }
  176. }
  177. public string Server {
  178. get {
  179. CheckDisposed ();
  180. return webHeaders ["Server"];
  181. }
  182. }
  183. public HttpStatusCode StatusCode {
  184. get {
  185. CheckDisposed ();
  186. return statusCode;
  187. }
  188. }
  189. public string StatusDescription {
  190. get {
  191. CheckDisposed ();
  192. return statusDescription;
  193. }
  194. }
  195. // Methods
  196. public override int GetHashCode ()
  197. {
  198. CheckDisposed ();
  199. return base.GetHashCode ();
  200. }
  201. public string GetResponseHeader (string headerName)
  202. {
  203. CheckDisposed ();
  204. string value = webHeaders [headerName];
  205. return (value != null) ? value : "";
  206. }
  207. public override Stream GetResponseStream ()
  208. {
  209. CheckDisposed ();
  210. if (stream == null)
  211. return Stream.Null;
  212. if (0 == String.Compare (method, "HEAD", true)) // see par 4.3 & 9.4
  213. return Stream.Null;
  214. return stream;
  215. }
  216. void ISerializable.GetObjectData (SerializationInfo serializationInfo,
  217. StreamingContext streamingContext)
  218. {
  219. SerializationInfo info = serializationInfo;
  220. info.AddValue ("uri", uri);
  221. info.AddValue ("contentLength", contentLength);
  222. info.AddValue ("contentType", contentType);
  223. info.AddValue ("method", method);
  224. info.AddValue ("statusDescription", statusDescription);
  225. info.AddValue ("cookieCollection", cookieCollection);
  226. info.AddValue ("version", version);
  227. info.AddValue ("statusCode", statusCode);
  228. }
  229. // Cleaning up stuff
  230. public override void Close ()
  231. {
  232. ((IDisposable) this).Dispose ();
  233. }
  234. void IDisposable.Dispose ()
  235. {
  236. Dispose (true);
  237. GC.SuppressFinalize (this);
  238. }
  239. protected virtual void Dispose (bool disposing)
  240. {
  241. if (this.disposed)
  242. return;
  243. this.disposed = true;
  244. if (disposing) {
  245. // release managed resources
  246. uri = null;
  247. webHeaders = null;
  248. cookieCollection = null;
  249. method = null;
  250. version = null;
  251. statusDescription = null;
  252. }
  253. // release unmanaged resources
  254. Stream st = stream;
  255. stream = null;
  256. if (st != null) {
  257. WebConnectionStream wce = st as WebConnectionStream;
  258. if (wce != null) {
  259. try {
  260. wce.ReadAll ();
  261. } catch {}
  262. }
  263. st.Close ();
  264. }
  265. }
  266. private void CheckDisposed ()
  267. {
  268. if (disposed)
  269. throw new ObjectDisposedException (GetType ().FullName);
  270. }
  271. void FillCookies ()
  272. {
  273. if (webHeaders == null)
  274. return;
  275. string val = webHeaders ["Set-Cookie"];
  276. if (val != null && val.Trim () != "")
  277. SetCookie (val);
  278. val = webHeaders ["Set-Cookie2"];
  279. if (val != null && val.Trim () != "")
  280. SetCookie2 (val);
  281. }
  282. static string [] SplitValue (string input)
  283. {
  284. string [] result = new string [2];
  285. int eq = input.IndexOf ('=');
  286. if (eq == -1) {
  287. result [0] = "invalid";
  288. } else {
  289. result [0] = input.Substring (0, eq).Trim ().ToUpper ();
  290. result [1] = input.Substring (eq + 1);
  291. }
  292. return result;
  293. }
  294. [MonoTODO ("Parse dates")]
  295. void SetCookie (string cookie_str)
  296. {
  297. string[] parts = null;
  298. Collections.Queue options = null;
  299. Cookie cookie = null;
  300. options = new Collections.Queue (cookie_str.Split (';'));
  301. parts = SplitValue ((string) options.Dequeue()); // NAME=VALUE must be first
  302. cookie = new Cookie (parts[0], parts[1]);
  303. while (options.Count > 0) {
  304. parts = SplitValue ((string) options.Dequeue());
  305. switch (parts [0]) {
  306. case "COMMENT":
  307. if (cookie.Comment == null)
  308. cookie.Comment = parts[1];
  309. break;
  310. case "COMMENTURL":
  311. if (cookie.CommentUri == null)
  312. cookie.CommentUri = new Uri(parts[1]);
  313. break;
  314. case "DISCARD":
  315. cookie.Discard = true;
  316. break;
  317. case "DOMAIN":
  318. if (cookie.Domain == "")
  319. cookie.Domain = parts[1];
  320. break;
  321. case "MAX-AGE": // RFC Style Set-Cookie2
  322. if (cookie.Expires == DateTime.MinValue)
  323. cookie.Expires = cookie.TimeStamp.AddSeconds (Int32.Parse (parts[1]));
  324. break;
  325. case "EXPIRES": // Netscape Style Set-Cookie
  326. if (cookie.Expires == DateTime.MinValue) {
  327. //FIXME: Does DateTime parse something like: "Sun, 17-Jan-2038 19:14:07 GMT"?
  328. //cookie.Expires = DateTime.ParseExact (parts[1]);
  329. cookie.Expires = DateTime.Now.AddDays (1);
  330. }
  331. break;
  332. case "PATH":
  333. cookie.Path = parts[1];
  334. break;
  335. case "PORT":
  336. if (cookie.Port == null)
  337. cookie.Port = parts[1];
  338. break;
  339. case "SECURE":
  340. cookie.Secure = true;
  341. break;
  342. case "VERSION":
  343. cookie.Version = Int32.Parse (parts[1]);
  344. break;
  345. } // switch
  346. } // while
  347. if (cookieCollection == null)
  348. cookieCollection = new CookieCollection();
  349. if (cookie.Domain == "")
  350. cookie.Domain = uri.Host;
  351. cookieCollection.Add (cookie);
  352. }
  353. void SetCookie2 (string cookies_str)
  354. {
  355. string [] cookies = cookies_str.Split (',');
  356. foreach (string cookie_str in cookies)
  357. SetCookie (cookie_str);
  358. }
  359. }
  360. }