Bug 1169044 - Patch 1 - Refactor setting referrer and referrer policy between fetch and XHR. r=khuey

--HG--
extra : rebase_source : 8b004536dab18706ae4b8c3f0c574f8769c05638
This commit is contained in:
Nikhil Marathe 2015-06-04 14:05:00 -07:00
Родитель 0c45c2cb42
Коммит bd1323708a
6 изменённых файлов: 121 добавлений и 112 удалений

Просмотреть файл

@ -7862,3 +7862,54 @@ nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType)
return aType;
}
}
nsresult
nsContentUtils::SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal,
nsIDocument* aDoc,
nsIHttpChannel* aChannel)
{
NS_ENSURE_ARG_POINTER(aPrincipal);
NS_ENSURE_ARG_POINTER(aChannel);
nsCOMPtr<nsIURI> principalURI;
if (IsSystemPrincipal(aPrincipal)) {
return NS_OK;
}
aPrincipal->GetURI(getter_AddRefs(principalURI));
if (!aDoc) {
return aChannel->SetReferrerWithPolicy(principalURI, net::RP_Default);
}
// If it weren't for history.push/replaceState, we could just use the
// principal's URI here. But since we want changes to the URI effected
// by push/replaceState to be reflected in the XHR referrer, we have to
// be more clever.
//
// If the document's original URI (before any push/replaceStates) matches
// our principal, then we use the document's current URI (after
// push/replaceStates). Otherwise (if the document is, say, a data:
// URI), we just use the principal's URI.
nsCOMPtr<nsIURI> docCurURI = aDoc->GetDocumentURI();
nsCOMPtr<nsIURI> docOrigURI = aDoc->GetOriginalURI();
nsCOMPtr<nsIURI> referrerURI;
if (principalURI && docCurURI && docOrigURI) {
bool equal = false;
principalURI->Equals(docOrigURI, &equal);
if (equal) {
referrerURI = docCurURI;
}
}
if (!referrerURI) {
referrerURI = principalURI;
}
net::ReferrerPolicy referrerPolicy = aDoc->GetReferrerPolicy();
return aChannel->SetReferrerWithPolicy(referrerURI, referrerPolicy);
}

Просмотреть файл

@ -2406,6 +2406,25 @@ public:
static already_AddRefed<nsPIWindowRoot> GetWindowRoot(nsIDocument* aDoc);
/*
* Implements step 3.1 and 3.3 of the Determine request's Referrer algorithm
* from the Referrer Policy specification.
*
* The referrer policy of the document is applied by Necko when using
* channels.
*
* For documents representing an iframe srcdoc attribute, the document sets
* its own URI correctly, so this method simply uses the document's original
* or current URI as appropriate.
*
* aDoc may be null.
*
* https://w3c.github.io/webappsec/specs/referrer-policy/#determine-requests-referrer
*/
static nsresult SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal,
nsIDocument* aDoc,
nsIHttpChannel* aChannel);
private:
static bool InitializeEventTable();

Просмотреть файл

@ -2682,50 +2682,10 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable<RequestBody>& aBody)
httpChannel->GetRequestMethod(method); // If GET, method name will be uppercase
if (!IsSystemXHR()) {
// Get the referrer for the request.
//
// If it weren't for history.push/replaceState, we could just use the
// principal's URI here. But since we want changes to the URI effected
// by push/replaceState to be reflected in the XHR referrer, we have to
// be more clever.
//
// If the document's original URI (before any push/replaceStates) matches
// our principal, then we use the document's current URI (after
// push/replaceStates). Otherwise (if the document is, say, a data:
// URI), we just use the principal's URI.
nsCOMPtr<nsIURI> principalURI;
mPrincipal->GetURI(getter_AddRefs(principalURI));
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc =
nsContentUtils::GetDocumentFromScriptContext(sc);
nsCOMPtr<nsIURI> docCurURI;
nsCOMPtr<nsIURI> docOrigURI;
net::ReferrerPolicy referrerPolicy = net::RP_Default;
if (doc) {
docCurURI = doc->GetDocumentURI();
docOrigURI = doc->GetOriginalURI();
referrerPolicy = doc->GetReferrerPolicy();
}
nsCOMPtr<nsIURI> referrerURI;
if (principalURI && docCurURI && docOrigURI) {
bool equal = false;
principalURI->Equals(docOrigURI, &equal);
if (equal) {
referrerURI = docCurURI;
}
}
if (!referrerURI)
referrerURI = principalURI;
httpChannel->SetReferrerWithPolicy(referrerURI, referrerPolicy);
nsCOMPtr<nsPIDOMWindow> owner = GetOwner();
nsCOMPtr<nsIDocument> doc = owner ? owner->GetExtantDoc() : nullptr;
nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal, doc,
httpChannel);
}
// Some extensions override the http protocol handler and provide their own

Просмотреть файл

