Bug 1314249 - if the target changes, assume we should not pass an opener ref, r=smaug
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Wed, 16 Nov 2016 16:31:42 +0000
changeset 324176 1bdd86bd35301cfd741d642cdac1249a749dd999
parent 324175 e13ca676d63607f1a19a73c77b7331253d0e2ba8
child 324177 be48744b160459666cbf97f065a97cdad695092f
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewerssmaug
bugs1314249
milestone53.0a1
Bug 1314249 - if the target changes, assume we should not pass an opener ref, r=smaug MozReview-Commit-ID: 7DBrRW1WiMP
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_bug1064280_changeUrlInPinnedTab.js
browser/base/content/test/tabs/browser.ini
browser/base/content/test/tabs/browser_navigatePinnedTab.js
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsILinkHandler.h
dom/html/HTMLFormElement.cpp
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -267,17 +267,16 @@ tags = mcb
 tags = mcb
 [browser_mixedContentFromOnunload.js]
 tags = mcb
 [browser_mixedContentFramesOnHttp.js]
 tags = mcb
 [browser_bug970746.js]
 [browser_bug1015721.js]
 skip-if = os == 'win'
-[browser_bug1064280_changeUrlInPinnedTab.js]
 [browser_accesskeys.js]
 [browser_clipboard.js]
 subsuite = clipboard
 [browser_clipboard_pastefile.js]
 skip-if = true # Disabled due to the clipboard not supporting real file types yet (bug 1288773)
 [browser_contentAreaClick.js]
 skip-if = e10s # Clicks in content don't go through contentAreaClick with e10s.
 [browser_contentAltClick.js]
--- a/browser/base/content/test/tabs/browser.ini
+++ b/browser/base/content/test/tabs/browser.ini
@@ -1,4 +1,5 @@
 [browser_tabSpinnerProbe.js]
 skip-if = !e10s # Tab spinner is e10s only.
 [browser_tabSwitchPrintPreview.js]
 skip-if = os == 'mac'
+[browser_navigatePinnedTab.js]
rename from browser/base/content/test/general/browser_bug1064280_changeUrlInPinnedTab.js
rename to browser/base/content/test/tabs/browser_navigatePinnedTab.js
--- a/browser/base/content/test/general/browser_bug1064280_changeUrlInPinnedTab.js
+++ b/browser/base/content/test/tabs/browser_navigatePinnedTab.js
@@ -24,13 +24,36 @@ add_task(function* () {
   gURLBar.value = TEST_LINK_CHANGED;
 
   goButton.click();
   yield BrowserTestUtils.browserLoaded(browser);
 
   is(appTab.linkedBrowser.currentURI.spec, TEST_LINK_CHANGED,
      "New page loaded in the app tab");
   is(gBrowser.tabs.length, initialTabsNo, "No additional tabs were opened");
+
+  // Now check that opening a link that does create a new tab works,
+  // and also that it nulls out the opener.
+  let pageLoadPromise = BrowserTestUtils.browserLoaded(appTab.linkedBrowser, "http://example.com/");
+  yield BrowserTestUtils.loadURI(appTab.linkedBrowser, "http://example.com/");
+  info("Started loading example.com");
+  yield pageLoadPromise;
+  info("Loaded example.com");
+  let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "http://example.org/");
+  yield ContentTask.spawn(browser, null, function* () {
+    let link = content.document.createElement("a");
+    link.href = "http://example.org/";
+    content.document.body.appendChild(link);
+    link.click();
+  });
+  info("Created & clicked link");
+  let extraTab = yield newTabPromise;
+  info("Got a new tab");
+  yield ContentTask.spawn(extraTab.linkedBrowser, null, function* () {
+    is(content.opener, null, "No opener should be available");
+  });
+  yield BrowserTestUtils.removeTab(extraTab);
 });
 
