Backed out bug 616264 because of regressions (bug 650522) a=LegNeato
authorEhsan Akhgari <ehsan@mozilla.com>
Mon, 18 Apr 2011 18:15:08 -0400
changeset 27398 9e0d3f6ee9af5b0270b43f60ceefd18e7ea31f7e
parent 27396 6035826050f498d492cab84a8d008e2cc472c58d
child 27399 a846a6d5bbf8694fa1512d056e90aa0ca1f6f722
push id2715
push usereakhgari@mozilla.com
push dateMon, 18 Apr 2011 22:19:00 +0000
reviewersLegNeato
bugs616264, 650522
milestone1.9.1.20pre
Backed out bug 616264 because of regressions (bug 650522) a=LegNeato
extensions/cookie/test/unit/test_bug526789.js
netwerk/cookie/src/nsCookieService.cpp
netwerk/cookie/src/nsCookieService.h
netwerk/dns/src/nsEffectiveTLDService.cpp
netwerk/test/TestCookie.cpp
--- a/extensions/cookie/test/unit/test_bug526789.js
+++ b/extensions/cookie/test/unit/test_bug526789.js
@@ -1,11 +1,8 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 function do_check_throws(f, result, stack)
 {
   if (!stack)
     stack = Components.stack.caller;
@@ -19,36 +16,20 @@ function do_check_throws(f, result, stac
   }
   do_throw("expected result " + result + ", none thrown", stack);
 }
 
 function run_test() {
   var cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService);
   var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2);
   var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
-  var expiry = (Date.now() + 1000) * 1000;
 
   cm.removeAll();
 
-  // Test that 'baz.com' and 'baz.com.' are treated differently
-  cm.add("baz.com", "/", "foo", "bar", false, false, true, expiry);
-  do_check_eq(cm.countCookiesFromHost("baz.com"), 1);
-  do_check_eq(cm.countCookiesFromHost("baz.com."), 0);
-  cm.remove("baz.com", "foo", "/", false);
-  do_check_eq(cm.countCookiesFromHost("baz.com"), 0);
-
-  cm.add("baz.com.", "/", "foo", "bar", false, false, true, expiry);
-  do_check_eq(cm.countCookiesFromHost("baz.com"), 0);
-  do_check_eq(cm.countCookiesFromHost("baz.com."), 1);
-  cm.remove("baz.com", "foo", "/", false);
-  do_check_eq(cm.countCookiesFromHost("baz.com."), 1);
-  cm.remove("baz.com.", "foo", "/", false);
-  do_check_eq(cm.countCookiesFromHost("baz.com."), 0);
-
-  // Test that setting an empty or '.' http:// host results in a no-op
+  // test that an empty or '.' http:// host results in a no-op
   var uri = ios.newURI("http://baz.com/", null, null);
   var emptyuri = ios.newURI("http:///", null, null);
   var doturi = ios.newURI("http://./", null, null);
   do_check_eq(uri.asciiHost, "baz.com");
   do_check_eq(emptyuri.asciiHost, "");
   do_check_eq(doturi.asciiHost, ".");
   cs.setCookieString(emptyuri, null, "foo2=bar", null);
   do_check_eq(getCookieCount(), 0);
