System.Drawing: added email to icon and test file headers
[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 #if MOONLIGHT
47         internal class HttpWebResponse : WebResponse, ISerializable, IDisposable {
48 #else
49         [Serializable]
50         public class HttpWebResponse : WebResponse, ISerializable, IDisposable {
51 #endif
52                 Uri uri;
53                 WebHeaderCollection webHeaders;
54                 CookieCollection cookieCollection;
55                 string method;
56                 Version version;
57                 HttpStatusCode statusCode;
58                 string statusDescription;
59                 long contentLength;
60                 string contentType;
61                 CookieContainer cookie_container;
62
63                 bool disposed;
64                 Stream stream;
65                 
66                 // Constructors
67                 
68                 internal HttpWebResponse (Uri uri, string method, WebConnectionData data, CookieContainer container)
69                 {
70                         this.uri = uri;
71                         this.method = method;
72                         webHeaders = data.Headers;
73                         version = data.Version;
74                         statusCode = (HttpStatusCode) data.StatusCode;
75                         statusDescription = data.StatusDescription;
76                         stream = data.stream;
77                         contentLength = -1;
78
79                         try {
80                                 string cl = webHeaders ["Content-Length"];
81                                 if (String.IsNullOrEmpty (cl) || !Int64.TryParse (cl, out contentLength))
82                                         contentLength = -1;
83                         } catch (Exception) {
84                                 contentLength = -1;
85                         }
86
87                         if (container != null) {
88                                 this.cookie_container = container;      
89                                 FillCookies ();
90                         }
91
92                         string content_encoding = webHeaders ["Content-Encoding"];
93                         if (content_encoding == "gzip" && (data.request.AutomaticDecompression & DecompressionMethods.GZip) != 0)
94                                 stream = new GZipStream (stream, CompressionMode.Decompress);
95                         else if (content_encoding == "deflate" && (data.request.AutomaticDecompression & DecompressionMethods.Deflate) != 0)
96                                 stream = new DeflateStream (stream, CompressionMode.Decompress);
97                 }
98
99                 [Obsolete ("Serialization is obsoleted for this type", false)]
100                 protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
101                 {
102                         SerializationInfo info = serializationInfo;
103
104                         uri = (Uri) info.GetValue ("uri", typeof (Uri));
105                         contentLength = info.GetInt64 ("contentLength");
106                         contentType = info.GetString ("contentType");
107                         method = info.GetString ("method");
108                         statusDescription = info.GetString ("statusDescription");
109                         cookieCollection = (CookieCollection) info.GetValue ("cookieCollection", typeof (CookieCollection));
110                         version = (Version) info.GetValue ("version", typeof (Version));
111                         statusCode = (HttpStatusCode) info.GetValue ("statusCode", typeof (HttpStatusCode));
112                 }
113                 
114                 // Properties
115                 
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                 
137                 public string ContentEncoding {
138                         get {
139                                 CheckDisposed ();
140                                 string h = webHeaders ["Content-Encoding"];
141                                 return h != null ? h : "";
142                         }
143                 }
144                 
145                 public override long ContentLength {            
146                         get {
147                                 return contentLength;
148                         }
149                 }
150                 
151                 public override string ContentType {            
152                         get {
153                                 CheckDisposed ();
154
155                                 if (contentType == null)
156                                         contentType = webHeaders ["Content-Type"];
157
158                                 return contentType;
159                         }
160                 }
161                 
162                 public CookieCollection Cookies {
163                         get {
164                                 CheckDisposed ();
165                                 if (cookieCollection == null)
166                                         cookieCollection = new CookieCollection ();
167                                 return cookieCollection;
168                         }
169                         set {
170                                 CheckDisposed ();
171                                 cookieCollection = value;
172                         }
173                 }
174                 
175                 public override WebHeaderCollection Headers {           
176                         get {
177                                 return webHeaders; 
178                         }
179                 }
180
181                 static Exception GetMustImplement ()
182                 {
183                         return new NotImplementedException ();
184                 }
185                 
186                 [MonoTODO]
187                 public override bool IsMutuallyAuthenticated
188                 {
189                         get {
190                                 throw GetMustImplement ();
191                         }
192                 }
193                 
194                 public DateTime LastModified {
195                         get {
196                                 CheckDisposed ();
197                                 try {
198                                         string dtStr = webHeaders ["Last-Modified"];
199                                         return MonoHttpDate.Parse (dtStr);
200                                 } catch (Exception) {
201                                         return DateTime.Now;    
202                                 }
203                         }
204                 }
205                 
206                 public string Method {
207                         get {
208                                 CheckDisposed ();
209                                 return method; 
210                         }
211                 }
212                 
213                 public Version ProtocolVersion {
214                         get {
215                                 CheckDisposed ();
216                                 return version; 
217                         }
218                 }
219                 
220                 public override Uri ResponseUri {               
221                         get {
222                                 CheckDisposed ();
223                                 return uri; 
224                         }
225                 }               
226                 
227                 public string Server {
228                         get {
229                                 CheckDisposed ();
230                                 return webHeaders ["Server"]; 
231                         }
232                 }
233                 
234                 public HttpStatusCode StatusCode {
235                         get {
236                                 return statusCode; 
237                         }
238                 }
239                 
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 (0 == String.Compare (method, "HEAD", true)) // 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                         GC.SuppressFinalize (this);  
315                 }
316
317                 void Dispose (bool disposing) 
318                 {
319                         this.disposed = true;
320                         if (disposing)
321                                 Close ();
322                 }
323                 
324                 private void CheckDisposed () 
325                 {
326                         if (disposed)
327                                 throw new ObjectDisposedException (GetType ().FullName);
328                 }
329
330                 void FillCookies ()
331                 {
332                         if (webHeaders == null)
333                                 return;
334
335                         string [] values = webHeaders.GetValues ("Set-Cookie");
336                         if (values != null) {
337                                 foreach (string va in values)
338                                         SetCookie (va);
339                         }
340
341                         values = webHeaders.GetValues ("Set-Cookie2");
342                         if (values != null) {
343                                 foreach (string va in values)
344                                         SetCookie2 (va);
345                         }
346                 }
347
348                 void SetCookie (string header)
349                 {
350                         string name, val;
351                         Cookie cookie = null;
352                         CookieParser parser = new CookieParser (header);
353
354                         while (parser.GetNextNameValue (out name, out val)) {
355                                 if ((name == null || name == "") && cookie == null)
356                                         continue;
357
358                                 if (cookie == null) {
359                                         cookie = new Cookie (name, val);
360                                         continue;
361                                 }
362
363                                 name = name.ToUpper ();
364                                 switch (name) {
365                                 case "COMMENT":
366                                         if (cookie.Comment == null)
367                                                 cookie.Comment = val;
368                                         break;
369                                 case "COMMENTURL":
370                                         if (cookie.CommentUri == null)
371                                                 cookie.CommentUri = new Uri (val);
372                                         break;
373                                 case "DISCARD":
374                                         cookie.Discard = true;
375                                         break;
376                                 case "DOMAIN":
377                                         if (cookie.Domain == "")
378                                                 cookie.Domain = val;
379                                         break;
380                                 case "HTTPONLY":
381                                         cookie.HttpOnly = true;
382                                         break;
383                                 case "MAX-AGE": // RFC Style Set-Cookie2
384                                         if (cookie.Expires == DateTime.MinValue) {
385                                                 try {
386                                                 cookie.Expires = cookie.TimeStamp.AddSeconds (UInt32.Parse (val));
387                                                 } catch {}
388                                         }
389                                         break;
390                                 case "EXPIRES": // Netscape Style Set-Cookie
391                                         if (cookie.Expires != DateTime.MinValue)
392                                                 break;
393
394                                         cookie.Expires = CookieParser.TryParseCookieExpires (val);
395                                         break;
396                                 case "PATH":
397                                         cookie.Path = val;
398                                         break;
399                                 case "PORT":
400                                         if (cookie.Port == null)
401                                                 cookie.Port = val;
402                                         break;
403                                 case "SECURE":
404                                         cookie.Secure = true;
405                                         break;
406                                 case "VERSION":
407                                         try {
408                                                 cookie.Version = (int) UInt32.Parse (val);
409                                         } catch {}
410                                         break;
411                                 }
412                         }
413
414                         if (cookie == null)
415                                 return;
416
417                         if (cookieCollection == null)
418                                 cookieCollection = new CookieCollection ();
419
420                         if (cookie.Domain == "")
421                                 cookie.Domain = uri.Host;
422
423                         cookieCollection.Add (cookie);
424                         if (cookie_container != null)
425                                 cookie_container.Add (uri, cookie);
426                 }
427
428                 void SetCookie2 (string cookies_str)
429                 {
430                         string [] cookies = cookies_str.Split (',');
431         
432                         foreach (string cookie_str in cookies)
433                                 SetCookie (cookie_str);
434                 }
435         }       
436 }
437