Allow navigations in subframes to get a ShouldOpenExternalURLsPolicy of "ShouldAllow".
<rdar://problem/22485589> and https://bugs.webkit.org/show_bug.cgi?id=174178

Reviewed by Alex Christensen.

Source/WebCore:

Test: loader/navigation-policy/should-open-external-urls/subframe-navigated-programatically-by-main-frame.html

This patch introduces a new flag to FrameLoadRequest to track when it is known with certainty that a
FrameLoadRequest originates from the main frame.

Later, when calculating the final ShouldOpenExternalURLsPolicy, main frames navigating iframes get to propagate
their permissions to the iframe.

* bindings/js/CommonVM.cpp:
(WebCore::lexicalFrameFromCommonVM): Helper to grab the current frame associated with the current JS callstack.
* bindings/js/CommonVM.h:

* inspector/InspectorFrontendClientLocal.cpp:
(WebCore::InspectorFrontendClientLocal::openInNewTab):

* inspector/InspectorPageAgent.cpp:
(WebCore::InspectorPageAgent::navigate):

Add the new flag to FrameLoadRequest (and force almost everybody to explicitly include the flag):
* loader/FrameLoadRequest.cpp:
(WebCore::FrameLoadRequest::FrameLoadRequest):
* loader/FrameLoadRequest.h:
(WebCore::FrameLoadRequest::FrameLoadRequest):
(WebCore::FrameLoadRequest::navigationInitiatedByMainFrame):

* loader/FrameLoader.cpp:
(WebCore::FrameLoader::urlSelected):
(WebCore::FrameLoader::loadURLIntoChildFrame):
(WebCore::shouldOpenExternalURLsPolicyToApply): Helper that takes the new flag into account when deciding
  what the final ShouldOpenExternalURLsPolicy will be.
(WebCore::applyShouldOpenExternalURLsPolicyToNewDocumentLoader):
(WebCore::FrameLoader::loadURL):
(WebCore::FrameLoader::load):
(WebCore::FrameLoader::loadWithNavigationAction):
(WebCore::FrameLoader::reloadWithOverrideEncoding):
(WebCore::FrameLoader::reload):
(WebCore::FrameLoader::loadPostRequest):
(WebCore::FrameLoader::continueLoadAfterNewWindowPolicy):
(WebCore::FrameLoader::loadDifferentDocumentItem):
(WebCore::createWindow):
(WebCore::FrameLoader::applyShouldOpenExternalURLsPolicyToNewDocumentLoader): Deleted.
* loader/FrameLoader.h:

* loader/FrameLoaderTypes.h:

* loader/NavigationAction.h:
(WebCore::NavigationAction::navigationInitiatedByMainFrame):
* loader/NavigationScheduler.cpp:
(WebCore::ScheduledNavigation::ScheduledNavigation): Grab the "initiating frame" at the time the
  ScheduledNavigation is created, as it dictates the policy we decide later.
(WebCore::ScheduledNavigation::navigationInitiatedByMainFrame):
(WebCore::NavigationScheduler::scheduleLocationChange):

* page/ContextMenuController.cpp:
(WebCore::openNewWindow):
(WebCore::ContextMenuController::contextMenuItemSelected):

* page/DOMWindow.cpp:
(WebCore::DOMWindow::createWindow):

Source/WebKit/ios:

Adopt to the new constructor for FrameLoadRequest.

* WebView/WebPDFViewPlaceholder.mm:
(-[WebPDFViewPlaceholder simulateClickOnLinkToURL:]):

Source/WebKit/mac:

Adopt to the new constructor for FrameLoadRequest.

* WebView/WebPDFView.mm:
(-[WebPDFView PDFViewWillClickOnLink:withURL:]):

Source/WebKit/win:

Adopt to the new constructor for FrameLoadRequest.

* Plugins/PluginView.cpp:
(WebCore::PluginView::start):
(WebCore::PluginView::getURLNotify):
(WebCore::PluginView::getURL):
(WebCore::PluginView::handlePost):