@@ -58,132 +39,78 @@ function run_test() {
   do_check_eq(getCookieCount(), 1);
 
   do_check_eq(cs.getCookieString(uri, null), "foo=bar");
   do_check_eq(cs.getCookieString(emptyuri, null), null);
   do_check_eq(cs.getCookieString(doturi, null), null);
 
   do_check_eq(cm.countCookiesFromHost("baz.com"), 1);
   do_check_eq(cm.countCookiesFromHost(""), 0);
-  do_check_throws(function() {
-    cm.countCookiesFromHost(".");
-  }, Cr.NS_ERROR_ILLEGAL_VALUE);
+  do_check_eq(cm.countCookiesFromHost("."), 0);
 
   cm.removeAll();
 
-  // Test that an empty file:// host works
-  emptyuri = ios.newURI("file:///", null, null);
+  // test that an empty file:// host works
+  var emptyuri = ios.newURI("file:///", null, null);
   do_check_eq(emptyuri.asciiHost, "");
   do_check_eq(ios.newURI("file://./", null, null).asciiHost, "");
   do_check_eq(ios.newURI("file://foo.bar/", null, null).asciiHost, "");
   cs.setCookieString(emptyuri, null, "foo2=bar", null);
   do_check_eq(getCookieCount(), 1);
   cs.setCookieString(emptyuri, null, "foo3=bar; domain=", null);
   do_check_eq(getCookieCount(), 2);
   cs.setCookieString(emptyuri, null, "foo4=bar; domain=.", null);
   do_check_eq(getCookieCount(), 2);
   cs.setCookieString(emptyuri, null, "foo5=bar; domain=bar.com", null);
   do_check_eq(getCookieCount(), 2);
 
   do_check_eq(cs.getCookieString(emptyuri, null), "foo2=bar; foo3=bar");
 
   do_check_eq(cm.countCookiesFromHost("baz.com"), 0);
   do_check_eq(cm.countCookiesFromHost(""), 2);
+  do_check_eq(cm.countCookiesFromHost("."), 0);
 
   cm.removeAll();
 
-  // Test that an empty host to add() or remove() works,
-  // but a host of '.' doesn't
+  // test that an empty host to add() or remove() works,
+  // but a host of '.' or ending with a '.' doesn't
+  var expiry = (Date.now() + 1000) * 1000;
   cm.add("", "/", "foo2", "bar", false, false, true, expiry);
   do_check_eq(getCookieCount(), 1);
   do_check_throws(function() {
     cm.add(".", "/", "foo3", "bar", false, false, true, expiry);
   }, Cr.NS_ERROR_ILLEGAL_VALUE);
   do_check_eq(getCookieCount(), 1);
+  cm.add("test.com", "/", "foo", "bar", false, false, true, expiry);
+  do_check_eq(getCookieCount(), 2);
+  do_check_throws(function() {
+    cm.add("test.com.", "/", "foo4", "bar", false, false, true, expiry);
+  }, Cr.NS_ERROR_ILLEGAL_VALUE);
+  do_check_eq(getCookieCount(), 2);
 
   cm.remove("", "foo2", "/", false);
-  do_check_eq(getCookieCount(), 0);
+  do_check_eq(getCookieCount(), 1);
   do_check_throws(function() {
     cm.remove(".", "foo3", "/", false);
   }, Cr.NS_ERROR_ILLEGAL_VALUE);
-
-  // Test that the 'domain' attribute accepts a leading dot for IP addresses,
-  // aliases such as 'localhost', and eTLD's such as 'co.uk'; but that the
-  // resulting cookie is for the exact host only.
-  testDomainCookie("http://192.168.0.1/", "192.168.0.1");
-  testDomainCookie("http://localhost/", "localhost");
-  testDomainCookie("http://co.uk/", "co.uk");
-
-  // Test that trailing dots are treated differently for purposes of the
-  // 'domain' attribute when using setCookieString.
-  testTrailingDotCookie("http://192.168.0.1", "192.168.0.1");
-  testTrailingDotCookie("http://localhost", "localhost");
-  testTrailingDotCookie("http://foo.com", "foo.com");
+  do_check_eq(getCookieCount(), 1);
+  do_check_throws(function() {
+    cm.remove("test.com.", "foo4", "/", false);
+  }, Cr.NS_ERROR_ILLEGAL_VALUE);
+  do_check_eq(getCookieCount(), 1);
+  cm.remove("test.com", "foo", "/", false);
+  do_check_eq(getCookieCount(), 0);
 
   cm.removeAll();
 }
 
 function getCookieCount() {
   var count = 0;
   var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2);
   var enumerator = cm.enumerator;
   while (enumerator.hasMoreElements()) {
     if (!(enumerator.getNext() instanceof Ci.nsICookie2))
       throw new Error("not a cookie");
     ++count;
   }
   return count;
 }
 
