Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Static Public Member Functions | Public Attributes | Protected Member Functions | Static Protected Member Functions | Protected Attributes | Static Protected Attributes | Friends
nsCookieService Class Reference

#include <nsCookieService.h>

Inheritance diagram for nsCookieService:
Inheritance graph
[legend]
Collaboration diagram for nsCookieService:
Collaboration graph
[legend]

List of all members.

Public Member Functions

NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSICOOKIESERVICE
NS_DECL_NSICOOKIEMANAGER
NS_DECL_NSICOOKIEMANAGER2 
nsCookieService ()
virtual ~nsCookieService ()
nsresult Init ()
string getCookieString (in nsIURI aURI, in nsIChannel aChannel)
string getCookieStringFromHttp (in nsIURI aURI, in nsIURI aFirstURI, in nsIChannel aChannel)
void setCookieString (in nsIURI aURI, in nsIPrompt aPrompt, in string aCookie, in nsIChannel aChannel)
void setCookieStringFromHttp (in nsIURI aURI, in nsIURI aFirstURI, in nsIPrompt aPrompt, in string aCookie, in string aServerTime, in nsIChannel aChannel)
void add (in AUTF8String aDomain, in AUTF8String aPath, in ACString aName, in ACString aValue, in boolean aSecure, in boolean aIsSession, in PRInt64 aExpiry)
 Add a cookie.
boolean findMatchingCookie (in nsICookie2 aCookie, out unsigned long aCountFromHost)
 Find whether a matching cookie already exists, and how many cookies a given host has already set.
void removeAll ()
 Called to remove all cookies from the cookie list.
void remove (in AUTF8String aDomain, in ACString aName, in AUTF8String aPath, in boolean aBlocked)
 Called to remove an individual cookie from the cookie list.
void observe (in nsISupports aSubject, in string aTopic, in wstring aData)
 Observe will be called when there is a notification for the topic |aTopic|.

Static Public Member Functions

static nsCookieServiceGetSingleton ()

Public Attributes

readonly attribute boolean cookieIconIsVisible
 This attribute really doesn't belong on this interface.
readonly attribute
nsISimpleEnumerator 
enumerator
 Called to enumerate through each cookie in the cookie list.

Protected Member Functions

void PrefChanged (nsIPrefBranch *aPrefBranch)
nsresult Read ()
nsresult Write ()
nsresult GetCookieInternal (nsIURI *aHostURI, nsIURI *aFirstURI, nsIChannel *aChannel, PRBool aHttpBound, char **aCookie)
nsresult SetCookieStringInternal (nsIURI *aHostURI, nsIURI *aFirstURI, nsIPrompt *aPrompt, const char *aCookieHeader, const char *aServerTime, nsIChannel *aChannel, PRBool aFromHttp)
PRBool SetCookieInternal (nsIURI *aHostURI, nsIChannel *aChannel, nsDependentCString &aCookieHeader, nsInt64 aServerTime, PRBool aFromHttp, nsCookieStatus aStatus, nsCookiePolicy aPolicy)
void AddInternal (nsCookie *aCookie, nsInt64 aCurrentTime, nsIURI *aHostURI, const char *aCookieHeader, PRBool aFromHttp)
void RemoveCookieFromList (nsListIter &aIter)
PRBool AddCookieToList (nsCookie *aCookie)
nsCookieStatus CheckPrefs (nsIURI *aHostURI, nsIURI *aFirstURI, nsIChannel *aChannel, const char *aCookieHeader, nsCookiePolicy &aPolicy)
void RemoveAllFromMemory ()
void RemoveExpiredCookies (nsInt64 aCurrentTime)
PRBool FindCookie (const nsAFlatCString &aHost, const nsAFlatCString &aName, const nsAFlatCString &aPath, nsListIter &aIter)
void FindOldestCookie (nsEnumerationData &aData)
PRUint32 CountCookiesFromHost (nsCookie *aCookie, nsEnumerationData &aData)
void NotifyRejected (nsIURI *aHostURI)
void NotifyChanged (nsICookie2 *aCookie, const PRUnichar *aData)
void LazyWrite ()

Static Protected Member Functions

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)
static PRBool IsIPAddress (const nsAFlatCString &aHost)
static PRBool IsInDomain (const nsACString &aDomain, const nsACString &aHost, PRBool aIsDomain=PR_TRUE)
static PRBool IsForeign (nsIURI *aHostURI, nsIURI *aFirstURI)
static PRBool CheckDomain (nsCookieAttributes &aCookie, nsIURI *aHostURI)
static PRBool CheckPath (nsCookieAttributes &aCookie, nsIURI *aHostURI)
static PRBool GetExpiry (nsCookieAttributes &aCookie, nsInt64 aServerTime, nsInt64 aCurrentTime, nsCookieStatus aStatus)
static void DoLazyWrite (nsITimer *aTimer, void *aClosure)

Protected Attributes

nsCOMPtr< nsIFilemCookieFile
nsCOMPtr< nsIObserverServicemObserverService
nsCOMPtr< nsICookieConsentmP3PService
nsCOMPtr< nsICookiePermissionmPermissionService
nsCOMPtr< nsITimermWriteTimer
nsTHashtable< nsCookieEntrymHostTable
PRUint32 mCookieCount
PRPackedBool mCookieChanged
PRPackedBool mCookieIconVisible
PRUint8 mCookiesPermissions
PRUint16 mMaxNumberOfCookies
PRUint16 mMaxCookiesPerHost

Static Protected Attributes

static nsCookieServicegCookieService = nsnull

Friends

PLDHashOperator PR_CALLBACK removeExpiredCallback (nsCookieEntry *aEntry, void *aArg)

Detailed Description

Definition at line 152 of file nsCookieService.h.


Constructor & Destructor Documentation

NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER NS_DECL_NSICOOKIESERVICE NS_DECL_NSICOOKIEMANAGER NS_DECL_NSICOOKIEMANAGER2 nsCookieService::nsCookieService ( )

Here is the caller graph for this function:

Definition at line 435 of file nsCookieService.cpp.


Member Function Documentation

void nsICookieManager2::add ( in AUTF8String  aDomain,
in AUTF8String  aPath,
in ACString  aName,
in ACString  aValue,
in boolean  aSecure,
in boolean  aIsSession,
in PRInt64  aExpiry 
) [inherited]

Add a cookie.

nsICookieService is the normal way to do this. This method is something of a backdoor.

Parameters:
aDomainthe 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.
aPathpath within the domain for which the cookie is valid
aNamecookie name
aValuecookie data
aSecuretrue if the cookie should only be sent over a secure connection.
aIsSessiontrue if the cookie should exist for the current session only.
aExpiryexpiration date, in seconds since the epoch. only relevant if aIsSession is false.
PRBool nsCookieService::AddCookieToList ( nsCookie aCookie) [protected]

Definition at line 2171 of file nsCookieService.cpp.

