Title: [244086] trunk
Revision
244086
Author
[email protected]
Date
2019-04-09 11:19:59 -0700 (Tue, 09 Apr 2019)

Log Message

Pick up Ad Click Attribution conversions in NetworkResourceLoader::willSendRedirectedRequest()
https://bugs.webkit.org/show_bug.cgi?id=196558
<rdar://problem/47650245>

Reviewed by Youenn Fablet.

Source/WebCore:

Tests: http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect.html
       http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority.html
       http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority.html

The existing API tests were expanded too.

* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::parseAdClickAttribution const):
   Enhanced the use of AdClickAttribution::MaxEntropy.
* loader/AdClickAttribution.cpp:
(WebCore::AdClickAttribution::parseConversionRequest):
    New function to parse and validate URLs with a path starting with
    /.well-known/ad-click-attribution/.
(WebCore::AdClickAttribution::toString const):
    Added output for the conversion priority for testing purposes.
* loader/AdClickAttribution.h:
(WebCore::AdClickAttribution::Campaign::isValid const):
(WebCore::AdClickAttribution::Conversion::isValid const):
   Enhanced the use of AdClickAttribution::MaxEntropy.

Source/WebKit:

So called pixel requests have traditionally been used to send ad click
attribution data to click sources. The privacy implications of such
pixel requests are severe which is in part why browsers have started to
block cookies from being sent in such third-party requests.

To allow for a smooth transition to more privacy-friendly ad click
attribution, we should allow servers to make a redirect to
https://click-source.example/.well-known/ad-click-attribution/ to
trigger a so called conversion.

This patch checks for the well-known location in the path component of
the redirect URL. If the request indeed goes to the well-known location,
we parse the conversion data and send it to the storage in the network
session.

* NetworkProcess/NetworkAdClickAttribution.cpp:
(WebKit::NetworkAdClickAttribution::convert):
    Reporting function.
* NetworkProcess/NetworkAdClickAttribution.h:
* NetworkProcess/NetworkResourceLoader.cpp:
(WebKit::NetworkResourceLoader::willSendRedirectedRequest):
    Now checks for the well-known location through a call to
    WebCore::AdClickAttribution::parseConversionRequest().
* NetworkProcess/NetworkSession.cpp:
(WebKit::NetworkSession::convertAdClickAttribution):
    Piping to WebKit::NetworkAdClickAttribution::convert().
* NetworkProcess/NetworkSession.h:

Tools:

* TestWebKitAPI/Tests/WebCore/AdClickAttribution.cpp:
(TestWebKitAPI::TEST):
    Added tests of WebCore::AdClickAttribution::parseConversionRequest().

LayoutTests:

* http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt:
   Enhanced the use of AdClickAttribution::MaxEntropy.
* http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect-expected.txt: Added.
* http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect.html: Added.
* http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority-expected.txt: Added.
* http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority.html: Added.
* http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority-expected.txt: Added.
* http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority.html: Added.
* http/tests/adClickAttribution/resources/redirectToConversion.php: Added.
* http/tests/adClickAttribution/resources/redirectToConversionOnIPAddress.php: Added.
* platform/ios-wk2/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt:
   Enhanced the use of AdClickAttribution::MaxEntropy.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (244085 => 244086)


--- trunk/LayoutTests/ChangeLog	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/LayoutTests/ChangeLog	2019-04-09 18:19:59 UTC (rev 244086)
@@ -1,3 +1,24 @@
+2019-04-09  John Wilander  <[email protected]>
+
+        Pick up Ad Click Attribution conversions in NetworkResourceLoader::willSendRedirectedRequest()
+        https://bugs.webkit.org/show_bug.cgi?id=196558
+        <rdar://problem/47650245>
+
+        Reviewed by Youenn Fablet.
+
+        * http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt:
+           Enhanced the use of AdClickAttribution::MaxEntropy.
+        * http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect-expected.txt: Added.
+        * http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect.html: Added.
+        * http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority-expected.txt: Added.
+        * http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority.html: Added.
+        * http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority-expected.txt: Added.
+        * http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority.html: Added.
+        * http/tests/adClickAttribution/resources/redirectToConversion.php: Added.
+        * http/tests/adClickAttribution/resources/redirectToConversionOnIPAddress.php: Added.
+        * platform/ios-wk2/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt:
+           Enhanced the use of AdClickAttribution::MaxEntropy.
+
 2019-04-09  Shawn Roberts  <[email protected]>
 
         inspector/canvas/css-canvas-clients.html is a flaky failure

Modified: trunk/LayoutTests/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt (244085 => 244086)


--- trunk/LayoutTests/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/LayoutTests/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt	2019-04-09 18:19:59 UTC (rev 244086)
@@ -1,5 +1,5 @@
-CONSOLE MESSAGE: line 165: adcampaignid must have a non-negative value less than 64 for Ad Click Attribution.
-CONSOLE MESSAGE: line 165: adcampaignid must have a non-negative value less than 64 for Ad Click Attribution.
+CONSOLE MESSAGE: line 165: adcampaignid must have a non-negative value less than or equal to 63 for Ad Click Attribution.
+CONSOLE MESSAGE: line 165: adcampaignid must have a non-negative value less than or equal to 63 for Ad Click Attribution.
 CONSOLE MESSAGE: line 165: adcampaignid can not be converted to a non-negative integer which is required for Ad Click Attribution.
 CONSOLE MESSAGE: line 165: adcampaignid can not be converted to a non-negative integer which is required for Ad Click Attribution.
 CONSOLE MESSAGE: line 165: adcampaignid can not be converted to a non-negative integer which is required for Ad Click Attribution.

