Title: [222308] trunk
Revision
222308
Author
[email protected]
Date
2017-09-20 19:48:38 -0700 (Wed, 20 Sep 2017)

Log Message

[WK2] Add API to get the redirect chain of a WKDownload
https://bugs.webkit.org/show_bug.cgi?id=176628
<rdar://problem/34338279>

Reviewed by Alex Christensen.

Source/WebKit:

Add API to get the redirect chain of a WKDwnload. The redirect chain includes redirects
that happened during initial load, before the load was converted into a download.

* UIProcess/API/C/WKDownload.cpp:
(WKDownloadCopyRedirectChain):
* UIProcess/API/C/WKDownload.h:
* UIProcess/API/Cocoa/_WKDownload.h:
* UIProcess/API/Cocoa/_WKDownload.mm:
(-[_WKDownload originatingWebView]):
(-[_WKDownload redirectChain]):
* UIProcess/Downloads/DownloadProxy.cpp:
(WebKit::DownloadProxy::willSendRequest):
* UIProcess/Downloads/DownloadProxy.h:
(WebKit::DownloadProxy::setRedirectChain):
(WebKit::DownloadProxy::redirectChain const):
* UIProcess/WebFrameProxy.cpp:
(WebKit::WebFrameProxy::didStartProvisionalLoad):
(WebKit::WebFrameProxy::didReceiveServerRedirectForProvisionalLoad):
* UIProcess/WebFrameProxy.h:
(WebKit::WebFrameProxy::redirectChain const):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::receivedPolicyDecision):

Tools:

Add API test coverage for the 2 cases:
1. Download started as a download and is redirected while
   downloading.
2. Download started as a load and was redirected during the
   initial load.

* TestWebKitAPI/Tests/WebKitCocoa/Download.mm:
(-[RedirectedDownloadDelegate _download:didReceiveServerRedirectToURL:]):
(-[RedirectedDownloadDelegate _downloadDidFinish:]):
(TEST):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (222307 => 222308)


--- trunk/Source/WebKit/ChangeLog	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Source/WebKit/ChangeLog	2017-09-21 02:48:38 UTC (rev 222308)
@@ -1,3 +1,34 @@
+2017-09-20  Chris Dumez  <[email protected]>
+
+        [WK2] Add API to get the redirect chain of a WKDownload
+        https://bugs.webkit.org/show_bug.cgi?id=176628
+        <rdar://problem/34338279>
+
+        Reviewed by Alex Christensen.
+
+        Add API to get the redirect chain of a WKDwnload. The redirect chain includes redirects
+        that happened during initial load, before the load was converted into a download.
+
+        * UIProcess/API/C/WKDownload.cpp:
+        (WKDownloadCopyRedirectChain):
+        * UIProcess/API/C/WKDownload.h:
+        * UIProcess/API/Cocoa/_WKDownload.h:
+        * UIProcess/API/Cocoa/_WKDownload.mm:
+        (-[_WKDownload originatingWebView]):
+        (-[_WKDownload redirectChain]):
+        * UIProcess/Downloads/DownloadProxy.cpp:
+        (WebKit::DownloadProxy::willSendRequest):
+        * UIProcess/Downloads/DownloadProxy.h:
+        (WebKit::DownloadProxy::setRedirectChain):
+        (WebKit::DownloadProxy::redirectChain const):
+        * UIProcess/WebFrameProxy.cpp:
+        (WebKit::WebFrameProxy::didStartProvisionalLoad):
+        (WebKit::WebFrameProxy::didReceiveServerRedirectForProvisionalLoad):
+        * UIProcess/WebFrameProxy.h:
+        (WebKit::WebFrameProxy::redirectChain const):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::receivedPolicyDecision):
+
 2017-09-20  Alex Christensen  <[email protected]>
 
         Add infrastructure for adding custom headers to requests per website

Modified: trunk/Source/WebKit/UIProcess/API/C/WKDownload.cpp (222307 => 222308)


--- trunk/Source/WebKit/UIProcess/API/C/WKDownload.cpp	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Source/WebKit/UIProcess/API/C/WKDownload.cpp	2017-09-21 02:48:38 UTC (rev 222308)
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "WKDownload.h"
 