{
  nsCookieEntry *entry = mHostTable.PutEntry(aCookie->Host().get());

  if (!entry) {
    NS_ERROR("can't insert element into a null entry!");
    return PR_FALSE;
  }

  NS_ADDREF(aCookie);

  aCookie->Next() = entry->Head();
  entry->Head() = aCookie;
  ++mCookieCount;
  mCookieChanged = PR_TRUE;

  return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsCookieService::AddInternal ( nsCookie aCookie,
nsInt64  aCurrentTime,
nsIURI aHostURI,
const char *  aCookieHeader,
PRBool  aFromHttp 
) [protected]

Definition at line 1304 of file nsCookieService.cpp.

{
  // if the new cookie is httponly, make sure we're not coming from script
  if (!aFromHttp && aCookie->IsHttpOnly()) {
    COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "cookie is httponly; coming from script");
    return;
  }

  nsListIter matchIter;
  const PRBool foundCookie =
    FindCookie(aCookie->Host(), aCookie->Name(), aCookie->Path(), matchIter);

  nsRefPtr<nsCookie> oldCookie;
  if (foundCookie) {
    oldCookie = matchIter.current;

    // if the old cookie is httponly, make sure we're not coming from script
    if (!aFromHttp && oldCookie->IsHttpOnly()) {
      COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "previously stored cookie is httponly; coming from script");
      return;
    }

    RemoveCookieFromList(matchIter);

    // check if the cookie has expired
    if (aCookie->Expiry() <= aCurrentTime) {
      COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "previously stored cookie was deleted");
      NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
      return;
    }

    // preserve creation time of cookie
    if (oldCookie) {
      aCookie->SetCreationTime(oldCookie->CreationTime());
    }

  } else {
    // check if cookie has already expired
    if (aCookie->Expiry() <= aCurrentTime) {
      COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "cookie has already expired");
      return;
    }

    // check if we have to delete an old cookie.
    nsEnumerationData data(aCurrentTime, LL_MAXINT);
    if (CountCookiesFromHost(aCookie, data) >= mMaxCookiesPerHost) {
      // remove the oldest cookie from host
      oldCookie = data.iter.current;
      RemoveCookieFromList(data.iter);

    } else if (mCookieCount >= mMaxNumberOfCookies) {
      // try to make room, by removing expired cookies
      RemoveExpiredCookies(aCurrentTime);

      // check if we still have to get rid of something
      if (mCookieCount >= mMaxNumberOfCookies) {
        // find the position of the oldest cookie, and remove it
        data.oldestTime = LL_MAXINT;
        FindOldestCookie(data);
        oldCookie = data.iter.current;
        RemoveCookieFromList(data.iter);
      }
    }

    // if we deleted an old cookie, notify consumers
    if (oldCookie)
      NotifyChanged(oldCookie, NS_LITERAL_STRING("deleted").get());
  }

  // add the cookie to head of list
  AddCookieToList(aCookie);
  NotifyChanged(aCookie, foundCookie ? NS_LITERAL_STRING("changed").get()
                                     : NS_LITERAL_STRING("added").get());

  COOKIE_LOGSUCCESS(SET_COOKIE, aHostURI, aCookieHeader, aCookie);
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsCookieService::CheckDomain ( nsCookieAttributes aCookie,
nsIURI aHostURI 
) [static, protected]

Definition at line 1861 of file nsCookieService.cpp.

{
  // get host from aHostURI
  nsCAutoString hostFromURI;
  if (NS_FAILED(aHostURI->GetAsciiHost(hostFromURI))) {
    return PR_FALSE;
  }
  // trim trailing dots
  hostFromURI.Trim(".");
  ToLowerCase(hostFromURI);

  // if a domain is given, check the host has permission
  if (!aCookieAttributes.host.IsEmpty()) {
    aCookieAttributes.host.Trim(".");
    // switch to lowercase now, to avoid case-insensitive compares everywhere
    ToLowerCase(aCookieAttributes.host);

    // check whether the host is an IP address, and override isDomain to
    // make the cookie 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 (IsIPAddress(aCookieAttributes.host)) {
      return IsInDomain(aCookieAttributes.host, hostFromURI, PR_FALSE);
    }

    /*
     * verify that this host has the authority to set for this domain.   We do
     * this by making sure that the host is in the domain.  We also require
     * that a domain have at least one embedded period to prevent domains of the form
     * ".com" and ".edu"
     */
    PRInt32 dot = aCookieAttributes.host.FindChar('.');
    if (dot == kNotFound) {
      // fail dot test
      return PR_FALSE;
    }

    // prepend a dot, and check if the host is in the domain
    aCookieAttributes.host.Insert(NS_LITERAL_CSTRING("."), 0);
    if (!IsInDomain(aCookieAttributes.host, hostFromURI)) {
      return PR_FALSE;
    }

    /*
     * note: RFC2109 section 4.3.2 requires that we check the following:
     * that the portion of host not in domain does not contain a dot.
     * this prevents hosts of the form x.y.co.nz from setting cookies in the
     * entire .co.nz domain. however, it's only a only a partial solution and
     * it breaks sites (IE doesn't enforce it), so we don't perform this check.
     */

  // no domain specified, use hostFromURI
  } else {
    // 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;
    }
    aCookieAttributes.host = hostFromURI;
  }

  return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsCookieService::CheckPath ( nsCookieAttributes aCookie,
nsIURI aHostURI 
) [static, protected]

Definition at line 1930 of file nsCookieService.cpp.

{
  // if a path is given, check the host has permission
  if (aCookieAttributes.path.IsEmpty()) {
    // strip down everything after the last slash to get the path,
    // ignoring slashes in the query string part.
    // if we can QI to nsIURL, that'll take care of the query string portion.
    // otherwise, it's not an nsIURL and can't have a query string, so just find the last slash.
    nsCOMPtr<nsIURL> hostURL = do_QueryInterface(aHostURI);
    if (hostURL) {
      hostURL->GetDirectory(aCookieAttributes.path);
    } else {
      aHostURI->GetPath(aCookieAttributes.path);
      PRInt32 slash = aCookieAttributes.path.RFindChar('/');
      if (slash != kNotFound) {
        aCookieAttributes.path.Truncate(slash + 1);
      }
    }

#if 0
  } else {
    // get path from aHostURI
    nsCAutoString pathFromURI;
    if (NS_FAILED(aHostURI->GetPath(pathFromURI)) ||
        !StringBeginsWith(pathFromURI, aCookieAttributes.path)) {
      return PR_FALSE;
    }
#endif
  }

  if (aCookieAttributes.path.Length() > kMaxBytesPerPath ||
      aCookieAttributes.path.FindChar('\t') != kNotFound )
    return PR_FALSE;

  return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsCookieStatus nsCookieService::CheckPrefs ( nsIURI aHostURI,
nsIURI aFirstURI,
nsIChannel aChannel,
const char *  aCookieHeader,
nsCookiePolicy aPolicy 
) [protected]

Definition at line 1755 of file nsCookieService.cpp.

{
  // pref tree:
  // 0) get the scheme strings from the two URI's
  // 1) disallow ftp
  // 2) disallow mailnews, if pref set
  // 3) perform a permissionlist lookup to see if an entry exists for this host
  //    (a match here will override defaults in 4)
  // 4) go through enumerated permissions to see which one we have:
  // -> cookies disabled: return
  // -> dontacceptforeign: check if cookie is foreign
  // -> p3p: check p3p cookie data

  // we've extended the "nsCookieStatus" type to be used for all cases now
  // (used to be only for p3p), so beware that its interpretation is not p3p-
  // specific anymore.

  // first, get the URI scheme for further use
  // if GetScheme fails on aHostURI, reject; aFirstURI is optional, so failing is ok
  nsCAutoString currentURIScheme, firstURIScheme;
  nsresult rv, rv2 = NS_OK;
  rv = aHostURI->GetScheme(currentURIScheme);
  if (aFirstURI) {
    rv2 = aFirstURI->GetScheme(firstURIScheme);
  }
  if (NS_FAILED(rv) || NS_FAILED(rv2)) {
    COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "couldn't get scheme of host URI");
    return STATUS_REJECTED_WITH_ERROR;
  }

  // don't let ftp sites get/set cookies (could be a security issue)
  if (currentURIScheme.EqualsLiteral("ftp")) {
    COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "ftp sites cannot read cookies");
    return STATUS_REJECTED_WITH_ERROR;
  }

  // check the permission list first; if we find an entry, it overrides
  // default prefs. see bug 184059.
  if (mPermissionService) {
    nsCookieAccess access;
    rv = mPermissionService->CanAccess(aHostURI, aFirstURI, aChannel, &access);

    // if we found an entry, use it
    if (NS_SUCCEEDED(rv)) {
      switch (access) {
      case nsICookiePermission::ACCESS_DENY:
        COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are blocked for this site");
        return nsICookie::STATUS_REJECTED;

      case nsICookiePermission::ACCESS_ALLOW:
        return nsICookie::STATUS_ACCEPTED;
      }
    }
  }

  // check default prefs - go thru enumerated permissions
  if (mCookiesPermissions == BEHAVIOR_REJECT) {
    COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "cookies are disabled");
    return nsICookie::STATUS_REJECTED;

  } else if (mCookiesPermissions == BEHAVIOR_REJECTFOREIGN) {
    // check if cookie is foreign.
    // if aFirstURI is null, allow by default

    // note: this can be circumvented if we have http redirects within html,
    // since the documentURI attribute isn't always correctly
    // passed to the redirected channels. (or isn't correctly set in the first place)
    if (IsForeign(aHostURI, aFirstURI)) {
      COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "originating server test failed");
      return nsICookie::STATUS_REJECTED;
    }

  } else if (mCookiesPermissions == BEHAVIOR_P3P) {
    // check to see if P3P conditions are satisfied. see nsICookie.idl for
    // P3P-related constants.

    nsCookieStatus p3pStatus = nsICookie::STATUS_UNKNOWN;

    nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);

    // lazily init the P3P service
    if (!mP3PService)
      mP3PService = do_GetService(NS_COOKIECONSENT_CONTRACTID);

    if (mP3PService) {
      // get the site policy and a status decision for the cookie
      PRBool isForeign = IsForeign(aHostURI, aFirstURI);
      mP3PService->GetConsent(aHostURI, httpChannel, isForeign, &aPolicy, &p3pStatus);
    }

    if (p3pStatus == nsICookie::STATUS_REJECTED) {
      COOKIE_LOGFAILURE(aCookieHeader ? SET_COOKIE : GET_COOKIE, aHostURI, aCookieHeader, "P3P test failed");
    }
    return p3pStatus;
  }

  // if nothing has complained, accept cookie
  return nsICookie::STATUS_ACCEPTED;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2091 of file nsCookieService.cpp.

