[WK2] Notify client when downloads are redirected
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Sep 2017 19:51:58 +0000 (19:51 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 7 Sep 2017 19:51:58 +0000 (19:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=176481
<rdar://problem/34309065>

Reviewed by Geoffrey Garen.

Source/WebKit:

Notify client when downloads are redirected via both ObjC and C
API.

* NetworkProcess/Downloads/Download.cpp:
(WebKit::Download::willSendRedirectedRequest):
* NetworkProcess/Downloads/Download.h:
* NetworkProcess/Downloads/mac/DownloadMac.mm:
(-[WKDownloadAsDelegate download:willSendRequest:redirectResponse:]):
* UIProcess/API/APIDownloadClient.h:
(API::DownloadClient::willSendRequest):
* UIProcess/API/C/WKContext.cpp:
(WKContextSetDownloadClient):
* UIProcess/API/C/WKContextDownloadClient.h:
* UIProcess/API/Cocoa/_WKDownloadDelegate.h:
* UIProcess/Cocoa/DownloadClient.h:
* UIProcess/Cocoa/DownloadClient.mm:
(WebKit::DownloadClient::DownloadClient):
(WebKit::DownloadClient::willSendRequest):
* UIProcess/Downloads/DownloadProxy.cpp:
(WebKit::DownloadProxy::willSendRequest):
* UIProcess/Downloads/DownloadProxy.h:
* UIProcess/Downloads/DownloadProxy.messages.in:

* UIProcess/mac/WebContextMenuProxyMac.mm:
(WebKit::WebContextMenuProxyMac::showContextMenuWithItems):
Set menu proxy before calling menuFromProposedMenu() client delegate.
This allows me to perform one of the menu item's action from the
menuFromProposedMenu() client delegate in my API test.

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/Download.mm:
(-[UIDownloadAsFileTestDelegate _webView:contextMenu:forElement:]):
(-[RedirectedDownloadDelegate _download:decideDestinationWithSuggestedFilename:allowOverwrite:]):
(-[RedirectedDownloadDelegate _download:didReceiveServerRedirectToURL:]):
(-[RedirectedDownloadDelegate _downloadDidFinish:]):
(TEST):
Add API test coverage.

* WebKitTestRunner/TestController.cpp:
(WTR::TestController::createWebViewWithOptions):
(WTR::TestController::downloadDidReceiveServerRedirectToURL):
* WebKitTestRunner/TestController.h:
Add layout test infrastructure.

LayoutTests:

Add layout test coverage.

* http/tests/download/anchor-download-redirect-expected.txt: Added.
* http/tests/download/anchor-download-redirect.html: Added.
* platform/ios-wk2/TestExpectations:
* platform/mac-wk1/TestExpectations:

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

23 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/download/anchor-download-redirect-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/download/anchor-download-redirect.html [new file with mode: 0644]
LayoutTests/platform/ios-wk2/TestExpectations
LayoutTests/platform/mac-wk1/TestExpectations
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/Downloads/Download.cpp
Source/WebKit/NetworkProcess/Downloads/Download.h
Source/WebKit/NetworkProcess/Downloads/mac/DownloadMac.mm
Source/WebKit/UIProcess/API/APIDownloadClient.h
Source/WebKit/UIProcess/API/C/WKContext.cpp
Source/WebKit/UIProcess/API/C/WKContextDownloadClient.h
Source/WebKit/UIProcess/API/Cocoa/_WKDownloadDelegate.h
Source/WebKit/UIProcess/Cocoa/DownloadClient.h
Source/WebKit/UIProcess/Cocoa/DownloadClient.mm
Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp
Source/WebKit/UIProcess/Downloads/DownloadProxy.h
Source/WebKit/UIProcess/Downloads/DownloadProxy.messages.in
Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/Download.mm
Tools/WebKitTestRunner/TestController.cpp
Tools/WebKitTestRunner/TestController.h

index f70fcfe..b64ba54 100644 (file)
@@ -1,3 +1,18 @@
+2017-09-07  Chris Dumez  <cdumez@apple.com>
+
+        [WK2] Notify client when downloads are redirected
+        https://bugs.webkit.org/show_bug.cgi?id=176481
+        <rdar://problem/34309065>
+
+        Reviewed by Geoffrey Garen.
+
+        Add layout test coverage.
+
+        * http/tests/download/anchor-download-redirect-expected.txt: Added.
+        * http/tests/download/anchor-download-redirect.html: Added.
+        * platform/ios-wk2/TestExpectations:
+        * platform/mac-wk1/TestExpectations:
+
 2017-09-07  Per Arne Vollan  <pvollan@apple.com>
 
         Marked imported/w3c/web-platform-tests/html/semantics/embedded-content/the-iframe-element/cross_origin_parentage.html as slow.
diff --git a/LayoutTests/http/tests/download/anchor-download-redirect-expected.txt b/LayoutTests/http/tests/download/anchor-download-redirect-expected.txt
new file mode 100644 (file)
index 0000000..735b029
--- /dev/null
@@ -0,0 +1,7 @@
+Download started.
+Download was redirected to "http://127.0.0.1:8000/media/resources/test.pdf".
+Downloading URL with suggested filename "foo.pdf"
+Download completed.
+Tests that download redirects are reported to the client. the link.
+
+The suggested filename at the top should be foo.pdf and you should see a redirect to /media/resources/test.pdf.
diff --git a/LayoutTests/http/tests/download/anchor-download-redirect.html b/LayoutTests/http/tests/download/anchor-download-redirect.html
new file mode 100644 (file)
index 0000000..32d3d21
--- /dev/null
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.setShouldLogDownloadCallbacks(true);
+        testRunner.waitUntilDownloadFinished();
+    }
+</script>
+</head>
+<body>
+<p>
+Tests that download redirects are reported to the client.
+<a id="dl" href="/resources/redirect.php?url=/media/resources/test.pdf" download="foo.pdf">the link</a>.
+<p>
+The suggested filename at the top should be foo.pdf and you should see a redirect to /media/resources/test.pdf.
+<script>
+    function click(elmt)
+    {
+        if (!window.eventSender)
+            return;
+
+        eventSender.mouseMoveTo(elmt.offsetLeft + 5, elmt.offsetTop + 5);
+        eventSender.mouseDown();
+        eventSender.mouseUp();
+    }
+
+    function runTest()
+    {
+        var link = document.getElementById("dl");
+        click(link);
+    }
+    runTest();
+</script>
+</body>
+</html>
index fb069ad..2943009 100644 (file)
@@ -1806,6 +1806,7 @@ webkit.org/b/156067 fast/dom/HTMLAnchorElement/anchor-download-synthetic-click.h
 webkit.org/b/156067 fast/dom/HTMLAnchorElement/anchor-download-user-triggered-synthetic-click.html [ Skip ]
 webkit.org/b/156067 http/tests/download/anchor-download-attribute-content-disposition.html [ Skip ]
 webkit.org/b/156067 http/tests/download/anchor-download-no-extension.html [ Skip ]
+webkit.org/b/156067 http/tests/download/anchor-download-redirect.html [ Skip ]
 webkit.org/b/156067 http/tests/download/area-download.html [ Skip ]
 webkit.org/b/156067 http/tests/security/anchor-download-allow-blob.html [ Skip ]
 webkit.org/b/156067 http/tests/security/anchor-download-allow-data.html [ Skip ]
index 43280a5..1864a68 100644 (file)
@@ -241,6 +241,7 @@ webkit.org/b/156069 fast/dom/HTMLAnchorElement/anchor-file-blob-download-include
 webkit.org/b/156069 fast/dom/HTMLAnchorElement/anchor-file-blob-download-no-extension.html [ Skip ]
 webkit.org/b/156069 http/tests/download/anchor-download-attribute-content-disposition.html [ Skip ]
 webkit.org/b/156069 http/tests/download/anchor-download-no-extension.html [ Skip ]
+webkit.org/b/156069 http/tests/download/anchor-download-redirect.html [ Skip ]
 webkit.org/b/156069 http/tests/download/area-download.html [ Skip ]
 webkit.org/b/156069 http/tests/security/anchor-download-allow-blob.html [ Skip ]
 webkit.org/b/156069 http/tests/security/anchor-download-allow-data.html [ Skip ]
index 2e8483f..612a4e0 100644 (file)
@@ -1,3 +1,40 @@
+2017-09-07  Chris Dumez  <cdumez@apple.com>
+
+        [WK2] Notify client when downloads are redirected
+        https://bugs.webkit.org/show_bug.cgi?id=176481
+        <rdar://problem/34309065>
+
+        Reviewed by Geoffrey Garen.
+
+        Notify client when downloads are redirected via both ObjC and C
+        API.
+
+        * NetworkProcess/Downloads/Download.cpp:
+        (WebKit::Download::willSendRedirectedRequest):
+        * NetworkProcess/Downloads/Download.h:
+        * NetworkProcess/Downloads/mac/DownloadMac.mm:
+        (-[WKDownloadAsDelegate download:willSendRequest:redirectResponse:]):
+        * UIProcess/API/APIDownloadClient.h:
+        (API::DownloadClient::willSendRequest):
+        * UIProcess/API/C/WKContext.cpp:
+        (WKContextSetDownloadClient):
+        * UIProcess/API/C/WKContextDownloadClient.h:
+        * UIProcess/API/Cocoa/_WKDownloadDelegate.h:
+        * UIProcess/Cocoa/DownloadClient.h:
+        * UIProcess/Cocoa/DownloadClient.mm:
+        (WebKit::DownloadClient::DownloadClient):
+        (WebKit::DownloadClient::willSendRequest):
+        * UIProcess/Downloads/DownloadProxy.cpp:
+        (WebKit::DownloadProxy::willSendRequest):
+        * UIProcess/Downloads/DownloadProxy.h:
+        * UIProcess/Downloads/DownloadProxy.messages.in:
+
+        * UIProcess/mac/WebContextMenuProxyMac.mm:
+        (WebKit::WebContextMenuProxyMac::showContextMenuWithItems):
+        Set menu proxy before calling menuFromProposedMenu() client delegate.
+        This allows me to perform one of the menu item's action from the
+        menuFromProposedMenu() client delegate in my API test.
+
 2017-09-07  Alex Christensen  <achristensen@webkit.org>
 
         Modernize Geolocation code
index cd92195..7312f72 100644 (file)
@@ -152,6 +152,11 @@ void Download::didStart()
     send(Messages::DownloadProxy::DidStart(m_request, m_suggestedName));
 }
 