-function testDomainCookie(uriString, domain) {
-  var cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService);
-  var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2);
-  var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
-
-  cm.removeAll();
-
-  var uri = ios.newURI(uriString, null, null);
-  cs.setCookieString(uri, null, "foo=bar; domain=" + domain, null);
-  do_check_true(cookieExistsForHost(domain));
-  do_check_false(cookieExistsForHost("." + domain));
-  cm.removeAll();
-
-  cs.setCookieString(uri, null, "foo=bar; domain=." + domain, null);
-  do_check_true(cookieExistsForHost(domain));
-  do_check_false(cookieExistsForHost("." + domain));
-  cm.removeAll();
-}
-
-function testTrailingDotCookie(uriString, domain) {
-  var cs = Cc["@mozilla.org/cookieService;1"].getService(Ci.nsICookieService);
-  var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2);
-  var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
-
-  cm.removeAll();
-
-  var uri = ios.newURI(uriString, null, null);
-  cs.setCookieString(uri, null, "foo=bar; domain=" + domain + ".", null);
-  do_check_eq(cm.countCookiesFromHost(domain), 0);
-  do_check_eq(cm.countCookiesFromHost(domain + "."), 0);
-  cm.removeAll();
-
-  uri = ios.newURI(uriString + ".", null, null);
-  cs.setCookieString(uri, null, "foo=bar; domain=" + domain, null);
-  do_check_eq(cm.countCookiesFromHost(domain), 0);
-  do_check_eq(cm.countCookiesFromHost(domain + "."), 0);
-  cm.removeAll();
-}
-
-// Get a single cookie with a host exactly equal to 'domain'.
-function cookieExistsForHost(domain) {
-  var result = false;
-  var cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2);
-  var enumerator = cm.enumerator;
-  while (enumerator.hasMoreElements()) {
-    var cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2);
-    if (cookie.host == domain) {
-      do_check_false(result);
-      result = true;
-    }
-  }
-  return result;
-}
-
--- a/netwerk/cookie/src/nsCookieService.cpp
+++ b/netwerk/cookie/src/nsCookieService.cpp
@@ -948,20 +948,20 @@ nsCookieService::Add(const nsACString &a
                      const nsACString &aPath,
                      const nsACString &aName,
                      const nsACString &aValue,
                      PRBool            aIsSecure,
                      PRBool            aIsHttpOnly,
                      PRBool            aIsSession,
                      PRInt64           aExpiry)
 {
-  // empty domains are acceptable (e.g. file:// URI's), but we reject the host
-  // '.'. 
-  NS_ENSURE_TRUE(aDomain.IsEmpty() ||
-    !(aDomain.Length() == 1 && aDomain.Last() == '.'), NS_ERROR_INVALID_ARG);
+  // empty domains are acceptable (e.g. file:// URI's), but domains containing
+  // a trailing '.' will break our domainwalking code.
+  NS_ENSURE_TRUE(aDomain.IsEmpty() || aDomain.Last() != '.',
+                 NS_ERROR_INVALID_ARG);
 
   PRInt64 currentTimeInUsec = PR_Now();
 
   nsRefPtr<nsCookie> cookie =
     nsCookie::Create(aName, aValue, aDomain, aPath,
                      aExpiry,
                      currentTimeInUsec,
                      currentTimeInUsec,
@@ -977,20 +977,20 @@ nsCookieService::Add(const nsACString &a
 }
 
 NS_IMETHODIMP
 nsCookieService::Remove(const nsACString &aHost,
                         const nsACString &aName,
                         const nsACString &aPath,
                         PRBool           aBlocked)
 {
-  // empty domains are acceptable (e.g. file:// URI's), but we reject the host
-  // '.'.
-  NS_ENSURE_TRUE(aHost.IsEmpty() ||
-    !(aHost.Length() == 1 && aHost.Last() == '.'), NS_ERROR_INVALID_ARG);
+  // empty domains are acceptable (e.g. file:// URI's), but domains containing
+  // a trailing '.' will break our domainwalking code.
+  NS_ENSURE_TRUE(aHost.IsEmpty() || aHost.Last() != '.',
+                 NS_ERROR_INVALID_ARG);
 
   nsListIter matchIter;
   if (FindCookie(PromiseFlatCString(aHost),
                  PromiseFlatCString(aName),
                  PromiseFlatCString(aPath),
                  matchIter,
                  PR_Now() / PR_USEC_PER_SEC)) {
     nsRefPtr<nsCookie> cookie = matchIter.current;
@@ -1260,31 +1260,29 @@ nsCookieService::GetCookieInternal(nsIUR
   // note: there was a "check if host has embedded whitespace" here.
   // it was removed since this check was added into the nsIURI impl (bug 146094).
   nsCAutoString hostFromURI, pathFromURI;
   if (NS_FAILED(aHostURI->GetAsciiHost(hostFromURI)) ||
       NS_FAILED(aHostURI->GetPath(pathFromURI))) {
     COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, nsnull, "couldn't get host/path from URI");
     return;
   }
+  // trim trailing dots
+  hostFromURI.Trim(".");
 
   // block any URIs without a host that aren't file:// URIs
   if (hostFromURI.IsEmpty()) {
     PRBool isFileURI = PR_FALSE;
     aHostURI->SchemeIs("file", &isFileURI);
     if (!isFileURI) {
       COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, nsnull, "host is empty");
       return;
     }
   }
 
-  // aHostURI may be the string '.'. If so, fail.
-  if (hostFromURI.Length() == 1 && hostFromURI.Last() == '.')
-    return;
-
   // insert a leading dot, so we begin the hash lookup with the
   // equivalent domain cookie host
   hostFromURI.Insert(NS_LITERAL_CSTRING("."), 0);
 
   // check if aHostURI is using an https secure protocol.
   // if it isn't, then we can't send a secure cookie over the connection.
   // if SchemeIs fails, assume an insecure connection, to be on the safe side
   PRBool isSecure;
@@ -1347,17 +1345,17 @@ nsCookieService::GetCookieInternal(nsIUR
       }
 
       // all checks passed - add to list and check if lastAccessed stamp needs updating
       foundCookieList.AppendElement(cookie);
       if (currentTimeInUsec - cookie->LastAccessed() > kCookieStaleThreshold)
         stale = PR_TRUE;
     }
 
-    if (!nextDot || *(nextDot + 1) == '.')
+    if (!nextDot)
       break;
 
     currentDot = nextDot;
     nextDot = *currentDot ? strchr(currentDot + 1, '.') : nsnull;
   } while (1);
 
   PRInt32 count = foundCookieList.Count();
   if (count == 0)
@@ -1861,16 +1859,19 @@ nsCookieService::IsForeign(nsIURI *aHost
 {
   // Get hosts
   nsCAutoString currentHost, firstHost;
   if (NS_FAILED(aHostURI->GetAsciiHost(currentHost)) ||
       NS_FAILED(aFirstURI->GetAsciiHost(firstHost))) {
     // assume foreign
     return PR_TRUE;
   }
+  // trim trailing dots
+  currentHost.Trim(".");
+  firstHost.Trim(".");
 
   // fast path: check if the two hosts are identical.
   // this also covers two special cases:
   // 1) if we're dealing with IP addresses, require an exact match. this
   // eliminates any chance of IP address funkiness (e.g. the alias 127.1
   // domain-matching 99.54.127.1). bug 105917 originally noted the requirement
   // to deal with IP addresses. note that GetBaseDomain() below will return an
   // error if the URI is an IP address.
@@ -1884,16 +1885,17 @@ nsCookieService::IsForeign(nsIURI *aHost
   // get the base domain for the originating URI.
   // e.g. for "images.bbc.co.uk", this would be "bbc.co.uk".
   nsCAutoString baseDomain;
   nsresult rv = mTLDService->GetBaseDomain(aFirstURI, 0, baseDomain);
   if (NS_FAILED(rv)) {
     // URI is an IP, eTLD, or something else went wrong - assume foreign
     return PR_TRUE;
   }  
+  baseDomain.Trim(".");
 
   // ensure the host domain is derived from the base domain.
   // we prepend dots before the comparison to ensure e.g.
   // "mybbc.co.uk" isn't matched as a superset of "bbc.co.uk".
   currentHost.Insert(NS_LITERAL_CSTRING("."), 0);
   baseDomain.Insert(NS_LITERAL_CSTRING("."), 0);
   return !StringEndsWith(currentHost, baseDomain);
 }
@@ -1964,53 +1966,46 @@ nsCookieService::CheckDomain(nsCookieAtt
 {
   nsresult rv;
 
   // get host from aHostURI
   nsCAutoString hostFromURI;
   if (NS_FAILED(aHostURI->GetAsciiHost(hostFromURI))) {
     return PR_FALSE;
   }
+  // trim trailing dots
+  hostFromURI.Trim(".");
 
   // block any URIs without a host that aren't file:// URIs
   if (hostFromURI.IsEmpty()) {
     PRBool isFileURI = PR_FALSE;
     aHostURI->SchemeIs("file", &isFileURI);
     if (!isFileURI)
       return PR_FALSE;
   }
 
-  // aHostURI may be the string '.'. If so, fail.
-  if (hostFromURI.Length() == 1 && hostFromURI.Last() == '.')
-    return PR_FALSE;
-
   // if a domain is given, check the host has permission
   if (!aCookieAttributes.host.IsEmpty()) {
-    // Tolerate leading '.' characters, but not if it's otherwise an empty host.
-    if (aCookieAttributes.host.Length() > 1 &&
-        aCookieAttributes.host.First() == '.') {
-      aCookieAttributes.host.Cut(0, 1);
-    }
-
+    aCookieAttributes.host.Trim(".");
     // switch to lowercase now, to avoid case-insensitive compares everywhere
     ToLowerCase(aCookieAttributes.host);
 
     // get the base domain for the host URI.
     // e.g. for "images.bbc.co.uk", this would be "bbc.co.uk", which
     // represents the lowest level domain a cookie can be set for.
     nsCAutoString baseDomain;
     rv = mTLDService->GetBaseDomain(aHostURI, 0, baseDomain);
+    baseDomain.Trim(".");
     if (NS_FAILED(rv)) {
       // check whether the host is an IP address, and leave the cookie as
       // a non-domain one. this will require an exact host match for the cookie,
       // so we eliminate any chance of IP address funkiness (e.g. the alias 127.1
       // domain-matching 99.54.127.1). bug 105917 originally noted the
       // requirement to deal with IP addresses.
-      if (rv == NS_ERROR_HOST_IS_IP_ADDRESS ||
-          rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS)
+      if (rv == NS_ERROR_HOST_IS_IP_ADDRESS)
         return hostFromURI.Equals(aCookieAttributes.host);
 
       return PR_FALSE;
     }
 
     // ensure the proposed domain is derived from the base domain; and also
     // that the host domain is derived from the proposed domain (per RFC2109).
     // we prepend a dot before the comparison to ensure e.g.
@@ -2201,21 +2196,16 @@ nsCookieService::CookieExists(nsICookie2
 }
 
 // count the number of cookies from a given host, and simultaneously find the
 // oldest cookie from the host.
 PRUint32
 nsCookieService::CountCookiesFromHostInternal(const nsACString  &aHost,
                                               nsEnumerationData &aData)
 {
-  // empty domains are acceptable (e.g. file:// URI's), but we reject the host
-  // '.'.
-  NS_ASSERTION(aHost.IsEmpty() ||
-    !(aHost.Length() == 1 && aHost.Last() == '.'), "invalid host");
-
   PRUint32 countFromHost = 0;
   nsCAutoString hostWithDot(NS_LITERAL_CSTRING(".") + aHost);
 
   const char *currentDot = hostWithDot.get();
   const char *nextDot = currentDot + 1;
   do {
     nsCookieEntry *entry = mDBState->hostTable.GetEntry(currentDot);
     for (nsListIter iter(entry); iter.current; ++iter) {
@@ -2226,37 +2216,32 @@ nsCookieService::CountCookiesFromHostInt
         // check if we've found the oldest cookie so far
         if (aData.oldestTime > iter.current->LastAccessed()) {
           aData.oldestTime = iter.current->LastAccessed();
           aData.iter = iter;
         }
       }
     }
 
-    if (!nextDot || *(nextDot + 1) == '.')
+    if (!nextDot)
       break;
 
     currentDot = nextDot;
     nextDot = *currentDot ? strchr(currentDot + 1, '.') : nsnull;
   } while (1);
 
   return countFromHost;
 }
 
 // count the number of cookies stored by a particular host. this is provided by the
 // nsICookieManager2 interface.
 NS_IMETHODIMP
 nsCookieService::CountCookiesFromHost(const nsACString &aHost,
                                       PRUint32         *aCountFromHost)
 {
-  // empty domains are acceptable (e.g. file:// URI's), but we reject the host
-  // '.'.
-  NS_ENSURE_TRUE(aHost.IsEmpty() ||
-    !(aHost.Length() == 1 && aHost.Last() == '.'), NS_ERROR_INVALID_ARG);
-
   // we don't care about finding the oldest cookie here, so disable the search
   nsEnumerationData data(PR_Now() / PR_USEC_PER_SEC, LL_MININT);
   *aCountFromHost = CountCookiesFromHostInternal(aHost, data);
   return NS_OK;
 }
 
 // find an exact cookie specified by host, name, and path that hasn't expired.
 PRBool
--- a/netwerk/cookie/src/nsCookieService.h
+++ b/netwerk/cookie/src/nsCookieService.h
@@ -187,17 +187,16 @@ class nsCookieService : public nsICookie
     nsresult                      SetCookieStringInternal(nsIURI *aHostURI, nsIPrompt *aPrompt, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, PRBool aFromHttp);
     PRBool                        SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, nsDependentCString &aCookieHeader, PRInt64 aServerTime, PRBool aFromHttp);
     void                          AddInternal(nsCookie *aCookie, PRInt64 aCurrentTime, nsIURI *aHostURI, const char *aCookieHeader, PRBool aFromHttp);
     void                          RemoveCookieFromList(nsListIter &aIter);
     PRBool                        AddCookieToList(nsCookie *aCookie, PRBool aWriteToDB = PR_TRUE);
     void                          UpdateCookieInList(nsCookie *aCookie, PRInt64 aLastAccessed);
     static PRBool                 GetTokenValue(nsASingleFragmentCString::const_char_iterator &aIter, nsASingleFragmentCString::const_char_iterator &aEndIter, nsDependentCSubstring &aTokenString, nsDependentCSubstring &aTokenValue, PRBool &aEqualsFound);
     static PRBool                 ParseAttributes(nsDependentCString &aCookieHeader, nsCookieAttributes &aCookie);
-    nsresult                      NormalizeHost(nsCString &aHost);
     PRBool                        IsForeign(nsIURI *aHostURI, nsIURI *aFirstURI);
     PRUint32                      CheckPrefs(nsIURI *aHostURI, nsIChannel *aChannel, const char *aCookieHeader);
     PRBool                        CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI);
     static PRBool                 CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
     static PRBool                 GetExpiry(nsCookieAttributes &aCookie, PRInt64 aServerTime, PRInt64 aCurrentTime);
     void                          RemoveAllFromMemory();
     void                          RemoveExpiredCookies(PRInt64 aCurrentTime);
     PRBool                        FindCookie(const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter, PRInt64 aCurrentTime);
--- a/netwerk/dns/src/nsEffectiveTLDService.cpp
+++ b/netwerk/dns/src/nsEffectiveTLDService.cpp
@@ -164,28 +164,23 @@ nsEffectiveTLDService::GetBaseDomainFrom
 // includes characters that are not valid in a URL. Normalization is performed
 // on the host string and the result will be in UTF8.
 nsresult
 nsEffectiveTLDService::GetBaseDomainInternal(nsCString  &aHostname,
                                              PRUint32    aAdditionalParts,
                                              nsACString &aBaseDomain)
 {
   if (aHostname.IsEmpty())
-    return NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS;
+    return NS_ERROR_INVALID_ARG;
 
   // chomp any trailing dot, and keep track of it for later
   PRBool trailingDot = aHostname.Last() == '.';
   if (trailingDot)
     aHostname.Truncate(aHostname.Length() - 1);
 
-  // check the edge cases of the host being '.' or having a second trailing '.',
-  // since subsequent checks won't catch it.
-  if (aHostname.IsEmpty() || aHostname.Last() == '.')
-    return NS_ERROR_INVALID_ARG;
-
   // Check if we're dealing with an IPv4/IPv6 hostname, and return
   PRNetAddr addr;
   PRStatus result = PR_StringToNetAddr(aHostname.get(), &addr);
   if (result == PR_SUCCESS)
     return NS_ERROR_HOST_IS_IP_ADDRESS;
 
   // Walk up the domain tree, most specific to least specific,
   // looking for matches at each level.  Note that a given level may
--- a/netwerk/test/TestCookie.cpp
+++ b/netwerk/test/TestCookie.cpp
@@ -304,21 +304,21 @@ main(PRInt32 argc, char *argv[])
 
       // test some basic variations of the domain & path
       SetACookie(cookieService, "http://www.basic.com", nsnull, "test=basic", nsnull);
       GetACookie(cookieService, "http://www.basic.com", nsnull, getter_Copies(cookie));
       rv[0] = CheckResult(cookie.get(), MUST_EQUAL, "test=basic");
       GetACookie(cookieService, "http://www.basic.com/testPath/testfile.txt", nsnull, getter_Copies(cookie));
       rv[1] = CheckResult(cookie.get(), MUST_EQUAL, "test=basic");
       GetACookie(cookieService, "http://www.basic.com./", nsnull, getter_Copies(cookie));
-      rv[2] = CheckResult(cookie.get(), MUST_BE_NULL);
+      rv[2] = CheckResult(cookie.get(), MUST_EQUAL, "test=basic");
       GetACookie(cookieService, "http://www.basic.com.", nsnull, getter_Copies(cookie));
-      rv[3] = CheckResult(cookie.get(), MUST_BE_NULL);
+      rv[3] = CheckResult(cookie.get(), MUST_EQUAL, "test=basic");
       GetACookie(cookieService, "http://www.basic.com./testPath/testfile.txt", nsnull, getter_Copies(cookie));
-      rv[4] = CheckResult(cookie.get(), MUST_BE_NULL);
+      rv[4] = CheckResult(cookie.get(), MUST_EQUAL, "test=basic");
       GetACookie(cookieService, "http://www.basic2.com/", nsnull, getter_Copies(cookie));
       rv[5] = CheckResult(cookie.get(), MUST_BE_NULL);
       SetACookie(cookieService, "http://www.basic.com", nsnull, "test=basic; max-age=-1", nsnull);
       GetACookie(cookieService, "http://www.basic.com/", nsnull, getter_Copies(cookie));
       rv[6] = CheckResult(cookie.get(), MUST_BE_NULL);
 
       allTestsPassed = PrintResult(rv, 7) && allTestsPassed;
 
@@ -327,17 +327,17 @@ main(PRInt32 argc, char *argv[])
       printf("*** Beginning domain tests...\n");
 
       // test some variations of the domain & path, for different domains of
       // a domain cookie
       SetACookie(cookieService, "http://www.domain.com", nsnull, "test=domain; domain=domain.com", nsnull);
       GetACookie(cookieService, "http://domain.com", nsnull, getter_Copies(cookie));
       rv[0] = CheckResult(cookie.get(), MUST_EQUAL, "test=domain");
       GetACookie(cookieService, "http://domain.com.", nsnull, getter_Copies(cookie));
-      rv[1] = CheckResult(cookie.get(), MUST_BE_NULL);
+      rv[1] = CheckResult(cookie.get(), MUST_EQUAL, "test=domain");
       GetACookie(cookieService, "http://www.domain.com", nsnull, getter_Copies(cookie));
       rv[2] = CheckResult(cookie.get(), MUST_EQUAL, "test=domain");
       GetACookie(cookieService, "http://foo.domain.com", nsnull, getter_Copies(cookie));
       rv[3] = CheckResult(cookie.get(), MUST_EQUAL, "test=domain");
       SetACookie(cookieService, "http://www.domain.com", nsnull, "test=domain; domain=domain.com; max-age=-1", nsnull);
       GetACookie(cookieService, "http://domain.com", nsnull, getter_Copies(cookie));
       rv[4] = CheckResult(cookie.get(), MUST_BE_NULL);