Added: trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect-expected.txt (0 => 244086)


--- trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect-expected.txt	2019-04-09 18:19:59 UTC (rev 244086)
@@ -0,0 +1,8 @@
+Tests that triggering of ad click attribution conversions through cross-site redirects do not work.
+
+
+WebCore::AdClickAttribution 1
+Source: 127.0.0.1
+Destination: localhost
+Campaign ID: 3
+No conversion data.

Added: trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect.html (0 => 244086)


--- trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect.html	2019-04-09 18:19:59 UTC (rev 244086)
@@ -0,0 +1,55 @@
+<!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=""
+</head>
+<body _onload_="setTimeout(runTest, 0)">
+<div id="description">Tests that triggering of ad click attribution conversions through cross-site redirects do not work.</div>
+<a id="targetLink" href="" adcampaignid="3" addestination="http://localhost:8000">Link</a><br>
+<div id="output"></div>
+<script>
+    if (window.testRunner) {
+        testRunner.waitUntilDone();
+        testRunner.dumpAsText();
+        testRunner.setAllowsAnySSLCertificate(true);
+    }
+
+    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.";
+                testRunner.notifyDone();
+            }
+        );
+    }
+
+    function runTest() {
+        if (window.testRunner) {
+            if (window.location.search === "?stepTwo") {
+                let imageElement = document.createElement("img");
+                imageElement.src = ""
+                imageElement.id = "pixel";
+                imageElement._onerror_ = function(e) {
+                    testRunner.dumpAdClickAttribution();
+                    document.body.removeChild(document.getElementById("targetLink"));
+                    document.body.removeChild(document.getElementById("pixel"));
+                    testRunner.notifyDone();
+                };
+                document.body.appendChild(imageElement);
+            } else {
+                activateElement("targetLink");
+            }
+        } else {
+            document.getElementById("output").innerText = "FAIL No testRunner.";
+        }
+    }
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority-expected.txt (0 => 244086)


--- trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority-expected.txt	2019-04-09 18:19:59 UTC (rev 244086)
@@ -0,0 +1,9 @@
+Tests triggering of ad click attribution conversions with priority.
+
+
+WebCore::AdClickAttribution 1
+Source: 127.0.0.1
+Destination: localhost
+Campaign ID: 3
+Conversion data: 12
+Conversion priority: 3

Added: trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority.html (0 => 244086)


--- trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority.html	2019-04-09 18:19:59 UTC (rev 244086)
@@ -0,0 +1,55 @@
+<!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=""
+</head>
+<body _onload_="setTimeout(runTest, 0)">
+<div id="description">Tests triggering of ad click attribution conversions with priority.</div>
+<a id="targetLink" href="" adcampaignid="3" addestination="http://localhost:8000">Link</a><br>
+<div id="output"></div>
+<script>
+    if (window.testRunner) {
+        testRunner.waitUntilDone();
+        testRunner.dumpAsText();
+        testRunner.setAllowsAnySSLCertificate(true);
+    }
+
+    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.";
+                testRunner.notifyDone();
+            }
+        );
+    }
+
+    function runTest() {
+        if (window.testRunner) {
+            if (window.location.search === "?stepTwo") {
+                let imageElement = document.createElement("img");
+                imageElement.src = ""
+                imageElement.id = "pixel";
+                imageElement._onerror_ = function(e) {
+                    testRunner.dumpAdClickAttribution();
+                    document.body.removeChild(document.getElementById("targetLink"));
+                    document.body.removeChild(document.getElementById("pixel"));
+                    testRunner.notifyDone();
+                };
+                document.body.appendChild(imageElement);
+            } else {
+                activateElement("targetLink");
+            }
+        } else {
+            document.getElementById("output").innerText = "FAIL No testRunner.";
+        }
+    }
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority-expected.txt (0 => 244086)


--- trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority-expected.txt	2019-04-09 18:19:59 UTC (rev 244086)
@@ -0,0 +1,9 @@
+Tests triggering of ad click attribution conversions without priority.
+
+
+WebCore::AdClickAttribution 1
+Source: 127.0.0.1
+Destination: localhost
+Campaign ID: 3
+Conversion data: 12
+Conversion priority: 0

Added: trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority.html (0 => 244086)


--- trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority.html	2019-04-09 18:19:59 UTC (rev 244086)
@@ -0,0 +1,55 @@
+<!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=""
+</head>
+<body _onload_="setTimeout(runTest, 0)">
+<div id="description">Tests triggering of ad click attribution conversions without priority.</div>
+<a id="targetLink" href="" adcampaignid="3" addestination="http://localhost:8000">Link</a><br>
+<div id="output"></div>
+<script>
+    if (window.testRunner) {
+        testRunner.waitUntilDone();
+        testRunner.dumpAsText();
+        testRunner.setAllowsAnySSLCertificate(true);
+    }
+
+    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.";
+                testRunner.notifyDone();
+            }
+        );
+    }
+
+    function runTest() {
+        if (window.testRunner) {
+            if (window.location.search === "?stepTwo") {
+                let imageElement = document.createElement("img");
+                imageElement.src = ""
+                imageElement.id = "pixel";
+                imageElement._onerror_ = function() {
+                    testRunner.dumpAdClickAttribution();
+                    document.body.removeChild(document.getElementById("targetLink"));
+                    document.body.removeChild(document.getElementById("pixel"));
+                    testRunner.notifyDone();
+                };
+                document.body.appendChild(imageElement);
+            } else {
+                activateElement("targetLink");
+            }
+        } else {
+            document.getElementById("output").innerText = "FAIL No testRunner.";
+        }
+    }
+</script>
+</body>
+</html>

Added: trunk/LayoutTests/http/tests/adClickAttribution/resources/redirectToConversion.php (0 => 244086)


--- trunk/LayoutTests/http/tests/adClickAttribution/resources/redirectToConversion.php	                        (rev 0)
+++ trunk/LayoutTests/http/tests/adClickAttribution/resources/redirectToConversion.php	2019-04-09 18:19:59 UTC (rev 244086)
@@ -0,0 +1,8 @@
+<?php
+header("HTTP/1.0 302 Found");
+if (isset($_GET["conversionData"]) && isset($_GET["priority"])) {
+  header("Location: /.well-known/ad-click-attribution/" . $_GET["conversionData"] . "/" . $_GET["priority"]);
+} else if (isset($_GET["conversionData"])) {
+  header("Location: /.well-known/ad-click-attribution/" . $_GET["conversionData"]);
+}
+?>

Added: trunk/LayoutTests/http/tests/adClickAttribution/resources/redirectToConversionOnIPAddress.php (0 => 244086)


--- trunk/LayoutTests/http/tests/adClickAttribution/resources/redirectToConversionOnIPAddress.php	                        (rev 0)
+++ trunk/LayoutTests/http/tests/adClickAttribution/resources/redirectToConversionOnIPAddress.php	2019-04-09 18:19:59 UTC (rev 244086)
@@ -0,0 +1,8 @@
+<?php
+header("HTTP/1.0 302 Found");
+if (isset($_GET["conversionData"]) && isset($_GET["priority"])) {
+  header("Location: https://127.0.0.1:8000/.well-known/ad-click-attribution/" . $_GET["conversionData"] . "/" . $_GET["priority"]);
+} else if (isset($_GET["conversionData"])) {
+  header("Location: https://127.0.0.1:8000/.well-known/ad-click-attribution/" . $_GET["conversionData"]);
+}
+?>

Modified: trunk/LayoutTests/platform/ios-wk2/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt (244085 => 244086)


--- trunk/LayoutTests/platform/ios-wk2/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/LayoutTests/platform/ios-wk2/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt	2019-04-09 18:19:59 UTC (rev 244086)
@@ -1,5 +1,5 @@
-CONSOLE MESSAGE: adcampaignid must have a non-negative value less than 64 for Ad Click Attribution.
-CONSOLE MESSAGE: adcampaignid must have a non-negative value less than 64 for Ad Click Attribution.
+CONSOLE MESSAGE: adcampaignid must have a non-negative value less than or equal to 63 for Ad Click Attribution.
+CONSOLE MESSAGE: adcampaignid must have a non-negative value less than or equal to 63 for Ad Click Attribution.
 CONSOLE MESSAGE: adcampaignid can not be converted to a non-negative integer which is required for Ad Click Attribution.
 CONSOLE MESSAGE: adcampaignid can not be converted to a non-negative integer which is required for Ad Click Attribution.
 CONSOLE MESSAGE: adcampaignid can not be converted to a non-negative integer which is required for Ad Click Attribution.

Modified: trunk/Source/WebCore/ChangeLog (244085 => 244086)


--- trunk/Source/WebCore/ChangeLog	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Source/WebCore/ChangeLog	2019-04-09 18:19:59 UTC (rev 244086)
@@ -1,3 +1,31 @@
+2019-04-09  John Wilander  <[email protected]>
+
+        Pick up Ad Click Attribution conversions in NetworkResourceLoader::willSendRedirectedRequest()
+        https://bugs.webkit.org/show_bug.cgi?id=196558
+        <rdar://problem/47650245>
+
+        Reviewed by Youenn Fablet.
+
+        Tests: http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect.html
+               http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority.html
+               http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority.html
+
+        The existing API tests were expanded too.
+
+        * html/HTMLAnchorElement.cpp:
+        (WebCore::HTMLAnchorElement::parseAdClickAttribution const):
+           Enhanced the use of AdClickAttribution::MaxEntropy.
+        * loader/AdClickAttribution.cpp:
+        (WebCore::AdClickAttribution::parseConversionRequest):
+            New function to parse and validate URLs with a path starting with
+            /.well-known/ad-click-attribution/.
+        (WebCore::AdClickAttribution::toString const):
+            Added output for the conversion priority for testing purposes.
+        * loader/AdClickAttribution.h:
+        (WebCore::AdClickAttribution::Campaign::isValid const):
+        (WebCore::AdClickAttribution::Conversion::isValid const):
+           Enhanced the use of AdClickAttribution::MaxEntropy.
+
 2019-04-09  Don Olmstead  <[email protected]>
 
         [CMake] Apple builds should use ICU_INCLUDE_DIRS

Modified: trunk/Source/WebCore/html/HTMLAnchorElement.cpp (244085 => 244086)


--- trunk/Source/WebCore/html/HTMLAnchorElement.cpp	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Source/WebCore/html/HTMLAnchorElement.cpp	2019-04-09 18:19:59 UTC (rev 244086)
@@ -431,8 +431,8 @@
         return WTF::nullopt;
     }
     
-    if (adCampaignID.value() >= AdClickAttribution::MaxEntropy) {
-        document().addConsoleMessage(MessageSource::Other, MessageLevel::Warning, makeString("adcampaignid must have a non-negative value less than ", AdClickAttribution::MaxEntropy, " for Ad Click Attribution."));
+    if (adCampaignID.value() > AdClickAttribution::MaxEntropy) {
+        document().addConsoleMessage(MessageSource::Other, MessageLevel::Warning, makeString("adcampaignid must have a non-negative value less than or equal to ", AdClickAttribution::MaxEntropy, " for Ad Click Attribution."));
         return WTF::nullopt;
     }
 

Modified: trunk/Source/WebCore/loader/AdClickAttribution.cpp (244085 => 244086)


--- trunk/Source/WebCore/loader/AdClickAttribution.cpp	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Source/WebCore/loader/AdClickAttribution.cpp	2019-04-09 18:19:59 UTC (rev 244086)
@@ -29,9 +29,14 @@
 #include <wtf/RandomNumber.h>
 #include <wtf/URL.h>
 #include <wtf/text/StringBuilder.h>
+#include <wtf/text/StringView.h>
 
 namespace WebCore {
 
+static const char adClickAttributionPathPrefix[] = "/.well-known/ad-click-attribution/";
+const size_t adClickConversionDataPathSegmentSize = 2;
+const size_t adClickPriorityPathSegmentSize = 2;
+
 bool AdClickAttribution::isValid() const
 {
     return m_conversion
@@ -42,6 +47,39 @@
         && m_earliestTimeToSend;
 }
 
+Optional<AdClickAttribution::Conversion> AdClickAttribution::parseConversionRequest(const URL& redirectURL)
+{
+    if (!redirectURL.protocolIs("https"_s) || redirectURL.hasUsername() || redirectURL.hasPassword() || redirectURL.hasQuery() || redirectURL.hasFragment())
+        return { };
+
+    auto path = StringView(redirectURL.string()).substring(redirectURL.pathStart(), redirectURL.pathEnd() - redirectURL.pathStart());
+    if (path.isEmpty() || !path.startsWith(adClickAttributionPathPrefix))
+        return { };
+
+    auto prefixLength = sizeof(adClickAttributionPathPrefix) - 1;
+    if (path.length() == prefixLength + adClickConversionDataPathSegmentSize) {
+        auto conversionDataUInt64 = path.substring(prefixLength, adClickConversionDataPathSegmentSize).toUInt64Strict();
+        if (!conversionDataUInt64 || *conversionDataUInt64 > MaxEntropy)
+            return { };
+
+        return Conversion { static_cast<uint32_t>(*conversionDataUInt64), Priority { 0 } };
+    }
+    
+    if (path.length() == prefixLength + adClickConversionDataPathSegmentSize + 1 + adClickPriorityPathSegmentSize) {
+        auto conversionDataUInt64 = path.substring(prefixLength, adClickConversionDataPathSegmentSize).toUInt64Strict();
+        if (!conversionDataUInt64 || *conversionDataUInt64 > MaxEntropy)
+            return { };
+
+        auto conversionPriorityUInt64 = path.substring(prefixLength + adClickConversionDataPathSegmentSize + 1, adClickPriorityPathSegmentSize).toUInt64Strict();
+        if (!conversionPriorityUInt64 || *conversionPriorityUInt64 > MaxEntropy)
+            return { };
+
+        return Conversion { static_cast<uint32_t>(*conversionDataUInt64), Priority { static_cast<uint32_t>(*conversionPriorityUInt64) } };
+    }
+
+    return { };
+}
+
 void AdClickAttribution::setConversion(Conversion&& conversion)
 {
     if (!conversion.isValid() || (m_conversion && m_conversion->priority > conversion.priority))
@@ -102,6 +140,8 @@
     if (m_conversion) {
         builder.appendLiteral("\nConversion data: ");
         builder.appendNumber(m_conversion.value().data);
+        builder.appendLiteral("\nConversion priority: ");
+        builder.appendNumber(m_conversion.value().priority);
     } else
         builder.appendLiteral("\nNo conversion data.");
     builder.append('\n');

Modified: trunk/Source/WebCore/loader/AdClickAttribution.h (244085 => 244086)


--- trunk/Source/WebCore/loader/AdClickAttribution.h	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Source/WebCore/loader/AdClickAttribution.h	2019-04-09 18:19:59 UTC (rev 244086)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "RegistrableDomain.h"
+#include <wtf/CompletionHandler.h>
 #include <wtf/Optional.h>
 #include <wtf/URL.h>
 #include <wtf/WallTime.h>
@@ -40,7 +41,7 @@
     using ConversionData = uint32_t;
     using PriorityValue = uint32_t;
 
-    static constexpr uint32_t MaxEntropy = 64;
+    static constexpr uint32_t MaxEntropy = 63;
 
     struct Campaign {
         Campaign() = default;
@@ -51,7 +52,7 @@
         
         bool isValid() const
         {
-            return id < MaxEntropy;
+            return id <= MaxEntropy;
         }
         
         CampaignId id { 0 };
@@ -210,7 +211,7 @@
 
         bool isValid() const
         {
-            return data < MaxEntropy && priority < MaxEntropy;
+            return data <= MaxEntropy && priority <= MaxEntropy;
         }
         
         ConversionData data;
@@ -229,6 +230,7 @@
     {
     }
 
+    WEBCORE_EXPORT static Optional<Conversion> parseConversionRequest(const URL& redirectURL);
     WEBCORE_EXPORT void setConversion(Conversion&&);
     WEBCORE_EXPORT URL url() const;
     WEBCORE_EXPORT URL referrer() const;

Modified: trunk/Source/WebKit/ChangeLog (244085 => 244086)


--- trunk/Source/WebKit/ChangeLog	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Source/WebKit/ChangeLog	2019-04-09 18:19:59 UTC (rev 244086)
@@ -1,3 +1,39 @@
+2019-04-09  John Wilander  <[email protected]>
+
+        Pick up Ad Click Attribution conversions in NetworkResourceLoader::willSendRedirectedRequest()
+        https://bugs.webkit.org/show_bug.cgi?id=196558
+        <rdar://problem/47650245>
+
+        Reviewed by Youenn Fablet.
+
+        So called pixel requests have traditionally been used to send ad click
+        attribution data to click sources. The privacy implications of such
+        pixel requests are severe which is in part why browsers have started to
+        block cookies from being sent in such third-party requests.
+
+        To allow for a smooth transition to more privacy-friendly ad click
+        attribution, we should allow servers to make a redirect to
+        https://click-source.example/.well-known/ad-click-attribution/ to
+        trigger a so called conversion.
+
+        This patch checks for the well-known location in the path component of
+        the redirect URL. If the request indeed goes to the well-known location,
+        we parse the conversion data and send it to the storage in the network
+        session.
+
+        * NetworkProcess/NetworkAdClickAttribution.cpp:
+        (WebKit::NetworkAdClickAttribution::convert):
+            Reporting function.
+        * NetworkProcess/NetworkAdClickAttribution.h:
+        * NetworkProcess/NetworkResourceLoader.cpp:
+        (WebKit::NetworkResourceLoader::willSendRedirectedRequest):
+            Now checks for the well-known location through a call to
+            WebCore::AdClickAttribution::parseConversionRequest().
+        * NetworkProcess/NetworkSession.cpp:
+        (WebKit::NetworkSession::convertAdClickAttribution):
+            Piping to WebKit::NetworkAdClickAttribution::convert().
+        * NetworkProcess/NetworkSession.h:
+
 2019-04-09  Chris Dumez  <[email protected]>
 
         [iOS] WebContent processes should be marked as "Foreground Running" when their view is visible

Modified: trunk/Source/WebKit/NetworkProcess/NetworkAdClickAttribution.cpp (244085 => 244086)


--- trunk/Source/WebKit/NetworkProcess/NetworkAdClickAttribution.cpp	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Source/WebKit/NetworkProcess/NetworkAdClickAttribution.cpp	2019-04-09 18:19:59 UTC (rev 244086)
@@ -31,10 +31,12 @@
 
 namespace WebKit {
 
+using RegistrableDomain = WebCore::RegistrableDomain;
 using AdClickAttribution = WebCore::AdClickAttribution;
 using Source = WebCore::AdClickAttribution::Source;
 using Destination = WebCore::AdClickAttribution::Destination;
 using DestinationMap = HashMap<Destination, AdClickAttribution>;
+using Conversion = WebCore::AdClickAttribution::Conversion;
 
 DestinationMap& NetworkAdClickAttribution::ensureDestinationMapForSource(const Source& source)
 {
@@ -49,6 +51,19 @@
     destinationMapForSource.add(adClickAttribution.destination(), WTFMove(adClickAttribution));
 }
 
+void NetworkAdClickAttribution::convert(const Source& source, const Destination& destination, Conversion&& conversion)
+{
+    auto sourceIter = m_adClickAttributionMap.find(source);
+    if (sourceIter == m_adClickAttributionMap.end())
+        return;
+
+    auto destinationIter = sourceIter->value.find(destination);
+    if (destinationIter == sourceIter->value.end())
+        return;
+
+    destinationIter->value.setConversion(WTFMove(conversion));
+}
+
 void NetworkAdClickAttribution::clear(CompletionHandler<void()>&& completionHandler)
 {
     m_adClickAttributionMap.clear();

Modified: trunk/Source/WebKit/NetworkProcess/NetworkAdClickAttribution.h (244085 => 244086)


--- trunk/Source/WebKit/NetworkProcess/NetworkAdClickAttribution.h	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Source/WebKit/NetworkProcess/NetworkAdClickAttribution.h	2019-04-09 18:19:59 UTC (rev 244086)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include <WebCore/AdClickAttribution.h>
+#include <WebCore/RegistrableDomain.h>
 #include <wtf/CompletionHandler.h>
 #include <wtf/HashMap.h>
 #include <wtf/text/WTFString.h>
@@ -35,17 +36,20 @@
 class NetworkAdClickAttribution {
 public:
 
+    using RegistrableDomain = WebCore::RegistrableDomain;
     using AdClickAttribution = WebCore::AdClickAttribution;
     using Source = WebCore::AdClickAttribution::Source;
     using Destination = WebCore::AdClickAttribution::Destination;
     using DestinationMap = HashMap<Destination, AdClickAttribution>;
+    using Conversion = WebCore::AdClickAttribution::Conversion;
 
     void store(AdClickAttribution&&);
+    void convert(const Source&, const Destination&, Conversion&&);
     void clear(CompletionHandler<void()>&&);
     void toString(CompletionHandler<void(String)>&&) const;
 
 private:
-    DestinationMap& ensureDestinationMapForSource(const AdClickAttribution::Source&);
+    DestinationMap& ensureDestinationMapForSource(const Source&);
 
     HashMap<Source, DestinationMap> m_adClickAttributionMap;
 };

Modified: trunk/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp (244085 => 244086)


--- trunk/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp	2019-04-09 18:19:59 UTC (rev 244086)
@@ -41,6 +41,7 @@
 #include "WebPageMessages.h"
 #include "WebResourceLoaderMessages.h"
 #include "WebsiteDataStoreParameters.h"
+#include <WebCore/AdClickAttribution.h>
 #include <WebCore/BlobDataFileReference.h>
 #include <WebCore/CertificateInfo.h>
 #include <WebCore/ContentSecurityPolicy.h>
@@ -583,6 +584,16 @@
 {
     ++m_redirectCount;
 
+    auto& redirectURL = redirectRequest.url();
+    if (auto adClickConversion = AdClickAttribution::parseConversionRequest(redirectURL)) {
+        RegistrableDomain redirectDomain { redirectURL };
+        auto& firstPartyURL = redirectRequest.firstPartyForCookies();
+        NetworkSession* networkSession;
+        // The redirect has to be done by the same registrable domain and it has to be a third-party request.
+        if (redirectDomain.matches(request.url()) && !redirectDomain.matches(firstPartyURL) && (networkSession = m_connection->networkProcess().networkSession(sessionID())))
+            networkSession->convertAdClickAttribution(AdClickAttribution::Source { WTFMove(redirectDomain) }, AdClickAttribution::Destination { firstPartyURL }, WTFMove(*adClickConversion));
+    }
+
     auto maxAgeCap = validateCacheEntryForMaxAgeCapValidation(request, redirectRequest, redirectResponse);
     if (redirectResponse.source() == ResourceResponse::Source::Network && canUseCachedRedirect(request))
         m_cache->storeRedirect(request, redirectResponse, redirectRequest, maxAgeCap);

Modified: trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp (244085 => 244086)


--- trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp	2019-04-09 18:19:59 UTC (rev 244086)
@@ -32,7 +32,6 @@
 #include "WebPageProxy.h"
 #include "WebPageProxyMessages.h"
 #include "WebProcessProxy.h"
-#include <WebCore/AdClickAttribution.h>
 #include <WebCore/CookieJar.h>
 #include <WebCore/NetworkStorageSession.h>
 
@@ -141,6 +140,11 @@
     m_adClickAttribution->store(WTFMove(adClickAttribution));
 }
 
+void NetworkSession::convertAdClickAttribution(const WebCore::AdClickAttribution::Source& source, const WebCore::AdClickAttribution::Destination& destination, WebCore::AdClickAttribution::Conversion&& conversion)
+{
+    m_adClickAttribution->convert(source, destination, WTFMove(conversion));
+}
+
 void NetworkSession::dumpAdClickAttribution(CompletionHandler<void(String)>&& completionHandler)
 {
     m_adClickAttribution->toString(WTFMove(completionHandler));

Modified: trunk/Source/WebKit/NetworkProcess/NetworkSession.h (244085 => 244086)


--- trunk/Source/WebKit/NetworkProcess/NetworkSession.h	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Source/WebKit/NetworkProcess/NetworkSession.h	2019-04-09 18:19:59 UTC (rev 244086)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "WebResourceLoadStatisticsStore.h"
+#include <WebCore/AdClickAttribution.h>
 #include <WebCore/RegistrableDomain.h>
 #include <pal/SessionID.h>
 #include <wtf/HashSet.h>
@@ -37,7 +38,6 @@
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
-class AdClickAttribution;
 class NetworkStorageSession;
 enum class IncludeHttpOnlyCookies : bool;
 enum class ShouldSample : bool;
@@ -80,6 +80,7 @@
     void notifyPageStatisticsTelemetryFinished(unsigned totalPrevalentResources, unsigned totalPrevalentResourcesWithUserInteraction, unsigned top3SubframeUnderTopFrameOrigins);
 #endif
     void storeAdClickAttribution(WebCore::AdClickAttribution&&);
+    void convertAdClickAttribution(const WebCore::AdClickAttribution::Source&, const WebCore::AdClickAttribution::Destination&, WebCore::AdClickAttribution::Conversion&&);
     void dumpAdClickAttribution(CompletionHandler<void(String)>&&);
     void clearAdClickAttribution(CompletionHandler<void()>&&);
 

Modified: trunk/Tools/ChangeLog (244085 => 244086)


--- trunk/Tools/ChangeLog	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Tools/ChangeLog	2019-04-09 18:19:59 UTC (rev 244086)
@@ -1,3 +1,15 @@
+2019-04-09  John Wilander  <[email protected]>
+
+        Pick up Ad Click Attribution conversions in NetworkResourceLoader::willSendRedirectedRequest()
+        https://bugs.webkit.org/show_bug.cgi?id=196558
+        <rdar://problem/47650245>
+
+        Reviewed by Youenn Fablet.
+
+        * TestWebKitAPI/Tests/WebCore/AdClickAttribution.cpp:
+        (TestWebKitAPI::TEST):
+            Added tests of WebCore::AdClickAttribution::parseConversionRequest().
+
 2019-04-09  Don Olmstead  <[email protected]>
 
         [CMake] Apple builds should use ICU_INCLUDE_DIRS

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/AdClickAttribution.cpp (244085 => 244086)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/AdClickAttribution.cpp	2019-04-09 18:08:27 UTC (rev 244085)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/AdClickAttribution.cpp	2019-04-09 18:19:59 UTC (rev 244086)
@@ -34,7 +34,6 @@
 namespace TestWebKitAPI {
 
 constexpr uint32_t min6BitValue { 0 };
-constexpr uint32_t max6BitValue { 63 };
 
 const URL webKitURL { { }, "https://webkit.org"_s };
 const URL exampleURL { { }, "https://example.com"_s };
@@ -68,8 +67,8 @@
 
 TEST(AdClickAttribution, ValidMaxValues)
 {
-    AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
-    attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue)));
+    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
+    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
 
     auto attributionURL = attribution.url();
     auto referrerURL = attribution.referrer();
@@ -80,20 +79,56 @@
 
 TEST(AdClickAttribution, EarliestTimeToSendAttributionMinimumDelay)
 {
-    AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
+    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
     auto now = WallTime::now();
-    attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue)));
+    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
     auto earliestTimeToSend = attribution.earliestTimeToSend();
     ASSERT_TRUE(earliestTimeToSend);
     ASSERT_TRUE(earliestTimeToSend.value().secondsSinceEpoch() - 24_h >= now.secondsSinceEpoch());
 }
 
+TEST(AdClickAttribution, ValidConversionURLs)
+{
+    const URL conversionURLWithoutPriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22"_s };
+    auto optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithoutPriority);
+    ASSERT_TRUE(optionalConversion);
+    ASSERT_EQ(optionalConversion->data, (uint32_t)22);
+
+    const URL conversionURLWithoutPriorityMaxEntropy { { }, "https://webkit.org/.well-known/ad-click-attribution/63"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithoutPriorityMaxEntropy);
+    ASSERT_TRUE(optionalConversion);
+    ASSERT_EQ(optionalConversion->data, (uint32_t)63);
+    
+    const URL conversionURLWithoutPriorityAndLeadingZero { { }, "https://webkit.org/.well-known/ad-click-attribution/02"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithoutPriorityAndLeadingZero);
+    ASSERT_TRUE(optionalConversion);
+    ASSERT_EQ(optionalConversion->data, (uint32_t)2);
+
+    const URL conversionURLWithPriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithPriority);
+    ASSERT_TRUE(optionalConversion);
+    ASSERT_EQ(optionalConversion->data, (uint32_t)22);
+    ASSERT_EQ(optionalConversion->priority, (uint32_t)12);
+
+    const URL conversionURLWithPriorityMaxEntropy { { }, "https://webkit.org/.well-known/ad-click-attribution/63/63"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithPriorityMaxEntropy);
+    ASSERT_TRUE(optionalConversion);
+    ASSERT_EQ(optionalConversion->data, (uint32_t)63);
+    ASSERT_EQ(optionalConversion->priority, (uint32_t)63);
+    
+    const URL conversionURLWithPriorityAndLeadingZero { { }, "https://webkit.org/.well-known/ad-click-attribution/22/02"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithPriorityAndLeadingZero);
+    ASSERT_TRUE(optionalConversion);
+    ASSERT_EQ(optionalConversion->data, (uint32_t)22);
+    ASSERT_EQ(optionalConversion->priority, (uint32_t)2);
+}
+
 // Negative test cases.
 
 TEST(AdClickAttribution, InvalidCampaignId)
 {
-    AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue + 1), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
-    attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue)));
+    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy + 1), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
+    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
 
     auto attributionURL = attribution.url();
     auto referrerURL = attribution.referrer();