+void Download::willSendRedirectedRequest(WebCore::ResourceRequest&& redirectRequest, WebCore::ResourceResponse&& redirectResponse)
+{
+    send(Messages::DownloadProxy::WillSendRequest(WTFMove(redirectRequest), WTFMove(redirectResponse)));
+}
+
 void Download::didReceiveAuthenticationChallenge(const AuthenticationChallenge& authenticationChallenge)
 {
     m_downloadManager.downloadsAuthenticationManager().didReceiveAuthenticationChallenge(*this, authenticationChallenge);
index d7c949c..c379bca 100644 (file)
@@ -62,6 +62,7 @@ class BlobDataFileReference;
 class Credential;
 class ResourceError;
 class ResourceHandle;
+class ResourceRequest;
 class ResourceResponse;
 }
 
@@ -104,6 +105,7 @@ public:
     const WebCore::ResourceRequest& request() const { return m_request; }
     void didReceiveAuthenticationChallenge(const WebCore::AuthenticationChallenge&);
     void didStart();
+    void willSendRedirectedRequest(WebCore::ResourceRequest&&, WebCore::ResourceResponse&&);
     void didReceiveResponse(const WebCore::ResourceResponse&);
     bool shouldDecodeSourceDataOfMIMEType(const String& mimeType);
     String decideDestinationWithSuggestedFilename(const String& filename, bool& allowOverwrite);
