Changeset 270136 in webkit
- Timestamp:
- Nov 20, 2020 4:38:46 PM (20 months ago)
- Location:
- trunk
- Files:
-
- 2 added
- 56 edited
- 2 copied
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/http/tests/contentextensions/block-private-click-measurement-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-cross-site-image-redirect-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-cross-site-image-redirect.html (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-in-new-window-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-in-new-window.html (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-with-priority-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-with-priority.html (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-without-priority-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-without-priority.html (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/conversion-disabled-in-ephemeral-session-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/expired-ad-click-gets-removed-on-session-start-expected.txt (added)
-
LayoutTests/http/tests/privateClickMeasurement/expired-ad-click-gets-removed-on-session-start.html (copied) (copied from trunk/LayoutTests/http/tests/privateClickMeasurement/second-conversion-with-higher-priority.html) (4 diffs)
-
LayoutTests/http/tests/privateClickMeasurement/expired-attribution-report-gets-sent-on-session-start-expected.txt (added)
-
LayoutTests/http/tests/privateClickMeasurement/expired-attribution-report-gets-sent-on-session-start.html (copied) (copied from trunk/LayoutTests/http/tests/privateClickMeasurement/send-attribution-conversion-request.html) (4 diffs)
-
LayoutTests/http/tests/privateClickMeasurement/resources/conversionReport.php (modified) (2 diffs)
-
LayoutTests/http/tests/privateClickMeasurement/resources/getConversionData.php (modified) (2 diffs)
-
LayoutTests/http/tests/privateClickMeasurement/second-attribution-converted-with-higher-priority-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/second-attribution-converted-with-higher-priority.html (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/second-attribution-converted-with-lower-priority-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/second-attribution-converted-with-lower-priority.html (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/second-conversion-with-higher-priority-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/second-conversion-with-higher-priority.html (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/second-conversion-with-lower-priority-expected.txt (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/second-conversion-with-lower-priority.html (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/send-attribution-conversion-request-expected.txt (modified) (2 diffs)
-
LayoutTests/http/tests/privateClickMeasurement/send-attribution-conversion-request.html (modified) (1 diff)
-
LayoutTests/http/tests/privateClickMeasurement/store-private-click-measurement-expected.txt (modified) (1 diff)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/html/HTMLAnchorElement.cpp (modified) (2 diffs)
-
Source/WebCore/loader/PrivateClickMeasurement.cpp (modified) (9 diffs)
-
Source/WebCore/loader/PrivateClickMeasurement.h (modified) (19 diffs)
-
Source/WebKit/ChangeLog (modified) (1 diff)
-
Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp (modified) (12 diffs)
-
Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h (modified) (4 diffs)
-
Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h (modified) (1 diff)
-
Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h (modified) (1 diff)
-
Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp (modified) (1 diff)
-
Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h (modified) (3 diffs)
-
Source/WebKit/NetworkProcess/NetworkProcess.cpp (modified) (1 diff)
-
Source/WebKit/NetworkProcess/NetworkProcess.h (modified) (2 diffs)
-
Source/WebKit/NetworkProcess/NetworkProcess.messages.in (modified) (1 diff)
-
Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp (modified) (4 diffs)
-
Source/WebKit/NetworkProcess/NetworkResourceLoader.h (modified) (2 diffs)
-
Source/WebKit/NetworkProcess/NetworkSession.cpp (modified) (5 diffs)
-
Source/WebKit/NetworkProcess/NetworkSession.h (modified) (1 diff)
-
Source/WebKit/NetworkProcess/PrivateClickMeasurementManager.cpp (modified) (8 diffs)
-
Source/WebKit/NetworkProcess/PrivateClickMeasurementManager.h (modified) (3 diffs)
-
Source/WebKit/UIProcess/API/C/WKPage.cpp (modified) (1 diff)
-
Source/WebKit/UIProcess/API/C/WKPagePrivate.h (modified) (1 diff)
-
Source/WebKit/UIProcess/WebPageProxy.cpp (modified) (2 diffs)
-
Source/WebKit/UIProcess/WebPageProxy.h (modified) (1 diff)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/TestWebKitAPI/Tests/WebCore/PrivateClickMeasurement.cpp (modified) (15 diffs)
-
Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl (modified) (1 diff)
-
Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp (modified) (1 diff)
-
Tools/WebKitTestRunner/InjectedBundle/TestRunner.h (modified) (1 diff)
-
Tools/WebKitTestRunner/TestController.cpp (modified) (1 diff)
-
Tools/WebKitTestRunner/TestController.h (modified) (1 diff)
-
Tools/WebKitTestRunner/TestInvocation.cpp (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r270133 r270136 1 2020-11-20 Kate Cheney <katherine_cheney@apple.com> 2 3 PCM: Persist pending ad clicks and attributions so they can survive browser restart 4 https://bugs.webkit.org/show_bug.cgi?id=219134 5 <rdar://problem/70470129> 6 7 Reviewed by John Wilander. 8 9 Added layout test coverage. Removed 'Conversion request sent:' 10 category in the toString() method because it will always be false. 11 Sent conversions are purged from the database, so it is not a useful 12 piece of information to report. Updated naming based on standards 13 coversations. 14 15 * http/tests/privateClickMeasurement/attribution-conversion-through-cross-site-image-redirect-expected.txt: 16 * http/tests/privateClickMeasurement/attribution-conversion-through-cross-site-image-redirect.html: 17 * http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-in-new-window-expected.txt: 18 * http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-in-new-window.html: 19 * http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-with-priority-expected.txt: 20 * http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-with-priority.html: 21 * http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-without-priority-expected.txt: 22 * http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-without-priority.html: 23 * http/tests/privateClickMeasurement/conversion-disabled-in-ephemeral-session-expected.txt: 24 * http/tests/privateClickMeasurement/expired-ad-click-gets-removed-on-session-start-expected.txt: Added. 25 * http/tests/privateClickMeasurement/expired-ad-click-gets-removed-on-session-start.html: Copied from LayoutTests/http/tests/privateClickMeasurement/second-conversion-with-higher-priority.html. 26 * http/tests/privateClickMeasurement/expired-attribution-report-gets-sent-on-session-start-expected.txt: Added. 27 * http/tests/privateClickMeasurement/expired-attribution-report-gets-sent-on-session-start.html: Copied from LayoutTests/http/tests/privateClickMeasurement/send-attribution-conversion-request.html. 28 * http/tests/privateClickMeasurement/resources/conversionReport.php: 29 * http/tests/privateClickMeasurement/resources/getConversionData.php: 30 * http/tests/privateClickMeasurement/second-attribution-converted-with-higher-priority-expected.txt: 31 * http/tests/privateClickMeasurement/second-attribution-converted-with-higher-priority.html: 32 * http/tests/privateClickMeasurement/second-attribution-converted-with-lower-priority-expected.txt: 33 * http/tests/privateClickMeasurement/second-attribution-converted-with-lower-priority.html: 34 * http/tests/privateClickMeasurement/second-conversion-with-higher-priority-expected.txt: 35 * http/tests/privateClickMeasurement/second-conversion-with-higher-priority.html: 36 * http/tests/privateClickMeasurement/second-conversion-with-lower-priority-expected.txt: 37 * http/tests/privateClickMeasurement/second-conversion-with-lower-priority.html: 38 * http/tests/privateClickMeasurement/send-attribution-conversion-request-expected.txt: 39 * http/tests/privateClickMeasurement/send-attribution-conversion-request.html: 40 * http/tests/privateClickMeasurement/store-private-click-measurement-expected.txt: 41 1 42 2020-11-20 Lauro Moura <lmoura@igalia.com> 2 43 -
trunk/LayoutTests/http/tests/contentextensions/block-private-click-measurement-expected.txt
r269712 r270136 8 8 Frame: '<!--frame1-->' 9 9 -------- 10 Conversion not received - timed out.10 Attribution not received - timed out. 11 11 12 Un converted Private Click Measurements:12 Unattributed Private Click Measurements: 13 13 WebCore::PrivateClickMeasurement 1 14 Source : 127.0.0.115 Destination: localhost16 CampaignID: 317 No conversiondata.14 Source site: 127.0.0.1 15 Attribute on site: localhost 16 Source ID: 3 17 No attribution trigger data. -
trunk/LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-cross-site-image-redirect-expected.txt
r269712 r270136 1 Tests that triggering of private click measurement conversions through cross-site redirects do not work.1 Tests that triggering of private click measurement attributions through cross-site redirects do not work. 2 2 3 3 4 Un converted Private Click Measurements:4 Unattributed Private Click Measurements: 5 5 WebCore::PrivateClickMeasurement 1 6 Source : 127.0.0.17 Destination: localhost8 CampaignID: 39 No conversiondata.6 Source site: 127.0.0.1 7 Attribute on site: localhost 8 Source ID: 3 9 No attribution trigger data. -
trunk/LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-cross-site-image-redirect.html
r269886 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests that triggering of private click measurement conversions through cross-site redirects do not work.</div>10 <div id="description">Tests that triggering of private click measurement attributions through cross-site redirects do not work.</div> 11 11 <a id="targetLink" href="http://localhost:8000/privateClickMeasurement/attribution-conversion-through-cross-site-image-redirect.html?stepTwo" attributionsourceid="3" attributeon="http://localhost:8000">Link</a><br> 12 12 <div id="output"></div> -
trunk/LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-in-new-window-expected.txt
r269712 r270136 1 Tests triggering of private click measurement conversions in a new window.1 Tests triggering of private click measurement attributions in a new window. 2 2 3 3 4 Converted Private Click Measurements:4 Attributed Private Click Measurements: 5 5 WebCore::PrivateClickMeasurement 1 6 Source: 127.0.0.1 7 Destination: localhost 8 Campaign ID: 3 9 Conversion data: 12 10 Conversion priority: 3 11 Conversion earliest time to send: Within 24-48 hours 12 Conversion request sent: false 6 Source site: 127.0.0.1 7 Attribute on site: localhost 8 Source ID: 3 9 Attribution trigger data: 12 10 Attribution priority: 3 11 Attribution earliest time to send: Within 24-48 hours -
trunk/LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-in-new-window.html
r269886 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests triggering of private click measurement conversions in a new window.</div>10 <div id="description">Tests triggering of private click measurement attributions in a new window.</div> 11 11 <a target="_blank" rel="opener" id="targetLink" href="http://localhost:8000/privateClickMeasurement/resources/convertAndPostMessageBack.html" attributionsourceid="3" attributeon="http://localhost:8000">Link</a><br> 12 12 <div id="output"></div> -
trunk/LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-with-priority-expected.txt
r269712 r270136 1 Tests triggering of private click measurement conversions with priority.1 Tests triggering of private click measurement attributions with priority. 2 2 3 3 4 Converted Private Click Measurements:4 Attributed Private Click Measurements: 5 5 WebCore::PrivateClickMeasurement 1 6 Source: 127.0.0.1 7 Destination: localhost 8 Campaign ID: 3 9 Conversion data: 12 10 Conversion priority: 3 11 Conversion earliest time to send: Within 24-48 hours 12 Conversion request sent: false 6 Source site: 127.0.0.1 7 Attribute on site: localhost 8 Source ID: 3 9 Attribution trigger data: 12 10 Attribution priority: 3 11 Attribution earliest time to send: Within 24-48 hours -
trunk/LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-with-priority.html
r269886 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests triggering of private click measurement conversions with priority.</div>10 <div id="description">Tests triggering of private click measurement attributions with priority.</div> 11 11 <a id="targetLink" href="http://localhost:8000/privateClickMeasurement/attribution-conversion-through-image-redirect-with-priority.html?stepTwo" attributionsourceid="3" attributeon="http://localhost:8000">Link</a><br> 12 12 <div id="output"></div> -
trunk/LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-without-priority-expected.txt
r269712 r270136 1 Tests triggering of private click measurement conversions without priority.1 Tests triggering of private click measurement attributions without priority. 2 2 3 3 4 Converted Private Click Measurements:4 Attributed Private Click Measurements: 5 5 WebCore::PrivateClickMeasurement 1 6 Source: 127.0.0.1 7 Destination: localhost 8 Campaign ID: 3 9 Conversion data: 12 10 Conversion priority: 0 11 Conversion earliest time to send: Within 24-48 hours 12 Conversion request sent: false 6 Source site: 127.0.0.1 7 Attribute on site: localhost 8 Source ID: 3 9 Attribution trigger data: 12 10 Attribution priority: 0 11 Attribution earliest time to send: Within 24-48 hours -
trunk/LayoutTests/http/tests/privateClickMeasurement/attribution-conversion-through-image-redirect-without-priority.html
r269886 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests triggering of private click measurement conversions without priority.</div>10 <div id="description">Tests triggering of private click measurement attributions without priority.</div> 11 11 <a id="targetLink" href="http://localhost:8000/privateClickMeasurement/attribution-conversion-through-image-redirect-without-priority.html?stepTwo" attributionsourceid="3" attributeon="http://localhost:8000">Link</a><br> 12 12 <div id="output"></div> -
trunk/LayoutTests/http/tests/privateClickMeasurement/conversion-disabled-in-ephemeral-session-expected.txt
r269712 r270136 6 6 Frame: '<!--frame1-->' 7 7 -------- 8 Conversion not received - timed out.8 Attribution not received - timed out. 9 9 10 Un converted Private Click Measurements:10 Unattributed Private Click Measurements: 11 11 WebCore::PrivateClickMeasurement 1 12 Source : 127.0.0.113 Destination: localhost14 CampaignID: 315 No conversiondata.12 Source site: 127.0.0.1 13 Attribute on site: localhost 14 Source ID: 3 15 No attribution trigger data. -
trunk/LayoutTests/http/tests/privateClickMeasurement/expired-ad-click-gets-removed-on-session-start.html
r270135 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests that the attribution is updated if it gets a second conversion with higher priority.</div>10 <div id="description">Tests that an expired ad click does not get converted on session start.</div> 11 11 <a id="targetLink">Link</a><br> 12 12 <div id="output"></div> 13 13 <script> 14 const path = "/privateClickMeasurement/ second-conversion-with-higher-priority.html";14 const path = "/privateClickMeasurement/expired-ad-click-gets-removed-on-session-start.html"; 15 15 const configuration = [ 16 16 { … … 44 44 } 45 45 46 function convert( priority,callback) {46 function convert(callback) { 47 47 let pixelElement = document.getElementById("pixel"); 48 48 if (pixelElement) … … 50 50 51 51 let imageElement = document.createElement("img"); 52 imageElement.src = "https://127.0.0.1:8443/privateClickMeasurement/resources/redirectToConversion.php?conversionData=12 &priority=" + priority;52 imageElement.src = "https://127.0.0.1:8443/privateClickMeasurement/resources/redirectToConversion.php?conversionData=12"; 53 53 imageElement.id = "pixel"; 54 54 imageElement.onerror = callback; … … 59 59 if (window.testRunner) { 60 60 if (window.location.search === "") { 61 // Ad click 127.0.0.1 –> localhost.62 61 configureLink(0); 63 62 activateElement("targetLink"); 64 63 } else if (window.location.search === "?stepTwo") { 65 // Convert the ad click with priority 3. 66 convert("03", function() { 67 // Convert the ad click with priority 4. 68 convert("04", function() { 69 testRunner.dumpPrivateClickMeasurement(); 70 document.body.removeChild(document.getElementById("targetLink")); 71 document.body.removeChild(document.getElementById("pixel")); 72 tearDownAndFinish(); 73 }); 64 window.testRunner.markPrivateClickMeasurementsAsExpiredForTesting(); 65 window.testRunner.simulateResourceLoadStatisticsSessionRestart(); 66 convert(function() { 67 testRunner.dumpPrivateClickMeasurement(); 68 document.body.removeChild(document.getElementById("targetLink")); 69 document.body.removeChild(document.getElementById("pixel")); 70 tearDownAndFinish(); 74 71 }); 75 } else {76 document.getElementById("output").innerText = "FAIL Unknown window.location.search == " + window.location.search + ".";77 tearDownAndFinish();78 72 } 79 73 } else { -
trunk/LayoutTests/http/tests/privateClickMeasurement/expired-attribution-report-gets-sent-on-session-start.html
r270135 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests sending of private click measurement requests after a conversion. Also tests that cookies are not sent in those requests and cookies are not accepted in the responses.</div>11 <a id="targetLink" href="http://localhost:8000/privateClickMeasurement/ send-attribution-conversion-request.html?stepTwo" attributionsourceid="3" attributeon="http://localhost:8000">Link</a><br>10 <div id="description">Tests sending of private click measurement requests after an attribution happens immediately for reports which have expired when a session is closed.</div> 11 <a id="targetLink" href="http://localhost:8000/privateClickMeasurement/expired-attribution-report-gets-sent-on-session-start.html?stepTwo" attributionsourceid="3" attributeon="http://localhost:8000">Link</a><br> 12 12 <div id="output"></div> 13 13 <script> … … 19 19 20 20 if (window.testRunner) { 21 testRunner.setPrivateClickMeasurementOverrideTimerForTesting(true);22 21 testRunner.setPrivateClickMeasurementConversionURLForTesting("http://127.0.0.1:8000/privateClickMeasurement/resources/conversionReport.php?nonce=" + nonce); 23 22 } … … 46 45 47 46 function appendConversionDataIframeAndFinish() { 47 // Mark this attribution as past-due for reporting, and simulate a session restart to 48 // make sure the attribution gets sent immediately. 49 window.testRunner.markAttributedPrivateClickMeasurementsAsExpiredForTesting(); 50 testRunner.simulateResourceLoadStatisticsSessionRestart(); 48 51 testRunner.dumpPrivateClickMeasurement(); 49 52 document.body.removeChild(document.getElementById("targetLink")); 50 53 document.body.removeChild(document.getElementById("pixel")); 51 54 52 appendIframe("http://127.0.0.1:8000/cookies/resources/echo-cookies.php");53 55 appendIframe("http://127.0.0.1:8000/privateClickMeasurement/resources/getConversionData.php?timeout_ms=2000&nonce=" + nonce, function() { 54 appendIframe("http://127.0.0.1:8000/cookies/resources/echo-cookies.php", function() { 55 tearDownAndFinish(); 56 }); 56 tearDownAndFinish(); 57 57 }); 58 58 } … … 69 69 document.body.appendChild(imageElement); 70 70 } else { 71 document.cookie = "cookieSetAsFirstParty=1; path=/";72 71 activateElement("targetLink"); 73 72 } -
trunk/LayoutTests/http/tests/privateClickMeasurement/resources/conversionReport.php
r269712 r270136 16 16 fwrite($conversionFile, "$name: $outputURL\n"); 17 17 } else if ($name === "HTTP_COOKIE") { 18 fwrite($conversionFile, "Cookies in conversion request: $value\n");18 fwrite($conversionFile, "Cookies in attribution request: $value\n"); 19 19 $cookiesFound = true; 20 20 } else if ($name === "CONTENT_TYPE") { … … 23 23 } 24 24 if (!$cookiesFound) { 25 fwrite($conversionFile, "No cookies in conversion request.\n");25 fwrite($conversionFile, "No cookies in attribution request.\n"); 26 26 } 27 27 -
trunk/LayoutTests/http/tests/privateClickMeasurement/resources/getConversionData.php
r269712 r270136 28 28 29 29 if ($conversionFileFound) { 30 echo " Conversion received.";30 echo "Attribution received."; 31 31 $conversionFile = fopen($conversionFilePath, 'r'); 32 32 while ($line = fgets($conversionFile)) { … … 38 38 unlink($conversionFilePath); 39 39 } else { 40 echo " Conversion not received - timed out.<br>";40 echo "Attribution not received - timed out.<br>"; 41 41 } 42 42 -
trunk/LayoutTests/http/tests/privateClickMeasurement/second-attribution-converted-with-higher-priority-expected.txt
r269712 r270136 1 Tests that a second attribution conversionwith higher priority replaces an older with lower priority.1 Tests that a second attribution with higher priority replaces an older with lower priority. 2 2 3 3 4 Converted Private Click Measurements:4 Attributed Private Click Measurements: 5 5 WebCore::PrivateClickMeasurement 1 6 Source: 127.0.0.1 7 Destination: localhost 8 Campaign ID: 4 9 Conversion data: 12 10 Conversion priority: 4 11 Conversion earliest time to send: Within 24-48 hours 12 Conversion request sent: false 6 Source site: 127.0.0.1 7 Attribute on site: localhost 8 Source ID: 4 9 Attribution trigger data: 12 10 Attribution priority: 4 11 Attribution earliest time to send: Within 24-48 hours -
trunk/LayoutTests/http/tests/privateClickMeasurement/second-attribution-converted-with-higher-priority.html
r269886 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests that a second attribution conversionwith higher priority replaces an older with lower priority.</div>10 <div id="description">Tests that a second attribution with higher priority replaces an older with lower priority.</div> 11 11 <a id="targetLink">Link</a><br> 12 12 <div id="output"></div> -
trunk/LayoutTests/http/tests/privateClickMeasurement/second-attribution-converted-with-lower-priority-expected.txt
r269712 r270136 1 Tests that a second attribution conversionwith lower priority does not replace an older with higher priority.1 Tests that a second attribution with lower priority does not replace an older with higher priority. 2 2 3 3 4 Converted Private Click Measurements:4 Attributed Private Click Measurements: 5 5 WebCore::PrivateClickMeasurement 1 6 Source: 127.0.0.1 7 Destination: localhost 8 Campaign ID: 3 9 Conversion data: 12 10 Conversion priority: 4 11 Conversion earliest time to send: Within 24-48 hours 12 Conversion request sent: false 6 Source site: 127.0.0.1 7 Attribute on site: localhost 8 Source ID: 3 9 Attribution trigger data: 12 10 Attribution priority: 4 11 Attribution earliest time to send: Within 24-48 hours -
trunk/LayoutTests/http/tests/privateClickMeasurement/second-attribution-converted-with-lower-priority.html
r269886 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests that a second attribution conversionwith lower priority does not replace an older with higher priority.</div>10 <div id="description">Tests that a second attribution with lower priority does not replace an older with higher priority.</div> 11 11 <a id="targetLink">Link</a><br> 12 12 <div id="output"></div> -
trunk/LayoutTests/http/tests/privateClickMeasurement/second-conversion-with-higher-priority-expected.txt
r269712 r270136 1 Tests that the attribution is updated if it gets a second conversion with higher priority.1 Tests that the attribution is updated if it gets a second attribution with higher priority. 2 2 3 3 4 Converted Private Click Measurements:4 Attributed Private Click Measurements: 5 5 WebCore::PrivateClickMeasurement 1 6 Source: 127.0.0.1 7 Destination: localhost 8 Campaign ID: 3 9 Conversion data: 12 10 Conversion priority: 4 11 Conversion earliest time to send: Within 24-48 hours 12 Conversion request sent: false 6 Source site: 127.0.0.1 7 Attribute on site: localhost 8 Source ID: 3 9 Attribution trigger data: 12 10 Attribution priority: 4 11 Attribution earliest time to send: Within 24-48 hours -
trunk/LayoutTests/http/tests/privateClickMeasurement/second-conversion-with-higher-priority.html
r269886 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests that the attribution is updated if it gets a second conversion with higher priority.</div>10 <div id="description">Tests that the attribution is updated if it gets a second attribution with higher priority.</div> 11 11 <a id="targetLink">Link</a><br> 12 12 <div id="output"></div> -
trunk/LayoutTests/http/tests/privateClickMeasurement/second-conversion-with-lower-priority-expected.txt
r269712 r270136 1 Tests that the attribution is not updated if it gets a second conversion with lower priority.1 Tests that the attribution is not updated if it gets a second attribution with lower priority. 2 2 3 3 4 Converted Private Click Measurements:4 Attributed Private Click Measurements: 5 5 WebCore::PrivateClickMeasurement 1 6 Source: 127.0.0.1 7 Destination: localhost 8 Campaign ID: 3 9 Conversion data: 12 10 Conversion priority: 4 11 Conversion earliest time to send: Within 24-48 hours 12 Conversion request sent: false 6 Source site: 127.0.0.1 7 Attribute on site: localhost 8 Source ID: 3 9 Attribution trigger data: 12 10 Attribution priority: 4 11 Attribution earliest time to send: Within 24-48 hours -
trunk/LayoutTests/http/tests/privateClickMeasurement/second-conversion-with-lower-priority.html
r269886 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests that the attribution is not updated if it gets a second conversion with lower priority.</div>10 <div id="description">Tests that the attribution is not updated if it gets a second attribution with lower priority.</div> 11 11 <a id="targetLink">Link</a><br> 12 12 <div id="output"></div> -
trunk/LayoutTests/http/tests/privateClickMeasurement/send-attribution-conversion-request-expected.txt
r269886 r270136 1 Tests sending of private click measurement requests after a conversion. Also tests that cookies are not sent in those requests and cookies are not accepted in the responses.1 Tests sending of private click measurement requests after an attribution. Also tests that cookies are not sent in those requests and cookies are not accepted in the responses. 2 2 3 3 … … 11 11 Frame: '<!--frame2-->' 12 12 -------- 13 Conversion received.13 Attribution received. 14 14 HTTP_HOST: 127.0.0.1:8000 15 15 Content type: application/json 16 16 REQUEST_URI: /privateClickMeasurement/resources/conversionReport.php 17 No cookies in conversion request.17 No cookies in attribution request. 18 18 Request body: 19 19 {"source-engagement-type":"click","source-site":"127.0.0.1","source-id":3,"attributed-on-site":"localhost","trigger-data":12,"report-version":1} -
trunk/LayoutTests/http/tests/privateClickMeasurement/send-attribution-conversion-request.html
r269886 r270136 8 8 </head> 9 9 <body onload="setTimeout(runTest, 0)"> 10 <div id="description">Tests sending of private click measurement requests after a conversion. Also tests that cookies are not sent in those requests and cookies are not accepted in the responses.</div>10 <div id="description">Tests sending of private click measurement requests after an attribution. Also tests that cookies are not sent in those requests and cookies are not accepted in the responses.</div> 11 11 <a id="targetLink" href="http://localhost:8000/privateClickMeasurement/send-attribution-conversion-request.html?stepTwo" attributionsourceid="3" attributeon="http://localhost:8000">Link</a><br> 12 12 <div id="output"></div> -
trunk/LayoutTests/http/tests/privateClickMeasurement/store-private-click-measurement-expected.txt
r269712 r270136 2 2 3 3 4 Un converted Private Click Measurements:4 Unattributed Private Click Measurements: 5 5 WebCore::PrivateClickMeasurement 1 6 Source : 127.0.0.17 Destination: localhost8 CampaignID: 39 No conversiondata.6 Source site: 127.0.0.1 7 Attribute on site: localhost 8 Source ID: 3 9 No attribution trigger data. -
trunk/Source/WebCore/ChangeLog
r270135 r270136 1 2020-11-20 Kate Cheney <katherine_cheney@apple.com> 2 3 PCM: Persist pending ad clicks and attributions so they can survive browser restart 4 https://bugs.webkit.org/show_bug.cgi?id=219134 5 <rdar://problem/70470129> 6 7 Reviewed by John Wilander. 8 9 This patch migrates PCM data to be stored on disk and 10 updates naming of various PCM data to match naming agreed 11 upon in standards bodies: 12 13 - source -> sourceSite 14 - campaign/campaignID -> sourceID 15 - destination -> attributeOnSite 16 - conversion/conversionValue -> attributionTriggerData 17 - unconverted -> unattributed 18 - convert(ed) -> attribute(d) 19 20 Tests: http/tests/privateClickMeasurement/expired-ad-click-gets-removed-on-session-start.html 21 http/tests/privateClickMeasurement/expired-attribution-report-gets-sent-on-session-start.html 22 23 * html/HTMLAnchorElement.cpp: 24 (WebCore::HTMLAnchorElement::parsePrivateClickMeasurement const): 25 * loader/PrivateClickMeasurement.cpp: 26 (WebCore::PrivateClickMeasurement::maxAge): 27 (WebCore::PrivateClickMeasurement::isValid const): 28 (WebCore::PrivateClickMeasurement::parseAttributionRequest): 29 (WebCore::PrivateClickMeasurement::attributeAndGetEarliestTimeToSend): 30 (WebCore::PrivateClickMeasurement::hasHigherPriorityThan const): 31 (WebCore::PrivateClickMeasurement::reportURL const): 32 (WebCore::PrivateClickMeasurement::json const): 33 (WebCore::PrivateClickMeasurement::parseConversionRequest): Deleted. 34 (WebCore::PrivateClickMeasurement::convertAndGetEarliestTimeToSend): Deleted. 35 Renaming. 36 37 (WebCore::PrivateClickMeasurement::markAsExpired): Deleted. 38 (WebCore::PrivateClickMeasurement::hasExpired const): Deleted. 39 (WebCore::PrivateClickMeasurement::markConversionAsSent): Deleted. 40 (WebCore::PrivateClickMeasurement::wasConversionSent const): Deleted. 41 We can remove the *Expired() functions as they were only indicators 42 for the HashMap storage to know what attributions to delete. This is 43 now handled by SQLite. Similarly, we can remove the markConversionAsSent 44 and wasConversionSent functions because a sent attribution will not 45 be stored in the database, so this value will always be false. 46 47 (WebCore::PrivateClickMeasurement::toString const): Deleted. 48 * loader/PrivateClickMeasurement.h: 49 (WebCore::PrivateClickMeasurement::SourceID::SourceID): 50 (WebCore::PrivateClickMeasurement::SourceSite::SourceSite): 51 (WebCore::PrivateClickMeasurement::SourceSite::operator== const): 52 (WebCore::PrivateClickMeasurement::SourceSite::deletedValue): 53 (WebCore::PrivateClickMeasurement::SourceSite::constructDeletedValue): 54 (WebCore::PrivateClickMeasurement::SourceSiteHash::hash): 55 (WebCore::PrivateClickMeasurement::SourceSiteHash::equal): 56 (WebCore::PrivateClickMeasurement::AttributeOnSite::AttributeOnSite): 57 (WebCore::PrivateClickMeasurement::AttributeOnSite::operator== const): 58 (WebCore::PrivateClickMeasurement::AttributeOnSite::deletedValue): 59 (WebCore::PrivateClickMeasurement::AttributeOnSite::constructDeletedValue): 60 (WebCore::PrivateClickMeasurement::AttributeOnSiteHash::hash): 61 (WebCore::PrivateClickMeasurement::AttributeOnSiteHash::equal): 62 (WebCore::PrivateClickMeasurement::AttributionTriggerData::AttributionTriggerData): 63 Renaming. 64 65 (WebCore::PrivateClickMeasurement::PrivateClickMeasurement): 66 (WebCore::PrivateClickMeasurement::sourceSite const): 67 (WebCore::PrivateClickMeasurement::attributeOnSite const): 68 (WebCore::PrivateClickMeasurement::timeOfAdClick const): 69 (WebCore::PrivateClickMeasurement::setEarliestTimeToSend): 70 (WebCore::PrivateClickMeasurement::sourceID): 71 (WebCore::PrivateClickMeasurement::attributionTriggerData): 72 (WebCore::PrivateClickMeasurement::setAttribution): 73 Now that we store data on disk, we need a more flexible constructor 74 and more functions to rebuild PCM objects from the database. 75 76 (WebCore::PrivateClickMeasurement::encode const): 77 (WebCore::PrivateClickMeasurement::decode): 78 (WebCore::PrivateClickMeasurement::AttributionTriggerData::encode const): 79 (WebCore::PrivateClickMeasurement::AttributionTriggerData::decode): 80 (WTF::HashTraits<WebCore::PrivateClickMeasurement::SourceSite>::emptyValue): 81 (WTF::HashTraits<WebCore::PrivateClickMeasurement::SourceSite>::constructDeletedValue): 82 (WTF::HashTraits<WebCore::PrivateClickMeasurement::SourceSite>::isDeletedValue): 83 (WTF::HashTraits<WebCore::PrivateClickMeasurement::AttributeOnSite>::emptyValue): 84 (WTF::HashTraits<WebCore::PrivateClickMeasurement::AttributeOnSite>::constructDeletedValue): 85 (WTF::HashTraits<WebCore::PrivateClickMeasurement::AttributeOnSite>::isDeletedValue): 86 (WebCore::PrivateClickMeasurement::Campaign::Campaign): Deleted. 87 (WebCore::PrivateClickMeasurement::Campaign::isValid const): Deleted. 88 (WebCore::PrivateClickMeasurement::Source::Source): Deleted. 89 (WebCore::PrivateClickMeasurement::Source::operator== const): Deleted. 90 (WebCore::PrivateClickMeasurement::Source::matches const): Deleted. 91 (WebCore::PrivateClickMeasurement::Source::isHashTableDeletedValue const): Deleted. 92 (WebCore::PrivateClickMeasurement::Source::deletedValue): Deleted. 93 (WebCore::PrivateClickMeasurement::Source::constructDeletedValue): Deleted. 94 (WebCore::PrivateClickMeasurement::Source::deleteValue): Deleted. 95 (WebCore::PrivateClickMeasurement::Source::isDeletedValue const): Deleted. 96 (WebCore::PrivateClickMeasurement::SourceHash::hash): Deleted. 97 (WebCore::PrivateClickMeasurement::SourceHash::equal): Deleted. 98 (WebCore::PrivateClickMeasurement::Destination::Destination): Deleted. 99 (WebCore::PrivateClickMeasurement::Destination::operator== const): Deleted. 100 (WebCore::PrivateClickMeasurement::Destination::matches const): Deleted. 101 (WebCore::PrivateClickMeasurement::Destination::isHashTableDeletedValue const): Deleted. 102 (WebCore::PrivateClickMeasurement::Destination::deletedValue): Deleted. 103 (WebCore::PrivateClickMeasurement::Destination::constructDeletedValue): Deleted. 104 (WebCore::PrivateClickMeasurement::Destination::deleteValue): Deleted. 105 (WebCore::PrivateClickMeasurement::Destination::isDeletedValue const): Deleted. 106 (WebCore::PrivateClickMeasurement::DestinationHash::hash): Deleted. 107 (WebCore::PrivateClickMeasurement::DestinationHash::equal): Deleted. 108 (WebCore::PrivateClickMeasurement::Conversion::Conversion): Deleted. 109 (WebCore::PrivateClickMeasurement::Conversion::isValid const): Deleted. 110 (WebCore::PrivateClickMeasurement::source const): Deleted. 111 (WebCore::PrivateClickMeasurement::destination const): Deleted. 112 Renaming. 113 114 (WebCore::PrivateClickMeasurement::isEmpty const): Deleted. 115 Not needed anymore, the database uses Optionals to indicate an empty result. 116 117 (WebCore::PrivateClickMeasurement::Conversion::encode const): Deleted. 118 (WebCore::PrivateClickMeasurement::Conversion::decode): Deleted. 119 (WTF::HashTraits<WebCore::PrivateClickMeasurement::Source>::emptyValue): Deleted. 120 (WTF::HashTraits<WebCore::PrivateClickMeasurement::Source>::constructDeletedValue): Deleted. 121 (WTF::HashTraits<WebCore::PrivateClickMeasurement::Source>::isDeletedValue): Deleted. 122 (WTF::HashTraits<WebCore::PrivateClickMeasurement::Destination>::emptyValue): Deleted. 123 (WTF::HashTraits<WebCore::PrivateClickMeasurement::Destination>::constructDeletedValue): Deleted. 124 (WTF::HashTraits<WebCore::PrivateClickMeasurement::Destination>::isDeletedValue): Deleted. 125 Renaming. 126 1 127 2020-11-20 Zalan Bujtas <zalan@apple.com> 2 128 -
trunk/Source/WebCore/html/HTMLAnchorElement.cpp
r269953 r270136 401 401 Optional<PrivateClickMeasurement> HTMLAnchorElement::parsePrivateClickMeasurement() const 402 402 { 403 using Campaign = PrivateClickMeasurement::Campaign;404 using Source = PrivateClickMeasurement::Source;405 using Destination = PrivateClickMeasurement::Destination;403 using SourceID = PrivateClickMeasurement::SourceID; 404 using SourceSite = PrivateClickMeasurement::SourceSite; 405 using AttributeOnSite = PrivateClickMeasurement::AttributeOnSite; 406 406 407 407 auto* page = document().page(); … … 451 451 } 452 452 453 return PrivateClickMeasurement { Campaign(attributionSourceID.value()), Source(documentRegistrableDomain), Destination(attributeOnURL) };453 return PrivateClickMeasurement { SourceID(attributionSourceID.value()), SourceSite(documentRegistrableDomain), AttributeOnSite(attributeOnURL) }; 454 454 } 455 455 -
trunk/Source/WebCore/loader/PrivateClickMeasurement.cpp
r269886 r270136 38 38 39 39 static const char privateClickMeasurementPathPrefix[] = "/.well-known/private-click-measurement/"; 40 const size_t privateClickMeasurement ConversionDataPathSegmentSize = 2;40 const size_t privateClickMeasurementAttributionTriggerDataPathSegmentSize = 2; 41 41 const size_t privateClickMeasurementPriorityPathSegmentSize = 2; 42 const Seconds maxAge { 24_h * 7 }; 42 43 const Seconds PrivateClickMeasurement::maxAge() 44 { 45 return 24_h * 7; 46 }; 43 47 44 48 bool PrivateClickMeasurement::isValid() const 45 49 { 46 return m_ conversion47 && m_ conversion.value().isValid()48 && m_ campaign.isValid()49 && !m_source .registrableDomain.isEmpty()50 && !m_ destination.registrableDomain.isEmpty()50 return m_attributionTriggerData 51 && m_attributionTriggerData.value().isValid() 52 && m_sourceID.isValid() 53 && !m_sourceSite.registrableDomain.isEmpty() 54 && !m_attributeOnSite.registrableDomain.isEmpty() 51 55 && m_earliestTimeToSend; 52 56 } 53 57 54 Expected<PrivateClickMeasurement:: Conversion, String> PrivateClickMeasurement::parseConversionRequest(const URL& redirectURL)58 Expected<PrivateClickMeasurement::AttributionTriggerData, String> PrivateClickMeasurement::parseAttributionRequest(const URL& redirectURL) 55 59 { 56 60 if (!redirectURL.protocolIs("https") || redirectURL.hasCredentials() || redirectURL.hasQuery() || redirectURL.hasFragmentIdentifier()) { … … 72 76 73 77 auto prefixLength = sizeof(privateClickMeasurementPathPrefix) - 1; 74 if (path.length() == prefixLength + privateClickMeasurement ConversionDataPathSegmentSize) {75 auto conversionDataUInt64 = path.substring(prefixLength, privateClickMeasurementConversionDataPathSegmentSize).toUInt64Strict();76 if (! conversionDataUInt64 || *conversionDataUInt64 > MaxEntropy) {78 if (path.length() == prefixLength + privateClickMeasurementAttributionTriggerDataPathSegmentSize) { 79 auto attributionTriggerDataUInt64 = path.substring(prefixLength, privateClickMeasurementAttributionTriggerDataPathSegmentSize).toUInt64Strict(); 80 if (!attributionTriggerDataUInt64 || *attributionTriggerDataUInt64 > MaxEntropy) { 77 81 if (UNLIKELY(debugModeEnabled())) { 78 82 RELEASE_LOG_INFO(PrivateClickMeasurement, "Conversion was not accepted because the conversion data could not be parsed or was higher than the allowed maximum of %{public}u.", MaxEntropy); … … 82 86 } 83 87 84 return Conversion { static_cast<uint32_t>(*conversionDataUInt64), Priority { 0 } };88 return AttributionTriggerData { static_cast<uint32_t>(*attributionTriggerDataUInt64), Priority { 0 } }; 85 89 } 86 90 87 if (path.length() == prefixLength + privateClickMeasurement ConversionDataPathSegmentSize + 1 + privateClickMeasurementPriorityPathSegmentSize) {88 auto conversionDataUInt64 = path.substring(prefixLength, privateClickMeasurementConversionDataPathSegmentSize).toUInt64Strict();89 if (! conversionDataUInt64 || *conversionDataUInt64 > MaxEntropy) {91 if (path.length() == prefixLength + privateClickMeasurementAttributionTriggerDataPathSegmentSize + 1 + privateClickMeasurementPriorityPathSegmentSize) { 92 auto attributionTriggerDataUInt64 = path.substring(prefixLength, privateClickMeasurementAttributionTriggerDataPathSegmentSize).toUInt64Strict(); 93 if (!attributionTriggerDataUInt64 || *attributionTriggerDataUInt64 > MaxEntropy) { 90 94 if (UNLIKELY(debugModeEnabled())) { 91 95 RELEASE_LOG_INFO(PrivateClickMeasurement, "Conversion was not accepted because the conversion data could not be parsed or was higher than the allowed maximum of %{public}u.", MaxEntropy); … … 95 99 } 96 100 97 auto conversionPriorityUInt64 = path.substring(prefixLength + privateClickMeasurementConversionDataPathSegmentSize + 1, privateClickMeasurementPriorityPathSegmentSize).toUInt64Strict();98 if (! conversionPriorityUInt64 || *conversionPriorityUInt64 > MaxEntropy) {101 auto attributionPriorityUInt64 = path.substring(prefixLength + privateClickMeasurementAttributionTriggerDataPathSegmentSize + 1, privateClickMeasurementPriorityPathSegmentSize).toUInt64Strict(); 102 if (!attributionPriorityUInt64 || *attributionPriorityUInt64 > MaxEntropy) { 99 103 if (UNLIKELY(debugModeEnabled())) { 100 104 RELEASE_LOG_INFO(PrivateClickMeasurement, "Conversion was not accepted because the priority could not be parsed or was higher than the allowed maximum of %{public}u.", MaxEntropy); … … 104 108 } 105 109 106 return Conversion { static_cast<uint32_t>(*conversionDataUInt64), Priority { static_cast<uint32_t>(*conversionPriorityUInt64) } };110 return AttributionTriggerData { static_cast<uint32_t>(*attributionTriggerDataUInt64), Priority { static_cast<uint32_t>(*attributionPriorityUInt64) } }; 107 111 } 108 112 … … 114 118 } 115 119 116 Optional<Seconds> PrivateClickMeasurement:: convertAndGetEarliestTimeToSend(Conversion&& conversion)120 Optional<Seconds> PrivateClickMeasurement::attributeAndGetEarliestTimeToSend(AttributionTriggerData&& attributionTriggerData) 117 121 { 118 if (! conversion.isValid() || (m_conversion && m_conversion->priority >= conversion.priority))122 if (!attributionTriggerData.isValid() || (m_attributionTriggerData && m_attributionTriggerData->priority >= attributionTriggerData.priority)) 119 123 return { }; 120 124 121 m_ conversion = WTFMove(conversion);125 m_attributionTriggerData = WTFMove(attributionTriggerData); 122 126 // 24-48 hour delay before sending. This helps privacy since the conversion and the attribution 123 127 // requests are detached and the time of the attribution does not reveal the time of the conversion. … … 127 131 } 128 132 129 void PrivateClickMeasurement::markAsExpired()130 {131 m_timeOfAdClick = { };132 }133 134 bool PrivateClickMeasurement::hasExpired() const135 {136 return WallTime::now() > m_timeOfAdClick + maxAge;137 }138 139 133 bool PrivateClickMeasurement::hasHigherPriorityThan(const PrivateClickMeasurement& other) const 140 134 { 141 if (!other.m_ conversion)135 if (!other.m_attributionTriggerData) 142 136 return true; 143 137 144 if (!m_ conversion)138 if (!m_attributionTriggerData) 145 139 return false; 146 140 147 return m_ conversion->priority > other.m_conversion->priority;141 return m_attributionTriggerData->priority > other.m_attributionTriggerData->priority; 148 142 } 149 143 … … 155 149 StringBuilder builder; 156 150 builder.appendLiteral("https://"); 157 builder.append(m_source .registrableDomain.string());151 builder.append(m_sourceSite.registrableDomain.string()); 158 152 builder.appendLiteral(privateClickMeasurementPathPrefix); 159 153 … … 168 162 { 169 163 auto reportDetails = JSON::Object::create(); 170 if (!m_ conversion)164 if (!m_attributionTriggerData) 171 165 return reportDetails; 172 166 173 167 reportDetails->setString("source-engagement-type"_s, "click"_s); 174 reportDetails->setString("source-site"_s, m_source .registrableDomain.string());175 reportDetails->setInteger("source-id"_s, m_ campaign.id);176 reportDetails->setString("attributed-on-site"_s, m_ destination.registrableDomain.string());177 reportDetails->setInteger("trigger-data"_s, m_ conversion->data);168 reportDetails->setString("source-site"_s, m_sourceSite.registrableDomain.string()); 169 reportDetails->setInteger("source-id"_s, m_sourceID.id); 170 reportDetails->setString("attributed-on-site"_s, m_attributeOnSite.registrableDomain.string()); 171 reportDetails->setInteger("trigger-data"_s, m_attributionTriggerData->data); 178 172 reportDetails->setInteger("report-version"_s, 1); 179 173 return reportDetails; 180 }181 182 void PrivateClickMeasurement::markConversionAsSent()183 {184 ASSERT(m_conversion);185 if (m_conversion)186 m_conversion->wasSent = Conversion::WasSent::Yes;187 }188 189 bool PrivateClickMeasurement::wasConversionSent() const190 {191 return m_conversion && m_conversion->wasSent == Conversion::WasSent::Yes;192 }193 194 String PrivateClickMeasurement::toString() const195 {196 StringBuilder builder;197 builder.appendLiteral("Source: ");198 builder.append(m_source.registrableDomain.string());199 builder.appendLiteral("\nDestination: ");200 builder.append(m_destination.registrableDomain.string());201 builder.appendLiteral("\nCampaign ID: ");202 builder.appendNumber(m_campaign.id);203 if (m_conversion) {204 builder.appendLiteral("\nConversion data: ");205 builder.appendNumber(m_conversion.value().data);206 builder.appendLiteral("\nConversion priority: ");207 builder.appendNumber(m_conversion.value().priority);208 builder.appendLiteral("\nConversion earliest time to send: ");209 if (!m_earliestTimeToSend)210 builder.appendLiteral("Not set");211 else {212 auto secondsUntilSend = *m_earliestTimeToSend - WallTime::now();213 builder.append((secondsUntilSend >= 24_h && secondsUntilSend <= 48_h) ? "Within 24-48 hours" : "Outside 24-48 hours");214 }215 builder.appendLiteral("\nConversion request sent: ");216 builder.append((wasConversionSent() ? "true" : "false"));217 } else218 builder.appendLiteral("\nNo conversion data.");219 builder.append('\n');220 221 return builder.toString();222 174 } 223 175 -
trunk/Source/WebCore/loader/PrivateClickMeasurement.h
r269712 r270136 40 40 class PrivateClickMeasurement { 41 41 public: 42 using CampaignId = uint32_t;43 using ConversionData = uint32_t;44 42 using PriorityValue = uint32_t; 45 43 46 44 static constexpr uint32_t MaxEntropy = 63; 47 45 48 struct Campaign{49 Campaign() = default;50 explicit Campaign(CampaignIdid)46 struct SourceID { 47 SourceID() = default; 48 explicit SourceID(uint32_t id) 51 49 : id { id } 52 50 { … … 58 56 } 59 57 60 CampaignIdid { 0 };61 }; 62 63 struct Source {64 Source () = default;65 explicit Source (const URL& url)58 uint32_t id { 0 }; 59 }; 60 61 struct SourceSite { 62 SourceSite() = default; 63 explicit SourceSite(const URL& url) 66 64 : registrableDomain { url } 67 65 { 68 66 } 69 67 70 explicit Source (const RegistrableDomain& domain)68 explicit SourceSite(const RegistrableDomain& domain) 71 69 : registrableDomain { domain } 72 70 { 73 71 } 74 72 75 explicit Source (WTF::HashTableDeletedValueType)73 explicit SourceSite(WTF::HashTableDeletedValueType) 76 74 : registrableDomain(WTF::HashTableDeletedValue) 77 75 { 78 76 } 79 77 80 bool operator==(const Source & other) const78 bool operator==(const SourceSite& other) const 81 79 { 82 80 return registrableDomain == other.registrableDomain; … … 93 91 } 94 92 95 static Source deletedValue()96 { 97 return Source { WTF::HashTableDeletedValue };98 } 99 100 static void constructDeletedValue(Source & source)101 { 102 new (&source ) Source;103 source = Source::deletedValue();93 static SourceSite deletedValue() 94 { 95 return SourceSite { WTF::HashTableDeletedValue }; 96 } 97 98 static void constructDeletedValue(SourceSite& sourceSite) 99 { 100 new (&sourceSite) SourceSite; 101 sourceSite = SourceSite::deletedValue(); 104 102 } 105 103 … … 117 115 }; 118 116 119 struct Source Hash {120 static unsigned hash(const Source & source)121 { 122 return source .registrableDomain.hash();123 } 124 125 static bool equal(const Source & a, const Source& b)117 struct SourceSiteHash { 118 static unsigned hash(const SourceSite& sourceSite) 119 { 120 return sourceSite.registrableDomain.hash(); 121 } 122 123 static bool equal(const SourceSite& a, const SourceSite& b) 126 124 { 127 125 return a == b; … … 131 129 }; 132 130 133 struct Destination{134 Destination() = default;135 explicit Destination(const URL& url)131 struct AttributeOnSite { 132 AttributeOnSite() = default; 133 explicit AttributeOnSite(const URL& url) 136 134 : registrableDomain { RegistrableDomain { url } } 137 135 { 138 136 } 139 137 140 explicit Destination(WTF::HashTableDeletedValueType)138 explicit AttributeOnSite(WTF::HashTableDeletedValueType) 141 139 : registrableDomain { WTF::HashTableDeletedValue } 142 140 { 143 141 } 144 142 145 explicit Destination(RegistrableDomain&& domain)143 explicit AttributeOnSite(RegistrableDomain&& domain) 146 144 : registrableDomain { WTFMove(domain) } 147 145 { 148 146 } 149 147 150 bool operator==(const Destination& other) const148 bool operator==(const AttributeOnSite& other) const 151 149 { 152 150 return registrableDomain == other.registrableDomain; … … 163 161 } 164 162 165 static DestinationdeletedValue()166 { 167 return Destination{ WTF::HashTableDeletedValue };168 } 169 170 static void constructDeletedValue( Destination& destination)171 { 172 new (& destination) Destination;173 destination = Destination::deletedValue();163 static AttributeOnSite deletedValue() 164 { 165 return AttributeOnSite { WTF::HashTableDeletedValue }; 166 } 167 168 static void constructDeletedValue(AttributeOnSite& attributeOnSite) 169 { 170 new (&attributeOnSite) AttributeOnSite; 171 attributeOnSite = AttributeOnSite::deletedValue(); 174 172 } 175 173 … … 187 185 }; 188 186 189 struct DestinationHash {190 static unsigned hash(const Destination& destination)191 { 192 return destination.registrableDomain.hash();193 } 194 195 static bool equal(const Destination& a, const Destination& b)187 struct AttributeOnSiteHash { 188 static unsigned hash(const AttributeOnSite& attributeOnSite) 189 { 190 return attributeOnSite.registrableDomain.hash(); 191 } 192 193 static bool equal(const AttributeOnSite& a, const AttributeOnSite& b) 196 194 { 197 195 return a == b; … … 210 208 }; 211 209 212 struct Conversion{210 struct AttributionTriggerData { 213 211 enum class WasSent : bool { No, Yes }; 214 212 215 Conversion(ConversionDatadata, Priority priority, WasSent wasSent = WasSent::No)213 AttributionTriggerData(uint32_t data, Priority priority, WasSent wasSent = WasSent::No) 216 214 : data { data } 217 215 , priority { priority.value } … … 225 223 } 226 224 227 ConversionDatadata;225 uint32_t data; 228 226 PriorityValue priority; 229 227 WasSent wasSent = WasSent::No; 230 228 231 229 template<class Encoder> void encode(Encoder&) const; 232 template<class Decoder> static Optional< Conversion> decode(Decoder&);230 template<class Decoder> static Optional<AttributionTriggerData> decode(Decoder&); 233 231 }; 234 232 235 233 PrivateClickMeasurement() = default; 236 PrivateClickMeasurement( Campaign campaign, const Source& source, const Destination& destination)237 : m_ campaign { campaign}238 , m_source { source }239 , m_ destination { destination}240 , m_timeOfAdClick { WallTime::now()}234 PrivateClickMeasurement(SourceID sourceID, const SourceSite& sourceSite, const AttributeOnSite& attributeOnSite, WallTime timeOfAdClick = WallTime::now()) 235 : m_sourceID { sourceID } 236 , m_sourceSite { sourceSite } 237 , m_attributeOnSite { attributeOnSite } 238 , m_timeOfAdClick { timeOfAdClick } 241 239 { 242 240 } 243 241 244 WEBCORE_EXPORT static Expected<Conversion, String> parseConversionRequest(const URL& redirectURL); 245 WEBCORE_EXPORT Optional<Seconds> convertAndGetEarliestTimeToSend(Conversion&&); 242 WEBCORE_EXPORT static const Seconds maxAge(); 243 WEBCORE_EXPORT static Expected<AttributionTriggerData, String> parseAttributionRequest(const URL& redirectURL); 244 WEBCORE_EXPORT Optional<Seconds> attributeAndGetEarliestTimeToSend(AttributionTriggerData&&); 246 245 WEBCORE_EXPORT bool hasHigherPriorityThan(const PrivateClickMeasurement&) const; 247 246 WEBCORE_EXPORT URL reportURL() const; 248 247 WEBCORE_EXPORT Ref<JSON::Object> json() const; 249 const Source& source() const { return m_source; }; 250 const Destination& destination() const { return m_destination; }; 248 const SourceSite& sourceSite() const { return m_sourceSite; }; 249 const AttributeOnSite& attributeOnSite() const { return m_attributeOnSite; }; 250 WallTime timeOfAdClick() const { return m_timeOfAdClick; } 251 251 Optional<WallTime> earliestTimeToSend() const { return m_earliestTimeToSend; }; 252 WEBCORE_EXPORT void markAsExpired(); 253 WEBCORE_EXPORT bool hasExpired() const; 254 WEBCORE_EXPORT void markConversionAsSent(); 255 WEBCORE_EXPORT bool wasConversionSent() const; 256 257 bool isEmpty() const { return m_source.registrableDomain.isEmpty(); }; 258 259 WEBCORE_EXPORT String toString() const; 252 void setEarliestTimeToSend(WallTime time) { m_earliestTimeToSend = time; } 253 SourceID sourceID() { return m_sourceID; } 254 Optional<AttributionTriggerData> attributionTriggerData() { return m_attributionTriggerData; } 255 void setAttribution(AttributionTriggerData&& attributionTriggerData) { m_attributionTriggerData = WTFMove(attributionTriggerData); } 260 256 261 257 template<class Encoder> void encode(Encoder&) const; … … 266 262 static bool debugModeEnabled(); 267 263 268 Campaign m_campaign;269 Source m_source;270 Destination m_destination;264 SourceID m_sourceID; 265 SourceSite m_sourceSite; 266 AttributeOnSite m_attributeOnSite; 271 267 WallTime m_timeOfAdClick; 272 268 273 Optional< Conversion> m_conversion;269 Optional<AttributionTriggerData> m_attributionTriggerData; 274 270 Optional<WallTime> m_earliestTimeToSend; 275 271 }; … … 278 274 void PrivateClickMeasurement::encode(Encoder& encoder) const 279 275 { 280 encoder << m_ campaign.id << m_source.registrableDomain << m_destination.registrableDomain << m_timeOfAdClick << m_conversion<< m_earliestTimeToSend;276 encoder << m_sourceID.id << m_sourceSite.registrableDomain << m_attributeOnSite.registrableDomain << m_timeOfAdClick << m_attributionTriggerData << m_earliestTimeToSend; 281 277 } 282 278 … … 284 280 Optional<PrivateClickMeasurement> PrivateClickMeasurement::decode(Decoder& decoder) 285 281 { 286 Optional< CampaignId> campaignId;287 decoder >> campaignId;288 if (! campaignId)282 Optional<uint32_t> sourceID; 283 decoder >> sourceID; 284 if (!sourceID) 289 285 return WTF::nullopt; 290 286 … … 294 290 return WTF::nullopt; 295 291 296 Optional<RegistrableDomain> destinationRegistrableDomain;297 decoder >> destinationRegistrableDomain;298 if (! destinationRegistrableDomain)292 Optional<RegistrableDomain> attributeOnRegistrableDomain; 293 decoder >> attributeOnRegistrableDomain; 294 if (!attributeOnRegistrableDomain) 299 295 return WTF::nullopt; 300 296 … … 304 300 return WTF::nullopt; 305 301 306 Optional<Optional< Conversion>> conversion;307 decoder >> conversion;308 if (! conversion)302 Optional<Optional<AttributionTriggerData>> attributionTriggerData; 303 decoder >> attributionTriggerData; 304 if (!attributionTriggerData) 309 305 return WTF::nullopt; 310 306 … … 314 310 return WTF::nullopt; 315 311 316 PrivateClickMeasurement attribution { Campaign { WTFMove(*campaignId) }, Source { WTFMove(*sourceRegistrableDomain) }, Destination { WTFMove(*destinationRegistrableDomain) } };317 attribution.m_ conversion = WTFMove(*conversion);312 PrivateClickMeasurement attribution { SourceID { WTFMove(*sourceID) }, SourceSite { WTFMove(*sourceRegistrableDomain) }, AttributeOnSite { WTFMove(*attributeOnRegistrableDomain) } }; 313 attribution.m_attributionTriggerData = WTFMove(*attributionTriggerData); 318 314 attribution.m_earliestTimeToSend = WTFMove(*earliestTimeToSend); 319 315 … … 322 318 323 319 template<class Encoder> 324 void PrivateClickMeasurement:: Conversion::encode(Encoder& encoder) const320 void PrivateClickMeasurement::AttributionTriggerData::encode(Encoder& encoder) const 325 321 { 326 322 encoder << data << priority << wasSent; … … 328 324 329 325 template<class Decoder> 330 Optional<PrivateClickMeasurement:: Conversion> PrivateClickMeasurement::Conversion::decode(Decoder& decoder)326 Optional<PrivateClickMeasurement::AttributionTriggerData> PrivateClickMeasurement::AttributionTriggerData::decode(Decoder& decoder) 331 327 { 332 Optional< ConversionData> data;328 Optional<uint32_t> data; 333 329 decoder >> data; 334 330 if (!data) … … 345 341 return WTF::nullopt; 346 342 347 return Conversion{ WTFMove(*data), Priority { *priority }, *wasSent };343 return AttributionTriggerData { WTFMove(*data), Priority { *priority }, *wasSent }; 348 344 } 349 345 … … 353 349 template<typename T> struct DefaultHash; 354 350 355 template<> struct DefaultHash<WebCore::PrivateClickMeasurement::Source > : WebCore::PrivateClickMeasurement::SourceHash { };356 template<> struct HashTraits<WebCore::PrivateClickMeasurement::Source > : GenericHashTraits<WebCore::PrivateClickMeasurement::Source> {357 static WebCore::PrivateClickMeasurement::Source emptyValue() { return { }; }358 static void constructDeletedValue(WebCore::PrivateClickMeasurement::Source & slot) { WebCore::PrivateClickMeasurement::Source::constructDeletedValue(slot); }359 static bool isDeletedValue(const WebCore::PrivateClickMeasurement::Source & slot) { return slot.isDeletedValue(); }351 template<> struct DefaultHash<WebCore::PrivateClickMeasurement::SourceSite> : WebCore::PrivateClickMeasurement::SourceSiteHash { }; 352 template<> struct HashTraits<WebCore::PrivateClickMeasurement::SourceSite> : GenericHashTraits<WebCore::PrivateClickMeasurement::SourceSite> { 353 static WebCore::PrivateClickMeasurement::SourceSite emptyValue() { return { }; } 354 static void constructDeletedValue(WebCore::PrivateClickMeasurement::SourceSite& slot) { WebCore::PrivateClickMeasurement::SourceSite::constructDeletedValue(slot); } 355 static bool isDeletedValue(const WebCore::PrivateClickMeasurement::SourceSite& slot) { return slot.isDeletedValue(); } 360 356 }; 361 357 362 template<> struct DefaultHash<WebCore::PrivateClickMeasurement:: Destination> : WebCore::PrivateClickMeasurement::DestinationHash { };363 template<> struct HashTraits<WebCore::PrivateClickMeasurement:: Destination> : GenericHashTraits<WebCore::PrivateClickMeasurement::Destination> {364 static WebCore::PrivateClickMeasurement:: DestinationemptyValue() { return { }; }365 static void constructDeletedValue(WebCore::PrivateClickMeasurement:: Destination& slot) { WebCore::PrivateClickMeasurement::Destination::constructDeletedValue(slot); }366 static bool isDeletedValue(const WebCore::PrivateClickMeasurement:: Destination& slot) { return slot.isDeletedValue(); }358 template<> struct DefaultHash<WebCore::PrivateClickMeasurement::AttributeOnSite> : WebCore::PrivateClickMeasurement::AttributeOnSiteHash { }; 359 template<> struct HashTraits<WebCore::PrivateClickMeasurement::AttributeOnSite> : GenericHashTraits<WebCore::PrivateClickMeasurement::AttributeOnSite> { 360 static WebCore::PrivateClickMeasurement::AttributeOnSite emptyValue() { return { }; } 361 static void constructDeletedValue(WebCore::PrivateClickMeasurement::AttributeOnSite& slot) { WebCore::PrivateClickMeasurement::AttributeOnSite::constructDeletedValue(slot); } 362 static bool isDeletedValue(const WebCore::PrivateClickMeasurement::AttributeOnSite& slot) { return slot.isDeletedValue(); } 367 363 }; 368 364 } -
trunk/Source/WebKit/ChangeLog
r270130 r270136 1 2020-11-20 Kate Cheney <katherine_cheney@apple.com> 2 3 PCM: Persist pending ad clicks and attributions so they can survive browser restart 4 https://bugs.webkit.org/show_bug.cgi?id=219134 5 <rdar://problem/70470129> 6 7 Reviewed by John Wilander. 8 9 This patch migrates Private Click Measurement to use SQLite, 10 which is beneficial because it requires less in-memory storage and 11 persists PCM data across browser sessions. It also updates naming 12 to match naming agreed upon in standards bodies: 13 14 - source -> sourceSite 15 - campaign/campaignID -> sourceID 16 - destination -> attributeOnSite 17 - conversion/conversionValue -> attributionTriggerData 18 - unconverted -> unattributed 19 - convert(ed) -> attribute(d) 20 21 This adds 3 SQLite tables: one for clicks that haven't been 22 attributed, one for attributions that haven't been sent, and one to 23 store the last time the reports were sent to make sure reports get 24 sent as soon as possible if needed after a browser restart. 25 26 Behavior is identical to existing PCM implementation with the addition 27 of persistence. Existing PCM tests confirm no regressions. 28 29 Reviewed by John Wilander. 30 31 * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp: 32 (WebKit::createTableQueries): 33 (WebKit::ResourceLoadStatisticsDatabaseStore::ResourceLoadStatisticsDatabaseStore): 34 (WebKit::ResourceLoadStatisticsDatabaseStore::createUniqueIndices): 35 (WebKit::ResourceLoadStatisticsDatabaseStore::createSchema): 36 (WebKit::ResourceLoadStatisticsDatabaseStore::destroyStatements): 37 New queries to interact with PCM data. 38 39 (WebKit::ResourceLoadStatisticsDatabaseStore::updateTimerLastFired): 40 (WebKit::ResourceLoadStatisticsDatabaseStore::timerLastFired): 41 (WebKit::ResourceLoadStatisticsDatabaseStore::updatePrivateClickMeasurementAttributionTimes): 42 Set earliestTimeToSend to be the original value minus the time passed since the last timer fire 43 for each entry. If the result is less than 0, set to 0 so the report gets sent immediately. 44 45 (WebKit::ResourceLoadStatisticsDatabaseStore::buildPrivateClickMeasurementFromDatabase): 46 Creates a PCM object from data in the database. 47 48 (WebKit::ResourceLoadStatisticsDatabaseStore::findPrivateClickMeasurement): 49 (WebKit::ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement): 50 (WebKit::ResourceLoadStatisticsDatabaseStore::markAllUnattributedPrivateClickMeasurementAsExpiredForTesting): 51 (WebKit::ResourceLoadStatisticsDatabaseStore::removeUnattributed): 52 (WebKit::ResourceLoadStatisticsDatabaseStore::attributePrivateClickMeasurement): 53 (WebKit::ResourceLoadStatisticsDatabaseStore::allAttributedPrivateClickMeasurement): 54 (WebKit::ResourceLoadStatisticsDatabaseStore::clearPrivateClickMeasurement): 55 (WebKit::ResourceLoadStatisticsDatabaseStore::clearExpiredPrivateClickMeasurement): 56 (WebKit::ResourceLoadStatisticsDatabaseStore::attributionToString): 57 (WebKit::ResourceLoadStatisticsDatabaseStore::privateClickMeasurementToString): 58 (WebKit::ResourceLoadStatisticsDatabaseStore::clearSentAttributions): 59 These functions use database queries to implement PCM functionality with exactly the same 60 behavior as the in-memory PCM implementation. 61 62 (WebKit::ResourceLoadStatisticsDatabaseStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting): 63 * NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h: 64 * NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h: 65 * NetworkProcess/Classifier/ResourceLoadStatisticsStore.h: 66 * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp: 67 (WebKit::WebResourceLoadStatisticsStore::updateTimerLastFired): 68 (WebKit::WebResourceLoadStatisticsStore::insertPrivateClickMeasurement): 69 (WebKit::WebResourceLoadStatisticsStore::markAllUnattributedPrivateClickMeasurementAsExpiredForTesting): 70 (WebKit::WebResourceLoadStatisticsStore::attributePrivateClickMeasurement): 71 (WebKit::WebResourceLoadStatisticsStore::allAttributedPrivateClickMeasurement): 72 (WebKit::WebResourceLoadStatisticsStore::clearPrivateClickMeasurement): 73 (WebKit::WebResourceLoadStatisticsStore::clearPrivateClickMeasurementForRegistrableDomain): 74 (WebKit::WebResourceLoadStatisticsStore::clearExpiredPrivateClickMeasurement): 75 (WebKit::WebResourceLoadStatisticsStore::privateClickMeasurementToString): 76 (WebKit::WebResourceLoadStatisticsStore::clearSentAttributions): 77 (WebKit::WebResourceLoadStatisticsStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting): 78 * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h: 79 80 * NetworkProcess/NetworkProcess.cpp: 81 (WebKit::NetworkProcess::firePrivateClickMeasurementTimerImmediately): 82 (WebKit::NetworkProcess::simulateResourceLoadStatisticsSessionRestart): 83 (WebKit::NetworkProcess::markAttributedPrivateClickMeasurementsAsExpiredForTesting): 84 Test functions to help simulate a browser restart after PCM data has expired during 85 a session close. This is the only behavior change from the existing PCM implementation. 86 87 * NetworkProcess/NetworkProcess.h: 88 * NetworkProcess/NetworkProcess.messages.in: 89 * NetworkProcess/NetworkResourceLoader.cpp: 90 (WebKit::NetworkResourceLoader::willSendRedirectedRequest): 91 (WebKit::NetworkResourceLoader::continueWillSendRedirectedRequest): 92 * NetworkProcess/NetworkResourceLoader.h: 93 * NetworkProcess/NetworkSession.cpp: 94 (WebKit::NetworkSession::NetworkSession): 95 (WebKit::NetworkSession::firePrivateClickMeasurementTimerImmediately): 96 (WebKit::NetworkSession::storePrivateClickMeasurement): 97 (WebKit::NetworkSession::handlePrivateClickMeasurementConversion): 98 (WebKit::NetworkSession::markAttributedPrivateClickMeasurementsAsExpiredForTesting): 99 (WebKit::NetworkSession::markPrivateClickMeasurementsAsExpiredForTesting): 100 * NetworkProcess/NetworkSession.h: 101 102 * NetworkProcess/PrivateClickMeasurementManager.cpp: 103 (WebKit::PrivateClickMeasurementManager::PrivateClickMeasurementManager): 104 Move constructor to cpp file to call startTimer(5_s) which will kick 105 off sending any reports that have expired in the database. We should 106 wait 5 seconds so we are sure ITP is up and running. 107 108 (WebKit::PrivateClickMeasurementManager::storeUnattributed): 109 (WebKit::PrivateClickMeasurementManager::handleAttribution): 110 (WebKit::PrivateClickMeasurementManager::startTimer): 111 (WebKit::PrivateClickMeasurementManager::attribute): 112 (WebKit::PrivateClickMeasurementManager::fireConversionRequest): 113 (WebKit::PrivateClickMeasurementManager::clearSentAttributions): 114 (WebKit::PrivateClickMeasurementManager::updateTimerLastFired): 115 (WebKit::PrivateClickMeasurementManager::firePendingAttributionRequests): 116 (WebKit::PrivateClickMeasurementManager::clear): 117 (WebKit::PrivateClickMeasurementManager::clearForRegistrableDomain): 118 (WebKit::PrivateClickMeasurementManager::clearExpired): 119 (WebKit::PrivateClickMeasurementManager::toString const): 120 (WebKit::PrivateClickMeasurementManager::setConversionURLForTesting): 121 (WebKit::PrivateClickMeasurementManager::markAllUnattributedAsExpiredForTesting): 122 (WebKit::PrivateClickMeasurementManager::markAttributedPrivateClickMeasurementsAsExpiredForTesting): 123 (WebKit::PrivateClickMeasurementManager::storeUnconverted): Deleted. 124 (WebKit::PrivateClickMeasurementManager::handleConversion): Deleted. 125 (WebKit::PrivateClickMeasurementManager::convert): Deleted. 126 (WebKit::PrivateClickMeasurementManager::firePendingConversionRequests): Deleted. 127 (WebKit::PrivateClickMeasurementManager::markAllUnconvertedAsExpiredForTesting): Deleted. 128 Implementation moved to ResourceLoadStatisticsDatabaseStore. 129 130 * NetworkProcess/PrivateClickMeasurementManager.h: 131 (WebKit::PrivateClickMeasurementManager::PrivateClickMeasurementManager): Deleted. 132 Moved to cpp file. 133 134 (WebKit::PrivateClickMeasurementManager::m_sessionID): Deleted. 135 * UIProcess/API/C/WKPage.cpp: 136 (WKPageMarkAttributedPrivateClickMeasurementsAsExpiredForTesting): 137 (WKPageSimulateResourceLoadStatisticsSessionRestart): 138 * UIProcess/API/C/WKPagePrivate.h: 139 * UIProcess/WebPageProxy.cpp: 140 (WebKit::WebPageProxy::didCommitLoadForFrame): 141 (WebKit::WebPageProxy::markAttributedPrivateClickMeasurementsAsExpiredForTesting): 142 (WebKit::WebPageProxy::simulateResourceLoadStatisticsSessionRestart): 143 * UIProcess/WebPageProxy.h: 144 Testing support. 145 1 146 2020-11-20 Simon Fraser <simon.fraser@apple.com> 2 147 -
trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp
r269807 r270136 81 81 constexpr auto topFrameLoadedThirdPartyScriptsQuery = "INSERT OR IGNORE into TopFrameLoadedThirdPartyScripts (topFrameDomainID, subresourceDomainID) SELECT ?, domainID FROM ObservedDomains where registrableDomain in ( "_s; 82 82 constexpr auto subresourceUniqueRedirectsFromQuery = "INSERT OR IGNORE INTO SubresourceUniqueRedirectsFrom (subresourceDomainID, fromDomainID) SELECT ?, domainID FROM ObservedDomains WHERE registrableDomain in ( "_s; 83 constexpr auto insertUnattributedPrivateClickMeasurementQuery = "INSERT OR REPLACE INTO UnattributedPrivateClickMeasurement (sourceSiteDomainID, attributeOnSiteDomainID, " 84 "sourceID, timeOfAdClick) VALUES (?, ?, ?, ?)"_s; 85 constexpr auto insertAttributedPrivateClickMeasurementQuery = "INSERT OR REPLACE INTO AttributedPrivateClickMeasurement (sourceSiteDomainID, attributeOnSiteDomainID, " 86 "sourceID, attributionTriggerData, priority, timeOfAdClick, earliestTimeToSend) VALUES (?, ?, ?, ?, ?, ?, ?)"_s; 87 constexpr auto updateTimerLastFiredQuery = "INSERT OR REPLACE INTO TimerLastFired (key, timeLastFiredSeconds) VALUES (1, ?)"_s; 83 88 84 89 // INSERT OR REPLACE Queries … … 111 116 constexpr auto updateGrandfatheredQuery = "UPDATE ObservedDomains SET grandfathered = ? WHERE registrableDomain = ?"_s; 112 117 constexpr auto updateIsScheduledForAllButCookieDataRemovalQuery = "UPDATE ObservedDomains SET isScheduledForAllButCookieDataRemoval = ? WHERE registrableDomain = ?"_s; 118 constexpr auto setUnattributedPrivateClickMeasurementAsExpiredQuery = "UPDATE UnattributedPrivateClickMeasurement SET timeOfAdClick = -1.0"_s; 119 constexpr auto updateAttributionsEarliestTimeToSendQuery = "UPDATE AttributedPrivateClickMeasurement as c SET " 120 "earliestTimeToSend = (SELECT MAX(0.0, newTime) FROM (SELECT (earliestTimeToSend - ?) as newTime FROM " 121 "AttributedPrivateClickMeasurement as d WHERE c.sourceSiteDomainID = d.sourceSiteDomainID AND c.attributeOnSiteDomainID = " 122 "d.attributeOnSiteDomainID))"_s; 113 123 114 124 // SELECT Queries … … 129 139 "UNION ALL SELECT topFrameDomainID FROM SubresourceUnderTopFrameDomains WHERE subresourceDomainID = ?" 130 140 "UNION ALL SELECT toDomainID FROM SubresourceUniqueRedirectsTo WHERE subresourceDomainID = ?"_s; 141 constexpr auto allUnattributedPrivateClickMeasurementAttributionsQuery = "SELECT * FROM UnattributedPrivateClickMeasurement"_s; 142 constexpr auto allAttributedPrivateClickMeasurementQuery = "SELECT * FROM AttributedPrivateClickMeasurement"_s; 143 constexpr auto findUnattributedQuery = "SELECT * FROM UnattributedPrivateClickMeasurement WHERE sourceSiteDomainID = ? AND attributeOnSiteDomainID = ?"_s; 144 constexpr auto findAttributedQuery = "SELECT * FROM AttributedPrivateClickMeasurement WHERE sourceSiteDomainID = ? AND attributeOnSiteDomainID = ?"_s; 145 constexpr auto timerLastFiredQuery = "SELECT timeLastFiredSeconds FROM TimerLastFired WHERE key = 1"_s; 131 146 132 147 // EXISTS for testing queries … … 140 155 // DELETE Queries 141 156 constexpr auto removeAllDataQuery = "DELETE FROM ObservedDomains WHERE domainID = ?"_s; 157 constexpr auto clearUnattributedPrivateClickMeasurementQuery = "DELETE FROM UnattributedPrivateClickMeasurement WHERE sourceSiteDomainID LIKE ? OR attributeOnSiteDomainID LIKE ?"_s; 158 constexpr auto clearAttributedPrivateClickMeasurementQuery = "DELETE FROM AttributedPrivateClickMeasurement WHERE sourceSiteDomainID LIKE ? OR attributeOnSiteDomainID LIKE ?"_s; 159 constexpr auto clearExpiredPrivateClickMeasurementQuery = "DELETE FROM UnattributedPrivateClickMeasurement WHERE ? > timeOfAdClick"_s; 160 constexpr auto removeUnattributedQuery = "DELETE FROM UnattributedPrivateClickMeasurement WHERE sourceSiteDomainID = ? AND attributeOnSiteDomainID = ?"_s; 142 161 143 162 constexpr auto createObservedDomain = "CREATE TABLE ObservedDomains (" … … 220 239 "year INTEGER NOT NULL, month INTEGER NOT NULL, monthDay INTEGER NOT NULL);"_s; 221 240 222 223 // CREATE UNIQUE INDEX Queries 241 constexpr auto createUnattributedPrivateClickMeasurement = "CREATE TABLE UnattributedPrivateClickMeasurement (" 242 "sourceSiteDomainID INTEGER NOT NULL, attributeOnSiteDomainID INTEGER NOT NULL, sourceID INTEGER NOT NULL, " 243 "timeOfAdClick REAL NOT NULL, FOREIGN KEY(sourceSiteDomainID) REFERENCES ObservedDomains(domainID) ON DELETE CASCADE, " 244 "FOREIGN KEY(attributeOnSiteDomainID) REFERENCES ObservedDomains(domainID) ON DELETE CASCADE);"_s; 245 246 constexpr auto createAttributedPrivateClickMeasurement = "CREATE TABLE AttributedPrivateClickMeasurement (" 247 "sourceSiteDomainID INTEGER NOT NULL, attributeOnSiteDomainID INTEGER NOT NULL, sourceID INTEGER NOT NULL, " 248 "attributionTriggerData INTEGER NOT NULL, priority INTEGER NOT NULL, timeOfAdClick REAL NOT NULL, earliestTimeToSend REAL NOT NULL, " 249 "FOREIGN KEY(sourceSiteDomainID) REFERENCES ObservedDomains(domainID) ON DELETE CASCADE, " 250 "FOREIGN KEY(attributeOnSiteDomainID) REFERENCES ObservedDomains(domainID) ON DELETE CASCADE);"_s; 251 252 constexpr auto createTimerLastFired = "CREATE TABLE TimerLastFired ( key INTEGER PRIMARY KEY, " 253 " timeLastFiredSeconds REAL NOT NULL )"_s; 254 255 // CREATE UNIQUE INDEX Queries. 224 256 constexpr auto createUniqueIndexStorageAccessUnderTopFrameDomains = "CREATE UNIQUE INDEX IF NOT EXISTS StorageAccessUnderTopFrameDomains_domainID_topLevelDomainID on StorageAccessUnderTopFrameDomains ( domainID, topLevelDomainID );"_s; 225 257 constexpr auto createUniqueIndexTopFrameUniqueRedirectsTo = "CREATE UNIQUE INDEX IF NOT EXISTS TopFrameUniqueRedirectsTo_sourceDomainID_toDomainID on TopFrameUniqueRedirectsTo ( sourceDomainID, toDomainID );"_s; … … 233 265 constexpr auto createUniqueIndexSubresourceUniqueRedirectsFrom = "CREATE UNIQUE INDEX IF NOT EXISTS SubresourceUniqueRedirectsFrom_subresourceDomainID_fromDomainID on SubresourceUnderTopFrameDomains ( subresourceDomainID, fromDomainID );"_s; 234 266 constexpr auto createUniqueIndexOperatingDates = "CREATE UNIQUE INDEX IF NOT EXISTS OperatingDates_year_month_monthDay on OperatingDates ( year, month, monthDay );"_s; 267 constexpr auto createUniqueIndexUnattributedPrivateClickMeasurement = "CREATE UNIQUE INDEX IF NOT EXISTS UnattributedPrivateClickMeasurement_sourceSiteDomainID_attributeOnSiteDomainID on UnattributedPrivateClickMeasurement ( sourceSiteDomainID, attributeOnSiteDomainID );"_s; 268 constexpr auto createUniqueIndexAttributedPrivateClickMeasurement = "CREATE UNIQUE INDEX IF NOT EXISTS AttributedPrivateClickMeasurement_sourceSiteDomainID_attributeOnSiteDomainID on AttributedPrivateClickMeasurement ( sourceSiteDomainID, attributeOnSiteDomainID );"_s; 235 269 236 270 static const String ObservedDomainsTableSchemaV1() … … 264 298 { "SubresourceUniqueRedirectsTo"_s, createSubresourceUniqueRedirectsTo}, 265 299 { "SubresourceUniqueRedirectsFrom"_s, createSubresourceUniqueRedirectsFrom}, 266 { "OperatingDates"_s, createOperatingDates} 300 { "OperatingDates"_s, createOperatingDates}, 301 { "UnattributedPrivateClickMeasurement"_s, createUnattributedPrivateClickMeasurement}, 302 { "AttributedPrivateClickMeasurement"_s, createAttributedPrivateClickMeasurement}, 303 { "TimerLastFired"_s, createTimerLastFired} 267 304 }); 268 305 … … 295 332 296 333 includeTodayAsOperatingDateIfNecessary(); 334 updatePrivateClickMeasurementAttributionTimes(); 297 335 allStores().add(this); 298 336 } … … 556 594 || !m_database.executeCommand(createUniqueIndexSubresourceUniqueRedirectsTo) 557 595 || !m_database.executeCommand(createUniqueIndexSubresourceUnderTopFrameDomains) 558 || !m_database.executeCommand(createUniqueIndexOperatingDates)) { 596 || !m_database.executeCommand(createUniqueIndexOperatingDates) 597 || !m_database.executeCommand(createUniqueIndexUnattributedPrivateClickMeasurement) 598 || !m_database.executeCommand(createUniqueIndexAttributedPrivateClickMeasurement)) { 559 599 RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::createUniqueIndices failed to execute, error message: %" PUBLIC_LOG_STRING, this, m_database.lastErrorMsg()); 560 600 return false; … … 631 671 return false; 632 672 } 633 673 674 if (!m_database.executeCommand(createUnattributedPrivateClickMeasurement)) { 675 LOG_ERROR("Could not create UnattributedPrivateClickMeasurement table in database (%i) - %s", m_database.lastError(), m_database.lastErrorMsg()); 676 return false; 677 } 678 679 if (!m_database.executeCommand(createAttributedPrivateClickMeasurement)) { 680 LOG_ERROR("Could not create AttributedPrivateClickMeasurement table in database (%i) - %s", m_database.lastError(), m_database.lastErrorMsg()); 681 return false; 682 } 683 684 if (!m_database.executeCommand(createTimerLastFired)) { 685 LOG_ERROR("Could not create TimerLastFired table in database (%i) - %s", m_database.lastError(), m_database.lastErrorMsg()); 686 return false; 687 } 688 634 689 if (!createUniqueIndices()) 635 690 return false; … … 679 734 m_observedDomainsExistsStatement = nullptr; 680 735 m_removeAllDataStatement = nullptr; 736 m_insertUnattributedPrivateClickMeasurementStatement = nullptr; 737 m_insertAttributedPrivateClickMeasurementStatement = nullptr; 738 m_setUnattributedPrivateClickMeasurementAsExpiredStatement = nullptr; 739 m_clearUnattributedPrivateClickMeasurementStatement = nullptr; 740 m_clearAttributedPrivateClickMeasurementStatement = nullptr; 741 m_clearExpiredPrivateClickMeasurementStatement = nullptr; 742 m_allUnattributedPrivateClickMeasurementAttributionsStatement = nullptr; 743 m_allAttributedPrivateClickMeasurementStatement = nullptr; 744 m_findUnattributedStatement = nullptr; 745 m_findAttributedStatement = nullptr; 746 m_updateTimerLastFiredStatement = nullptr; 747 m_timerLastFiredStatement = nullptr; 748 m_updateAttributionsEarliestTimeToSendStatement = nullptr; 749 m_removeUnattributedStatement = nullptr; 681 750 } 682 751 … … 2815 2884 } 2816 2885 2886 void ResourceLoadStatisticsDatabaseStore::updateTimerLastFired() 2887 { 2888 auto scopedStatement = this->scopedStatement(m_updateTimerLastFiredStatement, updateTimerLastFiredQuery, "updateTimerLastFired"_s); 2889 2890 auto now = WallTime::now().secondsSinceEpoch().value(); 2891 2892 if (!scopedStatement 2893 || scopedStatement->bindDouble(1, now) != SQLITE_OK 2894 || scopedStatement->step() != SQLITE_DONE) { 2895 RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::updateTimerLastFired failed, error message: %{private}s", this, m_database.lastErrorMsg()); 2896 ASSERT_NOT_REACHED(); 2897 } 2898 } 2899 2900 WallTime ResourceLoadStatisticsDatabaseStore::timerLastFired() 2901 { 2902 auto scopedStatement = this->scopedStatement(m_timerLastFiredStatement, timerLastFiredQuery, "timerLastFired"_s); 2903 2904 if (!scopedStatement) { 2905 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::timerLastFired, error message: %{private}s", this, m_database.lastErrorMsg()); 2906 ASSERT_NOT_REACHED(); 2907 } 2908 2909 if (scopedStatement->step() == SQLITE_ROW) 2910 return WallTime::fromRawSeconds(scopedStatement->getColumnDouble(0)); 2911 2912 return WallTime::now(); 2913 } 2914 2915 void ResourceLoadStatisticsDatabaseStore::updatePrivateClickMeasurementAttributionTimes() 2916 { 2917 // We should update attributions on session-start to account for the time 2918 // that passed while the session was closed. If the amount of time since the last 2919 // timer fire is greater than the earliestTimeToSend, we should set earliestTimeToSend 2920 // to be immediately. 2921 auto lastFired = timerLastFired(); 2922 auto timePassed = WallTime::now() - lastFired; 2923 2924 auto scopedStatement = this->scopedStatement(m_updateAttributionsEarliestTimeToSendStatement, updateAttributionsEarliestTimeToSendQuery, "updatePrivateClickMeasurementAttributionTimes"_s); 2925 2926 if (!scopedStatement 2927 || scopedStatement->bindDouble(1, timePassed.value()) != SQLITE_OK 2928 || scopedStatement->step() != SQLITE_DONE) { 2929 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::updatePrivateClickMeasurementAttributionTimes, error message: %{private}s", this, m_database.lastErrorMsg()); 2930 ASSERT_NOT_REACHED(); 2931 } 2932 } 2933 2934 PrivateClickMeasurement ResourceLoadStatisticsDatabaseStore::buildPrivateClickMeasurementFromDatabase(WebCore::SQLiteStatement* statement, PrivateClickMeasurementAttributionType attributionType) 2935 { 2936 auto sourceSiteDomain = getDomainStringFromDomainID(statement->getColumnInt(0)); 2937 auto attributeOnSiteDomain = getDomainStringFromDomainID(statement->getColumnInt(1)); 2938 auto sourceID = statement->getColumnInt(2); 2939 auto timeOfAdClick = attributionType == PrivateClickMeasurementAttributionType::Attributed ? statement->getColumnDouble(5) : statement->getColumnDouble(3); 2940 2941 PrivateClickMeasurement attribution(WebCore::PrivateClickMeasurement::SourceID(sourceID), WebCore::PrivateClickMeasurement::SourceSite(RegistrableDomain::uncheckedCreateFromRegistrableDomainString(sourceSiteDomain)), WebCore::PrivateClickMeasurement::AttributeOnSite(RegistrableDomain::uncheckedCreateFromRegistrableDomainString(attributeOnSiteDomain)), WallTime::fromRawSeconds(timeOfAdClick)); 2942 2943 if (attributionType == PrivateClickMeasurementAttributionType::Attributed) { 2944 auto attributionTriggerData = statement->getColumnInt(3); 2945 auto priority = statement->getColumnInt(4); 2946 auto earliestTimeToSend = statement->getColumnDouble(6); 2947 2948 if (attributionTriggerData != -1) 2949 attribution.setAttribution(WebCore::PrivateClickMeasurement::AttributionTriggerData { static_cast<uint32_t>(attributionTriggerData), WebCore::PrivateClickMeasurement::Priority(priority) }); 2950 2951 attribution.setEarliestTimeToSend(WallTime::fromRawSeconds(earliestTimeToSend)); 2952 } 2953 2954 return attribution; 2955 } 2956 2957 std::pair<Optional<UnattributedPrivateClickMeasurement>, Optional<AttributedPrivateClickMeasurement>> ResourceLoadStatisticsDatabaseStore::findPrivateClickMeasurement(const WebCore::PrivateClickMeasurement::SourceSite& sourceSite, const WebCore::PrivateClickMeasurement::AttributeOnSite& attributeOnSite) 2958 { 2959 auto sourceSiteDomainID = domainID(sourceSite.registrableDomain); 2960 auto attributeOnSiteDomainID = domainID(attributeOnSite.registrableDomain); 2961 2962 if (!sourceSiteDomainID || !attributeOnSiteDomainID) 2963 return std::make_pair(WTF::nullopt, WTF::nullopt); 2964 2965 auto findUnattributedScopedStatement = this->scopedStatement(m_findUnattributedStatement, findUnattributedQuery, "findPrivateClickMeasurement"_s); 2966 if (!findUnattributedScopedStatement 2967 || findUnattributedScopedStatement->bindInt(1, *sourceSiteDomainID) != SQLITE_OK 2968 || findUnattributedScopedStatement->bindInt(2, *attributeOnSiteDomainID) != SQLITE_OK) { 2969 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::findPrivateClickMeasurement findUnattributedQuery, error message: %{private}s", this, m_database.lastErrorMsg()); 2970 ASSERT_NOT_REACHED(); 2971 } 2972 2973 auto findAttributedScopedStatement = this->scopedStatement(m_findAttributedStatement, findAttributedQuery, "findPrivateClickMeasurement"_s); 2974 if (!findAttributedScopedStatement 2975 || findAttributedScopedStatement->bindInt(1, *sourceSiteDomainID) != SQLITE_OK 2976 || findAttributedScopedStatement->bindInt(2, *attributeOnSiteDomainID) != SQLITE_OK) { 2977 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::findPrivateClickMeasurement findAttributedQuery, error message: %{private}s", this, m_database.lastErrorMsg()); 2978 ASSERT_NOT_REACHED(); 2979 } 2980 2981 Optional<UnattributedPrivateClickMeasurement> unattributedPrivateClickMeasurement; 2982 if (findUnattributedScopedStatement->step() == SQLITE_ROW) 2983 unattributedPrivateClickMeasurement = buildPrivateClickMeasurementFromDatabase(findUnattributedScopedStatement.get(), PrivateClickMeasurementAttributionType::Unattributed); 2984 2985 Optional<AttributedPrivateClickMeasurement> attributedPrivateClickMeasurement; 2986 if (findAttributedScopedStatement->step() == SQLITE_ROW) 2987 attributedPrivateClickMeasurement = buildPrivateClickMeasurementFromDatabase(findAttributedScopedStatement.get(), PrivateClickMeasurementAttributionType::Attributed); 2988 2989 return std::make_pair(unattributedPrivateClickMeasurement, attributedPrivateClickMeasurement); 2990 } 2991 2992 void ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement(PrivateClickMeasurement&& attribution, PrivateClickMeasurementAttributionType attributionType) 2993 { 2994 auto sourceData = ensureResourceStatisticsForRegistrableDomain(attribution.sourceSite().registrableDomain); 2995 auto attributeOnData = ensureResourceStatisticsForRegistrableDomain(attribution.attributeOnSite().registrableDomain); 2996 2997 if (!sourceData.second || !attributeOnData.second) 2998 return; 2999 3000 if (attributionType == PrivateClickMeasurementAttributionType::Attributed) { 3001 auto attributionTriggerData = attribution.attributionTriggerData() ? attribution.attributionTriggerData().value().data : -1; 3002 auto priority = attribution.attributionTriggerData() ? attribution.attributionTriggerData().value().priority : -1; 3003 auto earliestTimeToSend = attribution.earliestTimeToSend() ? attribution.earliestTimeToSend().value().secondsSinceEpoch().value() : -1; 3004 3005 auto statement = SQLiteStatement(m_database, insertAttributedPrivateClickMeasurementQuery); 3006 if (statement.prepare() != SQLITE_OK 3007 || statement.bindInt(1, *sourceData.second) != SQLITE_OK 3008 || statement.bindInt(2, *attributeOnData.second) != SQLITE_OK 3009 || statement.bindInt(3, attribution.sourceID().id) != SQLITE_OK 3010 || statement.bindInt(4, attributionTriggerData) != SQLITE_OK 3011 || statement.bindInt(5, priority) != SQLITE_OK 3012 || statement.bindDouble(6, attribution.timeOfAdClick().secondsSinceEpoch().value()) != SQLITE_OK 3013 || statement.bindDouble(7, earliestTimeToSend) != SQLITE_OK 3014 || statement.step() != SQLITE_DONE) { 3015 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement insertAttributedPrivateClickMeasurementQuery, error message: %{private}s", this, m_database.lastErrorMsg()); 3016 ASSERT_NOT_REACHED(); 3017 } 3018 return; 3019 } 3020 3021 auto statement = SQLiteStatement(m_database, insertUnattributedPrivateClickMeasurementQuery); 3022 if (statement.prepare() != SQLITE_OK 3023 || statement.bindInt(1, *sourceData.second) != SQLITE_OK 3024 || statement.bindInt(2, *attributeOnData.second) != SQLITE_OK 3025 || statement.bindInt(3, attribution.sourceID().id) != SQLITE_OK 3026 || statement.bindDouble(4, attribution.timeOfAdClick().secondsSinceEpoch().value()) != SQLITE_OK 3027 || statement.step() != SQLITE_DONE) { 3028 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement insertUnattributedPrivateClickMeasurementQuery, error message: %{private}s", this, m_database.lastErrorMsg()); 3029 ASSERT_NOT_REACHED(); 3030 } 3031 } 3032 3033 void ResourceLoadStatisticsDatabaseStore::markAllUnattributedPrivateClickMeasurementAsExpiredForTesting() 3034 { 3035 auto scopedStatement = this->scopedStatement(m_setUnattributedPrivateClickMeasurementAsExpiredStatement, setUnattributedPrivateClickMeasurementAsExpiredQuery, "markAllUnattributedPrivateClickMeasurementAsExpiredForTesting"_s); 3036 3037 if (!scopedStatement || scopedStatement->step() != SQLITE_DONE) { 3038 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::markAllUnattributedPrivateClickMeasurementAsExpiredForTesting, error message: %{private}s", this, m_database.lastErrorMsg()); 3039 ASSERT_NOT_REACHED(); 3040 } 3041 } 3042 3043 void ResourceLoadStatisticsDatabaseStore::removeUnattributed(PrivateClickMeasurement& attribution) 3044 { 3045 auto sourceSiteDomainID = domainID(attribution.sourceSite().registrableDomain); 3046 auto attributeOnSiteDomainID = domainID(attribution.attributeOnSite().registrableDomain); 3047 3048 if (!sourceSiteDomainID || !attributeOnSiteDomainID) 3049 return; 3050 3051 auto scopedStatement = this->scopedStatement(m_removeUnattributedStatement, removeUnattributedQuery, "removeUnattributed"_s); 3052 3053 if (!scopedStatement 3054 || scopedStatement->bindInt(1, *sourceSiteDomainID) != SQLITE_OK 3055 || scopedStatement->bindInt(2, *attributeOnSiteDomainID) != SQLITE_OK 3056 || scopedStatement->step() != SQLITE_DONE) { 3057 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::removeUnattributed, error message: %{private}s", this, m_database.lastErrorMsg()); 3058 ASSERT_NOT_REACHED(); 3059 } 3060 } 3061 3062 Optional<Seconds> ResourceLoadStatisticsDatabaseStore::attributePrivateClickMeasurement(const SourceSite& sourceSite, const AttributeOnSite& attributeOnSite, AttributionTriggerData&& attributionTriggerData) 3063 { 3064 // We should always clear expired clicks from the database before scheduling an attribution. 3065 clearExpiredPrivateClickMeasurement(); 3066 3067 if (!attributionTriggerData.isValid()) { 3068 if (UNLIKELY(debugModeEnabled())) { 3069 RELEASE_LOG_INFO(PrivateClickMeasurement, "Got an invalid attribution."); 3070 debugBroadcastConsoleMessage(MessageSource::PrivateClickMeasurement, MessageLevel::Error, "[Private Click Measurement] Got an invalid attribution."_s); 3071 } 3072 return WTF::nullopt; 3073 } 3074 3075 auto data = attributionTriggerData.data; 3076 auto priority = attributionTriggerData.priority; 3077 3078 if (UNLIKELY(debugModeEnabled())) { 3079 RELEASE_LOG_INFO(PrivateClickMeasurement, "Got an attribution with attribution trigger data: %{public}u and priority: %{public}u.", data, priority); 3080 debugBroadcastConsoleMessage(MessageSource::PrivateClickMeasurement, MessageLevel::Info, makeString("[Private Click Measurement] Got an attribution with attribution trigger data: '"_s, data, "' and priority: '"_s, priority, "'."_s)); 3081 } 3082 3083 auto secondsUntilSend = Seconds::infinity(); 3084 3085 auto attribution = findPrivateClickMeasurement(sourceSite, attributeOnSite); 3086 auto& previouslyUnattributed = attribution.first; 3087 auto& previouslyAttributed = attribution.second; 3088 3089 if (previouslyUnattributed) { 3090 // Always convert the pending attribution and remove it from the unattributed map. 3091 removeUnattributed(*previouslyUnattributed); 3092 if (auto optionalSecondsUntilSend = previouslyUnattributed.value().attributeAndGetEarliestTimeToSend(WTFMove(attributionTriggerData))) { 3093 secondsUntilSend = *optionalSecondsUntilSend; 3094 ASSERT(secondsUntilSend != Seconds::infinity()); 3095 if (UNLIKELY(debugModeEnabled())) { 3096 RELEASE_LOG_INFO(PrivateClickMeasurement, "Converted a stored ad click with attribution trigger data: %{public}u and priority: %{public}u.", data, priority); 3097 debugBroadcastConsoleMessage(MessageSource::PrivateClickMeasurement, MessageLevel::Info, makeString("[Private Click Measurement] Converted a stored ad click with attribution trigger data: '"_s, data, "' and priority: '"_s, priority, "'."_s)); 3098 } 3099 } 3100 3101 // If there is no previous attribution, or the new attribution has higher priority, insert/update the database. 3102 if (!previouslyAttributed || previouslyUnattributed.value().hasHigherPriorityThan(*previouslyAttributed)) { 3103 insertPrivateClickMeasurement(WTFMove(*previouslyUnattributed), PrivateClickMeasurementAttributionType::Attributed); 3104 3105 if (UNLIKELY(debugModeEnabled())) { 3106 RELEASE_LOG_INFO(PrivateClickMeasurement, "Replaced a previously converted ad click with a new one with attribution data: %{public}u and priority: %{public}u because it had higher priority.", data, priority); 3107 debugBroadcastConsoleMessage(MessageSource::PrivateClickMeasurement, MessageLevel::Info, makeString("[Private Click Measurement] Replaced a previously converted ad click with a new one with attribution trigger data: '"_s, data, "' and priority: '"_s, priority, "' because it had higher priority."_s)); 3108 } 3109 } 3110 } else if (previouslyAttributed) { 3111 // If we have no new attribution, re-attribute the old one to respect the new priority. 3112 if (auto optionalSecondsUntilSend = previouslyAttributed.value().attributeAndGetEarliestTimeToSend(WTFMove(attributionTriggerData))) { 3113 insertPrivateClickMeasurement(WTFMove(*previouslyAttributed), PrivateClickMeasurementAttributionType::Attributed); 3114 3115 secondsUntilSend = *optionalSecondsUntilSend; 3116 ASSERT(secondsUntilSend != Seconds::infinity()); 3117 3118 if (UNLIKELY(debugModeEnabled())) { 3119 RELEASE_LOG_INFO(PrivateClickMeasurement, "Re-converted an ad click with a new one with attribution trigger data: %{public}u and priority: %{public}u because it had higher priority.", data, priority); 3120 debugBroadcastConsoleMessage(MessageSource::PrivateClickMeasurement, MessageLevel::Info, makeString("[Private Click Measurement] Re-converted an ad click with a new one with attribution trigger data: '"_s, data, "' and priority: '"_s, priority, "'' because it had higher priority."_s)); 3121 } 3122 } 3123 } 3124 3125 if (secondsUntilSend == Seconds::infinity()) 3126 return WTF::nullopt; 3127 3128 return secondsUntilSend; 3129 } 3130 3131 Vector<WebCore::PrivateClickMeasurement> ResourceLoadStatisticsDatabaseStore::allAttributedPrivateClickMeasurement() 3132 { 3133 auto attributedScopedStatement = this->scopedStatement(m_allAttributedPrivateClickMeasurementStatement, allAttributedPrivateClickMeasurementQuery, "privateClickMeasurementToString"_s); 3134 3135 if (!attributedScopedStatement) { 3136 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::privateClickMeasurementToString, error message: %{private}s", this, m_database.lastErrorMsg()); 3137 ASSERT_NOT_REACHED(); 3138 } 3139 3140 Vector<WebCore::PrivateClickMeasurement> attributions; 3141 while (attributedScopedStatement->step() == SQLITE_ROW) 3142 attributions.append(buildPrivateClickMeasurementFromDatabase(attributedScopedStatement.get(), PrivateClickMeasurementAttributionType::Attributed)); 3143 3144 return attributions; 3145 } 3146 3147 void ResourceLoadStatisticsDatabaseStore::clearPrivateClickMeasurement(Optional<RegistrableDomain> domain) 3148 { 3149 // Default to clear all entries if no domain is specified. 3150 String bindParameter = "%"; 3151 if (domain) { 3152 auto domainIDToMatch = domainID(*domain); 3153 if (!domainIDToMatch) 3154 return; 3155 3156 bindParameter = String::number(*domainIDToMatch); 3157 } 3158 3159 auto clearUnattributedScopedStatement = this->scopedStatement(m_clearUnattributedPrivateClickMeasurementStatement, clearUnattributedPrivateClickMeasurementQuery, "clearPrivateClickMeasurement"_s); 3160 3161 if (!clearUnattributedScopedStatement 3162 || clearUnattributedScopedStatement->bindText(1, bindParameter) != SQLITE_OK 3163 || clearUnattributedScopedStatement->bindText(2, bindParameter) != SQLITE_OK 3164 || clearUnattributedScopedStatement->step() != SQLITE_DONE) { 3165 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearPrivateClickMeasurement clearUnattributedScopedStatement, error message: %{private}s", this, m_database.lastErrorMsg()); 3166 ASSERT_NOT_REACHED(); 3167 } 3168 3169 auto clearAttributedScopedStatement = this->scopedStatement(m_clearAttributedPrivateClickMeasurementStatement, clearAttributedPrivateClickMeasurementQuery, "clearPrivateClickMeasurement"_s); 3170 3171 if (!clearAttributedScopedStatement 3172 || clearAttributedScopedStatement->bindText(1, bindParameter) != SQLITE_OK 3173 || clearAttributedScopedStatement->bindText(2, bindParameter) != SQLITE_OK 3174 || clearAttributedScopedStatement->step() != SQLITE_DONE) { 3175 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearPrivateClickMeasurement clearAttributedScopedStatement, error message: %{private}s", this, m_database.lastErrorMsg()); 3176 ASSERT_NOT_REACHED(); 3177 } 3178 } 3179 3180 void ResourceLoadStatisticsDatabaseStore::clearExpiredPrivateClickMeasurement() 3181 { 3182 auto expirationTimeFrame = WallTime::now() - WebCore::PrivateClickMeasurement::maxAge(); 3183 auto scopedStatement = this->scopedStatement(m_clearExpiredPrivateClickMeasurementStatement, clearExpiredPrivateClickMeasurementQuery, "clearExpiredPrivateClickMeasurement"_s); 3184 3185 if (!scopedStatement 3186 || scopedStatement->bindDouble(1, expirationTimeFrame.secondsSinceEpoch().value()) != SQLITE_OK 3187 || scopedStatement->step() != SQLITE_DONE) { 3188 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearExpiredPrivateClickMeasurement, error message: %{private}s", this, m_database.lastErrorMsg()); 3189 ASSERT_NOT_REACHED(); 3190 } 3191 } 3192 3193 String ResourceLoadStatisticsDatabaseStore::attributionToString(WebCore::SQLiteStatement* statement, PrivateClickMeasurementAttributionType attributionType) 3194 { 3195 auto sourceSiteDomain = getDomainStringFromDomainID(statement->getColumnInt(0)); 3196 auto attributeOnSiteDomain = getDomainStringFromDomainID(statement->getColumnInt(1)); 3197 auto sourceID = statement->getColumnInt(2); 3198 3199 StringBuilder builder; 3200 builder.appendLiteral("Source site: "); 3201 builder.append(sourceSiteDomain); 3202 builder.appendLiteral("\nAttribute on site: "); 3203 builder.append(attributeOnSiteDomain); 3204 builder.appendLiteral("\nSource ID: "); 3205 builder.appendNumber(sourceID); 3206 3207 if (attributionType == PrivateClickMeasurementAttributionType::Attributed) { 3208 auto attributionTriggerData = statement->getColumnInt(3); 3209 auto priority = statement->getColumnInt(4); 3210 auto earliestTimeToSend = statement->getColumnInt(6); 3211 3212 if (attributionTriggerData != -1) { 3213 builder.appendLiteral("\nAttribution trigger data: "); 3214 builder.appendNumber(attributionTriggerData); 3215 builder.appendLiteral("\nAttribution priority: "); 3216 builder.appendNumber(priority); 3217 builder.appendLiteral("\nAttribution earliest time to send: "); 3218 if (earliestTimeToSend == -1) 3219 builder.appendLiteral("Not set"); 3220 else { 3221 auto secondsUntilSend = WallTime::fromRawSeconds(earliestTimeToSend) - WallTime::now(); 3222 builder.append((secondsUntilSend >= 24_h && secondsUntilSend <= 48_h) ? "Within 24-48 hours" : "Outside 24-48 hours"); 3223 } 3224 } else 3225 builder.appendLiteral("\nNo attribution trigger data."); 3226 } else 3227 builder.appendLiteral("\nNo attribution trigger data."); 3228 builder.append('\n'); 3229 3230 return builder.toString(); 3231 } 3232 3233 String ResourceLoadStatisticsDatabaseStore::privateClickMeasurementToString() 3234 { 3235 SQLiteStatement privateClickMeasurementDataExists(m_database, "SELECT (SELECT COUNT(*) FROM UnattributedPrivateClickMeasurement) as cnt1, (SELECT COUNT(*) FROM AttributedPrivateClickMeasurement) as cnt2"_s); 3236 if (privateClickMeasurementDataExists.prepare() != SQLITE_OK || privateClickMeasurementDataExists.step() != SQLITE_ROW) { 3237 RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::privateClickMeasurementToString failed, error message: %{private}s", this, m_database.lastErrorMsg()); 3238 ASSERT_NOT_REACHED(); 3239 return { }; 3240 } 3241 3242 if (!privateClickMeasurementDataExists.getColumnInt(0) && !privateClickMeasurementDataExists.getColumnInt(1)) 3243 return "\nNo stored Private Click Measurement data.\n"_s; 3244 3245 auto unattributedScopedStatement = this->scopedStatement(m_allUnattributedPrivateClickMeasurementAttributionsStatement, allUnattributedPrivateClickMeasurementAttributionsQuery, "privateClickMeasurementToString"_s); 3246 3247 if (!unattributedScopedStatement) { 3248 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::privateClickMeasurementToString, error message: %{private}s", this, m_database.lastErrorMsg()); 3249 ASSERT_NOT_REACHED(); 3250 } 3251 3252 unsigned unattributedNumber = 0; 3253 StringBuilder builder; 3254 while (unattributedScopedStatement->step() == SQLITE_ROW) { 3255 if (!unattributedNumber) 3256 builder.appendLiteral("Unattributed Private Click Measurements:\n"); 3257 else 3258 builder.append('\n'); 3259 builder.appendLiteral("WebCore::PrivateClickMeasurement "); 3260 builder.appendNumber(++unattributedNumber); 3261 builder.append('\n'); 3262 builder.append(attributionToString(unattributedScopedStatement.get(), PrivateClickMeasurementAttributionType::Unattributed)); 3263 } 3264 3265 auto attributedScopedStatement = this->scopedStatement(m_allAttributedPrivateClickMeasurementStatement, allAttributedPrivateClickMeasurementQuery, "privateClickMeasurementToString"_s); 3266 3267 if (!attributedScopedStatement) { 3268 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::privateClickMeasurementToString, error message: %{private}s", this, m_database.lastErrorMsg()); 3269 ASSERT_NOT_REACHED(); 3270 } 3271 3272 unsigned attributedNumber = 0; 3273 while (attributedScopedStatement->step() == SQLITE_ROW) { 3274 if (unattributedNumber) 3275 builder.append('\n'); 3276 if (!attributedNumber) 3277 builder.appendLiteral("Attributed Private Click Measurements:\n"); 3278 else 3279 builder.append('\n'); 3280 builder.appendLiteral("WebCore::PrivateClickMeasurement "); 3281 builder.appendNumber(++attributedNumber + unattributedNumber); 3282 builder.append('\n'); 3283 builder.append(attributionToString(attributedScopedStatement.get(), PrivateClickMeasurementAttributionType::Attributed)); 3284 } 3285 return builder.toString(); 3286 } 3287 3288 void ResourceLoadStatisticsDatabaseStore::clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&& attributions) 3289 { 3290 for (auto& attribution : attributions) { 3291 auto sourceSiteDomainID = domainID(attribution.sourceSite().registrableDomain); 3292 auto attributeOnSiteDomainID = domainID(attribution.attributeOnSite().registrableDomain); 3293 3294 if (!sourceSiteDomainID || !attributeOnSiteDomainID) 3295 return; 3296 3297 SQLiteStatement clearAttributedStatement(m_database, "DELETE FROM AttributedPrivateClickMeasurement WHERE sourceSiteDomainID = ? AND attributeOnSiteDomainID = ?"_s); 3298 if (clearAttributedStatement.prepare() != SQLITE_OK 3299 || clearAttributedStatement.bindInt(1, *sourceSiteDomainID) != SQLITE_OK 3300 || clearAttributedStatement.bindInt(2, *attributeOnSiteDomainID) != SQLITE_OK 3301 || clearAttributedStatement.step() != SQLITE_DONE) { 3302 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::clearSentAttributions failed to step, error message: %{private}s", this, m_database.lastErrorMsg()); 3303 ASSERT_NOT_REACHED(); 3304 } 3305 clearAttributedStatement.reset(); 3306 } 3307 } 3308 3309 void ResourceLoadStatisticsDatabaseStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting() 3310 { 3311 // Update the last timer fired time to be one day ago. 3312 auto yesterday = (WallTime::now() - 24_h).secondsSinceEpoch().value(); 3313 auto scopedStatement = this->scopedStatement(m_updateTimerLastFiredStatement, updateTimerLastFiredQuery, "insertExpiredAttributionTesting"_s); 3314 if (!scopedStatement 3315 || scopedStatement->bindDouble(1, yesterday) != SQLITE_OK 3316 || scopedStatement->step() != SQLITE_DONE) { 3317 RELEASE_LOG_ERROR(Network, "%p - ResourceLoadStatisticsDatabaseStore::insertExpiredAttributionTesting failed, error message: %{private}s", this, m_database.lastErrorMsg()); 3318 ASSERT_NOT_REACHED(); 3319 } 3320 3321 auto expiredTimeToSend = 1_h; // Must be less than 1 day. 3322 3323 auto statement = SQLiteStatement(m_database, "UPDATE AttributedPrivateClickMeasurement SET earliestTimeToSend = ?"); 3324 if (statement.prepare() != SQLITE_OK 3325 || statement.bindInt(1, expiredTimeToSend.value()) != SQLITE_OK 3326 || statement.step() != SQLITE_DONE) { 3327 RELEASE_LOG_ERROR_IF_ALLOWED(m_sessionID, "%p - ResourceLoadStatisticsDatabaseStore::insertPrivateClickMeasurement, error message: %{private}s", this, m_database.lastErrorMsg()); 3328 ASSERT_NOT_REACHED(); 3329 } 3330 return; 3331 } 3332 2817 3333 } // namespace WebKit 2818 3334 -
trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h
r269807 r270136 54 54 55 55 class ResourceLoadStatisticsMemoryStore; 56 class PrivateClickMeasurementManager; 57 58 using AttributedPrivateClickMeasurement = WebCore::PrivateClickMeasurement; 59 using UnattributedPrivateClickMeasurement = WebCore::PrivateClickMeasurement; 60 using SourceSite = WebCore::PrivateClickMeasurement::SourceSite; 61 using AttributeOnSite = WebCore::PrivateClickMeasurement::AttributeOnSite; 62 using AttributionTriggerData = WebCore::PrivateClickMeasurement::AttributionTriggerData; 56 63 57 64 // This is always constructed / used / destroyed on the WebResourceLoadStatisticsStore's statistics queue. … … 124 131 void insertExpiredStatisticForTesting(const RegistrableDomain&, bool hasUserInteraction, bool isScheduledForAllButCookieDataRemoval, bool isPrevalent) override; 125 132 void interrupt(); 133 134 // Private Click Measurement. 135 void insertPrivateClickMeasurement(WebCore::PrivateClickMeasurement&&, PrivateClickMeasurementAttributionType) override; 136 void markAllUnattributedPrivateClickMeasurementAsExpiredForTesting() override; 137 Optional<Seconds> attributePrivateClickMeasurement(const WebCore::PrivateClickMeasurement::SourceSite&, const WebCore::PrivateClickMeasurement::AttributeOnSite&, WebCore::PrivateClickMeasurement::AttributionTriggerData&&) override; 138 Vector<WebCore::PrivateClickMeasurement> allAttributedPrivateClickMeasurement() override; 139 void clearPrivateClickMeasurement(Optional<RegistrableDomain>) override; 140 void clearExpiredPrivateClickMeasurement() override; 141 String privateClickMeasurementToString() override; 142 void clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&&) override; 143 void updateTimerLastFired() override; 144 void markAttributedPrivateClickMeasurementsAsExpiredForTesting() override; 145 void updatePrivateClickMeasurementAttributionTimes(); 126 146 127 147 private: … … 214 234 Optional<WallTime> mostRecentUserInteractionTime(const DomainData&); 215 235 236 void removeUnattributed(WebCore::PrivateClickMeasurement&); 237 WebCore::PrivateClickMeasurement buildPrivateClickMeasurementFromDatabase(WebCore::SQLiteStatement*, PrivateClickMeasurementAttributionType); 238 String attributionToString(WebCore::SQLiteStatement*, PrivateClickMeasurementAttributionType); 239 std::pair<Optional<UnattributedPrivateClickMeasurement>, Optional<AttributedPrivateClickMeasurement>> findPrivateClickMeasurement(const WebCore::PrivateClickMeasurement::SourceSite&, const WebCore::PrivateClickMeasurement::AttributeOnSite&); 240 WallTime timerLastFired(); 241 216 242 const String m_storageDirectoryPath; 217 243 mutable WebCore::SQLiteDatabase m_database; … … 253 279 mutable std::unique_ptr<WebCore::SQLiteStatement> m_observedDomainsExistsStatement; 254 280 mutable std::unique_ptr<WebCore::SQLiteStatement> m_removeAllDataStatement; 281 std::unique_ptr<WebCore::SQLiteStatement> m_insertUnattributedPrivateClickMeasurementStatement; 282 std::unique_ptr<WebCore::SQLiteStatement> m_insertAttributedPrivateClickMeasurementStatement; 283 std::unique_ptr<WebCore::SQLiteStatement> m_setUnattributedPrivateClickMeasurementAsExpiredStatement; 284 std::unique_ptr<WebCore::SQLiteStatement> m_clearUnattributedPrivateClickMeasurementStatement; 285 std::unique_ptr<WebCore::SQLiteStatement> m_clearAttributedPrivateClickMeasurementStatement; 286 std::unique_ptr<WebCore::SQLiteStatement> m_clearExpiredPrivateClickMeasurementStatement; 287 std::unique_ptr<WebCore::SQLiteStatement> m_allUnattributedPrivateClickMeasurementAttributionsStatement; 288 std::unique_ptr<WebCore::SQLiteStatement> m_allAttributedPrivateClickMeasurementStatement; 289 std::unique_ptr<WebCore::SQLiteStatement> m_findUnattributedStatement; 290 std::unique_ptr<WebCore::SQLiteStatement> m_findAttributedStatement; 291 std::unique_ptr<WebCore::SQLiteStatement> m_updateTimerLastFiredStatement; 292 std::unique_ptr<WebCore::SQLiteStatement> m_timerLastFiredStatement; 293 std::unique_ptr<WebCore::SQLiteStatement> m_updateAttributionsEarliestTimeToSendStatement; 294 std::unique_ptr<WebCore::SQLiteStatement> m_removeUnattributedStatement; 295 255 296 PAL::SessionID m_sessionID; 256 297 bool m_isNewResourceLoadStatisticsDatabaseFile { false }; -
trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h
r268458 r270136 109 109 void insertExpiredStatisticForTesting(const RegistrableDomain&, bool hasUserInteraction, bool isScheduledForAllButCookieDataRemoval, bool isPrevalent) override; 110 110 111 // Private Click Measurement is not implemented in the ITP memory store. 112 void insertPrivateClickMeasurement(WebCore::PrivateClickMeasurement&&, PrivateClickMeasurementAttributionType) override { }; 113 void markAllUnattributedPrivateClickMeasurementAsExpiredForTesting() override { }; 114 Optional<Seconds> attributePrivateClickMeasurement(const WebCore::PrivateClickMeasurement::SourceSite&, const WebCore::PrivateClickMeasurement::AttributeOnSite&, WebCore::PrivateClickMeasurement::AttributionTriggerData&&) override { return { }; }; 115 Vector<WebCore::PrivateClickMeasurement> allAttributedPrivateClickMeasurement() override { return { }; }; 116 void clearPrivateClickMeasurement(Optional<RegistrableDomain>) override { }; 117 void clearExpiredPrivateClickMeasurement() override { }; 118 String privateClickMeasurementToString() override { return String(); }; 119 void clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&&) override { }; 120 void markAttributedPrivateClickMeasurementsAsExpiredForTesting() override { }; 121 void updateTimerLastFired() override { }; 122 111 123 private: 112 124 void includeTodayAsOperatingDateIfNecessary() override; -
trunk/Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.h
r268458 r270136 203 203 virtual bool hasStatisticsExpired(WallTime mostRecentUserInteractionTime, OperatingDatesWindow) const = 0; 204 204 virtual void insertExpiredStatisticForTesting(const RegistrableDomain&, bool hasUserInteraction, bool isScheduledForAllButCookieDataRemoval, bool) = 0; 205 206 // Private Click Measurement. 207 virtual void insertPrivateClickMeasurement(WebCore::PrivateClickMeasurement&&, PrivateClickMeasurementAttributionType) = 0; 208 virtual void markAllUnattributedPrivateClickMeasurementAsExpiredForTesting() = 0; 209 virtual Optional<Seconds> attributePrivateClickMeasurement(const WebCore::PrivateClickMeasurement::SourceSite&, const WebCore::PrivateClickMeasurement::AttributeOnSite&, WebCore::PrivateClickMeasurement::AttributionTriggerData&&) = 0; 210 virtual Vector<WebCore::PrivateClickMeasurement> allAttributedPrivateClickMeasurement() = 0; 211 virtual void clearPrivateClickMeasurement(Optional<RegistrableDomain>) = 0; 212 virtual void clearExpiredPrivateClickMeasurement() = 0; 213 virtual String privateClickMeasurementToString() = 0; 214 virtual void clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&&) = 0; 215 virtual void markAttributedPrivateClickMeasurementsAsExpiredForTesting() = 0; 216 virtual void updateTimerLastFired() = 0; 205 217 206 218 protected: -
trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp
r269807 r270136 1476 1476 } 1477 1477 1478 void WebResourceLoadStatisticsStore::updateTimerLastFired() 1479 { 1480 ASSERT(RunLoop::isMain()); 1481 1482 if (isEphemeral()) 1483 return; 1484 1485 postTask([this]() mutable { 1486 if (!m_statisticsStore) 1487 return; 1488 1489 m_statisticsStore->updateTimerLastFired(); 1490 }); 1491 } 1492 1493 void WebResourceLoadStatisticsStore::insertPrivateClickMeasurement(PrivateClickMeasurement&& attribution, PrivateClickMeasurementAttributionType attributionType) 1494 { 1495 ASSERT(RunLoop::isMain()); 1496 1497 if (isEphemeral()) 1498 return; 1499 1500 postTask([this, attribution = WTFMove(attribution), attributionType]() mutable { 1501 if (!m_statisticsStore) 1502 return; 1503 1504 m_statisticsStore->insertPrivateClickMeasurement(WTFMove(attribution), attributionType); 1505 }); 1506 } 1507 1508 void WebResourceLoadStatisticsStore::markAllUnattributedPrivateClickMeasurementAsExpiredForTesting() 1509 { 1510 ASSERT(RunLoop::isMain()); 1511 1512 if (isEphemeral()) 1513 return; 1514 1515 postTask([this]() { 1516 if (!m_statisticsStore) 1517 return; 1518 1519 m_statisticsStore->markAllUnattributedPrivateClickMeasurementAsExpiredForTesting(); 1520 }); 1521 } 1522 1523 void WebResourceLoadStatisticsStore::attributePrivateClickMeasurement(const PrivateClickMeasurement::SourceSite& sourceSite, const PrivateClickMeasurement::AttributeOnSite& attributeOnSite, PrivateClickMeasurement::AttributionTriggerData&& attributionTriggerData, CompletionHandler<void(Optional<Seconds>)>&& completionHandler) 1524 { 1525 ASSERT(RunLoop::isMain()); 1526 1527 if (isEphemeral()) { 1528 completionHandler({ }); 1529 return; 1530 } 1531 1532 postTask([this, sourceSite, attributeOnSite, attributionTriggerData = WTFMove(attributionTriggerData), completionHandler = WTFMove(completionHandler)]() mutable { 1533 if (!m_statisticsStore) { 1534 postTaskReply([completionHandler = WTFMove(completionHandler)]() mutable { 1535 completionHandler(WTF::nullopt); 1536 }); 1537 return; 1538 } 1539 1540 auto seconds = m_statisticsStore->attributePrivateClickMeasurement(sourceSite, attributeOnSite, WTFMove(attributionTriggerData)); 1541 postTaskReply([seconds, completionHandler = WTFMove(completionHandler)]() mutable { 1542 completionHandler(seconds); 1543 }); 1544 }); 1545 } 1546 1547 void WebResourceLoadStatisticsStore::allAttributedPrivateClickMeasurement(CompletionHandler<void(Vector<PrivateClickMeasurement>&&)>&& completionHandler) 1548 { 1549 ASSERT(RunLoop::isMain()); 1550 1551 if (isEphemeral()) { 1552 completionHandler({ }); 1553 return; 1554 } 1555 1556 postTask([this, completionHandler = WTFMove(completionHandler)]() mutable { 1557 if (!m_statisticsStore) { 1558 postTaskReply([completionHandler = WTFMove(completionHandler)]() mutable { 1559 completionHandler({ }); 1560 }); 1561 return; 1562 } 1563 1564 auto convertedAttributions = m_statisticsStore->allAttributedPrivateClickMeasurement(); 1565 postTaskReply([convertedAttributions = WTFMove(convertedAttributions), completionHandler = WTFMove(completionHandler)]() mutable { 1566 completionHandler(WTFMove(convertedAttributions)); 1567 }); 1568 }); 1569 } 1570 1571 void WebResourceLoadStatisticsStore::clearPrivateClickMeasurement() 1572 { 1573 ASSERT(RunLoop::isMain()); 1574 1575 if (isEphemeral()) 1576 return; 1577 1578 postTask([this]() { 1579 if (!m_statisticsStore) 1580 return; 1581 1582 m_statisticsStore->clearPrivateClickMeasurement(WTF::nullopt); 1583 }); 1584 } 1585 1586 void WebResourceLoadStatisticsStore::clearPrivateClickMeasurementForRegistrableDomain(const RegistrableDomain& domain) 1587 { 1588 ASSERT(RunLoop::isMain()); 1589 1590 if (isEphemeral()) 1591 return; 1592 1593 postTask([this, domain = domain.isolatedCopy()]() mutable { 1594 if (!m_statisticsStore) 1595 return; 1596 1597 m_statisticsStore->clearPrivateClickMeasurement(domain); 1598 }); 1599 } 1600 1601 void WebResourceLoadStatisticsStore::clearExpiredPrivateClickMeasurement() 1602 { 1603 ASSERT(RunLoop::isMain()); 1604 1605 if (isEphemeral()) 1606 return; 1607 1608 postTask([this]() { 1609 if (!m_statisticsStore) 1610 return; 1611 1612 m_statisticsStore->clearExpiredPrivateClickMeasurement(); 1613 }); 1614 } 1615 1616 void WebResourceLoadStatisticsStore::privateClickMeasurementToString(CompletionHandler<void(String)>&& completionHandler) 1617 { 1618 ASSERT(RunLoop::isMain()); 1619 1620 if (isEphemeral()) { 1621 completionHandler("\nNo stored Private Click Measurement data.\n"_s); 1622 return; 1623 } 1624 1625 postTask([this, completionHandler = WTFMove(completionHandler)]() mutable { 1626 if (!m_statisticsStore) { 1627 postTaskReply([completionHandler = WTFMove(completionHandler)]() mutable { 1628 completionHandler({ }); 1629 }); 1630 return; 1631 } 1632 1633 auto result = m_statisticsStore->privateClickMeasurementToString(); 1634 postTaskReply([result, completionHandler = WTFMove(completionHandler)]() mutable { 1635 completionHandler(result); 1636 }); 1637 }); 1638 } 1639 1640 void WebResourceLoadStatisticsStore::clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&& attributionsToClear) 1641 { 1642 ASSERT(RunLoop::isMain()); 1643 1644 if (isEphemeral()) 1645 return; 1646 1647 postTask([this, attributionsToClear = WTFMove(attributionsToClear)]() mutable { 1648 if (!m_statisticsStore) 1649 return; 1650 1651 m_statisticsStore->clearSentAttributions(WTFMove(attributionsToClear)); 1652 }); 1653 } 1654 1655 void WebResourceLoadStatisticsStore::markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&& completionHandler) 1656 { 1657 ASSERT(RunLoop::isMain()); 1658 1659 if (isEphemeral()) { 1660 completionHandler(); 1661 return; 1662 } 1663 1664 postTask([this, completionHandler = WTFMove(completionHandler)]() mutable { 1665 if (m_statisticsStore) 1666 m_statisticsStore->markAttributedPrivateClickMeasurementsAsExpiredForTesting(); 1667 1668 postTaskReply(WTFMove(completionHandler)); 1669 }); 1670 } 1671 1478 1672 } // namespace WebKit 1479 1673 -
trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h
r269807 r270136 38 38 #include <WebCore/NetworkStorageSession.h> 39 39 #include <WebCore/PageIdentifier.h> 40 #include <WebCore/PrivateClickMeasurement.h> 40 41 #include <WebCore/RegistrableDomain.h> 41 42 #include <WebCore/ResourceLoadObserver.h> … … 66 67 class WebFrameProxy; 67 68 class WebProcessProxy; 69 enum class PrivateClickMeasurementAttributionType : bool; 68 70 enum class ShouldGrandfatherStatistics : bool; 69 71 enum class ShouldIncludeLocalhost : bool { No, Yes }; … … 305 307 void insertExpiredStatisticForTesting(const RegistrableDomain&, bool hadUserInteraction, bool isScheduledForAllButCookieDataRemoval, bool isPrevalent, CompletionHandler<void()>&&); 306 308 309 // Private Click Measurement. 310 void insertPrivateClickMeasurement(WebCore::PrivateClickMeasurement&&, PrivateClickMeasurementAttributionType); 311 void markAllUnattributedPrivateClickMeasurementAsExpiredForTesting(); 312 void attributePrivateClickMeasurement(const WebCore::PrivateClickMeasurement::SourceSite&, const WebCore::PrivateClickMeasurement::AttributeOnSite&, WebCore::PrivateClickMeasurement::AttributionTriggerData&&, CompletionHandler<void(Optional<Seconds>)>&&); 313 void allAttributedPrivateClickMeasurement(CompletionHandler<void(Vector<WebCore::PrivateClickMeasurement>&&)>&&); 314 void clearPrivateClickMeasurement(); 315 void clearPrivateClickMeasurementForRegistrableDomain(const WebCore::RegistrableDomain&); 316 void clearExpiredPrivateClickMeasurement(); 317 void privateClickMeasurementToString(CompletionHandler<void(String)>&&); 318 void clearSentAttributions(Vector<WebCore::PrivateClickMeasurement>&&); 319 void updateTimerLastFired(); 320 void markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&&); 321 307 322 private: 308 323 explicit WebResourceLoadStatisticsStore(NetworkSession&, const String&, ShouldIncludeLocalhost, WebCore::ResourceLoadStatistics::IsEphemeral); -
trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp
r269712 r270136 2563 2563 } 2564 2564 2565 void NetworkProcess::firePrivateClickMeasurementTimerImmediately(PAL::SessionID sessionID) 2566 { 2567 if (auto* session = networkSession(sessionID)) 2568 session->firePrivateClickMeasurementTimerImmediately(); 2569 } 2570 2571 void NetworkProcess::simulateResourceLoadStatisticsSessionRestart(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) 2572 { 2573 if (auto* session = networkSession(sessionID)) { 2574 session->recreateResourceLoadStatisticStore([this, sessionID, completionHandler = WTFMove(completionHandler)] () mutable { 2575 firePrivateClickMeasurementTimerImmediately(sessionID); 2576 completionHandler(); 2577 }); 2578 return; 2579 } 2580 completionHandler(); 2581 } 2582 2583 void NetworkProcess::markAttributedPrivateClickMeasurementsAsExpiredForTesting(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) 2584 { 2585 if (auto* session = networkSession(sessionID)) { 2586 session->markAttributedPrivateClickMeasurementsAsExpiredForTesting(WTFMove(completionHandler)); 2587 return; 2588 } 2589 completionHandler(); 2590 } 2591 2565 2592 void NetworkProcess::setPrivateClickMeasurementConversionURLForTesting(PAL::SessionID sessionID, URL&& url, CompletionHandler<void()>&& completionHandler) 2566 2593 { -
trunk/Source/WebKit/NetworkProcess/NetworkProcess.h
r269712 r270136 337 337 void clearPrivateClickMeasurement(PAL::SessionID, CompletionHandler<void()>&&); 338 338 void setPrivateClickMeasurementOverrideTimerForTesting(PAL::SessionID, bool value, CompletionHandler<void()>&&); 339 void markAttributedPrivateClickMeasurementsAsExpiredForTesting(PAL::SessionID, CompletionHandler<void()>&&); 340 void simulateResourceLoadStatisticsSessionRestart(PAL::SessionID, CompletionHandler<void()>&&); 339 341 void setPrivateClickMeasurementConversionURLForTesting(PAL::SessionID, URL&&, CompletionHandler<void()>&&); 340 342 void markPrivateClickMeasurementsAsExpiredForTesting(PAL::SessionID, CompletionHandler<void()>&&); … … 479 481 void addServiceWorkerSession(PAL::SessionID, bool processTerminationDelayEnabled, String&& serviceWorkerRegistrationDirectory, const SandboxExtension::Handle&); 480 482 #endif 483 484 void firePrivateClickMeasurementTimerImmediately(PAL::SessionID); 481 485 482 486 class SessionStorageQuotaManager { -
trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in
r269712 r270136 166 166 ClearPrivateClickMeasurement(PAL::SessionID sessionID) -> () Async 167 167 SetPrivateClickMeasurementOverrideTimerForTesting(PAL::SessionID sessionID, bool value) -> () Async 168 MarkAttributedPrivateClickMeasurementsAsExpiredForTesting(PAL::SessionID sessionID) -> () Async 169 SimulateResourceLoadStatisticsSessionRestart(PAL::SessionID sessionID) -> () Async 168 170 SetPrivateClickMeasurementConversionURLForTesting(PAL::SessionID sessionID, URL url) -> () Async 169 171 MarkPrivateClickMeasurementsAsExpiredForTesting(PAL::SessionID sessionID) -> () Async -
trunk/Source/WebKit/NetworkProcess/NetworkResourceLoader.cpp
r269712 r270136 815 815 m_redirectResponse = redirectResponse; 816 816 817 Optional<PrivateClickMeasurement:: Conversion> privateClickMeasurementConversion;817 Optional<PrivateClickMeasurement::AttributionTriggerData> privateClickMeasurementAttributionTriggerData; 818 818 if (!sessionID().isEphemeral()) { 819 if (auto result = PrivateClickMeasurement::parse ConversionRequest(redirectRequest.url()))820 privateClickMeasurement Conversion= result.value();819 if (auto result = PrivateClickMeasurement::parseAttributionRequest(redirectRequest.url())) 820 privateClickMeasurementAttributionTriggerData = result.value(); 821 821 else if (!result.error().isEmpty()) 822 822 addConsoleMessage(MessageSource::PrivateClickMeasurement, MessageLevel::Error, result.error()); … … 828 828 829 829 if (m_networkLoadChecker) { 830 if (privateClickMeasurement Conversion)830 if (privateClickMeasurementAttributionTriggerData) 831 831 m_networkLoadChecker->enableContentExtensionsCheck(); 832 832 m_networkLoadChecker->storeRedirectionIfNeeded(request, redirectResponse); 833 833 834 834 RELEASE_LOG_IF_ALLOWED("willSendRedirectedRequest: Checking redirect using NetworkLoadChecker"); 835 m_networkLoadChecker->checkRedirection(WTFMove(request), WTFMove(redirectRequest), WTFMove(redirectResponse), this, [protectedThis = makeRef(*this), this, storedCredentialsPolicy = m_networkLoadChecker->storedCredentialsPolicy(), privateClickMeasurement Conversion = WTFMove(privateClickMeasurementConversion)](auto&& result) mutable {835 m_networkLoadChecker->checkRedirection(WTFMove(request), WTFMove(redirectRequest), WTFMove(redirectResponse), this, [protectedThis = makeRef(*this), this, storedCredentialsPolicy = m_networkLoadChecker->storedCredentialsPolicy(), privateClickMeasurementAttributionTriggerData = WTFMove(privateClickMeasurementAttributionTriggerData)](auto&& result) mutable { 836 836 if (!result.has_value()) { 837 837 if (result.error().isCancellation()) { … … 866 866 867 867 m_shouldRestartLoad = storedCredentialsPolicy != m_networkLoadChecker->storedCredentialsPolicy(); 868 this->continueWillSendRedirectedRequest(WTFMove(result->request), WTFMove(result->redirectRequest), WTFMove(result->redirectResponse), WTFMove(privateClickMeasurement Conversion));868 this->continueWillSendRedirectedRequest(WTFMove(result->request), WTFMove(result->redirectRequest), WTFMove(result->redirectResponse), WTFMove(privateClickMeasurementAttributionTriggerData)); 869 869 }); 870 870 return; 871 871 } 872 continueWillSendRedirectedRequest(WTFMove(request), WTFMove(redirectRequest), WTFMove(redirectResponse), WTFMove(privateClickMeasurement Conversion));873 } 874 875 void NetworkResourceLoader::continueWillSendRedirectedRequest(ResourceRequest&& request, ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse, Optional<PrivateClickMeasurement:: Conversion>&& privateClickMeasurementConversion)876 { 877 RELEASE_LOG_IF_ALLOWED("continueWillSendRedirectedRequest: (m_isKeptAlive=%d, hasAdClickConversion=%d)", m_isKeptAlive, !!privateClickMeasurement Conversion);872 continueWillSendRedirectedRequest(WTFMove(request), WTFMove(redirectRequest), WTFMove(redirectResponse), WTFMove(privateClickMeasurementAttributionTriggerData)); 873 } 874 875 void NetworkResourceLoader::continueWillSendRedirectedRequest(ResourceRequest&& request, ResourceRequest&& redirectRequest, ResourceResponse&& redirectResponse, Optional<PrivateClickMeasurement::AttributionTriggerData>&& privateClickMeasurementAttributionTriggerData) 876 { 877 RELEASE_LOG_IF_ALLOWED("continueWillSendRedirectedRequest: (m_isKeptAlive=%d, hasAdClickConversion=%d)", m_isKeptAlive, !!privateClickMeasurementAttributionTriggerData); 878 878 ASSERT(!isSynchronous()); 879 879 … … 884 884 885 885 NetworkSession* networkSession = nullptr; 886 if (privateClickMeasurement Conversion&& (networkSession = m_connection->networkProcess().networkSession(sessionID())))887 networkSession->handlePrivateClickMeasurementConversion(WTFMove(*privateClickMeasurement Conversion), request.url(), redirectRequest);886 if (privateClickMeasurementAttributionTriggerData && (networkSession = m_connection->networkProcess().networkSession(sessionID()))) 887 networkSession->handlePrivateClickMeasurementConversion(WTFMove(*privateClickMeasurementAttributionTriggerData), request.url(), redirectRequest); 888 888 889 889 // We send the request body separately because the ResourceRequest body normally does not get encoded when sent over IPC, as an optimization. -
trunk/Source/WebKit/NetworkProcess/NetworkResourceLoader.h
r269712 r270136 192 192 #endif 193 193 194 void continueWillSendRedirectedRequest(WebCore::ResourceRequest&&, WebCore::ResourceRequest&& redirectRequest, WebCore::ResourceResponse&&, Optional<WebCore::PrivateClickMeasurement:: Conversion>&&);194 void continueWillSendRedirectedRequest(WebCore::ResourceRequest&&, WebCore::ResourceRequest&& redirectRequest, WebCore::ResourceResponse&&, Optional<WebCore::PrivateClickMeasurement::AttributionTriggerData>&&); 195 195 void didFinishWithRedirectResponse(WebCore::ResourceRequest&&, WebCore::ResourceRequest&& redirectRequest, WebCore::ResourceResponse&&); 196 196 WebCore::ResourceResponse sanitizeResponseIfPossible(WebCore::ResourceResponse&&, WebCore::ResourceResponse::SanitizationType); … … 203 203 void logSlowCacheRetrieveIfNeeded(const NetworkCache::Cache::RetrieveInfo&); 204 204 205 void handlePrivateClickMeasurementConversion(WebCore::PrivateClickMeasurement:: Conversion&&, const URL&, const WebCore::ResourceRequest&);205 void handlePrivateClickMeasurementConversion(WebCore::PrivateClickMeasurement::AttributionTriggerData&&, const URL&, const WebCore::ResourceRequest&); 206 206 207 207 Optional<Seconds> validateCacheEntryForMaxAgeCapValidation(const WebCore::ResourceRequest&, const WebCore::ResourceRequest& redirectRequest, const WebCore::ResourceResponse&); -
trunk/Source/WebKit/NetworkProcess/NetworkSession.cpp
r269712 r270136 91 91 , m_standaloneApplicationDomain(parameters.resourceLoadStatisticsParameters.standaloneApplicationDomain) 92 92 #endif 93 , m_privateClickMeasurement(makeUniqueRef<PrivateClickMeasurementManager>( networkProcess, parameters.sessionID))93 , m_privateClickMeasurement(makeUniqueRef<PrivateClickMeasurementManager>(*this, networkProcess, parameters.sessionID)) 94 94 , m_testSpeedMultiplier(parameters.testSpeedMultiplier) 95 95 , m_allowsServerPreconnect(parameters.allowsServerPreconnect) … … 187 187 m_resourceLoadStatistics->setPrevalentResourceForDebugMode(m_resourceLoadStatisticsManualPrevalentResource, [] { }); 188 188 forwardResourceLoadStatisticsSettings(); 189 } 190 191 void NetworkSession::firePrivateClickMeasurementTimerImmediately() 192 { 193 m_privateClickMeasurement->startTimer(0_s); 189 194 } 190 195 … … 306 311 void NetworkSession::storePrivateClickMeasurement(WebCore::PrivateClickMeasurement&& privateClickMeasurement) 307 312 { 308 m_privateClickMeasurement->storeUn converted(WTFMove(privateClickMeasurement));309 } 310 311 void NetworkSession::handlePrivateClickMeasurementConversion(PrivateClickMeasurement:: Conversion&& conversion, const URL& requestURL, const WebCore::ResourceRequest& redirectRequest)312 { 313 m_privateClickMeasurement->handle Conversion(WTFMove(conversion), requestURL, redirectRequest);313 m_privateClickMeasurement->storeUnattributed(WTFMove(privateClickMeasurement)); 314 } 315 316 void NetworkSession::handlePrivateClickMeasurementConversion(PrivateClickMeasurement::AttributionTriggerData&& attributionTriggerData, const URL& requestURL, const WebCore::ResourceRequest& redirectRequest) 317 { 318 m_privateClickMeasurement->handleAttribution(WTFMove(attributionTriggerData), requestURL, redirectRequest); 314 319 } 315 320 … … 334 339 } 335 340 341 void NetworkSession::markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&& completionHandler) 342 { 343 m_privateClickMeasurement->markAttributedPrivateClickMeasurementsAsExpiredForTesting(WTFMove(completionHandler)); 344 } 345 336 346 void NetworkSession::setPrivateClickMeasurementConversionURLForTesting(URL&& url) 337 347 { … … 341 351 void NetworkSession::markPrivateClickMeasurementsAsExpiredForTesting() 342 352 { 343 m_privateClickMeasurement->markAllUn convertedAsExpiredForTesting();353 m_privateClickMeasurement->markAllUnattributedAsExpiredForTesting(); 344 354 } 345 355 -
trunk/Source/WebKit/NetworkProcess/NetworkSession.h
r269712 r270136 118 118 #endif 119 119 void storePrivateClickMeasurement(WebCore::PrivateClickMeasurement&&); 120 void handlePrivateClickMeasurementConversion(WebCore::PrivateClickMeasurement:: Conversion&&, const URL& requestURL, const WebCore::ResourceRequest& redirectRequest);120 void handlePrivateClickMeasurementConversion(WebCore::PrivateClickMeasurement::AttributionTriggerData&&, const URL& requestURL, const WebCore::ResourceRequest& redirectRequest); 121 121 void dumpPrivateClickMeasurement(CompletionHandler<void(String)>&&); 122 122 void clearPrivateClickMeasurement(); 123 123 void clearPrivateClickMeasurementForRegistrableDomain(WebCore::RegistrableDomain&&); 124 124 void setPrivateClickMeasurementOverrideTimerForTesting(bool value); 125 void markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&&); 125 126 void setPrivateClickMeasurementConversionURLForTesting(URL&&); 126 127 void markPrivateClickMeasurementsAsExpiredForTesting(); 128 void firePrivateClickMeasurementTimerImmediately(); 127 129 128 130 void addKeptAliveLoad(Ref<NetworkResourceLoader>&&); -
trunk/Source/WebKit/NetworkProcess/PrivateClickMeasurementManager.cpp
r269712 r270136 43 43 using namespace WebCore; 44 44 45 using Source = PrivateClickMeasurement::Source; 46 using Destination = PrivateClickMeasurement::Destination; 47 using DestinationMap = HashMap<Destination, PrivateClickMeasurement>; 48 using Conversion = PrivateClickMeasurement::Conversion; 45 using SourceSite = PrivateClickMeasurement::SourceSite; 46 using AttributeOnSite = PrivateClickMeasurement::AttributeOnSite; 47 using AttributionTriggerData = PrivateClickMeasurement::AttributionTriggerData; 49 48 50 49 constexpr Seconds debugModeSecondsUntilSend { 60_s }; 51 50 52 void PrivateClickMeasurementManager::storeUnconverted(PrivateClickMeasurement&& attribution) 51 PrivateClickMeasurementManager::PrivateClickMeasurementManager(NetworkSession& networkSession, NetworkProcess& networkProcess, PAL::SessionID sessionID) 52 : m_firePendingAttributionRequestsTimer(*this, &PrivateClickMeasurementManager::firePendingAttributionRequests) 53 , m_networkSession(makeWeakPtr(networkSession)) 54 , m_networkProcess(networkProcess) 55 , m_sessionID(sessionID) 56 , m_pingLoadFunction([](NetworkResourceLoadParameters&& params, CompletionHandler<void(const WebCore::ResourceError&, const WebCore::ResourceResponse&)>&& completionHandler) { 57 UNUSED_PARAM(params); 58 completionHandler(WebCore::ResourceError(), WebCore::ResourceResponse()); 59 }) 60 { 61 // We should send any pending attributions on session-start in case their 62 // send delay has expired while the session was closed. Waiting 5 seconds accounts for the 63 // delay in database startup. 64 startTimer(5_s); 65 } 66 67 void PrivateClickMeasurementManager::storeUnattributed(PrivateClickMeasurement&& attribution) 53 68 { 54 69 clearExpired(); … … 59 74 } 60 75 61 m_unconvertedPrivateClickMeasurementMap.set(std::make_pair(attribution.source(), attribution.destination()), WTFMove(attribution)); 62 } 63 64 void PrivateClickMeasurementManager::handleConversion(Conversion&& conversion, const URL& requestURL, const WebCore::ResourceRequest& redirectRequest) 76 if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics()) 77 resourceLoadStatistics->insertPrivateClickMeasurement(WTFMove(attribution), PrivateClickMeasurementAttributionType::Unattributed); 78 } 79 80 void PrivateClickMeasurementManager::handleAttribution(AttributionTriggerData&& attributionTriggerData, const URL& requestURL, const WebCore::ResourceRequest& redirectRequest) 65 81 { 66 82 if (m_sessionID.isEphemeral()) … … 72 88 if (!redirectDomain.matches(requestURL)) { 73 89 if (UNLIKELY(debugModeEnabled())) { 74 RELEASE_LOG_INFO(PrivateClickMeasurement, " Conversion was not accepted because the HTTP redirect was not same-site.");75 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Error, "[Private Click Measurement] Conversion was not accepted because the HTTP redirect was not same-site."_s);90 RELEASE_LOG_INFO(PrivateClickMeasurement, "Attribution was not accepted because the HTTP redirect was not same-site."); 91 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Error, "[Private Click Measurement] Attribution was not accepted because the HTTP redirect was not same-site."_s); 76 92 } 77 93 return; … … 80 96 if (redirectDomain.matches(firstPartyURL)) { 81 97 if (UNLIKELY(debugModeEnabled())) { 82 RELEASE_LOG_INFO(PrivateClickMeasurement, " Conversion was not accepted because it was requested in an HTTP redirect that is same-site as the first-party.");83 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Error, "[Private Click Measurement] Conversion was not accepted because it was requested in an HTTP redirect that is same-site as the first-party."_s);84 } 85 return; 86 } 87 88 convert(PrivateClickMeasurement::Source { WTFMove(redirectDomain) }, PrivateClickMeasurement::Destination { firstPartyURL }, WTFMove(conversion));98 RELEASE_LOG_INFO(PrivateClickMeasurement, "Attribution was not accepted because it was requested in an HTTP redirect that is same-site as the first-party."); 99 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Error, "[Private Click Measurement] Attribution was not accepted because it was requested in an HTTP redirect that is same-site as the first-party."_s); 100 } 101 return; 102 } 103 104 attribute(SourceSite { WTFMove(redirectDomain) }, AttributeOnSite { firstPartyURL }, WTFMove(attributionTriggerData)); 89 105 } 90 106 91 107 void PrivateClickMeasurementManager::startTimer(Seconds seconds) 92 108 { 93 m_firePendingConversionRequestsTimer.startOneShot(m_isRunningTest ? 0_s : seconds); 94 } 95 96 void PrivateClickMeasurementManager::convert(const Source& source, const Destination& destination, Conversion&& conversion) 97 { 98 clearExpired(); 99 100 if (!conversion.isValid()) { 101 if (UNLIKELY(debugModeEnabled())) { 102 RELEASE_LOG_INFO(PrivateClickMeasurement, "Got an invalid conversion."); 103 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Error, "[Private Click Measurement] Got an invalid conversion."_s); 104 } 105 return; 106 } 107 108 auto conversionData = conversion.data; 109 auto conversionPriority = conversion.priority; 110 111 if (UNLIKELY(debugModeEnabled())) { 112 RELEASE_LOG_INFO(PrivateClickMeasurement, "Got a conversion with conversion data: %{public}u and priority: %{public}u.", conversionData, conversionPriority); 113 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Info, makeString("[Private Click Measurement] Got a conversion with conversion data: '"_s, conversionData, "' and priority: '"_s, conversionPriority, "'."_s)); 114 } 115 116 auto secondsUntilSend = Seconds::infinity(); 117 118 auto pair = std::make_pair(source, destination); 119 auto previouslyUnconvertedAttribution = m_unconvertedPrivateClickMeasurementMap.take(pair); 120 auto previouslyConvertedAttributionIter = m_convertedPrivateClickMeasurementMap.find(pair); 121 122 if (!previouslyUnconvertedAttribution.isEmpty()) { 123 // Always convert the pending attribution and remove it from the unconverted map. 124 if (auto optionalSecondsUntilSend = previouslyUnconvertedAttribution.convertAndGetEarliestTimeToSend(WTFMove(conversion))) { 125 secondsUntilSend = *optionalSecondsUntilSend; 126 ASSERT(secondsUntilSend != Seconds::infinity()); 127 128 if (UNLIKELY(debugModeEnabled())) { 129 RELEASE_LOG_INFO(PrivateClickMeasurement, "Converted a stored ad click with conversion data: %{public}u and priority: %{public}u.", conversionData, conversionPriority); 130 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Info, makeString("[Private Click Measurement] Converted a stored ad click with conversion data: '"_s, conversionData, "' and priority: '"_s, conversionPriority, "'."_s)); 131 } 132 } 133 134 if (previouslyConvertedAttributionIter == m_convertedPrivateClickMeasurementMap.end()) 135 m_convertedPrivateClickMeasurementMap.add(pair, WTFMove(previouslyUnconvertedAttribution)); 136 else if (previouslyUnconvertedAttribution.hasHigherPriorityThan(previouslyConvertedAttributionIter->value)) { 137 // If the newly converted attribution has higher priority, replace the old one. 138 m_convertedPrivateClickMeasurementMap.set(pair, WTFMove(previouslyUnconvertedAttribution)); 139 140 if (UNLIKELY(debugModeEnabled())) { 141 RELEASE_LOG_INFO(PrivateClickMeasurement, "Replaced a previously converted ad click with a new one with conversion data: %{public}u and priority: %{public}u because it had higher priority.", conversionData, conversionPriority); 142 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Info, makeString("[Private Click Measurement] Replaced a previously converted ad click with a new one with conversion data: '"_s, conversionData, "' and priority: '"_s, conversionPriority, "' because it had higher priority."_s)); 143 } 144 } 145 } else if (previouslyConvertedAttributionIter != m_convertedPrivateClickMeasurementMap.end()) { 146 // If we have no newly converted attribution, re-convert the old one to respect the new priority. 147 if (auto optionalSecondsUntilSend = previouslyConvertedAttributionIter->value.convertAndGetEarliestTimeToSend(WTFMove(conversion))) { 148 secondsUntilSend = *optionalSecondsUntilSend; 149 ASSERT(secondsUntilSend != Seconds::infinity()); 150 151 if (UNLIKELY(debugModeEnabled())) { 152 RELEASE_LOG_INFO(PrivateClickMeasurement, "Re-converted an ad click with a new one with conversion data: %{public}u and priority: %{public}u because it had higher priority.", conversionData, conversionPriority); 153 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Info, makeString("[Private Click Measurement] Re-converted an ad click with a new one with conversion data: '"_s, conversionData, "' and priority: '"_s, conversionPriority, "'' because it had higher priority."_s)); 154 } 155 } 156 } 157 158 if (secondsUntilSend == Seconds::infinity()) 159 return; 160 161 if (m_firePendingConversionRequestsTimer.isActive() && m_firePendingConversionRequestsTimer.nextFireInterval() < secondsUntilSend) 162 return; 163 164 if (UNLIKELY(debugModeEnabled())) { 165 RELEASE_LOG_INFO(PrivateClickMeasurement, "Setting timer for firing conversion requests to the debug mode timeout of %{public}f seconds where the regular timeout would have been %{public}f seconds.", debugModeSecondsUntilSend.seconds(), secondsUntilSend.seconds()); 166 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Info, makeString("[Private Click Measurement] Setting timer for firing conversion requests to the debug mode timeout of "_s, debugModeSecondsUntilSend.seconds(), " seconds where the regular timeout would have been "_s, secondsUntilSend.seconds(), " seconds."_s)); 167 secondsUntilSend = debugModeSecondsUntilSend; 168 } 169 170 startTimer(secondsUntilSend); 109 m_firePendingAttributionRequestsTimer.startOneShot(m_isRunningTest ? 0_s : seconds); 110 } 111 112 void PrivateClickMeasurementManager::attribute(const SourceSite& sourceSite, const AttributeOnSite& attributeOnSite, AttributionTriggerData&& attributionTriggerData) 113 { 114 if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics()) { 115 resourceLoadStatistics->attributePrivateClickMeasurement(sourceSite, attributeOnSite, WTFMove(attributionTriggerData), [this] (auto optionalSecondsUntilSend) { 116 if (optionalSecondsUntilSend) { 117 auto secondsUntilSend = *optionalSecondsUntilSend; 118 if (m_firePendingAttributionRequestsTimer.isActive() && m_firePendingAttributionRequestsTimer.nextFireInterval() < secondsUntilSend) 119 return; 120 121 if (UNLIKELY(debugModeEnabled())) { 122 RELEASE_LOG_INFO(PrivateClickMeasurement, "Setting timer for firing attribution requests to the debug mode timeout of %{public}f seconds where the regular timeout would have been %{public}f seconds.", debugModeSecondsUntilSend.seconds(), secondsUntilSend.seconds()); 123 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Info, makeString("[Private Click Measurement] Setting timer for firing attribution requests to the debug mode timeout of "_s, debugModeSecondsUntilSend.seconds(), " seconds where the regular timeout would have been "_s, secondsUntilSend.seconds(), " seconds."_s)); 124 secondsUntilSend = debugModeSecondsUntilSend; 125 } 126 startTimer(secondsUntilSend); 127 } 128 }); 129 } 171 130 } 172 131 173 132 void PrivateClickMeasurementManager::fireConversionRequest(const PrivateClickMeasurement& attribution) 174 133 { 175 auto conversionURL = m_conversionBaseURLForTesting ? *m_conversionBaseURLForTesting : attribution.reportURL();176 if ( conversionURL.isEmpty() || !conversionURL.isValid())177 return; 178 179 ResourceRequest request { WTFMove( conversionURL) };134 auto attributionURL = m_attributionBaseURLForTesting ? *m_attributionBaseURLForTesting : attribution.reportURL(); 135 if (attributionURL.isEmpty() || !attributionURL.isValid()) 136 return; 137 138 ResourceRequest request { WTFMove(attributionURL) }; 180 139 181 140 request.setHTTPMethod("POST"_s); … … 201 160 202 161 if (UNLIKELY(debugModeEnabled())) { 203 RELEASE_LOG_INFO(PrivateClickMeasurement, "About to fire an attribution request for a conversion.");204 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Error, "[Private Click Measurement] About to fire an attribution request for a conversion."_s);162 RELEASE_LOG_INFO(PrivateClickMeasurement, "About to fire an attribution request."); 163 m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::PrivateClickMeasurement, MessageLevel::Error, "[Private Click Measurement] About to fire an attribution request."_s); 205 164 } 206 165 … … 222 181 } 223 182 224 void PrivateClickMeasurementManager::firePendingConversionRequests() 225 { 226 auto nextTimeToFire = Seconds::infinity(); 227 for (auto& attribution : m_convertedPrivateClickMeasurementMap.values()) { 228 if (attribution.wasConversionSent()) { 229 ASSERT_NOT_REACHED(); 230 continue; 231 } 232 auto earliestTimeToSend = attribution.earliestTimeToSend(); 233 if (!earliestTimeToSend) { 234 ASSERT_NOT_REACHED(); 235 continue; 236 } 237 238 auto now = WallTime::now(); 239 if (*earliestTimeToSend <= now || m_isRunningTest || debugModeEnabled()) { 240 fireConversionRequest(attribution); 241 attribution.markConversionAsSent(); 242 continue; 243 } 244 245 auto seconds = *earliestTimeToSend - now; 246 nextTimeToFire = std::min(nextTimeToFire, seconds); 247 } 248 249 m_convertedPrivateClickMeasurementMap.removeIf([](auto& keyAndValue) { 250 return keyAndValue.value.wasConversionSent(); 183 void PrivateClickMeasurementManager::clearSentAttributions(Vector<PrivateClickMeasurement>&& sentConversions) 184 { 185 if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics()) 186 resourceLoadStatistics->clearSentAttributions(WTFMove(sentConversions)); 187 } 188 189 void PrivateClickMeasurementManager::updateTimerLastFired() 190 { 191 if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics()) 192 resourceLoadStatistics->updateTimerLastFired(); 193 } 194 195 void PrivateClickMeasurementManager::firePendingAttributionRequests() 196 { 197 auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics(); 198 if (!resourceLoadStatistics) 199 return; 200 201 resourceLoadStatistics->allAttributedPrivateClickMeasurement([this] (auto&& attributions) { 202 auto nextTimeToFire = Seconds::infinity(); 203 Vector<PrivateClickMeasurement> sentAttributions; 204 205 for (auto& attribution : attributions) { 206 auto earliestTimeToSend = attribution.earliestTimeToSend(); 207 if (!earliestTimeToSend) { 208 ASSERT_NOT_REACHED(); 209 continue; 210 } 211 212 auto now = WallTime::now(); 213 if (*earliestTimeToSend <= now || m_isRunningTest || debugModeEnabled()) { 214 fireConversionRequest(attribution); 215 sentAttributions.append(WTFMove(attribution)); 216 continue; 217 } 218 219 auto seconds = *earliestTimeToSend - now; 220 nextTimeToFire = std::min(nextTimeToFire, seconds); 221 } 222 223 clearSentAttributions(WTFMove(sentAttributions)); 224 updateTimerLastFired(); 225 226 if (nextTimeToFire < Seconds::infinity()) 227 startTimer(nextTimeToFire); 251 228 }); 252 253 if (nextTimeToFire < Seconds::infinity())254 startTimer(nextTimeToFire);255 229 } 256 230 257 231 void PrivateClickMeasurementManager::clear() 258 232 { 259 m_firePendingConversionRequestsTimer.stop(); 260 m_unconvertedPrivateClickMeasurementMap.clear(); 261 m_convertedPrivateClickMeasurementMap.clear(); 233 m_firePendingAttributionRequestsTimer.stop(); 234 235 if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics()) 236 resourceLoadStatistics->clearPrivateClickMeasurement(); 262 237 } 263 238 264 239 void PrivateClickMeasurementManager::clearForRegistrableDomain(const RegistrableDomain& domain) 265 240 { 266 m_unconvertedPrivateClickMeasurementMap.removeIf([&domain](auto& keyAndValue) { 267 return keyAndValue.key.first.registrableDomain == domain || keyAndValue.key.second.registrableDomain == domain; 268 }); 269 270 m_convertedPrivateClickMeasurementMap.removeIf([&domain](auto& keyAndValue) { 271 return keyAndValue.key.first.registrableDomain == domain || keyAndValue.key.second.registrableDomain == domain; 272 }); 241 if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics()) 242 resourceLoadStatistics->clearPrivateClickMeasurementForRegistrableDomain(domain); 273 243 } 274 244 275 245 void PrivateClickMeasurementManager::clearExpired() 276 246 { 277 m_unconvertedPrivateClickMeasurementMap.removeIf([](auto& keyAndValue) { 278 return keyAndValue.value.hasExpired(); 279 }); 247 if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics()) 248 resourceLoadStatistics->clearExpiredPrivateClickMeasurement(); 280 249 } 281 250 282 251 void PrivateClickMeasurementManager::toString(CompletionHandler<void(String)>&& completionHandler) const 283 252 { 284 if (m_unconvertedPrivateClickMeasurementMap.isEmpty() && m_convertedPrivateClickMeasurementMap.isEmpty()) 285 return completionHandler("\nNo stored Private Click Measurement data.\n"_s); 286 287 unsigned unconvertedAttributionNumber = 0; 288 StringBuilder builder; 289 for (auto& attribution : m_unconvertedPrivateClickMeasurementMap.values()) { 290 if (!unconvertedAttributionNumber) 291 builder.appendLiteral("Unconverted Private Click Measurements:\n"); 292 else 293 builder.append('\n'); 294 builder.appendLiteral("WebCore::PrivateClickMeasurement "); 295 builder.appendNumber(++unconvertedAttributionNumber); 296 builder.append('\n'); 297 builder.append(attribution.toString()); 298 } 299 300 unsigned convertedAttributionNumber = 0; 301 for (auto& attribution : m_convertedPrivateClickMeasurementMap.values()) { 302 if (unconvertedAttributionNumber) 303 builder.append('\n'); 304 if (!convertedAttributionNumber) 305 builder.appendLiteral("Converted Private Click Measurements:\n"); 306 else 307 builder.append('\n'); 308 builder.appendLiteral("WebCore::PrivateClickMeasurement "); 309 builder.appendNumber(++convertedAttributionNumber + unconvertedAttributionNumber); 310 builder.append('\n'); 311 builder.append(attribution.toString()); 312 } 313 314 completionHandler(builder.toString()); 253 if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics()) 254 resourceLoadStatistics->privateClickMeasurementToString(WTFMove(completionHandler)); 315 255 } 316 256 … … 318 258 { 319 259 if (testURL.isEmpty()) 320 m_ conversionBaseURLForTesting = { };260 m_attributionBaseURLForTesting = { }; 321 261 else 322 m_ conversionBaseURLForTesting = WTFMove(testURL);323 } 324 325 void PrivateClickMeasurementManager::markAllUn convertedAsExpiredForTesting()326 { 327 for (auto& attribution : m_unconvertedPrivateClickMeasurementMap.values())328 attribution.markAsExpired();262 m_attributionBaseURLForTesting = WTFMove(testURL); 263 } 264 265 void PrivateClickMeasurementManager::markAllUnattributedAsExpiredForTesting() 266 { 267 if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics()) 268 resourceLoadStatistics->markAllUnattributedPrivateClickMeasurementAsExpiredForTesting(); 329 269 } 330 270 … … 334 274 } 335 275 276 void PrivateClickMeasurementManager::markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&& completionHandler) 277 { 278 if (auto* resourceLoadStatistics = m_networkSession->resourceLoadStatistics()) { 279 resourceLoadStatistics->markAttributedPrivateClickMeasurementsAsExpiredForTesting(WTFMove(completionHandler)); 280 return; 281 } 282 completionHandler(); 283 } 284 336 285 } // namespace WebKit -
trunk/Source/WebKit/NetworkProcess/PrivateClickMeasurementManager.h
r269712 r270136 41 41 namespace WebKit { 42 42 43 enum class PrivateClickMeasurementAttributionType : bool { Unattributed, Attributed }; 44 43 45 class PrivateClickMeasurementManager : public CanMakeWeakPtr<PrivateClickMeasurementManager> { 44 46 WTF_MAKE_FAST_ALLOCATED; … … 47 49 using RegistrableDomain = WebCore::RegistrableDomain; 48 50 using PrivateClickMeasurement = WebCore::PrivateClickMeasurement; 49 using Source = WebCore::PrivateClickMeasurement::Source;50 using Destination = WebCore::PrivateClickMeasurement::Destination;51 using Conversion = WebCore::PrivateClickMeasurement::Conversion;51 using SourceSite = WebCore::PrivateClickMeasurement::SourceSite; 52 using AttributeOnSite = WebCore::PrivateClickMeasurement::AttributeOnSite; 53 using AttributionTriggerData = WebCore::PrivateClickMeasurement::AttributionTriggerData; 52 54 53 explicit PrivateClickMeasurementManager(NetworkProcess& networkProcess, PAL::SessionID sessionID) 54 : m_firePendingConversionRequestsTimer(*this, &PrivateClickMeasurementManager::firePendingConversionRequests) 55 , m_pingLoadFunction([](NetworkResourceLoadParameters&& params, CompletionHandler<void(const WebCore::ResourceError&, const WebCore::ResourceResponse&)>&& completionHandler) { 56 UNUSED_PARAM(params); 57 completionHandler(WebCore::ResourceError(), WebCore::ResourceResponse()); 58 }) 59 , m_networkProcess(networkProcess) 60 , m_sessionID(sessionID) 61 { 62 } 55 explicit PrivateClickMeasurementManager(NetworkSession&, NetworkProcess&, PAL::SessionID); 63 56 64 void storeUn converted(PrivateClickMeasurement&&);65 void handle Conversion(Conversion&&, const URL& requestURL, const WebCore::ResourceRequest& redirectRequest);57 void storeUnattributed(PrivateClickMeasurement&&); 58 void handleAttribution(AttributionTriggerData&&, const URL& requestURL, const WebCore::ResourceRequest& redirectRequest); 66 59 void clear(); 67 60 void clearForRegistrableDomain(const RegistrableDomain&); … … 70 63 void setOverrideTimerForTesting(bool value) { m_isRunningTest = value; } 71 64 void setConversionURLForTesting(URL&&); 72 void markAllUnconvertedAsExpiredForTesting(); 65 void markAllUnattributedAsExpiredForTesting(); 66 void markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&&); 67 void startTimer(Seconds); 73 68 74 69 private: 75 void startTimer(Seconds);76 void convert(const Source&, const Destination&, Conversion&&);70 void clearSentAttributions(Vector<PrivateClickMeasurement>&&); 71 void attribute(const SourceSite&, const AttributeOnSite&, AttributionTriggerData&&); 77 72 void fireConversionRequest(const PrivateClickMeasurement&); 78 void firePending ConversionRequests();73 void firePendingAttributionRequests(); 79 74 void clearExpired(); 80 75 bool debugModeEnabled() const; 76 void updateTimerLastFired(); 81 77 82 HashMap<std::pair<Source, Destination>, PrivateClickMeasurement> m_unconvertedPrivateClickMeasurementMap; 83 HashMap<std::pair<Source, Destination>, PrivateClickMeasurement> m_convertedPrivateClickMeasurementMap; 84 WebCore::Timer m_firePendingConversionRequestsTimer; 85 Function<void(NetworkResourceLoadParameters&&, CompletionHandler<void(const WebCore::ResourceError&, const WebCore::ResourceResponse&)>&&)> m_pingLoadFunction; 78 WebCore::Timer m_firePendingAttributionRequestsTimer; 86 79 bool m_isRunningTest { false }; 87 Optional<URL> m_conversionBaseURLForTesting; 80 Optional<URL> m_attributionBaseURLForTesting; 81 WeakPtr<NetworkSession> m_networkSession; 88 82 Ref<NetworkProcess> m_networkProcess; 89 83 PAL::SessionID m_sessionID; 84 Function<void(NetworkResourceLoadParameters&&, CompletionHandler<void(const WebCore::ResourceError&, const WebCore::ResourceResponse&)>&&)> m_pingLoadFunction; 90 85 }; 91 86 -
trunk/Source/WebKit/UIProcess/API/C/WKPage.cpp
r269810 r270136 2892 2892 } 2893 2893 2894 void WKPageMarkAttributedPrivateClickMeasurementsAsExpiredForTesting(WKPageRef page, WKPageMarkAttributedPrivateClickMeasurementsAsExpiredForTestingFunction callback, void* callbackContext) 2895 { 2896 toImpl(page)->markAttributedPrivateClickMeasurementsAsExpiredForTesting([callbackContext, callback] () { 2897 callback(callbackContext); 2898 }); 2899 } 2900 2901 void WKPageSimulateResourceLoadStatisticsSessionRestart(WKPageRef page, WKPageSimulateResourceLoadStatisticsSessionRestartFunction callback, void* callbackContext) 2902 { 2903 toImpl(page)->simulateResourceLoadStatisticsSessionRestart([callbackContext, callback] () { 2904 callback(callbackContext); 2905 }); 2906 } 2907 2894 2908 void WKPageSetPrivateClickMeasurementConversionURLForTesting(WKPageRef page, WKURLRef URLRef, WKPageSetPrivateClickMeasurementConversionURLForTestingFunction callback, void* callbackContext) 2895 2909 { -
trunk/Source/WebKit/UIProcess/API/C/WKPagePrivate.h
r269712 r270136 176 176 typedef void (*WKPageSetPrivateClickMeasurementOverrideTimerForTestingFunction)(void* functionContext); 177 177 WK_EXPORT void WKPageSetPrivateClickMeasurementOverrideTimerForTesting(WKPageRef page, bool value, WKPageSetPrivateClickMeasurementOverrideTimerForTestingFunction callback, void* callbackContext); 178 typedef void (*WKPageMarkAttributedPrivateClickMeasurementsAsExpiredForTestingFunction)(void* functionContext); 179 WK_EXPORT void WKPageMarkAttributedPrivateClickMeasurementsAsExpiredForTesting(WKPageRef page, WKPageMarkAttributedPrivateClickMeasurementsAsExpiredForTestingFunction callback, void* callbackContext); 180 typedef void (*WKPageSimulateResourceLoadStatisticsSessionRestartFunction)(void* functionContext); 181 WK_EXPORT void WKPageSimulateResourceLoadStatisticsSessionRestart(WKPageRef page, WKPageSimulateResourceLoadStatisticsSessionRestartFunction callback, void* callbackContext); 178 182 typedef void (*WKPageSetPrivateClickMeasurementConversionURLForTestingFunction)(void* functionContext); 179 183 WK_EXPORT void WKPageSetPrivateClickMeasurementConversionURLForTesting(WKPageRef page, WKURLRef urlString, WKPageSetPrivateClickMeasurementConversionURLForTestingFunction callback, void* callbackContext); -
trunk/Source/WebKit/UIProcess/WebPageProxy.cpp
r270028 r270136 4661 4661 privateClickMeasurement = navigation->privateClickMeasurement(); 4662 4662 if (privateClickMeasurement) { 4663 if (privateClickMeasurement-> destination().matches(frame->url()))4663 if (privateClickMeasurement->attributeOnSite().matches(frame->url())) 4664 4664 websiteDataStore().networkProcess().send(Messages::NetworkProcess::StorePrivateClickMeasurement(m_websiteDataStore->sessionID(), *privateClickMeasurement), 0); 4665 4665 } … … 9966 9966 } 9967 9967 9968 void WebPageProxy::markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&& completionHandler) 9969 { 9970 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::MarkAttributedPrivateClickMeasurementsAsExpiredForTesting(m_websiteDataStore->sessionID()), WTFMove(completionHandler)); 9971 } 9972 9973 void WebPageProxy::simulateResourceLoadStatisticsSessionRestart(CompletionHandler<void()>&& completionHandler) 9974 { 9975 websiteDataStore().networkProcess().sendWithAsyncReply(Messages::NetworkProcess::SimulateResourceLoadStatisticsSessionRestart(m_websiteDataStore->sessionID()), WTFMove(completionHandler)); 9976 } 9977 9968 9978 void WebPageProxy::setPrivateClickMeasurementConversionURLForTesting(const URL& url, CompletionHandler<void()>&& completionHandler) 9969 9979 { -
trunk/Source/WebKit/UIProcess/WebPageProxy.h
r269953 r270136 1689 1689 void clearPrivateClickMeasurement(CompletionHandler<void()>&&); 1690 1690 void setPrivateClickMeasurementOverrideTimerForTesting(bool value, CompletionHandler<void()>&&); 1691 void markAttributedPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&&); 1692 void simulateResourceLoadStatisticsSessionRestart(CompletionHandler<void()>&&); 1691 1693 void setPrivateClickMeasurementConversionURLForTesting(const URL&, CompletionHandler<void()>&&); 1692 1694 void markPrivateClickMeasurementsAsExpiredForTesting(CompletionHandler<void()>&&); -
trunk/Tools/ChangeLog
r270132 r270136 1 2020-11-20 Kate Cheney <katherine_cheney@apple.com> 2 3 PCM: Persist pending ad clicks and attributions so they can survive browser restart 4 https://bugs.webkit.org/show_bug.cgi?id=219134 5 <rdar://problem/70470129> 6 7 Reviewed by John Wilander. 8 9 Add support for testing of expired ad-clicks and attributions. 10 Update names after Private Click Measurement standards discussions. 11 12 * TestWebKitAPI/Tests/WebCore/PrivateClickMeasurement.cpp: 13 (TestWebKitAPI::TEST): 14 * WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl: 15 * WebKitTestRunner/InjectedBundle/TestRunner.cpp: 16 (WTR::TestRunner::markAttributedPrivateClickMeasurementsAsExpiredForTesting): 17 (WTR::TestRunner::simulateResourceLoadStatisticsSessionRestart): 18 * WebKitTestRunner/InjectedBundle/TestRunner.h: 19 * WebKitTestRunner/TestController.cpp: 20 (WTR::TestController::markAttributedPrivateClickMeasurementsAsExpiredForTesting): 21 (WTR::TestController::simulateResourceLoadStatisticsSessionRestart): 22 * WebKitTestRunner/TestController.h: 23 * WebKitTestRunner/TestInvocation.cpp: 24 (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle): 25 1 26 2020-11-20 Geoffrey Garen <ggaren@apple.com> 2 27 -
trunk/Tools/TestWebKitAPI/Tests/WebCore/PrivateClickMeasurement.cpp
r269886 r270136 44 44 TEST(PrivateClickMeasurement, ValidMinValues) 45 45 { 46 PrivateClickMeasurement attribution { PrivateClickMeasurement:: Campaign(min6BitValue), PrivateClickMeasurement::Source { webKitURL }, PrivateClickMeasurement::Destination{ exampleURL } };47 attribution. convertAndGetEarliestTimeToSend(PrivateClickMeasurement::Conversion(min6BitValue, PrivateClickMeasurement::Priority(min6BitValue)));46 PrivateClickMeasurement attribution { PrivateClickMeasurement::SourceID(min6BitValue), PrivateClickMeasurement::SourceSite { webKitURL }, PrivateClickMeasurement::AttributeOnSite { exampleURL } }; 47 attribution.attributeAndGetEarliestTimeToSend(PrivateClickMeasurement::AttributionTriggerData(min6BitValue, PrivateClickMeasurement::Priority(min6BitValue))); 48 48 49 49 auto attributionURL = attribution.reportURL(); … … 56 56 TEST(PrivateClickMeasurement, ValidMidValues) 57 57 { 58 PrivateClickMeasurement attribution { PrivateClickMeasurement:: Campaign((uint32_t)12), PrivateClickMeasurement::Source { webKitURL }, PrivateClickMeasurement::Destination{ exampleURL } };59 attribution. convertAndGetEarliestTimeToSend(PrivateClickMeasurement::Conversion((uint32_t)44, PrivateClickMeasurement::Priority((uint32_t)22)));58 PrivateClickMeasurement attribution { PrivateClickMeasurement::SourceID((uint32_t)12), PrivateClickMeasurement::SourceSite { webKitURL }, PrivateClickMeasurement::AttributeOnSite { exampleURL } }; 59 attribution.attributeAndGetEarliestTimeToSend(PrivateClickMeasurement::AttributionTriggerData((uint32_t)44, PrivateClickMeasurement::Priority((uint32_t)22))); 60 60 61 61 auto attributionURL = attribution.reportURL(); … … 68 68 TEST(PrivateClickMeasurement, ValidMaxValues) 69 69 { 70 PrivateClickMeasurement attribution { PrivateClickMeasurement:: Campaign(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::Source { webKitURL }, PrivateClickMeasurement::Destination{ exampleURL } };71 attribution. convertAndGetEarliestTimeToSend(PrivateClickMeasurement::Conversion(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy)));70 PrivateClickMeasurement attribution { PrivateClickMeasurement::SourceID(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::SourceSite { webKitURL }, PrivateClickMeasurement::AttributeOnSite { exampleURL } }; 71 attribution.attributeAndGetEarliestTimeToSend(PrivateClickMeasurement::AttributionTriggerData(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy))); 72 72 73 73 auto attributionURL = attribution.reportURL(); … … 80 80 TEST(PrivateClickMeasurement, EarliestTimeToSendAttributionMinimumDelay) 81 81 { 82 PrivateClickMeasurement attribution { PrivateClickMeasurement:: Campaign(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::Source { webKitURL }, PrivateClickMeasurement::Destination{ exampleURL } };82 PrivateClickMeasurement attribution { PrivateClickMeasurement::SourceID(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::SourceSite { webKitURL }, PrivateClickMeasurement::AttributeOnSite { exampleURL } }; 83 83 auto now = WallTime::now(); 84 attribution. convertAndGetEarliestTimeToSend(PrivateClickMeasurement::Conversion(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy)));84 attribution.attributeAndGetEarliestTimeToSend(PrivateClickMeasurement::AttributionTriggerData(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy))); 85 85 auto earliestTimeToSend = attribution.earliestTimeToSend(); 86 86 ASSERT_TRUE(earliestTimeToSend); … … 91 91 { 92 92 const URL conversionURLWithoutPriority { { }, "https://webkit.org/.well-known/private-click-measurement/22"_s }; 93 auto optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithoutPriority);93 auto optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithoutPriority); 94 94 ASSERT_TRUE(optionalConversion); 95 95 ASSERT_EQ(optionalConversion->data, (uint32_t)22); 96 96 97 97 const URL conversionURLWithoutPriorityMaxEntropy { { }, "https://webkit.org/.well-known/private-click-measurement/63"_s }; 98 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithoutPriorityMaxEntropy);98 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithoutPriorityMaxEntropy); 99 99 ASSERT_TRUE(optionalConversion); 100 100 ASSERT_EQ(optionalConversion->data, (uint32_t)63); 101 101 102 102 const URL conversionURLWithoutPriorityAndLeadingZero { { }, "https://webkit.org/.well-known/private-click-measurement/02"_s }; 103 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithoutPriorityAndLeadingZero);103 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithoutPriorityAndLeadingZero); 104 104 ASSERT_TRUE(optionalConversion); 105 105 ASSERT_EQ(optionalConversion->data, (uint32_t)2); 106 106 107 107 const URL conversionURLWithPriority { { }, "https://webkit.org/.well-known/private-click-measurement/22/12"_s }; 108 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithPriority);108 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithPriority); 109 109 ASSERT_TRUE(optionalConversion); 110 110 ASSERT_EQ(optionalConversion->data, (uint32_t)22); … … 112 112 113 113 const URL conversionURLWithPriorityMaxEntropy { { }, "https://webkit.org/.well-known/private-click-measurement/63/63"_s }; 114 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithPriorityMaxEntropy);114 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithPriorityMaxEntropy); 115 115 ASSERT_TRUE(optionalConversion); 116 116 ASSERT_EQ(optionalConversion->data, (uint32_t)63); … … 118 118 119 119 const URL conversionURLWithPriorityAndLeadingZero { { }, "https://webkit.org/.well-known/private-click-measurement/22/02"_s }; 120 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithPriorityAndLeadingZero);120 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithPriorityAndLeadingZero); 121 121 ASSERT_TRUE(optionalConversion); 122 122 ASSERT_EQ(optionalConversion->data, (uint32_t)22); … … 128 128 TEST(PrivateClickMeasurement, InvalidCampaignId) 129 129 { 130 PrivateClickMeasurement attribution { PrivateClickMeasurement:: Campaign(PrivateClickMeasurement::MaxEntropy + 1), PrivateClickMeasurement::Source { webKitURL }, PrivateClickMeasurement::Destination{ exampleURL } };131 attribution. convertAndGetEarliestTimeToSend(PrivateClickMeasurement::Conversion(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy)));130 PrivateClickMeasurement attribution { PrivateClickMeasurement::SourceID(PrivateClickMeasurement::MaxEntropy + 1), PrivateClickMeasurement::SourceSite { webKitURL }, PrivateClickMeasurement::AttributeOnSite { exampleURL } }; 131 attribution.attributeAndGetEarliestTimeToSend(PrivateClickMeasurement::AttributionTriggerData(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy))); 132 132 133 133 ASSERT_TRUE(attribution.reportURL().isEmpty()); … … 136 136 TEST(PrivateClickMeasurement, InvalidSourceHost) 137 137 { 138 PrivateClickMeasurement attribution { PrivateClickMeasurement:: Campaign(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::Source { emptyURL }, PrivateClickMeasurement::Destination{ exampleURL } };139 attribution. convertAndGetEarliestTimeToSend(PrivateClickMeasurement::Conversion(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy)));138 PrivateClickMeasurement attribution { PrivateClickMeasurement::SourceID(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::SourceSite { emptyURL }, PrivateClickMeasurement::AttributeOnSite { exampleURL } }; 139 attribution.attributeAndGetEarliestTimeToSend(PrivateClickMeasurement::AttributionTriggerData(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy))); 140 140 141 141 ASSERT_TRUE(attribution.reportURL().isEmpty()); … … 144 144 TEST(PrivateClickMeasurement, InvalidDestinationHost) 145 145 { 146 PrivateClickMeasurement attribution { PrivateClickMeasurement:: Campaign(PrivateClickMeasurement::MaxEntropy + 1), PrivateClickMeasurement::Source { webKitURL }, PrivateClickMeasurement::Destination{ emptyURL } };147 attribution. convertAndGetEarliestTimeToSend(PrivateClickMeasurement::Conversion(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy)));146 PrivateClickMeasurement attribution { PrivateClickMeasurement::SourceID(PrivateClickMeasurement::MaxEntropy + 1), PrivateClickMeasurement::SourceSite { webKitURL }, PrivateClickMeasurement::AttributeOnSite { emptyURL } }; 147 attribution.attributeAndGetEarliestTimeToSend(PrivateClickMeasurement::AttributionTriggerData(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy))); 148 148 149 149 ASSERT_TRUE(attribution.reportURL().isEmpty()); … … 152 152 TEST(PrivateClickMeasurement, InvalidConversionData) 153 153 { 154 PrivateClickMeasurement attribution { PrivateClickMeasurement:: Campaign(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::Source { webKitURL }, PrivateClickMeasurement::Destination{ exampleURL } };155 attribution. convertAndGetEarliestTimeToSend(PrivateClickMeasurement::Conversion((PrivateClickMeasurement::MaxEntropy + 1), PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy)));154 PrivateClickMeasurement attribution { PrivateClickMeasurement::SourceID(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::SourceSite { webKitURL }, PrivateClickMeasurement::AttributeOnSite { exampleURL } }; 155 attribution.attributeAndGetEarliestTimeToSend(PrivateClickMeasurement::AttributionTriggerData((PrivateClickMeasurement::MaxEntropy + 1), PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy))); 156 156 157 157 ASSERT_TRUE(attribution.reportURL().isEmpty()); … … 160 160 TEST(PrivateClickMeasurement, InvalidPriority) 161 161 { 162 PrivateClickMeasurement attribution { PrivateClickMeasurement:: Campaign(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::Source { webKitURL }, PrivateClickMeasurement::Destination{ exampleURL } };163 attribution. convertAndGetEarliestTimeToSend(PrivateClickMeasurement::Conversion(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy + 1)));162 PrivateClickMeasurement attribution { PrivateClickMeasurement::SourceID(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::SourceSite { webKitURL }, PrivateClickMeasurement::AttributeOnSite { exampleURL } }; 163 attribution.attributeAndGetEarliestTimeToSend(PrivateClickMeasurement::AttributionTriggerData(PrivateClickMeasurement::MaxEntropy, PrivateClickMeasurement::Priority(PrivateClickMeasurement::MaxEntropy + 1))); 164 164 165 165 ASSERT_TRUE(attribution.reportURL().isEmpty()); … … 168 168 TEST(PrivateClickMeasurement, InvalidMissingConversion) 169 169 { 170 PrivateClickMeasurement attribution { PrivateClickMeasurement:: Campaign(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::Source { webKitURL }, PrivateClickMeasurement::Destination{ exampleURL } };170 PrivateClickMeasurement attribution { PrivateClickMeasurement::SourceID(PrivateClickMeasurement::MaxEntropy), PrivateClickMeasurement::SourceSite { webKitURL }, PrivateClickMeasurement::AttributeOnSite { exampleURL } }; 171 171 172 172 ASSERT_TRUE(attribution.reportURL().isEmpty()); … … 177 177 { 178 178 const URL conversionURLWithSingleDigitConversionData { { }, "https://webkit.org/.well-known/private-click-measurement/2"_s }; 179 auto optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithSingleDigitConversionData);179 auto optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithSingleDigitConversionData); 180 180 ASSERT_FALSE(optionalConversion); 181 181 182 182 const URL conversionURLWithNonNumeralConversionData { { }, "https://webkit.org/.well-known/private-click-measurement/2s"_s }; 183 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithNonNumeralConversionData);183 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithNonNumeralConversionData); 184 184 ASSERT_FALSE(optionalConversion); 185 185 186 186 const URL conversionURLWithNegativeConversionData { { }, "https://webkit.org/.well-known/private-click-measurement/-2"_s }; 187 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithNegativeConversionData);187 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithNegativeConversionData); 188 188 ASSERT_FALSE(optionalConversion); 189 189 190 190 const URL conversionURLWithTooLargeConversionData { { }, "https://webkit.org/.well-known/private-click-measurement/64"_s }; 191 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithTooLargeConversionData);191 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithTooLargeConversionData); 192 192 ASSERT_FALSE(optionalConversion); 193 193 194 194 const URL conversionURLWithSingleDigitPriority { { }, "https://webkit.org/.well-known/private-click-measurement/22/2"_s }; 195 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithSingleDigitPriority);195 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithSingleDigitPriority); 196 196 ASSERT_FALSE(optionalConversion); 197 197 198 198 const URL conversionURLWithNonNumeralPriority { { }, "https://webkit.org/.well-known/private-click-measurement/22/2s"_s }; 199 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithNonNumeralPriority);199 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithNonNumeralPriority); 200 200 ASSERT_FALSE(optionalConversion); 201 201 202 202 const URL conversionURLWithNegativePriority { { }, "https://webkit.org/.well-known/private-click-measurement/22/-2"_s }; 203 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithNegativePriority);203 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithNegativePriority); 204 204 ASSERT_FALSE(optionalConversion); 205 205 206 206 const URL conversionURLWithTooLargePriority { { }, "https://webkit.org/.well-known/private-click-measurement/22/64"_s }; 207 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithTooLargePriority);207 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithTooLargePriority); 208 208 ASSERT_FALSE(optionalConversion); 209 209 210 210 const URL conversionURLWithTooLargeConversionDataAndPriority { { }, "https://webkit.org/.well-known/private-click-measurement/64/22"_s }; 211 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithTooLargeConversionDataAndPriority);211 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithTooLargeConversionDataAndPriority); 212 212 ASSERT_FALSE(optionalConversion); 213 213 214 214 const URL conversionURLWithTooLargeConversionDataAndTooLargePriority { { }, "https://webkit.org/.well-known/private-click-measurement/64/64"_s }; 215 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithTooLargeConversionDataAndTooLargePriority);215 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithTooLargeConversionDataAndTooLargePriority); 216 216 ASSERT_FALSE(optionalConversion); 217 217 218 218 const URL conversionURLWithExtraLeadingSlash = { { }, "https://webkit.org/.well-known/private-click-measurement//22/12"_s }; 219 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithExtraLeadingSlash);219 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithExtraLeadingSlash); 220 220 ASSERT_FALSE(optionalConversion); 221 221 222 222 const URL conversionURLWithExtraTrailingSlash = { { }, "https://webkit.org/.well-known/private-click-measurement/22/12/"_s }; 223 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithExtraTrailingSlash);223 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithExtraTrailingSlash); 224 224 ASSERT_FALSE(optionalConversion); 225 225 226 226 const URL conversionURLWithTrailingQuestionMark = { { }, "https://webkit.org/.well-known/private-click-measurement/22/12?"_s }; 227 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithTrailingQuestionMark);227 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithTrailingQuestionMark); 228 228 ASSERT_FALSE(optionalConversion); 229 229 } … … 233 233 // Protocol. 234 234 const URL conversionURLWithHttpProtocol { { }, "http://webkit.org/.well-known/private-click-measurement/2"_s }; 235 auto optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithHttpProtocol);235 auto optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithHttpProtocol); 236 236 ASSERT_FALSE(optionalConversion); 237 237 238 238 const URL conversionURLWithWssProtocol { { }, "wss://webkit.org/.well-known/private-click-measurement/2"_s }; 239 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithWssProtocol);239 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithWssProtocol); 240 240 ASSERT_FALSE(optionalConversion); 241 241 242 242 const URL conversionURLWithFileProtocol { { }, "file:///.well-known/private-click-measurement/2"_s }; 243 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithFileProtocol);243 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithFileProtocol); 244 244 ASSERT_FALSE(optionalConversion); 245 245 246 246 // Username and password. 247 247 const URL conversionURLWithUserName { { }, "https://user@webkit.org/.well-known/private-click-measurement/2"_s }; 248 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithUserName);248 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithUserName); 249 249 ASSERT_FALSE(optionalConversion); 250 250 251 251 const URL conversionURLWithPassword = { { }, "https://:pwd@webkit.org/.well-known/private-click-measurement/22/12?"_s }; 252 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithPassword);252 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithPassword); 253 253 ASSERT_FALSE(optionalConversion); 254 254 255 255 const URL conversionURLWithUsernameAndPassword = { { }, "https://user:pwd@webkit.org/.well-known/private-click-measurement/22/12?"_s }; 256 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithUsernameAndPassword);256 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithUsernameAndPassword); 257 257 ASSERT_FALSE(optionalConversion); 258 258 259 259 // Query string. 260 260 const URL conversionURLWithTrailingQuestionMark = { { }, "https://webkit.org/.well-known/private-click-measurement/22/12?"_s }; 261 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithTrailingQuestionMark);261 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithTrailingQuestionMark); 262 262 ASSERT_FALSE(optionalConversion); 263 263 264 264 const URL conversionURLWithQueryString = { { }, "https://webkit.org/.well-known/private-click-measurement/22/12?extra=data"_s }; 265 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithQueryString);265 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithQueryString); 266 266 ASSERT_FALSE(optionalConversion); 267 267 268 268 // Fragment. 269 269 const URL conversionURLWithTrailingHash = { { }, "https://webkit.org/.well-known/private-click-measurement/22/12#"_s }; 270 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithTrailingHash);270 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithTrailingHash); 271 271 ASSERT_FALSE(optionalConversion); 272 272 273 273 const URL conversionURLWithFragment = { { }, "https://webkit.org/.well-known/private-click-measurement/22/12#fragment"_s }; 274 optionalConversion = PrivateClickMeasurement::parse ConversionRequest(conversionURLWithFragment);274 optionalConversion = PrivateClickMeasurement::parseAttributionRequest(conversionURLWithFragment); 275 275 ASSERT_FALSE(optionalConversion); 276 276 } -
trunk/Tools/WebKitTestRunner/InjectedBundle/Bindings/TestRunner.idl
r269810 r270136 402 402 undefined clearPrivateClickMeasurementsThroughWebsiteDataRemoval(); 403 403 undefined setPrivateClickMeasurementOverrideTimerForTesting(boolean value); 404 undefined markAttributedPrivateClickMeasurementsAsExpiredForTesting(); 405 undefined simulateResourceLoadStatisticsSessionRestart(); 404 406 undefined setPrivateClickMeasurementConversionURLForTesting(DOMString url); 405 407 undefined markPrivateClickMeasurementsAsExpiredForTesting(); -
trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.cpp
r269810 r270136 2016 2016 } 2017 2017 2018 void TestRunner::markAttributedPrivateClickMeasurementsAsExpiredForTesting() 2019 { 2020 postSynchronousPageMessage("MarkAttributedPrivateClickMeasurementsAsExpiredForTesting"); 2021 } 2022 2023 void TestRunner::simulateResourceLoadStatisticsSessionRestart() 2024 { 2025 postSynchronousPageMessage("SimulateResourceLoadStatisticsSessionRestart"); 2026 } 2027 2018 2028 void TestRunner::setPrivateClickMeasurementConversionURLForTesting(JSStringRef urlString) 2019 2029 { -
trunk/Tools/WebKitTestRunner/InjectedBundle/TestRunner.h
r269810 r270136 515 515 void setPrivateClickMeasurementConversionURLForTesting(JSStringRef); 516 516 void markPrivateClickMeasurementsAsExpiredForTesting(); 517 void markAttributedPrivateClickMeasurementsAsExpiredForTesting(); 518 void simulateResourceLoadStatisticsSessionRestart(); 517 519 518 520 void setIsSpeechRecognitionPermissionGranted(bool); -
trunk/Tools/WebKitTestRunner/TestController.cpp
r269810 r270136 3593 3593 } 3594 3594 3595 void TestController::markAttributedPrivateClickMeasurementsAsExpiredForTesting() 3596 { 3597 PrivateClickMeasurementVoidCallbackContext callbackContext(*this); 3598 WKPageMarkAttributedPrivateClickMeasurementsAsExpiredForTesting(m_mainWebView->page(), privateClickMeasurementVoidCallback, &callbackContext); 3599 runUntil(callbackContext.done, noTimeout); 3600 } 3601 3602 void TestController::simulateResourceLoadStatisticsSessionRestart() 3603 { 3604 PrivateClickMeasurementVoidCallbackContext callbackContext(*this); 3605 WKPageSimulateResourceLoadStatisticsSessionRestart(m_mainWebView->page(), privateClickMeasurementVoidCallback, &callbackContext); 3606 runUntil(callbackContext.done, noTimeout); 3607 } 3608 3595 3609 void TestController::setPrivateClickMeasurementConversionURLForTesting(WKURLRef url) 3596 3610 { -
trunk/Tools/WebKitTestRunner/TestController.h
r269810 r270136 345 345 void clearPrivateClickMeasurementsThroughWebsiteDataRemoval(); 346 346 void setPrivateClickMeasurementOverrideTimerForTesting(bool value); 347 void markAttributedPrivateClickMeasurementsAsExpiredForTesting(); 348 void simulateResourceLoadStatisticsSessionRestart(); 347 349 void setPrivateClickMeasurementConversionURLForTesting(WKURLRef); 348 350 void markPrivateClickMeasurementsAsExpiredForTesting(); -
trunk/Tools/WebKitTestRunner/TestInvocation.cpp
r269810 r270136 1330 1330 } 1331 1331 1332 if (WKStringIsEqualToUTF8CString(messageName, "MarkAttributedPrivateClickMeasurementsAsExpiredForTesting")) { 1333 TestController::singleton().markAttributedPrivateClickMeasurementsAsExpiredForTesting(); 1334 return nullptr; 1335 } 1336 1337 if (WKStringIsEqualToUTF8CString(messageName, "SimulateResourceLoadStatisticsSessionRestart")) { 1338 TestController::singleton().simulateResourceLoadStatisticsSessionRestart(); 1339 return nullptr; 1340 } 1341 1332 1342 if (WKStringIsEqualToUTF8CString(messageName, "SetPrivateClickMeasurementConversionURLForTesting")) { 1333 1343 ASSERT(WKGetTypeID(messageBody) == WKURLGetTypeID());
Note: See TracChangeset
for help on using the changeset viewer.