[WK2] Add API to query if a download was user-initiated
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 25 Sep 2017 21:28:01 +0000 (21:28 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 25 Sep 2017 21:28:01 +0000 (21:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=177435
<rdar://problem/34498422>

Reviewed by Alex Christensen.

Source/WebKit:

Add C and Cocoa private API to query if a download was user-initiated.

For clarity, we now construct navigation object for subframe loads
as well (we used to do so only for main frame loads). This allows us
to store the user-intiated flag and the redirect chain on the navigation
object instead of the WebFrameProxy.

* UIProcess/API/APINavigation.cpp:
(API::Navigation::Navigation):
(API::Navigation::appendRedirectionURL):
* UIProcess/API/APINavigation.h:
(API::Navigation::takeRedirectChain):
(API::Navigation::setWasUserInitiated):
(API::Navigation::wasUserInitiated const):
* UIProcess/API/C/WKDownload.cpp:
(WKDownloadGetWasUserInitiated):
* UIProcess/API/C/WKDownload.h:
* UIProcess/API/Cocoa/_WKDownload.h:
* UIProcess/API/Cocoa/_WKDownload.mm:
(-[_WKDownload wasUserInitiated]):
* UIProcess/Downloads/DownloadProxy.h:
(WebKit::DownloadProxy::setWasUserInitiated):
(WebKit::DownloadProxy::wasUserInitiated const):
* UIProcess/WebFrameProxy.cpp:
(WebKit::WebFrameProxy::didStartProvisionalLoad):
(WebKit::WebFrameProxy::didReceiveServerRedirectForProvisionalLoad):
(WebKit::WebFrameProxy::didFailProvisionalLoad):
(WebKit::WebFrameProxy::didFinishLoad):
(WebKit::WebFrameProxy::didFailLoad):
* UIProcess/WebFrameProxy.h:
(WebKit::WebFrameProxy::title const):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::receivedPolicyDecision):
(WebKit::WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame):
(WebKit::WebPageProxy::decidePolicyForNavigationAction):
(WebKit::WebPageProxy::decidePolicyForResponse):
(WebKit::WebPageProxy::decidePolicyForResponseSync):
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForResponse):

Tools:

Add API test coverage.