index 19d2ceb..5c63f5a 100644 (file)
@@ -208,6 +208,10 @@ static void dispatchOnMainThread(void (^block)())
 
 - (NSURLRequest *)download:(NSURLDownload *)download willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
 {
+    dispatchOnMainThread(^ {
+        if (_download && redirectResponse)
+            _download->willSendRedirectedRequest(request, redirectResponse);
+    });
     return request;
 }
 
index b57dde4..c43749f 100644 (file)
@@ -60,7 +60,7 @@ public:
     virtual void didCancel(WebKit::WebProcessPool*, WebKit::DownloadProxy*) { }
     virtual void processDidCrash(WebKit::WebProcessPool*, WebKit::DownloadProxy*) { }
     virtual bool canAuthenticateAgainstProtectionSpace(WebKit::WebProtectionSpace*) { return true; }
-    virtual void willSendRequest(const WebCore::ResourceRequest& request, const WebCore::ResourceResponse&, WTF::Function<void(const WebCore::ResourceRequest&)>&& callback) { callback(request); }
+    virtual void willSendRequest(WebKit::WebProcessPool*, WebKit::DownloadProxy*, const WebCore::ResourceRequest& request, const WebCore::ResourceResponse&, WTF::Function<void(const WebCore::ResourceRequest&)>&& callback) { callback(request); }
 };
 
 } // namespace API
