Skip to content
This repository has been archived by the owner on Aug 4, 2022. It is now read-only.

Commit

Permalink
Bug 1527287 - Add support for "noreferrer" feature argument to window…
Browse files Browse the repository at this point in the history
….open(); r=qdot

Differential Revision: https://phabricator.services.mozilla.com/D28396
  • Loading branch information
ehsan committed Apr 25, 2019
1 parent ee756e9 commit 151cd76
Show file tree
Hide file tree
Showing 23 changed files with 131 additions and 71 deletions.
9 changes: 7 additions & 2 deletions browser/base/content/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -5749,8 +5749,13 @@ nsBrowserAccess.prototype = {
aWhere = Services.prefs.getIntPref("browser.link.open_newwindow");
}

let referrerInfo = new ReferrerInfo(Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true,
aOpener ? makeURI(aOpener.location.href) : null);
let referrerInfo;
if (aFlags & Ci.nsIBrowserDOMWindow.OPEN_NO_REFERRER) {
referrerInfo = new ReferrerInfo(Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, false, null);
} else {
referrerInfo = new ReferrerInfo(Ci.nsIHttpChannel.REFERRER_POLICY_UNSET, true,
aOpener ? makeURI(aOpener.location.href) : null);
}
if (aOpener && aOpener.document) {
referrerInfo.referrerPolicy = aOpener.document.referrerPolicy;
}
Expand Down
7 changes: 5 additions & 2 deletions devtools/client/responsive.html/browser/tunnel.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,16 @@ function tunnelToInnerBrowser(outer, inner) {
const { detail } = event;
event.preventDefault();
const uri = Services.io.newURI(detail.url);
let flags = Ci.nsIBrowserDOMWindow.OPEN_NEWTAB;
if (detail.forceNoReferrer) {
flags |= Ci.nsIBrowserDOMWindow.OPEN_NO_REFERRER;
}
// This API is used mainly because it's near the path used for <a target/> with
// regular browser tabs (which calls `openURIInFrame`). The more elaborate APIs
// that support openers, window features, etc. didn't seem callable from JS and / or
// this event doesn't give enough info to use them.
browserWindow.browserDOMWindow
.openURI(uri, null, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
Ci.nsIBrowserDOMWindow.OPEN_NEW,
.openURI(uri, null, flags, Ci.nsIBrowserDOMWindow.OPEN_NEW,
outer.contentPrincipal);
},

Expand Down
12 changes: 10 additions & 2 deletions dom/base/nsGlobalWindowOuter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7071,6 +7071,7 @@ nsresult nsGlobalWindowOuter::OpenInternal(

nsAutoCString options;
bool forceNoOpener = aForceNoOpener;
bool forceNoReferrer = false;
// Unlike other window flags, "noopener" comes from splitting on commas with
// HTML whitespace trimming...
nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(
Expand All @@ -7081,6 +7082,13 @@ nsresult nsGlobalWindowOuter::OpenInternal(
forceNoOpener = true;
continue;
}
if (StaticPrefs::dom_window_open_noreferrer_enabled() &&
nextTok.LowerCaseEqualsLiteral("noreferrer")) {
forceNoReferrer = true;
// noreferrer implies noopener
forceNoOpener = true;
continue;
}
// Want to create a copy of the options without 'noopener' because having
// 'noopener' in the options affects other window features.
if (!options.IsEmpty()) {
Expand Down Expand Up @@ -7186,7 +7194,7 @@ nsresult nsGlobalWindowOuter::OpenInternal(
rv = pwwatch->OpenWindow2(
this, url.IsVoid() ? nullptr : url.get(), name_ptr, options_ptr,
/* aCalledFromScript = */ true, aDialog, aNavigate, argv,
isPopupSpamWindow, forceNoOpener, aLoadState,
isPopupSpamWindow, forceNoOpener, forceNoReferrer, aLoadState,
getter_AddRefs(domReturn));
} else {
// Force a system caller here so that the window watcher won't screw us
Expand All @@ -7206,7 +7214,7 @@ nsresult nsGlobalWindowOuter::OpenInternal(
rv = pwwatch->OpenWindow2(
this, url.IsVoid() ? nullptr : url.get(), name_ptr, options_ptr,
/* aCalledFromScript = */ false, aDialog, aNavigate, aExtraArgument,
isPopupSpamWindow, forceNoOpener, aLoadState,
isPopupSpamWindow, forceNoOpener, forceNoReferrer, aLoadState,
getter_AddRefs(domReturn));
}
}
Expand Down
12 changes: 8 additions & 4 deletions dom/browser-element/BrowserElementParent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ BrowserElementParent::DispatchOpenWindowEvent(Element* aOpenerFrameElement,
Element* aPopupFrameElement,
const nsAString& aURL,
const nsAString& aName,
bool aForceNoReferrer,
const nsAString& aFeatures) {
// Dispatch a CustomEvent at aOpenerFrameElement with a detail object
// (OpenWindowEventDetail) containing aPopupFrameElement, aURL, aName, and
Expand All @@ -130,6 +131,7 @@ BrowserElementParent::DispatchOpenWindowEvent(Element* aOpenerFrameElement,
detail.mName = aName;
detail.mFeatures = aFeatures;
detail.mFrameElement = aPopupFrameElement;
detail.mForceNoReferrer = aForceNoReferrer;

nsIGlobalObject* sgo = aPopupFrameElement->OwnerDoc()->GetScopeObject();
if (!sgo) {
Expand Down Expand Up @@ -173,7 +175,8 @@ BrowserElementParent::DispatchOpenWindowEvent(Element* aOpenerFrameElement,
/*static*/
BrowserElementParent::OpenWindowResult BrowserElementParent::OpenWindowOOP(
BrowserParent* aOpenerBrowserParent, BrowserParent* aPopupBrowserParent,
const nsAString& aURL, const nsAString& aName, const nsAString& aFeatures) {
const nsAString& aURL, const nsAString& aName, bool aForceNoReferrer,
const nsAString& aFeatures) {
// Create an iframe owned by the same document which owns openerFrameElement.
nsCOMPtr<Element> openerFrameElement =
aOpenerBrowserParent->GetOwnerElement();
Expand All @@ -193,8 +196,9 @@ BrowserElementParent::OpenWindowResult BrowserElementParent::OpenWindowOOP(
// allowed.
popupFrameElement->DisallowCreateFrameLoader();

OpenWindowResult opened = DispatchOpenWindowEvent(
openerFrameElement, popupFrameElement, aURL, aName, aFeatures);
OpenWindowResult opened =
DispatchOpenWindowEvent(openerFrameElement, popupFrameElement, aURL,
aName, aForceNoReferrer, aFeatures);

if (opened != BrowserElementParent::OPEN_WINDOW_ADDED) {
return opened;
Expand Down Expand Up @@ -250,7 +254,7 @@ BrowserElementParent::OpenWindowInProcess(BrowsingContext* aOpenerWindow,

OpenWindowResult opened = DispatchOpenWindowEvent(
openerFrameElement, popupFrameElement, NS_ConvertUTF8toUTF16(spec), aName,
NS_ConvertUTF8toUTF16(aFeatures));
false, NS_ConvertUTF8toUTF16(aFeatures));

if (opened != BrowserElementParent::OPEN_WINDOW_ADDED) {
return opened;
Expand Down
5 changes: 3 additions & 2 deletions dom/browser-element/BrowserElementParent.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ class BrowserElementParent {
static OpenWindowResult OpenWindowOOP(
dom::BrowserParent* aOpenerBrowserParent,
dom::BrowserParent* aPopupBrowserParent, const nsAString& aURL,
const nsAString& aName, const nsAString& aFeatures);
const nsAString& aName, bool aForceNoReferrer,
const nsAString& aFeatures);

/**
* Handle a window.open call from an in-process <iframe mozbrowser>.
Expand All @@ -111,7 +112,7 @@ class BrowserElementParent {
private:
static OpenWindowResult DispatchOpenWindowEvent(
dom::Element* aOpenerFrameElement, dom::Element* aPopupFrameElement,
const nsAString& aURL, const nsAString& aName,
const nsAString& aURL, const nsAString& aName, bool aForceNoReferrer,
const nsAString& aFeatures);
};

Expand Down
1 change: 1 addition & 0 deletions dom/clients/manager/ClientOpenWindowUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ nsresult OpenWindow(const ClientOpenWindowArgs& aArgs,
// opener anyway, and we _do_ want the returned
// window.
/* aForceNoOpener = */ false,
/* aForceNoReferrer = */ false,
/* aLoadInfp = */ nullptr, getter_AddRefs(newWindow));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
Expand Down
6 changes: 6 additions & 0 deletions dom/interfaces/base/nsIBrowserDOMWindow.idl
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ interface nsIBrowserDOMWindow : nsISupports
*/
const long OPEN_NO_OPENER = 0x4;

/**
* Don't set the referrer on the navigation inside the window which is
* being opened.
*/
const long OPEN_NO_REFERRER = 0x8;

/**
* Create the content window for the given URI.

Expand Down
6 changes: 3 additions & 3 deletions dom/ipc/BrowserChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,7 @@ BrowserChild::ProvideWindow(mozIDOMWindowProxy* aParent, uint32_t aChromeFlags,
bool aCalledFromJS, bool aPositionSpecified,
bool aSizeSpecified, nsIURI* aURI,
const nsAString& aName, const nsACString& aFeatures,
bool aForceNoOpener,
bool aForceNoOpener, bool aForceNoReferrer,
nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
mozIDOMWindowProxy** aReturn) {
*aReturn = nullptr;
Expand Down Expand Up @@ -943,8 +943,8 @@ BrowserChild::ProvideWindow(mozIDOMWindowProxy* aParent, uint32_t aChromeFlags,
ContentChild* cc = ContentChild::GetSingleton();
return cc->ProvideWindowCommon(
this, aParent, iframeMoz, aChromeFlags, aCalledFromJS, aPositionSpecified,
aSizeSpecified, aURI, aName, aFeatures, aForceNoOpener, aLoadState,
aWindowIsNew, aReturn);
aSizeSpecified, aURI, aName, aFeatures, aForceNoOpener, aForceNoReferrer,
aLoadState, aWindowIsNew, aReturn);
}

void BrowserChild::DestroyWindow() {
Expand Down
6 changes: 4 additions & 2 deletions dom/ipc/BrowserParent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2883,14 +2883,16 @@ void BrowserParent::ApzAwareEventRoutingToChild(

mozilla::ipc::IPCResult BrowserParent::RecvBrowserFrameOpenWindow(
PBrowserParent* aOpener, const nsString& aURL, const nsString& aName,
const nsString& aFeatures, BrowserFrameOpenWindowResolver&& aResolve) {
bool aForceNoReferrer, const nsString& aFeatures,
BrowserFrameOpenWindowResolver&& aResolve) {
CreatedWindowInfo cwi;
cwi.rv() = NS_OK;
cwi.maxTouchPoints() = 0;

BrowserElementParent::OpenWindowResult opened =
BrowserElementParent::OpenWindowOOP(BrowserParent::GetFrom(aOpener), this,
aURL, aName, aFeatures);
aURL, aName, aForceNoReferrer,
aFeatures);
cwi.windowOpened() = (opened == BrowserElementParent::OPEN_WINDOW_ADDED);
nsCOMPtr<nsIWidget> widget = GetWidget();
if (widget) {
Expand Down
3 changes: 2 additions & 1 deletion dom/ipc/BrowserParent.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ class BrowserParent final : public PBrowserParent,

mozilla::ipc::IPCResult RecvBrowserFrameOpenWindow(
PBrowserParent* aOpener, const nsString& aURL, const nsString& aName,
const nsString& aFeatures, BrowserFrameOpenWindowResolver&& aResolve);
bool aForceNoReferrer, const nsString& aFeatures,
BrowserFrameOpenWindowResolver&& aResolve);

mozilla::ipc::IPCResult RecvSyncMessage(
const nsString& aMessage, const ClonedMessageData& aData,
Expand Down
40 changes: 23 additions & 17 deletions dom/ipc/ContentChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,18 +754,18 @@ ContentChild::ProvideWindow(mozIDOMWindowProxy* aParent, uint32_t aChromeFlags,
bool aCalledFromJS, bool aPositionSpecified,
bool aSizeSpecified, nsIURI* aURI,
const nsAString& aName, const nsACString& aFeatures,
bool aForceNoOpener,
bool aForceNoOpener, bool aForceNoReferrer,
nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
mozIDOMWindowProxy** aReturn) {
return ProvideWindowCommon(nullptr, aParent, false, aChromeFlags,
aCalledFromJS, aPositionSpecified, aSizeSpecified,
aURI, aName, aFeatures, aForceNoOpener, aLoadState,
aWindowIsNew, aReturn);
return ProvideWindowCommon(
nullptr, aParent, false, aChromeFlags, aCalledFromJS, aPositionSpecified,
aSizeSpecified, aURI, aName, aFeatures, aForceNoOpener, aForceNoReferrer,
aLoadState, aWindowIsNew, aReturn);
}

static nsresult GetCreateWindowParams(mozIDOMWindowProxy* aParent,
nsDocShellLoadState* aLoadState,
float* aFullZoom,
bool aForceNoReferrer, float* aFullZoom,
nsIReferrerInfo** aReferrerInfo,
nsIPrincipal** aTriggeringPrincipal,
nsIContentSecurityPolicy** aCsp) {
Expand All @@ -781,7 +781,11 @@ static nsresult GetCreateWindowParams(mozIDOMWindowProxy* aParent,
}

nsCOMPtr<nsIReferrerInfo> referrerInfo;
if (aLoadState) {
if (aForceNoReferrer) {
referrerInfo = new ReferrerInfo(
nullptr, mozilla::net::ReferrerPolicy::RP_Unset, false);
}
if (aLoadState && !referrerInfo) {
referrerInfo = aLoadState->GetReferrerInfo();
}

Expand Down Expand Up @@ -842,7 +846,7 @@ nsresult ContentChild::ProvideWindowCommon(
BrowserChild* aTabOpener, mozIDOMWindowProxy* aParent, bool aIframeMoz,
uint32_t aChromeFlags, bool aCalledFromJS, bool aPositionSpecified,
bool aSizeSpecified, nsIURI* aURI, const nsAString& aName,
const nsACString& aFeatures, bool aForceNoOpener,
const nsACString& aFeatures, bool aForceNoOpener, bool aForceNoReferrer,
nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
mozIDOMWindowProxy** aReturn) {
*aReturn = nullptr;
Expand Down Expand Up @@ -888,9 +892,10 @@ nsresult ContentChild::ProvideWindowCommon(
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
nsCOMPtr<nsIContentSecurityPolicy> csp;
nsCOMPtr<nsIReferrerInfo> referrerInfo;
rv = GetCreateWindowParams(
aParent, aLoadState, &fullZoom, getter_AddRefs(referrerInfo),
getter_AddRefs(triggeringPrincipal), getter_AddRefs(csp));
rv = GetCreateWindowParams(aParent, aLoadState, aForceNoReferrer, &fullZoom,
getter_AddRefs(referrerInfo),
getter_AddRefs(triggeringPrincipal),
getter_AddRefs(csp));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
Expand Down Expand Up @@ -1106,17 +1111,18 @@ nsresult ContentChild::ProvideWindowCommon(

// NOTE: BrowserFrameOpenWindowPromise is the same type as
// CreateWindowPromise, and this code depends on that fact.
newChild->SendBrowserFrameOpenWindow(aTabOpener, NS_ConvertUTF8toUTF16(url),
name, NS_ConvertUTF8toUTF16(features),
std::move(resolve), std::move(reject));
newChild->SendBrowserFrameOpenWindow(
aTabOpener, NS_ConvertUTF8toUTF16(url), name, aForceNoReferrer,
NS_ConvertUTF8toUTF16(features), std::move(resolve), std::move(reject));
} else {
float fullZoom;
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
nsCOMPtr<nsIContentSecurityPolicy> csp;
nsCOMPtr<nsIReferrerInfo> referrerInfo;
rv = GetCreateWindowParams(
aParent, aLoadState, &fullZoom, getter_AddRefs(referrerInfo),
getter_AddRefs(triggeringPrincipal), getter_AddRefs(csp));
rv = GetCreateWindowParams(aParent, aLoadState, aForceNoReferrer, &fullZoom,
getter_AddRefs(referrerInfo),
getter_AddRefs(triggeringPrincipal),
getter_AddRefs(csp));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
Expand Down
16 changes: 7 additions & 9 deletions dom/ipc/ContentChild.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,13 @@ class ContentChild final : public PContentChild,
nsCString sourceURL;
};

nsresult ProvideWindowCommon(BrowserChild* aTabOpener,
mozIDOMWindowProxy* aOpener, bool aIframeMoz,
uint32_t aChromeFlags, bool aCalledFromJS,
bool aPositionSpecified, bool aSizeSpecified,
nsIURI* aURI, const nsAString& aName,
const nsACString& aFeatures, bool aForceNoOpener,
nsDocShellLoadState* aLoadState,
bool* aWindowIsNew,
mozIDOMWindowProxy** aReturn);
nsresult ProvideWindowCommon(
BrowserChild* aTabOpener, mozIDOMWindowProxy* aParent, bool aIframeMoz,
uint32_t aChromeFlags, bool aCalledFromJS, bool aPositionSpecified,
bool aSizeSpecified, nsIURI* aURI, const nsAString& aName,
const nsACString& aFeatures, bool aForceNoOpener, bool aForceNoReferrer,
nsDocShellLoadState* aLoadState, bool* aWindowIsNew,
mozIDOMWindowProxy** aReturn);

bool Init(MessageLoop* aIOLoop, base::ProcessId aParentPid,
const char* aParentBuildID, IPC::Channel* aChannel,
Expand Down
3 changes: 2 additions & 1 deletion dom/ipc/PBrowser.ipdl
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,8 @@ parent:
* @param opener the PBrowser whose content called window.open.
*/
async BrowserFrameOpenWindow(PBrowser opener,
nsString aURL, nsString aName, nsString aFeatures)
nsString aURL, nsString aName,
bool aForceNoReferrer, nsString aFeatures)
returns (CreatedWindowInfo window);

/**
Expand Down
8 changes: 6 additions & 2 deletions dom/tests/browser/browser_noopener.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ const TESTS = [

{id: "#test7", name: "", opener: true, newWindow: false},
{id: "#test8", name: "", opener: false, newWindow: false},
{id: "#test9", name: "", opener: true, newWindow: true},
{id: "#test9", name: "", opener: false, newWindow: false},

{id: "#test10", name: "uniquename1", opener: true, newWindow: false},
{id: "#test11", name: "uniquename2", opener: false, newWindow: false},
{id: "#test12", name: "uniquename3", opener: true, newWindow: true},
{id: "#test12", name: "uniquename3", opener: false, newWindow: false},
];

const TEST_URL = "http://mochi.test:8888/browser/dom/tests/browser/test_noopener_source.html";
Expand Down Expand Up @@ -99,6 +99,10 @@ async function doAllTests() {
// constant starting and stopping processes, and opens a new window ~144 times.
requestLongerTimeout(25);

add_task(async function prepare() {
await SpecialPowers.pushPrefEnv({set: [["dom.window.open.noreferrer.enabled", true]]});
});

add_task(async function newtab_sameproc() {
await SpecialPowers.pushPrefEnv({set: [[OPEN_NEWWINDOW_PREF, OPEN_NEWTAB],
[NOOPENER_NEWPROC_PREF, false]]});
Expand Down
1 change: 1 addition & 0 deletions dom/webidl/BrowserElementDictionaries.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dictionary OpenWindowEventDetail {
DOMString name = "";
DOMString features = "";
Node? frameElement = null;
boolean forceNoReferrer = false;
};

dictionary DOMWindowResizeEventDetail {
Expand Down
3 changes: 2 additions & 1 deletion mobile/android/chrome/content/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -3412,10 +3412,11 @@ nsBrowserAccess.prototype = {
Services.io.offline = false;

let referrer;
let forceNoReferrer = !!(aFlags & Ci.nsIBrowserDOMWindow.OPEN_NO_REFERRER);
if (aOpener) {
try {
let location = aOpener.location;
referrer = Services.io.newURI(location);
referrer = forceNoReferrer ? null : Services.io.newURI(location);
} catch(e) { }
}

Expand Down
8 changes: 8 additions & 0 deletions modules/libpref/init/StaticPrefList.h
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,14 @@ VARCACHE_PREF(
bool, true
)

// Enable the "noreferrer" feature argument for window.open()
VARCACHE_PREF(
"dom.window.open.noreferrer.enabled",
dom_window_open_noreferrer_enabled,
bool, true
)


//---------------------------------------------------------------------------
// Extension prefs
//---------------------------------------------------------------------------
Expand Down

This file was deleted.

Loading

0 comments on commit 151cd76

Please sign in to comment.