{
  PRUint32 countFromHost = 0;

  nsCAutoString hostWithDot(NS_LITERAL_CSTRING(".") + aCookie->RawHost());

  const char *currentDot = hostWithDot.get();
  const char *nextDot = currentDot + 1;
  do {
    nsCookieEntry *entry = mHostTable.GetEntry(currentDot);
    for (nsListIter iter(entry); iter.current; ++iter) {
      // only count non-expired cookies
      if (iter.current->Expiry() > aData.currentTime) {
        ++countFromHost;

        // check if we've found the oldest cookie so far
        if (aData.oldestTime > iter.current->LastAccessed()) {
          aData.oldestTime = iter.current->LastAccessed();
          aData.iter = iter;
        }
      }
    }

    currentDot = nextDot;
    if (currentDot)
      nextDot = strchr(currentDot + 1, '.');

  } while (currentDot);

  return countFromHost;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsCookieService::DoLazyWrite ( nsITimer aTimer,
void aClosure 
) [static, protected]

Definition at line 761 of file nsCookieService.cpp.

{
  nsCookieService *service = NS_REINTERPRET_CAST(nsCookieService*, aClosure);
  service->Write();
  service->mWriteTimer = 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsCookieService::FindCookie ( const nsAFlatCString aHost,
const nsAFlatCString aName,
const nsAFlatCString aPath,
nsListIter aIter 
) [protected]

Definition at line 2126 of file nsCookieService.cpp.

{
  nsCookieEntry *entry = mHostTable.GetEntry(aHost.get());
  for (aIter = nsListIter(entry); aIter.current; ++aIter) {
    if (aPath.Equals(aIter.current->Path()) &&
        aName.Equals(aIter.current->Name())) {
      return PR_TRUE;
    }
  }

  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

boolean nsICookieManager2::findMatchingCookie ( in nsICookie2  aCookie,
out unsigned long  aCountFromHost 
) [inherited]

Find whether a matching cookie already exists, and how many cookies a given host has already set.

This is useful when e.g. prompting the user whether to accept a given cookie.

Parameters:
aCookiethe cookie to look for
aCountFromHostthe number of cookies found whose hosts are the same as, or subdomains of, the host field of aCookie
Returns:
true if a cookie was found which matches the host, path, and name fields of aCookie

Definition at line 2206 of file nsCookieService.cpp.

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsCookieService::GetCookieInternal ( nsIURI aHostURI,
nsIURI aFirstURI,
nsIChannel aChannel,
PRBool  aHttpBound,
char **  aCookie 
) [protected]

Definition at line 495 of file nsCookieService.cpp.

{
  *aCookie = nsnull;

  if (!aHostURI) {
    COOKIE_LOGFAILURE(GET_COOKIE, nsnull, nsnull, "host URI is null");
    return NS_OK;
  }

  // check default prefs
  nsCookiePolicy cookiePolicy; // we don't use this here... just a placeholder
  nsCookieStatus cookieStatus = CheckPrefs(aHostURI, aFirstURI, aChannel, nsnull, cookiePolicy);
  // for GetCookie(), we don't fire rejection notifications.
  switch (cookieStatus) {
  case nsICookie::STATUS_REJECTED:
  case STATUS_REJECTED_WITH_ERROR:
    return NS_OK;
  }

  // get host and path from the nsIURI
  // 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 NS_OK;
  }
  // trim trailing dots
  hostFromURI.Trim(".");
  // insert a leading dot, so we begin the hash lookup with the
  // equivalent domain cookie host
  hostFromURI.Insert(NS_LITERAL_CSTRING("."), 0);
  ToLowerCase(hostFromURI);

  // 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;
  if NS_FAILED(aHostURI->SchemeIs("https", &isSecure)) {
    isSecure = PR_FALSE;
  }

  nsCookie *cookie;
  nsAutoVoidArray foundCookieList;
  nsInt64 currentTime = NOW_IN_SECONDS;
  const char *currentDot = hostFromURI.get();
  const char *nextDot = currentDot + 1;

  // begin hash lookup, walking up the subdomain levels.
  // we use nextDot to force a lookup of the original host (without leading dot).
  do {
    nsCookieEntry *entry = mHostTable.GetEntry(currentDot);
    cookie = entry ? entry->Head() : nsnull;
    for (; cookie; cookie = cookie->Next()) {
      // if the cookie is secure and the host scheme isn't, we can't send it
      if (cookie->IsSecure() && !isSecure) {
        continue;
      }

      // if the cookie is httpOnly and it's not going directly to the HTTP
      // connection, don't send it
      if (cookie->IsHttpOnly() && !aHttpBound) {
        continue;
      }

      // calculate cookie path length, excluding trailing '/'
      PRUint32 cookiePathLen = cookie->Path().Length();
      if (cookiePathLen > 0 && cookie->Path().Last() == '/') {
        --cookiePathLen;
      }

      // if the nsIURI path is shorter than the cookie path, don't send it back
      if (!StringBeginsWith(pathFromURI, Substring(cookie->Path(), 0, cookiePathLen))) {
        continue;
      }

      if (pathFromURI.Length() > cookiePathLen &&
          !ispathdelimiter(pathFromURI.CharAt(cookiePathLen))) {
        /*
         * |ispathdelimiter| tests four cases: '/', '?', '#', and ';'.
         * '/' is the "standard" case; the '?' test allows a site at host/abc?def
         * to receive a cookie that has a path attribute of abc.  this seems
         * strange but at least one major site (citibank, bug 156725) depends
         * on it.  The test for # and ; are put in to proactively avoid problems
         * with other sites - these are the only other chars allowed in the path.
         */
        continue;
      }

      // check if the cookie has expired
      if (cookie->Expiry() <= currentTime) {
        continue;
      }

      // all checks passed - add to list and update lastAccessed stamp of cookie
      foundCookieList.AppendElement(cookie);
      cookie->SetLastAccessed(currentTime);
    }

    currentDot = nextDot;
    if (currentDot)
      nextDot = strchr(currentDot + 1, '.');

  } while (currentDot);

  // return cookies in order of path length; longest to shortest.
  // this is required per RFC2109.  if cookies match in length,
  // then sort by creation time (see bug 236772).
  foundCookieList.Sort(compareCookiesForSending, nsnull);

  nsCAutoString cookieData;
  PRInt32 count = foundCookieList.Count();
  for (PRInt32 i = 0; i < count; ++i) {
    cookie = NS_STATIC_CAST(nsCookie*, foundCookieList.ElementAt(i));

    // check if we have anything to write
    if (!cookie->Name().IsEmpty() || !cookie->Value().IsEmpty()) {
      // if we've already added a cookie to the return list, append a "; " so
      // that subsequent cookies are delimited in the final list.
      if (!cookieData.IsEmpty()) {
        cookieData.AppendLiteral("; ");
      }

      if (!cookie->Name().IsEmpty()) {
        // we have a name and value - write both
        cookieData += cookie->Name() + NS_LITERAL_CSTRING("=") + cookie->Value();
      } else {
        // just write value
        cookieData += cookie->Value();
      }
    }
  }

  // it's wasteful to alloc a new string; but we have no other choice, until we
  // fix the callers to use nsACStrings.
  if (!cookieData.IsEmpty()) {
    COOKIE_LOGSUCCESS(GET_COOKIE, aHostURI, cookieData, nsnull);
    *aCookie = ToNewCString(cookieData);
  }

  return NS_OK;
}

Here is the call graph for this function:

string nsICookieService::getCookieString ( in nsIURI  aURI,
in nsIChannel  aChannel 
) [inherited]
string nsICookieService::getCookieStringFromHttp ( in nsIURI  aURI,
in nsIURI  aFirstURI,
in nsIChannel  aChannel 
) [inherited]
PRBool nsCookieService::GetExpiry ( nsCookieAttributes aCookie,
nsInt64  aServerTime,
nsInt64  aCurrentTime,
nsCookieStatus  aStatus 
) [static, protected]

Definition at line 1975 of file nsCookieService.cpp.

{
  /* Determine when the cookie should expire. This is done by taking the difference between 
   * the server time and the time the server wants the cookie to expire, and adding that 
   * difference to the client time. This localizes the client time regardless of whether or
   * not the TZ environment variable was set on the client.
   *
   * Note: We need to consider accounting for network lag here, per RFC.
   */
  nsInt64 delta;

  // check for max-age attribute first; this overrides expires attribute
  if (!aCookieAttributes.maxage.IsEmpty()) {
    // obtain numeric value of maxageAttribute
    PRInt64 maxage;
    PRInt32 numInts = PR_sscanf(aCookieAttributes.maxage.get(), "%lld", &maxage);

    // default to session cookie if the conversion failed
    if (numInts != 1) {
      return PR_TRUE;
    }

    delta = nsInt64(maxage);

  // check for expires attribute
  } else if (!aCookieAttributes.expires.IsEmpty()) {
    nsInt64 expires;
    PRTime tempExpires;

    // parse expiry time
    if (PR_ParseTimeString(aCookieAttributes.expires.get(), PR_TRUE, &tempExpires) == PR_SUCCESS) {
      expires = nsInt64(tempExpires) / USEC_PER_SEC;
    } else {
      return PR_TRUE;
    }

    delta = expires - aServerTime;

  // default to session cookie if no attributes found
  } else {
    return PR_TRUE;
  }

  // if this addition overflows, expiryTime will be less than currentTime
  // and the cookie will be expired - that's okay.
  aCookieAttributes.expiryTime = aCurrentTime + delta;

  // we need to return whether the cookie is a session cookie or not:
  // the cookie may have been previously downgraded by p3p prefs,
  // so we take that into account here. only applies to non-expired cookies.
  return aStatus == nsICookie::STATUS_DOWNGRADED &&
         aCookieAttributes.expiryTime > aCurrentTime;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 353 of file nsCookieService.cpp.

{
  if (gCookieService) {
    NS_ADDREF(gCookieService);
    return gCookieService;
  }

  // Create a new singleton nsCookieService.
  // We AddRef only once since XPCOM has rules about the ordering of module
  // teardowns - by the time our module destructor is called, it's too late to
  // Release our members (e.g. nsIObserverService and nsIPrefBranch), since GC
  // cycles have already been completed and would result in serious leaks.
  // See bug 209571.
  gCookieService = new nsCookieService();
  if (gCookieService) {
    NS_ADDREF(gCookieService);
    if (NS_FAILED(gCookieService->Init())) {
      NS_RELEASE(gCookieService);
    }
  }

  return gCookieService;
}

Here is the call graph for this function:

PRBool nsCookieService::GetTokenValue ( nsASingleFragmentCString::const_char_iterator &  aIter,
nsASingleFragmentCString::const_char_iterator &  aEndIter,
nsDependentCSubstring aTokenString,
nsDependentCSubstring aTokenValue,
PRBool aEqualsFound 
) [static, protected]

Definition at line 1473 of file nsCookieService.cpp.

{
  nsASingleFragmentCString::const_char_iterator start, lastSpace;
  // initialize value string to clear garbage
  aTokenValue.Rebind(aIter, aIter);

  // find <token>, including any <LWS> between the end-of-token and the
  // token separator. we'll remove trailing <LWS> next
  while (aIter != aEndIter && iswhitespace(*aIter))
    ++aIter;
  start = aIter;
  while (aIter != aEndIter && !istokenseparator(*aIter))
    ++aIter;

  // remove trailing <LWS>; first check we're not at the beginning
  lastSpace = aIter;
  if (lastSpace != start) {
    while (--lastSpace != start && iswhitespace(*lastSpace));
    ++lastSpace;
  }
  aTokenString.Rebind(start, lastSpace);

  aEqualsFound = (*aIter == '=');
  if (aEqualsFound) {
    // find <value>
    while (++aIter != aEndIter && iswhitespace(*aIter));

    start = aIter;

    if (*aIter == '"') {
      // process <quoted-string>
      // (note: cookie terminators, CR | LF, can't happen:
      // they're removed by necko before the header gets here)
      // assume value mangled if no terminating '"', return
      while (++aIter != aEndIter && !isquoteterminator(*aIter)) {
        // if <qdtext> (backwhacked char), skip over it. this allows '\"' in <quoted-string>.
        // we increment once over the backwhack, nullcheck, then continue to the 'while',
        // which increments over the backwhacked char. one exception - we don't allow
        // CR | LF here either (see above about necko)
        if (*aIter == '\\' && (++aIter == aEndIter || isterminator(*aIter)))
          break;
      }

      if (aIter != aEndIter && !isterminator(*aIter)) {
        // include terminating quote in attribute string
        aTokenValue.Rebind(start, ++aIter);
        // skip to next ';'
        while (aIter != aEndIter && !isvalueseparator(*aIter))
          ++aIter;
      }
    } else {
      // process <token-value>
      // just look for ';' to terminate ('=' allowed)
      while (aIter != aEndIter && !isvalueseparator(*aIter))
        ++aIter;

      // remove trailing <LWS>; first check we're not at the beginning
      if (aIter != start) {
        lastSpace = aIter;
        while (--lastSpace != start && iswhitespace(*lastSpace));
        aTokenValue.Rebind(start, ++lastSpace);
      }
    }
  }

  // aIter is on ';', or terminator, or EOS
  if (aIter != aEndIter) {
    // if on terminator, increment past & return PR_TRUE to process new cookie
    if (isterminator(*aIter)) {
      ++aIter;
      return PR_TRUE;
    }
    // fall-through: aIter is on ';', increment and return PR_FALSE
    ++aIter;
  }
  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 400 of file nsCookieService.cpp.

{
  if (!mHostTable.Init()) {
    return NS_ERROR_OUT_OF_MEMORY;
  }

  // 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);
    PrefChanged(prefBranch);
  }

  // cache mCookieFile
  NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mCookieFile));
  if (mCookieFile) {
    mCookieFile->AppendNative(NS_LITERAL_CSTRING(kCookieFileName));
  }

  Read();

  mObserverService = do_GetService("@mozilla.org/observer-service;1");
  if (mObserverService) {
    mObserverService->AddObserver(this, "profile-before-change", PR_TRUE);
    mObserverService->AddObserver(this, "profile-do-change", PR_TRUE);
    mObserverService->AddObserver(this, "cookieIcon", PR_TRUE);
  }

  mPermissionService = do_GetService(NS_COOKIEPERMISSION_CONTRACTID);

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsCookieService::IsForeign ( nsIURI aHostURI,
nsIURI aFirstURI 
) [static, protected]

Definition at line 1693 of file nsCookieService.cpp.

{
  // if aFirstURI is null, default to not foreign
  if (!aFirstURI) {
    return PR_FALSE;
  }

  // chrome URLs are never foreign (otherwise sidebar cookies won't work).
  // eventually we want to have a protocol whitelist here,
  // _or_ do something smart with nsIProtocolHandler::protocolFlags.
  PRBool isChrome = PR_FALSE;
  nsresult rv = aFirstURI->SchemeIs("chrome", &isChrome);
  if (NS_SUCCEEDED(rv) && isChrome) {
    return PR_FALSE;
  }

  // Get hosts
  nsCAutoString currentHost, firstHost;
  if (NS_FAILED(aHostURI->GetAsciiHost(currentHost)) ||
      NS_FAILED(aFirstURI->GetAsciiHost(firstHost))) {
    return PR_TRUE;
  }
  // trim trailing dots
  currentHost.Trim(".");
  firstHost.Trim(".");
  ToLowerCase(currentHost);
  ToLowerCase(firstHost);

  // determine if it's foreign. we have a new algorithm for doing this,
  // since the old behavior was broken:

  // first ensure we're not dealing with IP addresses; if we are, require an
  // exact match. we can't avoid this, otherwise the algo below will allow two
  // IP's such as 128.12.96.5 and 213.12.96.5 to match.
  if (IsIPAddress(firstHost)) {
    return !IsInDomain(firstHost, currentHost, PR_FALSE);
  }

  // next, allow a one-subdomain-level "fuzz" in the comparison. first, we need
  // to find how many subdomain levels each host has; we only do the looser
  // comparison if they have the same number of levels. e.g.
  //  firstHost = weather.yahoo.com, currentHost = cookies.yahoo.com -> match
  //  firstHost =     a.b.yahoo.com, currentHost =       b.yahoo.com -> no match
  //  firstHost =         yahoo.com, currentHost = weather.yahoo.com -> no match
  //  (since the normal test (next) will catch this case and give a match.)
  // also, we can only do this if they have >=2 subdomain levels, to avoid
  // matching yahoo.com with netscape.com (yes, this breaks for .co.nz etc...)
  PRUint32 dotsInFirstHost = firstHost.CountChar('.');
  if (dotsInFirstHost == currentHost.CountChar('.') &&
      dotsInFirstHost >= 2) {
    // we have enough dots - check IsInDomain(choppedFirstHost, currentHost)
    PRInt32 dot1 = firstHost.FindChar('.');
    return !IsInDomain(Substring(firstHost, dot1, firstHost.Length() - dot1), currentHost);
  }

  // don't have enough dots to chop firstHost, or the subdomain levels differ;
  // so we just do the plain old check, IsInDomain(firstHost, currentHost).
  return !IsInDomain(NS_LITERAL_CSTRING(".") + firstHost, currentHost);
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsCookieService::IsInDomain ( const nsACString &  aDomain,
const nsACString &  aHost,
PRBool  aIsDomain = PR_TRUE 
) [static, protected]

Definition at line 1649 of file nsCookieService.cpp.

{
  // if we have a non-domain cookie, require an exact match between domain and host.
  // RFC2109 specifies this behavior; it allows a site to prevent its subdomains
  // from accessing a cookie, for whatever reason.
  if (!aIsDomain) {
    return aDomain.Equals(aHost);
  }

  // we have a domain cookie; test the following two cases:
  /*
   * normal case for hostName = x<domainName>
   *    e.g., hostName = home.netscape.com
   *          domainName = .netscape.com
   *
   * special case for domainName = .hostName
   *    e.g., hostName = netscape.com
   *          domainName = .netscape.com
   */
  // the lengthDifference tests are for efficiency, so we do only one .Equals()
  PRUint32 domainLength = aDomain.Length();
  PRInt32 lengthDifference = aHost.Length() - domainLength;
  // case for host & domain equal
  // (e.g. .netscape.com & .netscape.com)
  // this gives us slightly more efficiency, since we don't have
  // to call up Substring().
  if (lengthDifference == 0) {
    return aDomain.Equals(aHost);
  }
  // normal case
  if (lengthDifference > 0) {
    return aDomain.Equals(Substring(aHost, lengthDifference, domainLength));
  }
  // special case
  if (lengthDifference == -1) {
    return Substring(aDomain, 1, domainLength - 1).Equals(aHost);
  }
  // no match
  return PR_FALSE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsCookieService::IsIPAddress ( const nsAFlatCString aHost) [static, protected]

Definition at line 1642 of file nsCookieService.cpp.

{
  PRNetAddr addr;
  return (PR_StringToNetAddr(aHost.get(), &addr) == PR_SUCCESS);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 747 of file nsCookieService.cpp.

{
  if (mWriteTimer) {
    mWriteTimer->SetDelay(kLazyWriteTimeout);
  } else {
    mWriteTimer = do_CreateInstance("@mozilla.org/timer;1");
    if (mWriteTimer) {
      mWriteTimer->InitWithFuncCallback(DoLazyWrite, this, kLazyWriteTimeout,
                                        nsITimer::TYPE_ONE_SHOT);
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsCookieService::NotifyChanged ( nsICookie2 aCookie,
const PRUnichar aData 
) [protected]

Definition at line 784 of file nsCookieService.cpp.

{
  mCookieChanged = PR_TRUE;

  if (mObserverService)
    mObserverService->NotifyObservers(aCookie, "cookie-changed", aData);

  // fire a cookieIcon notification if the cookie was downgraded or flagged
  // by p3p. the cookieIcon notification is now deprecated, but we still need
  // this until consumers can be fixed. to see if cookies have been
  // downgraded or flagged, listen to cookie-changed directly.
  if (mCookiesPermissions == BEHAVIOR_P3P &&
      (!nsCRT::strcmp(aData, NS_LITERAL_STRING("added").get()) ||
       !nsCRT::strcmp(aData, NS_LITERAL_STRING("changed").get()))) {
    nsCookieStatus status;
    aCookie->GetStatus(&status);
    if (status == nsICookie::STATUS_DOWNGRADED ||
        status == nsICookie::STATUS_FLAGGED) {
      mCookieIconVisible = PR_TRUE;
      if (mObserverService)
        mObserverService->NotifyObservers(nsnull, "cookieIcon", NS_LITERAL_STRING("on").get());
    }
  }
}

Here is the caller graph for this function:

void nsCookieService::NotifyRejected ( nsIURI aHostURI) [protected]

Definition at line 771 of file nsCookieService.cpp.

{
  if (mObserverService)
    mObserverService->NotifyObservers(aHostURI, "cookie-rejected", nsnull);
}

Here is the caller graph for this function:

void nsIObserver::observe ( in nsISupports  aSubject,
in string  aTopic,
in wstring  aData 
) [inherited]

Observe will be called when there is a notification for the topic |aTopic|.

This assumes that the object implementing this interface has been registered with an observer service such as the nsIObserverService.

If you expect multiple topics/subjects, the impl is responsible for filtering.

You should not modify, add, remove, or enumerate notifications in the implemention of observe.

Parameters:
aSubject: Notification specific interface pointer.
aTopic: The notification topic or subject.
aData: Notification specific wide string. subject event.
PRBool nsCookieService::ParseAttributes ( nsDependentCString aCookieHeader,
nsCookieAttributes aCookie 
) [static, protected]

Definition at line 1558 of file nsCookieService.cpp.

{
  static const char kPath[]    = "path";
  static const char kDomain[]  = "domain";
  static const char kExpires[] = "expires";
  static const char kMaxage[]  = "max-age";
  static const char kSecure[]  = "secure";
  static const char kHttpOnly[]  = "httponly";

  nsASingleFragmentCString::const_char_iterator tempBegin, tempEnd;
  nsASingleFragmentCString::const_char_iterator cookieStart, cookieEnd;
  aCookieHeader.BeginReading(cookieStart);
  aCookieHeader.EndReading(cookieEnd);

  aCookieAttributes.isSecure = PR_FALSE;

  aCookieAttributes.isHttpOnly = PR_FALSE;

  nsDependentCSubstring tokenString(cookieStart, cookieStart);
  nsDependentCSubstring tokenValue (cookieStart, cookieStart);
  PRBool newCookie, equalsFound;

  // extract cookie <NAME> & <VALUE> (first attribute), and copy the strings.
  // if we find multiple cookies, return for processing
  // note: if there's no '=', we assume token is <VALUE>. this is required by
  //       some sites (see bug 169091).
  // XXX fix the parser to parse according to <VALUE> grammar for this case
  newCookie = GetTokenValue(cookieStart, cookieEnd, tokenString, tokenValue, equalsFound);
  if (equalsFound) {
    aCookieAttributes.name = tokenString;
    aCookieAttributes.value = tokenValue;
  } else {
    aCookieAttributes.value = tokenString;
  }

  // extract remaining attributes
  while (cookieStart != cookieEnd && !newCookie) {
    newCookie = GetTokenValue(cookieStart, cookieEnd, tokenString, tokenValue, equalsFound);

    if (!tokenValue.IsEmpty()) {
      tokenValue.BeginReading(tempBegin);
      tokenValue.EndReading(tempEnd);
      if (*tempBegin == '"' && *--tempEnd == '"') {
        // our parameter is a quoted-string; remove quotes for later parsing
        tokenValue.Rebind(++tempBegin, tempEnd);
      }
    }

    // decide which attribute we have, and copy the string
    if (tokenString.LowerCaseEqualsLiteral(kPath))
      aCookieAttributes.path = tokenValue;

    else if (tokenString.LowerCaseEqualsLiteral(kDomain))
      aCookieAttributes.host = tokenValue;

    else if (tokenString.LowerCaseEqualsLiteral(kExpires))
      aCookieAttributes.expires = tokenValue;

    else if (tokenString.LowerCaseEqualsLiteral(kMaxage))
      aCookieAttributes.maxage = tokenValue;

    // ignore any tokenValue for isSecure; just set the boolean
    else if (tokenString.LowerCaseEqualsLiteral(kSecure))
      aCookieAttributes.isSecure = PR_TRUE;

    // ignore any tokenValue for isHttpOnly (see bug 178993);
    // just set the boolean
    else if (tokenString.LowerCaseEqualsLiteral(kHttpOnly))
      aCookieAttributes.isHttpOnly = PR_TRUE;
  }

  // rebind aCookieHeader, in case we need to process another cookie
  aCookieHeader.Rebind(cookieStart, cookieEnd);
  return newCookie;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsCookieService::PrefChanged ( nsIPrefBranch aPrefBranch) [protected]

Definition at line 824 of file nsCookieService.cpp.

{
  PRInt32 val;
  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookiesPermissions, &val)))
    mCookiesPermissions = LIMIT(val, 0, 3, 0);

  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxNumberOfCookies, &val)))
    mMaxNumberOfCookies = LIMIT(val, 0, 0xFFFF, 0xFFFF);

  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefMaxCookiesPerHost, &val)))
    mMaxCookiesPerHost = LIMIT(val, 0, 0xFFFF, 0xFFFF);
}