index db4704a..d1baf6d 100644 (file)
@@ -51,7 +51,7 @@
 
 namespace API {
 template<> struct ClientTraits<WKContextDownloadClientBase> {
-    typedef std::tuple<WKContextDownloadClientV0> Versions;
+    typedef std::tuple<WKContextDownloadClientV0, WKContextDownloadClientV1> Versions;
 };
 template<> struct ClientTraits<WKContextHistoryClientBase> {
     typedef std::tuple<WKContextHistoryClientV0> Versions;
@@ -261,6 +261,15 @@ void WKContextSetDownloadClient(WKContextRef contextRef, const WKContextDownload
             m_client.processDidCrash(toAPI(processPool), toAPI(downloadProxy), m_client.base.clientInfo);
         }
 
+        void willSendRequest(WebProcessPool* processPool, DownloadProxy* downloadProxy, const ResourceRequest& request, const ResourceResponse&, WTF::Function<void(const ResourceRequest&)>&& callback) override
+        {
+            if (m_client.didReceiveServerRedirect)
+                m_client.didReceiveServerRedirect(toAPI(processPool), toAPI(downloadProxy), toURLRef(request.url().string().impl()), m_client.base.clientInfo);
+
+            callback(request);
+        }
+
+
     };
 
     toImpl(contextRef)->setDownloadClient(std::make_unique<DownloadClient>(wkClient));
index 5bb8d83..fcf96ab 100644 (file)
@@ -39,6 +39,7 @@ typedef void (*WKContextDownloadDidFinishCallback)(WKContextRef context, WKDownl
 typedef void (*WKContextDownloadDidFailCallback)(WKContextRef context, WKDownloadRef download, WKErrorRef error, const void *clientInfo);
 typedef void (*WKContextDownloadDidCancel)(WKContextRef context, WKDownloadRef download, const void *clientInfo);
 typedef void (*WKContextDownloadProcessDidCrashCallback)(WKContextRef context, WKDownloadRef download, const void *clientInfo);
+typedef void (*WKContextDownloadDidReceiveServerRedirect)(WKContextRef context, WKDownloadRef download, WKURLRef url, const void *clientInfo);
 
 typedef struct WKContextDownloadClientBase {
     int                                                                 version;
@@ -62,4 +63,24 @@ typedef struct WKContextDownloadClientV0 {
     WKContextDownloadProcessDidCrashCallback                            processDidCrash;
 } WKContextDownloadClientV0;
 
+typedef struct WKContextDownloadClientV1 {
+    WKContextDownloadClientBase                                         base;
+
+    // Version 0.
+    WKContextDownloadDidStartCallback                                   didStart;
+    WKContextDownloadDidReceiveAuthenticationChallengeCallback          didReceiveAuthenticationChallenge;
+    WKContextDownloadDidReceiveResponseCallback                         didReceiveResponse;
+    WKContextDownloadDidReceiveDataCallback                             didReceiveData;
+    WKContextDownloadShouldDecodeSourceDataOfMIMETypeCallback           shouldDecodeSourceDataOfMIMEType;
+    WKContextDownloadDecideDestinationWithSuggestedFilenameCallback     decideDestinationWithSuggestedFilename;
+    WKContextDownloadDidCreateDestinationCallback                       didCreateDestination;
+    WKContextDownloadDidFinishCallback                                  didFinish;
+    WKContextDownloadDidFailCallback                                    didFail;
+    WKContextDownloadDidCancel                                          didCancel;
+    WKContextDownloadProcessDidCrashCallback                            processDidCrash;
+
+    // Version 1.
+    WKContextDownloadDidReceiveServerRedirect                           didReceiveServerRedirect;
+} WKContextDownloadClientV1;
+
 #endif // WKContextDownloadClient_h
index b3ef2ce..d26d06f 100644 (file)
@@ -34,6 +34,7 @@
 @protocol _WKDownloadDelegate <NSObject>
 @optional
 - (void)_downloadDidStart:(_WKDownload *)download;
+- (void)_download:(_WKDownload *)download didReceiveServerRedirectToURL:(NSURL *)url WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)_download:(_WKDownload *)download didReceiveResponse:(NSURLResponse *)response;
 - (void)_download:(_WKDownload *)download didReceiveData:(uint64_t)length;
 - (NSString *)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename allowOverwrite:(BOOL *)allowOverwrite;
index 0cac4f0..0a76719 100644 (file)
@@ -48,13 +48,14 @@ public:
     
 private:
     // From API::DownloadClient
-    virtual void didStart(WebProcessPool*, DownloadProxy*);
-    virtual void didReceiveResponse(WebProcessPool*, DownloadProxy*, const WebCore::ResourceResponse&);
-    virtual void didReceiveData(WebProcessPool*, DownloadProxy*, uint64_t length);
-    virtual String decideDestinationWithSuggestedFilename(WebProcessPool*, DownloadProxy*, const String& filename, bool& allowOverwriteParam);
-    virtual void didFinish(WebProcessPool*, DownloadProxy*);
-    virtual void didFail(WebProcessPool*, DownloadProxy*, const WebCore::ResourceError&);
-    virtual void didCancel(WebProcessPool*, DownloadProxy*);
+    void didStart(WebProcessPool*, DownloadProxy*) final;
+    void didReceiveResponse(WebProcessPool*, DownloadProxy*, const WebCore::ResourceResponse&) final;
+    void didReceiveData(WebProcessPool*, DownloadProxy*, uint64_t length) final;
+    String decideDestinationWithSuggestedFilename(WebProcessPool*, DownloadProxy*, const String& filename, bool& allowOverwriteParam) final;
+    void didFinish(WebProcessPool*, DownloadProxy*) final;
+    void didFail(WebProcessPool*, DownloadProxy*, const WebCore::ResourceError&) final;
+    void didCancel(WebProcessPool*, DownloadProxy*) final;
+    void willSendRequest(WebProcessPool*, DownloadProxy*, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&, WTF::Function<void(const WebCore::ResourceRequest&)>&&) final;
 
     WeakObjCPtr<id <_WKDownloadDelegate>> m_delegate;
 
@@ -66,6 +67,7 @@ private:
         bool downloadDidFinish : 1;
         bool downloadDidFail : 1;
         bool downloadDidCancel : 1;
+        bool downloadDidReceiveServerRedirectToURL : 1;
     } m_delegateMethods;
 };
 
