Bug 1264792 - Update request'referrer policy when redirect.r=bkelly,dragana.

MozReview-Commit-ID: 3V6W0fuRomZ

--HG--
extra : rebase_source : 4b708f9646ea42ef40c60ba0b7a86e14edf621e3
This commit is contained in:
Thomas Nguyen 2016-11-14 15:15:32 +08:00
parent 2c891cc35b
commit b169621e2e
16 changed files with 243 additions and 91 deletions

View File

@ -8480,10 +8480,8 @@ nsContentUtils::SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal,
referrerURI = principalURI;
}
net::ReferrerPolicy referrerPolicy = aReferrerPolicy;
if (referrerPolicy == net::RP_Default) {
referrerPolicy = aDoc->GetReferrerPolicy();
}
net::ReferrerPolicy referrerPolicy = (aReferrerPolicy != net::RP_Unset) ?
aReferrerPolicy : net::RP_Default;
return aChannel->SetReferrerWithPolicy(referrerURI, referrerPolicy);
}

View File

@ -197,7 +197,10 @@ static_assert(int(ReferrerPolicy::_empty) == 0 &&
int(ReferrerPolicy::Origin) == 3 &&
int(ReferrerPolicy::Origin_when_cross_origin) == 4 &&
int(ReferrerPolicy::Unsafe_url) == 5 &&
int(ReferrerPolicy::EndGuard_) == 6,
int(ReferrerPolicy::Same_origin) == 6 &&
int(ReferrerPolicy::Strict_origin) == 7 &&
int(ReferrerPolicy::Strict_origin_when_cross_origin) == 8 &&
int(ReferrerPolicy::EndGuard_) == 9,
"ReferrerPolicy values are as expected");
static_assert(int(RequestMode::Same_origin) == 0 &&
int(RequestMode::No_cors) == 1 &&

View File

@ -35,6 +35,7 @@
#include "mozilla/Unused.h"
#include "Fetch.h"
#include "FetchUtil.h"
#include "InternalRequest.h"
#include "InternalResponse.h"
@ -260,62 +261,30 @@ FetchDriver::HttpFetch()
// Set the same headers.
SetRequestHeaders(httpChan);
// Step 2. Set the referrer.
nsAutoString referrer;
mRequest->GetReferrer(referrer);
// The Referrer Policy in Request can be used to override a referrer policy
// associated with an environment settings object.
// If there's no Referrer Policy in the request, it should be inherited
// from environment.
ReferrerPolicy referrerPolicy = mRequest->ReferrerPolicy_();
net::ReferrerPolicy net_referrerPolicy = mRequest->GetEnvironmentReferrerPolicy();
switch (referrerPolicy) {
case ReferrerPolicy::_empty:
break;
case ReferrerPolicy::No_referrer:
net_referrerPolicy = net::RP_No_Referrer;
break;
case ReferrerPolicy::No_referrer_when_downgrade:
net_referrerPolicy = net::RP_No_Referrer_When_Downgrade;
break;
case ReferrerPolicy::Origin:
net_referrerPolicy = net::RP_Origin;
break;
case ReferrerPolicy::Origin_when_cross_origin:
net_referrerPolicy = net::RP_Origin_When_Crossorigin;
break;
case ReferrerPolicy::Unsafe_url:
net_referrerPolicy = net::RP_Unsafe_URL;
break;
default:
MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?");
break;
// Step 6 of
// https://fetch.spec.whatwg.org/#main-fetch
// If request's referrer policy is the empty string and request's client is
// non-null, then set request's referrer policy to request's client's
// associated referrer policy.
// Basically, "client" is not in our implementation, we use
// EnvironmentReferrerPolicy of the worker or document context
if (mRequest->ReferrerPolicy_() == ReferrerPolicy::_empty) {
mRequest->SetReferrerPolicy(net_referrerPolicy);
}
// Step 7 of
// https://fetch.spec.whatwg.org/#main-fetch
// If requests referrer policy is the empty string,
// then set requests referrer policy to "no-referrer-when-downgrade".
if (mRequest->ReferrerPolicy_() == ReferrerPolicy::_empty) {
mRequest->SetReferrerPolicy(net::RP_No_Referrer_When_Downgrade);
}
if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
rv = nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal,
mDocument,
httpChan,
net_referrerPolicy);
NS_ENSURE_SUCCESS(rv, rv);
} else if (referrer.IsEmpty()) {
rv = httpChan->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// From "Determine request's Referrer" step 3
// "If request's referrer is a URL, let referrerSource be request's
// referrer."
nsCOMPtr<nsIURI> referrerURI;
rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
rv =
httpChan->SetReferrerWithPolicy(referrerURI,
referrerPolicy == ReferrerPolicy::_empty ?
mRequest->GetEnvironmentReferrerPolicy() :
net_referrerPolicy);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = FetchUtil::SetRequestReferrer(mPrincipal,
mDocument,
httpChan,
mRequest);
NS_ENSURE_SUCCESS(rv, rv);
// Bug 1120722 - Authorization will be handled later.
// Auth may require prompting, we don't support it yet.
@ -823,29 +792,15 @@ FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
net::ReferrerPolicy net_referrerPolicy =
nsContentUtils::GetReferrerPolicyFromHeader(tRPHeaderValue);
if (net_referrerPolicy != net::RP_Unset) {
ReferrerPolicy referrerPolicy = mRequest->ReferrerPolicy_();
switch (net_referrerPolicy) {
case net::RP_No_Referrer:
referrerPolicy = ReferrerPolicy::No_referrer;
break;
case net::RP_No_Referrer_When_Downgrade:
referrerPolicy = ReferrerPolicy::No_referrer_when_downgrade;
break;
case net::RP_Origin:
referrerPolicy = ReferrerPolicy::Origin;
break;
case net::RP_Origin_When_Crossorigin:
referrerPolicy = ReferrerPolicy::Origin_when_cross_origin;
break;
case net::RP_Unsafe_URL:
referrerPolicy = ReferrerPolicy::Unsafe_url;
break;
default:
MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value");
break;
mRequest->SetReferrerPolicy(net_referrerPolicy);
// Should update channel's referrer policy
if (httpChannel) {
rv = FetchUtil::SetRequestReferrer(mPrincipal,
mDocument,
httpChannel,
mRequest);
NS_ENSURE_SUCCESS(rv, rv);
}
mRequest->SetReferrerPolicy(referrerPolicy);
}
}

View File

@ -3,8 +3,10 @@
#include "nsError.h"
#include "nsIUnicodeDecoder.h"
#include "nsString.h"
#include "nsIDocument.h"
#include "mozilla/dom/EncodingUtils.h"
#include "mozilla/dom/InternalRequest.h"
namespace mozilla {
namespace dom {
@ -110,5 +112,59 @@ FetchUtil::ExtractHeader(nsACString::const_iterator& aStart,
return PushOverLine(aStart, aEnd);
}
// static
nsresult
FetchUtil::SetRequestReferrer(nsIPrincipal* aPrincipal,
nsIDocument* aDoc,
nsIHttpChannel* aChannel,
InternalRequest* aRequest) {
MOZ_ASSERT(NS_IsMainThread());
nsAutoString referrer;
aRequest->GetReferrer(referrer);
net::ReferrerPolicy policy = aRequest->GetReferrerPolicy();
nsresult rv = NS_OK;
if (referrer.IsEmpty()) {
// This is the case requests referrer is "no-referrer"
rv = aChannel->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer);
NS_ENSURE_SUCCESS(rv, rv);
} else if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
rv = nsContentUtils::SetFetchReferrerURIWithPolicy(aPrincipal,
aDoc,
aChannel,
policy);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// From "Determine request's Referrer" step 3
// "If request's referrer is a URL, let referrerSource be request's
// referrer."
nsCOMPtr<nsIURI> referrerURI;
rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
rv = aChannel->SetReferrerWithPolicy(referrerURI, policy);
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIURI> referrerURI;
aChannel->GetReferrer(getter_AddRefs(referrerURI));
// Step 8 https://fetch.spec.whatwg.org/#main-fetch
// If requests referrer is not "no-referrer", set requests referrer to
// the result of invoking determine requests referrer.
if (referrerURI) {
nsAutoCString spec;
rv = referrerURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
aRequest->SetReferrer(NS_ConvertUTF8toUTF16(spec));
} else {
aRequest->SetReferrer(EmptyString());
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla

View File

@ -8,9 +8,15 @@
#include "mozilla/dom/File.h"
#include "mozilla/dom/FormData.h"
class nsIPrincipal;
class nsIDocument;
class nsIHttpChannel;
namespace mozilla {
namespace dom {
class InternalRequest;
class FetchUtil final
{
private:
@ -35,6 +41,13 @@ public:
nsCString& aHeaderName,
nsCString& aHeaderValue,
bool* aWasEmptyHeader);
static nsresult
SetRequestReferrer(nsIPrincipal* aPrincipal,
nsIDocument* aDoc,
nsIHttpChannel* aChannel,
InternalRequest* aRequest);
};
} // namespace dom

View File

@ -233,6 +233,72 @@ public:
mReferrerPolicy = aReferrerPolicy;
}
void
SetReferrerPolicy(net::ReferrerPolicy aReferrerPolicy)
{
switch (aReferrerPolicy) {
case net::RP_Unset:
mReferrerPolicy = ReferrerPolicy::_empty;
break;
case net::RP_No_Referrer:
mReferrerPolicy = ReferrerPolicy::No_referrer;
break;
case net::RP_No_Referrer_When_Downgrade:
mReferrerPolicy = ReferrerPolicy::No_referrer_when_downgrade;
break;
case net::RP_Origin:
mReferrerPolicy = ReferrerPolicy::Origin;
break;
case net::RP_Origin_When_Crossorigin:
mReferrerPolicy = ReferrerPolicy::Origin_when_cross_origin;
break;
case net::RP_Unsafe_URL:
mReferrerPolicy = ReferrerPolicy::Unsafe_url;
break;
case net::RP_Same_Origin:
mReferrerPolicy = ReferrerPolicy::Same_origin;
break;
case net::RP_Strict_Origin:
mReferrerPolicy = ReferrerPolicy::Strict_origin;
break;
case net::RP_Strict_Origin_When_Cross_Origin:
mReferrerPolicy = ReferrerPolicy::Strict_origin_when_cross_origin;
break;
default:
MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value");
break;
}
}
net::ReferrerPolicy
GetReferrerPolicy()
{
switch (mReferrerPolicy) {
case ReferrerPolicy::_empty:
return net::RP_Unset;
case ReferrerPolicy::No_referrer:
return net::RP_No_Referrer;
case ReferrerPolicy::No_referrer_when_downgrade:
return net::RP_No_Referrer_When_Downgrade;
case ReferrerPolicy::Origin:
return net::RP_Origin;
case ReferrerPolicy::Origin_when_cross_origin:
return net::RP_Origin_When_Crossorigin;
case ReferrerPolicy::Unsafe_url:
return net::RP_Unsafe_URL;
case ReferrerPolicy::Strict_origin:
return net::RP_Strict_Origin;
case ReferrerPolicy::Same_origin:
return net::RP_Same_Origin;
case ReferrerPolicy::Strict_origin_when_cross_origin:
return net::RP_Strict_Origin_When_Cross_Origin;
default:
MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy enum value?");
break;
}
return net::RP_Unset;
}
net::ReferrerPolicy
GetEnvironmentReferrerPolicy() const
{

View File

@ -63,4 +63,8 @@ enum RequestMode { "same-origin", "no-cors", "cors", "navigate" };
enum RequestCredentials { "omit", "same-origin", "include" };
enum RequestCache { "default", "no-store", "reload", "no-cache", "force-cache", "only-if-cached" };
enum RequestRedirect { "follow", "error", "manual" };
enum ReferrerPolicy { "", "no-referrer", "no-referrer-when-downgrade", "origin", "origin-when-cross-origin", "unsafe-url" };
enum ReferrerPolicy {
"", "no-referrer", "no-referrer-when-downgrade", "origin",
"origin-when-cross-origin", "unsafe-url", "same-origin", "strict-origin",
"strict-origin-when-cross-origin"
};

View File

@ -205,8 +205,10 @@ ChannelFromScriptURL(nsIPrincipal* principal,
NS_ENSURE_SUCCESS(rv, rv);
if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel)) {
mozilla::net::ReferrerPolicy referrerPolicy = parentDoc ?
parentDoc->GetReferrerPolicy() : mozilla::net::RP_Default;
rv = nsContentUtils::SetFetchReferrerURIWithPolicy(principal, parentDoc,
httpChannel, mozilla::net::RP_Default);
httpChannel, referrerPolicy);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

View File

@ -1341,12 +1341,19 @@ public:
httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("Referer"), referrer);
if (!referrer.IsEmpty()) {
mReferrer = referrer;
} else {
// If there's no referrer Header, means the header was omitted for
// security/privacy reason.
mReferrer = EmptyCString();
}
uint32_t referrerPolicy = 0;
rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
NS_ENSURE_SUCCESS(rv, rv);
switch (referrerPolicy) {
case nsIHttpChannel::REFERRER_POLICY_UNSET:
mReferrerPolicy = ReferrerPolicy::_empty;
break;
case nsIHttpChannel::REFERRER_POLICY_NO_REFERRER:
mReferrerPolicy = ReferrerPolicy::No_referrer;
break;
@ -1362,6 +1369,15 @@ public:
case nsIHttpChannel::REFERRER_POLICY_UNSAFE_URL:
mReferrerPolicy = ReferrerPolicy::Unsafe_url;
break;
case nsIHttpChannel::REFERRER_POLICY_SAME_ORIGIN:
mReferrerPolicy = ReferrerPolicy::Same_origin;
break;
case nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN:
mReferrerPolicy = ReferrerPolicy::Strict_origin_when_cross_origin;
break;
case nsIHttpChannel::REFERRER_POLICY_STRICT_ORIGIN:
mReferrerPolicy = ReferrerPolicy::Strict_origin;
break;
default:
MOZ_ASSERT_UNREACHABLE("Invalid Referrer Policy enum value?");
break;

View File

@ -2541,9 +2541,10 @@ XMLHttpRequestMainThread::InitiateFetch(nsIInputStream* aUploadStream,
if (!IsSystemXHR()) {
nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
nsCOMPtr<nsIDocument> doc = owner ? owner->GetExtantDoc() : nullptr;
mozilla::net::ReferrerPolicy referrerPolicy = doc ?
doc->GetReferrerPolicy() : mozilla::net::RP_Default;
nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal, doc,
httpChannel,
mozilla::net::RP_Default);
httpChannel, referrerPolicy);
}
// Some extensions override the http protocol handler and provide their own

View File

@ -1288,7 +1288,7 @@ HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer,
if(NS_FAILED(rv)) {
return rv;
}
mReferrerPolicy = REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE;
mReferrerPolicy = referrerPolicy;
if (!referrer) {
return NS_OK;
@ -1296,7 +1296,6 @@ HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer,
// Don't send referrer at all when the meta referrer setting is "no-referrer"
if (referrerPolicy == REFERRER_POLICY_NO_REFERRER) {
mReferrerPolicy = REFERRER_POLICY_NO_REFERRER;
return NS_OK;
}
@ -1581,7 +1580,6 @@ HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer,
if (NS_FAILED(rv)) return rv;
mReferrer = clone;
mReferrerPolicy = referrerPolicy;
return NS_OK;
}

View File

@ -1682,6 +1682,11 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
LOG(("HttpChannelChild::OnRedirectVerifyCallback [this=%p]\n", this));
nsresult rv;
OptionalURIParams redirectURI;
uint32_t referrerPolicy = REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE;
OptionalURIParams referrerURI;
SerializeURI(nullptr, referrerURI);
nsCOMPtr<nsIHttpChannel> newHttpChannel =
do_QueryInterface(mRedirectChannelChild);
@ -1708,6 +1713,12 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
forceHSTSPriming = newLoadInfo->GetForceHSTSPriming();
mixedContentWouldBlock = newLoadInfo->GetMixedContentWouldBlock();
}
newHttpChannel->GetReferrerPolicy(&referrerPolicy);
nsCOMPtr<nsIURI> newChannelReferrerURI;
newHttpChannel->GetReferrer(getter_AddRefs(newChannelReferrerURI));
SerializeURI(newChannelReferrerURI, referrerURI);
}
if (mRedirectingForSubsequentSynthesizedResponse) {
@ -1778,9 +1789,9 @@ HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
}
if (mIPCOpen)
SendRedirect2Verify(result, *headerTuples, loadFlags, redirectURI,
corsPreflightArgs, forceHSTSPriming,
mixedContentWouldBlock, chooseAppcache);
SendRedirect2Verify(result, *headerTuples, loadFlags, referrerPolicy,
referrerURI, redirectURI, corsPreflightArgs,
forceHSTSPriming, mixedContentWouldBlock, chooseAppcache);
return NS_OK;
}
@ -2134,6 +2145,25 @@ HttpChannelChild::ContinueAsyncOpen()
// HttpChannelChild::nsIHttpChannel
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelChild::SetReferrerWithPolicy(nsIURI *referrer,
uint32_t referrerPolicy)
{
ENSURE_CALLED_BEFORE_CONNECT();
// remove old referrer if any, loop backwards
for (int i = mClientSetRequestHeaders.Length() - 1; i >= 0; --i) {
if (NS_LITERAL_CSTRING("Referer").Equals(mClientSetRequestHeaders[i].mHeader)) {
mClientSetRequestHeaders.RemoveElementAt(i);
}
}
nsresult rv = HttpBaseChannel::SetReferrerWithPolicy(referrer, referrerPolicy);
if (NS_FAILED(rv))
return rv;
return NS_OK;
}
NS_IMETHODIMP
HttpChannelChild::SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue,