Here is the caller graph for this function:

Definition at line 936 of file nsCookieService.cpp.

{
  nsresult rv;
  nsCOMPtr<nsIInputStream> fileInputStream;
  rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), mCookieFile);
  if (NS_FAILED(rv)) {
    return rv;
  }

  nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv);
  if (NS_FAILED(rv)) {
    return rv;
  }

  static const char kTrue[] = "TRUE";

  nsCAutoString buffer;
  PRBool isMore = PR_TRUE;
  PRInt32 hostIndex, isDomainIndex, pathIndex, secureIndex, expiresIndex, nameIndex, cookieIndex;
  nsASingleFragmentCString::char_iterator iter;
  PRInt32 numInts;
  PRInt64 expires;
  PRBool isDomain, isHttpOnly = PR_FALSE;
  nsInt64 currentTime = NOW_IN_SECONDS;
  // we use lastAccessedCounter to keep cookies in recently-used order,
  // so we start by initializing to currentTime (somewhat arbitrary)
  nsInt64 lastAccessedCounter = currentTime;
  nsCookie *newCookie;

  /* file format is:
   *
   * host \t isDomain \t path \t secure \t expires \t name \t cookie
   *
   * if this format isn't respected we move onto the next line in the file.
   * isDomain is "TRUE" or "FALSE" (default to "FALSE")
   * isSecure is "TRUE" or "FALSE" (default to "TRUE")
   * expires is a PRInt64 integer
   * note 1: cookie can contain tabs.
   * note 2: cookies are written in order of lastAccessed time:
   *         most-recently used come first; least-recently-used come last.
   */

  /*
   * ...but due to bug 178933, we hide HttpOnly cookies from older code
   * in a comment, so they don't expose HttpOnly cookies to JS.
   *
   * The format for HttpOnly cookies is
   *
   * #HttpOnly_host \t isDomain \t path \t secure \t expires \t name \t cookie
   *
   */

  while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) {
    if (StringBeginsWith(buffer, NS_LITERAL_CSTRING(kHttpOnlyPrefix))) {
      isHttpOnly = PR_TRUE;
      hostIndex = sizeof(kHttpOnlyPrefix) - 1;
    } else if (buffer.IsEmpty() || buffer.First() == '#') {
      continue;
    } else {
      isHttpOnly = PR_FALSE;
      hostIndex = 0;
    }
    // this is a cheap, cheesy way of parsing a tab-delimited line into
    // string indexes, which can be lopped off into substrings. just for
    // purposes of obfuscation, it also checks that each token was found.
    // todo: use iterators?
    if ((isDomainIndex = buffer.FindChar('\t', hostIndex)     + 1) == 0 ||
        (pathIndex     = buffer.FindChar('\t', isDomainIndex) + 1) == 0 ||
        (secureIndex   = buffer.FindChar('\t', pathIndex)     + 1) == 0 ||
        (expiresIndex  = buffer.FindChar('\t', secureIndex)   + 1) == 0 ||
        (nameIndex     = buffer.FindChar('\t', expiresIndex)  + 1) == 0 ||
        (cookieIndex   = buffer.FindChar('\t', nameIndex)     + 1) == 0) {
      continue;
    }

    // check the expirytime first - if it's expired, ignore
    // nullstomp the trailing tab, to avoid copying the string
    buffer.BeginWriting(iter);
    *(iter += nameIndex - 1) = char(0);
    numInts = PR_sscanf(buffer.get() + expiresIndex, "%lld", &expires);
    if (numInts != 1 || nsInt64(expires) < currentTime) {
      continue;
    }

    isDomain = Substring(buffer, isDomainIndex, pathIndex - isDomainIndex - 1)
               .EqualsLiteral(kTrue);
    const nsASingleFragmentCString &host = Substring(buffer, hostIndex, isDomainIndex - hostIndex - 1);
    // check for bad legacy cookies (domain not starting with a dot, or containing a port),
    // and discard
    if (isDomain && !host.IsEmpty() && host.First() != '.' ||
        host.FindChar(':') != kNotFound) {
      continue;
    }

    // create a new nsCookie and assign the data.
    newCookie =
      nsCookie::Create(Substring(buffer, nameIndex, cookieIndex - nameIndex - 1),
                       Substring(buffer, cookieIndex, buffer.Length() - cookieIndex),
                       host,
                       Substring(buffer, pathIndex, secureIndex - pathIndex - 1),
                       nsInt64(expires),
                       lastAccessedCounter,
                       PR_FALSE,
                       Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).EqualsLiteral(kTrue),
                       isHttpOnly,
                       nsICookie::STATUS_UNKNOWN,
                       nsICookie::POLICY_UNKNOWN);
    if (!newCookie) {
      return NS_ERROR_OUT_OF_MEMORY;
    }

    // trick: keep the cookies in most-recently-used order,
    // by successively decrementing the lastAccessed time
    lastAccessedCounter -= nsInt64(1);

    if (!AddCookieToList(newCookie)) {
      // It is purpose that created us; purpose that connects us;
      // purpose that pulls us; that guides us; that drives us.
      // It is purpose that defines us; purpose that binds us.
      // When a cookie no longer has purpose, it has a choice:
      // it can return to the source to be deleted, or it can go
      // into exile, and stay hidden inside the Matrix.
      // Let's choose deletion.
      delete newCookie;
    }
  }

  mCookieChanged = PR_FALSE;
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsICookieManager::remove ( in AUTF8String  aDomain,
in ACString  aName,
in AUTF8String  aPath,
in boolean  aBlocked 
) [inherited]

