--- a/extensions/cookie/test/unit/test_bug526789.js
+++ b/extensions/cookie/test/unit/test_bug526789.js
@@ -1,12 +1,14 @@
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+
function do_check_throws(f, result, stack)
{
if (!stack)
stack = Components.stack.caller;
try {
f();
} catch (exc) {
@@ -15,81 +17,212 @@ function do_check_throws(f, result, stac
do_throw("expected result " + result + ", caught " + exc, stack);
}
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 an empty 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);
+ // test that variants of 'baz.com' get normalized appropriately, but that
+ // malformed hosts are rejected
+ 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"), 1);
+ do_check_eq(cm.countCookiesFromHost(".baz.com"), 1);
+ do_check_eq(cm.countCookiesFromHost("baz.com."), 1);
+ do_check_eq(cm.countCookiesFromHost(".baz.com."), 1);
+ do_check_throws(function() {
+ cm.countCookiesFromHost("baz.com..");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+ do_check_throws(function() {
+ cm.countCookiesFromHost("baz..com");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+ do_check_throws(function() {
+ cm.countCookiesFromHost("..baz.com");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+ cm.remove("BAZ.com.", "foo", "/", false);
+ do_check_eq(cm.countCookiesFromHost("baz.com"), 0);
+
+ // test that domain cookies are illegal for IP addresses, aliases such as
+ // 'localhost', and eTLD's such as 'co.uk'
+ cm.add("192.168.0.1", "/", "foo", "bar", false, false, true, expiry);
+ do_check_eq(cm.countCookiesFromHost("192.168.0.1"), 1);
+ do_check_eq(cm.countCookiesFromHost("192.168.0.1."), 1);
+ do_check_throws(function() {
+ cm.countCookiesFromHost(".192.168.0.1");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+ do_check_throws(function() {
+ cm.countCookiesFromHost(".192.168.0.1.");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ cm.add("localhost", "/", "foo", "bar", false, false, true, expiry);
+ do_check_eq(cm.countCookiesFromHost("localhost"), 1);
+ do_check_eq(cm.countCookiesFromHost("localhost."), 1);
+ do_check_throws(function() {
+ cm.countCookiesFromHost(".localhost");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+ do_check_throws(function() {
+ cm.countCookiesFromHost(".localhost.");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ cm.add("co.uk", "/", "foo", "bar", false, false, true, expiry);
+ do_check_eq(cm.countCookiesFromHost("co.uk"), 1);
+ do_check_eq(cm.countCookiesFromHost("co.uk."), 1);
+ do_check_throws(function() {
+ cm.countCookiesFromHost(".co.uk");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+ do_check_throws(function() {
+ cm.countCookiesFromHost(".co.uk.");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ cm.removeAll();
+
+ // test that setting an empty or '.' http:// host results in a no-op
+ var uri = NetUtil.newURI("http://baz.com/");
+ var emptyuri = NetUtil.newURI("http:///");
+ var doturi = NetUtil.newURI("http://./");
+ 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);
cs.setCookieString(doturi, null, "foo3=bar", null);
do_check_eq(getCookieCount(), 0);
cs.setCookieString(uri, null, "foo=bar", null);
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);
- // test that an empty host to add() or remove() throws
- var expiry = (Date.now() + 1000) * 1000;
+ do_check_eq(cm.countCookiesFromHost(""), 0);
+ do_check_throws(function() {
+ cm.countCookiesFromHost(".");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+ do_check_throws(function() {
+ cm.countCookiesFromHost("..");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ var e = cm.getCookiesFromHost("");
+ do_check_false(e.hasMoreElements());
+ do_check_throws(function() {
+ cm.getCookiesFromHost(".");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+ do_check_throws(function() {
+ cm.getCookiesFromHost("..");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ e = cm.getCookiesFromHost("baz.com");
+ do_check_true(e.hasMoreElements());
+ do_check_eq(e.getNext().QueryInterface(Ci.nsICookie2).name, "foo");
+ do_check_false(e.hasMoreElements());
+ e = cm.getCookiesFromHost("");
+ do_check_false(e.hasMoreElements());
+ do_check_throws(function() {
+ cm.getCookiesFromHost(".");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
do_check_throws(function() {
- cm.add("", "/", "foo2", "bar", false, false, true, expiry);
+ cm.getCookiesFromHost("..");
}, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ cm.removeAll();
+
+ // test that an empty file:// host works
+ emptyuri = NetUtil.newURI("file:///");
+ do_check_eq(emptyuri.asciiHost, "");
+ do_check_eq(NetUtil.newURI("file://./").asciiHost, "");
+ do_check_eq(NetUtil.newURI("file://foo.bar/").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(), 3);
+ cs.setCookieString(emptyuri, null, "foo5=bar; domain=bar.com", null);
+ do_check_eq(getCookieCount(), 3);
+
+ do_check_eq(cs.getCookieString(emptyuri, null), "foo2=bar; foo3=bar; foo4=bar");
+
+ do_check_eq(cm.countCookiesFromHost("baz.com"), 0);
+ do_check_eq(cm.countCookiesFromHost(""), 3);
+ do_check_throws(function() {
+ cm.countCookiesFromHost(".");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ e = cm.getCookiesFromHost("baz.com");
+ do_check_false(e.hasMoreElements());
+ e = cm.getCookiesFromHost("");
+ do_check_true(e.hasMoreElements());
+ e.getNext();
+ do_check_true(e.hasMoreElements());
+ e.getNext();
+ do_check_true(e.hasMoreElements());
+ e.getNext();
+ do_check_false(e.hasMoreElements());
+ do_check_throws(function() {
+ cm.getCookiesFromHost(".");
+ }, Cr.NS_ERROR_ILLEGAL_VALUE);
+
+ cm.removeAll();
+
+ // test that an empty host to add() or remove() works,
+ // but a host of '.' doesn't
+ 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.remove("", "foo2", "/", false);
- }, Cr.NS_ERROR_ILLEGAL_VALUE);
- do_check_eq(getCookieCount(), 2);
+ cm.remove("", "foo2", "/", false);
+ do_check_eq(getCookieCount(), 0);
do_check_throws(function() {
cm.remove(".", "foo3", "/", false);
}, Cr.NS_ERROR_ILLEGAL_VALUE);
- do_check_eq(getCookieCount(), 2);
- cm.remove("test.com", "foo", "/", false);
- do_check_eq(getCookieCount(), 1);
- do_check_eq(cm.countCookiesFromHost("baz.com"), 1);
- do_check_eq(cm.countCookiesFromHost(""), 0);
- do_check_eq(cm.countCookiesFromHost("."), 0);
-
- var e = cm.getCookiesFromHost("baz.com");
- do_check_true(e.hasMoreElements());
- do_check_eq(e.getNext().QueryInterface(Ci.nsICookie2).name, "foo");
- do_check_false(e.hasMoreElements());
- e = cm.getCookiesFromHost("");
- do_check_false(e.hasMoreElements());
- e = cm.getCookiesFromHost(".");
- do_check_false(e.hasMoreElements());
+ // test that the 'domain' attribute accepts a leading dot for IP addresses,
+ // aliases such as 'localhost', eTLD's such as 'co.uk', and the empty host;
+ // 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");
+ testDomainCookie("file:///", "");
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);
+
+ cm.removeAll();
+
+ var uri = NetUtil.newURI(uriString);
+ cs.setCookieString(uri, null, "foo=bar; domain=" + domain, null);
+ var e = cm.getCookiesFromHost(domain);
+ do_check_true(e.hasMoreElements());
+ do_check_eq(e.getNext().QueryInterface(Ci.nsICookie2).host, domain);
+ cm.removeAll();
+
+ cs.setCookieString(uri, null, "foo=bar; domain=." + domain, null);
+ e = cm.getCookiesFromHost(domain);
+ do_check_true(e.hasMoreElements());
+ do_check_eq(e.getNext().QueryInterface(Ci.nsICookie2).host, domain);
+ cm.removeAll();
+}
+
--- a/netwerk/cookie/public/nsICookieManager.idl
+++ b/netwerk/cookie/public/nsICookieManager.idl
@@ -57,18 +57,27 @@ interface nsICookieManager : nsISupports
/**
* Called to enumerate through each cookie in the cookie list.
* The objects enumerated over are of type nsICookie
*/
readonly attribute nsISimpleEnumerator enumerator;
/**
- * Called to remove an individual cookie from the cookie list
+ * Called to remove an individual cookie from the cookie list, specified
+ * by host, name, and path. If the cookie cannot be found, no exception
+ * is thrown. Typically, the arguments to this method will be obtained
+ * directly from the desired nsICookie object.
*
- * @param aDomain The host or domain for which the cookie was set
+ * @param aHost The host or domain for which the cookie was set. @see
+ * nsICookieManager2::add for a description of acceptable host
+ * strings. If the target cookie is a domain cookie, a leading
+ * dot must be present.
* @param aName The name specified in the cookie
* @param aPath The path for which the cookie was set
* @param aBlocked Indicates if cookies from this host should be permanently blocked
*
*/
- void remove(in AUTF8String aDomain, in ACString aName, in AUTF8String aPath, in boolean aBlocked);
+ void remove(in AUTF8String aHost,
+ in ACString aName,
+ in AUTF8String aPath,
+ in boolean aBlocked);
};
--- a/netwerk/cookie/public/nsICookieManager2.idl
+++ b/netwerk/cookie/public/nsICookieManager2.idl
@@ -39,27 +39,32 @@
interface nsICookie2;
interface nsIFile;
/**
* Additions to the frozen nsICookieManager
*/
-[scriptable, uuid(d1e9e50f-b78b-4e3b-a474-f3cbca59b013)]
+[scriptable, uuid(94628d1d-8b31-4baa-b474-9c872c440f90)]
interface nsICookieManager2 : nsICookieManager
{
/**
* Add a cookie. nsICookieService is the normal way to do this. This
* method is something of a backdoor.
*
- * @param aDomain
+ * @param aHost
* the host or domain for which the cookie is set. presence of a
* leading dot indicates a domain cookie; otherwise, the cookie
- * is treated as a non-domain cookie. see RFC2109.
+ * is treated as a non-domain cookie (see RFC2109). The host string
+ * will be normalized to ASCII or ACE; any trailing dot will be
+ * stripped. To be a domain cookie, the host must have at least two
+ * subdomain parts (e.g. '.foo.com', not '.com'), otherwise an
+ * exception will be thrown. An empty string is acceptable
+ * (e.g. file:// URI's).
* @param aPath
* path within the domain for which the cookie is valid
* @param aName
* cookie name
* @param aValue
* cookie data
* @param aIsSecure
* true if the cookie should only be sent over a secure connection.
@@ -69,17 +74,17 @@ interface nsICookieManager2 : nsICookieM
* @param aIsSession
* true if the cookie should exist for the current session only.
* see aExpiry.
* @param aExpiry
* expiration date, in seconds since midnight (00:00:00), January 1,
* 1970 UTC. note that expiry time will also be honored for session cookies;
* in this way, the more restrictive of the two will take effect.
*/
- void add(in AUTF8String aDomain,
+ void add(in AUTF8String aHost,
in AUTF8String aPath,
in ACString aName,
in ACString aValue,
in boolean aIsSecure,
in boolean aIsHttpOnly,
in boolean aIsSession,
in PRInt64 aExpiry);
@@ -96,40 +101,40 @@ interface nsICookieManager2 : nsICookieM
/**
* Count how many cookies exist within the base domain of 'aHost'.
* Thus, for a host "weather.yahoo.com", the base domain would be "yahoo.com",
* and any host or domain cookies for "yahoo.com" and its subdomains would be
* counted.
*
* @param aHost
- * the host string to begin from, e.g. "google.com". this should consist
- * of only the host portion of a URI, and should not contain a leading
- * dot, a port, etc.
+ * the host string to search for, e.g. "google.com". this should consist
+ * of only the host portion of a URI. see @add for a description of
+ * acceptable host strings.
*
* @return the number of cookies found.
*/
- unsigned long countCookiesFromHost(in ACString aHost);
+ unsigned long countCookiesFromHost(in AUTF8String aHost);
/**
* Returns an enumerator of cookies that exist within the base domain of
* 'aHost'. Thus, for a host "weather.yahoo.com", the base domain would be
* "yahoo.com", and any host or domain cookies for "yahoo.com" and its
* subdomains would be returned.
*
* @param aHost
- * the host string to begin from, e.g. "google.com". this should consist
- * of only the host portion of a URI, and should not contain a leading
- * dot, a port, etc.
+ * the host string to search for, e.g. "google.com". this should consist
+ * of only the host portion of a URI. see @add for a description of
+ * acceptable host strings.
*
* @return an nsISimpleEnumerator of nsICookie2 objects.
*
* @see countCookiesFromHost
*/
- nsISimpleEnumerator getCookiesFromHost(in ACString aHost);
+ nsISimpleEnumerator getCookiesFromHost(in AUTF8String aHost);
/**
* Import an old-style cookie file. Imported cookies will be added to the
* existing database. If the database contains any cookies the same as those
* being imported (i.e. domain, name, and path match), they will be replaced.
*
* @param aCookieFile the file to import, usually cookies.txt
*/
--- a/netwerk/cookie/public/nsICookieService.idl
+++ b/netwerk/cookie/public/nsICookieService.idl
@@ -84,16 +84,19 @@ interface nsIChannel;
[scriptable, uuid(2aaa897a-293c-4d2b-a657-8c9b7136996d)]
interface nsICookieService : nsISupports
{
/*
* Get the complete cookie string associated with the URI.
*
* @param aURI
* the URI of the document for which cookies are being queried.
+ * file:// URI's (i.e. with an empty host) are allowed, but any other
+ * scheme must have a non-empty host. A trailing dot in the host
+ * is acceptable, and will be stripped.
* @param aChannel
* the channel used to load the document. this parameter should not
* be null, otherwise the cookies will not be returned if third-party
* cookies have been disabled by the user. (the channel is used
* to determine the originating URI of the document; if it is not
* provided, the cookies will be assumed third-party.)
*
* @return the resulting cookie string
@@ -103,16 +106,19 @@ interface nsICookieService : nsISupports
/*
* Get the complete cookie string associated with the URI.
*
* This function is NOT redundant with getCookieString, as the result
* will be different based on httponly (see bug 178993)
*
* @param aURI
* the URI of the document for which cookies are being queried.
+ * file:// URI's (i.e. with an empty host) are allowed, but any other
+ * scheme must have a non-empty host. A trailing dot in the host
+ * is acceptable, and will be stripped.
* @param aFirstURI
* the URI that the user originally typed in or clicked on to initiate
* the load of the document referenced by aURI.
* @param aChannel
* the channel used to load the document. this parameter should not
* be null, otherwise the cookies will not be returned if third-party
* cookies have been disabled by the user. (the channel is used
* to determine the originating URI of the document; if it is not
@@ -122,16 +128,19 @@ interface nsICookieService : nsISupports
*/
string getCookieStringFromHttp(in nsIURI aURI, in nsIURI aFirstURI, in nsIChannel aChannel);
/*
* Set the cookie string associated with the URI.
*
* @param aURI
* the URI of the document for which cookies are being set.
+ * file:// URI's (i.e. with an empty host) are allowed, but any other
+ * scheme must have a non-empty host. A trailing dot in the host
+ * is acceptable, and will be stripped.
* @param aPrompt
* the prompt to use for all user-level cookie notifications.
* @param aCookie
* the cookie string to set.
* @param aChannel
* the channel used to load the document. this parameter should not
* be null, otherwise the cookies will not be set if third-party
* cookies have been disabled by the user. (the channel is used
@@ -146,16 +155,19 @@ interface nsICookieService : nsISupports
/*
* Set the cookie string and expires associated with the URI.
*
* This function is NOT redundant with setCookieString, as the result
* will be different based on httponly (see bug 178993)
*
* @param aURI
* the URI of the document for which cookies are being set.
+ * file:// URI's (i.e. with an empty host) are allowed, but any other
+ * scheme must have a non-empty host. A trailing dot in the host
+ * is acceptable, and will be stripped.
* @param aFirstURI
* the URI that the user originally typed in or clicked on to initiate
* the load of the document referenced by aURI.
* @param aPrompt
* the prompt to use for all user-level cookie notifications.
* @param aCookie
* the cookie string to set.
* @param aServerTime
--- a/netwerk/cookie/src/nsCookieService.cpp
+++ b/netwerk/cookie/src/nsCookieService.cpp
@@ -49,16 +49,17 @@
#include "nsICookiePermission.h"
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsIChannel.h"
#include "nsIFile.h"
#include "nsIObserverService.h"
#include "nsILineInputStream.h"
#include "nsIEffectiveTLDService.h"
+#include "nsIIDNService.h"
#include "nsTArray.h"
#include "nsCOMArray.h"
#include "nsIMutableArray.h"
#include "nsArrayEnumerator.h"
#include "nsEnumeratorUtils.h"
#include "nsAutoPtr.h"
#include "nsReadableUtils.h"
@@ -400,16 +401,19 @@ nsCookieService::Init()
if (!mDBState->hostTable.Init()) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult rv;
mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
+ mIDNService = do_GetService(NS_IDNSERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
// init our pref and observer
nsCOMPtr<nsIPrefBranch2> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefBranch) {
prefBranch->AddObserver(kPrefCookiesPermissions, this, PR_TRUE);
prefBranch->AddObserver(kPrefMaxNumberOfCookies, this, PR_TRUE);
prefBranch->AddObserver(kPrefMaxCookiesPerHost, this, PR_TRUE);
prefBranch->AddObserver(kPrefCookiePurgeAge, this, PR_TRUE);
PrefChanged(prefBranch);
@@ -805,28 +809,31 @@ nsCookieService::SetCookieStringInternal
{
if (!aHostURI) {
COOKIE_LOGFAILURE(SET_COOKIE, nsnull, aCookieHeader, "host URI is null");
return NS_OK;
}
// get the base domain for the host URI.
// e.g. for "www.bbc.co.uk", this would be "bbc.co.uk".
- PRBool isIPAddress;
+ // file:// URI's (i.e. with an empty host) are allowed, but any other
+ // scheme must have a non-empty host. A trailing dot in the host
+ // is acceptable, and will be stripped.
+ PRBool requireHostMatch;
nsCAutoString baseDomain;
- nsresult rv = GetBaseDomain(aHostURI, baseDomain, isIPAddress);
+ nsresult rv = GetBaseDomain(aHostURI, baseDomain, requireHostMatch);
if (NS_FAILED(rv)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader,
"couldn't get base domain from URI");
return NS_OK;
}
// check default prefs
PRUint32 cookieStatus = CheckPrefs(aHostURI, aChannel, baseDomain,
- isIPAddress, aCookieHeader);
+ requireHostMatch, aCookieHeader);
// fire a notification if cookie was rejected (but not if there was an error)
switch (cookieStatus) {
case STATUS_REJECTED:
NotifyRejected(aHostURI);
case STATUS_REJECTED_WITH_ERROR:
return NS_OK;
}
@@ -845,17 +852,17 @@ nsCookieService::SetCookieStringInternal
}
// start a transaction on the storage db, to optimize insertions.
// transaction will automically commit on completion
mozStorageTransaction transaction(mDBState->dbConn, PR_TRUE);
// switch to a nice string type now, and process each cookie in the header
nsDependentCString cookieHeader(aCookieHeader);
- while (SetCookieInternal(aHostURI, aChannel, baseDomain, isIPAddress,
+ while (SetCookieInternal(aHostURI, aChannel, baseDomain, requireHostMatch,
cookieHeader, serverTime, aFromHttp));
return NS_OK;
}
// notify observers that a cookie was rejected due to the users' prefs.
void
nsCookieService::NotifyRejected(nsIURI *aHostURI)
@@ -967,35 +974,40 @@ nsCookieService::GetEnumerator(nsISimple
nsGetEnumeratorData data(&cookieList, PR_Now() / PR_USEC_PER_SEC);
mDBState->hostTable.EnumerateEntries(COMArrayCallback, &data);
return NS_NewArrayEnumerator(aEnumerator, cookieList);
}
NS_IMETHODIMP
-nsCookieService::Add(const nsACString &aDomain,
+nsCookieService::Add(const nsACString &aHost,
const nsACString &aPath,
const nsACString &aName,
const nsACString &aValue,
PRBool aIsSecure,
PRBool aIsHttpOnly,
PRBool aIsSession,
PRInt64 aExpiry)
{
+ // first, normalize the hostname, and fail if it contains illegal characters.
+ nsCAutoString host(aHost);
+ nsresult rv = NormalizeHost(host);
+ NS_ENSURE_SUCCESS(rv, rv);
+
// get the base domain for the host URI.
// e.g. for "www.bbc.co.uk", this would be "bbc.co.uk".
nsCAutoString baseDomain;
- nsresult rv = GetBaseDomainFromHost(aDomain, baseDomain);
+ rv = GetBaseDomainFromHost(host, baseDomain);
NS_ENSURE_SUCCESS(rv, rv);
PRInt64 currentTimeInUsec = PR_Now();
nsRefPtr<nsCookie> cookie =
- nsCookie::Create(aName, aValue, aDomain, aPath,
+ nsCookie::Create(aName, aValue, host, aPath,
aExpiry,
currentTimeInUsec,
currentTimeInUsec,
aIsSession,
aIsSecure,
aIsHttpOnly);
if (!cookie) {
return NS_ERROR_OUT_OF_MEMORY;
@@ -1006,41 +1018,44 @@ nsCookieService::Add(const nsACString &a
}
NS_IMETHODIMP
nsCookieService::Remove(const nsACString &aHost,
const nsACString &aName,
const nsACString &aPath,
PRBool aBlocked)
{
+ // first, normalize the hostname, and fail if it contains illegal characters.
+ nsCAutoString host(aHost);
+ nsresult rv = NormalizeHost(host);
+ NS_ENSURE_SUCCESS(rv, rv);
+
nsCAutoString baseDomain;
- nsresult rv = GetBaseDomainFromHost(aHost, baseDomain);
+ rv = GetBaseDomainFromHost(host, baseDomain);
NS_ENSURE_SUCCESS(rv, rv);
nsListIter matchIter;
if (FindCookie(baseDomain,
- PromiseFlatCString(aHost),
+ host,
PromiseFlatCString(aName),
PromiseFlatCString(aPath),
matchIter,
PR_Now() / PR_USEC_PER_SEC)) {
nsRefPtr<nsCookie> cookie = matchIter.Cookie();
RemoveCookieFromList(matchIter);
NotifyChanged(cookie, NS_LITERAL_STRING("deleted").get());
}
// check if we need to add the host to the permissions blacklist.
if (aBlocked && mPermissionService) {
- nsCAutoString host(NS_LITERAL_CSTRING("http://"));
-
// strip off the domain dot, if necessary
- if (aHost.First() == '.')
- host.Append(Substring(aHost, 1, aHost.Length() - 1));
- else
- host.Append(aHost);
+ if (!host.IsEmpty() && host.First() == '.')
+ host.Cut(0, 1);
+
+ host.Insert(NS_LITERAL_CSTRING("http://"), 0);
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), host);
if (uri)
mPermissionService->SetAccess(uri, nsICookiePermission::ACCESS_DENY);
}
@@ -1318,33 +1333,37 @@ nsCookieService::GetCookieInternal(nsIUR
if (!aHostURI) {
COOKIE_LOGFAILURE(GET_COOKIE, nsnull, nsnull, "host URI is null");
return;
}
// get the base domain, host, and path from the URI.
// e.g. for "www.bbc.co.uk", the base domain would be "bbc.co.uk".
- PRBool isIPAddress;
+ // file:// URI's (i.e. with an empty host) are allowed, but any other
+ // scheme must have a non-empty host. A trailing dot in the host
+ // is acceptable, and will be stripped.
+ PRBool requireHostMatch;
nsCAutoString baseDomain, hostFromURI, pathFromURI;
- nsresult rv = GetBaseDomain(aHostURI, baseDomain, isIPAddress);
+ nsresult rv = GetBaseDomain(aHostURI, baseDomain, requireHostMatch);
if (NS_SUCCEEDED(rv))
rv = aHostURI->GetAsciiHost(hostFromURI);
if (NS_SUCCEEDED(rv))
rv = aHostURI->GetPath(pathFromURI);
- // trim trailing dots
- hostFromURI.Trim(".");
- if (NS_FAILED(rv) || hostFromURI.IsEmpty()) {
+ // trim any trailing dot
+ if (!hostFromURI.IsEmpty() && hostFromURI.Last() == '.')
+ hostFromURI.Truncate(hostFromURI.Length() - 1);
+ if (NS_FAILED(rv)) {
COOKIE_LOGFAILURE(GET_COOKIE, aHostURI, nsnull, "invalid host/path from URI");
return;
}
// check default prefs
PRUint32 cookieStatus = CheckPrefs(aHostURI, aChannel, baseDomain,
- isIPAddress, nsnull);
+ requireHostMatch, nsnull);
// for GetCookie(), we don't fire rejection notifications.
switch (cookieStatus) {
case STATUS_REJECTED:
case STATUS_REJECTED_WITH_ERROR:
return;
}
// check if aHostURI is using an https secure protocol.
@@ -1476,17 +1495,17 @@ nsCookieService::GetCookieInternal(nsIUR
}
// processes a single cookie, and returns PR_TRUE if there are more cookies
// to be processed
PRBool
nsCookieService::SetCookieInternal(nsIURI *aHostURI,
nsIChannel *aChannel,
const nsCString &aBaseDomain,
- PRBool aIsIPAddress,
+ PRBool aRequireHostMatch,
nsDependentCString &aCookieHeader,
PRInt64 aServerTime,
PRBool aFromHttp)
{
// create a stack-based nsCookieAttributes, to store all the
// attributes parsed from the cookie
nsCookieAttributes cookieAttributes;
@@ -1514,17 +1533,17 @@ nsCookieService::SetCookieInternal(nsIUR
}
if (cookieAttributes.name.FindChar('\t') != kNotFound) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "invalid name character");
return newCookie;
}
// domain & path checks
- if (!CheckDomain(cookieAttributes, aHostURI, aBaseDomain, aIsIPAddress)) {
+ if (!CheckDomain(cookieAttributes, aHostURI, aBaseDomain, aRequireHostMatch)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "failed the domain tests");
return newCookie;
}
if (!CheckPath(cookieAttributes, aHostURI)) {
COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, savedCookieHeader, "failed the path tests");
return newCookie;
}
@@ -1915,107 +1934,160 @@ nsCookieService::ParseAttributes(nsDepen
return newCookie;
}
/******************************************************************************
* nsCookieService impl:
* private domain & permission compliance enforcement functions
******************************************************************************/
+// Get the base domain for aHostURI; e.g. for "www.bbc.co.uk", this would be
+// "bbc.co.uk". Only properly-formed URI's are tolerated, though a trailing
+// dot may be present (and will be stripped). If aHostURI is an IP address,
+// an alias such as 'localhost', an eTLD such as 'co.uk', or the empty string,
+// aBaseDomain will be the exact host, and aRequireHostMatch will be true to
+// indicate that substring matches should not be performed.
nsresult
nsCookieService::GetBaseDomain(nsIURI *aHostURI,
nsCString &aBaseDomain,
- PRBool &aIsIPAddress)
+ PRBool &aRequireHostMatch)
{
- // get the base domain for the host URI.
- // e.g. for "www.bbc.co.uk", this would be "bbc.co.uk".
+ // get the base domain. this will fail if the host contains a leading dot,
+ // more than one trailing dot, or is otherwise malformed.
nsresult rv = mTLDService->GetBaseDomain(aHostURI, 0, aBaseDomain);
- aIsIPAddress = rv == NS_ERROR_HOST_IS_IP_ADDRESS;
- if (rv == NS_ERROR_HOST_IS_IP_ADDRESS ||
- rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
- // address is either an IP address or an alias such as 'localhost'.
- // use the host as a key in such cases.
+ aRequireHostMatch = rv == NS_ERROR_HOST_IS_IP_ADDRESS ||
+ rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS;
+ if (aRequireHostMatch) {
+ // aHostURI is either an IP address, an alias such as 'localhost', an eTLD
+ // such as 'co.uk', or the empty string. use the host as a key in such
+ // cases.
rv = aHostURI->GetAsciiHost(aBaseDomain);
}
NS_ENSURE_SUCCESS(rv, rv);
- // trim trailing dots
- aBaseDomain.Trim(".");
- if (aBaseDomain.IsEmpty())
- return NS_ERROR_INVALID_ARG;
-
- aIsIPAddress = PR_FALSE;
+ // aHost (and thus aBaseDomain) may contain a trailing dot; if so, trim it.
+ if (!aBaseDomain.IsEmpty() && aBaseDomain.Last() == '.')
+ aBaseDomain.Truncate(aBaseDomain.Length() - 1);
+
+ // block any URIs without a host that aren't file:// URIs.
+ if (aBaseDomain.IsEmpty()) {
+ PRBool isFileURI = PR_FALSE;
+ aHostURI->SchemeIs("file", &isFileURI);
+ if (!isFileURI)
+ return NS_ERROR_INVALID_ARG;
+ }
+
return NS_OK;
}
-nsresult
+// Get the base domain for aHost; e.g. for "www.bbc.co.uk", this would be
+// "bbc.co.uk". This is done differently than GetBaseDomain(): it is assumed
+// that aHost is already normalized, and it may contain a leading dot
+// (indicating that it represents a domain). A trailing dot must not be present.
+// If aHost is an IP address, an alias such as 'localhost', an eTLD such as
+// 'co.uk', or the empty string, aBaseDomain will be the exact host, and a
+// leading dot will be treated as an error.
+nsresult
nsCookieService::GetBaseDomainFromHost(const nsACString &aHost,
nsCString &aBaseDomain)
{
- // trim leading and trailing dots
- nsCAutoString host(aHost);
- host.Trim(".");
- if (host.IsEmpty())
+ // aHost must not contain a trailing dot, or be the string '.'.
+ if (!aHost.IsEmpty() && aHost.Last() == '.')
return NS_ERROR_INVALID_ARG;
- // get the base domain for the host.
- // e.g. for "www.bbc.co.uk", this would be "bbc.co.uk".
+ // aHost may contain a leading dot; if so, strip it now.
+ nsDependentCString host(aHost);
+ PRBool domain = !host.IsEmpty() && host.First() == '.';
+ if (domain)
+ host.Rebind(host.BeginReading() + 1, host.EndReading());
+
+ // get the base domain. this will fail if the host contains a leading dot,
+ // more than one trailing dot, or is otherwise malformed.
nsresult rv = mTLDService->GetBaseDomainFromHost(host, 0, aBaseDomain);
if (rv == NS_ERROR_HOST_IS_IP_ADDRESS ||
rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
- // address is either an IP address or an alias such as 'localhost'.
- // use the host as a key in such cases.
+ // aHost is either an IP address, an alias such as 'localhost', an eTLD
+ // such as 'co.uk', or the empty string. use the host as a key in such
+ // cases; however, we reject any such hosts with a leading dot, since it
+ // doesn't make sense for them to be domain cookies.
+ if (domain)
+ return NS_ERROR_INVALID_ARG;
+
aBaseDomain = host;
return NS_OK;
}
return rv;
}
+// Normalizes the given hostname, component by component. ASCII/ACE
+// components are lower-cased, and UTF-8 components are normalized per
+// RFC 3454 and converted to ACE. Any trailing dot is stripped.
+nsresult
+nsCookieService::NormalizeHost(nsCString &aHost)
+{
+ if (!IsASCII(aHost)) {
+ nsCAutoString host;
+ nsresult rv = mIDNService->ConvertUTF8toACE(aHost, host);
+ if (NS_FAILED(rv))
+ return rv;
+
+ aHost = host;
+ }
+
+ // Only strip the trailing dot if it wouldn't result in the empty string;
+ // in that case, treat it like a leading dot.
+ if (aHost.Length() > 1 && aHost.Last() == '.')
+ aHost.Truncate(aHost.Length() - 1);
+
+ ToLowerCase(aHost);
+ return NS_OK;
+}
+
// returns PR_TRUE if 'a' is equal to or a subdomain of 'b',
// assuming no leading or trailing dots are present.
static inline PRBool IsSubdomainOf(const nsCString &a, const nsCString &b)
{
if (a == b)
return PR_TRUE;
if (a.Length() > b.Length())
return a[a.Length() - b.Length() - 1] == '.' && StringEndsWith(a, b);
return PR_FALSE;
}
PRBool
nsCookieService::IsForeign(const nsCString &aBaseDomain,
- PRBool aHostIsIPAddress,
+ PRBool aRequireHostMatch,
nsIURI *aFirstURI)
{
nsCAutoString firstHost;
if (NS_FAILED(aFirstURI->GetAsciiHost(firstHost))) {
// assume foreign
return PR_TRUE;
}
- // trim trailing dots
- firstHost.Trim(".");
-
- // 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). note that the base domain parameter will be
- // equivalent to the host IP in this case.
- if (aHostIsIPAddress)
+
+ // trim any trailing dot
+ if (!firstHost.IsEmpty() && firstHost.Last() == '.')
+ firstHost.Truncate(firstHost.Length() - 1);
+
+ // check whether the host is either an IP address, an alias such as
+ // 'localhost', an eTLD such as 'co.uk', or the empty string. in these
+ // cases, require an exact string match for the domain. note that the base
+ // domain parameter will be equivalent to the host in this case.
+ if (aRequireHostMatch)
return !firstHost.Equals(aBaseDomain);
// ensure the originating domain is also derived from the host's base domain.
- // note that if the host is an alias such as 'localhost', the base domain
- // parameter will also be 'localhost', and this comparison will work.
return !IsSubdomainOf(firstHost, aBaseDomain);
}
PRUint32
nsCookieService::CheckPrefs(nsIURI *aHostURI,
nsIChannel *aChannel,
const nsCString &aBaseDomain,
- PRBool aIsIPAddress,
+ PRBool aRequireHostMatch,
const char *aCookieHeader)
{
nsresult rv;
// don't let ftp sites get/set cookies (could be a security issue)
PRBool ftp;
if (NS_SUCCEEDED(aHostURI->SchemeIs("ftp", &ftp)) && ftp) {
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "ftp sites cannot read cookies");
@@ -2052,56 +2124,56 @@ nsCookieService::CheckPrefs(nsIURI
NS_WARNING("Foreign cookie blocking enabled, but nsICookiePermission unavailable! Rejecting cookie");
COOKIE_LOGSTRING(PR_LOG_WARNING, ("CheckPrefs(): foreign blocking enabled, but nsICookiePermission unavailable! Rejecting cookie"));
return STATUS_REJECTED;
}
nsCOMPtr<nsIURI> firstURI;
rv = mPermissionService->GetOriginatingURI(aChannel, getter_AddRefs(firstURI));
- if (NS_FAILED(rv) || IsForeign(aBaseDomain, aIsIPAddress, firstURI)) {
+ if (NS_FAILED(rv) || IsForeign(aBaseDomain, aRequireHostMatch, firstURI)) {
COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "originating server test failed");
return STATUS_REJECTED;
}
}
// if nothing has complained, accept cookie
return STATUS_ACCEPTED;
}
// processes domain attribute, and returns PR_TRUE if host has permission to set for this domain.
PRBool
nsCookieService::CheckDomain(nsCookieAttributes &aCookieAttributes,
nsIURI *aHostURI,
const nsCString &aBaseDomain,
- PRBool aIsIPAddress)
+ PRBool aRequireHostMatch)
{
// get host from aHostURI
nsCAutoString hostFromURI;
aHostURI->GetAsciiHost(hostFromURI);
- // trim trailing dots
- hostFromURI.Trim(".");
- NS_ASSERTION(!hostFromURI.IsEmpty(), "empty host");
+ // trim any trailing dot
+ if (!hostFromURI.IsEmpty() && hostFromURI.Last() == '.')
+ hostFromURI.Truncate(hostFromURI.Length() - 1);
// if a domain is given, check the host has permission
if (!aCookieAttributes.host.IsEmpty()) {
// Tolerate leading '.' characters.
if (aCookieAttributes.host.First() == '.')
aCookieAttributes.host.Cut(0, 1);
// switch to lowercase now, to avoid case-insensitive compares everywhere
ToLowerCase(aCookieAttributes.host);
- // 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 (aIsIPAddress)
+ // check whether the host is either an IP address, an alias such as
+ // 'localhost', an eTLD such as 'co.uk', or the empty string. in these
+ // cases, require an exact string match for the domain, and leave the cookie
+ // as a non-domain one. bug 105917 originally noted the requirement to deal
+ // with IP addresses.
+ if (aRequireHostMatch)
return hostFromURI.Equals(aCookieAttributes.host);
// ensure the proposed domain is derived from the base domain; and also
// that the host domain is derived from the proposed domain (per RFC2109).
if (IsSubdomainOf(aCookieAttributes.host, aBaseDomain) &&
IsSubdomainOf(hostFromURI, aCookieAttributes.host)) {
// prepend a dot to indicate a domain cookie
aCookieAttributes.host.Insert(NS_LITERAL_CSTRING("."), 0);
@@ -2463,39 +2535,45 @@ nsCookieService::CountCookiesFromHostInt
}
// 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)
{
+ // first, normalize the hostname, and fail if it contains illegal characters.
+ nsCAutoString host(aHost);
+ nsresult rv = NormalizeHost(host);
+ NS_ENSURE_SUCCESS(rv, rv);
+
nsCAutoString baseDomain;
- nsresult rv = GetBaseDomainFromHost(aHost, baseDomain);
- if (NS_FAILED(rv)) {
- *aCountFromHost = 0;
- return NS_OK;
- }
+ rv = GetBaseDomainFromHost(host, baseDomain);
+ NS_ENSURE_SUCCESS(rv, rv);
// 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(baseDomain, data);
return NS_OK;
}
// get an enumerator of cookies stored by a particular host. this is provided by the
// nsICookieManager2 interface.
NS_IMETHODIMP
nsCookieService::GetCookiesFromHost(const nsACString &aHost,
nsISimpleEnumerator **aEnumerator)
{
+ // first, normalize the hostname, and fail if it contains illegal characters.
+ nsCAutoString host(aHost);
+ nsresult rv = NormalizeHost(host);
+ NS_ENSURE_SUCCESS(rv, rv);
+
nsCAutoString baseDomain;
- nsresult rv = GetBaseDomainFromHost(aHost, baseDomain);
- if (NS_FAILED(rv))
- return NS_NewEmptyEnumerator(aEnumerator);
+ rv = GetBaseDomainFromHost(host, baseDomain);
+ NS_ENSURE_SUCCESS(rv, rv);
nsCOMArray<nsICookie> cookieList(mMaxCookiesPerHost);
PRInt64 currentTime = PR_Now() / PR_USEC_PER_SEC;
nsCookieEntry *entry = mDBState->hostTable.GetEntry(baseDomain);
if (!entry)
return NS_NewEmptyEnumerator(aEnumerator);
--- a/netwerk/cookie/src/nsCookieService.h
+++ b/netwerk/cookie/src/nsCookieService.h
@@ -57,16 +57,17 @@
#include "mozIStorageConnection.h"
struct nsCookieAttributes;
struct nsListIter;
struct nsEnumerationData;
class nsICookiePermission;
class nsIEffectiveTLDService;
+class nsIIDNService;
class nsIPrefBranch;
class nsIObserverService;
class nsIURI;
class nsIChannel;
// hash entry class
class nsCookieEntry : public PLDHashEntryHdr
{
@@ -163,44 +164,46 @@ class nsCookieService : public nsICookie
protected:
void PrefChanged(nsIPrefBranch *aPrefBranch);
nsresult InitDB();
nsresult TryInitDB(PRBool aDeleteExistingDB);
nsresult CreateTable();
void CloseDB();
nsresult Read();
- nsresult GetBaseDomain(nsIURI *aHostURI, nsCString &aBaseDomain, PRBool &aIsIPAddress);
+ nsresult NormalizeHost(nsCString &aHost);
+ nsresult GetBaseDomain(nsIURI *aHostURI, nsCString &aBaseDomain, PRBool &aRequireHostMatch);
nsresult GetBaseDomainFromHost(const nsACString &aHost, nsCString &aBaseDomain);
void GetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, PRBool aHttpBound, char **aCookie);
nsresult SetCookieStringInternal(nsIURI *aHostURI, nsIPrompt *aPrompt, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, PRBool aFromHttp);
- PRBool SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, const nsCString& aBaseDomain, PRBool aIsIPAddress, nsDependentCString &aCookieHeader, PRInt64 aServerTime, PRBool aFromHttp);
+ PRBool SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, const nsCString& aBaseDomain, PRBool aRequireHostMatch, nsDependentCString &aCookieHeader, PRInt64 aServerTime, PRBool aFromHttp);
void AddInternal(const nsCString& aBaseDomain, nsCookie *aCookie, PRInt64 aCurrentTimeInUsec, nsIURI *aHostURI, const char *aCookieHeader, PRBool aFromHttp);
void RemoveCookieFromList(const nsListIter &aIter);
PRBool AddCookieToList(const nsCString& aBaseDomain, 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);
- PRBool IsForeign(const nsCString &aBaseDomain, PRBool aHostIsIPAddress, nsIURI *aFirstURI);
- PRUint32 CheckPrefs(nsIURI *aHostURI, nsIChannel *aChannel, const nsCString &aBaseDomain, PRBool aIsIPAddress, const char *aCookieHeader);
- PRBool CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, PRBool aIsIPAddress);
+ PRBool IsForeign(const nsCString &aBaseDomain, PRBool aRequireHostMatch, nsIURI *aFirstURI);
+ PRUint32 CheckPrefs(nsIURI *aHostURI, nsIChannel *aChannel, const nsCString &aBaseDomain, PRBool aRequireHostMatch, const char *aCookieHeader);
+ PRBool CheckDomain(nsCookieAttributes &aCookie, nsIURI *aHostURI, const nsCString &aBaseDomain, PRBool aRequireHostMatch);
static PRBool CheckPath(nsCookieAttributes &aCookie, nsIURI *aHostURI);
static PRBool GetExpiry(nsCookieAttributes &aCookie, PRInt64 aServerTime, PRInt64 aCurrentTime);
void RemoveAllFromMemory();
void PurgeCookies(PRInt64 aCurrentTimeInUsec);
PRBool FindCookie(const nsCString& aBaseDomain, const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter, PRInt64 aCurrentTime);
PRUint32 CountCookiesFromHostInternal(const nsCString &aBaseDomain, nsEnumerationData &aData);
void NotifyRejected(nsIURI *aHostURI);
void NotifyChanged(nsISupports *aSubject, const PRUnichar *aData);
protected:
// cached members.
nsCOMPtr<nsIObserverService> mObserverService;
nsCOMPtr<nsICookiePermission> mPermissionService;
nsCOMPtr<nsIEffectiveTLDService> mTLDService;
+ nsCOMPtr<nsIIDNService> mIDNService;
// we have two separate DB states: one for normal browsing and one for
// private browsing, switching between them as appropriate. this state
// encapsulates both the in-memory table and the on-disk DB.
// note that the private states' dbConn should always be null - we never
// want to be dealing with the on-disk DB when in private browsing.
DBState *mDBState;
DBState mDefaultDBState;