* TestWebKitAPI/Tests/WebKit/mac/ContextMenuDownload.mm:
(TestWebKitAPI::decideDestinationWithSuggestedFilename):
* TestWebKitAPI/Tests/WebKitCocoa/Download.mm:
(-[DownloadDelegate _downloadDidStart:]):
(-[DownloadDelegate _downloadDidFinish:]):
(runTest):
(TEST):
(-[BlobDownloadDelegate _downloadDidStart:]):
(-[BlobDownloadDelegate _downloadDidFinish:]):
(-[RedirectedDownloadDelegate _downloadDidStart:]):
(-[RedirectedDownloadDelegate _downloadDidFinish:]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@222468 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/APINavigation.cpp
Source/WebKit/UIProcess/API/APINavigation.h
Source/WebKit/UIProcess/API/C/WKDownload.cpp
Source/WebKit/UIProcess/API/C/WKDownload.h
Source/WebKit/UIProcess/API/Cocoa/_WKDownload.h
Source/WebKit/UIProcess/API/Cocoa/_WKDownload.mm
Source/WebKit/UIProcess/Downloads/DownloadProxy.h
Source/WebKit/UIProcess/WebFrameProxy.cpp
Source/WebKit/UIProcess/WebFrameProxy.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/WebPageProxy.messages.in
Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
Source/WebKit/WebProcess/WebPage/WebFrame.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKit/mac/ContextMenuDownload.mm
Tools/TestWebKitAPI/Tests/WebKitCocoa/Download.mm

index c33732e..54414fa 100644 (file)
@@ -1,5 +1,55 @@
 2017-09-25  Chris Dumez  <cdumez@apple.com>
 
+        [WK2] Add API to query if a download was user-initiated
+        https://bugs.webkit.org/show_bug.cgi?id=177435
+        <rdar://problem/34498422>
+
+        Reviewed by Alex Christensen.
+
+        Add C and Cocoa private API to query if a download was user-initiated.
+
+        For clarity, we now construct navigation object for subframe loads
+        as well (we used to do so only for main frame loads). This allows us
+        to store the user-intiated flag and the redirect chain on the navigation
+        object instead of the WebFrameProxy.
+
+        * UIProcess/API/APINavigation.cpp:
+        (API::Navigation::Navigation):
+        (API::Navigation::appendRedirectionURL):
+        * UIProcess/API/APINavigation.h:
+        (API::Navigation::takeRedirectChain):
+        (API::Navigation::setWasUserInitiated):
+        (API::Navigation::wasUserInitiated const):
+        * UIProcess/API/C/WKDownload.cpp:
+        (WKDownloadGetWasUserInitiated):
+        * UIProcess/API/C/WKDownload.h:
+        * UIProcess/API/Cocoa/_WKDownload.h:
+        * UIProcess/API/Cocoa/_WKDownload.mm:
+        (-[_WKDownload wasUserInitiated]):
+        * UIProcess/Downloads/DownloadProxy.h:
+        (WebKit::DownloadProxy::setWasUserInitiated):
+        (WebKit::DownloadProxy::wasUserInitiated const):
+        * UIProcess/WebFrameProxy.cpp:
+        (WebKit::WebFrameProxy::didStartProvisionalLoad):
+        (WebKit::WebFrameProxy::didReceiveServerRedirectForProvisionalLoad):
+        (WebKit::WebFrameProxy::didFailProvisionalLoad):
+        (WebKit::WebFrameProxy::didFinishLoad):
+        (WebKit::WebFrameProxy::didFailLoad):
+        * UIProcess/WebFrameProxy.h:
+        (WebKit::WebFrameProxy::title const):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::receivedPolicyDecision):
+        (WebKit::WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame):
+        (WebKit::WebPageProxy::decidePolicyForNavigationAction):
+        (WebKit::WebPageProxy::decidePolicyForResponse):
+        (WebKit::WebPageProxy::decidePolicyForResponseSync):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForResponse):
+
+2017-09-25  Chris Dumez  <cdumez@apple.com>
+
         Make StoredCredentials an enum class and rename its header
         https://bugs.webkit.org/show_bug.cgi?id=177455
 
index 82bc368..b7f698e 100644 (file)
@@ -39,10 +39,17 @@ Navigation::Navigation(WebKit::WebNavigationState& state, WebCore::ResourceReque
     : m_navigationID(state.generateNavigationID())
     , m_request(WTFMove(request))
 {
+    m_redirectChain.append(m_request.url());
 }
 
 Navigation::~Navigation()
 {
 }
 
+void Navigation::appendRedirectionURL(const WebCore::URL& url)
+{
+    if (m_redirectChain.isEmpty() || m_redirectChain.last() != url)
+        m_redirectChain.append(url);
+}
+
 } // namespace WebKit
index 6a30d06..054e08e 100644 (file)
@@ -53,12 +53,20 @@ public:
 
     const WebCore::ResourceRequest& request() const { return m_request; }
 
+    void appendRedirectionURL(const WebCore::URL&);
+    Vector<WebCore::URL> takeRedirectChain() { return WTFMove(m_redirectChain); }
+
+    void setWasUserInitiated(bool value) { m_wasUserInitiated = value; }
+    bool wasUserInitiated() const { return m_wasUserInitiated; }
+
 private:
     explicit Navigation(WebKit::WebNavigationState&);
     explicit Navigation(WebKit::WebNavigationState&, WebCore::ResourceRequest&&);
 
     uint64_t m_navigationID;
     WebCore::ResourceRequest m_request;
+    Vector<WebCore::URL> m_redirectChain;
+    bool m_wasUserInitiated { true };
 };
 
 } // namespace API