+#include "APIArray.h"
 #include "APIData.h"
 #include "APIURLRequest.h"
 #include "DownloadProxy.h"
@@ -63,3 +64,13 @@
 {
     return toAPI(toImpl(download)->originatingPage());
 }
+
+WKArrayRef WKDownloadCopyRedirectChain(WKDownloadRef download)
+{
+    auto& redirectChain =  toImpl(download)->redirectChain();
+    Vector<RefPtr<API::Object>> urls;
+    urls.reserveInitialCapacity(redirectChain.size());
+    for (auto& redirectURL : redirectChain)
+        urls.uncheckedAppend(API::URL::create(redirectURL.string()));
+    return toAPI(&API::Array::create(WTFMove(urls)).leakRef());
+}

Modified: trunk/Source/WebKit/UIProcess/API/C/WKDownload.h (222307 => 222308)


--- trunk/Source/WebKit/UIProcess/API/C/WKDownload.h	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Source/WebKit/UIProcess/API/C/WKDownload.h	2017-09-21 02:48:38 UTC (rev 222308)
@@ -43,6 +43,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);
 
 #ifdef __cplusplus
 }

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.h (222307 => 222308)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.h	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.h	2017-09-21 02:48:38 UTC (rev 222308)
@@ -38,6 +38,7 @@
 
 @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));
 
 @end
 

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.mm (222307 => 222308)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.mm	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.mm	2017-09-21 02:48:38 UTC (rev 222308)
@@ -58,7 +58,15 @@
     if (auto* originatingPage = _download->originatingPage())
         return [[fromWebPageProxy(*originatingPage) retain] autorelease];
     return nil;
+}
 
+-(NSArray<NSURL *> *)redirectChain
+{
+    auto& redirectURLs = _download->redirectChain();
+    NSMutableArray<NSURL *> *nsURLs = [NSMutableArray arrayWithCapacity:redirectURLs.size()];
+    for (const auto& redirectURL : redirectURLs)
+        [nsURLs addObject:(NSURL *)redirectURL];
+    return nsURLs;
 }
 
 #pragma mark WKObject protocol implementation

Modified: trunk/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp (222307 => 222308)


--- trunk/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp	2017-09-21 02:48:38 UTC (rev 222308)
@@ -107,6 +107,9 @@
     m_request = request;
     m_suggestedFilename = suggestedFilename;
 
+    if (m_redirectChain.isEmpty() || m_redirectChain.last() != request.url())
+        m_redirectChain.append(request.url());
+
     if (!m_processPool)
         return;
 
@@ -144,8 +147,9 @@
     if (!m_processPool)
         return;
 
-    RefPtr<DownloadProxy> protectedThis(this);
-    m_processPool->downloadClient().willSendRequest(m_processPool.get(), this, proposedRequest, redirectResponse, [protectedThis](const ResourceRequest& newRequest) {
+    m_processPool->downloadClient().willSendRequest(m_processPool.get(), this, proposedRequest, redirectResponse, [this, protectedThis = makeRef(*this)](const ResourceRequest& newRequest) {
+        m_redirectChain.append(newRequest.url());
+
 #if USE(NETWORK_SESSION)
         if (!protectedThis->m_processPool)
             return;
@@ -155,8 +159,6 @@
             return;
 
         networkProcessProxy->send(Messages::NetworkProcess::ContinueWillSendRequest(protectedThis->m_downloadID, newRequest), 0);
-#else
-        UNUSED_PARAM(newRequest);
 #endif
     });
 }

Modified: trunk/Source/WebKit/UIProcess/Downloads/DownloadProxy.h (222307 => 222308)


--- trunk/Source/WebKit/UIProcess/Downloads/DownloadProxy.h	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Source/WebKit/UIProcess/Downloads/DownloadProxy.h	2017-09-21 02:48:38 UTC (rev 222308)
@@ -44,6 +44,7 @@
 class ProtectionSpace;
 class ResourceError;
 class ResourceResponse;
+class URL;
 }
 
 namespace WebKit {
@@ -73,6 +74,9 @@
     WebPageProxy* originatingPage() const;
     void setOriginatingPage(WebPageProxy*);
 
+    void setRedirectChain(Vector<WebCore::URL>&& redirectChain) { m_redirectChain = WTFMove(redirectChain); }
+    const Vector<WebCore::URL>& redirectChain() const { return m_redirectChain; }
+
 private:
     explicit DownloadProxy(DownloadProxyMap&, WebProcessPool&, const WebCore::ResourceRequest&);
 
@@ -109,6 +113,7 @@
     String m_suggestedFilename;
 
     WeakPtr<WebPageProxy> m_originatingPage;
+    Vector<WebCore::URL> m_redirectChain;
 };
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/UIProcess/WebFrameProxy.cpp (222307 => 222308)