@ -217,11 +217,6 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
nsRefPtr<InternalRequest> r = request->GetInternalRequest();
aRv = UpdateRequestReferrer(aGlobal, r);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal);
nsCOMPtr<nsIDocument> doc;
@ -398,58 +393,6 @@ WorkerFetchResolver::OnResponseEnd()
}
}
// This method sets the request's referrerURL, as specified by the "determine
// request's referrer" steps from Referrer Policy [1].
// The actual referrer policy and stripping is dealt with by HttpBaseChannel,
// this always sets the full API referrer URL of the relevant global if it is
// not already a url or no-referrer.
// [1]: https://w3c.github.io/webappsec/specs/referrer-policy/#determine-requests-referrer
nsresult
UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest)
{
nsAutoString originalReferrer;
aRequest->GetReferrer(originalReferrer);
// If it is no-referrer ("") or a URL, don't modify.
if (!originalReferrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
return NS_OK;
}
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal);
if (window) {
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
if (doc) {
nsAutoString referrer;
doc->GetReferrer(referrer);
aRequest->SetReferrer(referrer);
}
} else if (NS_IsMainThread()) {
// Pull the principal from the global for non-worker scripts.
nsIPrincipal *principal = aGlobal->PrincipalOrNull();
bool isNull;
// Only set the referrer if the principal is present,
// and the principal is not null or the system principal.
if (principal &&
NS_SUCCEEDED(principal->GetIsNullPrincipal(&isNull)) && !isNull &&
!nsContentUtils::IsSystemPrincipal(principal)) {
nsCOMPtr<nsIURI> uri;
if (NS_SUCCEEDED(principal->GetURI(getter_AddRefs(uri))) && uri) {
nsAutoCString referrer;
if (NS_SUCCEEDED(uri->GetSpec(referrer))) {
aRequest->SetReferrer(NS_ConvertUTF8toUTF16(referrer));
}
}
}
} else {
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
WorkerPrivate::LocationInfo& info = worker->GetLocationInfo();
aRequest->SetReferrer(NS_ConvertUTF8toUTF16(info.mHref));
}
return NS_OK;
}
namespace {
nsresult
ExtractFromArrayBuffer(const ArrayBuffer& aBuffer,

Просмотреть файл

@ -416,21 +416,37 @@ FetchDriver::HttpFetch(bool aCORSFlag, bool aCORSPreflightFlag, bool aAuthentica
// Step 2. Set the referrer.
nsAutoString referrer;
mRequest->GetReferrer(referrer);
// The referrer should have already been resolved to a URL by the caller.
MOZ_ASSERT(!referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR));
if (!referrer.IsEmpty()) {
nsCOMPtr<nsIURI> refURI;
rv = NS_NewURI(getter_AddRefs(refURI), referrer, nullptr, nullptr);
if (referrer.EqualsLiteral(kFETCH_CLIENT_REFERRER_STR)) {
rv = nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal,
mDocument,
httpChan);
if (NS_WARN_IF(NS_FAILED(rv))) {
return FailWithNetworkError();
}
} else if (referrer.IsEmpty()) {
rv = httpChan->SetReferrerWithPolicy(nullptr, net::RP_No_Referrer);
if (NS_WARN_IF(NS_FAILED(rv))) {
return FailWithNetworkError();
}
} else {
// From "Determine request's Referrer" step 3
// "If request's referrer is a URL, let referrerSource be request's
// referrer."
//
// This allows ServiceWorkers to function transparently when the referrer
// of the intercepted request is already set.
nsCOMPtr<nsIURI> referrerURI;
rv = NS_NewURI(getter_AddRefs(referrerURI), referrer, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return FailWithNetworkError();
}
net::ReferrerPolicy referrerPolicy = net::RP_Default;
if (mDocument) {
referrerPolicy = mDocument->GetReferrerPolicy();
}
rv = httpChan->SetReferrerWithPolicy(refURI, referrerPolicy);
// FIXME(nsm): Can we assert that this case can only happen in
// ServiceWorkers and assume null mDocument?
rv =
httpChan->SetReferrerWithPolicy(nullptr,
mDocument ? mDocument->GetReferrerPolicy() :
net::RP_Default);
if (NS_WARN_IF(NS_FAILED(rv))) {
return FailWithNetworkError();
}

Просмотреть файл

@ -1250,6 +1250,25 @@ function testRedirects() {
return Promise.all(fetches);
}
function testReferrer() {
var referrer;
if (self && self.location) {
referrer = self.location.href;
} else {
referrer = document.documentURI;
}
var dict = {
'Referer': referrer
};
return fetch(corsServerPath + "headers=" + dict.toSource()).then(function(res) {
is(res.status, 200, "expected correct referrer header to be sent");
dump(res.statusText);
}, function(e) {
ok(false, "expected correct referrer header to be sent");
});
}
function runTest() {
testNoCorsCtor();
@ -1260,5 +1279,6 @@ function runTest() {
.then(testSameOriginCredentials)
.then(testCrossOriginCredentials)
.then(testRedirects)
.then(testReferrer)
// Put more promise based tests here.
}