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