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