Called to remove an individual cookie from the cookie list.

Parameters:
aDomainThe host or domain for which the cookie was set
aNameThe name specified in the cookie
aBlockedIndicates if cookies from this host should be permanently blocked

Called to remove all cookies from the cookie list.

Definition at line 2038 of file nsCookieService.cpp.

{
  // clearing the hashtable will call each nsCookieEntry's dtor,
  // which releases all their respective children.
  mHostTable.Clear();
  mCookieCount = 0;
  mCookieChanged = PR_TRUE;
}

Here is the call graph for this function:

Definition at line 2144 of file nsCookieService.cpp.

{
  if (!aIter.prev && !aIter.current->Next()) {
    // we're removing the last element in the list - so just remove the entry
    // from the hash. note that the entryclass' dtor will take care of
    // releasing this last element for us!
    mHostTable.RawRemoveEntry(aIter.entry);
    aIter.current = nsnull;

  } else {
    // just remove the element from the list, and increment the iterator
    nsCookie *next = aIter.current->Next();
    NS_RELEASE(aIter.current);
    if (aIter.prev) {
      // element to remove is not the head
      aIter.current = aIter.prev->Next() = next;
    } else {
      // element to remove is the head
      aIter.current = aIter.entry->Head() = next;
    }
  }

  --mCookieCount;
  mCookieChanged = PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsCookieService::RemoveExpiredCookies ( nsInt64  aCurrentTime) [protected]

Definition at line 2064 of file nsCookieService.cpp.

Here is the call graph for this function:

Here is the caller graph for this function:

PRBool nsCookieService::SetCookieInternal ( nsIURI aHostURI,
nsIChannel aChannel,
nsDependentCString aCookieHeader,
nsInt64  aServerTime,
PRBool  aFromHttp,
nsCookieStatus  aStatus,
nsCookiePolicy  aPolicy 
) [protected]

Definition at line 1202 of file nsCookieService.cpp.

{
  // keep a |const char*| version of the unmodified aCookieHeader,
  // for logging purposes
  const char *cookieHeader = aCookieHeader.get();

  // create a stack-based nsCookieAttributes, to store all the
  // attributes parsed from the cookie
  nsCookieAttributes cookieAttributes;

  // init expiryTime such that session cookies won't prematurely expire
  cookieAttributes.expiryTime = LL_MAXINT;

  // newCookie says whether there are multiple cookies in the header; so we can handle them separately.
  // after this function, we don't need the cookieHeader string for processing this cookie anymore;
  // so this function uses it as an outparam to point to the next cookie, if there is one.
  const PRBool newCookie = ParseAttributes(aCookieHeader, cookieAttributes);

  // reject cookie if it's over the size limit, per RFC2109
  if ((cookieAttributes.name.Length() + cookieAttributes.value.Length()) > kMaxBytesPerCookie) {
    COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, cookieHeader, "cookie too big (> 4kb)");
    return newCookie;
  }

  if (cookieAttributes.name.FindChar('\t') != kNotFound) {
    COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, cookieHeader, "invalid name character");
    return newCookie;
  }

  // calculate expiry time of cookie. we need to pass in cookieStatus, since
  // the cookie may have been downgraded to a session cookie by p3p.
  const nsInt64 currentTime = NOW_IN_SECONDS;
  cookieAttributes.isSession = GetExpiry(cookieAttributes, aServerTime,
                                         currentTime, aStatus);

  // domain & path checks
  if (!CheckDomain(cookieAttributes, aHostURI)) {
    COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, cookieHeader, "failed the domain tests");
    return newCookie;
  }
  if (!CheckPath(cookieAttributes, aHostURI)) {
    COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, cookieHeader, "failed the path tests");
    return newCookie;
  }

  // create a new nsCookie and copy attributes
  nsRefPtr<nsCookie> cookie =
    nsCookie::Create(cookieAttributes.name,
                     cookieAttributes.value,
                     cookieAttributes.host,
                     cookieAttributes.path,
                     cookieAttributes.expiryTime,
                     currentTime,
                     cookieAttributes.isSession,
                     cookieAttributes.isSecure,
                     cookieAttributes.isHttpOnly,
                     aStatus,
                     aPolicy);
  if (!cookie) {
    return newCookie;
  }

  // check permissions from site permission list, or ask the user,
  // to determine if we can set the cookie
  if (mPermissionService) {
    PRBool permission;
    // we need to think about prompters/parent windows here - TestPermission
    // needs one to prompt, so right now it has to fend for itself to get one
    mPermissionService->CanSetCookie(aHostURI,
                                     aChannel,
                                     NS_STATIC_CAST(nsICookie2*, NS_STATIC_CAST(nsCookie*, cookie)),
                                     &cookieAttributes.isSession,
                                     &cookieAttributes.expiryTime.mValue,
                                     &permission);
    if (!permission) {
      COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, cookieHeader, "cookie rejected by permission manager");
      NotifyRejected(aHostURI);
      return newCookie;
    }

    // update isSession and expiry attributes, in case they changed
    cookie->SetIsSession(cookieAttributes.isSession);
    cookie->SetExpiry(cookieAttributes.expiryTime);
  }

  // add the cookie to the list. AddInternal() takes care of logging.
  AddInternal(cookie, NOW_IN_SECONDS, aHostURI, cookieHeader, aFromHttp);
  return newCookie;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsICookieService::setCookieString ( in nsIURI  aURI,
in nsIPrompt  aPrompt,
in string  aCookie,
in nsIChannel  aChannel 
) [inherited]
void nsICookieService::setCookieStringFromHttp ( in nsIURI  aURI,
in nsIURI  aFirstURI,
in nsIPrompt  aPrompt,
in string  aCookie,
in string  aServerTime,
in nsIChannel  aChannel 
) [inherited]
nsresult nsCookieService::SetCookieStringInternal ( nsIURI aHostURI,
nsIURI aFirstURI,
nsIPrompt aPrompt,
const char *  aCookieHeader,
const char *  aServerTime,
nsIChannel aChannel,
PRBool  aFromHttp 
) [protected]

