зеркало из https://github.com/mozilla/pjs.git
Bug 178993 -patch from robert sayre and others - r=bsmedberg, dveditz, mvl, sr=darin - add HTTPOnly support
This commit is contained in:
Родитель
cbafae509c
Коммит
921e9a8206
|
@ -44,7 +44,7 @@
|
|||
* access of cookie objects
|
||||
*/
|
||||
|
||||
[scriptable, uuid(d3493503-7854-46ed-8284-8af54a847efb)]
|
||||
[scriptable, uuid(1f5b06e1-8d52-46a0-a26d-762bd6a1Cf75)]
|
||||
|
||||
interface nsICookie2 : nsICookie
|
||||
{
|
||||
|
@ -71,4 +71,10 @@ interface nsICookie2 : nsICookie
|
|||
*/
|
||||
readonly attribute PRInt64 expiry;
|
||||
|
||||
/**
|
||||
* true if the cookie is an http only cookie
|
||||
*/
|
||||
readonly attribute boolean httpOnly;
|
||||
|
||||
|
||||
};
|
||||
|
|
|
@ -94,10 +94,8 @@ interface nsICookieService : nsISupports
|
|||
/*
|
||||
* Get the complete cookie string associated with the URI.
|
||||
*
|
||||
* XXX this function is redundant and will most likely be removed in a future
|
||||
* revision of this interface. GetCookieString will query the documentURI
|
||||
* property off of nsIHttpChannelInternal if supported, so GetCookieString
|
||||
* can be used in place of this method.
|
||||
* 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.
|
||||
|
@ -135,11 +133,8 @@ interface nsICookieService : nsISupports
|
|||
/*
|
||||
* Set the cookie string and expires associated with the URI.
|
||||
*
|
||||
* XXX this function is redundant and will most likely be removed in a future
|
||||
* revision of this interface. SetCookieString will query the documentURI
|
||||
* property off of nsIHttpChannelInternal if supported, and SetCookieString
|
||||
* could also query the Date header from the channel if aChannel supports
|
||||
* nsIHttpChannel.
|
||||
* 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.
|
||||
|
|
|
@ -89,6 +89,7 @@ nsCookie::Create(const nsACString &aName,
|
|||
nsInt64 aLastAccessed,
|
||||
PRBool aIsSession,
|
||||
PRBool aIsSecure,
|
||||
PRBool aIsHttpOnly,
|
||||
nsCookieStatus aStatus,
|
||||
nsCookiePolicy aPolicy)
|
||||
{
|
||||
|
@ -111,7 +112,8 @@ nsCookie::Create(const nsACString &aName,
|
|||
// construct the cookie. placement new, oh yeah!
|
||||
return new (place) nsCookie(name, value, host, path, end,
|
||||
aExpiry, aLastAccessed, ++gLastCreationTime,
|
||||
aIsSession, aIsSecure, aStatus, aPolicy);
|
||||
aIsSession, aIsSecure, aIsHttpOnly,
|
||||
aStatus, aPolicy);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -131,6 +133,7 @@ NS_IMETHODIMP nsCookie::GetIsDomain(PRBool *aIsDomain) { *aIsDomain = IsDoma
|
|||
NS_IMETHODIMP nsCookie::GetIsSecure(PRBool *aIsSecure) { *aIsSecure = IsSecure(); return NS_OK; }
|
||||
NS_IMETHODIMP nsCookie::GetStatus(nsCookieStatus *aStatus) { *aStatus = Status(); return NS_OK; }
|
||||
NS_IMETHODIMP nsCookie::GetPolicy(nsCookiePolicy *aPolicy) { *aPolicy = Policy(); return NS_OK; }
|
||||
NS_IMETHODIMP nsCookie::GetHttpOnly(PRBool *aHttpOnly) { *aHttpOnly = IsHttpOnly(); return NS_OK; }
|
||||
|
||||
// compatibility method, for use with the legacy nsICookie interface.
|
||||
// here, expires == 0 denotes a session cookie.
|
||||
|
|
|
@ -80,6 +80,7 @@ class nsCookie : public nsICookie2
|
|||
PRUint32 aCreationTime,
|
||||
PRBool aIsSession,
|
||||
PRBool aIsSecure,
|
||||
PRBool aIsHttpOnly,
|
||||
nsCookieStatus aStatus,
|
||||
nsCookiePolicy aPolicy)
|
||||
: mNext(nsnull)
|
||||
|
@ -94,6 +95,7 @@ class nsCookie : public nsICookie2
|
|||
, mRefCnt(0)
|
||||
, mIsSession(aIsSession != PR_FALSE)
|
||||
, mIsSecure(aIsSecure != PR_FALSE)
|
||||
, mIsHttpOnly(aIsHttpOnly != PR_FALSE)
|
||||
, mStatus(aStatus)
|
||||
, mPolicy(aPolicy)
|
||||
{
|
||||
|
@ -110,6 +112,7 @@ class nsCookie : public nsICookie2
|
|||
nsInt64 aLastAccessed,
|
||||
PRBool aIsSession,
|
||||
PRBool aIsSecure,
|
||||
PRBool aIsHttpOnly,
|
||||
nsCookieStatus aStatus,
|
||||
nsCookiePolicy aPolicy);
|
||||
|
||||
|
@ -127,6 +130,7 @@ class nsCookie : public nsICookie2
|
|||
inline PRBool IsSession() const { return mIsSession; }
|
||||
inline PRBool IsDomain() const { return *mHost == '.'; }
|
||||
inline PRBool IsSecure() const { return mIsSecure; }
|
||||
inline PRBool IsHttpOnly() const { return mIsHttpOnly; }
|
||||
inline nsCookieStatus Status() const { return mStatus; }
|
||||
inline nsCookiePolicy Policy() const { return mPolicy; }
|
||||
|
||||
|
@ -158,6 +162,7 @@ class nsCookie : public nsICookie2
|
|||
PRUint32 mRefCnt : 16;
|
||||
PRUint32 mIsSession : 1;
|
||||
PRUint32 mIsSecure : 1;
|
||||
PRUint32 mIsHttpOnly: 1;
|
||||
PRUint32 mStatus : 3;
|
||||
PRUint32 mPolicy : 3;
|
||||
};
|
||||
|
|
|
@ -75,6 +75,11 @@
|
|||
* useful types & constants
|
||||
******************************************************************************/
|
||||
|
||||
// XXX_hack. See bug 178993.
|
||||
// This is a hack to hide HttpOnly cookies from older browsers
|
||||
//
|
||||
static const char kHttpOnlyPrefix[] = "#HttpOnly_";
|
||||
|
||||
static const char kCookieFileName[] = "cookies.txt";
|
||||
|
||||
static const PRUint32 kLazyWriteTimeout = 5000; //msec
|
||||
|
@ -123,6 +128,7 @@ struct nsCookieAttributes
|
|||
nsInt64 expiryTime;
|
||||
PRBool isSession;
|
||||
PRBool isSecure;
|
||||
PRBool isHttpOnly;
|
||||
};
|
||||
|
||||
// stores linked list iteration state, and provides a rudimentary
|
||||
|
@ -482,7 +488,7 @@ nsCookieService::Observe(nsISupports *aSubject,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// helper function for GetCookieStringFromHttp
|
||||
// helper function for GetCookieList
|
||||
static inline PRBool ispathdelimiter(char c) { return c == '/' || c == '?' || c == '#' || c == ';'; }
|
||||
|
||||
void
|
||||
|
@ -490,6 +496,7 @@ nsCookieService::GetCookieList(nsIURI *aHostURI,
|
|||
nsIURI *aFirstURI,
|
||||
nsIChannel *aChannel,
|
||||
const nsACString *aName,
|
||||
PRBool aHttpBound,
|
||||
nsAutoVoidArray &aResult)
|
||||
{
|
||||
if (!aHostURI) {
|
||||
|
@ -552,6 +559,12 @@ nsCookieService::GetCookieList(nsIURI *aHostURI,
|
|||
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() == '/') {
|
||||
|
@ -615,7 +628,7 @@ nsCookieService::GetCookieValue(nsIURI *aHostURI,
|
|||
}
|
||||
|
||||
nsAutoVoidArray foundCookieList;
|
||||
GetCookieList(aHostURI, firstURI, aChannel, &aName,
|
||||
GetCookieList(aHostURI, firstURI, aChannel, &aName, PR_FALSE,
|
||||
foundCookieList);
|
||||
|
||||
if (!foundCookieList.Count())
|
||||
|
@ -640,7 +653,12 @@ nsCookieService::GetCookieString(nsIURI *aHostURI,
|
|||
httpInternal->GetDocumentURI(getter_AddRefs(firstURI));
|
||||
}
|
||||
|
||||
return GetCookieStringFromHttp(aHostURI, firstURI, aChannel, aCookie);
|
||||
nsAutoVoidArray foundCookieList;
|
||||
GetCookieList(aHostURI, firstURI, aChannel, nsnull, PR_FALSE,
|
||||
foundCookieList);
|
||||
*aCookie = CookieStringFromArray(foundCookieList, aHostURI);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -649,16 +667,22 @@ nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI,
|
|||
nsIChannel *aChannel,
|
||||
char **aCookie)
|
||||
{
|
||||
*aCookie = nsnull;
|
||||
|
||||
nsAutoVoidArray foundCookieList;
|
||||
GetCookieList(aHostURI, aFirstURI, aChannel, nsnull,
|
||||
GetCookieList(aHostURI, aFirstURI, aChannel, nsnull, PR_TRUE,
|
||||
foundCookieList);
|
||||
*aCookie = CookieStringFromArray(foundCookieList, aHostURI);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
char*
|
||||
nsCookieService::CookieStringFromArray(const nsAutoVoidArray& aCookieList,
|
||||
nsIURI *aHostURI)
|
||||
{
|
||||
nsCAutoString cookieData;
|
||||
PRInt32 count = foundCookieList.Count();
|
||||
PRInt32 count = aCookieList.Count();
|
||||
for (PRInt32 i = 0; i < count; ++i) {
|
||||
nsCookie *cookie = NS_STATIC_CAST(nsCookie*, foundCookieList.ElementAt(i));
|
||||
nsCookie *cookie = NS_STATIC_CAST(nsCookie*, aCookieList.ElementAt(i));
|
||||
|
||||
// check if we have anything to write
|
||||
if (!cookie->Name().IsEmpty() || !cookie->Value().IsEmpty()) {
|
||||
|
@ -682,10 +706,10 @@ nsCookieService::GetCookieStringFromHttp(nsIURI *aHostURI,
|
|||
// fix the callers to use nsACStrings.
|
||||
if (!cookieData.IsEmpty()) {
|
||||
COOKIE_LOGSUCCESS(GET_COOKIE, aHostURI, cookieData, nsnull);
|
||||
*aCookie = ToNewCString(cookieData);
|
||||
return ToNewCString(cookieData);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -943,6 +967,7 @@ nsCookieService::Add(const nsACString &aDomain,
|
|||
currentTime,
|
||||
aIsSession,
|
||||
aIsSecure,
|
||||
PR_FALSE,
|
||||
nsICookie::STATUS_UNKNOWN,
|
||||
nsICookie::POLICY_UNKNOWN);
|
||||
if (!cookie) {
|
||||
|
@ -1007,11 +1032,11 @@ nsCookieService::Read()
|
|||
|
||||
nsCAutoString buffer;
|
||||
PRBool isMore = PR_TRUE;
|
||||
PRInt32 hostIndex = 0, isDomainIndex, pathIndex, secureIndex, expiresIndex, nameIndex, cookieIndex;
|
||||
PRInt32 hostIndex, isDomainIndex, pathIndex, secureIndex, expiresIndex, nameIndex, cookieIndex;
|
||||
nsASingleFragmentCString::char_iterator iter;
|
||||
PRInt32 numInts;
|
||||
PRInt64 expires;
|
||||
PRBool isDomain;
|
||||
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)
|
||||
|
@ -1031,9 +1056,25 @@ nsCookieService::Read()
|
|||
* 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 (buffer.IsEmpty() || buffer.First() == '#') {
|
||||
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
|
||||
|
@ -1077,6 +1118,7 @@ nsCookieService::Read()
|
|||
nsInt64(expires),
|
||||
lastAccessedCounter,
|
||||
PR_FALSE,
|
||||
isHttpOnly,
|
||||
Substring(buffer, secureIndex, expiresIndex - secureIndex - 1).EqualsLiteral(kTrue),
|
||||
nsICookie::STATUS_UNKNOWN,
|
||||
nsICookie::POLICY_UNKNOWN);
|
||||
|
@ -1173,6 +1215,11 @@ nsCookieService::Write()
|
|||
* 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];
|
||||
|
@ -1185,6 +1232,10 @@ nsCookieService::Write()
|
|||
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);
|
||||
|
@ -1300,6 +1351,7 @@ nsCookieService::CheckAndAdd(nsIURI *aHostURI,
|
|||
currentTime,
|
||||
aAttributes.isSession,
|
||||
aAttributes.isSecure,
|
||||
aAttributes.isHttpOnly,
|
||||
aStatus,
|
||||
aPolicy);
|
||||
if (!cookie) {
|
||||
|
@ -1442,6 +1494,9 @@ nsCookieService::AddInternal(nsCookie *aCookie,
|
|||
5. cookie <NAME> is optional, where spec requires it. This is a fairly
|
||||
trivial case, but allows the flexibility of setting only a cookie <VALUE>
|
||||
with a blank <NAME> and is required by some sites (see bug 169091).
|
||||
|
||||
6. Attribute "HttpOnly", not covered in the RFCs, is supported
|
||||
(see bug 178993).
|
||||
|
||||
** Begin BNF:
|
||||
token = 1*<any allowed-chars except separators>
|
||||
|
@ -1477,6 +1532,7 @@ nsCookieService::AddInternal(nsCookie *aCookie,
|
|||
| "Comment" "=" value
|
||||
| "Version" "=" value
|
||||
| "Secure"
|
||||
| "HttpOnly"
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -1583,6 +1639,7 @@ nsCookieService::ParseAttributes(nsDependentCString &aCookieHeader,
|
|||
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;
|
||||
|
@ -1590,7 +1647,8 @@ nsCookieService::ParseAttributes(nsDependentCString &aCookieHeader,
|
|||
aCookieHeader.EndReading(cookieEnd);
|
||||
|
||||
aCookieAttributes.isSecure = PR_FALSE;
|
||||
|
||||
aCookieAttributes.isHttpOnly = PR_FALSE;
|
||||
|
||||
nsDependentCSubstring tokenString(cookieStart, cookieStart);
|
||||
nsDependentCSubstring tokenValue (cookieStart, cookieStart);
|
||||
PRBool newCookie, equalsFound;
|
||||
|
@ -1637,6 +1695,11 @@ nsCookieService::ParseAttributes(nsDependentCString &aCookieHeader,
|
|||
// 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
|
||||
|
|
|
@ -175,7 +175,8 @@ class nsCookieService : public nsICookieServiceInternal
|
|||
void PrefChanged(nsIPrefBranch *aPrefBranch);
|
||||
nsresult Read();
|
||||
nsresult Write();
|
||||
void GetCookieList(nsIURI *aHostURI, nsIURI *aFirstURI, nsIChannel *aChannel, const nsACString *aName, nsAutoVoidArray &aResult);
|
||||
void GetCookieList(nsIURI *aHostURI, nsIURI *aFirstURI, nsIChannel *aChannel, const nsACString *aName, PRBool isHttpBound, nsAutoVoidArray &aResult);
|
||||
char* CookieStringFromArray(const nsAutoVoidArray& aCookieList, nsIURI *aHostURI);
|
||||
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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче