Title: [272660] trunk/Source/WebKit
Revision
272660
Author
katherine_che...@apple.com
Date
2021-02-10 09:38:10 -0800 (Wed, 10 Feb 2021)

Log Message

PCM: Expired reports get sent at the same time after a session restart
https://bugs.webkit.org/show_bug.cgi?id=221555
<rdar://problem/73724816>

Reviewed by John Wilander.

Since PCM data is now persisted, we need to address the case of a
session-restart after 24-48+ hours. We should not send all overdue
attributions in the same burst in case multiple have the same destination
and could identify a user cross-site.

This patch kicks off the timer to fire pending attributions on session-start
and sends one report at a time. If more than one overdue report exists
at any time, we schedule the timer for a random interval between 15 and
30 minutes.

In theory this could result in some attributions never being sent if a
user keeps quitting and restarting a session. In practice this is
probably unlikely. Protecting the user's privacy is a hard requirement,
so we think possible starvation of some reports is the right tradeoff.

* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
(WebKit::ResourceLoadStatisticsDatabaseStore::clearSentAttribution):
(WebKit::ResourceLoadStatisticsDatabaseStore::clearSentAttributions): Deleted.
* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
* NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h:
* NetworkProcess/Classifier/ResourceLoadStatisticsStore.h:
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::clearSentAttribution):
(WebKit::WebResourceLoadStatisticsStore::clearSentAttributions): Deleted.
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h:
Remove unused SQLite query. Update the query to sort attributed PCM
by earliestTimeToSend, which seems important now that we send only
one overdue report at a time. Change the clearSentAttributions
function to take only a single attribution.

* NetworkProcess/NetworkSession.cpp:
(WebKit::NetworkSession::NetworkSession):
Convert m_privateClickMeasurement to a unique_ptr so we can wait to
create it after WebResourceLoadStatisticsStore is created. This ensures
that the call to create the SQLite database will run on a
background thread before we try to collect overdue PCM attributions.

(WebKit::NetworkSession::storePrivateClickMeasurement):
(WebKit::NetworkSession::handlePrivateClickMeasurementConversion):
(WebKit::NetworkSession::dumpPrivateClickMeasurement):
(WebKit::NetworkSession::clearPrivateClickMeasurement):
(WebKit::NetworkSession::clearPrivateClickMeasurementForRegistrableDomain):
(WebKit::NetworkSession::setPrivateClickMeasurementOverrideTimerForTesting):
(WebKit::NetworkSession::markAttributedPrivateClickMeasurementsAsExpiredForTesting):
(WebKit::NetworkSession::setPrivateClickMeasurementConversionURLForTesting):
(WebKit::NetworkSession::markPrivateClickMeasurementsAsExpiredForTesting):
(WebKit::NetworkSession::firePrivateClickMeasurementTimerImmediately):
* NetworkProcess/NetworkSession.h:
* NetworkProcess/PrivateClickMeasurementManager.cpp:
(WebKit::PrivateClickMeasurementManager::PrivateClickMeasurementManager):
(WebKit::PrivateClickMeasurementManager::firePendingAttributionRequest):
(WebKit::PrivateClickMeasurementManager::attribute):
Drive-by fixes to add protectedThis and check if PrivateClickMeasurementManager
is still alive when this lambda is called.

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (272659 => 272660)


