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