60bf0a84ee09b708f8cf6c4cf1394de6dc0cca51
[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 //
8 // (c) 2002 Lawrence Pit
9 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
10 //
11
12 using System;
13 using System.IO;
14 using System.Net.Sockets;
15 using System.Runtime.Serialization;
16 using System.Text;
17
18 namespace System.Net 
19 {
20         [Serializable]
21         public class HttpWebResponse : WebResponse, ISerializable, IDisposable
22         {
23                 Uri uri;
24                 WebHeaderCollection webHeaders;
25                 CookieCollection cookieCollection;
26                 string method;
27                 Version version;
28                 HttpStatusCode statusCode;
29                 string statusDescription;
30                 long contentLength = -1;
31                 string contentType;
32
33                 bool disposed = false;
34                 Stream stream;
35                 
36                 // Constructors
37                 
38                 internal HttpWebResponse (Uri uri, string method, WebConnectionData data, bool cookiesSet)
39                 {
40                         this.uri = uri;
41                         this.method = method;
42                         webHeaders = data.Headers;
43                         version = data.Version;
44                         statusCode = (HttpStatusCode) data.StatusCode;
45                         statusDescription = data.StatusDescription;
46                         stream = data.stream;
47                         if (cookiesSet) {
48                                 FillCookies ();
49                         } else if (webHeaders != null) {
50                                 webHeaders.RemoveInternal ("Set-Cookie");
51                                 webHeaders.RemoveInternal ("Set-Cookie2");
52                         }
53                 }
54
55                 protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
56                 {
57                         SerializationInfo info = serializationInfo;
58
59                         uri = (Uri) info.GetValue ("uri", typeof (Uri));
60                         contentLength = info.GetInt64 ("contentLength");
61                         contentType = info.GetString ("contentType");
62                         method = info.GetString ("method");
63                         statusDescription = info.GetString ("statusDescription");
64                         cookieCollection = (CookieCollection) info.GetValue ("cookieCollection", typeof (CookieCollection));
65                         version = (Version) info.GetValue ("version", typeof (Version));
66                         statusCode = (HttpStatusCode) info.GetValue ("statusCode", typeof (HttpStatusCode));
67                 }
68                 
69                 // Properties
70                 
71                 public string CharacterSet {
72                         // Content-Type   = "Content-Type" ":" media-type
73                         // media-type     = type "/" subtype *( ";" parameter )
74                         // parameter      = attribute "=" value
75                         // 3.7.1. default is ISO-8859-1
76                         get { 
77                                 CheckDisposed ();
78                                 string contentType = ContentType;
79                                 if (contentType == null)
80                                         return "ISO-8859-1";
81                                 string val = contentType.ToLower ();                                    
82                                 int pos = val.IndexOf ("charset=");
83                                 if (pos == -1)
84                                         return "ISO-8859-1";
85                                 pos += 8;
86                                 int pos2 = val.IndexOf (';', pos);
87                                 return (pos2 == -1)
88                                      ? contentType.Substring (pos) 
89                                      : contentType.Substring (pos, pos2 - pos);
90                         }
91                 }
92                 
93                 public string ContentEncoding {
94                         get { 
95                                 CheckDisposed ();
96                                 return webHeaders ["Content-Encoding"];
97                         }
98                 }
99                 
100                 public override long ContentLength {            
101                         get {
102                                 CheckDisposed ();
103                                 if (contentLength != -1)
104                                         return contentLength;
105
106                                 try {
107                                         contentLength = (long) UInt64.Parse (webHeaders ["Content-Length"]); 
108                                 } catch (Exception) {
109                                         return -1;
110                                 }
111
112                                 return contentLength;
113                         }
114                 }
115                 
116                 public override string ContentType {            
117                         get {
118                                 CheckDisposed ();
119                                 if (contentType == null)
120                                         contentType = webHeaders ["Content-Type"];
121
122                                 return contentType;
123                         }
124                 }
125                 
126                 public CookieCollection Cookies {
127                         get { 
128                                 CheckDisposed ();
129                                 
130                                 if (cookieCollection == null)
131                                         cookieCollection = new CookieCollection ();
132                                 return cookieCollection;
133                         }
134                         set {
135                                 CheckDisposed ();
136                                 cookieCollection = value;
137                         }
138                 }
139                 
140                 public override WebHeaderCollection Headers {           
141                         get { 
142                                 CheckDisposed ();
143                                 return webHeaders; 
144                         }
145                 }
146                 
147                 public DateTime LastModified {
148                         get {
149                                 CheckDisposed ();
150                                 try {
151                                         string dtStr = webHeaders ["Last-Modified"];
152                                         return MonoHttpDate.Parse (dtStr);
153                                 } catch (Exception) {
154                                         return DateTime.Now;    
155                                 }
156                         }
157                 }
158                 
159                 public string Method {
160                         get { 
161                                 CheckDisposed ();
162                                 return method; 
163                         }
164                 }
165                 
166                 public Version ProtocolVersion {
167                         get { 
168                                 CheckDisposed ();
169                                 return version; 
170                         }
171                 }
172                 
173                 public override Uri ResponseUri {               
174                         get { 
175                                 CheckDisposed ();
176                                 return uri; 
177                         }
178                 }               
179                 
180                 public string Server {
181                         get { 
182                                 CheckDisposed ();
183                                 return webHeaders ["Server"]; 
184                         }
185                 }
186                 
187                 public HttpStatusCode StatusCode {
188                         get { 
189                                 CheckDisposed ();
190                                 return statusCode; 
191                         }
192                 }
193                 
194                 public string StatusDescription {
195                         get { 
196                                 CheckDisposed ();
197                                 return statusDescription; 
198                         }
199                 }
200
201                 // Methods
202                 
203                 public override int GetHashCode ()
204                 {
205                         CheckDisposed ();
206                         return base.GetHashCode ();
207                 }
208                 
209                 public string GetResponseHeader (string headerName)
210                 {
211                         CheckDisposed ();
212                         string value = webHeaders [headerName];
213                         return (value != null) ? value : "";
214                 }
215                 
216                 public override Stream GetResponseStream ()
217                 {
218                         CheckDisposed ();
219                         if (stream == null)
220                                 return Stream.Null;  
221                         if (0 == String.Compare (method, "HEAD", true)) // see par 4.3 & 9.4
222                                 return Stream.Null;  
223
224                         return stream;
225                 }
226                 
227                 void ISerializable.GetObjectData (SerializationInfo serializationInfo,
228                                                   StreamingContext streamingContext)
229                 {
230                         SerializationInfo info = serializationInfo;
231
232                         info.AddValue ("uri", uri);
233                         info.AddValue ("contentLength", contentLength);
234                         info.AddValue ("contentType", contentType);
235                         info.AddValue ("method", method);
236                         info.AddValue ("statusDescription", statusDescription);
237                         info.AddValue ("cookieCollection", cookieCollection);
238                         info.AddValue ("version", version);
239                         info.AddValue ("statusCode", statusCode);
240                 }               
241
242
243                 // Cleaning up stuff
244
245                 public override void Close ()
246                 {
247                         ((IDisposable) this).Dispose ();
248                 }
249                 
250                 void IDisposable.Dispose ()
251                 {
252                         Dispose (true);
253                         GC.SuppressFinalize (this);  
254                 }
255                 
256                 protected virtual void Dispose (bool disposing) 
257                 {
258                         if (this.disposed)
259                                 return;
260                         this.disposed = true;
261                         
262                         if (disposing) {
263                                 // release managed resources
264                                 uri = null;
265                                 webHeaders = null;
266                                 cookieCollection = null;
267                                 method = null;
268                                 version = null;
269                                 statusDescription = null;
270                         }
271                         
272                         // release unmanaged resources
273                         Stream st = stream;
274                         stream = null;
275                         if (st != null) {
276                                 WebConnectionStream wce = st as WebConnectionStream;
277                                 if (wce != null) {
278                                         try {
279                                                 wce.ReadAll ();
280                                         } catch {}
281                                 }
282                                 st.Close ();
283                         }
284                 }
285                 
286                 private void CheckDisposed () 
287                 {
288                         if (disposed)
289                                 throw new ObjectDisposedException (GetType ().FullName);
290                 }
291
292                 void FillCookies ()
293                 {
294                         if (webHeaders == null)
295                                 return;
296
297                         string val = webHeaders ["Set-Cookie"];
298                         if (val != null && val.Trim () != "")
299                                 SetCookie (val);
300
301                         val = webHeaders ["Set-Cookie2"];
302                         if (val != null && val.Trim () != "")
303                                 SetCookie2 (val);
304                 }
305                 
306                 static string [] SplitValue (string input)
307                 {
308                         string [] result = new string [2];
309                         int eq = input.IndexOf ('=');
310                         if (eq == -1) {
311                                 result [0] = "invalid";
312                         } else {
313                                 result [0] = input.Substring (0, eq).Trim ().ToUpper ();
314                                 result [1] = input.Substring (eq + 1);
315                         }
316                         
317                         return result;
318                 }
319                 
320                 [MonoTODO ("Parse dates")]
321                 void SetCookie (string cookie_str)
322                 {
323                         string[] parts = null;
324                         Collections.Queue options = null;
325                         Cookie cookie = null;
326
327                         options = new Collections.Queue (cookie_str.Split (';'));
328                         parts = SplitValue ((string) options.Dequeue()); // NAME=VALUE must be first
329
330                         cookie = new Cookie (parts[0], parts[1]);
331
332                         while (options.Count > 0) {
333                                 parts = SplitValue ((string) options.Dequeue());
334                                 switch (parts [0]) {
335                                         case "COMMENT":
336                                                 if (cookie.Comment == null)
337                                                         cookie.Comment = parts[1];
338                                         break;
339                                         case "COMMENTURL":
340                                                 if (cookie.CommentUri == null)
341                                                         cookie.CommentUri = new Uri(parts[1]);
342                                         break;
343                                         case "DISCARD":
344                                                 cookie.Discard = true;
345                                         break;
346                                         case "DOMAIN":
347                                                 if (cookie.Domain == "")
348                                                         cookie.Domain = parts[1];
349                                         break;
350                                         case "MAX-AGE": // RFC Style Set-Cookie2
351                                                 if (cookie.Expires == DateTime.MinValue)
352                                                         cookie.Expires = cookie.TimeStamp.AddSeconds (Int32.Parse (parts[1]));
353                                         break;
354                                         case "EXPIRES": // Netscape Style Set-Cookie
355                                                 if (cookie.Expires == DateTime.MinValue) {
356                                                         //FIXME: Does DateTime parse something like: "Sun, 17-Jan-2038 19:14:07 GMT"?
357                                                         //cookie.Expires = DateTime.ParseExact (parts[1]);
358                                                         cookie.Expires = DateTime.Now.AddDays (1);
359                                                 }
360                                         break;
361                                         case "PATH":
362                                                         cookie.Path = parts[1];
363                                         break;
364                                         case "PORT":
365                                                 if (cookie.Port == null)
366                                                         cookie.Port = parts[1];
367                                         break;
368                                         case "SECURE":
369                                                 cookie.Secure = true;
370                                         break;
371                                         case "VERSION":
372                                                 cookie.Version = Int32.Parse (parts[1]);
373                                         break;
374                                 } // switch
375                         } // while
376
377                         if (cookieCollection == null)
378                                 cookieCollection = new CookieCollection();
379
380                         if (cookie.Domain == "")
381                                 cookie.Domain = uri.Host;
382
383                         cookieCollection.Add (cookie);
384                 }
385
386                 void SetCookie2 (string cookies_str)
387                 {
388                         string [] cookies = cookies_str.Split (',');
389         
390                         foreach (string cookie_str in cookies)
391                                 SetCookie (cookie_str);
392                 }
393         }       
394 }
395