--- trunk/Source/WebKit/ChangeLog	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/ChangeLog	2021-02-10 17:38:10 UTC (rev 272660)
@@ -1,3 +1,66 @@
+2021-02-10  Kate Cheney  <katherine_che...@apple.com>
+
+        PCM: Expired reports get sent at the same time after a session restart
+        https://bugs.webkit.org/show_bug.cgi?id=221555
+        <rdar://problem/73724816>
+
+        Reviewed by John Wilander.
+
+        Since PCM data is now persisted, we need to address the case of a
+        session-restart after 24-48+ hours. We should not send all overdue
+        attributions in the same burst in case multiple have the same destination
+        and could identify a user cross-site.
+
+        This patch kicks off the timer to fire pending attributions on session-start
+        and sends one report at a time. If more than one overdue report exists
+        at any time, we schedule the timer for a random interval between 15 and
+        30 minutes.
+
+        In theory this could result in some attributions never being sent if a
+        user keeps quitting and restarting a session. In practice this is
+        probably unlikely. Protecting the user's privacy is a hard requirement,
+        so we think possible starvation of some reports is the right tradeoff.
+
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
+        (WebKit::ResourceLoadStatisticsDatabaseStore::clearSentAttribution):
+        (WebKit::ResourceLoadStatisticsDatabaseStore::clearSentAttributions): Deleted.
+        * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
+        * NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h:
+        * NetworkProcess/Classifier/ResourceLoadStatisticsStore.h:
+        * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
+        (WebKit::WebResourceLoadStatisticsStore::clearSentAttribution):
+        (WebKit::WebResourceLoadStatisticsStore::clearSentAttributions): Deleted.
+        * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h:
+        Remove unused SQLite query. Update the query to sort attributed PCM
+        by earliestTimeToSend, which seems important now that we send only
+        one overdue report at a time. Change the clearSentAttributions
+        function to take only a single attribution.
+
+        * NetworkProcess/NetworkSession.cpp:
+        (WebKit::NetworkSession::NetworkSession):
+        Convert m_privateClickMeasurement to a unique_ptr so we can wait to
+        create it after WebResourceLoadStatisticsStore is created. This ensures
+        that the call to create the SQLite database will run on a
+        background thread before we try to collect overdue PCM attributions. 
+
+        (WebKit::NetworkSession::storePrivateClickMeasurement):
+        (WebKit::NetworkSession::handlePrivateClickMeasurementConversion):
+        (WebKit::NetworkSession::dumpPrivateClickMeasurement):
+        (WebKit::NetworkSession::clearPrivateClickMeasurement):
+        (WebKit::NetworkSession::clearPrivateClickMeasurementForRegistrableDomain):
+        (WebKit::NetworkSession::setPrivateClickMeasurementOverrideTimerForTesting):
+        (WebKit::NetworkSession::markAttributedPrivateClickMeasurementsAsExpiredForTesting):
+        (WebKit::NetworkSession::setPrivateClickMeasurementConversionURLForTesting):
+        (WebKit::NetworkSession::markPrivateClickMeasurementsAsExpiredForTesting):
+        (WebKit::NetworkSession::firePrivateClickMeasurementTimerImmediately):
+        * NetworkProcess/NetworkSession.h:
+        * NetworkProcess/PrivateClickMeasurementManager.cpp:
+        (WebKit::PrivateClickMeasurementManager::PrivateClickMeasurementManager):
+        (WebKit::PrivateClickMeasurementManager::firePendingAttributionRequest):
+        (WebKit::PrivateClickMeasurementManager::attribute):
+        Drive-by fixes to add protectedThis and check if PrivateClickMeasurementManager
+        is still alive when this lambda is called.
+
 2021-02-10  Wenson Hsieh  <wenson_hs...@apple.com>
 
         [watchOS] Adopt PUICQuickboardController for text input

Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp (272659 => 272660)


--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp	2021-02-10 17:38:10 UTC (rev 272660)
@@ -116,10 +116,6 @@
 constexpr auto updateGrandfatheredQuery = "UPDATE ObservedDomains SET grandfathered = ? WHERE registrableDomain = ?"_s;
 constexpr auto updateIsScheduledForAllButCookieDataRemovalQuery = "UPDATE ObservedDomains SET isScheduledForAllButCookieDataRemoval = ? WHERE registrableDomain = ?"_s;
 constexpr auto setUnattributedPrivateClickMeasurementAsExpiredQuery = "UPDATE UnattributedPrivateClickMeasurement SET timeOfAdClick = -1.0"_s;
-constexpr auto updateAttributionsEarliestTimeToSendQuery = "UPDATE AttributedPrivateClickMeasurement as c SET "
-    "earliestTimeToSend = (SELECT MAX(0.0, newTime) FROM (SELECT (earliestTimeToSend - ?) as newTime FROM "
-    "AttributedPrivateClickMeasurement as d WHERE c.sourceSiteDomainID = d.sourceSiteDomainID AND c.attributeOnSiteDomainID = "
-    "d.attributeOnSiteDomainID))"_s;
 
 // SELECT Queries
 constexpr auto domainIDFromStringQuery = "SELECT domainID FROM ObservedDomains WHERE registrableDomain = ?"_s;
