HttpWebResponse.cs 9.3 KB

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