HttpWebResponse.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. //
  2. // System.Net.HttpWebResponse
  3. //
  4. // Authors:
  5. // Lawrence Pit ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. // Daniel Nauck (dna(at)mono-project(dot)de)
  8. //
  9. // (c) 2002 Lawrence Pit
  10. // (c) 2003 Ximian, Inc. (http://www.ximian.com)
  11. // (c) 2008 Daniel Nauck
  12. //
  13. //
  14. // Permission is hereby granted, free of charge, to any person obtaining
  15. // a copy of this software and associated documentation files (the
  16. // "Software"), to deal in the Software without restriction, including
  17. // without limitation the rights to use, copy, modify, merge, publish,
  18. // distribute, sublicense, and/or sell copies of the Software, and to
  19. // permit persons to whom the Software is furnished to do so, subject to
  20. // the following conditions:
  21. //
  22. // The above copyright notice and this permission notice shall be
  23. // included in all copies or substantial portions of the Software.
  24. //
  25. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  28. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  29. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  30. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  31. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  32. //
  33. using System;
  34. using System.Collections;
  35. using System.Globalization;
  36. using System.IO;
  37. using System.IO.Compression;
  38. using System.Net.Sockets;
  39. using System.Runtime.Serialization;
  40. using System.Text;
  41. namespace System.Net
  42. {
  43. [Serializable]
  44. public class HttpWebResponse : WebResponse, ISerializable, IDisposable {
  45. Uri uri;
  46. WebHeaderCollection webHeaders;
  47. CookieCollection cookieCollection;
  48. string method;
  49. Version version;
  50. HttpStatusCode statusCode;
  51. string statusDescription;
  52. long contentLength;
  53. string contentType;
  54. CookieContainer cookie_container;
  55. bool disposed;
  56. Stream stream;
  57. // Constructors
  58. internal HttpWebResponse (Uri uri, string method, WebConnectionData data, CookieContainer container)
  59. {
  60. this.uri = uri;
  61. this.method = method;
  62. webHeaders = data.Headers;
  63. version = data.Version;
  64. statusCode = (HttpStatusCode) data.StatusCode;
  65. statusDescription = data.StatusDescription;
  66. stream = data.stream;
  67. contentLength = -1;
  68. try {
  69. string cl = webHeaders ["Content-Length"];
  70. if (String.IsNullOrEmpty (cl) || !Int64.TryParse (cl, out contentLength))
  71. contentLength = -1;
  72. } catch (Exception) {
  73. contentLength = -1;
  74. }
  75. if (container != null) {
  76. this.cookie_container = container;
  77. FillCookies ();
  78. }
  79. string content_encoding = webHeaders ["Content-Encoding"];
  80. if (content_encoding == "gzip" && (data.request.AutomaticDecompression & DecompressionMethods.GZip) != 0)
  81. stream = new GZipStream (stream, CompressionMode.Decompress);
  82. else if (content_encoding == "deflate" && (data.request.AutomaticDecompression & DecompressionMethods.Deflate) != 0)
  83. stream = new DeflateStream (stream, CompressionMode.Decompress);
  84. }
  85. [Obsolete ("Serialization is obsoleted for this type", false)]
  86. protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
  87. {
  88. SerializationInfo info = serializationInfo;
  89. uri = (Uri) info.GetValue ("uri", typeof (Uri));
  90. contentLength = info.GetInt64 ("contentLength");
  91. contentType = info.GetString ("contentType");
  92. method = info.GetString ("method");
  93. statusDescription = info.GetString ("statusDescription");
  94. cookieCollection = (CookieCollection) info.GetValue ("cookieCollection", typeof (CookieCollection));
  95. version = (Version) info.GetValue ("version", typeof (Version));
  96. statusCode = (HttpStatusCode) info.GetValue ("statusCode", typeof (HttpStatusCode));
  97. }
  98. // Properties
  99. public string CharacterSet {
  100. // Content-Type = "Content-Type" ":" media-type
  101. // media-type = type "/" subtype *( ";" parameter )
  102. // parameter = attribute "=" value
  103. // 3.7.1. default is ISO-8859-1
  104. get {
  105. string contentType = ContentType;
  106. if (contentType == null)
  107. return "ISO-8859-1";
  108. string val = contentType.ToLower ();
  109. int pos = val.IndexOf ("charset=", StringComparison.Ordinal);
  110. if (pos == -1)
  111. return "ISO-8859-1";
  112. pos += 8;
  113. int pos2 = val.IndexOf (';', pos);
  114. return (pos2 == -1)
  115. ? contentType.Substring (pos)
  116. : contentType.Substring (pos, pos2 - pos);
  117. }
  118. }
  119. public string ContentEncoding {
  120. get {
  121. CheckDisposed ();
  122. string h = webHeaders ["Content-Encoding"];
  123. return h != null ? h : "";
  124. }
  125. }
  126. public override long ContentLength {
  127. get {
  128. return contentLength;
  129. }
  130. }
  131. public override string ContentType {
  132. get {
  133. CheckDisposed ();
  134. if (contentType == null)
  135. contentType = webHeaders ["Content-Type"];
  136. return contentType;
  137. }
  138. }
  139. #if NET_4_5
  140. virtual
  141. #endif
  142. public CookieCollection Cookies {
  143. get {
  144. CheckDisposed ();
  145. if (cookieCollection == null)
  146. cookieCollection = new CookieCollection ();
  147. return cookieCollection;
  148. }
  149. set {
  150. CheckDisposed ();
  151. cookieCollection = value;
  152. }
  153. }
  154. public override WebHeaderCollection Headers {
  155. get {
  156. return webHeaders;
  157. }
  158. }
  159. static Exception GetMustImplement ()
  160. {
  161. return new NotImplementedException ();
  162. }
  163. [MonoTODO]
  164. public override bool IsMutuallyAuthenticated
  165. {
  166. get {
  167. throw GetMustImplement ();
  168. }
  169. }
  170. public DateTime LastModified {
  171. get {
  172. CheckDisposed ();
  173. try {
  174. string dtStr = webHeaders ["Last-Modified"];
  175. return MonoHttpDate.Parse (dtStr);
  176. } catch (Exception) {
  177. return DateTime.Now;
  178. }
  179. }
  180. }
  181. #if NET_4_5
  182. virtual
  183. #endif
  184. public string Method {
  185. get {
  186. CheckDisposed ();
  187. return method;
  188. }
  189. }
  190. public Version ProtocolVersion {
  191. get {
  192. CheckDisposed ();
  193. return version;
  194. }
  195. }
  196. public override Uri ResponseUri {
  197. get {
  198. CheckDisposed ();
  199. return uri;
  200. }
  201. }
  202. public string Server {
  203. get {
  204. CheckDisposed ();
  205. return webHeaders ["Server"];
  206. }
  207. }
  208. #if NET_4_5
  209. virtual
  210. #endif
  211. public HttpStatusCode StatusCode {
  212. get {
  213. return statusCode;
  214. }
  215. }
  216. #if NET_4_5
  217. virtual
  218. #endif
  219. public string StatusDescription {
  220. get {
  221. CheckDisposed ();
  222. return statusDescription;
  223. }
  224. }
  225. // Methods
  226. public string GetResponseHeader (string headerName)
  227. {
  228. CheckDisposed ();
  229. string value = webHeaders [headerName];
  230. return (value != null) ? value : "";
  231. }
  232. internal void ReadAll ()
  233. {
  234. WebConnectionStream wce = stream as WebConnectionStream;
  235. if (wce == null)
  236. return;
  237. try {
  238. wce.ReadAll ();
  239. } catch {}
  240. }
  241. public override Stream GetResponseStream ()
  242. {
  243. CheckDisposed ();
  244. if (stream == null)
  245. return Stream.Null;
  246. if (string.Equals (method, "HEAD", StringComparison.OrdinalIgnoreCase)) // see par 4.3 & 9.4
  247. return Stream.Null;
  248. return stream;
  249. }
  250. void ISerializable.GetObjectData (SerializationInfo serializationInfo,
  251. StreamingContext streamingContext)
  252. {
  253. GetObjectData (serializationInfo, streamingContext);
  254. }
  255. protected override void GetObjectData (SerializationInfo serializationInfo,
  256. StreamingContext streamingContext)
  257. {
  258. SerializationInfo info = serializationInfo;
  259. info.AddValue ("uri", uri);
  260. info.AddValue ("contentLength", contentLength);
  261. info.AddValue ("contentType", contentType);
  262. info.AddValue ("method", method);
  263. info.AddValue ("statusDescription", statusDescription);
  264. info.AddValue ("cookieCollection", cookieCollection);
  265. info.AddValue ("version", version);
  266. info.AddValue ("statusCode", statusCode);
  267. }
  268. // Cleaning up stuff
  269. public override void Close ()
  270. {
  271. if (stream != null) {
  272. Stream st = stream;
  273. stream = null;
  274. if (st != null)
  275. st.Close ();
  276. }
  277. }
  278. void IDisposable.Dispose ()
  279. {
  280. Dispose (true);
  281. }
  282. #if NET_4_0
  283. protected override void Dispose (bool disposing)
  284. {
  285. this.disposed = true;
  286. base.Dispose (true);
  287. }
  288. #else
  289. void Dispose (bool disposing)
  290. {
  291. this.disposed = true;
  292. if (disposing)
  293. Close ();
  294. }
  295. #endif
  296. private void CheckDisposed ()
  297. {
  298. if (disposed)
  299. throw new ObjectDisposedException (GetType ().FullName);
  300. }
  301. void FillCookies ()
  302. {
  303. if (webHeaders == null)
  304. return;
  305. string value = webHeaders.Get ("Set-Cookie");
  306. if (value != null) {
  307. SetCookie (value);
  308. }
  309. value = webHeaders.Get ("Set-Cookie2");
  310. if (value != null) {
  311. SetCookie (value);
  312. }
  313. }
  314. void SetCookie (string header)
  315. {
  316. if (cookieCollection == null)
  317. cookieCollection = new CookieCollection ();
  318. var parser = new CookieParser (header);
  319. foreach (var cookie in parser.Parse ()) {
  320. if (cookie.Domain == "") {
  321. cookie.Domain = uri.Host;
  322. cookie.HasDomain = false;
  323. }
  324. if (cookie.HasDomain &&
  325. !CookieContainer.CheckSameOrigin (uri, cookie.Domain))
  326. continue;
  327. cookieCollection.Add (cookie);
  328. if (cookie_container != null)
  329. cookie_container.Add (uri, cookie);
  330. }
  331. }
  332. }
  333. }