index ea56d10..ce4c3b6 100644 (file)
@@ -31,6 +31,7 @@
 #import "_WKDownloadDelegate.h"
 #import "_WKDownloadInternal.h"
 #import "DownloadProxy.h"
+#import "WKNSURLExtras.h"
 #import <WebCore/ResourceError.h>
 #import <WebCore/ResourceResponse.h>
 
@@ -52,6 +53,7 @@ DownloadClient::DownloadClient(id <_WKDownloadDelegate> delegate)
     m_delegateMethods.downloadDidFinish = [delegate respondsToSelector:@selector(_downloadDidFinish:)];
     m_delegateMethods.downloadDidFail = [delegate respondsToSelector:@selector(_download:didFailWithError:)];
     m_delegateMethods.downloadDidCancel = [delegate respondsToSelector:@selector(_downloadDidCancel:)];
+    m_delegateMethods.downloadDidReceiveServerRedirectToURL = [delegate respondsToSelector:@selector(_download:didReceiveServerRedirectToURL:)];
 }
 
 void DownloadClient::didStart(WebProcessPool*, DownloadProxy* downloadProxy)
@@ -101,6 +103,14 @@ void DownloadClient::didCancel(WebProcessPool*, DownloadProxy* downloadProxy)
         [m_delegate.get() _downloadDidCancel:wrapper(*downloadProxy)];
 }
 
+void DownloadClient::willSendRequest(WebProcessPool*, DownloadProxy* downloadProxy, const WebCore::ResourceRequest& request, const WebCore::ResourceResponse&, WTF::Function<void(const WebCore::ResourceRequest&)>&& callback)
+{
+    if (m_delegateMethods.downloadDidReceiveServerRedirectToURL)
+        [m_delegate.get() _download:wrapper(*downloadProxy) didReceiveServerRedirectToURL:[NSURL _web_URLWithWTFString:request.url().string()]];
+
+    callback(request);
+}
+
 } // namespace WebKit
 
 #endif // WK_API_ENABLED