Source/WebKit2:

Adopt to the new constructor for FrameLoadRequest.

* WebProcess/Plugins/PluginView.cpp:
(WebKit::PluginView::loadURL):
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::dispatchCreatePage):
* WebProcess/WebPage/WebInspector.cpp:
(WebKit::WebInspector::openInNewTab):

LayoutTests:

Added a new explicit test and updated expectations for an old one.

* loader/navigation-policy/should-open-external-urls/resources/main-frame-with-subframe-main-programatically-navigates-subframe.html: Added.
* loader/navigation-policy/should-open-external-urls/subframe-click-target-self-expected.txt:
* loader/navigation-policy/should-open-external-urls/subframe-navigated-programatically-by-main-frame-expected.txt: Added.
* loader/navigation-policy/should-open-external-urls/subframe-navigated-programatically-by-main-frame.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@219170 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/loader/NavigationScheduler.cpp b/Source/WebCore/loader/NavigationScheduler.cpp
index b41a54f..3bcb1a5 100644
--- a/Source/WebCore/loader/NavigationScheduler.cpp
+++ b/Source/WebCore/loader/NavigationScheduler.cpp
@@ -33,6 +33,7 @@
 #include "NavigationScheduler.h"
 
 #include "BackForwardController.h"
+#include "CommonVM.h"
 #include "DOMWindow.h"
 #include "DocumentLoader.h"
 #include "Event.h"
@@ -79,6 +80,10 @@
         , m_userGestureToForward(UserGestureIndicator::currentUserGesture())
         , m_shouldOpenExternalURLsPolicy(externalURLPolicy)
     {
+        if (auto* frame = lexicalFrameFromCommonVM()) {
+            if (frame->isMainFrame())
+                m_navigationInitiatedByMainFrame = NavigationInitiatedByMainFrame::Yes;
+        }
     }
     virtual ~ScheduledNavigation() { }
 
@@ -98,6 +103,7 @@
 protected:
     void clearUserGesture() { m_userGestureToForward = nullptr; }
     ShouldOpenExternalURLsPolicy shouldOpenExternalURLs() const { return m_shouldOpenExternalURLsPolicy; }
+    NavigationInitiatedByMainFrame navigationInitiatedByMainFrame() const { return m_navigationInitiatedByMainFrame; };
 
 private:
     double m_delay;
@@ -107,6 +113,7 @@
     bool m_isLocationChange;
     RefPtr<UserGestureToken> m_userGestureToForward;
     ShouldOpenExternalURLsPolicy m_shouldOpenExternalURLsPolicy { ShouldOpenExternalURLsPolicy::ShouldNotAllow };
+    NavigationInitiatedByMainFrame m_navigationInitiatedByMainFrame { NavigationInitiatedByMainFrame::Unknown };
 };
 
 class ScheduledURLNavigation : public ScheduledNavigation {
@@ -125,7 +132,7 @@
         UserGestureIndicator gestureIndicator { userGestureToForward() };
 
         ResourceRequest resourceRequest { m_url, m_referrer, UseProtocolCachePolicy };
-        FrameLoadRequest frameLoadRequest { m_initiatingDocument.get(), *m_securityOrigin, resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs() };
+        FrameLoadRequest frameLoadRequest { m_initiatingDocument.get(), *m_securityOrigin, resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs(), navigationInitiatedByMainFrame() };
 
         frame.loader().changeLocation(WTFMove(frameLoadRequest));
     }
@@ -186,7 +193,7 @@
 
         bool refresh = equalIgnoringFragmentIdentifier(frame.document()->url(), url());
         ResourceRequest resourceRequest { url(), referrer(), refresh ? ReloadIgnoringCacheData : UseProtocolCachePolicy };
-        FrameLoadRequest frameLoadRequest { initiatingDocument(), *securityOrigin(), resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs() };
+        FrameLoadRequest frameLoadRequest { initiatingDocument(), *securityOrigin(), resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs(), navigationInitiatedByMainFrame() };
 
         frame.loader().changeLocation(WTFMove(frameLoadRequest));
     }
