PCM: Accept ad click data when the link opens a new window
https://bugs.webkit.org/show_bug.cgi?id=214176
<rdar://problem/65358005>

Reviewed by Brent Fulgham.

A link with the attribute target="_blank" takes another code path for
navigation which involves the creation of a new window and webpage. That
code path needs to transfer ad click attribution data to the new webpage
Source/WebKit:

where it can be picked up in WebPageProxy::didCommitLoadForFrame().
The ad click attribution data sits in the NavigationAction which is not
available in the completion handler WebPageProxy::createNewPage().
The client, which differs between TestRunner and e.g. Safari, consumes
the NavigationAction. I don't want to risk a regression in e.g. Safari
while still passing the test because TestRunner hasn't regressed.

Test: http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window.html

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::didCommitLoadForFrame):
    Now also checks for pending ad click attribution data in its new
    member variable m_newPageNavigationAdClickAttribution.
(WebKit::WebPageProxy::createNewPage):
    Now forwards optional ad click attribution data to the completion
    handler where it can be stored on the newly created webpage in the
    new member variable m_newPageNavigationAdClickAttribution.
* UIProcess/WebPageProxy.h:
    Added m_newPageNavigationAdClickAttribution.
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::createWindow):
    Added missing navigationAction.adClickAttribution() copy.
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNewWindowAction):
    Added missing navigationAction.adClickAttribution() copy.

LayoutTests:

where it can be picked up.

* http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window-expected.txt: Added.
* http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window.html: Added.
* http/tests/adClickAttribution/resources/convertAndPostMessageBack.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@269129 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 8a06a3d..c8fa9c3 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,20 @@
+2020-10-28  John Wilander  <wilander@apple.com>
+
+        PCM: Accept ad click data when the link opens a new window
+        https://bugs.webkit.org/show_bug.cgi?id=214176
+        <rdar://problem/65358005>
+
+        Reviewed by Brent Fulgham.
+
+        A link with the attribute target="_blank" takes another code path for
+        navigation which involves the creation of a new window and webpage. That
+        code path needs to transfer ad click attribution data to the new webpage
+        where it can be picked up.
+
+        * http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window-expected.txt: Added.
+        * http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window.html: Added.
+        * http/tests/adClickAttribution/resources/convertAndPostMessageBack.html: Added.
+
 2020-10-28  Truitt Savell  <tsavell@apple.com>
 
         Rebase for fast/forms/input-appearance-spinbutton.html on Catalina after changes in r269036
