HttpWebResponse.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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.Threading;
  41. using System.Threading.Tasks;
  42. using System.Text;
  43. namespace System.Net
  44. {
  45. [Serializable]
  46. public class HttpWebResponse : WebResponse, ISerializable, IDisposable {
  47. Uri uri;
  48. WebHeaderCollection webHeaders;
  49. CookieCollection cookieCollection;
  50. string method;
  51. Version version;
  52. HttpStatusCode statusCode;
  53. string statusDescription;
  54. long contentLength;
  55. string contentType;
  56. CookieContainer cookie_container;
  57. bool disposed;
  58. Stream stream;
  59. // Constructors
  60. internal HttpWebResponse (Uri uri, string method, HttpStatusCode status, WebHeaderCollection headers)
  61. {
  62. this.uri = uri;
  63. this.method = method;
  64. this.statusCode = status;
  65. this.statusDescription = HttpStatusDescription.Get (status);
  66. this.webHeaders = headers;
  67. version = HttpVersion.Version10;
  68. contentLength = -1;
  69. }
  70. internal HttpWebResponse (Uri uri, string method, WebResponseStream stream, CookieContainer container)
  71. {
  72. this.uri = uri;
  73. this.method = method;
  74. this.stream = stream;
  75. webHeaders = stream.Headers ?? new WebHeaderCollection ();
  76. version = stream.Version;
  77. statusCode = stream.StatusCode;
  78. statusDescription = stream.StatusDescription ?? HttpStatusDescription.Get (statusCode);
  79. contentLength = -1;
  80. try {
  81. string cl = webHeaders ["Content-Length"];
  82. if (String.IsNullOrEmpty (cl) || !Int64.TryParse (cl, out contentLength))
  83. contentLength = -1;
  84. } catch (Exception) {
  85. contentLength = -1;
  86. }
  87. if (container != null) {
  88. this.cookie_container = container;
  89. FillCookies ();
  90. }
  91. string content_encoding = webHeaders ["Content-Encoding"];
  92. if (content_encoding == "gzip" && (stream.Request.AutomaticDecompression & DecompressionMethods.GZip) != 0) {
  93. this.stream = new GZipStream (stream, CompressionMode.Decompress);
  94. webHeaders.Remove (HttpRequestHeader.ContentEncoding);
  95. }
  96. else if (content_encoding == "deflate" && (stream.Request.AutomaticDecompression & DecompressionMethods.Deflate) != 0) {
  97. this.stream = new DeflateStream (stream, CompressionMode.Decompress);
  98. webHeaders.Remove (HttpRequestHeader.ContentEncoding);
  99. }
  100. }
  101. [Obsolete ("Serialization is obsoleted for this type", false)]
  102. protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
  103. {
  104. SerializationInfo info = serializationInfo;
  105. uri = (Uri) info.GetValue ("uri", typeof (Uri));
  106. contentLength = info.GetInt64 ("contentLength");
  107. contentType = info.GetString ("contentType");
  108. method = info.GetString ("method");
  109. statusDescription = info.GetString ("statusDescription");
  110. cookieCollection = (CookieCollection) info.GetValue ("cookieCollection", typeof (CookieCollection));
  111. version = (Version) info.GetValue ("version", typeof (Version));
  112. statusCode = (HttpStatusCode) info.GetValue ("statusCode", typeof (HttpStatusCode));
  113. }
  114. // Properties
  115. public string CharacterSet {
  116. // Content-Type = "Content-Type" ":" media-type
  117. // media-type = type "/" subtype *( ";" parameter )
  118. // parameter = attribute "=" value
  119. // 3.7.1. default is ISO-8859-1
  120. get {
  121. string contentType = ContentType;
  122. if (contentType == null)
  123. return "ISO-8859-1";
  124. string val = contentType.ToLower ();
  125. int pos = val.IndexOf ("charset=", StringComparison.Ordinal);
  126. if (pos == -1)
  127. return "ISO-8859-1";
  128. pos += 8;
  129. int pos2 = val.IndexOf (';', pos);
  130. return (pos2 == -1)
  131. ? contentType.Substring (pos)
  132. : contentType.Substring (pos, pos2 - pos);
  133. }
  134. }
  135. public string ContentEncoding {
  136. get {
  137. CheckDisposed ();
  138. string h = webHeaders ["Content-Encoding"];
  139. return h != null ? h : "";
  140. }
  141. }
  142. public override long ContentLength {
  143. get {
  144. return contentLength;
  145. }
  146. }
  147. public override string ContentType {
  148. get {
  149. CheckDisposed ();
  150. if (contentType == null)
  151. contentType = webHeaders ["Content-Type"];
  152. return contentType;
  153. }
  154. }
  155. virtual
  156. public CookieCollection Cookies {
  157. get {
  158. CheckDisposed ();
  159. if (cookieCollection == null)
  160. cookieCollection = new CookieCollection ();
  161. return cookieCollection;
  162. }
  163. set {
  164. CheckDisposed ();
  165. cookieCollection = value;
  166. }
  167. }
  168. public override WebHeaderCollection Headers {
  169. get {
  170. return webHeaders;
  171. }
  172. }
  173. static Exception GetMustImplement ()
  174. {
  175. return new NotImplementedException ();
  176. }
  177. [MonoTODO]
  178. public override bool IsMutuallyAuthenticated
  179. {
  180. get {
  181. throw GetMustImplement ();
  182. }
  183. }
  184. public DateTime LastModified {
  185. get {
  186. CheckDisposed ();
  187. try {
  188. string dtStr = webHeaders ["Last-Modified"];
  189. return MonoHttpDate.Parse (dtStr);
  190. } catch (Exception) {
  191. return DateTime.Now;
  192. }
  193. }
  194. }
  195. virtual
  196. public string Method {
  197. get {
  198. CheckDisposed ();
  199. return method;
  200. }
  201. }
  202. public Version ProtocolVersion {
  203. get {
  204. CheckDisposed ();
  205. return version;
  206. }
  207. }
  208. public override Uri ResponseUri {
  209. get {
  210. CheckDisposed ();
  211. return uri;
  212. }
  213. }
  214. public string Server {
  215. get {
  216. CheckDisposed ();
  217. return webHeaders ["Server"] ?? "";
  218. }
  219. }
  220. virtual
  221. public HttpStatusCode StatusCode {
  222. get {
  223. return statusCode;
  224. }
  225. }
  226. virtual
  227. public string StatusDescription {
  228. get {
  229. CheckDisposed ();
  230. return statusDescription;
  231. }
  232. }
  233. public override bool SupportsHeaders {
  234. get {
  235. return true;
  236. }
  237. }
  238. // Methods
  239. public string GetResponseHeader (string headerName)
  240. {
  241. CheckDisposed ();
  242. string value = webHeaders [headerName];
  243. return (value != null) ? value : "";
  244. }
  245. public override Stream GetResponseStream ()
  246. {
  247. CheckDisposed ();
  248. if (stream == null)
  249. return Stream.Null;
  250. if (string.Equals (method, "HEAD", StringComparison.OrdinalIgnoreCase)) // see par 4.3 & 9.4
  251. return Stream.Null;
  252. return stream;
  253. }
  254. void ISerializable.GetObjectData (SerializationInfo serializationInfo,
  255. StreamingContext streamingContext)
  256. {
  257. GetObjectData (serializationInfo, streamingContext);
  258. }
  259. protected override void GetObjectData (SerializationInfo serializationInfo,
  260. StreamingContext streamingContext)
  261. {
  262. SerializationInfo info = serializationInfo;
  263. info.AddValue ("uri", uri);
  264. info.AddValue ("contentLength", contentLength);
  265. info.AddValue ("contentType", contentType);
  266. info.AddValue ("method", method);
  267. info.AddValue ("statusDescription", statusDescription);
  268. info.AddValue ("cookieCollection", cookieCollection);
  269. info.AddValue ("version", version);
  270. info.AddValue ("statusCode", statusCode);
  271. }
  272. // Cleaning up stuff
  273. public override void Close ()
  274. {
  275. var st = Interlocked.Exchange (ref stream, null);
  276. if (st != null)
  277. st.Close ();
  278. }
  279. void IDisposable.Dispose ()
  280. {
  281. Dispose (true);
  282. }
  283. protected override void Dispose (bool disposing)
  284. {
  285. this.disposed = true;
  286. base.Dispose (true);
  287. }
  288. private void CheckDisposed ()
  289. {
  290. if (disposed)
  291. throw new ObjectDisposedException (GetType ().FullName);
  292. }
  293. void FillCookies ()
  294. {
  295. if (webHeaders == null)
  296. return;
  297. //
  298. // Don't terminate response reading on bad cookie value
  299. //
  300. string value;
  301. CookieCollection cookies = null;
  302. try {
  303. value = webHeaders.Get ("Set-Cookie");
  304. if (value != null)
  305. cookies = cookie_container.CookieCutter (uri, HttpKnownHeaderNames.SetCookie, value, false);
  306. } catch {
  307. }
  308. try {
  309. value = webHeaders.Get ("Set-Cookie2");
  310. if (value != null) {
  311. var cookies2 = cookie_container.CookieCutter (uri, HttpKnownHeaderNames.SetCookie2, value, false);
  312. if (cookies != null && cookies.Count != 0) {
  313. cookies.Add (cookies2);
  314. } else {
  315. cookies = cookies2;
  316. }
  317. }
  318. } catch {
  319. }
  320. this.cookieCollection = cookies;
  321. }
  322. }
  323. }