@@ -139,7 +135,7 @@
     "UNION ALL SELECT topFrameDomainID FROM SubresourceUnderTopFrameDomains WHERE subresourceDomainID = ?"
     "UNION ALL SELECT toDomainID FROM SubresourceUniqueRedirectsTo WHERE subresourceDomainID = ?"_s;
 constexpr auto allUnattributedPrivateClickMeasurementAttributionsQuery = "SELECT * FROM UnattributedPrivateClickMeasurement"_s;
-constexpr auto allAttributedPrivateClickMeasurementQuery = "SELECT * FROM AttributedPrivateClickMeasurement"_s;
+constexpr auto allAttributedPrivateClickMeasurementQuery = "SELECT * FROM AttributedPrivateClickMeasurement ORDER BY earliestTimeToSend"_s;
 constexpr auto findUnattributedQuery = "SELECT * FROM UnattributedPrivateClickMeasurement WHERE sourceSiteDomainID = ? AND attributeOnSiteDomainID = ?"_s;
 constexpr auto findAttributedQuery = "SELECT * FROM AttributedPrivateClickMeasurement WHERE sourceSiteDomainID = ? AND attributeOnSiteDomainID = ?"_s;
 
@@ -3237,24 +3233,21 @@
     return builder.toString();
 }
 
-void ResourceLoadStatisticsDatabaseStore::clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&& attributions)
+void ResourceLoadStatisticsDatabaseStore::clearSentAttribution(WebCore::PrivateClickMeasurement&& attribution)
 {
-    for (auto& attribution : attributions) {
-        auto sourceSiteDomainID = domainID(attribution.sourceSite().registrableDomain);
-        auto attributeOnSiteDomainID = domainID(attribution.attributeOnSite().registrableDomain);
+    auto sourceSiteDomainID = domainID(attribution.sourceSite().registrableDomain);
+    auto attributeOnSiteDomainID = domainID(attribution.attributeOnSite().registrableDomain);
 
-        if (!sourceSiteDomainID || !attributeOnSiteDomainID)
-            return;
+    if (!sourceSiteDomainID || !attributeOnSiteDomainID)
+        return;
 
-        SQLiteStatement clearAttributedStatement(m_database, "DELETE FROM AttributedPrivateClickMeasurement WHERE sourceSiteDomainID = ? AND attributeOnSiteDomainID = ?"_s);
-        if (clearAttributedStatement.prepare() != SQLITE_OK
-            || clearAttributedStatement.bindInt(1, *sourceSiteDomainID) != SQLITE_OK
-            || clearAttributedStatement.bindInt(2, *attributeOnSiteDomainID) != SQLITE_OK
-            || clearAttributedStatement.step() != SQLITE_DONE) {
-            RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearSentAttributions failed to step, error message: %{private}s", this, m_database.lastErrorMsg());
-            ASSERT_NOT_REACHED();
-        }
-        clearAttributedStatement.reset();
+    SQLiteStatement clearAttributedStatement(m_database, "DELETE FROM AttributedPrivateClickMeasurement WHERE sourceSiteDomainID = ? AND attributeOnSiteDomainID = ?"_s);
+    if (clearAttributedStatement.prepare() != SQLITE_OK
+        || clearAttributedStatement.bindInt(1, *sourceSiteDomainID) != SQLITE_OK
+        || clearAttributedStatement.bindInt(2, *attributeOnSiteDomainID) != SQLITE_OK
+        || clearAttributedStatement.step() != SQLITE_DONE) {
+        RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearSentAttribution failed to step, error message: %{private}s", this, m_database.lastErrorMsg());
+        ASSERT_NOT_REACHED();
     }
 }
 

Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h (272659 => 272660)


--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h	2021-02-10 17:38:10 UTC (rev 272660)
@@ -139,7 +139,7 @@
     void clearPrivateClickMeasurement(Optional<RegistrableDomain>) override;
     void clearExpiredPrivateClickMeasurement() override;
     String privateClickMeasurementToString() override;
-    void clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&&) override;
+    void clearSentAttribution(WebCore::PrivateClickMeasurement&&) override;
     void markAttributedPrivateClickMeasurementsAsExpiredForTesting() override;
 
 private:

Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h (272659 => 272660)