index 24de09f..48d8b82 100644 (file)
@@ -74,3 +74,8 @@ WKArrayRef WKDownloadCopyRedirectChain(WKDownloadRef download)
         urls.uncheckedAppend(API::URL::create(redirectURL.string()));
     return toAPI(&API::Array::create(WTFMove(urls)).leakRef());
 }
+
+bool WKDownloadGetWasUserInitiated(WKDownloadRef download)
+{
+    return toImpl(download)->wasUserInitiated();
+}
index 6a8c6cf..004e46c 100644 (file)
@@ -44,6 +44,7 @@ WK_EXPORT WKDataRef WKDownloadGetResumeData(WKDownloadRef download);
 WK_EXPORT void WKDownloadCancel(WKDownloadRef download);
 WK_EXPORT WKPageRef WKDownloadGetOriginatingPage(WKDownloadRef download);
 WK_EXPORT WKArrayRef WKDownloadCopyRedirectChain(WKDownloadRef download);
+WK_EXPORT bool WKDownloadGetWasUserInitiated(WKDownloadRef download);
 
 #ifdef __cplusplus
 }
index 8db3330..5992f80 100644 (file)
@@ -39,6 +39,7 @@ WK_CLASS_AVAILABLE(macosx(10.10), ios(8.0))
 @property (nonatomic, readonly) NSURLRequest *request;
 @property (nonatomic, readonly, weak) WKWebView *originatingWebView;
 @property (nonatomic, readonly, copy) NSArray<NSURL *> *redirectChain WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+@property (nonatomic, readonly) BOOL wasUserInitiated WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 @end
 
index 47e6f47..152e36e 100644 (file)
     return nsURLs;
 }
 
+- (BOOL)wasUserInitiated
+{
+    return _download->wasUserInitiated();
+}
+
 #pragma mark WKObject protocol implementation
 
 - (API::Object&)_apiObject
index ca55fb3..4779e92 100644 (file)
@@ -77,6 +77,9 @@ public:
     void setRedirectChain(Vector<WebCore::URL>&& redirectChain) { m_redirectChain = WTFMove(redirectChain); }
     const Vector<WebCore::URL>& redirectChain() const { return m_redirectChain; }
 
+    void setWasUserInitiated(bool value) { m_wasUserInitiated = value; }
+    bool wasUserInitiated() const { return m_wasUserInitiated; }
+
 private:
     explicit DownloadProxy(DownloadProxyMap&, WebProcessPool&, const WebCore::ResourceRequest&);
 
@@ -114,6 +117,7 @@ private:
 
     WeakPtr<WebPageProxy> m_originatingPage;
     Vector<WebCore::URL> m_redirectChain;
+    bool m_wasUserInitiated { true };
 };
 
 } // namespace WebKit
index c43b8e0..855d5d1 100644 (file)
@@ -131,23 +131,16 @@ bool WebFrameProxy::isDisplayingPDFDocument() const
 
 void WebFrameProxy::didStartProvisionalLoad(const URL& url)
 {
-    m_provisionalLoadRedirectChain = { url };
-
     m_frameLoadState.didStartProvisionalLoad(url);
 }
 
 void WebFrameProxy::didReceiveServerRedirectForProvisionalLoad(const URL& url)
 {
-    // didReceiveServerRedirectForProvisionalLoad() often gets called twice for the same redirect.
-    if (m_provisionalLoadRedirectChain.isEmpty() || m_provisionalLoadRedirectChain.last() != url)
-        m_provisionalLoadRedirectChain.append(url);
-
     m_frameLoadState.didReceiveServerRedirectForProvisionalLoad(url);
 }
 
 void WebFrameProxy::didFailProvisionalLoad()
 {
-    m_provisionalLoadRedirectChain.clear();
     m_frameLoadState.didFailProvisionalLoad();
 }
 