--- trunk/Source/WebKit/UIProcess/WebFrameProxy.cpp	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Source/WebKit/UIProcess/WebFrameProxy.cpp	2017-09-21 02:48:38 UTC (rev 222308)
@@ -132,11 +132,18 @@
 
 void WebFrameProxy::didStartProvisionalLoad(const URL& url)
 {
+    ASSERT(m_provisionalLoadRedirectChain.isEmpty());
+    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);
 }
 
@@ -158,11 +165,13 @@
 
 void WebFrameProxy::didFinishLoad()
 {
+    m_provisionalLoadRedirectChain.clear();
     m_frameLoadState.didFinishLoad();
 }
 
 void WebFrameProxy::didFailLoad()
 {
+    m_provisionalLoadRedirectChain.clear();
     m_frameLoadState.didFailLoad();
 }
 

Modified: trunk/Source/WebKit/UIProcess/WebFrameProxy.h (222307 => 222308)


--- trunk/Source/WebKit/UIProcess/WebFrameProxy.h	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Source/WebKit/UIProcess/WebFrameProxy.h	2017-09-21 02:48:38 UTC (rev 222308)
@@ -90,6 +90,7 @@
     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(); }
 
@@ -142,7 +143,7 @@
     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

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (222307 => 222308)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2017-09-21 02:48:38 UTC (rev 222308)
@@ -2278,6 +2278,8 @@
     if (action == PolicyDownload) {
         // Create a download proxy.
         auto* download = m_process->processPool().createDownloadProxy(m_decidePolicyForResponseRequest, this);
+        download->setRedirectChain(frame.takeProvisionalLoadRedirectChain());
+
         downloadID = download->downloadID();
         handleDownloadRequest(download);
         m_decidePolicyForResponseRequest = { };

Modified: trunk/Tools/ChangeLog (222307 => 222308)


--- trunk/Tools/ChangeLog	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Tools/ChangeLog	2017-09-21 02:48:38 UTC (rev 222308)
@@ -1,3 +1,22 @@
+2017-09-20  Chris Dumez  <[email protected]>
+
+        [WK2] Add API to get the redirect chain of a WKDownload
+        https://bugs.webkit.org/show_bug.cgi?id=176628
+        <rdar://problem/34338279>
+
+        Reviewed by Alex Christensen.
+
+        Add API test coverage for the 2 cases:
+        1. Download started as a download and is redirected while
+           downloading.
+        2. Download started as a load and was redirected during the
+           initial load.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/Download.mm:
+        (-[RedirectedDownloadDelegate _download:didReceiveServerRedirectToURL:]):
+        (-[RedirectedDownloadDelegate _downloadDidFinish:]):
+        (TEST):
+
 2017-09-20  Alex Christensen  <[email protected]>
 
         Add infrastructure for adding custom headers to requests per website

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/Download.mm (222307 => 222308)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/Download.mm	2017-09-21 01:34:12 UTC (rev 222307)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/Download.mm	2017-09-21 02:48:38 UTC (rev 222308)
@@ -46,7 +46,7 @@
 #import <wtf/text/WTFString.h>
 
 static bool isDone;
-static bool hasReceivedRedirect;
+static unsigned redirectCount = 0;
 static bool hasReceivedResponse;
 static NSURL *sourceURL = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
 static WKWebView* expectedOriginatingWebView;
@@ -468,12 +468,24 @@
 
 - (void)_download:(_WKDownload *)download didReceiveServerRedirectToURL:(NSURL *)url
 {
-    EXPECT_STREQ("http://pass/", [url.absoluteString UTF8String]);
-    hasReceivedRedirect = true;
+    if (!redirectCount)
+        EXPECT_STREQ("http://redirect/?pass", [url.absoluteString UTF8String]);
+    else
+        EXPECT_STREQ("http://pass/", [url.absoluteString UTF8String]);
+    ++redirectCount = true;
 }
 
 - (void)_downloadDidFinish:(_WKDownload *)download
 {
+    NSArray<NSURL *> *redirectChain = download.redirectChain;
+    EXPECT_EQ(3U, redirectChain.count);
+    if (redirectChain.count > 0)
+        EXPECT_STREQ("http://redirect/?redirect/?pass", [redirectChain[0].absoluteString UTF8String]);
+    if (redirectChain.count > 1)
+        EXPECT_STREQ("http://redirect/?pass", [redirectChain[1].absoluteString UTF8String]);
+    if (redirectChain.count > 2)
+        EXPECT_STREQ("http://pass/", [redirectChain[2].absoluteString UTF8String]);
+
     WebCore::deleteFile(_destinationPath);
     isDone = true;
 }
@@ -484,7 +496,7 @@
 {
     [TestProtocol registerWithScheme:@"http"];
 
-    hasReceivedRedirect = false;
+    redirectCount = 0;
     isDone = false;
 
     auto delegate = adoptNS([[UIDownloadAsFileTestDelegate alloc] init]);
@@ -497,7 +509,9 @@
     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=''>test</a>"];
+    // Do 2 loads in the same view to make sure the redirect chain is properly cleared between loads.
+    [webView synchronouslyLoadHTMLString:@"<div>First load</div>"];
+    [webView synchronouslyLoadHTMLString:@"<a style='display: block; height: 100%; width: 100%' href=''>test</a>"];
 
     expectedOriginatingWebView = webView.get();
     NSPoint clickPoint = NSMakePoint(100, 100);
@@ -506,10 +520,54 @@
 
     isDone = false;
     TestWebKitAPI::Util::run(&isDone);
-    EXPECT_TRUE(hasReceivedRedirect);
+    EXPECT_EQ(1U, redirectCount);
 
     [TestProtocol unregister];
 }
 
+TEST(_WKDownload, RedirectedLoadConvertedToDownload)
+{
+    [TestProtocol registerWithScheme:@"http"];
+
+    auto navigationDelegate = adoptNS([[ConvertResponseToDownloadNavigationDelegate alloc] init]);
+    auto downloadDelegate = adoptNS([[RedirectedDownloadDelegate alloc] init]);
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+    [webView setNavigationDelegate:navigationDelegate.get()];
+    [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
+
+    expectedOriginatingWebView = webView.get();
+    isDone = false;
+    redirectCount = 0;
+    hasReceivedResponse = false;
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://redirect/?redirect/?pass"]]];
+    TestWebKitAPI::Util::run(&isDone);
+    EXPECT_EQ(0U, redirectCount);
+
+    [TestProtocol unregister];
+}
+
+TEST(_WKDownload, RedirectedSubframeLoadConvertedToDownload)
+{
+    [TestProtocol registerWithScheme:@"http"];
+
+    auto navigationDelegate = adoptNS([[ConvertResponseToDownloadNavigationDelegate alloc] init]);
+    auto downloadDelegate = adoptNS([[RedirectedDownloadDelegate alloc] init]);
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
+    [webView setNavigationDelegate:navigationDelegate.get()];
+    [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
+
+    expectedOriginatingWebView = webView.get();
+    isDone = false;
+    redirectCount = 0;
+    hasReceivedResponse = false;
+    [webView loadHTMLString:@"<body><iframe src=''></iframe></body>" baseURL:nil];
+    TestWebKitAPI::Util::run(&isDone);
+    EXPECT_EQ(0U, redirectCount);
+
+    [TestProtocol unregister];
+}
+
 #endif
 #endif
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to