Revert "Revert "Merge branch 'master' of https://github.com/mono/mono""
[mono.git] / mcs / class / System / System.Net / HttpWebResponse.cs
index 8eb5b7f84ee646a3d8e8d45fe216c030a3fc2a07..79e61a436249dc4f6653567b75d6080e397f4c72 100644 (file)
@@ -36,18 +36,15 @@ 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;
-#if NET_2_0
-using System.IO.Compression;
-#endif
 
 namespace System.Net 
 {
        [Serializable]
-       public class HttpWebResponse : WebResponse, ISerializable, IDisposable
-       {
+       public class HttpWebResponse : WebResponse, ISerializable, IDisposable {
                Uri uri;
                WebHeaderCollection webHeaders;
                CookieCollection cookieCollection;
@@ -77,13 +74,8 @@ namespace System.Net
 
                        try {
                                string cl = webHeaders ["Content-Length"];
-#if NET_2_0
                                if (String.IsNullOrEmpty (cl) || !Int64.TryParse (cl, out contentLength))
                                        contentLength = -1;
-#else
-                               if (cl != null && cl != String.Empty)
-                                       contentLength = (long) UInt64.Parse (cl);
-#endif
                        } catch (Exception) {
                                contentLength = -1;
                        }
@@ -92,18 +84,15 @@ namespace System.Net
                                this.cookie_container = container;      
                                FillCookies ();
                        }
-#if NET_2_0
+
                        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);
-#endif
                }
 
-#if NET_2_0
                [Obsolete ("Serialization is obsoleted for this type", false)]
-#endif
                protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
                {
                        SerializationInfo info = serializationInfo;
@@ -130,7 +119,7 @@ namespace System.Net
                                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;
@@ -166,6 +155,9 @@ namespace System.Net
                        }
                }
                
+#if NET_4_5
+               virtual
+#endif
                public CookieCollection Cookies {
                        get {
                                CheckDisposed ();
@@ -181,14 +173,10 @@ namespace System.Net
                
                public override WebHeaderCollection Headers {           
                        get {
-#if ONLY_1_1
-                               CheckDisposed ();
-#endif
                                return webHeaders; 
                        }
                }
 
-#if NET_2_0
                static Exception GetMustImplement ()
                {
                        return new NotImplementedException ();
@@ -201,7 +189,6 @@ namespace System.Net
                                throw GetMustImplement ();
                        }
                }
-#endif
                
                public DateTime LastModified {
                        get {
@@ -215,6 +202,9 @@ namespace System.Net
                        }
                }
                
+#if NET_4_5
+               virtual
+#endif
                public string Method {
                        get {
                                CheckDisposed ();
@@ -243,12 +233,18 @@ namespace System.Net
                        }
                }
                
+#if NET_4_5
+               virtual
+#endif
                public HttpStatusCode StatusCode {
                        get {
                                return statusCode; 
                        }
                }
                
+#if NET_4_5
+               virtual
+#endif
                public string StatusDescription {
                        get {
                                CheckDisposed ();
@@ -257,12 +253,6 @@ namespace System.Net
                }
 
                // Methods
-#if !NET_2_0
-               public override int GetHashCode ()
-               {
-                       return base.GetHashCode ();
-               }
-#endif
                
                public string GetResponseHeader (string headerName)
                {
@@ -287,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;
@@ -299,11 +289,8 @@ namespace System.Net
                        GetObjectData (serializationInfo, streamingContext);
                }
 
-#if NET_2_0
-               protected override
-#endif
-               void GetObjectData (SerializationInfo serializationInfo,
-                                   StreamingContext streamingContext)
+               protected override void GetObjectData (SerializationInfo serializationInfo,
+                       StreamingContext streamingContext)
                {
                        SerializationInfo info = serializationInfo;
 
@@ -321,42 +308,33 @@ namespace System.Net
 
                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;
-#if !NET_2_0
-                               webHeaders = null;
-#endif
-                               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 () 
                {
@@ -369,217 +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);
-
-                       while (parser.GetNextNameValue (out name, out val)) {
-                               if ((name == null || name == "") && cookie == null)
-                                       continue;
-
-                               if (cookie == null) {
-                                       cookie = new Cookie (name, val);
-                                       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;
-#if NET_2_0
-                               case "HTTPONLY":
-                                       cookie.HttpOnly = true;
-                                       break;
-#endif
-                               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;
-
-                                       cookie.Expires = TryParseCookieExpires (val);
-                                       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;
-                               }
-                       }
-
                        if (cookieCollection == null)
                                cookieCollection = new CookieCollection ();
 
-                       if (cookie.Domain == "")
-                               cookie.Domain = uri.Host;
-
-                       cookieCollection.Add (cookie);
-                       if (cookie_container != null)
-                               cookie_container.Add (uri, cookie);
-               }
-
-               void SetCookie2 (string cookies_str)
-               {
-                       string [] cookies = cookies_str.Split (',');
-       
-                       foreach (string cookie_str in cookies)
-                               SetCookie (cookie_str);
-               }
-
-               string[] cookieExpiresFormats =
-                       new string[] { "r",
-                                       "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
-                                       "ddd, dd'-'MMM'-'yy HH':'mm':'ss 'GMT'" };
-
-               DateTime TryParseCookieExpires (string value)
-               {
-                       if (value == null || value.Length == 0)
-                               return DateTime.MinValue;
+                       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;
+                               }
 
-                       for (int i = 0; i < cookieExpiresFormats.Length; i++)
-                       {
-                               try {
-                                       DateTime cookieExpiresUtc = DateTime.ParseExact (value, cookieExpiresFormats [i], CultureInfo.InvariantCulture);
+                               if (cookie.HasDomain &&
+                                   !CookieContainer.CheckSameOrigin (uri, cookie.Domain))
+                                       continue;
 
-                                       //convert UTC/GMT time to local time
-#if NET_2_0
-                                       cookieExpiresUtc = DateTime.SpecifyKind (cookieExpiresUtc, DateTimeKind.Utc);
-                                       return TimeZone.CurrentTimeZone.ToLocalTime (cookieExpiresUtc);
-#else
-                                       //DateTime.Kind is only available on .NET 2.0, so do some calculation
-                                       TimeSpan localOffset = TimeZone.CurrentTimeZone.GetUtcOffset (cookieExpiresUtc.Date);
-                                       return cookieExpiresUtc.Add (localOffset);
-#endif
-                               } catch {}
+                               cookieCollection.Add (cookie);
+                               if (cookie_container != null) {
+                                       cookie_container.Add (uri, cookie);
+                                       at_least_one_set = true;
+                               }
                        }
 
-                       //If we can't parse Expires, use cookie as session cookie (expires is DateTime.MinValue)
-                       return DateTime.MinValue;
+                       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 ();
-               }
-       }
 }