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