--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h	2021-02-10 17:38:10 UTC (rev 272660)
@@ -116,7 +116,7 @@
     void clearPrivateClickMeasurement(Optional<RegistrableDomain>) override { };
     void clearExpiredPrivateClickMeasurement() override { };
     String privateClickMeasurementToString() override { return String(); };
-    void clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&&) override { };
+    void clearSentAttribution(WebCore::PrivateClickMeasurement&&) override { };
     void markAttributedPrivateClickMeasurementsAsExpiredForTesting() override { };
 
 private:

Modified: trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h (272659 => 272660)


--- trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h	2021-02-10 17:38:10 UTC (rev 272660)
@@ -211,7 +211,7 @@
     virtual void clearPrivateClickMeasurement(Optional<RegistrableDomain>) = 0;
     virtual void clearExpiredPrivateClickMeasurement() = 0;
     virtual String privateClickMeasurementToString() = 0;
-    virtual void clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&&) = 0;
+    virtual void clearSentAttribution(WebCore::PrivateClickMeasurement&&) = 0;
     virtual void markAttributedPrivateClickMeasurementsAsExpiredForTesting() = 0;
 
 protected:

Modified: trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp (272659 => 272660)


--- trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp	2021-02-10 17:38:10 UTC (rev 272660)
@@ -1622,7 +1622,7 @@
     });
 }
 
-void WebResourceLoadStatisticsStore::clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&& attributionsToClear)
+void WebResourceLoadStatisticsStore::clearSentAttribution(WebCore::PrivateClickMeasurement&& attributionToClear)
 {
     ASSERT(RunLoop::isMain());
 
@@ -1629,11 +1629,11 @@
     if (isEphemeral())
         return;
 
-    postTask([this, attributionsToClear = WTFMove(attributionsToClear)]() mutable {
+    postTask([this, attributionToClear = WTFMove(attributionToClear)]() mutable {
         if (!m_statisticsStore)
             return;
 
-        m_statisticsStore->clearSentAttributions(WTFMove(attributionsToClear));
+        m_statisticsStore->clearSentAttribution(WTFMove(attributionToClear));
     });
 }
 

Modified: trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h (272659 => 272660)


--- trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h	2021-02-10 17:38:10 UTC (rev 272660)
@@ -315,7 +315,7 @@
     void clearPrivateClickMeasurementForRegistrableDomain(const WebCore::RegistrableDomain&);
     void clearExpiredPrivateClickMeasurement();
     void privateClickMeasurementToString(CompletionHandler<void(String)>&&);
-    void clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&&);
+    void clearSentAttribution(WebCore::PrivateClickMeasurement&&);
     void markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&&);
 
 private:

Modified: trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp (272659 => 272660)


--- trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp	2021-02-10 17:38:10 UTC (rev 272660)
@@ -91,7 +91,6 @@
     , m_firstPartyWebsiteDataRemovalMode(parameters.resourceLoadStatisticsParameters.firstPartyWebsiteDataRemovalMode)
     , m_standaloneApplicationDomain(parameters.resourceLoadStatisticsParameters.standaloneApplicationDomain)
 #endif
-    , m_privateClickMeasurement(makeUniqueRef<PrivateClickMeasurementManager>(*this, networkProcess, parameters.sessionID))
     , m_testSpeedMultiplier(parameters.testSpeedMultiplier)
     , m_allowsServerPreconnect(parameters.allowsServerPreconnect)
 {
@@ -120,6 +119,9 @@
 
     m_isStaleWhileRevalidateEnabled = parameters.staleWhileRevalidateEnabled;
 
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    setResourceLoadStatisticsEnabled(parameters.resourceLoadStatisticsParameters.enabled);
+    m_privateClickMeasurement = makeUnique<PrivateClickMeasurementManager>(*this, networkProcess, parameters.sessionID);
     m_privateClickMeasurement->setPingLoadFunction([this, weakThis = makeWeakPtr(this)](NetworkResourceLoadParameters&& loadParameters, CompletionHandler<void(const WebCore::ResourceError&, const WebCore::ResourceResponse&)>&& completionHandler) {
         if (!weakThis)
             return;
@@ -126,9 +128,6 @@
         // PingLoad manages its own lifetime, deleting itself when its purpose has been fulfilled.
         new PingLoad(m_networkProcess, m_sessionID, WTFMove(loadParameters), WTFMove(completionHandler));
     });
-
-#if ENABLE(RESOURCE_LOAD_STATISTICS)
-    setResourceLoadStatisticsEnabled(parameters.resourceLoadStatisticsParameters.enabled);
 #endif
 }
 