index a535ac2..06a38de 100644 (file)
@@ -113,8 +113,7 @@ void DownloadProxy::didReceiveAuthenticationChallenge(const AuthenticationChalle
     m_processPool->downloadClient().didReceiveAuthenticationChallenge(m_processPool.get(), this, authenticationChallengeProxy.get());
 }
 
-#if USE(NETWORK_SESSION)
-#if USE(PROTECTION_SPACE_AUTH_CALLBACK)
+#if USE(NETWORK_SESSION) && USE(PROTECTION_SPACE_AUTH_CALLBACK)
 void DownloadProxy::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace)
 {
     if (!m_processPool)
@@ -136,18 +135,21 @@ void DownloadProxy::willSendRequest(const ResourceRequest& proposedRequest, cons
         return;
 
     RefPtr<DownloadProxy> protectedThis(this);
-    m_processPool->downloadClient().willSendRequest(proposedRequest, redirectResponse, [protectedThis](const ResourceRequest& newRequest) {
+    m_processPool->downloadClient().willSendRequest(m_processPool.get(), this, proposedRequest, redirectResponse, [protectedThis](const ResourceRequest& newRequest) {
+#if USE(NETWORK_SESSION)
         if (!protectedThis->m_processPool)
             return;
-        
+
         auto* networkProcessProxy = protectedThis->m_processPool->networkProcess();
         if (!networkProcessProxy)
             return;
-        
+
         networkProcessProxy->send(Messages::NetworkProcess::ContinueWillSendRequest(protectedThis->m_downloadID, newRequest), 0);
+#else
+        UNUSED_PARAM(newRequest);
+#endif
     });
 }
-#endif
 
 void DownloadProxy::didReceiveResponse(const ResourceResponse& response)
 {
index e2ae56e..ea16af7 100644 (file)
@@ -86,11 +86,11 @@ private:
     void didFinish();
     void didFail(const WebCore::ResourceError&, const IPC::DataReference& resumeData);
     void didCancel(const IPC::DataReference& resumeData);
+    void willSendRequest(const WebCore::ResourceRequest& redirectRequest, const WebCore::ResourceResponse& redirectResponse);
 #if USE(NETWORK_SESSION)
 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
     void canAuthenticateAgainstProtectionSpace(const WebCore::ProtectionSpace&);
 #endif
-    void willSendRequest(const WebCore::ResourceRequest& redirectRequest, const WebCore::ResourceResponse& redirectResponse);
 #else
     void decideDestinationWithSuggestedFilename(const String& filename, const String& mimeType, String& destination, bool& allowOverwrite, SandboxExtension::Handle& sandboxExtensionHandle);
 #endif
index c22d099..8ca7b01 100644 (file)
@@ -23,8 +23,8 @@
 messages -> DownloadProxy {
     DidStart(WebCore::ResourceRequest request, AtomicString suggestedFilename)
     DidReceiveAuthenticationChallenge(WebCore::AuthenticationChallenge challenge, uint64_t challengeID)
-#if USE(NETWORK_SESSION)
     WillSendRequest(WebCore::ResourceRequest redirectRequest, WebCore::ResourceResponse redirectResponse))
+#if USE(NETWORK_SESSION)
 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
     CanAuthenticateAgainstProtectionSpace(WebCore::ProtectionSpace protectionSpace)
 #endif
index d41091e..013b515 100644 (file)
@@ -455,9 +455,8 @@ RetainPtr<NSMenuItem> WebContextMenuProxyMac::createContextMenuItem(const WebCon
 void WebContextMenuProxyMac::showContextMenuWithItems(const Vector<WebContextMenuItemData>& items)
 {
     auto menu = createContextMenuFromItems(items);
-    m_menu = m_page.contextMenuClient().menuFromProposedMenu(m_page, menu.get(), m_context.webHitTestResultData(), m_userData.object());
-
     [[WKMenuTarget sharedMenuTarget] setMenuProxy:this];
+    m_menu = m_page.contextMenuClient().menuFromProposedMenu(m_page, menu.get(), m_context.webHitTestResultData(), m_userData.object());
 
     NSPoint menuLocation = [m_webView convertPoint:m_context.menuLocation() toView:nil];
     NSEvent *event = [NSEvent mouseEventWithType:NSEventTypeRightMouseUp location:menuLocation modifierFlags:0 timestamp:0 windowNumber:m_webView.window.windowNumber context:nil eventNumber:0 clickCount:0 pressure:0];
index e783abd..675c00b 100644 (file)
@@ -1,3 +1,25 @@
+2017-09-07  Chris Dumez  <cdumez@apple.com>
+
+        [WK2] Notify client when downloads are redirected
+        https://bugs.webkit.org/show_bug.cgi?id=176481
+        <rdar://problem/34309065>
+
+        Reviewed by Geoffrey Garen.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/Download.mm:
+        (-[UIDownloadAsFileTestDelegate _webView:contextMenu:forElement:]):
+        (-[RedirectedDownloadDelegate _download:decideDestinationWithSuggestedFilename:allowOverwrite:]):
+        (-[RedirectedDownloadDelegate _download:didReceiveServerRedirectToURL:]):
+        (-[RedirectedDownloadDelegate _downloadDidFinish:]):
+        (TEST):
+        Add API test coverage.
+
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::createWebViewWithOptions):
+        (WTR::TestController::downloadDidReceiveServerRedirectToURL):
+        * WebKitTestRunner/TestController.h:
+        Add layout test infrastructure.
+
 2017-09-07  Per Arne Vollan  <pvollan@apple.com>
 
         [Win] fast/canvas/2d.getPath.modification.html is failing.
index 151b7b7..4762069 100644 (file)
 
 #import "PlatformUtilities.h"
 #import "Test.h"
+#import "TestProtocol.h"
+#import "TestWKWebView.h"
 #import <WebCore/FileSystem.h>
 #import <WebKit/_WKDownload.h>
 #import <WebKit/_WKDownloadDelegate.h>
 #import <WebKit/WKNavigationDelegatePrivate.h>
 #import <WebKit/WKProcessPoolPrivate.h>
+#import <WebKit/WKUIDelegatePrivate.h>
 #import <WebKit/WKWebView.h>
 #import <WebKit/WKWebViewConfiguration.h>
 #import <wtf/RetainPtr.h>
+#import <wtf/mac/AppKitCompatibilityDeclarations.h>
 #import <wtf/text/WTFString.h>
 
 static bool isDone;
+static bool hasReceivedRedirect;
 static bool hasReceivedResponse;
 static NSURL *sourceURL = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
 
@@ -422,5 +427,81 @@ TEST(_WKDownload, DownloadRequestBlobURL)
     runTest(adoptNS([[DownloadBlobURLNavigationDelegate alloc] init]).get(), adoptNS([[BlobDownloadDelegate alloc] init]).get(), originalURL);
 }
 
+@interface UIDownloadAsFileTestDelegate : NSObject <WKUIDelegatePrivate>
+@end
+
+@implementation UIDownloadAsFileTestDelegate
+
+- (NSMenu *)_webView:(WKWebView *)webView contextMenu:(NSMenu *)menu forElement:(_WKContextMenuElementInfo *)element
+{
+    static const long downloadLinkedFileTag = 2;
+    auto index = [menu indexOfItemWithTag:downloadLinkedFileTag];
+    [menu performActionForItemAtIndex:index];
+    return nil;
+}
+
+@end
+
+@interface RedirectedDownloadDelegate : NSObject <_WKDownloadDelegate>
+@end
+
+@implementation RedirectedDownloadDelegate {
+    String _destinationPath;
+}
+
+- (NSString *)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename allowOverwrite:(BOOL *)allowOverwrite
+{
+    WebCore::PlatformFileHandle fileHandle;
+    _destinationPath = WebCore::openTemporaryFile("TestWebKitAPI", fileHandle);
+    EXPECT_TRUE(fileHandle != WebCore::invalidPlatformFileHandle);
+    WebCore::closeFile(fileHandle);
+    *allowOverwrite = YES;
+    return _destinationPath;
+}
+
+- (void)_download:(_WKDownload *)download didReceiveServerRedirectToURL:(NSURL *)url
+{
+    EXPECT_STREQ("http://pass/", [url.absoluteString UTF8String]);
+    hasReceivedRedirect = true;
+}
+
+- (void)_downloadDidFinish:(_WKDownload *)download
+{
+    WebCore::deleteFile(_destinationPath);
+    isDone = true;
+}
+
+@end
+
+TEST(_WKDownload, RedirectedDownload)
+{
+    [TestProtocol registerWithScheme:@"http"];
+
+    hasReceivedRedirect = false;
+    isDone = false;
+
+    auto delegate = adoptNS([[UIDownloadAsFileTestDelegate alloc] init]);
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
+    [webView setUIDelegate:delegate.get()];
+    auto downloadDelegate = adoptNS([[RedirectedDownloadDelegate alloc] init]);
+    [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
+
+    auto window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered defer:YES]);
+    [[window contentView] addSubview:webView.get()];
+
+    [webView synchronouslyLoadHTMLString:@"<a style='display: block; height: 100%; width: 100%' href='http://redirect/?pass'>test</a>"];
+
+    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]];
+
+    isDone = false;
+    TestWebKitAPI::Util::run(&isDone);
+    EXPECT_TRUE(hasReceivedRedirect);
+
+    [TestProtocol unregister];
+}
+
 #endif
 #endif
index 7aab8e6..c7464e7 100644 (file)
@@ -596,8 +596,8 @@ void TestController::createWebViewWithOptions(const TestOptions& options)
     };
     WKPageSetPageNavigationClient(m_mainWebView->page(), &pageNavigationClient.base);
 
