Bug 1049299 - Correctly calculate 3rd-party cookie status for content-process HTTP channels. r=jduell

This commit is contained in:
Blake Kaplan
2014-10-28 14:23:00 +01:00
parent 60ead4688f
commit 1bd13f9ab8
11 changed files with 128 additions and 25 deletions

View File

@@ -10378,7 +10378,7 @@ nsDocShell::DoURILoad(nsIURI * aURI,
nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel)); nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(channel));
if (httpChannelInternal) { if (httpChannelInternal) {
if (aForceAllowCookies) { if (aForceAllowCookies) {
httpChannelInternal->SetForceAllowThirdPartyCookie(true); httpChannelInternal->SetThirdPartyFlags(nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
} }
if (aFirstParty) { if (aFirstParty) {
httpChannelInternal->SetDocumentURI(aURI); httpChannelInternal->SetDocumentURI(aURI);

View File

@@ -1093,7 +1093,10 @@ Navigator::SendBeacon(const nsAString& aUrl,
} }
bool isForeign = true; bool isForeign = true;
thirdPartyUtil->IsThirdPartyWindow(mWindow, uri, &isForeign); thirdPartyUtil->IsThirdPartyWindow(mWindow, uri, &isForeign);
httpChannelInternal->SetForceAllowThirdPartyCookie(!isForeign); uint32_t thirdPartyFlags = isForeign ?
0 :
nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW;
httpChannelInternal->SetThirdPartyFlags(thirdPartyFlags);
nsCString mimeType; nsCString mimeType;
if (!aData.IsNull()) { if (!aData.IsNull()) {

View File

@@ -1,3 +1,5 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 sts=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public /* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@@ -166,12 +168,17 @@ ThirdPartyUtil::IsThirdPartyChannel(nsIChannel* aChannel,
nsresult rv; nsresult rv;
bool doForce = false; bool doForce = false;
bool checkWindowChain = true;
bool parentIsThird = false;
nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal = nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
do_QueryInterface(aChannel); do_QueryInterface(aChannel);
if (httpChannelInternal) { if (httpChannelInternal) {
rv = httpChannelInternal->GetForceAllowThirdPartyCookie(&doForce); uint32_t flags;
rv = httpChannelInternal->GetThirdPartyFlags(&flags);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
doForce = (flags & nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
// If aURI was not supplied, and we're forcing, then we're by definition // If aURI was not supplied, and we're forcing, then we're by definition
// not foreign. If aURI was supplied, we still want to check whether it's // not foreign. If aURI was supplied, we still want to check whether it's
// foreign with respect to the channel URI. (The forcing only applies to // foreign with respect to the channel URI. (The forcing only applies to
@@ -180,6 +187,28 @@ ThirdPartyUtil::IsThirdPartyChannel(nsIChannel* aChannel,
*aResult = false; *aResult = false;
return NS_OK; return NS_OK;
} }
if (flags & nsIHttpChannelInternal::THIRD_PARTY_PARENT_IS_THIRD_PARTY) {
// Check that the two PARENT_IS_{THIRD,SAME}_PARTY are mutually exclusive.
MOZ_ASSERT(!(flags & nsIHttpChannelInternal::THIRD_PARTY_PARENT_IS_SAME_PARTY));
// If we're not forcing and we know that the window chain of the channel
// is third party, then we know now that we're third party.
if (!doForce) {
*aResult = true;
return NS_OK;
}
checkWindowChain = false;
parentIsThird = true;
} else {
// In e10s, we can't check the parent chain in the parent, so we do so
// in the child and send the result to the parent.
// Note that we only check the window chain if neither
// THIRD_PARTY_PARENT_IS_* flag is set.
checkWindowChain = !(flags & nsIHttpChannelInternal::THIRD_PARTY_PARENT_IS_SAME_PARTY);
parentIsThird = false;
}
} }
// Obtain the URI from the channel, and its base domain. // Obtain the URI from the channel, and its base domain.
@@ -206,6 +235,12 @@ ThirdPartyUtil::IsThirdPartyChannel(nsIChannel* aChannel,
} }
} }
// If we've already computed this in the child process, we're done.
if (!checkWindowChain) {
*aResult = parentIsThird;
return NS_OK;
}
// Find the associated window and its parent window. // Find the associated window and its parent window.
nsCOMPtr<nsILoadContext> ctx; nsCOMPtr<nsILoadContext> ctx;
NS_QueryNotificationCallbacks(aChannel, ctx); NS_QueryNotificationCallbacks(aChannel, ctx);

View File

@@ -1236,7 +1236,7 @@ nsresult nsWebBrowserPersist::SaveURIInternal(
nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal = nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal =
do_QueryInterface(inputChannel); do_QueryInterface(inputChannel);
if (httpChannelInternal) if (httpChannelInternal)
httpChannelInternal->SetForceAllowThirdPartyCookie(true); httpChannelInternal->SetThirdPartyFlags(nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
} }
// Set the referrer, post data and headers if any // Set the referrer, post data and headers if any

View File

@@ -42,7 +42,7 @@ struct HttpChannelOpenArgs
uint8_t redirectionLimit; uint8_t redirectionLimit;
bool allowPipelining; bool allowPipelining;
bool allowSTS; bool allowSTS;
bool forceAllowThirdPartyCookie; uint32_t thirdPartyFlags;
bool resumeAt; bool resumeAt;
uint64_t startPos; uint64_t startPos;
nsCString entityID; nsCString entityID;

View File

@@ -56,7 +56,7 @@ HttpBaseChannel::HttpBaseChannel()
, mResponseHeadersModified(false) , mResponseHeadersModified(false)
, mAllowPipelining(true) , mAllowPipelining(true)
, mAllowSTS(true) , mAllowSTS(true)
, mForceAllowThirdPartyCookie(false) , mThirdPartyFlags(0)
, mUploadStreamHasHeaders(false) , mUploadStreamHasHeaders(false)
, mInheritApplicationCache(true) , mInheritApplicationCache(true)
, mChooseApplicationCache(false) , mChooseApplicationCache(false)
@@ -1428,10 +1428,26 @@ HttpBaseChannel::SetCookie(const char *aCookieHeader)
return rv; return rv;
} }
NS_IMETHODIMP
HttpBaseChannel::GetThirdPartyFlags(uint32_t *aFlags)
{
*aFlags = mThirdPartyFlags;
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::SetThirdPartyFlags(uint32_t aFlags)
{
ENSURE_CALLED_BEFORE_ASYNC_OPEN();
mThirdPartyFlags = aFlags;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
HttpBaseChannel::GetForceAllowThirdPartyCookie(bool *aForce) HttpBaseChannel::GetForceAllowThirdPartyCookie(bool *aForce)
{ {
*aForce = mForceAllowThirdPartyCookie; *aForce = !!(mThirdPartyFlags & nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
return NS_OK; return NS_OK;
} }
@@ -1440,7 +1456,11 @@ HttpBaseChannel::SetForceAllowThirdPartyCookie(bool aForce)
{ {
ENSURE_CALLED_BEFORE_ASYNC_OPEN(); ENSURE_CALLED_BEFORE_ASYNC_OPEN();
mForceAllowThirdPartyCookie = aForce; if (aForce)
mThirdPartyFlags |= nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW;
else
mThirdPartyFlags &= ~nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW;
return NS_OK; return NS_OK;
} }
@@ -2040,9 +2060,8 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel); nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
if (httpInternal) { if (httpInternal) {
// convey the mForceAllowThirdPartyCookie flag // Convey third party cookie and spdy flags.
httpInternal->SetForceAllowThirdPartyCookie(mForceAllowThirdPartyCookie); httpInternal->SetThirdPartyFlags(mThirdPartyFlags);
// convey the spdy flag
httpInternal->SetAllowSpdy(mAllowSpdy); httpInternal->SetAllowSpdy(mAllowSpdy);
// update the DocumentURI indicator since we are being redirected. // update the DocumentURI indicator since we are being redirected.

View File

@@ -160,6 +160,8 @@ public:
NS_IMETHOD GetRequestVersion(uint32_t *major, uint32_t *minor); NS_IMETHOD GetRequestVersion(uint32_t *major, uint32_t *minor);
NS_IMETHOD GetResponseVersion(uint32_t *major, uint32_t *minor); NS_IMETHOD GetResponseVersion(uint32_t *major, uint32_t *minor);
NS_IMETHOD SetCookie(const char *aCookieHeader); NS_IMETHOD SetCookie(const char *aCookieHeader);
NS_IMETHOD GetThirdPartyFlags(uint32_t *aForce);
NS_IMETHOD SetThirdPartyFlags(uint32_t aForce);
NS_IMETHOD GetForceAllowThirdPartyCookie(bool *aForce); NS_IMETHOD GetForceAllowThirdPartyCookie(bool *aForce);
NS_IMETHOD SetForceAllowThirdPartyCookie(bool aForce); NS_IMETHOD SetForceAllowThirdPartyCookie(bool aForce);
NS_IMETHOD GetCanceled(bool *aCanceled); NS_IMETHOD GetCanceled(bool *aCanceled);
@@ -341,7 +343,7 @@ protected:
uint32_t mResponseHeadersModified : 1; uint32_t mResponseHeadersModified : 1;
uint32_t mAllowPipelining : 1; uint32_t mAllowPipelining : 1;
uint32_t mAllowSTS : 1; uint32_t mAllowSTS : 1;
uint32_t mForceAllowThirdPartyCookie : 1; uint32_t mThirdPartyFlags : 3;
uint32_t mUploadStreamHasHeaders : 1; uint32_t mUploadStreamHasHeaders : 1;
uint32_t mInheritApplicationCache : 1; uint32_t mInheritApplicationCache : 1;
uint32_t mChooseApplicationCache : 1; uint32_t mChooseApplicationCache : 1;

View File

@@ -31,6 +31,7 @@
#include "nsInputStreamPump.h" #include "nsInputStreamPump.h"
#include "InterceptedChannel.h" #include "InterceptedChannel.h"
#include "nsPerformance.h" #include "nsPerformance.h"
#include "mozIThirdPartyUtil.h"
using namespace mozilla::dom; using namespace mozilla::dom;
using namespace mozilla::ipc; using namespace mozilla::ipc;
@@ -1484,6 +1485,21 @@ HttpChannelChild::ContinueAsyncOpen()
optionalFDs = mozilla::void_t(); optionalFDs = mozilla::void_t();
} }
nsCOMPtr<mozIThirdPartyUtil> util(do_GetService(THIRDPARTYUTIL_CONTRACTID));
if (util) {
bool thirdParty;
nsresult rv = util->IsThirdPartyChannel(this, nullptr, &thirdParty);
if (NS_FAILED(rv)) {
// If we couldn't compute whether this is a third-party load, assume that
// it is.
thirdParty = true;
}
mThirdPartyFlags |= thirdParty ?
nsIHttpChannelInternal::THIRD_PARTY_PARENT_IS_THIRD_PARTY :
nsIHttpChannelInternal::THIRD_PARTY_PARENT_IS_SAME_PARTY;
}
openArgs.fds() = optionalFDs; openArgs.fds() = optionalFDs;
openArgs.uploadStreamHasHeaders() = mUploadStreamHasHeaders; openArgs.uploadStreamHasHeaders() = mUploadStreamHasHeaders;
@@ -1491,7 +1507,7 @@ HttpChannelChild::ContinueAsyncOpen()
openArgs.redirectionLimit() = mRedirectionLimit; openArgs.redirectionLimit() = mRedirectionLimit;
openArgs.allowPipelining() = mAllowPipelining; openArgs.allowPipelining() = mAllowPipelining;
openArgs.allowSTS() = mAllowSTS; openArgs.allowSTS() = mAllowSTS;
openArgs.forceAllowThirdPartyCookie() = mForceAllowThirdPartyCookie; openArgs.thirdPartyFlags() = mThirdPartyFlags;
openArgs.resumeAt() = mSendResumeAt; openArgs.resumeAt() = mSendResumeAt;
openArgs.startPos() = mStartPos; openArgs.startPos() = mStartPos;
openArgs.entityID() = mEntityID; openArgs.entityID() = mEntityID;

View File

@@ -101,8 +101,8 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
a.requestMethod(), a.uploadStream(), a.requestMethod(), a.uploadStream(),
a.uploadStreamHasHeaders(), a.priority(), a.uploadStreamHasHeaders(), a.priority(),
a.redirectionLimit(), a.allowPipelining(), a.allowSTS(), a.redirectionLimit(), a.allowPipelining(), a.allowSTS(),
a.forceAllowThirdPartyCookie(), a.resumeAt(), a.thirdPartyFlags(), a.resumeAt(), a.startPos(),
a.startPos(), a.entityID(), a.chooseApplicationCache(), a.entityID(), a.chooseApplicationCache(),
a.appCacheClientID(), a.allowSpdy(), a.fds(), a.appCacheClientID(), a.allowSpdy(), a.fds(),
a.requestingPrincipalInfo(), a.securityFlags(), a.requestingPrincipalInfo(), a.securityFlags(),
a.contentPolicyType()); a.contentPolicyType());
@@ -176,12 +176,12 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
const RequestHeaderTuples& requestHeaders, const RequestHeaderTuples& requestHeaders,
const nsCString& requestMethod, const nsCString& requestMethod,
const OptionalInputStreamParams& uploadStream, const OptionalInputStreamParams& uploadStream,
const bool& uploadStreamHasHeaders, const bool& uploadStreamHasHeaders,
const uint16_t& priority, const uint16_t& priority,
const uint8_t& redirectionLimit, const uint8_t& redirectionLimit,
const bool& allowPipelining, const bool& allowPipelining,
const bool& allowSTS, const bool& allowSTS,
const bool& forceAllowThirdPartyCookie, const uint32_t& thirdPartyFlags,
const bool& doResumeAt, const bool& doResumeAt,
const uint64_t& startPos, const uint64_t& startPos,
const nsCString& entityID, const nsCString& entityID,
@@ -304,7 +304,7 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
mChannel->SetRedirectionLimit(redirectionLimit); mChannel->SetRedirectionLimit(redirectionLimit);
mChannel->SetAllowPipelining(allowPipelining); mChannel->SetAllowPipelining(allowPipelining);
mChannel->SetAllowSTS(allowSTS); mChannel->SetAllowSTS(allowSTS);
mChannel->SetForceAllowThirdPartyCookie(forceAllowThirdPartyCookie); mChannel->SetThirdPartyFlags(thirdPartyFlags);
mChannel->SetAllowSpdy(allowSpdy); mChannel->SetAllowSpdy(allowSpdy);
nsCOMPtr<nsIApplicationCacheChannel> appCacheChan = nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =

View File

@@ -99,7 +99,7 @@ protected:
const uint8_t& redirectionLimit, const uint8_t& redirectionLimit,
const bool& allowPipelining, const bool& allowPipelining,
const bool& allowSTS, const bool& allowSTS,
const bool& forceAllowThirdPartyCookie, const uint32_t& thirdPartyFlags,
const bool& doResumeAt, const bool& doResumeAt,
const uint64_t& startPos, const uint64_t& startPos,
const nsCString& entityID, const nsCString& entityID,

View File

@@ -38,7 +38,7 @@ interface nsIHttpUpgradeListener : nsISupports
* using any feature exposed by this interface, be aware that this interface * using any feature exposed by this interface, be aware that this interface
* will change and you will be broken. You have been warned. * will change and you will be broken. You have been warned.
*/ */
[scriptable, uuid(a95e45c1-b145-487c-b2a9-4e96e814a1b5)] [scriptable, uuid(2677e555-8c48-4147-b883-5c2a673f65d5)]
interface nsIHttpChannelInternal : nsISupports interface nsIHttpChannelInternal : nsISupports
{ {
/** /**
@@ -78,8 +78,36 @@ interface nsIHttpChannelInternal : nsISupports
void setupFallbackChannel(in string aFallbackKey); void setupFallbackChannel(in string aFallbackKey);
/** /**
* Force relevant cookies to be sent with this load even if normally they * This flag is set to force relevant cookies to be sent with this load
* wouldn't be. * even if normally they wouldn't be.
*/
const unsigned long THIRD_PARTY_FORCE_ALLOW = 1 << 0;
/**
* This flag is set in the parent if the child has already computed that
* it originates from a 3rd party frame (i.e. a 3rd party iframe).
*/
const unsigned long THIRD_PARTY_PARENT_IS_THIRD_PARTY = 1 << 1;
/**
* This flag is set in the parent if the child has already computed that
* it is not a 3rd party request due to iframe parentage. However, if
* someone calls mozIThirdPartyUtil::IsThirdPartyChannel with a 3rd-party
* URI, the result would be true if the URI is third-party from this
* channel's URI.
*/
const unsigned long THIRD_PARTY_PARENT_IS_SAME_PARTY = 1 << 2;
/**
* When set, these flags modify the algorithm used to decide whether to
* send 3rd party cookies for a given channel.
*/
attribute unsigned long thirdPartyFlags;
/**
* This attribute was added before the "flags" above and is retained here
* for compatibility. When set to true, has the same effect as
* THIRD_PARTY_FORCE_ALLOW, described above.
*/ */
attribute boolean forceAllowThirdPartyCookie; attribute boolean forceAllowThirdPartyCookie;