Merge pull request #704 from jgagnon/master
[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                 // Methods
248                 
249                 public string GetResponseHeader (string headerName)
250                 {
251                         CheckDisposed ();
252                         string value = webHeaders [headerName];
253                         return (value != null) ? value : "";
254                 }
255
256                 internal void ReadAll ()
257                 {
258                         WebConnectionStream wce = stream as WebConnectionStream;
259                         if (wce == null)
260                                 return;
261                                 
262                         try {
263                                 wce.ReadAll ();
264                         } catch {}
265                 }
266
267                 public override Stream GetResponseStream ()
268                 {
269                         CheckDisposed ();
270                         if (stream == null)
271                                 return Stream.Null;  
272                         if (string.Equals (method, "HEAD", StringComparison.OrdinalIgnoreCase))  // see par 4.3 & 9.4
273                                 return Stream.Null;  
274
275                         return stream;
276                 }
277                 
278                 void ISerializable.GetObjectData (SerializationInfo serializationInfo,
279                                                   StreamingContext streamingContext)
280                 {
281                         GetObjectData (serializationInfo, streamingContext);
282                 }
283
284                 protected override void GetObjectData (SerializationInfo serializationInfo,
285                         StreamingContext streamingContext)
286                 {
287                         SerializationInfo info = serializationInfo;
288
289                         info.AddValue ("uri", uri);
290                         info.AddValue ("contentLength", contentLength);
291                         info.AddValue ("contentType", contentType);
292                         info.AddValue ("method", method);
293                         info.AddValue ("statusDescription", statusDescription);
294                         info.AddValue ("cookieCollection", cookieCollection);
295                         info.AddValue ("version", version);
296                         info.AddValue ("statusCode", statusCode);
297                 }
298
299                 // Cleaning up stuff
300
301                 public override void Close ()
302                 {
303                         if (stream != null) {
304                                 Stream st = stream;
305                                 stream = null;
306                                 if (st != null)
307                                         st.Close ();
308                         }
309                 }
310                 
311                 void IDisposable.Dispose ()
312                 {
313                         Dispose (true);
314                 }
315                 
316                 protected override void Dispose (bool disposing)
317                 {
318                         this.disposed = true;
319                         base.Dispose (true);
320                 }
321                 
322                 private void CheckDisposed () 
323                 {
324                         if (disposed)
325                                 throw new ObjectDisposedException (GetType ().FullName);
326                 }
327
328                 void FillCookies ()
329                 {
330                         if (webHeaders == null)
331                                 return;
332
333                         //
334                         // Don't terminate response reading on bad cookie value
335                         //
336                         string value;
337                         CookieCollection cookies = null;
338                         try {
339                                 value = webHeaders.Get ("Set-Cookie");
340                                 if (value != null)
341                                         cookies = cookie_container.CookieCutter (uri, HttpKnownHeaderNames.SetCookie, value, false);
342                         } catch {
343                         }
344
345                         try {
346                                 value = webHeaders.Get ("Set-Cookie2");
347                                 if (value != null) {
348                                         var cookies2 = cookie_container.CookieCutter (uri, HttpKnownHeaderNames.SetCookie2, value, false);
349
350                                         if (cookies != null && cookies.Count != 0) {
351                                                 cookies.Add (cookies2);
352                                         } else {
353                                                 cookies = cookies2;
354                                         }
355                                 }
356                         } catch {
357                         }
358
359                         this.cookieCollection = cookies;
360                 }
361         }       
362 }
363