View File

@ -78,6 +78,7 @@ public:
NS_IMETHOD AsyncOpen2(nsIStreamListener *aListener) override;
// HttpBaseChannel::nsIHttpChannel
NS_IMETHOD SetReferrerWithPolicy(nsIURI *referrer, uint32_t referrerPolicy) override;
NS_IMETHOD SetRequestHeader(const nsACString& aHeader,
const nsACString& aValue,
bool aMerge) override;

View File

@ -694,6 +694,8 @@ bool
HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
const RequestHeaderTuples& changedHeaders,
const uint32_t& loadFlags,
const uint32_t& referrerPolicy,
const OptionalURIParams& aReferrerURI,
const OptionalURIParams& aAPIRedirectURI,
const OptionalCorsPreflightArgs& aCorsPreflightArgs,
const bool& aForceHSTSPriming,
@ -745,6 +747,9 @@ HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
}
}
nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
newHttpChannel->SetReferrerWithPolicy(referrerUri, referrerPolicy);
nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
do_QueryInterface(newHttpChannel);
if (appCacheChannel) {

View File

@ -152,6 +152,8 @@ protected:
virtual bool RecvRedirect2Verify(const nsresult& result,
const RequestHeaderTuples& changedHeaders,
const uint32_t& loadFlags,
const uint32_t& referrerPolicy,
const OptionalURIParams& aReferrerURI,
const OptionalURIParams& apiRedirectUri,
const OptionalCorsPreflightArgs& aCorsPreflightArgs,
const bool& aForceHSTSPriming,

View File

@ -45,7 +45,9 @@ parent:
// Reports approval/veto of redirect by child process redirect observers
async Redirect2Verify(nsresult result, RequestHeaderTuples changedHeaders,
uint32_t loadFlags, OptionalURIParams apiRedirectTo,
uint32_t loadFlags, uint32_t referrerPolicy,
OptionalURIParams referrerUri,
OptionalURIParams apiRedirectTo,
OptionalCorsPreflightArgs corsPreflightArgs,
bool forceHSTSPriming, bool mixedContentWouldBlock,
bool chooseAppcache);