Definition at line 698 of file nsCookieService.cpp.

{
  if (!aHostURI) {
    COOKIE_LOGFAILURE(SET_COOKIE, nsnull, aCookieHeader, "host URI is null");
    return NS_OK;
  }

  // check default prefs
  nsCookiePolicy cookiePolicy = nsICookie::POLICY_UNKNOWN;
  nsCookieStatus cookieStatus = CheckPrefs(aHostURI, aFirstURI, aChannel, aCookieHeader, cookiePolicy);
  // fire a notification if cookie was rejected (but not if there was an error)
  switch (cookieStatus) {
  case nsICookie::STATUS_REJECTED:
    NotifyRejected(aHostURI);
  case STATUS_REJECTED_WITH_ERROR:
    return NS_OK;
  }

  // parse server local time. this is not just done here for efficiency
  // reasons - if there's an error parsing it, and we need to default it
  // to the current time, we must do it here since the current time in
  // SetCookieInternal() will change for each cookie processed (e.g. if the
  // user is prompted).
  nsInt64 serverTime;
  PRTime tempServerTime;
  if (aServerTime && PR_ParseTimeString(aServerTime, PR_TRUE, &tempServerTime) == PR_SUCCESS) {
    serverTime = nsInt64(tempServerTime) / USEC_PER_SEC;
  } else {
    serverTime = NOW_IN_SECONDS;
  }

  // switch to a nice string type now, and process each cookie in the header
  nsDependentCString cookieHeader(aCookieHeader);
  while (SetCookieInternal(aHostURI, aChannel,
                           cookieHeader, serverTime, aFromHttp,
                           cookieStatus, cookiePolicy));

  // write out the cookie file
  LazyWrite();
  return NS_OK;
}