-    WKContextDownloadClientV0 downloadClient = {
-        { 0, this },
+    WKContextDownloadClientV1 downloadClient = {
+        { 1, this },
         downloadDidStart,
         0, // didReceiveAuthenticationChallenge
         0, // didReceiveResponse
@@ -608,7 +608,8 @@ void TestController::createWebViewWithOptions(const TestOptions& options)
         downloadDidFinish,
         downloadDidFail,
         downloadDidCancel,
-        0 // processDidCrash;
+        0, // processDidCrash;
+        downloadDidReceiveServerRedirectToURL
     };
     WKContextSetDownloadClient(context(), &downloadClient.base);
     
@@ -1730,6 +1731,11 @@ void TestController::downloadDidCancel(WKContextRef context, WKDownloadRef downl
     static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidCancel(context, download);
 }
 
+void TestController::downloadDidReceiveServerRedirectToURL(WKContextRef context, WKDownloadRef download, WKURLRef url, const void* clientInfo)
+{
+    static_cast<TestController*>(const_cast<void*>(clientInfo))->downloadDidReceiveServerRedirectToURL(context, download, url);
+}
+
 void TestController::downloadDidStart(WKContextRef context, WKDownloadRef download)
 {
     if (m_shouldLogDownloadCallbacks)
@@ -1767,6 +1773,18 @@ void TestController::downloadDidFinish(WKContextRef, WKDownloadRef)
     m_currentInvocation->notifyDownloadDone();
 }
 
+void TestController::downloadDidReceiveServerRedirectToURL(WKContextRef, WKDownloadRef, WKURLRef url)
+{
+    if (m_shouldLogDownloadCallbacks) {
+        StringBuilder builder;
+        builder.appendLiteral("Download was redirected to \"");
+        WKRetainPtr<WKStringRef> urlStringWK = adoptWK(WKURLCopyString(url));
+        builder.append(toSTD(urlStringWK).c_str());
+        builder.appendLiteral("\".\n");
+        m_currentInvocation->outputText(builder.toString());
+    }
+}
+
 void TestController::downloadDidFail(WKContextRef, WKDownloadRef, WKErrorRef error)
 {
     if (m_shouldLogDownloadCallbacks) {
index 97c1d08..eec0892 100644 (file)
@@ -266,6 +266,8 @@ private:
     void downloadDidFail(WKContextRef, WKDownloadRef, WKErrorRef);
     static void downloadDidCancel(WKContextRef, WKDownloadRef, const void*);
     void downloadDidCancel(WKContextRef, WKDownloadRef);
+    static void downloadDidReceiveServerRedirectToURL(WKContextRef, WKDownloadRef, WKURLRef, const void*);
+    void downloadDidReceiveServerRedirectToURL(WKContextRef, WKDownloadRef, WKURLRef);
     
     static void processDidCrash(WKPageRef, const void* clientInfo);
     void processDidCrash();