@@ -104,8 +139,8 @@
 
 TEST(AdClickAttribution, InvalidSourceHost)
 {
-    AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { emptyURL }, AdClickAttribution::Destination { exampleURL } };
-    attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue)));
+    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { emptyURL }, AdClickAttribution::Destination { exampleURL } };
+    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
 
     auto attributionURL = attribution.url();
     auto referrerURL = attribution.referrer();
@@ -116,8 +151,8 @@
 
 TEST(AdClickAttribution, InvalidDestinationHost)
 {
-    AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue + 1), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { emptyURL } };
-    attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue)));
+    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy + 1), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { emptyURL } };
+    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
 
     auto attributionURL = attribution.url();
     auto referrerURL = attribution.referrer();
@@ -128,8 +163,8 @@
 
 TEST(AdClickAttribution, InvalidConversionData)
 {
-    AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
-    attribution.setConversion(AdClickAttribution::Conversion((max6BitValue + 1), AdClickAttribution::Priority(max6BitValue)));
+    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
+    attribution.setConversion(AdClickAttribution::Conversion((AdClickAttribution::MaxEntropy + 1), AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
 
     auto attributionURL = attribution.url();
     auto referrerURL = attribution.referrer();
@@ -140,8 +175,8 @@
 
 TEST(AdClickAttribution, InvalidPriority)
 {
-    AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
-    attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue + 1)));
+    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
+    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy + 1)));
 
     auto attributionURL = attribution.url();
     auto referrerURL = attribution.referrer();