Here is the call graph for this function:

Definition at line 1078 of file nsCookieService.cpp.

{
  if (!mCookieChanged) {
    return NS_OK;
  }

  if (!mCookieFile) {
    return NS_ERROR_NULL_POINTER;
  }

  nsresult rv;
  nsCOMPtr<nsIOutputStream> fileOutputStream;
  rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(fileOutputStream),
                                       mCookieFile,
                                       -1,
                                       0600);
  if (NS_FAILED(rv)) {
    NS_ERROR("failed to open cookies.txt for writing");
    return rv;
  }

  // get a buffered output stream 4096 bytes big, to optimize writes
  nsCOMPtr<nsIOutputStream> bufferedOutputStream;
  rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), fileOutputStream, 4096);
  if (NS_FAILED(rv)) {
    return rv;
  }

  static const char kHeader[] =
      "# HTTP Cookie File\n"
      "# http://www.netscape.com/newsref/std/cookie_spec.html\n"
      "# This is a generated file!  Do not edit.\n"
      "# To delete cookies, use the Cookie Manager.\n\n";
  // note: kTrue and kFalse have leading/trailing tabs already added
  static const char kTrue[] = "\tTRUE\t";
  static const char kFalse[] = "\tFALSE\t";
  static const char kTab[] = "\t";
  static const char kNew[] = "\n";

  // create a new nsVoidArray to hold the cookie list, and sort it
  // such that least-recently-used cookies come last
  nsVoidArray sortedCookieList(mCookieCount);
  mHostTable.EnumerateEntries(cookieListCallback, &sortedCookieList);
  sortedCookieList.Sort(compareCookiesForWriting, nsnull);

  bufferedOutputStream->Write(kHeader, sizeof(kHeader) - 1, &rv);

  /* file format is:
   *
   * host \t isDomain \t path \t secure \t expires \t name \t cookie
   *
   * isDomain is "TRUE" or "FALSE"
   * isSecure is "TRUE" or "FALSE"
   * expires is a PRInt64 integer
   * note 1: cookie can contain tabs.
   * note 2: cookies are written in order of lastAccessed time:
   *         most-recently used come first; least-recently-used come last.
   */

  /*
   * XXX but see above in ::Read for the HttpOnly hack
   */
   
  nsCookie *cookie;
  nsInt64 currentTime = NOW_IN_SECONDS;
  char dateString[22];
  PRUint32 dateLen;
  for (PRUint32 i = 0; i < mCookieCount; ++i) {
    cookie = NS_STATIC_CAST(nsCookie*, sortedCookieList.ElementAt(i));

    // don't write entry if cookie has expired, or is a session cookie
    if (cookie->IsSession() || cookie->Expiry() <= currentTime) {
      continue;
    }

    // XXX hack for HttpOnly. see bug 178993.
    if (cookie->IsHttpOnly()) {
      bufferedOutputStream->Write(kHttpOnlyPrefix, sizeof(kHttpOnlyPrefix) - 1, &rv);
    }
    bufferedOutputStream->Write(cookie->Host().get(), cookie->Host().Length(), &rv);
    if (cookie->IsDomain()) {
      bufferedOutputStream->Write(kTrue, sizeof(kTrue) - 1, &rv);
    } else {
      bufferedOutputStream->Write(kFalse, sizeof(kFalse) - 1, &rv);
    }
    bufferedOutputStream->Write(cookie->Path().get(), cookie->Path().Length(), &rv);
    if (cookie->IsSecure()) {
      bufferedOutputStream->Write(kTrue, sizeof(kTrue) - 1, &rv);
    } else {
      bufferedOutputStream->Write(kFalse, sizeof(kFalse) - 1, &rv);
    }
    dateLen = PR_snprintf(dateString, sizeof(dateString), "%lld", PRInt64(cookie->Expiry()));
    bufferedOutputStream->Write(dateString, dateLen, &rv);
    bufferedOutputStream->Write(kTab, sizeof(kTab) - 1, &rv);
    bufferedOutputStream->Write(cookie->Name().get(), cookie->Name().Length(), &rv);
    bufferedOutputStream->Write(kTab, sizeof(kTab) - 1, &rv);
    bufferedOutputStream->Write(cookie->Value().get(), cookie->Value().Length(), &rv);
    bufferedOutputStream->Write(kNew, sizeof(kNew) - 1, &rv);
  }

  // All went ok. Maybe except for problems in Write(), but the stream detects
  // that for us
  nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOutputStream);
  NS_ASSERTION(safeStream, "expected a safe output stream!");
  if (safeStream) {
    rv = safeStream->Finish();
    if (NS_FAILED(rv)) {
      NS_WARNING("failed to save cookie file! possible dataloss");
      return rv;
    }
  }

  mCookieChanged = PR_FALSE;
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Friends And Related Function Documentation