@@ -202,7 +209,8 @@
         UserGestureIndicator gestureIndicator { userGestureToForward() };
 
         ResourceRequest resourceRequest { url(), referrer(), UseProtocolCachePolicy };
-        FrameLoadRequest frameLoadRequest { initiatingDocument(), *securityOrigin(), resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs() };
+        FrameLoadRequest frameLoadRequest { initiatingDocument(), *securityOrigin(), resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs(), navigationInitiatedByMainFrame() };
+
         frame.loader().changeLocation(WTFMove(frameLoadRequest));
     }
 };
@@ -219,7 +227,8 @@
         UserGestureIndicator gestureIndicator { userGestureToForward() };
 
         ResourceRequest resourceRequest { url(), referrer(), ReloadIgnoringCacheData };
-        FrameLoadRequest frameLoadRequest { initiatingDocument(), *securityOrigin(), resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs() };
+        FrameLoadRequest frameLoadRequest { initiatingDocument(), *securityOrigin(), resourceRequest, "_self", lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs(), navigationInitiatedByMainFrame() };
+
         frame.loader().changeLocation(WTFMove(frameLoadRequest));
     }
 };
@@ -271,7 +280,7 @@
         auto& requestingDocument = m_submission->state().sourceDocument();
         if (!requestingDocument.canNavigate(&frame))
             return;
-        FrameLoadRequest frameLoadRequest { requestingDocument, requestingDocument.securityOrigin(), { }, { }, lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs() };
+        FrameLoadRequest frameLoadRequest { requestingDocument, requestingDocument.securityOrigin(), { }, { }, lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs(), navigationInitiatedByMainFrame() };
         m_submission->populateFrameLoadRequest(frameLoadRequest);
         frame.loader().loadFrameRequest(WTFMove(frameLoadRequest), m_submission->event(), &m_submission->state());
     }
@@ -321,7 +330,7 @@
         SubstituteData replacementData { SharedBuffer::create(), m_originDocument.url(), replacementResponse, SubstituteData::SessionHistoryVisibility::Hidden };
 
         ResourceRequest resourceRequest { m_originDocument.url(), emptyString(), ReloadIgnoringCacheData };
-        FrameLoadRequest frameLoadRequest { m_originDocument, m_originDocument.securityOrigin(), resourceRequest, { }, lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs() };
+        FrameLoadRequest frameLoadRequest { m_originDocument, m_originDocument.securityOrigin(), resourceRequest, { }, lockHistory(), lockBackForwardList(), MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, shouldOpenExternalURLs(), navigationInitiatedByMainFrame() };
         frameLoadRequest.setSubstituteData(replacementData);
         frame.loader().load(WTFMove(frameLoadRequest));
     }
@@ -420,7 +429,10 @@
     // fragment part, we don't need to schedule the location change.
     if (url.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(m_frame.document()->url(), url)) {
         ResourceRequest resourceRequest { m_frame.document()->completeURL(url), referrer, UseProtocolCachePolicy };
-        FrameLoadRequest frameLoadRequest { initiatingDocument, securityOrigin, resourceRequest, ASCIILiteral("_self"), lockHistory, lockBackForwardList, MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, initiatingDocument.shouldOpenExternalURLsPolicyToPropagate() };
+        auto* frame = lexicalFrameFromCommonVM();
+        auto navigationInitiatedByMainFrame = frame && frame->isMainFrame() ? NavigationInitiatedByMainFrame::Yes : NavigationInitiatedByMainFrame::Unknown;
+        
+        FrameLoadRequest frameLoadRequest { initiatingDocument, securityOrigin, resourceRequest, ASCIILiteral("_self"), lockHistory, lockBackForwardList, MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, initiatingDocument.shouldOpenExternalURLsPolicyToPropagate(), navigationInitiatedByMainFrame };
         loader.changeLocation(WTFMove(frameLoadRequest));
         return;
     }