@@ -152,7 +187,7 @@
 
 TEST(AdClickAttribution, InvalidMissingConversion)
 {
-    AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
+    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
 
     auto attributionURL = attribution.url();
     auto referrerURL = attribution.referrer();
@@ -162,4 +197,106 @@
     ASSERT_FALSE(attribution.earliestTimeToSend());
 }
 
+TEST(AdClickAttribution, InvalidConversionURLs)
+{
+    const URL conversionURLWithSingleDigitConversionData { { }, "https://webkit.org/.well-known/ad-click-attribution/2"_s };
+    auto optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithSingleDigitConversionData);
+    ASSERT_FALSE(optionalConversion);
+    
+    const URL conversionURLWithNonNumeralConversionData { { }, "https://webkit.org/.well-known/ad-click-attribution/2s"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithNonNumeralConversionData);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithNegativeConversionData { { }, "https://webkit.org/.well-known/ad-click-attribution/-2"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithNegativeConversionData);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithTooLargeConversionData { { }, "https://webkit.org/.well-known/ad-click-attribution/64"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTooLargeConversionData);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithSingleDigitPriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22/2"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithSingleDigitPriority);
+    ASSERT_FALSE(optionalConversion);
+    
+    const URL conversionURLWithNonNumeralPriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22/2s"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithNonNumeralPriority);
+    ASSERT_FALSE(optionalConversion);
+    
+    const URL conversionURLWithNegativePriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22/-2"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithNegativePriority);
+    ASSERT_FALSE(optionalConversion);
+    
+    const URL conversionURLWithTooLargePriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22/64"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTooLargePriority);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithTooLargeConversionDataAndPriority { { }, "https://webkit.org/.well-known/ad-click-attribution/64/22"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTooLargeConversionDataAndPriority);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithTooLargeConversionDataAndTooLargePriority { { }, "https://webkit.org/.well-known/ad-click-attribution/64/64"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTooLargeConversionDataAndTooLargePriority);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithExtraLeadingSlash = { { }, "https://webkit.org/.well-known/ad-click-attribution//22/12"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithExtraLeadingSlash);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithExtraTrailingSlash = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12/"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithExtraTrailingSlash);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithTrailingQuestionMark = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12?"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTrailingQuestionMark);
+    ASSERT_FALSE(optionalConversion);
+}
+
+TEST(AdClickAttribution, InvalidConversionWithDisallowedURLComponents)
+{
+    // Protocol.
+    const URL conversionURLWithHttpProtocol { { }, "http://webkit.org/.well-known/ad-click-attribution/2"_s };
+    auto optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithHttpProtocol);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithWssProtocol { { }, "wss://webkit.org/.well-known/ad-click-attribution/2"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithWssProtocol);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithFileProtocol { { }, "file:///.well-known/ad-click-attribution/2"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithFileProtocol);
+    ASSERT_FALSE(optionalConversion);
+
+    // Username and password.
+    const URL conversionURLWithUserName { { }, "https://[email protected]/.well-known/ad-click-attribution/2"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithUserName);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithPassword = { { }, "https://:[email protected]/.well-known/ad-click-attribution/22/12?"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithPassword);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithUsernameAndPassword = { { }, "https://user:[email protected]/.well-known/ad-click-attribution/22/12?"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithUsernameAndPassword);
+    ASSERT_FALSE(optionalConversion);
+
+    // Query string.
+    const URL conversionURLWithTrailingQuestionMark = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12?"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTrailingQuestionMark);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithQueryString = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12?extra=data"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithQueryString);
+    ASSERT_FALSE(optionalConversion);
+    
+    // Fragment.
+    const URL conversionURLWithTrailingHash = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12#"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTrailingHash);
+    ASSERT_FALSE(optionalConversion);
+
+    const URL conversionURLWithFragment = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12#fragment"_s };
+    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithFragment);
+    ASSERT_FALSE(optionalConversion);
+}
+
 } // namespace TestWebKitAPI
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to