Definition at line 2048 of file nsCookieService.cpp.

{
  const nsInt64 &currentTime = *NS_STATIC_CAST(nsInt64*, aArg);
  for (nsListIter iter(aEntry, nsnull, aEntry->Head()); iter.current; ) {
    if (iter.current->Expiry() <= currentTime)
      // remove from list. this takes care of updating the iterator for us
      nsCookieService::gCookieService->RemoveCookieFromList(iter);
    else
      ++iter;
  }
  return PL_DHASH_NEXT;
}

Member Data Documentation

This attribute really doesn't belong on this interface.

CVS blame will tell you why it is here. It remains until we can find a better home for it. Read the source if you want to know what it does :-(

Definition at line 168 of file nsICookieService.idl.

Called to enumerate through each cookie in the cookie list.

The objects enumerated over are of type nsICookie

Definition at line 62 of file nsICookieManager.idl.

Definition at line 223 of file nsCookieService.h.

Definition at line 213 of file nsCookieService.h.

Definition at line 212 of file nsCookieService.h.

Definition at line 204 of file nsCookieService.h.

Definition at line 214 of file nsCookieService.h.

Definition at line 217 of file nsCookieService.h.

Definition at line 211 of file nsCookieService.h.

Definition at line 219 of file nsCookieService.h.

Definition at line 218 of file nsCookieService.h.

Definition at line 205 of file nsCookieService.h.

Definition at line 206 of file nsCookieService.h.

Definition at line 207 of file nsCookieService.h.

Definition at line 210 of file nsCookieService.h.


The documentation for this class was generated from the following files: