diff --git a/netwerk/cookie/public/Makefile.in b/netwerk/cookie/public/Makefile.in index 3e458bcd96e..12a5e8a9b0e 100644 --- a/netwerk/cookie/public/Makefile.in +++ b/netwerk/cookie/public/Makefile.in @@ -53,6 +53,7 @@ SDK_XPIDLSRCS = \ XPIDLSRCS = \ nsICookieService.idl \ + nsICookieServiceInternal.idl \ nsICookie2.idl \ nsICookieConsent.idl \ nsICookieManager2.idl \ diff --git a/netwerk/cookie/public/nsICookieServiceInternal.idl b/netwerk/cookie/public/nsICookieServiceInternal.idl new file mode 100644 index 00000000000..e69de29bb2d diff --git a/netwerk/cookie/src/nsCookieService.cpp b/netwerk/cookie/src/nsCookieService.cpp index c6024e554d7..0d638860bf2 100644 --- a/netwerk/cookie/src/nsCookieService.cpp +++ b/netwerk/cookie/src/nsCookieService.cpp @@ -1,5 +1,5 @@ // vim:ts=2:sw=2:et: -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -371,8 +371,9 @@ nsCookieService::GetSingleton() * public methods ******************************************************************************/ -NS_IMPL_ISUPPORTS5(nsCookieService, +NS_IMPL_ISUPPORTS6(nsCookieService, nsICookieService, + nsICookieServiceInternal, nsICookieManager, nsICookieManager2, nsIObserver, @@ -481,36 +482,19 @@ nsCookieService::Observe(nsISupports *aSubject, return NS_OK; } -NS_IMETHODIMP -nsCookieService::GetCookieString(nsIURI *aHostURI, - nsIChannel *aChannel, - char **aCookie) -{ - // try to determine first party URI - nsCOMPtr firstURI; - if (aChannel) { - nsCOMPtr httpInternal = do_QueryInterface(aChannel); - if (httpInternal) - httpInternal->GetDocumentURI(getter_AddRefs(firstURI)); - } - - return GetCookieStringFromHttp(aHostURI, firstURI, aChannel, aCookie); -} - // helper function for GetCookieStringFromHttp static inline PRBool ispathdelimiter(char c) { return c == '/' || c == '?' || c == '#' || c == ';'; } -NS_IMETHODIMP -nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI, - nsIURI *aFirstURI, - nsIChannel *aChannel, - char **aCookie) +void +nsCookieService::GetCookieList(nsIURI *aHostURI, + nsIURI *aFirstURI, + nsIChannel *aChannel, + const nsACString *aName, + nsAutoVoidArray &aResult) { - *aCookie = nsnull; - if (!aHostURI) { COOKIE_LOGFAILURE(GET_COOKIE, nsnull, nsnull, "host URI is null"); - return NS_OK; + return; } // check default prefs @@ -520,7 +504,7 @@ nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI, switch (cookieStatus) { case nsICookie::STATUS_REJECTED: case STATUS_REJECTED_WITH_ERROR: - return NS_OK; + return; } // get host and path from the nsIURI @@ -530,7 +514,7 @@ nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI, 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; + return; } // trim trailing dots hostFromURI.Trim("."); @@ -548,7 +532,6 @@ nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI, } nsCookie *cookie; - nsAutoVoidArray foundCookieList; nsInt64 currentTime = NOW_IN_SECONDS; const char *currentDot = hostFromURI.get(); const char *nextDot = currentDot + 1; @@ -559,6 +542,11 @@ nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI, nsCookieEntry *entry = mHostTable.GetEntry(currentDot); cookie = entry ? entry->Head() : nsnull; for (; cookie; cookie = cookie->Next()) { + // check the cookie name, if appropriate + if (aName && !aName->Equals(cookie->Name())) { + continue; + } + // if the cookie is secure and the host scheme isn't, we can't send it if (cookie->IsSecure() && !isSecure) { continue; @@ -594,7 +582,7 @@ nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI, } // all checks passed - add to list and update lastAccessed stamp of cookie - foundCookieList.AppendElement(cookie); + aResult.AppendElement(cookie); cookie->SetLastAccessed(currentTime); } @@ -607,12 +595,70 @@ nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI, // 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); + aResult.Sort(compareCookiesForSending, nsnull); +} + +NS_IMETHODIMP +nsCookieService::GetCookieValue(nsIURI *aHostURI, + nsIChannel *aChannel, + const nsACString& aName, + nsACString& aResult) +{ + aResult.Truncate(); + + // try to determine first party URI + nsCOMPtr firstURI; + if (aChannel) { + nsCOMPtr httpInternal = do_QueryInterface(aChannel); + if (httpInternal) + httpInternal->GetDocumentURI(getter_AddRefs(firstURI)); + } + + nsAutoVoidArray foundCookieList; + GetCookieList(aHostURI, firstURI, aChannel, &aName, + foundCookieList); + + if (!foundCookieList.Count()) + return NS_ERROR_NOT_AVAILABLE; + + nsCookie *cookie = NS_STATIC_CAST(nsCookie*, foundCookieList[0]); + + aResult.Assign(cookie->Value()); + return NS_OK; +} + +NS_IMETHODIMP +nsCookieService::GetCookieString(nsIURI *aHostURI, + nsIChannel *aChannel, + char **aCookie) +{ + // try to determine first party URI + nsCOMPtr firstURI; + if (aChannel) { + nsCOMPtr httpInternal = do_QueryInterface(aChannel); + if (httpInternal) + httpInternal->GetDocumentURI(getter_AddRefs(firstURI)); + } + + return GetCookieStringFromHttp(aHostURI, firstURI, aChannel, aCookie); +} + +NS_IMETHODIMP +nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI, + nsIURI *aFirstURI, + nsIChannel *aChannel, + char **aCookie) +{ + *aCookie = nsnull; + + nsAutoVoidArray foundCookieList; + GetCookieList(aHostURI, aFirstURI, aChannel, nsnull, + foundCookieList); nsCAutoString cookieData; PRInt32 count = foundCookieList.Count(); for (PRInt32 i = 0; i < count; ++i) { - cookie = NS_STATIC_CAST(nsCookie*, foundCookieList.ElementAt(i)); + nsCookie *cookie = NS_STATIC_CAST(nsCookie*, foundCookieList.ElementAt(i)); // check if we have anything to write if (!cookie->Name().IsEmpty() || !cookie->Value().IsEmpty()) { @@ -642,6 +688,52 @@ nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI, return NS_OK; } +NS_IMETHODIMP +nsCookieService::SetCookieValue(nsIURI *aHostURI, + nsIChannel *aChannel, + const nsACString& aDomain, + const nsACString& aPath, + const nsACString& aName, + const nsACString& aValue, + PRBool aIsSession, + PRInt64 aExpiry) +{ + // try to determine first party URI + nsCOMPtr firstURI; + + if (aChannel) { + nsCOMPtr httpInternal = do_QueryInterface(aChannel); + if (httpInternal) + httpInternal->GetDocumentURI(getter_AddRefs(firstURI)); + } + + // check default prefs + nsCookiePolicy cookiePolicy = nsICookie::POLICY_UNKNOWN; + nsCookieStatus cookieStatus = CheckPrefs(aHostURI, firstURI, aChannel, "", 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; + } + + nsCookieAttributes attributes; + attributes.name = aName; + attributes.value = aValue; + attributes.host = aDomain; + attributes.path = aPath; + attributes.expiryTime = aExpiry; + attributes.isSession = aIsSession; + + attributes.isSecure = PR_FALSE; + aHostURI->SchemeIs("https", &attributes.isSecure); + + CheckAndAdd(aHostURI, aChannel, attributes, + cookieStatus, cookiePolicy, EmptyCString()); + return NS_OK; +} + NS_IMETHODIMP nsCookieService::SetCookieString(nsIURI *aHostURI, nsIPrompt *aPrompt, @@ -1141,14 +1233,10 @@ PRBool nsCookieService::SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, nsDependentCString &aCookieHeader, - nsInt64 aServerTime, - nsCookieStatus aStatus, - nsCookiePolicy aPolicy) + nsInt64 aServerTime, + nsCookieStatus aStatus, + nsCookiePolicy aPolicy) { - // 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; @@ -1156,16 +1244,12 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI, // 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; - } + // newCookie says whether there are multiple cookies in the header; + // so we can handle them separately. This function uses + // "thisCookieHaeder" as an in/out param to point to the next + // cookie, if there is one. + nsDependentCString thisCookieHeader(aCookieHeader); + const PRBool newCookie = ParseAttributes(thisCookieHeader, cookieAttributes); // calculate expiry time of cookie. we need to pass in cookieStatus, since // the cookie may have been downgraded to a session cookie by p3p. @@ -1173,30 +1257,52 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI, cookieAttributes.isSession = GetExpiry(cookieAttributes, aServerTime, currentTime, aStatus); + CheckAndAdd(aHostURI, aChannel, cookieAttributes, + aStatus, aPolicy, aCookieHeader); + + return newCookie; +} + +void +nsCookieService::CheckAndAdd(nsIURI *aHostURI, + nsIChannel *aChannel, + nsCookieAttributes &aAttributes, + nsCookieStatus aStatus, + const nsCookiePolicy aPolicy, + const nsAFlatCString &aCookieHeader) +{ + // reject cookie if it's over the size limit, per RFC2109 + if ((aAttributes.name.Length() + aAttributes.value.Length()) > kMaxBytesPerCookie) { + COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "cookie too big (> 4kb)"); + return; + } + // domain & path checks - if (!CheckDomain(cookieAttributes, aHostURI)) { - COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, cookieHeader, "failed the domain tests"); - return newCookie; + if (!CheckDomain(aAttributes, aHostURI)) { + COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "failed the domain tests"); + return; } - if (!CheckPath(cookieAttributes, aHostURI)) { - COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, cookieHeader, "failed the path tests"); - return newCookie; + if (!CheckPath(aAttributes, aHostURI)) { + COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "failed the path tests"); + return; } + const nsInt64 currentTime = NOW_IN_SECONDS; + // create a new nsCookie and copy attributes nsRefPtr cookie = - nsCookie::Create(cookieAttributes.name, - cookieAttributes.value, - cookieAttributes.host, - cookieAttributes.path, - cookieAttributes.expiryTime, + nsCookie::Create(aAttributes.name, + aAttributes.value, + aAttributes.host, + aAttributes.path, + aAttributes.expiryTime, currentTime, - cookieAttributes.isSession, - cookieAttributes.isSecure, + aAttributes.isSession, + aAttributes.isSecure, aStatus, aPolicy); if (!cookie) { - return newCookie; + return; } // check permissions from site permission list, or ask the user, @@ -1208,23 +1314,22 @@ nsCookieService::SetCookieInternal(nsIURI *aHostURI, mPermissionService->CanSetCookie(aHostURI, aChannel, NS_STATIC_CAST(nsICookie2*, NS_STATIC_CAST(nsCookie*, cookie)), - &cookieAttributes.isSession, - &cookieAttributes.expiryTime.mValue, + &aAttributes.isSession, + &aAttributes.expiryTime.mValue, &permission); if (!permission) { - COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, cookieHeader, "cookie rejected by permission manager"); + COOKIE_LOGFAILURE(SET_COOKIE, aHostURI, aCookieHeader, "cookie rejected by permission manager"); NotifyRejected(aHostURI); - return newCookie; + return; } // update isSession and expiry attributes, in case they changed - cookie->SetIsSession(cookieAttributes.isSession); - cookie->SetExpiry(cookieAttributes.expiryTime); + cookie->SetIsSession(aAttributes.isSession); + cookie->SetExpiry(aAttributes.expiryTime); } // add the cookie to the list. AddInternal() takes care of logging. - AddInternal(cookie, NOW_IN_SECONDS, aHostURI, cookieHeader); - return newCookie; + AddInternal(cookie, NOW_IN_SECONDS, aHostURI, aCookieHeader.get()); } // this is a backend function for adding a cookie to the list, via SetCookie. diff --git a/netwerk/cookie/src/nsCookieService.h b/netwerk/cookie/src/nsCookieService.h index 86b88074747..327c3a447b1 100644 --- a/netwerk/cookie/src/nsCookieService.h +++ b/netwerk/cookie/src/nsCookieService.h @@ -40,7 +40,7 @@ #ifndef nsCookieService_h__ #define nsCookieService_h__ -#include "nsICookieService.h" +#include "nsICookieServiceInternal.h" #include "nsICookieManager.h" #include "nsICookieManager2.h" #include "nsIObserver.h" @@ -55,6 +55,9 @@ struct nsCookieAttributes; struct nsListIter; struct nsEnumerationData; + +class nsAutoVoidArray; + class nsIPrefBranch; class nsICookieConsent; class nsICookiePermission; @@ -149,7 +152,7 @@ class nsCookieEntry : public PLDHashEntryHdr * class declaration ******************************************************************************/ -class nsCookieService : public nsICookieService +class nsCookieService : public nsICookieServiceInternal , public nsICookieManager2 , public nsIObserver , public nsSupportsWeakReference @@ -159,6 +162,7 @@ class nsCookieService : public nsICookieService NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER NS_DECL_NSICOOKIESERVICE + NS_DECL_NSICOOKIESERVICEINTERNAL NS_DECL_NSICOOKIEMANAGER NS_DECL_NSICOOKIEMANAGER2 @@ -171,7 +175,9 @@ class nsCookieService : public nsICookieService void PrefChanged(nsIPrefBranch *aPrefBranch); nsresult Read(); nsresult Write(); + void GetCookieList(nsIURI *aHostURI, nsIURI *aFirstURI, nsIChannel *aChannel, const nsACString *aName, nsAutoVoidArray &aResult); PRBool SetCookieInternal(nsIURI *aHostURI, nsIChannel *aChannel, nsDependentCString &aCookieHeader, nsInt64 aServerTime, nsCookieStatus aStatus, nsCookiePolicy aPolicy); + void CheckAndAdd(nsIURI *aHostURI, nsIChannel *aChannel, nsCookieAttributes &aAttributes, nsCookieStatus aStatus, nsCookiePolicy aPolicy, const nsAFlatCString &aCookieHeader); void AddInternal(nsCookie *aCookie, nsInt64 aCurrentTime, nsIURI *aHostURI, const char *aCookieHeader); void RemoveCookieFromList(nsListIter &aIter); PRBool AddCookieToList(nsCookie *aCookie);