⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 244086 in webkit


Ignore:
Timestamp:
Apr 9, 2019, 11:19:59 AM (7 years ago)
Author:
wilander@apple.com
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.

Location:
trunk
Files:
9 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r244084 r244086  
     12019-04-09  John Wilander  <wilander@apple.com>
     2
     3        Pick up Ad Click Attribution conversions in NetworkResourceLoader::willSendRedirectedRequest()
     4        https://bugs.webkit.org/show_bug.cgi?id=196558
     5        <rdar://problem/47650245>
     6
     7        Reviewed by Youenn Fablet.
     8
     9        * http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt:
     10           Enhanced the use of AdClickAttribution::MaxEntropy.
     11        * http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect-expected.txt: Added.
     12        * http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect.html: Added.
     13        * http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority-expected.txt: Added.
     14        * http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority.html: Added.
     15        * http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority-expected.txt: Added.
     16        * http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority.html: Added.
     17        * http/tests/adClickAttribution/resources/redirectToConversion.php: Added.
     18        * http/tests/adClickAttribution/resources/redirectToConversionOnIPAddress.php: Added.
     19        * platform/ios-wk2/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt:
     20           Enhanced the use of AdClickAttribution::MaxEntropy.
     21
    1222019-04-09  Shawn Roberts  <sroberts@apple.com>
    223
  • trunk/LayoutTests/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt

    r243262 r244086  
    1 CONSOLE MESSAGE: line 165: adcampaignid must have a non-negative value less than 64 for Ad Click Attribution.
    2 CONSOLE MESSAGE: line 165: adcampaignid must have a non-negative value less than 64 for Ad Click Attribution.
     1CONSOLE MESSAGE: line 165: adcampaignid must have a non-negative value less than or equal to 63 for Ad Click Attribution.
     2CONSOLE MESSAGE: line 165: adcampaignid must have a non-negative value less than or equal to 63 for Ad Click Attribution.
    33CONSOLE MESSAGE: line 165: adcampaignid can not be converted to a non-negative integer which is required for Ad Click Attribution.
    44CONSOLE MESSAGE: line 165: adcampaignid can not be converted to a non-negative integer which is required for Ad Click Attribution.
  • trunk/LayoutTests/platform/ios-wk2/http/tests/adClickAttribution/anchor-tag-attributes-validation-expected.txt

    r241490 r244086  
    1 CONSOLE MESSAGE: adcampaignid must have a non-negative value less than 64 for Ad Click Attribution.
    2 CONSOLE MESSAGE: adcampaignid must have a non-negative value less than 64 for Ad Click Attribution.
     1CONSOLE MESSAGE: adcampaignid must have a non-negative value less than or equal to 63 for Ad Click Attribution.
     2CONSOLE MESSAGE: adcampaignid must have a non-negative value less than or equal to 63 for Ad Click Attribution.
    33CONSOLE MESSAGE: adcampaignid can not be converted to a non-negative integer which is required for Ad Click Attribution.
    44CONSOLE MESSAGE: adcampaignid can not be converted to a non-negative integer which is required for Ad Click Attribution.
  • trunk/Source/WebCore/ChangeLog

    r244081 r244086  
     12019-04-09  John Wilander  <wilander@apple.com>
     2
     3        Pick up Ad Click Attribution conversions in NetworkResourceLoader::willSendRedirectedRequest()
     4        https://bugs.webkit.org/show_bug.cgi?id=196558
     5        <rdar://problem/47650245>
     6
     7        Reviewed by Youenn Fablet.
     8
     9        Tests: http/tests/adClickAttribution/attribution-conversion-through-cross-site-image-redirect.html
     10               http/tests/adClickAttribution/attribution-conversion-through-image-redirect-with-priority.html
     11               http/tests/adClickAttribution/attribution-conversion-through-image-redirect-without-priority.html
     12
     13        The existing API tests were expanded too.
     14
     15        * html/HTMLAnchorElement.cpp:
     16        (WebCore::HTMLAnchorElement::parseAdClickAttribution const):
     17           Enhanced the use of AdClickAttribution::MaxEntropy.
     18        * loader/AdClickAttribution.cpp:
     19        (WebCore::AdClickAttribution::parseConversionRequest):
     20            New function to parse and validate URLs with a path starting with
     21            /.well-known/ad-click-attribution/.
     22        (WebCore::AdClickAttribution::toString const):
     23            Added output for the conversion priority for testing purposes.
     24        * loader/AdClickAttribution.h:
     25        (WebCore::AdClickAttribution::Campaign::isValid const):
     26        (WebCore::AdClickAttribution::Conversion::isValid const):
     27           Enhanced the use of AdClickAttribution::MaxEntropy.
     28
    1292019-04-09  Don Olmstead  <don.olmstead@sony.com>
    230
  • trunk/Source/WebCore/html/HTMLAnchorElement.cpp

    r242776 r244086  
    432432    }
    433433   
    434     if (adCampaignID.value() >= AdClickAttribution::MaxEntropy) {
    435         document().addConsoleMessage(MessageSource::Other, MessageLevel::Warning, makeString("adcampaignid must have a non-negative value less than ", AdClickAttribution::MaxEntropy, " for Ad Click Attribution."));
     434    if (adCampaignID.value() > AdClickAttribution::MaxEntropy) {
     435        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."));
    436436        return WTF::nullopt;
    437437    }
  • trunk/Source/WebCore/loader/AdClickAttribution.cpp

    r242056 r244086  
    3030#include <wtf/URL.h>
    3131#include <wtf/text/StringBuilder.h>
     32#include <wtf/text/StringView.h>
    3233
    3334namespace WebCore {
     35
     36static const char adClickAttributionPathPrefix[] = "/.well-known/ad-click-attribution/";
     37const size_t adClickConversionDataPathSegmentSize = 2;
     38const size_t adClickPriorityPathSegmentSize = 2;
    3439
    3540bool AdClickAttribution::isValid() const
     
    4146        && !m_destination.registrableDomain.isEmpty()
    4247        && m_earliestTimeToSend;
     48}
     49
     50Optional<AdClickAttribution::Conversion> AdClickAttribution::parseConversionRequest(const URL& redirectURL)
     51{
     52    if (!redirectURL.protocolIs("https"_s) || redirectURL.hasUsername() || redirectURL.hasPassword() || redirectURL.hasQuery() || redirectURL.hasFragment())
     53        return { };
     54
     55    auto path = StringView(redirectURL.string()).substring(redirectURL.pathStart(), redirectURL.pathEnd() - redirectURL.pathStart());
     56    if (path.isEmpty() || !path.startsWith(adClickAttributionPathPrefix))
     57        return { };
     58
     59    auto prefixLength = sizeof(adClickAttributionPathPrefix) - 1;
     60    if (path.length() == prefixLength + adClickConversionDataPathSegmentSize) {
     61        auto conversionDataUInt64 = path.substring(prefixLength, adClickConversionDataPathSegmentSize).toUInt64Strict();
     62        if (!conversionDataUInt64 || *conversionDataUInt64 > MaxEntropy)
     63            return { };
     64
     65        return Conversion { static_cast<uint32_t>(*conversionDataUInt64), Priority { 0 } };
     66    }
     67   
     68    if (path.length() == prefixLength + adClickConversionDataPathSegmentSize + 1 + adClickPriorityPathSegmentSize) {
     69        auto conversionDataUInt64 = path.substring(prefixLength, adClickConversionDataPathSegmentSize).toUInt64Strict();
     70        if (!conversionDataUInt64 || *conversionDataUInt64 > MaxEntropy)
     71            return { };
     72
     73        auto conversionPriorityUInt64 = path.substring(prefixLength + adClickConversionDataPathSegmentSize + 1, adClickPriorityPathSegmentSize).toUInt64Strict();
     74        if (!conversionPriorityUInt64 || *conversionPriorityUInt64 > MaxEntropy)
     75            return { };
     76
     77        return Conversion { static_cast<uint32_t>(*conversionDataUInt64), Priority { static_cast<uint32_t>(*conversionPriorityUInt64) } };
     78    }
     79
     80    return { };
    4381}
    4482
     
    103141        builder.appendLiteral("\nConversion data: ");
    104142        builder.appendNumber(m_conversion.value().data);
     143        builder.appendLiteral("\nConversion priority: ");
     144        builder.appendNumber(m_conversion.value().priority);
    105145    } else
    106146        builder.appendLiteral("\nNo conversion data.");
  • trunk/Source/WebCore/loader/AdClickAttribution.h

    r242155 r244086  
    2727
    2828#include "RegistrableDomain.h"
     29#include <wtf/CompletionHandler.h>
    2930#include <wtf/Optional.h>
    3031#include <wtf/URL.h>
     
    4142    using PriorityValue = uint32_t;
    4243
    43     static constexpr uint32_t MaxEntropy = 64;
     44    static constexpr uint32_t MaxEntropy = 63;
    4445
    4546    struct Campaign {
     
    5253        bool isValid() const
    5354        {
    54             return id < MaxEntropy;
     55            return id <= MaxEntropy;
    5556        }
    5657       
     
    211212        bool isValid() const
    212213        {
    213             return data < MaxEntropy && priority < MaxEntropy;
     214            return data <= MaxEntropy && priority <= MaxEntropy;
    214215        }
    215216       
     
    230231    }
    231232
     233    WEBCORE_EXPORT static Optional<Conversion> parseConversionRequest(const URL& redirectURL);
    232234    WEBCORE_EXPORT void setConversion(Conversion&&);
    233235    WEBCORE_EXPORT URL url() const;
  • trunk/Source/WebKit/ChangeLog

    r244085 r244086  
     12019-04-09  John Wilander  <wilander@apple.com>
     2
     3        Pick up Ad Click Attribution conversions in NetworkResourceLoader::willSendRedirectedRequest()
     4        https://bugs.webkit.org/show_bug.cgi?id=196558
     5        <rdar://problem/47650245>
     6
     7        Reviewed by Youenn Fablet.
     8
     9        So called pixel requests have traditionally been used to send ad click
     10        attribution data to click sources. The privacy implications of such
     11        pixel requests are severe which is in part why browsers have started to
     12        block cookies from being sent in such third-party requests.
     13
     14        To allow for a smooth transition to more privacy-friendly ad click
     15        attribution, we should allow servers to make a redirect to
     16        https://click-source.example/.well-known/ad-click-attribution/ to
     17        trigger a so called conversion.
     18
     19        This patch checks for the well-known location in the path component of
     20        the redirect URL. If the request indeed goes to the well-known location,
     21        we parse the conversion data and send it to the storage in the network
     22        session.
     23
     24        * NetworkProcess/NetworkAdClickAttribution.cpp:
     25        (WebKit::NetworkAdClickAttribution::convert):
     26            Reporting function.
     27        * NetworkProcess/NetworkAdClickAttribution.h:
     28        * NetworkProcess/NetworkResourceLoader.cpp:
     29        (WebKit::NetworkResourceLoader::willSendRedirectedRequest):
     30            Now checks for the well-known location through a call to
     31            WebCore::AdClickAttribution::parseConversionRequest().
     32        * NetworkProcess/NetworkSession.cpp:
     33        (WebKit::NetworkSession::convertAdClickAttribution):
     34            Piping to WebKit::NetworkAdClickAttribution::convert().
     35        * NetworkProcess/NetworkSession.h:
     36
    1372019-04-09  Chris Dumez  <cdumez@apple.com>
    238
  • trunk/Source/WebKit/NetworkProcess/NetworkAdClickAttribution.cpp

    r241451 r244086  
    3232namespace WebKit {
    3333
     34using RegistrableDomain = WebCore::RegistrableDomain;
    3435using AdClickAttribution = WebCore::AdClickAttribution;
    3536using Source = WebCore::AdClickAttribution::Source;
    3637using Destination = WebCore::AdClickAttribution::Destination;
    3738using DestinationMap = HashMap<Destination, AdClickAttribution>;
     39using Conversion = WebCore::AdClickAttribution::Conversion;
    3840
    3941DestinationMap& NetworkAdClickAttribution::ensureDestinationMapForSource(const Source& source)
     
    4850    auto& destinationMapForSource = ensureDestinationMapForSource(adClickAttribution.source());
    4951    destinationMapForSource.add(adClickAttribution.destination(), WTFMove(adClickAttribution));
     52}
     53
     54void NetworkAdClickAttribution::convert(const Source& source, const Destination& destination, Conversion&& conversion)
     55{
     56    auto sourceIter = m_adClickAttributionMap.find(source);
     57    if (sourceIter == m_adClickAttributionMap.end())
     58        return;
     59
     60    auto destinationIter = sourceIter->value.find(destination);
     61    if (destinationIter == sourceIter->value.end())
     62        return;
     63
     64    destinationIter->value.setConversion(WTFMove(conversion));
    5065}
    5166
  • trunk/Source/WebKit/NetworkProcess/NetworkAdClickAttribution.h

    r241451 r244086  
    2727
    2828#include <WebCore/AdClickAttribution.h>
     29#include <WebCore/RegistrableDomain.h>
    2930#include <wtf/CompletionHandler.h>
    3031#include <wtf/HashMap.h>
     
    3637public:
    3738
     39    using RegistrableDomain = WebCore::RegistrableDomain;
    3840    using AdClickAttribution = WebCore::AdClickAttribution;
    3941    using Source = WebCore::AdClickAttribution::Source;
    4042    using Destination = WebCore::AdClickAttribution::Destination;
    4143    using DestinationMap = HashMap<Destination, AdClickAttribution>;
     44    using Conversion = WebCore::AdClickAttribution::Conversion;
    4245
    4346    void store(AdClickAttribution&&);
     47    void convert(const Source&, const Destination&, Conversion&&);
    4448    void clear(CompletionHandler<void()>&&);
    4549    void toString(CompletionHandler<void(String)>&&) const;
    4650
    4751private:
    48     DestinationMap& ensureDestinationMapForSource(const AdClickAttribution::Source&);
     52    DestinationMap& ensureDestinationMapForSource(const Source&);
    4953
    5054    HashMap<Source, DestinationMap> m_adClickAttributionMap;
  • trunk/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp

    r244030 r244086  
    4242#include "WebResourceLoaderMessages.h"
    4343#include "WebsiteDataStoreParameters.h"
     44#include <WebCore/AdClickAttribution.h>
    4445#include <WebCore/BlobDataFileReference.h>
    4546#include <WebCore/CertificateInfo.h>
     
    584585    ++m_redirectCount;
    585586
     587    auto& redirectURL = redirectRequest.url();
     588    if (auto adClickConversion = AdClickAttribution::parseConversionRequest(redirectURL)) {
     589        RegistrableDomain redirectDomain { redirectURL };
     590        auto& firstPartyURL = redirectRequest.firstPartyForCookies();
     591        NetworkSession* networkSession;
     592        // The redirect has to be done by the same registrable domain and it has to be a third-party request.
     593        if (redirectDomain.matches(request.url()) && !redirectDomain.matches(firstPartyURL) && (networkSession = m_connection->networkProcess().networkSession(sessionID())))
     594            networkSession->convertAdClickAttribution(AdClickAttribution::Source { WTFMove(redirectDomain) }, AdClickAttribution::Destination { firstPartyURL }, WTFMove(*adClickConversion));
     595    }
     596
    586597    auto maxAgeCap = validateCacheEntryForMaxAgeCapValidation(request, redirectRequest, redirectResponse);
    587598    if (redirectResponse.source() == ResourceResponse::Source::Network && canUseCachedRedirect(request))
  • trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp

    r243181 r244086  
    3333#include "WebPageProxyMessages.h"
    3434#include "WebProcessProxy.h"
    35 #include <WebCore/AdClickAttribution.h>
    3635#include <WebCore/CookieJar.h>
    3736#include <WebCore/NetworkStorageSession.h>
     
    142141}
    143142
     143void NetworkSession::convertAdClickAttribution(const WebCore::AdClickAttribution::Source& source, const WebCore::AdClickAttribution::Destination& destination, WebCore::AdClickAttribution::Conversion&& conversion)
     144{
     145    m_adClickAttribution->convert(source, destination, WTFMove(conversion));
     146}
     147
    144148void NetworkSession::dumpAdClickAttribution(CompletionHandler<void(String)>&& completionHandler)
    145149{
  • trunk/Source/WebKit/NetworkProcess/NetworkSession.h

    r243181 r244086  
    2727
    2828#include "WebResourceLoadStatisticsStore.h"
     29#include <WebCore/AdClickAttribution.h>
    2930#include <WebCore/RegistrableDomain.h>
    3031#include <pal/SessionID.h>
     
    3839
    3940namespace WebCore {
    40 class AdClickAttribution;
    4141class NetworkStorageSession;
    4242enum class IncludeHttpOnlyCookies : bool;
     
    8181#endif
    8282    void storeAdClickAttribution(WebCore::AdClickAttribution&&);
     83    void convertAdClickAttribution(const WebCore::AdClickAttribution::Source&, const WebCore::AdClickAttribution::Destination&, WebCore::AdClickAttribution::Conversion&&);
    8384    void dumpAdClickAttribution(CompletionHandler<void(String)>&&);
    8485    void clearAdClickAttribution(CompletionHandler<void()>&&);
  • trunk/Tools/ChangeLog

    r244081 r244086  
     12019-04-09  John Wilander  <wilander@apple.com>
     2
     3        Pick up Ad Click Attribution conversions in NetworkResourceLoader::willSendRedirectedRequest()
     4        https://bugs.webkit.org/show_bug.cgi?id=196558
     5        <rdar://problem/47650245>
     6
     7        Reviewed by Youenn Fablet.
     8
     9        * TestWebKitAPI/Tests/WebCore/AdClickAttribution.cpp:
     10        (TestWebKitAPI::TEST):
     11            Added tests of WebCore::AdClickAttribution::parseConversionRequest().
     12
    1132019-04-09  Don Olmstead  <don.olmstead@sony.com>
    214
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/AdClickAttribution.cpp

    r242155 r244086  
    3535
    3636constexpr uint32_t min6BitValue { 0 };
    37 constexpr uint32_t max6BitValue { 63 };
    3837
    3938const URL webKitURL { { }, "https://webkit.org"_s };
     
    6968TEST(AdClickAttribution, ValidMaxValues)
    7069{
    71     AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
    72     attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue)));
     70    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
     71    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
    7372
    7473    auto attributionURL = attribution.url();
     
    8180TEST(AdClickAttribution, EarliestTimeToSendAttributionMinimumDelay)
    8281{
    83     AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
     82    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
    8483    auto now = WallTime::now();
    85     attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue)));
     84    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
    8685    auto earliestTimeToSend = attribution.earliestTimeToSend();
    8786    ASSERT_TRUE(earliestTimeToSend);
     
    8988}
    9089
     90TEST(AdClickAttribution, ValidConversionURLs)
     91{
     92    const URL conversionURLWithoutPriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22"_s };
     93    auto optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithoutPriority);
     94    ASSERT_TRUE(optionalConversion);
     95    ASSERT_EQ(optionalConversion->data, (uint32_t)22);
     96
     97    const URL conversionURLWithoutPriorityMaxEntropy { { }, "https://webkit.org/.well-known/ad-click-attribution/63"_s };
     98    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithoutPriorityMaxEntropy);
     99    ASSERT_TRUE(optionalConversion);
     100    ASSERT_EQ(optionalConversion->data, (uint32_t)63);
     101   
     102    const URL conversionURLWithoutPriorityAndLeadingZero { { }, "https://webkit.org/.well-known/ad-click-attribution/02"_s };
     103    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithoutPriorityAndLeadingZero);
     104    ASSERT_TRUE(optionalConversion);
     105    ASSERT_EQ(optionalConversion->data, (uint32_t)2);
     106
     107    const URL conversionURLWithPriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12"_s };
     108    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithPriority);
     109    ASSERT_TRUE(optionalConversion);
     110    ASSERT_EQ(optionalConversion->data, (uint32_t)22);
     111    ASSERT_EQ(optionalConversion->priority, (uint32_t)12);
     112
     113    const URL conversionURLWithPriorityMaxEntropy { { }, "https://webkit.org/.well-known/ad-click-attribution/63/63"_s };
     114    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithPriorityMaxEntropy);
     115    ASSERT_TRUE(optionalConversion);
     116    ASSERT_EQ(optionalConversion->data, (uint32_t)63);
     117    ASSERT_EQ(optionalConversion->priority, (uint32_t)63);
     118   
     119    const URL conversionURLWithPriorityAndLeadingZero { { }, "https://webkit.org/.well-known/ad-click-attribution/22/02"_s };
     120    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithPriorityAndLeadingZero);
     121    ASSERT_TRUE(optionalConversion);
     122    ASSERT_EQ(optionalConversion->data, (uint32_t)22);
     123    ASSERT_EQ(optionalConversion->priority, (uint32_t)2);
     124}
     125
    91126// Negative test cases.
    92127
    93128TEST(AdClickAttribution, InvalidCampaignId)
    94129{
    95     AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue + 1), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
    96     attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue)));
     130    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy + 1), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
     131    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
    97132
    98133    auto attributionURL = attribution.url();
     
    105140TEST(AdClickAttribution, InvalidSourceHost)
    106141{
    107     AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { emptyURL }, AdClickAttribution::Destination { exampleURL } };
    108     attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue)));
     142    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { emptyURL }, AdClickAttribution::Destination { exampleURL } };
     143    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
    109144
    110145    auto attributionURL = attribution.url();
     
    117152TEST(AdClickAttribution, InvalidDestinationHost)
    118153{
    119     AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue + 1), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { emptyURL } };
    120     attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue)));
     154    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy + 1), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { emptyURL } };
     155    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
    121156
    122157    auto attributionURL = attribution.url();
     
    129164TEST(AdClickAttribution, InvalidConversionData)
    130165{
    131     AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
    132     attribution.setConversion(AdClickAttribution::Conversion((max6BitValue + 1), AdClickAttribution::Priority(max6BitValue)));
     166    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
     167    attribution.setConversion(AdClickAttribution::Conversion((AdClickAttribution::MaxEntropy + 1), AdClickAttribution::Priority(AdClickAttribution::MaxEntropy)));
    133168
    134169    auto attributionURL = attribution.url();
     
    141176TEST(AdClickAttribution, InvalidPriority)
    142177{
    143     AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
    144     attribution.setConversion(AdClickAttribution::Conversion(max6BitValue, AdClickAttribution::Priority(max6BitValue + 1)));
     178    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
     179    attribution.setConversion(AdClickAttribution::Conversion(AdClickAttribution::MaxEntropy, AdClickAttribution::Priority(AdClickAttribution::MaxEntropy + 1)));
    145180
    146181    auto attributionURL = attribution.url();
     
    153188TEST(AdClickAttribution, InvalidMissingConversion)
    154189{
    155     AdClickAttribution attribution { AdClickAttribution::Campaign(max6BitValue), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
     190    AdClickAttribution attribution { AdClickAttribution::Campaign(AdClickAttribution::MaxEntropy), AdClickAttribution::Source { webKitURL }, AdClickAttribution::Destination { exampleURL } };
    156191
    157192    auto attributionURL = attribution.url();
     
    163198}
    164199
     200TEST(AdClickAttribution, InvalidConversionURLs)
     201{
     202    const URL conversionURLWithSingleDigitConversionData { { }, "https://webkit.org/.well-known/ad-click-attribution/2"_s };
     203    auto optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithSingleDigitConversionData);
     204    ASSERT_FALSE(optionalConversion);
     205   
     206    const URL conversionURLWithNonNumeralConversionData { { }, "https://webkit.org/.well-known/ad-click-attribution/2s"_s };
     207    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithNonNumeralConversionData);
     208    ASSERT_FALSE(optionalConversion);
     209
     210    const URL conversionURLWithNegativeConversionData { { }, "https://webkit.org/.well-known/ad-click-attribution/-2"_s };
     211    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithNegativeConversionData);
     212    ASSERT_FALSE(optionalConversion);
     213
     214    const URL conversionURLWithTooLargeConversionData { { }, "https://webkit.org/.well-known/ad-click-attribution/64"_s };
     215    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTooLargeConversionData);
     216    ASSERT_FALSE(optionalConversion);
     217
     218    const URL conversionURLWithSingleDigitPriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22/2"_s };
     219    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithSingleDigitPriority);
     220    ASSERT_FALSE(optionalConversion);
     221   
     222    const URL conversionURLWithNonNumeralPriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22/2s"_s };
     223    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithNonNumeralPriority);
     224    ASSERT_FALSE(optionalConversion);
     225   
     226    const URL conversionURLWithNegativePriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22/-2"_s };
     227    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithNegativePriority);
     228    ASSERT_FALSE(optionalConversion);
     229   
     230    const URL conversionURLWithTooLargePriority { { }, "https://webkit.org/.well-known/ad-click-attribution/22/64"_s };
     231    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTooLargePriority);
     232    ASSERT_FALSE(optionalConversion);
     233
     234    const URL conversionURLWithTooLargeConversionDataAndPriority { { }, "https://webkit.org/.well-known/ad-click-attribution/64/22"_s };
     235    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTooLargeConversionDataAndPriority);
     236    ASSERT_FALSE(optionalConversion);
     237
     238    const URL conversionURLWithTooLargeConversionDataAndTooLargePriority { { }, "https://webkit.org/.well-known/ad-click-attribution/64/64"_s };
     239    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTooLargeConversionDataAndTooLargePriority);
     240    ASSERT_FALSE(optionalConversion);
     241
     242    const URL conversionURLWithExtraLeadingSlash = { { }, "https://webkit.org/.well-known/ad-click-attribution//22/12"_s };
     243    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithExtraLeadingSlash);
     244    ASSERT_FALSE(optionalConversion);
     245
     246    const URL conversionURLWithExtraTrailingSlash = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12/"_s };
     247    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithExtraTrailingSlash);
     248    ASSERT_FALSE(optionalConversion);
     249
     250    const URL conversionURLWithTrailingQuestionMark = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12?"_s };
     251    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTrailingQuestionMark);
     252    ASSERT_FALSE(optionalConversion);
     253}
     254
     255TEST(AdClickAttribution, InvalidConversionWithDisallowedURLComponents)
     256{
     257    // Protocol.
     258    const URL conversionURLWithHttpProtocol { { }, "http://webkit.org/.well-known/ad-click-attribution/2"_s };
     259    auto optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithHttpProtocol);
     260    ASSERT_FALSE(optionalConversion);
     261
     262    const URL conversionURLWithWssProtocol { { }, "wss://webkit.org/.well-known/ad-click-attribution/2"_s };
     263    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithWssProtocol);
     264    ASSERT_FALSE(optionalConversion);
     265
     266    const URL conversionURLWithFileProtocol { { }, "file:///.well-known/ad-click-attribution/2"_s };
     267    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithFileProtocol);
     268    ASSERT_FALSE(optionalConversion);
     269
     270    // Username and password.
     271    const URL conversionURLWithUserName { { }, "https://user@webkit.org/.well-known/ad-click-attribution/2"_s };
     272    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithUserName);
     273    ASSERT_FALSE(optionalConversion);
     274
     275    const URL conversionURLWithPassword = { { }, "https://:pwd@webkit.org/.well-known/ad-click-attribution/22/12?"_s };
     276    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithPassword);
     277    ASSERT_FALSE(optionalConversion);
     278
     279    const URL conversionURLWithUsernameAndPassword = { { }, "https://user:pwd@webkit.org/.well-known/ad-click-attribution/22/12?"_s };
     280    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithUsernameAndPassword);
     281    ASSERT_FALSE(optionalConversion);
     282
     283    // Query string.
     284    const URL conversionURLWithTrailingQuestionMark = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12?"_s };
     285    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTrailingQuestionMark);
     286    ASSERT_FALSE(optionalConversion);
     287
     288    const URL conversionURLWithQueryString = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12?extra=data"_s };
     289    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithQueryString);
     290    ASSERT_FALSE(optionalConversion);
     291   
     292    // Fragment.
     293    const URL conversionURLWithTrailingHash = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12#"_s };
     294    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithTrailingHash);
     295    ASSERT_FALSE(optionalConversion);
     296
     297    const URL conversionURLWithFragment = { { }, "https://webkit.org/.well-known/ad-click-attribution/22/12#fragment"_s };
     298    optionalConversion = AdClickAttribution::parseConversionRequest(conversionURLWithFragment);
     299    ASSERT_FALSE(optionalConversion);
     300}
     301
    165302} // namespace TestWebKitAPI
Note: See TracChangeset for help on using the changeset viewer.