+
 registerCleanupFunction(function() {
   gBrowser.removeTab(gBrowser.selectedTab);
 });
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -13780,65 +13780,70 @@ class OnLinkClickEvent : public Runnable
 {
 public:
   OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
                    nsIURI* aURI,
                    const char16_t* aTargetSpec,
                    const nsAString& aFileName,
                    nsIInputStream* aPostDataStream,
                    nsIInputStream* aHeadersDataStream,
+                   bool aNoOpenerImplied,
                    bool aIsTrusted);
 
   NS_IMETHOD Run() override
   {
     nsAutoPopupStatePusher popupStatePusher(mPopupState);
 
     // We need to set up an AutoJSAPI here for the following reason: When we do
     // OnLinkClickSync we'll eventually end up in nsGlobalWindow::OpenInternal
     // which only does popup blocking if !LegacyIsCallerChromeOrNativeCode().
     // So we need to fake things so that we don't look like native code as far
     // as LegacyIsCallerNativeCode() is concerned.
     AutoJSAPI jsapi;
     if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) {
       mHandler->OnLinkClickSync(mContent, mURI,
                                 mTargetSpec.get(), mFileName,
                                 mPostDataStream, mHeadersDataStream,
+                                mNoOpenerImplied,
                                 nullptr, nullptr);
     }
     return NS_OK;
   }
 
 private:
   RefPtr<nsDocShell> mHandler;
   nsCOMPtr<nsIURI> mURI;
   nsString mTargetSpec;
   nsString mFileName;
   nsCOMPtr<nsIInputStream> mPostDataStream;
   nsCOMPtr<nsIInputStream> mHeadersDataStream;
   nsCOMPtr<nsIContent> mContent;
   PopupControlState mPopupState;
+  bool mNoOpenerImplied;
   bool mIsTrusted;
 };
 
 OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
                                    nsIContent* aContent,
                                    nsIURI* aURI,
                                    const char16_t* aTargetSpec,
                                    const nsAString& aFileName,
                                    nsIInputStream* aPostDataStream,
                                    nsIInputStream* aHeadersDataStream,
+                                   bool aNoOpenerImplied,
                                    bool aIsTrusted)
   : mHandler(aHandler)
   , mURI(aURI)
   , mTargetSpec(aTargetSpec)
   , mFileName(aFileName)
   , mPostDataStream(aPostDataStream)
   , mHeadersDataStream(aHeadersDataStream)
   , mContent(aContent)
   , mPopupState(mHandler->mScriptGlobal->GetPopupControlState())
