Remove leading dot check for cookie domain (#39781)
authorNatalia Kondratyeva <knatalia@microsoft.com>
Fri, 24 Jul 2020 07:18:00 +0000 (10:18 +0300)
committerGitHub <noreply@github.com>
Fri, 24 Jul 2020 07:18:00 +0000 (10:18 +0300)
Minimal fix for domain-related cookie issues of #26141

To fully comply with RFC 6265, one should remove deprecated cookie
properties, such as Version, from public API. So only the stated
issues with leading dot were addressed now.

Also note that the leading dot was not stripped from the domain even
though RFC 6265 proposed it. This behavior was chosen because
browsers like Chrome and Edge also don't strip the leading dot.

src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs
src/libraries/System.Net.Primitives/tests/FunctionalTests/CookieTest/CookieContainerTest.cs
src/libraries/System.Net.Primitives/tests/UnitTests/CookieContainerTest.cs

index c953ef2..c9a4ef4 100644 (file)
@@ -414,14 +414,6 @@ namespace System.Net
                     // Domain must start with '.' if set explicitly.
                     if (domain[0] != '.')
                     {
-                        if (!(variant == CookieVariant.Rfc2965 || variant == CookieVariant.Plain))
-                        {
-                            if (shouldThrow)
-                            {
-                                throw new CookieException(SR.Format(SR.net_cookie_attribute, CookieFields.DomainAttributeName, m_domain));
-                            }
-                            return false;
-                        }
                         domain = '.' + domain;
                     }
 
index 621bc1d..ca50863 100644 (file)
@@ -13,7 +13,7 @@ namespace System.Net.Primitives.Functional.Tests
         private const string CookieValue2 = "CookieValue2";
 
         [Fact]
-        public void Add_CookieVersion1AndRootDomainWithNoLeadingDot_ThrowsCookieException()
+        public void Add_CookieVersion1AndRootDomainWithNoLeadingDot_Success()
         {
             const string SchemePrefix = "http://";
             const string OriginalDomain = "contoso.com";
@@ -21,7 +21,8 @@ namespace System.Net.Primitives.Functional.Tests
             var container = new CookieContainer();
             var cookie = new Cookie(CookieName1, CookieValue1) { Version = 1, Domain = OriginalDomain };
             var uri = new Uri(SchemePrefix + OriginalDomain);
-            Assert.Throws<CookieException>(() => container.Add(uri, cookie));
+            container.Add(uri, cookie);
+            Assert.Equal(1, container.GetCookies(uri).Count);
         }
 
         [Fact]
index ec97b80..cd2ba34 100644 (file)
@@ -364,7 +364,7 @@ namespace System.Net.Primitives.Unit.Tests
         }
 
         [Fact]
-        public void Add_CookieVersion1AndRootDomainWithNoLeadingDot_ThrowsCookieException()
+        public void Add_CookieVersion1AndRootDomainWithNoLeadingDot_Success()
         {
             const string SchemePrefix = "http://";
             const string OriginalDomain = "contoso.com";
@@ -372,7 +372,8 @@ namespace System.Net.Primitives.Unit.Tests
             var container = new CookieContainer();
             var cookie = new Cookie(CookieName1, CookieValue1) { Version = 1, Domain = OriginalDomain };
             var uri = new Uri(SchemePrefix + OriginalDomain);
-            Assert.Throws<CookieException>(() => container.Add(uri, cookie));
+            container.Add(uri, cookie);
+            Assert.Equal(1, container.GetCookies(uri).Count);
         }
 
         [Fact]
@@ -762,5 +763,80 @@ namespace System.Net.Primitives.Unit.Tests
                 Assert.Equal(c1.Value, c2.Value);
             }
         }
+
+        public static IEnumerable<object[]> DomainCheckIgnoresVersionData()
+        {
+            string[] hosts = { "localhost", "example.com", "test.example.com" };
+            int?[] ports = { null, 5000 };
+            int?[] versions = { null, 0, 1, 100 };
+
+            foreach (string host in hosts)
+            {
+                foreach (int? port in ports)
+                {
+                    string url = $"http://{host}" + (port != null ? $":{port}" : "");
+                    string domainWithLeadingDot = "." + host;
+
+                    foreach (int? version in versions)
+                    {
+                        // domain with leading dot
+                        yield return new object[] { url, domainWithLeadingDot, version };
+
+                        // domain without leading dot
+                        yield return new object[] { url, host, version };
+                    }
+                }
+            }
+        }
+
+        [Theory]
+        [MemberData(nameof(DomainCheckIgnoresVersionData))]
+        public void SetCookies_DomainCheckSuccess_IgnoresVersion(string url, string domain, int? version)
+        {
+            var uri = new Uri(url);
+
+            string cookie = $"my_cookie=my_value; Domain={domain}" + (version != null ? $"; Version = {version}" : "");
+            CookieContainer container = new CookieContainer();
+
+            container.SetCookies(uri, cookie);
+
+            CookieCollection acceptedCookies = container.GetCookies(uri);
+            Assert.Equal(1, acceptedCookies.Count);
+            Assert.Equal(domain, acceptedCookies[0].Domain);
+        }
+
+        [Theory]
+        [InlineData(".example.com")]
+        [InlineData("example.com")]
+        [InlineData(".test.example.com")]
+        [InlineData("test.example.com")]
+        public void SetCookies_DomainCheckSuccess_IgnoresAbsenceOfLeadingDot(string domain)
+        {
+            var uri = new Uri("http://test.example.com");
+
+            string cookie = $"my_cookie=my_value; Domain={domain}";
+            CookieContainer container = new CookieContainer();
+
+            container.SetCookies(uri, cookie);
+
+            CookieCollection acceptedCookies = container.GetCookies(uri);
+            Assert.Equal(1, acceptedCookies.Count);
+            Assert.Equal(domain, acceptedCookies[0].Domain);
+        }
+
+        [Theory]
+        [InlineData(".other.example.com")]
+        [InlineData("other.example.com")]
+        [InlineData(".xample.com")]
+        [InlineData("xample.com")]
+        public void SetCookies_DomainCheckFailure_IgnoresAbsenceOfLeadingDot(string domain)
+        {
+            var uri = new Uri("http://test.example.com");
+
+            string cookie = $"my_cookie=my_value; Domain={domain}";
+            CookieContainer container = new CookieContainer();
+
+            Assert.Throws<CookieException>(() => container.SetCookies(uri, cookie));
+        }
     }
 }