@@ -164,13 +157,11 @@ void WebFrameProxy::didCommitLoad(const String& contentType, WebCertificateInfo&
 
 void WebFrameProxy::didFinishLoad()
 {
-    m_provisionalLoadRedirectChain.clear();
     m_frameLoadState.didFinishLoad();
 }
 
 void WebFrameProxy::didFailLoad()
 {
-    m_provisionalLoadRedirectChain.clear();
     m_frameLoadState.didFailLoad();
 }
 
index dfc199d..b834197 100644 (file)
@@ -89,7 +89,6 @@ public:
     bool containsPluginDocument() const { return m_containsPluginDocument; }
 
     const String& title() const { return m_title; }
-    Vector<WebCore::URL>&& takeProvisionalLoadRedirectChain() { return WTFMove(m_provisionalLoadRedirectChain); }
 
     WebCertificateInfo* certificateInfo() const { return m_certificateInfo.get(); }
 
@@ -141,7 +140,6 @@ private:
     RefPtr<WebCertificateInfo> m_certificateInfo;
     RefPtr<WebFrameListenerProxy> m_activeListener;
     uint64_t m_frameID;
-    Vector<WebCore::URL> m_provisionalLoadRedirectChain;
 #if ENABLE(CONTENT_FILTERING)
     WebCore::ContentFilterUnblockHandler m_contentFilterUnblockHandler;
 #endif
index 2a7f605..9091785 100644 (file)
@@ -2276,7 +2276,10 @@ void WebPageProxy::receivedPolicyDecision(PolicyAction action, WebFrameProxy& fr
     if (action == PolicyDownload) {
         // Create a download proxy.
         auto* download = m_process->processPool().createDownloadProxy(m_decidePolicyForResponseRequest, this);
-        download->setRedirectChain(frame.takeProvisionalLoadRedirectChain());
+        if (navigation) {
+            download->setWasUserInitiated(navigation->wasUserInitiated());
+            download->setRedirectChain(navigation->takeRedirectChain());
+        }
 
         downloadID = download->downloadID();
         handleDownloadRequest(download);
@@ -3192,8 +3195,10 @@ void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t f
 
     // FIXME: We should message check that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
     RefPtr<API::Navigation> navigation;
-    if (frame->isMainFrame() && navigationID)
+    if (navigationID) {
         navigation = &navigationState().navigation(navigationID);
+        navigation->appendRedirectionURL(url);
+    }
 
     auto transaction = m_pageLoadState.transaction();
 
@@ -3207,7 +3212,7 @@ void WebPageProxy::didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t f
         if (frame->isMainFrame())
             m_navigationClient->didReceiveServerRedirectForProvisionalNavigation(*this, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
     } else
-        m_loaderClient->didReceiveServerRedirectForProvisionalLoadForFrame(*this, *frame, navigation.get(), m_process->transformHandlesToObjects(userData.object()).get());
+        m_loaderClient->didReceiveServerRedirectForProvisionalLoadForFrame(*this, *frame, frame->isMainFrame() ? navigation.get() : nullptr, m_process->transformHandlesToObjects(userData.object()).get());
 }
 
 void WebPageProxy::willPerformClientRedirectForFrame(uint64_t frameID, const String& url, double delay)
@@ -3668,10 +3673,15 @@ void WebPageProxy::decidePolicyForNavigationAction(uint64_t frameID, const Secur
     
     m_newNavigationID = 0;
     Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID);
-    if (!navigationID && frame->isMainFrame()) {
+    if (!navigationID) {
         auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request));
         m_newNavigationID = navigation->navigationID();
+        navigation->setWasUserInitiated(!!navigationActionData.userGestureTokenIdentifier);
         listener->setNavigation(WTFMove(navigation));
+    } else {
+        auto& navigation = m_navigationState->navigation(navigationID);
+        navigation.setWasUserInitiated(!!navigationActionData.userGestureTokenIdentifier);
+        listener->setNavigation(navigation);
     }
 
 #if ENABLE(CONTENT_FILTERING)
@@ -3734,7 +3744,7 @@ void WebPageProxy::decidePolicyForNewWindowAction(uint64_t frameID, const Securi
         m_policyClient->decidePolicyForNewWindowAction(*this, *frame, navigationActionData, request, frameName, WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get());
 }
 
-void WebPageProxy::decidePolicyForResponse(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, uint64_t listenerID, const UserData& userData)
+void WebPageProxy::decidePolicyForResponse(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, uint64_t listenerID, const UserData& userData)
 {
     PageClientProtector protector(m_pageClient);
 
@@ -3744,6 +3754,8 @@ void WebPageProxy::decidePolicyForResponse(uint64_t frameID, const SecurityOrigi
     MESSAGE_CHECK_URL(response.url());
 
     Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID);
+    if (navigationID)
+        listener->setNavigation(m_navigationState->navigation(navigationID));
 
     if (m_navigationClient) {
         auto navigationResponse = API::NavigationResponse::create(API::FrameInfo::create(*frame, frameSecurityOrigin.securityOrigin()).get(), request, response, canShowMIMEType);
@@ -3752,14 +3764,14 @@ void WebPageProxy::decidePolicyForResponse(uint64_t frameID, const SecurityOrigi
         m_policyClient->decidePolicyForResponse(*this, *frame, response, request, canShowMIMEType, WTFMove(listener), m_process->transformHandlesToObjects(userData.object()).get());
 }
 
-void WebPageProxy::decidePolicyForResponseSync(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, uint64_t listenerID, const UserData& userData, Ref<Messages::WebPageProxy::DecidePolicyForResponseSync::DelayedReply>&& reply)
+void WebPageProxy::decidePolicyForResponseSync(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const ResourceResponse& response, const ResourceRequest& request, bool canShowMIMEType, uint64_t listenerID, const UserData& userData, Ref<Messages::WebPageProxy::DecidePolicyForResponseSync::DelayedReply>&& reply)
 {
     PageClientProtector protector(m_pageClient);
 
     m_decidePolicyForResponseRequest = request;
     m_responsePolicyReply = WTFMove(reply);
 
-    decidePolicyForResponse(frameID, frameSecurityOrigin, response, request, canShowMIMEType, listenerID, userData);
+    decidePolicyForResponse(frameID, frameSecurityOrigin, navigationID, response, request, canShowMIMEType, listenerID, userData);
 }
 
 void WebPageProxy::unableToImplementPolicy(uint64_t frameID, const ResourceError& error, const UserData& userData)
index 7152822..13167da 100644 (file)
@@ -1281,8 +1281,8 @@ private:
 
     void decidePolicyForNavigationAction(uint64_t frameID, const WebCore::SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, NavigationActionData&&, const FrameInfoData&, uint64_t originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&&, uint64_t listenerID, const UserData&, Ref<Messages::WebPageProxy::DecidePolicyForNavigationAction::DelayedReply>&&);
     void decidePolicyForNewWindowAction(uint64_t frameID, const WebCore::SecurityOriginData& frameSecurityOrigin, NavigationActionData&&, WebCore::ResourceRequest&&, const String& frameName, uint64_t listenerID, const UserData&);
-    void decidePolicyForResponse(uint64_t frameID, const WebCore::SecurityOriginData& frameSecurityOrigin, const WebCore::ResourceResponse&, const WebCore::ResourceRequest&, bool canShowMIMEType, uint64_t listenerID, const UserData&);
-    void decidePolicyForResponseSync(uint64_t frameID, const WebCore::SecurityOriginData& frameSecurityOrigin, const WebCore::ResourceResponse&, const WebCore::ResourceRequest&, bool canShowMIMEType, uint64_t listenerID, const UserData&, Ref<Messages::WebPageProxy::DecidePolicyForResponseSync::DelayedReply>&&);
+    void decidePolicyForResponse(uint64_t frameID, const WebCore::SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const WebCore::ResourceResponse&, const WebCore::ResourceRequest&, bool canShowMIMEType, uint64_t listenerID, const UserData&);
+    void decidePolicyForResponseSync(uint64_t frameID, const WebCore::SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const WebCore::ResourceResponse&, const WebCore::ResourceRequest&, bool canShowMIMEType, uint64_t listenerID, const UserData&, Ref<Messages::WebPageProxy::DecidePolicyForResponseSync::DelayedReply>&&);
     void unableToImplementPolicy(uint64_t frameID, const WebCore::ResourceError&, const UserData&);
 
     void willSubmitForm(uint64_t frameID, uint64_t sourceFrameID, const Vector<std::pair<String, String>>& textFieldValues, uint64_t listenerID, const UserData&);
index ca2a0f2..49698a5 100644 (file)
@@ -98,7 +98,7 @@ messages -> WebPageProxy {
 #endif
 
     # Policy messages
-    DecidePolicyForResponseSync(uint64_t frameID, struct WebCore::SecurityOriginData frameSecurityOrigin, WebCore::ResourceResponse response, WebCore::ResourceRequest request, bool canShowMIMEType, uint64_t listenerID, WebKit::UserData userData) -> (uint64_t policyAction, WebKit::DownloadID downloadID) Delayed
+    DecidePolicyForResponseSync(uint64_t frameID, struct WebCore::SecurityOriginData frameSecurityOrigin, uint64_t navigationID, WebCore::ResourceResponse response, WebCore::ResourceRequest request, bool canShowMIMEType, uint64_t listenerID, WebKit::UserData userData) -> (uint64_t policyAction, WebKit::DownloadID downloadID) Delayed
     DecidePolicyForNavigationAction(uint64_t frameID, struct WebCore::SecurityOriginData frameSecurityOrigin, uint64_t navigationID, struct WebKit::NavigationActionData navigationActionData, struct WebKit::FrameInfoData originatingFrameInfoData, uint64_t originatingPageID, WebCore::ResourceRequest originalRequest, WebCore::ResourceRequest request, uint64_t listenerID, WebKit::UserData userData) -> (uint64_t newNavigationID, uint64_t policyAction, WebKit::DownloadID downloadID, struct WebKit::WebsitePolicies websitePolicies) Delayed
     DecidePolicyForNewWindowAction(uint64_t frameID, struct WebCore::SecurityOriginData frameSecurityOrigin, struct WebKit::NavigationActionData navigationActionData, WebCore::ResourceRequest request, String frameName, uint64_t listenerID, WebKit::UserData userData)
     UnableToImplementPolicy(uint64_t frameID, WebCore::ResourceError error, WebKit::UserData userData)
index 2e872b5..86e7e83 100644 (file)
@@ -704,7 +704,8 @@ void WebFrameLoaderClient::dispatchDecidePolicyForResponse(const ResourceRespons
 
     Ref<WebFrame> protect(*m_frame);
     WebCore::Frame* coreFrame = m_frame->coreFrame();
-    if (!webPage->sendSync(Messages::WebPageProxy::DecidePolicyForResponseSync(m_frame->frameID(), SecurityOriginData::fromFrame(coreFrame), response, request, canShowMIMEType, listenerID, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())), Messages::WebPageProxy::DecidePolicyForResponseSync::Reply(policyAction, downloadID), Seconds::infinity(), IPC::SendSyncOption::InformPlatformProcessWillSuspend)) {
+    auto navigationID = static_cast<WebDocumentLoader&>(*coreFrame->loader().provisionalDocumentLoader()).navigationID();
+    if (!webPage->sendSync(Messages::WebPageProxy::DecidePolicyForResponseSync(m_frame->frameID(), SecurityOriginData::fromFrame(coreFrame), navigationID, response, request, canShowMIMEType, listenerID, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())), Messages::WebPageProxy::DecidePolicyForResponseSync::Reply(policyAction, downloadID), Seconds::infinity(), IPC::SendSyncOption::InformPlatformProcessWillSuspend)) {
         m_frame->didReceivePolicyDecision(listenerID, PolicyIgnore, 0, { });
         return;
     }
index c866f8b..0d9861b 100644 (file)
@@ -808,7 +808,8 @@ void WebFrame::setTextDirection(const String& direction)
 
 void WebFrame::documentLoaderDetached(uint64_t navigationID)
 {
-    page()->send(Messages::WebPageProxy::DidDestroyNavigation(navigationID));
+    if (auto * page = this->page())
+        page->send(Messages::WebPageProxy::DidDestroyNavigation(navigationID));
 }
 
 #if PLATFORM(COCOA)
index aeb4fee..b12e424 100644 (file)
@@ -1,3 +1,25 @@
+2017-09-25  Chris Dumez  <cdumez@apple.com>
+
+        [WK2] Add API to query if a download was user-initiated
+        https://bugs.webkit.org/show_bug.cgi?id=177435
+        <rdar://problem/34498422>
+
+        Reviewed by Alex Christensen.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/Tests/WebKit/mac/ContextMenuDownload.mm:
+        (TestWebKitAPI::decideDestinationWithSuggestedFilename):
+        * TestWebKitAPI/Tests/WebKitCocoa/Download.mm:
+        (-[DownloadDelegate _downloadDidStart:]):
+        (-[DownloadDelegate _downloadDidFinish:]):
+        (runTest):
+        (TEST):
+        (-[BlobDownloadDelegate _downloadDidStart:]):
+        (-[BlobDownloadDelegate _downloadDidFinish:]):
+        (-[RedirectedDownloadDelegate _downloadDidStart:]):
+        (-[RedirectedDownloadDelegate _downloadDidFinish:]):
+
 2017-09-25  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r222455.
index 5dc5473..720d21a 100644 (file)
@@ -71,6 +71,7 @@ static WKStringRef decideDestinationWithSuggestedFilename(WKContextRef, WKDownlo
     didDecideDownloadDestination = true;
 
     EXPECT_EQ(expectedOriginatingPage, WKDownloadGetOriginatingPage(download));
+    EXPECT_TRUE(WKDownloadGetWasUserInitiated(download)); // Download was started via context menu so it is user initiated.
 
     return Util::toWK("/tmp/WebKitAPITest/ContextMenuDownload").leakRef();
 }
index d6e4252..748665c 100644 (file)
@@ -50,6 +50,7 @@ static unsigned redirectCount = 0;
 static bool hasReceivedResponse;
 static NSURL *sourceURL = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
 static WKWebView* expectedOriginatingWebView;
+static bool expectedUserInitiatedState = false;
 
 @interface DownloadDelegate : NSObject <_WKDownloadDelegate>
 @end
@@ -66,6 +67,7 @@ static WKWebView* expectedOriginatingWebView;
     EXPECT_NULL(_download);
     EXPECT_NOT_NULL(download);
     EXPECT_TRUE([[[[download request] URL] path] isEqualToString:[sourceURL path]]);
+    EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
     _download = download;
 }
 
@@ -102,6 +104,7 @@ static WKWebView* expectedOriginatingWebView;
 - (void)_downloadDidFinish:(_WKDownload *)download
 {
     EXPECT_EQ(_download, download);
+    EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
     EXPECT_TRUE(_expectedContentLength == NSURLResponseUnknownLength || static_cast<uint64_t>(_expectedContentLength) == _receivedContentLength);
     EXPECT_TRUE([[NSFileManager defaultManager] contentsEqualAtPath:_destinationPath andPath:[sourceURL path]]);
     WebCore::deleteFile(_destinationPath);
@@ -132,6 +135,7 @@ static void runTest(id <WKNavigationDelegate> navigationDelegate, id <_WKDownloa
 
     isDone = false;
     hasReceivedResponse = false;
+    expectedUserInitiatedState = false;
     [webView loadRequest:[NSURLRequest requestWithURL:url]];
     TestWebKitAPI::Util::run(&isDone);
 }
@@ -339,6 +343,7 @@ TEST(_WKDownload, DownloadRequestOriginalURLDirectDownloadWithLoadedContent)
     [webView setNavigationDelegate:[[DownloadRequestOriginalURLNavigationDelegate alloc] init]];
     [[[webView configuration] processPool] _setDownloadDelegate:[[DownloadRequestOriginalURLDelegate alloc] initWithExpectedOriginalURL:sourceURL]];
 
+    expectedUserInitiatedState = false;
     NSURL *contentURL = [[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
     // Here is to test if the original URL can be set correctly when the current document
     // is completely unrelated to the download.
@@ -363,6 +368,7 @@ TEST(_WKDownload, DownloadRequestOriginalURLDirectDownloadWithLoadedContent)
     EXPECT_NULL(_download);
     EXPECT_NOT_NULL(download);
     EXPECT_TRUE([[[[download request] URL] scheme] isEqualToString:@"blob"]);
+    EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
     _download = download;
 }
 
@@ -399,6 +405,7 @@ TEST(_WKDownload, DownloadRequestOriginalURLDirectDownloadWithLoadedContent)
 - (void)_downloadDidFinish:(_WKDownload *)download
 {
     EXPECT_EQ(_download, download);
+    EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
     EXPECT_TRUE(_expectedContentLength == NSURLResponseUnknownLength || static_cast<uint64_t>(_expectedContentLength) == _receivedContentLength);
     NSString* expectedContent = @"{\"x\":42,\"s\":\"hello, world\"}";
     NSData* expectedData = [expectedContent dataUsingEncoding:NSUTF8StringEncoding];
@@ -454,6 +461,7 @@ TEST(_WKDownload, DownloadRequestBlobURL)
 {
     EXPECT_NOT_NULL(download);
     EXPECT_EQ(expectedOriginatingWebView, download.originatingWebView);
+    EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
 }
 
 - (NSString *)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename allowOverwrite:(BOOL *)allowOverwrite
@@ -477,6 +485,8 @@ TEST(_WKDownload, DownloadRequestBlobURL)
 
 - (void)_downloadDidFinish:(_WKDownload *)download
 {
+    EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
+
     NSArray<NSURL *> *redirectChain = download.redirectChain;
     EXPECT_EQ(3U, redirectChain.count);
     if (redirectChain.count > 0)
@@ -514,6 +524,7 @@ TEST(_WKDownload, RedirectedDownload)
     [webView synchronouslyLoadHTMLString:@"<a style='display: block; height: 100%; width: 100%' href='http://redirect/?redirect/?pass'>test</a>"];
 
     expectedOriginatingWebView = webView.get();
+    expectedUserInitiatedState = true;
     NSPoint clickPoint = NSMakePoint(100, 100);
     [[webView hitTest:clickPoint] mouseDown:[NSEvent mouseEventWithType:NSEventTypeRightMouseDown location:clickPoint modifierFlags:0 timestamp:0 windowNumber:[window windowNumber] context:nil eventNumber:0 clickCount:1 pressure:1]];
     [[webView hitTest:clickPoint] mouseUp:[NSEvent mouseEventWithType:NSEventTypeRightMouseUp location:clickPoint modifierFlags:0 timestamp:0 windowNumber:[window windowNumber] context:nil eventNumber:0 clickCount:1 pressure:1]];
@@ -537,6 +548,7 @@ TEST(_WKDownload, RedirectedLoadConvertedToDownload)
     [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
 
     expectedOriginatingWebView = webView.get();
+    expectedUserInitiatedState = false;
     isDone = false;
     redirectCount = 0;
     hasReceivedResponse = false;
@@ -559,6 +571,7 @@ TEST(_WKDownload, RedirectedSubframeLoadConvertedToDownload)
     [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
 
     expectedOriginatingWebView = webView.get();
+    expectedUserInitiatedState = false;
     isDone = false;
     redirectCount = 0;
     hasReceivedResponse = false;