2b756a97bd1e513400a25f64f3484ddc7e40f117
[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 #if NET_4_5
159                 virtual
160 #endif
161                 public CookieCollection Cookies {
162                         get {
163                                 CheckDisposed ();
164                                 if (cookieCollection == null)
165                                         cookieCollection = new CookieCollection ();
166                                 return cookieCollection;
167                         }
168                         set {
169                                 CheckDisposed ();
170                                 cookieCollection = value;
171                         }
172                 }
173                 
174                 public override WebHeaderCollection Headers {           
175                         get {
176                                 return webHeaders; 
177                         }
178                 }
179
180                 static Exception GetMustImplement ()
181                 {
182                         return new NotImplementedException ();
183                 }
184                 
185                 [MonoTODO]
186                 public override bool IsMutuallyAuthenticated
187                 {
188                         get {
189                                 throw GetMustImplement ();
190                         }
191                 }
192                 
193                 public DateTime LastModified {
194                         get {
195                                 CheckDisposed ();
196                                 try {
197                                         string dtStr = webHeaders ["Last-Modified"];
198                                         return MonoHttpDate.Parse (dtStr);
199                                 } catch (Exception) {
200                                         return DateTime.Now;    
201                                 }
202                         }
203                 }
204                 
205 #if NET_4_5
206                 virtual
207 #endif
208                 public string Method {
209                         get {
210                                 CheckDisposed ();
211                                 return method; 
212                         }
213                 }
214                 
215                 public Version ProtocolVersion {
216                         get {
217                                 CheckDisposed ();
218                                 return version; 
219                         }
220                 }
221                 
222                 public override Uri ResponseUri {               
223                         get {
224                                 CheckDisposed ();
225                                 return uri; 
226                         }
227                 }               
228                 
229                 public string Server {
230                         get {
231                                 CheckDisposed ();
232                                 return webHeaders ["Server"]; 
233                         }
234                 }
235                 
236 #if NET_4_5
237                 virtual
238 #endif
239                 public HttpStatusCode StatusCode {
240                         get {
241                                 return statusCode; 
242                         }
243                 }
244                 
245 #if NET_4_5
246                 virtual
247 #endif
248                 public string StatusDescription {
249                         get {
250                                 CheckDisposed ();
251                                 return statusDescription; 
252                         }
253                 }
254
255                 // Methods
256                 
257                 public string GetResponseHeader (string headerName)
258                 {
259                         CheckDisposed ();
260                         string value = webHeaders [headerName];
261                         return (value != null) ? value : "";
262                 }
263
264                 internal void ReadAll ()
265                 {
266                         WebConnectionStream wce = stream as WebConnectionStream;
267                         if (wce == null)
268                                 return;
269                                 
270                         try {
271                                 wce.ReadAll ();
272                         } catch {}
273                 }
274
275                 public override Stream GetResponseStream ()
276                 {
277                         CheckDisposed ();
278                         if (stream == null)
279                                 return Stream.Null;  
280                         if (string.Equals (method, "HEAD", StringComparison.OrdinalIgnoreCase))  // see par 4.3 & 9.4
281                                 return Stream.Null;  
282
283                         return stream;
284                 }
285                 
286                 void ISerializable.GetObjectData (SerializationInfo serializationInfo,
287                                                   StreamingContext streamingContext)
288                 {
289                         GetObjectData (serializationInfo, streamingContext);
290                 }
291
292                 protected override void GetObjectData (SerializationInfo serializationInfo,
293                         StreamingContext streamingContext)
294                 {
295                         SerializationInfo info = serializationInfo;
296
297                         info.AddValue ("uri", uri);
298                         info.AddValue ("contentLength", contentLength);
299                         info.AddValue ("contentType", contentType);
300                         info.AddValue ("method", method);
301                         info.AddValue ("statusDescription", statusDescription);
302                         info.AddValue ("cookieCollection", cookieCollection);
303                         info.AddValue ("version", version);
304                         info.AddValue ("statusCode", statusCode);
305                 }
306
307                 // Cleaning up stuff
308
309                 public override void Close ()
310                 {
311                         if (stream != null) {
312                                 Stream st = stream;
313                                 stream = null;
314                                 if (st != null)
315                                         st.Close ();
316                         }
317                 }
318                 
319                 void IDisposable.Dispose ()
320                 {
321                         Dispose (true);
322                 }
323                 
324 #if NET_4_0
325                 protected override void Dispose (bool disposing)
326                 {
327                         this.disposed = true;
328                         base.Dispose (true);
329                 }
330 #else
331                 void Dispose (bool disposing) 
332                 {
333                         this.disposed = true;
334                         if (disposing)
335                                 Close ();
336                 }
337 #endif
338                 
339                 private void CheckDisposed () 
340                 {
341                         if (disposed)
342                                 throw new ObjectDisposedException (GetType ().FullName);
343                 }
344
345                 void FillCookies ()
346                 {
347                         if (webHeaders == null)
348                                 return;
349
350                         string value = webHeaders.Get ("Set-Cookie");
351                         if (value != null) {
352                                 SetCookie (value);
353                         }
354
355                         value = webHeaders.Get ("Set-Cookie2");
356                         if (value != null) {
357                                 SetCookie (value);
358                         }
359                 }
360
361                 void SetCookie (string header)
362                 {
363                         if (cookieCollection == null)
364                                 cookieCollection = new CookieCollection ();
365
366                         var parser = new CookieParser (header);
367                         foreach (var cookie in parser.Parse ()) {
368                                 if (cookie.Domain == "") {
369                                         cookie.Domain = uri.Host;
370                                         cookie.HasDomain = false;
371                                 }
372
373                                 if (cookie.HasDomain &&
374                                     !CookieContainer.CheckSameOrigin (uri, cookie.Domain))
375                                         continue;
376
377                                 cookieCollection.Add (cookie);
378                                 if (cookie_container != null)
379                                         cookie_container.Add (uri, cookie);
380                         }
381                 }
382         }       
383 }
384