Revert "Revert "Merge branch 'master' of https://github.com/mono/mono""
[mono.git] / mcs / class / System / System.Net / HttpWebResponse.cs
index 7e1eccebbf8395a085caddba16131d20bab0eb9b..79e61a436249dc4f6653567b75d6080e397f4c72 100644 (file)
@@ -4,9 +4,11 @@
 // Authors:
 //     Lawrence Pit (loz@cable.a2000.nl)
 //     Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//      Daniel Nauck    (dna(at)mono-project(dot)de)
 //
 // (c) 2002 Lawrence Pit
 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
+// (c) 2008 Daniel Nauck
 //
 
 //
@@ -34,6 +36,7 @@ using System;
 using System.Collections;
 using System.Globalization;
 using System.IO;
+using System.IO.Compression;
 using System.Net.Sockets;
 using System.Runtime.Serialization;
 using System.Text;
@@ -41,8 +44,7 @@ using System.Text;
 namespace System.Net 
 {
        [Serializable]
-       public class HttpWebResponse : WebResponse, ISerializable, IDisposable
-       {
+       public class HttpWebResponse : WebResponse, ISerializable, IDisposable {
                Uri uri;
                WebHeaderCollection webHeaders;
                CookieCollection cookieCollection;
@@ -50,10 +52,11 @@ namespace System.Net
                Version version;
                HttpStatusCode statusCode;
                string statusDescription;
-               long contentLength = -1;
+               long contentLength;
                string contentType;
+               CookieContainer cookie_container;
 
-               bool disposed = false;
+               bool disposed;
                Stream stream;
                
                // Constructors
@@ -67,11 +70,29 @@ namespace System.Net
                        statusCode = (HttpStatusCode) data.StatusCode;
                        statusDescription = data.StatusDescription;
                        stream = data.stream;
+                       contentLength = -1;
+
+                       try {
+                               string cl = webHeaders ["Content-Length"];
+                               if (String.IsNullOrEmpty (cl) || !Int64.TryParse (cl, out contentLength))
+                                       contentLength = -1;
+                       } catch (Exception) {
+                               contentLength = -1;
+                       }
+
                        if (container != null) {
+                               this.cookie_container = container;      
                                FillCookies ();
                        }
+
+                       string content_encoding = webHeaders ["Content-Encoding"];
+                       if (content_encoding == "gzip" && (data.request.AutomaticDecompression & DecompressionMethods.GZip) != 0)
+                               stream = new GZipStream (stream, CompressionMode.Decompress);
+                       else if (content_encoding == "deflate" && (data.request.AutomaticDecompression & DecompressionMethods.Deflate) != 0)
+                               stream = new DeflateStream (stream, CompressionMode.Decompress);
                }
 
+               [Obsolete ("Serialization is obsoleted for this type", false)]
                protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
                {
                        SerializationInfo info = serializationInfo;
@@ -94,12 +115,11 @@ namespace System.Net
                        // parameter      = attribute "=" value
                        // 3.7.1. default is ISO-8859-1
                        get { 
-                               CheckDisposed ();
                                string contentType = ContentType;
                                if (contentType == null)
                                        return "ISO-8859-1";
                                string val = contentType.ToLower ();                                    
-                               int pos = val.IndexOf ("charset=");
+                               int pos = val.IndexOf ("charset=", StringComparison.Ordinal);
                                if (pos == -1)
                                        return "ISO-8859-1";
                                pos += 8;
@@ -111,7 +131,7 @@ namespace System.Net
                }
                
                public string ContentEncoding {
-                       get { 
+                       get {
                                CheckDisposed ();
                                string h = webHeaders ["Content-Encoding"];
                                return h != null ? h : "";
@@ -120,16 +140,6 @@ namespace System.Net
                
                public override long ContentLength {            
                        get {
-                               CheckDisposed ();
-                               if (contentLength != -1)
-                                       return contentLength;
-
-                               try {
-                                       contentLength = (long) UInt64.Parse (webHeaders ["Content-Length"]); 
-                               } catch (Exception) {
-                                       return -1;
-                               }
-
                                return contentLength;
                        }
                }
@@ -137,6 +147,7 @@ namespace System.Net
                public override string ContentType {            
                        get {
                                CheckDisposed ();
+
                                if (contentType == null)
                                        contentType = webHeaders ["Content-Type"];
 
@@ -144,10 +155,12 @@ namespace System.Net
                        }
                }
                
+#if NET_4_5
+               virtual
+#endif
                public CookieCollection Cookies {
-                       get { 
+                       get {
                                CheckDisposed ();
-                               
                                if (cookieCollection == null)
                                        cookieCollection = new CookieCollection ();
                                return cookieCollection;
@@ -159,11 +172,23 @@ namespace System.Net
                }
                
                public override WebHeaderCollection Headers {           
-                       get { 
-                               CheckDisposed ();
+                       get {
                                return webHeaders; 
                        }
                }
+
+               static Exception GetMustImplement ()
+               {
+                       return new NotImplementedException ();
+               }
+               
+               [MonoTODO]
+               public override bool IsMutuallyAuthenticated
+               {
+                       get {
+                               throw GetMustImplement ();
+                       }
+               }
                
                public DateTime LastModified {
                        get {
@@ -177,56 +202,57 @@ namespace System.Net
                        }
                }
                
+#if NET_4_5
+               virtual
+#endif
                public string Method {
-                       get { 
+                       get {
                                CheckDisposed ();
                                return method; 
                        }
                }
                
                public Version ProtocolVersion {
-                       get { 
+                       get {
                                CheckDisposed ();
                                return version; 
                        }
                }
                
                public override Uri ResponseUri {               
-                       get { 
+                       get {
                                CheckDisposed ();
                                return uri; 
                        }
                }               
                
                public string Server {
-                       get { 
+                       get {
                                CheckDisposed ();
                                return webHeaders ["Server"]; 
                        }
                }
                
+#if NET_4_5
+               virtual
+#endif
                public HttpStatusCode StatusCode {
-                       get { 
-                               CheckDisposed ();
+                       get {
                                return statusCode; 
                        }
                }
                
+#if NET_4_5
+               virtual
+#endif
                public string StatusDescription {
-                       get { 
+                       get {
                                CheckDisposed ();
                                return statusDescription; 
                        }
                }
 
                // Methods
-#if !NET_2_0
-               public override int GetHashCode ()
-               {
-                       CheckDisposed ();
-                       return base.GetHashCode ();
-               }
-#endif
                
                public string GetResponseHeader (string headerName)
                {
@@ -251,7 +277,7 @@ namespace System.Net
                        CheckDisposed ();
                        if (stream == null)
                                return Stream.Null;  
-                       if (0 == String.Compare (method, "HEAD", true)) // see par 4.3 & 9.4
+                       if (string.Equals (method, "HEAD", StringComparison.OrdinalIgnoreCase))  // see par 4.3 & 9.4
                                return Stream.Null;  
 
                        return stream;
@@ -259,6 +285,12 @@ namespace System.Net
                
                void ISerializable.GetObjectData (SerializationInfo serializationInfo,
                                                  StreamingContext streamingContext)
+               {
+                       GetObjectData (serializationInfo, streamingContext);
+               }
+
+               protected override void GetObjectData (SerializationInfo serializationInfo,
+                       StreamingContext streamingContext)
                {
                        SerializationInfo info = serializationInfo;
 
@@ -270,47 +302,39 @@ namespace System.Net
                        info.AddValue ("cookieCollection", cookieCollection);
                        info.AddValue ("version", version);
                        info.AddValue ("statusCode", statusCode);
-               }               
-
+               }
 
                // Cleaning up stuff
 
                public override void Close ()
                {
-                       ((IDisposable) this).Dispose ();
+                       if (stream != null) {
+                               Stream st = stream;
+                               stream = null;
+                               if (st != null)
+                                       st.Close ();
+                       }
                }
                
                void IDisposable.Dispose ()
                {
                        Dispose (true);
-                       GC.SuppressFinalize (this);  
                }
-
-#if !NET_2_0
-               protected virtual
-#endif
+               
+#if NET_4_0
+               protected override void Dispose (bool disposing)
+               {
+                       this.disposed = true;
+                       base.Dispose (true);
+               }
+#else
                void Dispose (bool disposing) 
                {
-                       if (this.disposed)
-                               return;
                        this.disposed = true;
-                       
-                       if (disposing) {
-                               // release managed resources
-                               uri = null;
-                               webHeaders = null;
-                               cookieCollection = null;
-                               method = null;
-                               version = null;
-                               statusDescription = null;
-                       }
-                       
-                       // release unmanaged resources
-                       Stream st = stream;
-                       stream = null;
-                       if (st != null)
-                               st.Close ();
+                       if (disposing)
+                               Close ();
                }
+#endif
                
                private void CheckDisposed () 
                {
@@ -323,188 +347,51 @@ namespace System.Net
                        if (webHeaders == null)
                                return;
 
-                       string [] values = webHeaders.GetValues ("Set-Cookie");
-                       if (values != null) {
-                               foreach (string va in values)
-                                       SetCookie (va);
+                       //
+                       // Don't terminate response reading on bad cookie value
+                       //
+                       string value;
+                       try {
+                               value = webHeaders.Get ("Set-Cookie");
+                               if (value != null && SetCookie (value))
+                                       return;
+                       } catch {
                        }
 
-                       values = webHeaders.GetValues ("Set-Cookie2");
-                       if (values != null) {
-                               foreach (string va in values)
-                                       SetCookie2 (va);
+                       try {
+                               value = webHeaders.Get ("Set-Cookie2");
+                               if (value != null)
+                                       SetCookie (value);
+                       } catch {
                        }
                }
 
-               void SetCookie (string header)
+               bool SetCookie (string header)
                {
-                       string name, val;
-                       Cookie cookie = null;
-                       CookieParser parser = new CookieParser (header);
+                       if (cookieCollection == null)
+                               cookieCollection = new CookieCollection ();
 
-                       while (parser.GetNextNameValue (out name, out val)) {
-                               if ((name == null || name == "") && cookie == null)
-                                       continue;
+                       bool at_least_one_set = false;
+                       var parser = new CookieParser (header);
+                       foreach (var cookie in parser.Parse ()) {
+                               if (cookie.Domain == "") {
+                                       cookie.Domain = uri.Host;
+                                       cookie.HasDomain = false;
+                               }
 
-                               if (cookie == null) {
-                                       cookie = new Cookie (name, val);
+                               if (cookie.HasDomain &&
+                                   !CookieContainer.CheckSameOrigin (uri, cookie.Domain))
                                        continue;
-                               }
 
-                               name = name.ToUpper ();
-                               switch (name) {
-                               case "COMMENT":
-                                       if (cookie.Comment == null)
-                                               cookie.Comment = val;
-                                       break;
-                               case "COMMENTURL":
-                                       if (cookie.CommentUri == null)
-                                               cookie.CommentUri = new Uri (val);
-                                       break;
-                               case "DISCARD":
-                                       cookie.Discard = true;
-                                       break;
-                               case "DOMAIN":
-                                       if (cookie.Domain == "")
-                                               cookie.Domain = val;
-                                       break;
-                               case "MAX-AGE": // RFC Style Set-Cookie2
-                                       if (cookie.Expires == DateTime.MinValue) {
-                                               try {
-                                               cookie.Expires = cookie.TimeStamp.AddSeconds (UInt32.Parse (val));
-                                               } catch {}
-                                       }
-                                       break;
-                               case "EXPIRES": // Netscape Style Set-Cookie
-                                       if (cookie.Expires != DateTime.MinValue)
-                                               break;
-                                       try {
-                                               cookie.Expires = DateTime.ParseExact (val, "r", CultureInfo.InvariantCulture);
-                                       } catch {
-                                               try { 
-                                               cookie.Expires = DateTime.ParseExact (val,
-                                                               "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
-                                                               CultureInfo.InvariantCulture);
-                                               } catch {
-                                                       cookie.Expires = DateTime.Now.AddDays (1);
-                                               }
-                                       }
-                                       break;
-                               case "PATH":
-                                       cookie.Path = val;
-                                       break;
-                               case "PORT":
-                                       if (cookie.Port == null)
-                                               cookie.Port = val;
-                                       break;
-                               case "SECURE":
-                                       cookie.Secure = true;
-                                       break;
-                               case "VERSION":
-                                       try {
-                                               cookie.Version = (int) UInt32.Parse (val);
-                                       } catch {}
-                                       break;
+                               cookieCollection.Add (cookie);
+                               if (cookie_container != null) {
+                                       cookie_container.Add (uri, cookie);
+                                       at_least_one_set = true;
                                }
                        }
 
-                       if (cookieCollection == null)
-                               cookieCollection = new CookieCollection ();
-
-                       if (cookie.Domain == "")
-                               cookie.Domain = uri.Host;
-
-                       cookieCollection.Add (cookie);
-               }
-
-               void SetCookie2 (string cookies_str)
-               {
-                       string [] cookies = cookies_str.Split (',');
-       
-                       foreach (string cookie_str in cookies)
-                               SetCookie (cookie_str);
+                       return at_least_one_set;
                }
        }       
-
-       class CookieParser {
-               string header;
-               int pos;
-               int length;
-
-               public CookieParser (string header) : this (header, 0)
-               {
-               }
-
-               public CookieParser (string header, int position)
-               {
-                       this.header = header;
-                       this.pos = position;
-                       this.length = header.Length;
-               }
-
-               public bool GetNextNameValue (out string name, out string val)
-               {
-                       name = null;
-                       val = null;
-
-                       if (pos >= length)
-                               return false;
-
-                       name = GetCookieName ();
-                       if (pos < header.Length && header [pos] == '=') {
-                               pos++;
-                               val = GetCookieValue ();
-                       }
-
-                       if (pos < length && header [pos] == ';')
-                               pos++;
-
-                       return true;
-               }
-
-               string GetCookieName ()
-               {
-                       int k = pos;
-                       while (k < length && Char.IsWhiteSpace (header [k]))
-                               k++;
-
-                       int begin = k;
-                       while (k < length && header [k] != ';' &&  header [k] != '=')
-                               k++;
-
-                       pos = k;
-                       return header.Substring (begin, k - begin).Trim ();
-               }
-
-               string GetCookieValue ()
-               {
-                       if (pos >= length)
-                               return null;
-
-                       int k = pos;
-                       while (k < length && Char.IsWhiteSpace (header [k]))
-                               k++;
-
-                       int begin;
-                       if (header [k] == '"'){
-                               int j;
-                               begin = ++k;
-
-                               while (k < length && header [k] != '"')
-                                       k++;
-
-                               for (j = k; j < length && header [j] != ';'; j++)
-                                       ;
-                               pos = j;
-                       } else {
-                               begin = k;
-                               while (k < length && header [k] != ';')
-                                       k++;
-                               pos = k;
-                       }
-                               
-                       return header.Substring (begin, k - begin).Trim ();
-               }
-       }
 }