@@ -304,54 +303,54 @@
 }
 #endif // ENABLE(RESOURCE_LOAD_STATISTICS)
 
-void NetworkSession::storePrivateClickMeasurement(WebCore::PrivateClickMeasurement&& privateClickMeasurement)
+void NetworkSession::storePrivateClickMeasurement(WebCore::PrivateClickMeasurement&& unattributedPrivateClickMeasurement)
 {
-    m_privateClickMeasurement->storeUnattributed(WTFMove(privateClickMeasurement));
+    privateClickMeasurement().storeUnattributed(WTFMove(unattributedPrivateClickMeasurement));
 }
 
 void NetworkSession::handlePrivateClickMeasurementConversion(PrivateClickMeasurement::AttributionTriggerData&& attributionTriggerData, const URL& requestURL, const WebCore::ResourceRequest& redirectRequest)
 {
-    m_privateClickMeasurement->handleAttribution(WTFMove(attributionTriggerData), requestURL, redirectRequest);
+    privateClickMeasurement().handleAttribution(WTFMove(attributionTriggerData), requestURL, redirectRequest);
 }
 
 void NetworkSession::dumpPrivateClickMeasurement(CompletionHandler<void(String)>&& completionHandler)
 {
-    m_privateClickMeasurement->toString(WTFMove(completionHandler));
+    privateClickMeasurement().toString(WTFMove(completionHandler));
 }
 
 void NetworkSession::clearPrivateClickMeasurement()
 {
-    m_privateClickMeasurement->clear();
+    privateClickMeasurement().clear();
 }
 
 void NetworkSession::clearPrivateClickMeasurementForRegistrableDomain(WebCore::RegistrableDomain&& domain)
 {
-    m_privateClickMeasurement->clearForRegistrableDomain(WTFMove(domain));
+    privateClickMeasurement().clearForRegistrableDomain(WTFMove(domain));
 }
 
 void NetworkSession::setPrivateClickMeasurementOverrideTimerForTesting(bool value)
 {
-    m_privateClickMeasurement->setOverrideTimerForTesting(value);
+    privateClickMeasurement().setOverrideTimerForTesting(value);
 }
 
 void NetworkSession::markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&& completionHandler)
 {
-    m_privateClickMeasurement->markAttributedPrivateClickMeasurementsAsExpiredForTesting(WTFMove(completionHandler));
+    privateClickMeasurement().markAttributedPrivateClickMeasurementsAsExpiredForTesting(WTFMove(completionHandler));
 }
 
 void NetworkSession::setPrivateClickMeasurementConversionURLForTesting(URL&& url)
 {
-    m_privateClickMeasurement->setConversionURLForTesting(WTFMove(url));
+    privateClickMeasurement().setConversionURLForTesting(WTFMove(url));
 }
 
 void NetworkSession::markPrivateClickMeasurementsAsExpiredForTesting()
 {
-    m_privateClickMeasurement->markAllUnattributedAsExpiredForTesting();
+    privateClickMeasurement().markAllUnattributedAsExpiredForTesting();
 }
 
 void NetworkSession::firePrivateClickMeasurementTimerImmediately()
 {
-    m_privateClickMeasurement->startTimer(0_s);
+    privateClickMeasurement().startTimer(0_s);
 }
 
 void NetworkSession::addKeptAliveLoad(Ref<NetworkResourceLoader>&& loader)

Modified: trunk/Source/WebKit/NetworkProcess/NetworkSession.h (272659 => 272660)


--- trunk/Source/WebKit/NetworkProcess/NetworkSession.h	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/NetworkProcess/NetworkSession.h	2021-02-10 17:38:10 UTC (rev 272660)
@@ -152,6 +152,7 @@
 #endif
 
     NetworkLoadScheduler& networkLoadScheduler();
+    PrivateClickMeasurementManager& privateClickMeasurement() { return *m_privateClickMeasurement; }
 
 protected:
     NetworkSession(NetworkProcess&, const NetworkSessionCreationParameters&);