+  , mNoOpenerImplied(aNoOpenerImplied)
   , mIsTrusted(aIsTrusted)
 {
 }
 
 NS_IMETHODIMP
 nsDocShell::OnLinkClick(nsIContent* aContent,
                         nsIURI* aURI,
                         const char16_t* aTargetSpec,
@@ -13866,40 +13871,46 @@ nsDocShell::OnLinkClick(nsIContent* aCon
   if (aContent->IsEditable()) {
     return NS_OK;
   }
 
   nsresult rv = NS_ERROR_FAILURE;
   nsAutoString target;
 
   nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
+  bool noOpenerImplied = false;
   if (browserChrome3) {
     nsCOMPtr<nsIDOMNode> linkNode = do_QueryInterface(aContent);
     nsAutoString oldTarget(aTargetSpec);
     rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI,
                                                linkNode, mIsAppTab, target);
+    if (!oldTarget.Equals(target)) {
+      noOpenerImplied = true;
+    }
   }
 
   if (NS_FAILED(rv)) {
     target = aTargetSpec;
   }
 
   nsCOMPtr<nsIRunnable> ev =
     new OnLinkClickEvent(this, aContent, aURI, target.get(), aFileName,
-                         aPostDataStream, aHeadersDataStream, aIsTrusted);
+                         aPostDataStream, aHeadersDataStream, noOpenerImplied,
+                         aIsTrusted);
   return NS_DispatchToCurrentThread(ev);
 }
 
 NS_IMETHODIMP
 nsDocShell::OnLinkClickSync(nsIContent* aContent,
                             nsIURI* aURI,
                             const char16_t* aTargetSpec,
                             const nsAString& aFileName,
                             nsIInputStream* aPostDataStream,
                             nsIInputStream* aHeadersDataStream,
+                            bool aNoOpenerImplied,
                             nsIDocShell** aDocShell,
                             nsIRequest** aRequest)
 {
   // Initialize the DocShell / Request
   if (aDocShell) {
     *aDocShell = nullptr;
   }
   if (aRequest) {
@@ -13955,16 +13966,19 @@ nsDocShell::OnLinkClickSync(nsIContent* 
                  INTERNAL_LOAD_FLAGS_NO_OPENER;
         // We now have all the flags we could possibly have, so just stop.
         break;
       }
       if (token.LowerCaseEqualsLiteral("noopener")) {
         flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
       }
     }
+    if (aNoOpenerImplied) {
+      flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
+    }
   }
 
   // Get the owner document of the link that was clicked, this will be
   // the document that the link is in, or the last document that the
   // link was in. From that document, we'll get the URI to use as the
   // referer, since the current URI in this docshell may be a
   // new document that we're in the process of loading.
   nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc();
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -202,16 +202,17 @@ public:
                          nsIInputStream* aHeadersDataStream,
                          bool aIsTrusted) override;
   NS_IMETHOD OnLinkClickSync(nsIContent* aContent,
                              nsIURI* aURI,
                              const char16_t* aTargetSpec,
                              const nsAString& aFileName,
                              nsIInputStream* aPostDataStream = 0,
                              nsIInputStream* aHeadersDataStream = 0,
+                             bool aNoOpenerImplied = false,
                              nsIDocShell** aDocShell = 0,
                              nsIRequest** aRequest = 0) override;
   NS_IMETHOD OnOverLink(nsIContent* aContent,
                         nsIURI* aURI,
                         const char16_t* aTargetSpec) override;
   NS_IMETHOD OnLeaveLink() override;
 
   nsDocShellInfoLoadType ConvertLoadTypeToDocShellLoadInfo(uint32_t aLoadType);
--- a/docshell/base/nsILinkHandler.h
+++ b/docshell/base/nsILinkHandler.h
@@ -54,25 +54,27 @@ public:
    *
    * @param aContent the content for the frame that generated the trigger
    * @param aURI a URI obect that defines the destination for the link
    * @param aTargetSpec indicates where the link is targeted (may be an empty
    *        string)
    * @param aFileName non-null when the link should be downloaded as the given file
    * @param aPostDataStream the POST data to send
    * @param aHeadersDataStream ???
+   * @param aNoOpenerImplied if the link implies "noopener"
    * @param aDocShell (out-param) the DocShell that the request was opened on
    * @param aRequest the request that was opened
    */
   NS_IMETHOD OnLinkClickSync(nsIContent* aContent,
                              nsIURI* aURI,
                              const char16_t* aTargetSpec,
                              const nsAString& aFileName,
                              nsIInputStream* aPostDataStream = 0,
                              nsIInputStream* aHeadersDataStream = 0,
+                             bool aNoOpenerImplied = false,
                              nsIDocShell** aDocShell = 0,
                              nsIRequest** aRequest = 0) = 0;
 
   /**
    * Process a mouse-over a link.
    *
    * @param aContent the linked content.
    * @param aURI an URI object that defines the destination for the link
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -824,17 +824,17 @@ HTMLFormElement::SubmitSubmission(HTMLFo
     nsCOMPtr<nsIInputStream> postDataStream;
     rv = aFormSubmission->GetEncodedSubmission(actionURI,
                                                getter_AddRefs(postDataStream));
     NS_ENSURE_SUBMIT_SUCCESS(rv);
 
     rv = linkHandler->OnLinkClickSync(this, actionURI,
                                       target.get(),
                                       NullString(),
-                                      postDataStream, nullptr,
+                                      postDataStream, nullptr, false,
                                       getter_AddRefs(docShell),
                                       getter_AddRefs(mSubmittingRequest));
     NS_ENSURE_SUBMIT_SUCCESS(rv);
   }
 
   // Even if the submit succeeds, it's possible for there to be no docshell
   // or request; for example, if it's to a named anchor within the same page
   // the submit will not really do anything.