diff --git a/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window-expected.txt b/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window-expected.txt
new file mode 100644
index 0000000..38436b0
--- /dev/null
+++ b/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window-expected.txt
@@ -0,0 +1,12 @@
+Tests triggering of ad click attribution conversions in a new window.
+
+
+Converted Ad Click Attributions:
+WebCore::AdClickAttribution 1
+Source: 127.0.0.1
+Destination: localhost
+Campaign ID: 3
+Conversion data: 12
+Conversion priority: 3
+Conversion earliest time to send: Within 24-48 hours
+Conversion request sent: false
diff --git a/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window.html b/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window.html
new file mode 100644
index 0000000..989dcd1
--- /dev/null
+++ b/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AdClickAttributionEnabled=true ] -->
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
+    <script src="/js-test-resources/ui-helper.js"></script>
+    <script src="resources/util.js"></script>
+</head>
+<body onload="setTimeout(runTest, 0)">
+<div id="description">Tests triggering of ad click attribution conversions in a new window.</div>
+<a target="_blank" rel="opener" id="targetLink" href="http://localhost:8000/adClickAttribution/resources/convertAndPostMessageBack.html" adcampaignid="3" addestination="http://localhost:8000">Link</a><br>
+<div id="output"></div>
+<script>
+    prepareTest();
+
+    function activateElement(elementID) {
+        var element = document.getElementById(elementID);
+        var centerX = element.offsetLeft + element.offsetWidth / 2;
+        var centerY = element.offsetTop + element.offsetHeight / 2;
+        UIHelper.activateAt(centerX, centerY).then(
+            function () {
+            },
+            function () {
+                document.getElementById("output").innerText = "FAIL Promise rejected.";
+                tearDownAndFinish();
+            }
+        );
+    }
+
+    function receiveMessage(event) {
+        if (event.origin === "http://localhost:8000") {
+            if (event.data === "Done") {
+                testRunner.dumpAdClickAttribution();
+                document.body.removeChild(document.getElementById("targetLink"));
+                tearDownAndFinish();
+            } else {
+                testFailed("Received unknown message: " + event.data);
+                tearDownAndFinish();
+            }
+        } else {
+            testFailed("Received a message from an unexpected origin: " + event.origin);
+            tearDownAndFinish();
+        }
+    }
+
+    window.addEventListener("message", receiveMessage, false);
+
+    function runTest() {
+        if (window.testRunner) {
+            testRunner.setCanOpenWindows();
+            activateElement("targetLink");
+        } else {
+            document.getElementById("output").innerText = "FAIL No testRunner.";
+            tearDownAndFinish();
+        }
+    }
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/adClickAttribution/resources/convertAndPostMessageBack.html b/LayoutTests/http/tests/adClickAttribution/resources/convertAndPostMessageBack.html
new file mode 100644
index 0000000..24835a7
--- /dev/null
+++ b/LayoutTests/http/tests/adClickAttribution/resources/convertAndPostMessageBack.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <script>
+        function fireConversionPixel() {
+            let imageElement = document.createElement("img");
+            imageElement.src = "https://127.0.0.1:8443/adClickAttribution/resources/redirectToConversion.php?conversionData=12&priority=03";
+            imageElement.id = "pixel";
+            imageElement.onerror = function() {
+                document.body.removeChild(document.getElementById("pixel"));
+                postMessageBack();
+            };
+            document.body.appendChild(imageElement);
+        }
+
+        function postMessageBack() {
+            if (window.opener) {
+                window.opener.postMessage("Done", "http://127.0.0.1:8000");
+                window.close();
+            }
+        }
+    </script>
+</head>
+<body onload="setTimeout(fireConversionPixel, 0)">
+</body>
+</html>
\ No newline at end of file
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index ad67a67..acf88b4 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,40 @@
+2020-10-28  John Wilander  <wilander@apple.com>
+
+        PCM: Accept ad click data when the link opens a new window
+        https://bugs.webkit.org/show_bug.cgi?id=214176
+        <rdar://problem/65358005>
+
+        Reviewed by Brent Fulgham.
+
+        A link with the attribute target="_blank" takes another code path for
+        navigation which involves the creation of a new window and webpage. That
+        code path needs to transfer ad click attribution data to the new webpage
+        where it can be picked up in WebPageProxy::didCommitLoadForFrame().
+        The ad click attribution data sits in the NavigationAction which is not
+        available in the completion handler WebPageProxy::createNewPage().
+        The client, which differs between TestRunner and e.g. Safari, consumes
+        the NavigationAction. I don't want to risk a regression in e.g. Safari
+        while still passing the test because TestRunner hasn't regressed.
+
+        Test: http/tests/adClickAttribution/attribution-conversion-through-image-redirect-in-new-window.html
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::didCommitLoadForFrame):
+            Now also checks for pending ad click attribution data in its new
+            member variable m_newPageNavigationAdClickAttribution.
+        (WebKit::WebPageProxy::createNewPage):
+            Now forwards optional ad click attribution data to the completion
+            handler where it can be stored on the newly created webpage in the
+            new member variable m_newPageNavigationAdClickAttribution.
+        * UIProcess/WebPageProxy.h:
+            Added m_newPageNavigationAdClickAttribution.
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::createWindow):
+            Added missing navigationAction.adClickAttribution() copy.
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNewWindowAction):
+            Added missing navigationAction.adClickAttribution() copy.
+
 2020-10-28  Said Abou-Hallawa  <said@apple.com>
 
         [GPU Process] Eagerly flush the PutImageData item to the GPU Process
diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp
index 9a2aa80..2617fdf 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.cpp
+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp
@@ -4651,12 +4651,18 @@
 
     frame->didCommitLoad(mimeType, webCertificateInfo, containsPluginDocument);
 
-    if (navigation && frame->isMainFrame()) {
-        if (auto& adClickAttribution = navigation->adClickAttribution()) {
+    if (frame->isMainFrame()) {
+        Optional<WebCore::AdClickAttribution> adClickAttribution;
+        if (m_newPageNavigationAdClickAttribution)
+            adClickAttribution = m_newPageNavigationAdClickAttribution;
+        else if (navigation && navigation->adClickAttribution())
+            adClickAttribution = navigation->adClickAttribution();
+        if (adClickAttribution) {
             if (adClickAttribution->destination().matches(frame->url()))
                 websiteDataStore().networkProcess().send(Messages::NetworkProcess::StoreAdClickAttribution(m_websiteDataStore->sessionID(), *adClickAttribution), 0);
         }
     }
+    m_newPageNavigationAdClickAttribution.reset();
 
     if (frame->isMainFrame()) {
         m_mainFrameHasCustomContentProvider = frameHasCustomContentProvider;
@@ -5518,7 +5524,7 @@
     auto* originatingPage = m_process->webPage(originatingPageID);
     auto originatingFrameInfo = API::FrameInfo::create(WTFMove(originatingFrameInfoData), originatingPage);
     auto mainFrameURL = m_mainFrame ? m_mainFrame->url() : URL();
-    auto completionHandler = [this, protectedThis = makeRef(*this), mainFrameURL, request, reply = WTFMove(reply)] (RefPtr<WebPageProxy> newPage) mutable {
+    auto completionHandler = [this, protectedThis = makeRef(*this), mainFrameURL, request, reply = WTFMove(reply), adClickAttribution = navigationActionData.adClickAttribution] (RefPtr<WebPageProxy> newPage) mutable {
         if (!newPage) {
             reply(WTF::nullopt, WTF::nullopt);
             return;
@@ -5530,6 +5536,7 @@
 
         newPage->m_shouldSuppressAppLinksInNextNavigationPolicyDecision = mainFrameURL.host() == request.url().host();
 
+        newPage->m_newPageNavigationAdClickAttribution = adClickAttribution;
 #if HAVE(APP_SSO)
         newPage->m_shouldSuppressSOAuthorizationInNextNavigationPolicyDecision = true;
 #endif
diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h
index d4694f0..bdf11ba 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.h
+++ b/Source/WebKit/UIProcess/WebPageProxy.h
@@ -2885,6 +2885,8 @@
     bool m_canUseCredentialStorage { true };
 
     size_t m_suspendMediaPlaybackCounter { 0 };
+
+    Optional<WebCore::AdClickAttribution> m_newPageNavigationAdClickAttribution;
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
index 2979ae0..1cd7ad7 100644
--- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
@@ -267,6 +267,7 @@
     navigationActionData.canHandleRequest = m_page.canHandleRequest(navigationAction.resourceRequest());
     navigationActionData.shouldOpenExternalURLsPolicy = navigationAction.shouldOpenExternalURLsPolicy();
     navigationActionData.downloadAttribute = navigationAction.downloadAttribute();
+    navigationActionData.adClickAttribution = navigationAction.adClickAttribution();
 
     WebFrame* webFrame = WebFrame::fromCoreFrame(frame);
 
diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
index 66afdfc..975fd89 100644
--- a/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
@@ -879,6 +879,7 @@
     navigationActionData.canHandleRequest = webPage->canHandleRequest(request);
     navigationActionData.shouldOpenExternalURLsPolicy = navigationAction.shouldOpenExternalURLsPolicy();
     navigationActionData.downloadAttribute = navigationAction.downloadAttribute();
+    navigationActionData.adClickAttribution = navigationAction.adClickAttribution();
 
     webPage->send(Messages::WebPageProxy::DecidePolicyForNewWindowAction(m_frame->frameID(), m_frame->info(), identifier, navigationActionData, request,
         frameName, listenerID, UserData(WebProcess::singleton().transformObjectsToHandles(userData.get()).get())));