@@ -179,7 +180,7 @@
     Optional<WebCore::RegistrableDomain> m_thirdPartyCNAMEDomainForTesting;
 #endif
     bool m_isStaleWhileRevalidateEnabled { false };
-    UniqueRef<PrivateClickMeasurementManager> m_privateClickMeasurement;
+    std::unique_ptr<PrivateClickMeasurementManager> m_privateClickMeasurement;
 
     HashSet<Ref<NetworkResourceLoader>> m_keptAliveLoads;
 

Modified: trunk/Source/WebKit/NetworkProcess/PrivateClickMeasurementManager.cpp (272659 => 272660)


--- trunk/Source/WebKit/NetworkProcess/PrivateClickMeasurementManager.cpp	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/NetworkProcess/PrivateClickMeasurementManager.cpp	2021-02-10 17:38:10 UTC (rev 272660)
@@ -178,7 +178,7 @@
     });
 }
 
-void PrivateClickMeasurementManager::clearSentAttributions(Vector<PrivateClickMeasurement>&& sentConversions)
+void PrivateClickMeasurementManager::clearSentAttribution(PrivateClickMeasurement&& sentConversion)
 {
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
     if (!featureEnabled())
@@ -185,7 +185,7 @@
         return;
 
     if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics())
-        resourceLoadStatistics->clearSentAttributions(WTFMove(sentConversions));
+        resourceLoadStatistics->clearSentAttribution(WTFMove(sentConversion));
 #endif
 }
 
@@ -201,8 +201,8 @@
 
     resourceLoadStatistics->allAttributedPrivateClickMeasurement([this] (auto&& attributions) {
         auto nextTimeToFire = Seconds::infinity();
-        Vector<PrivateClickMeasurement> sentAttributions;
-        
+        bool hasSentAttribution = false;
+
         for (auto& attribution : attributions) {
             auto earliestTimeToSend = attribution.earliestTimeToSend();
             if (!earliestTimeToSend) {
@@ -212,16 +212,28 @@
 
             auto now = WallTime::now();
             if (*earliestTimeToSend <= now || m_isRunningTest || debugModeEnabled()) {
+                if (hasSentAttribution) {
+                    // We've already sent an attribution this round. We should send additional overdue attributions at
+                    // a random time between 15 and 30 minutes to avoid a burst of simultaneous attributions. If debug
+                    // mode is enabled, this should be every minute for easy testing.
+                    auto interval = debugModeEnabled() ? 1_min : 15_min + Seconds(cryptographicallyRandomNumber() % 900);
+                    startTimer(interval);
+                    return;
+                }
+
                 fireConversionRequest(attribution);
-                sentAttributions.append(WTFMove(attribution));
+                clearSentAttribution(WTFMove(attribution));
+                hasSentAttribution = true;
                 continue;
             }
 
             auto seconds = *earliestTimeToSend - now;
             nextTimeToFire = std::min(nextTimeToFire, seconds);
+
+            // Attributions are sorted by earliestTimeToSend, so the first time we hit this there can be no further attributions
+            // due for reporting, and nextTimeToFire is the minimum earliestTimeToSend value for any pending attribution.
+            break;
         }
-        
-        clearSentAttributions(WTFMove(sentAttributions));
 
         if (nextTimeToFire < Seconds::infinity())
             startTimer(nextTimeToFire);

Modified: trunk/Source/WebKit/NetworkProcess/PrivateClickMeasurementManager.h (272659 => 272660)


--- trunk/Source/WebKit/NetworkProcess/PrivateClickMeasurementManager.h	2021-02-10 17:07:58 UTC (rev 272659)
+++ trunk/Source/WebKit/NetworkProcess/PrivateClickMeasurementManager.h	2021-02-10 17:38:10 UTC (rev 272660)
@@ -67,7 +67,7 @@
     void startTimer(Seconds);
 
 private:
-    void clearSentAttributions(Vector<PrivateClickMeasurement>&&);
+    void clearSentAttribution(PrivateClickMeasurement&&);
     void attribute(const SourceSite&, const AttributeOnSite&, AttributionTriggerData&&);
     void fireConversionRequest(const PrivateClickMeasurement&);
     void firePendingAttributionRequests();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to