Changeset 249603 in webkit
- Timestamp:
- Sep 6, 2019 6:53:20 PM (5 years ago)
- Location:
- trunk/Source
- Files:
-
- 1 added
- 11 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r249601 r249603 1 2019-09-06 Chris Dumez <cdumez@apple.com> 2 3 Move the ResourceLoadObserver logic to WebKit2 4 https://bugs.webkit.org/show_bug.cgi?id=201517 5 6 Reviewed by Brent Fulgham. 7 8 Move the ResourceLoadObserver logic to WebKit2 since it is not used by WebKit1. This allows us to simplify 9 code. 10 11 In a follow-up patch, I will simplify the code even further by leveraging the fact that a WebContent process 12 is always associated with a single WebsiteDataStore / sessionID: 13 - No need for a HashMap of sessionIDs 14 - No need to even allocate the ResourceLoadObserver if the WebProcess is associated with an ephemeral session. 15 16 * dom/Document.h: 17 * loader/ResourceLoadObserver.cpp: 18 (WebCore::sharedObserver): 19 (WebCore::ResourceLoadObserver::setShared): 20 (WebCore::ResourceLoadObserver::shared): 21 * loader/ResourceLoadObserver.h: 22 (WebCore::ResourceLoadObserver::~ResourceLoadObserver): 23 (WebCore::ResourceLoadObserver::logSubresourceLoading): 24 (WebCore::ResourceLoadObserver::logWebSocketLoading): 25 (WebCore::ResourceLoadObserver::logUserInteractionWithReducedTimeResolution): 26 (WebCore::ResourceLoadObserver::logFontLoad): 27 (WebCore::ResourceLoadObserver::logCanvasRead): 28 (WebCore::ResourceLoadObserver::logCanvasWriteOrMeasure): 29 (WebCore::ResourceLoadObserver::logNavigatorAPIAccessed): 30 (WebCore::ResourceLoadObserver::logScreenAPIAccessed): 31 (WebCore::ResourceLoadObserver::statisticsForURL): 32 (WebCore::ResourceLoadObserver::updateCentralStatisticsStore): 33 (WebCore::ResourceLoadObserver::clearState): 34 (WebCore::ResourceLoadObserver::setShouldLogUserInteraction): 35 * page/DeprecatedGlobalSettings.h: 36 1 37 2019-09-06 Justin Fan <justin_fan@apple.com> 2 38 -
trunk/Source/WebCore/dom/Document.h
r249378 r249603 1492 1492 1493 1493 #if ENABLE(RESOURCE_LOAD_STATISTICS) 1494 bool hasRequestedPageSpecificStorageAccessWithUserInteraction(const RegistrableDomain&);1495 void setHasRequestedPageSpecificStorageAccessWithUserInteraction(const RegistrableDomain&);1494 WEBCORE_EXPORT bool hasRequestedPageSpecificStorageAccessWithUserInteraction(const RegistrableDomain&); 1495 WEBCORE_EXPORT void setHasRequestedPageSpecificStorageAccessWithUserInteraction(const RegistrableDomain&); 1496 1496 WEBCORE_EXPORT void wasLoadedWithDataTransferFromPrevalentResource(); 1497 1497 void downgradeReferrerToRegistrableDomain(); -
trunk/Source/WebCore/loader/ResourceLoadObserver.cpp
r249126 r249603 27 27 #include "ResourceLoadObserver.h" 28 28 29 #include "DeprecatedGlobalSettings.h"30 #include "Document.h"31 #include "Frame.h"32 #include "FrameLoader.h"33 #include "FrameLoaderClient.h"34 #include "HTMLFrameOwnerElement.h"35 #include "Logging.h"36 #include "Page.h"37 #include "RegistrableDomain.h"38 #include "ResourceLoadStatistics.h"39 #include "ResourceRequest.h"40 #include "ResourceResponse.h"41 #include "RuntimeEnabledFeatures.h"42 #include "ScriptExecutionContext.h"43 #include "SecurityOrigin.h"44 #include "Settings.h"45 #include <wtf/URL.h>46 47 29 namespace WebCore { 48 30 49 static const Seconds minimumNotificationInterval { 5_s }; 31 static ResourceLoadObserver*& sharedObserver() 32 { 33 static ResourceLoadObserver* observer = nullptr; 34 return observer; 35 } 50 36 51 ResourceLoadObserver::ResourceLoadObserver() 52 : m_notificationTimer(*this, &ResourceLoadObserver::updateCentralStatisticsStore) 37 void ResourceLoadObserver::setShared(ResourceLoadObserver& observer) 53 38 { 39 RELEASE_ASSERT(!sharedObserver()); 40 sharedObserver() = &observer; 54 41 } 55 42 56 43 ResourceLoadObserver& ResourceLoadObserver::shared() 57 44 { 58 static NeverDestroyed<ResourceLoadObserver> resourceLoadObserver; 59 return resourceLoadObserver; 60 } 61 62 void ResourceLoadObserver::setStatisticsUpdatedCallback(Function<void(PerSessionResourceLoadData&&)>&& notificationCallback) 63 { 64 ASSERT(!m_notificationCallback); 65 m_notificationCallback = WTFMove(notificationCallback); 66 } 67 68 void ResourceLoadObserver::setRequestStorageAccessUnderOpenerCallback(Function<void(PAL::SessionID sessionID, const RegistrableDomain& domainInNeedOfStorageAccess, PageIdentifier openerPageID, const RegistrableDomain& openerDomain)>&& callback) 69 { 70 ASSERT(!m_requestStorageAccessUnderOpenerCallback); 71 m_requestStorageAccessUnderOpenerCallback = WTFMove(callback); 72 } 73 74 void ResourceLoadObserver::setLogUserInteractionNotificationCallback(Function<void(PAL::SessionID, const RegistrableDomain&)>&& callback) 75 { 76 ASSERT(!m_logUserInteractionNotificationCallback); 77 m_logUserInteractionNotificationCallback = WTFMove(callback); 78 } 79 80 static inline bool is3xxRedirect(const ResourceResponse& response) 81 { 82 return response.httpStatusCode() >= 300 && response.httpStatusCode() <= 399; 83 } 84 85 bool ResourceLoadObserver::shouldLog(PAL::SessionID sessionID) const 86 { 87 return DeprecatedGlobalSettings::resourceLoadStatisticsEnabled() && !sessionID.isEphemeral() && m_notificationCallback; 88 } 89 90 void ResourceLoadObserver::logSubresourceLoading(const Frame* frame, const ResourceRequest& newRequest, const ResourceResponse& redirectResponse) 91 { 92 ASSERT(frame->page()); 93 94 if (!frame) 95 return; 96 97 auto* page = frame->page(); 98 if (!page || !shouldLog(page->sessionID())) 99 return; 100 101 bool isRedirect = is3xxRedirect(redirectResponse); 102 const URL& redirectedFromURL = redirectResponse.url(); 103 const URL& targetURL = newRequest.url(); 104 const URL& topFrameURL = frame ? frame->mainFrame().document()->url() : URL(); 105 106 auto targetHost = targetURL.host(); 107 auto topFrameHost = topFrameURL.host(); 108 109 if (targetHost.isEmpty() || topFrameHost.isEmpty() || targetHost == topFrameHost || (isRedirect && targetHost == redirectedFromURL.host())) 110 return; 111 112 RegistrableDomain targetDomain { targetURL }; 113 RegistrableDomain topFrameDomain { topFrameURL }; 114 RegistrableDomain redirectedFromDomain { redirectedFromURL }; 115 116 if (targetDomain == topFrameDomain || (isRedirect && targetDomain == redirectedFromDomain)) 117 return; 118 119 { 120 auto& targetStatistics = ensureResourceStatisticsForRegistrableDomain(page->sessionID(), targetDomain); 121 auto lastSeen = ResourceLoadStatistics::reduceTimeResolution(WallTime::now()); 122 targetStatistics.lastSeen = lastSeen; 123 targetStatistics.subresourceUnderTopFrameDomains.add(topFrameDomain); 124 125 scheduleNotificationIfNeeded(); 126 } 127 128 if (isRedirect) { 129 auto& redirectingOriginStatistics = ensureResourceStatisticsForRegistrableDomain(page->sessionID(), redirectedFromDomain); 130 redirectingOriginStatistics.subresourceUniqueRedirectsTo.add(targetDomain); 131 auto& targetStatistics = ensureResourceStatisticsForRegistrableDomain(page->sessionID(), targetDomain); 132 targetStatistics.subresourceUniqueRedirectsFrom.add(redirectedFromDomain); 133 134 scheduleNotificationIfNeeded(); 135 } 136 } 137 138 void ResourceLoadObserver::logWebSocketLoading(const URL& targetURL, const URL& mainFrameURL, PAL::SessionID sessionID) 139 { 140 if (!shouldLog(sessionID)) 141 return; 142 143 auto targetHost = targetURL.host(); 144 auto mainFrameHost = mainFrameURL.host(); 145 146 if (targetHost.isEmpty() || mainFrameHost.isEmpty() || targetHost == mainFrameHost) 147 return; 148 149 RegistrableDomain targetDomain { targetURL }; 150 RegistrableDomain topFrameDomain { mainFrameURL }; 151 152 if (targetDomain == topFrameDomain) 153 return; 154 155 auto lastSeen = ResourceLoadStatistics::reduceTimeResolution(WallTime::now()); 156 157 auto& targetStatistics = ensureResourceStatisticsForRegistrableDomain(sessionID, targetDomain); 158 targetStatistics.lastSeen = lastSeen; 159 targetStatistics.subresourceUnderTopFrameDomains.add(topFrameDomain); 160 161 scheduleNotificationIfNeeded(); 162 } 163 164 void ResourceLoadObserver::logUserInteractionWithReducedTimeResolution(const Document& document) 165 { 166 if (!document.sessionID().isValid() || !shouldLog(document.sessionID())) 167 return; 168 169 auto& url = document.url(); 170 if (url.protocolIsAbout() || url.isLocalFile() || url.isEmpty()) 171 return; 172 173 RegistrableDomain topFrameDomain { url }; 174 auto newTime = ResourceLoadStatistics::reduceTimeResolution(WallTime::now()); 175 auto lastReportedUserInteraction = m_lastReportedUserInteractionMap.get(topFrameDomain); 176 if (newTime == lastReportedUserInteraction) 177 return; 178 179 m_lastReportedUserInteractionMap.set(topFrameDomain, newTime); 180 181 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID(), topFrameDomain); 182 statistics.hadUserInteraction = true; 183 statistics.lastSeen = newTime; 184 statistics.mostRecentUserInteractionTime = newTime; 185 186 #if ENABLE(RESOURCE_LOAD_STATISTICS) 187 if (auto* frame = document.frame()) { 188 if (auto* opener = frame->loader().opener()) { 189 if (auto* openerDocument = opener->document()) { 190 if (auto* openerFrame = openerDocument->frame()) { 191 if (auto openerPageID = openerFrame->loader().client().pageID()) 192 requestStorageAccessUnderOpener(document.sessionID(), topFrameDomain, openerPageID.value(), *openerDocument); 193 } 194 } 195 } 196 } 197 198 // We notify right away in case of a user interaction instead of waiting the usual 5 seconds because we want 199 // to update cookie blocking state as quickly as possible. 200 m_logUserInteractionNotificationCallback(document.sessionID(), topFrameDomain); 201 #endif 202 203 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED 204 if (shouldLogUserInteraction()) { 205 auto counter = ++m_loggingCounter; 206 #define LOCAL_LOG(str, ...) \ 207 RELEASE_LOG(ResourceLoadStatistics, "ResourceLoadObserver::logUserInteraction: counter = %" PRIu64 ": " str, counter, ##__VA_ARGS__) 208 209 auto escapeForJSON = [](String s) { 210 s.replace('\\', "\\\\").replace('"', "\\\""); 211 return s; 212 }; 213 auto escapedURL = escapeForJSON(url.string()); 214 auto escapedDomain = escapeForJSON(topFrameDomain.string()); 215 216 LOCAL_LOG(R"({ "url": "%{public}s",)", escapedURL.utf8().data()); 217 LOCAL_LOG(R"( "domain" : "%{public}s",)", escapedDomain.utf8().data()); 218 LOCAL_LOG(R"( "until" : %f })", newTime.secondsSinceEpoch().seconds()); 219 220 #undef LOCAL_LOG 221 } 222 #endif 223 } 224 225 #if ENABLE(RESOURCE_LOAD_STATISTICS) 226 void ResourceLoadObserver::requestStorageAccessUnderOpener(PAL::SessionID sessionID, const RegistrableDomain& domainInNeedOfStorageAccess, PageIdentifier openerPageID, Document& openerDocument) 227 { 228 auto openerUrl = openerDocument.url(); 229 RegistrableDomain openerDomain { openerUrl }; 230 if (domainInNeedOfStorageAccess != openerDomain 231 && !openerDocument.hasRequestedPageSpecificStorageAccessWithUserInteraction(domainInNeedOfStorageAccess) 232 && !equalIgnoringASCIICase(openerUrl.string(), WTF::blankURL())) { 233 m_requestStorageAccessUnderOpenerCallback(sessionID, domainInNeedOfStorageAccess, openerPageID, openerDomain); 234 // Remember user interaction-based requests since they don't need to be repeated. 235 openerDocument.setHasRequestedPageSpecificStorageAccessWithUserInteraction(domainInNeedOfStorageAccess); 236 } 237 } 238 #endif 239 240 void ResourceLoadObserver::logFontLoad(const Document& document, const String& familyName, bool loadStatus) 241 { 242 #if ENABLE(WEB_API_STATISTICS) 243 if (!shouldLog(document.sessionID())) 244 return; 245 RegistrableDomain registrableDomain { document.url() }; 246 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 247 bool shouldCallNotificationCallback = false; 248 if (!loadStatus) { 249 if (statistics.fontsFailedToLoad.add(familyName).isNewEntry) 250 shouldCallNotificationCallback = true; 251 } else { 252 if (statistics.fontsSuccessfullyLoaded.add(familyName).isNewEntry) 253 shouldCallNotificationCallback = true; 254 } 255 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 256 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 257 shouldCallNotificationCallback = true; 258 if (shouldCallNotificationCallback) 259 scheduleNotificationIfNeeded(); 260 #else 261 UNUSED_PARAM(document); 262 UNUSED_PARAM(familyName); 263 UNUSED_PARAM(loadStatus); 264 #endif 265 } 266 267 void ResourceLoadObserver::logCanvasRead(const Document& document) 268 { 269 #if ENABLE(WEB_API_STATISTICS) 270 if (!shouldLog(document.sessionID())) 271 return; 272 RegistrableDomain registrableDomain { document.url() }; 273 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID(), registrableDomain); 274 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 275 statistics.canvasActivityRecord.wasDataRead = true; 276 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 277 scheduleNotificationIfNeeded(); 278 #else 279 UNUSED_PARAM(document); 280 #endif 281 } 282 283 void ResourceLoadObserver::logCanvasWriteOrMeasure(const Document& document, const String& textWritten) 284 { 285 #if ENABLE(WEB_API_STATISTICS) 286 if (!shouldLog(document.sessionID())) 287 return; 288 RegistrableDomain registrableDomain { document.url() }; 289 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 290 bool shouldCallNotificationCallback = false; 291 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 292 if (statistics.canvasActivityRecord.recordWrittenOrMeasuredText(textWritten)) 293 shouldCallNotificationCallback = true; 294 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 295 shouldCallNotificationCallback = true; 296 if (shouldCallNotificationCallback) 297 scheduleNotificationIfNeeded(); 298 #else 299 UNUSED_PARAM(document); 300 UNUSED_PARAM(textWritten); 301 #endif 302 } 303 304 void ResourceLoadObserver::logNavigatorAPIAccessed(const Document& document, const ResourceLoadStatistics::NavigatorAPI functionName) 305 { 306 #if ENABLE(WEB_API_STATISTICS) 307 if (!shouldLog(document.sessionID())) 308 return; 309 RegistrableDomain registrableDomain { document.url() }; 310 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 311 bool shouldCallNotificationCallback = false; 312 if (!statistics.navigatorFunctionsAccessed.contains(functionName)) { 313 statistics.navigatorFunctionsAccessed.add(functionName); 314 shouldCallNotificationCallback = true; 315 } 316 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 317 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 318 shouldCallNotificationCallback = true; 319 if (shouldCallNotificationCallback) 320 scheduleNotificationIfNeeded(); 321 #else 322 UNUSED_PARAM(document); 323 UNUSED_PARAM(functionName); 324 #endif 325 } 326 327 void ResourceLoadObserver::logScreenAPIAccessed(const Document& document, const ResourceLoadStatistics::ScreenAPI functionName) 328 { 329 #if ENABLE(WEB_API_STATISTICS) 330 if (!shouldLog(document.sessionID())) 331 return; 332 RegistrableDomain registrableDomain { document.url() }; 333 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 334 bool shouldCallNotificationCallback = false; 335 if (!statistics.screenFunctionsAccessed.contains(functionName)) { 336 statistics.screenFunctionsAccessed.add(functionName); 337 shouldCallNotificationCallback = true; 338 } 339 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 340 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 341 shouldCallNotificationCallback = true; 342 if (shouldCallNotificationCallback) 343 scheduleNotificationIfNeeded(); 344 #else 345 UNUSED_PARAM(document); 346 UNUSED_PARAM(functionName); 347 #endif 348 } 349 350 ResourceLoadStatistics& ResourceLoadObserver::ensureResourceStatisticsForRegistrableDomain(PAL::SessionID sessionID, const RegistrableDomain& domain) 351 { 352 auto addResult = m_perSessionResourceStatisticsMap.ensure(sessionID, [] { 353 return makeUnique<HashMap<RegistrableDomain, ResourceLoadStatistics>>(); 354 }); 355 356 auto addDomainResult = addResult.iterator->value->ensure(domain, [&domain] { 357 return ResourceLoadStatistics(domain); 358 }); 359 return addDomainResult.iterator->value; 360 } 361 362 void ResourceLoadObserver::scheduleNotificationIfNeeded() 363 { 364 ASSERT(m_notificationCallback); 365 if (m_perSessionResourceStatisticsMap.isEmpty()) { 366 m_notificationTimer.stop(); 367 return; 368 } 369 370 if (!m_notificationTimer.isActive()) 371 m_notificationTimer.startOneShot(minimumNotificationInterval); 372 } 373 374 void ResourceLoadObserver::updateCentralStatisticsStore() 375 { 376 ASSERT(m_notificationCallback); 377 m_notificationTimer.stop(); 378 m_notificationCallback(takeStatistics()); 379 } 380 381 String ResourceLoadObserver::statisticsForURL(PAL::SessionID sessionID, const URL& url) 382 { 383 auto* resourceStatisticsByDomain = m_perSessionResourceStatisticsMap.get(sessionID); 384 if (!resourceStatisticsByDomain) 385 return emptyString(); 386 387 auto iter = resourceStatisticsByDomain->find(RegistrableDomain { url }); 388 if (iter == resourceStatisticsByDomain->end()) 389 return emptyString(); 390 391 return makeString("Statistics for ", url.host().toString(), ":\n", iter->value.toString()); 392 } 393 394 auto ResourceLoadObserver::takeStatistics() -> PerSessionResourceLoadData 395 { 396 PerSessionResourceLoadData perSessionStatistics; 397 398 for (auto& iter : m_perSessionResourceStatisticsMap) { 399 Vector<ResourceLoadStatistics> statistics; 400 statistics.reserveInitialCapacity(iter.value->size()); 401 402 for (auto& statistic : iter.value->values()) 403 statistics.uncheckedAppend(WTFMove(statistic)); 404 405 perSessionStatistics.append(std::make_pair(iter.key, WTFMove(statistics))); 406 } 407 408 m_perSessionResourceStatisticsMap.clear(); 409 return perSessionStatistics; 410 } 411 412 void ResourceLoadObserver::clearState() 413 { 414 m_notificationTimer.stop(); 415 m_perSessionResourceStatisticsMap.clear(); 416 m_lastReportedUserInteractionMap.clear(); 417 } 418 419 URL ResourceLoadObserver::nonNullOwnerURL(const Document& document) const 420 { 421 auto url = document.url(); 422 auto* frame = document.frame(); 423 auto host = document.url().host(); 424 425 while ((host.isNull() || host.isEmpty()) && frame && !frame->isMainFrame()) { 426 auto* ownerElement = frame->ownerElement(); 427 428 ASSERT(ownerElement != nullptr); 429 430 auto& doc = ownerElement->document(); 431 frame = doc.frame(); 432 url = doc.url(); 433 host = url.host(); 434 } 435 436 return url; 45 if (!sharedObserver()) 46 sharedObserver() = new ResourceLoadObserver; 47 return *sharedObserver(); 437 48 } 438 49 -
trunk/Source/WebCore/loader/ResourceLoadObserver.h
r249223 r249603 26 26 #pragma once 27 27 28 #include "CanvasActivityRecord.h"29 #include "PageIdentifier.h"30 28 #include "ResourceLoadStatistics.h" 31 #include "Timer.h"32 29 #include <pal/SessionID.h> 33 #include <wtf/HashMap.h> 34 #include <wtf/HashSet.h> 35 #include <wtf/NeverDestroyed.h> 36 #include <wtf/text/WTFString.h> 37 38 namespace WTF { 39 class Lock; 40 class WorkQueue; 41 class WallTime; 42 } 30 #include <wtf/Forward.h> 43 31 44 32 namespace WebCore { … … 46 34 class Document; 47 35 class Frame; 48 class Page;49 class RegistrableDomain;50 36 class ResourceRequest; 51 37 class ResourceResponse; 52 class ScriptExecutionContext;53 54 struct ResourceLoadStatistics;55 38 56 39 class ResourceLoadObserver { 57 friend class WTF::NeverDestroyed<ResourceLoadObserver>;40 WTF_MAKE_FAST_ALLOCATED; 58 41 public: 59 using PerSessionResourceLoadData = Vector<std::pair<PAL::SessionID, Vector<ResourceLoadStatistics>>>;60 42 WEBCORE_EXPORT static ResourceLoadObserver& shared(); 43 WEBCORE_EXPORT static void setShared(ResourceLoadObserver&); 44 45 virtual ~ResourceLoadObserver() { } 61 46 62 void logSubresourceLoading(const Frame*, const ResourceRequest& newRequest, const ResourceResponse& redirectResponse); 63 void logWebSocketLoading(const URL& targetURL, const URL& mainFrameURL, PAL::SessionID); 64 void logUserInteractionWithReducedTimeResolution(const Document&); 47 virtual void logSubresourceLoading(const Frame*, const ResourceRequest& /* newRequest */, const ResourceResponse& /* redirectResponse */) { } 48 virtual void logWebSocketLoading(const URL& /* targetURL */, const URL& /* mainFrameURL */, PAL::SessionID) { } 49 virtual void logUserInteractionWithReducedTimeResolution(const Document&) { } 50 virtual void logFontLoad(const Document&, const String& /* familyName */, bool /* loadStatus */) { } 51 virtual void logCanvasRead(const Document&) { } 52 virtual void logCanvasWriteOrMeasure(const Document&, const String& /* textWritten */) { } 53 virtual void logNavigatorAPIAccessed(const Document&, const ResourceLoadStatistics::NavigatorAPI) { } 54 virtual void logScreenAPIAccessed(const Document&, const ResourceLoadStatistics::ScreenAPI) { } 55 56 virtual String statisticsForURL(PAL::SessionID, const URL&) { return { }; } 57 virtual void updateCentralStatisticsStore() { } 58 virtual void clearState() { } 65 59 66 void logFontLoad(const Document&, const String& familyName, bool loadStatus);67 void logCanvasRead(const Document&);68 void logCanvasWriteOrMeasure(const Document&, const String& textWritten);69 void logNavigatorAPIAccessed(const Document&, const ResourceLoadStatistics::NavigatorAPI);70 void logScreenAPIAccessed(const Document&, const ResourceLoadStatistics::ScreenAPI);71 72 WEBCORE_EXPORT String statisticsForURL(PAL::SessionID, const URL&);73 74 WEBCORE_EXPORT void setStatisticsUpdatedCallback(Function<void(PerSessionResourceLoadData&&)>&&);75 WEBCORE_EXPORT void setRequestStorageAccessUnderOpenerCallback(Function<void(PAL::SessionID, const RegistrableDomain&, PageIdentifier, const RegistrableDomain&)>&&);76 WEBCORE_EXPORT void setLogUserInteractionNotificationCallback(Function<void(PAL::SessionID, const RegistrableDomain&)>&&);77 78 WEBCORE_EXPORT void updateCentralStatisticsStore();79 WEBCORE_EXPORT void clearState();80 81 60 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED 82 bool shouldLogUserInteraction() const { return m_shouldLogUserInteraction; } 83 void setShouldLogUserInteraction(bool shouldLogUserInteraction) { m_shouldLogUserInteraction = shouldLogUserInteraction; } 61 virtual void setShouldLogUserInteraction(bool) { } 84 62 #endif 85 86 private:87 ResourceLoadObserver();88 89 bool shouldLog(PAL::SessionID) const;90 ResourceLoadStatistics& ensureResourceStatisticsForRegistrableDomain(PAL::SessionID, const RegistrableDomain&);91 void scheduleNotificationIfNeeded();92 93 PerSessionResourceLoadData takeStatistics();94 95 #if ENABLE(RESOURCE_LOAD_STATISTICS)96 void requestStorageAccessUnderOpener(PAL::SessionID, const RegistrableDomain& domainInNeedOfStorageAccess, PageIdentifier openerPageID, Document& openerDocument);97 #endif98 99 HashMap<PAL::SessionID, std::unique_ptr<HashMap<RegistrableDomain, ResourceLoadStatistics>>> m_perSessionResourceStatisticsMap;100 HashMap<RegistrableDomain, WTF::WallTime> m_lastReportedUserInteractionMap;101 Function<void(PerSessionResourceLoadData)> m_notificationCallback;102 Function<void(PAL::SessionID, const RegistrableDomain&, PageIdentifier, const RegistrableDomain&)> m_requestStorageAccessUnderOpenerCallback;103 Function<void(PAL::SessionID, const RegistrableDomain&)> m_logUserInteractionNotificationCallback;104 105 Timer m_notificationTimer;106 107 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED108 uint64_t m_loggingCounter { 0 };109 bool m_shouldLogUserInteraction { false };110 #endif111 112 URL nonNullOwnerURL(const Document&) const;113 63 }; 114 64 -
trunk/Source/WebCore/page/DeprecatedGlobalSettings.h
r240644 r249603 135 135 136 136 static bool gLowPowerVideoAudioBufferSizeEnabled; 137 static bool gResourceLoadStatisticsEnabledEnabled;137 WEBCORE_EXPORT static bool gResourceLoadStatisticsEnabledEnabled; 138 138 static bool gAllowsAnySSLCertificate; 139 139 }; -
trunk/Source/WebKit/ChangeLog
r249600 r249603 1 2019-09-06 Chris Dumez <cdumez@apple.com> 2 3 Move the ResourceLoadObserver logic to WebKit2 4 https://bugs.webkit.org/show_bug.cgi?id=201517 5 6 Reviewed by Brent Fulgham. 7 8 Move the ResourceLoadObserver logic to WebKit2 since it is not used by WebKit1. This allows us to simplify 9 code. 10 11 In a follow-up patch, I will simplify the code even further by leveraging the fact that a WebContent process 12 is always associated with a single WebsiteDataStore / sessionID: 13 - No need for a HashMap of sessionIDs 14 - No need to even allocate the ResourceLoadObserver if the WebProcess is associated with an ephemeral session. 15 16 * NetworkProcess/NetworkConnectionToWebProcess.cpp: 17 (WebKit::NetworkConnectionToWebProcess::resourceLoadStatisticsUpdated): 18 * NetworkProcess/NetworkConnectionToWebProcess.h: 19 * Sources.txt: 20 * WebKit.xcodeproj/project.pbxproj: 21 * WebProcess/WebCoreSupport/WebResourceLoadObserver.cpp: Copied from Source/WebCore/loader/ResourceLoadObserver.cpp. 22 (WebKit::is3xxRedirect): 23 (WebKit::WebResourceLoadObserver::WebResourceLoadObserver): 24 (WebKit::WebResourceLoadObserver::shouldLog const): 25 (WebKit::WebResourceLoadObserver::requestStorageAccessUnderOpener): 26 (WebKit::WebResourceLoadObserver::ensureResourceStatisticsForRegistrableDomain): 27 (WebKit::WebResourceLoadObserver::scheduleNotificationIfNeeded): 28 (WebKit::WebResourceLoadObserver::updateCentralStatisticsStore): 29 (WebKit::WebResourceLoadObserver::statisticsForURL): 30 (WebKit::WebResourceLoadObserver::takeStatistics): 31 (WebKit::WebResourceLoadObserver::clearState): 32 (WebKit::WebResourceLoadObserver::nonNullOwnerURL const): 33 (WebKit::WebResourceLoadObserver::logFontLoad): 34 (WebKit::WebResourceLoadObserver::logCanvasRead): 35 (WebKit::WebResourceLoadObserver::logCanvasWriteOrMeasure): 36 (WebKit::WebResourceLoadObserver::logNavigatorAPIAccessed): 37 (WebKit::WebResourceLoadObserver::logScreenAPIAccessed): 38 (WebKit::WebResourceLoadObserver::logSubresourceLoading): 39 (WebKit::WebResourceLoadObserver::logWebSocketLoading): 40 (WebKit::WebResourceLoadObserver::logUserInteractionWithReducedTimeResolution): 41 * WebProcess/WebCoreSupport/WebResourceLoadObserver.h: Added. 42 * WebProcess/WebProcess.cpp: 43 1 44 2019-09-06 Jiewen Tan <jiewen_tan@apple.com> 2 45 -
trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
r249501 r249603 697 697 } 698 698 699 void NetworkConnectionToWebProcess::resourceLoadStatisticsUpdated( ResourceLoadObserver::PerSessionResourceLoadData&& statistics)699 void NetworkConnectionToWebProcess::resourceLoadStatisticsUpdated(WebResourceLoadObserver::PerSessionResourceLoadData&& statistics) 700 700 { 701 701 for (auto& iter : statistics) { -
trunk/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
r249501 r249603 35 35 #include "NetworkResourceLoadMap.h" 36 36 #include "WebPaymentCoordinatorProxy.h" 37 #include "WebResourceLoadObserver.h" 37 38 #include <WebCore/FrameIdentifier.h> 38 39 #include <WebCore/MessagePortChannelProvider.h> … … 42 43 #include <WebCore/ProcessIdentifier.h> 43 44 #include <WebCore/RegistrableDomain.h> 44 #include <WebCore/ResourceLoadObserver.h>45 45 #include <wtf/RefCounted.h> 46 46 … … 236 236 237 237 void logUserInteraction(PAL::SessionID, const RegistrableDomain&); 238 void resourceLoadStatisticsUpdated(Web Core::ResourceLoadObserver::PerSessionResourceLoadData&&);238 void resourceLoadStatisticsUpdated(WebResourceLoadObserver::PerSessionResourceLoadData&&); 239 239 void hasStorageAccess(PAL::SessionID, const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, WebCore::FrameIdentifier, WebCore::PageIdentifier, CompletionHandler<void(bool)>&&); 240 240 void requestStorageAccess(PAL::SessionID, const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebPageProxyIdentifier, CompletionHandler<void(WebCore::StorageAccessWasGranted, WebCore::StorageAccessPromptWasShown)>&&); -
trunk/Source/WebKit/Sources.txt
r249589 r249603 555 555 WebProcess/WebCoreSupport/WebPopupMenu.cpp 556 556 WebProcess/WebCoreSupport/WebProgressTrackerClient.cpp 557 WebProcess/WebCoreSupport/WebResourceLoadObserver.cpp 557 558 WebProcess/WebCoreSupport/WebSearchPopupMenu.cpp 558 559 WebProcess/WebCoreSupport/WebUserMediaClient.cpp -
trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj
r249589 r249603 911 911 465F4E06230B2E95003CEDB7 /* StorageNamespaceIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 465F4E05230B2E7C003CEDB7 /* StorageNamespaceIdentifier.h */; }; 912 912 466BC03C1FA266DA002FA9C1 /* WebSWContextManagerConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 466BC0391FA266C9002FA9C1 /* WebSWContextManagerConnection.h */; }; 913 4671FF1F23217EFF001B64C7 /* WebResourceLoadObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4671FF1D23217EFF001B64C7 /* WebResourceLoadObserver.h */; }; 913 914 467E43E82243FF7D00B13924 /* WebProcessDataStoreParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 467E43E72243FF6D00B13924 /* WebProcessDataStoreParameters.h */; }; 914 915 46A2B6091E5676A600C3DEDA /* BackgroundProcessResponsivenessTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 46A2B6071E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.h */; }; … … 3218 3219 466BC0391FA266C9002FA9C1 /* WebSWContextManagerConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSWContextManagerConnection.h; sourceTree = "<group>"; }; 3219 3220 466BC03A1FA266C9002FA9C1 /* WebSWContextManagerConnection.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebSWContextManagerConnection.messages.in; sourceTree = "<group>"; }; 3221 4671FF1D23217EFF001B64C7 /* WebResourceLoadObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebResourceLoadObserver.h; sourceTree = "<group>"; }; 3222 4671FF1E23217EFF001B64C7 /* WebResourceLoadObserver.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebResourceLoadObserver.cpp; sourceTree = "<group>"; }; 3220 3223 467E43E72243FF6D00B13924 /* WebProcessDataStoreParameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebProcessDataStoreParameters.h; sourceTree = "<group>"; }; 3221 3224 4683569A21E81CC7006E27A3 /* ProvisionalPageProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProvisionalPageProxy.h; sourceTree = "<group>"; }; … … 7626 7629 1A1E093118861D3800D2DC49 /* WebProgressTrackerClient.cpp */, 7627 7630 1A1E093218861D3800D2DC49 /* WebProgressTrackerClient.h */, 7631 4671FF1E23217EFF001B64C7 /* WebResourceLoadObserver.cpp */, 7632 4671FF1D23217EFF001B64C7 /* WebResourceLoadObserver.h */, 7628 7633 D3B9484411FF4B6500032B39 /* WebSearchPopupMenu.cpp */, 7629 7634 D3B9484511FF4B6500032B39 /* WebSearchPopupMenu.h */, … … 9994 9999 37948404150C350600E52CE9 /* WebRenderLayer.h in Headers */, 9995 10000 3760881F150413E900FC82C7 /* WebRenderObject.h in Headers */, 10001 A5860E71230F67FC00461AAE /* WebResourceInterceptController.h in Headers */, 9996 10002 510AFFBA16542048001BA05E /* WebResourceLoader.h in Headers */, 9997 10003 51F060E01654317F00F3281B /* WebResourceLoaderMessages.h in Headers */, 10004 4671FF1F23217EFF001B64C7 /* WebResourceLoadObserver.h in Headers */, 9998 10005 7AFBD36321E50F39005DBACB /* WebResourceLoadStatisticsStore.h in Headers */, 9999 10006 413075B01DE85F580039EC69 /* WebRTCMonitor.h in Headers */, … … 10212 10219 A54293A4195A43DA002782C7 /* WKInspectorNodeSearchGestureRecognizer.h in Headers */, 10213 10220 6EE849C81368D9390038D481 /* WKInspectorPrivateMac.h in Headers */, 10214 A5860E71230F67FC00461AAE /* WebResourceInterceptController.h in Headers */,10215 10221 994BADF41F7D781400B571E7 /* WKInspectorViewController.h in Headers */, 10216 10222 A518B5D21FE1D55B00F9FA28 /* WKInspectorWKWebView.h in Headers */, -
trunk/Source/WebKit/WebProcess/WebCoreSupport/WebResourceLoadObserver.cpp
r249602 r249603 1 1 /* 2 * Copyright (C) 2016-2019 Apple Inc. All rights reserved.3 4 5 6 7 8 9 10 11 12 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THEIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 *THE POSSIBILITY OF SUCH DAMAGE.24 2 * Copyright (C) 2019 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 25 26 26 #include "config.h" 27 #include "ResourceLoadObserver.h" 28 29 #include "DeprecatedGlobalSettings.h" 30 #include "Document.h" 31 #include "Frame.h" 32 #include "FrameLoader.h" 33 #include "FrameLoaderClient.h" 34 #include "HTMLFrameOwnerElement.h" 35 #include "Logging.h" 36 #include "Page.h" 37 #include "RegistrableDomain.h" 38 #include "ResourceLoadStatistics.h" 39 #include "ResourceRequest.h" 40 #include "ResourceResponse.h" 41 #include "RuntimeEnabledFeatures.h" 42 #include "ScriptExecutionContext.h" 43 #include "SecurityOrigin.h" 44 #include "Settings.h" 45 #include <wtf/URL.h> 46 47 namespace WebCore { 27 #include "WebResourceLoadObserver.h" 28 29 #if ENABLE(RESOURCE_LOAD_STATISTICS) 30 31 #include "NetworkConnectionToWebProcessMessages.h" 32 #include "NetworkProcessConnection.h" 33 #include "WebProcess.h" 34 #include <WebCore/DeprecatedGlobalSettings.h> 35 #include <WebCore/Frame.h> 36 #include <WebCore/FrameLoader.h> 37 #include <WebCore/HTMLFrameOwnerElement.h> 38 39 namespace WebKit { 40 41 using namespace WebCore; 48 42 49 43 static const Seconds minimumNotificationInterval { 5_s }; 50 44 51 ResourceLoadObserver::ResourceLoadObserver() 52 : m_notificationTimer(*this, &ResourceLoadObserver::updateCentralStatisticsStore) 53 { 54 } 55 56 ResourceLoadObserver& ResourceLoadObserver::shared() 57 { 58 static NeverDestroyed<ResourceLoadObserver> resourceLoadObserver; 59 return resourceLoadObserver; 60 } 61 62 void ResourceLoadObserver::setStatisticsUpdatedCallback(Function<void(PerSessionResourceLoadData&&)>&& notificationCallback) 63 { 64 ASSERT(!m_notificationCallback); 65 m_notificationCallback = WTFMove(notificationCallback); 66 } 67 68 void ResourceLoadObserver::setRequestStorageAccessUnderOpenerCallback(Function<void(PAL::SessionID sessionID, const RegistrableDomain& domainInNeedOfStorageAccess, PageIdentifier openerPageID, const RegistrableDomain& openerDomain)>&& callback) 69 { 70 ASSERT(!m_requestStorageAccessUnderOpenerCallback); 71 m_requestStorageAccessUnderOpenerCallback = WTFMove(callback); 72 } 73 74 void ResourceLoadObserver::setLogUserInteractionNotificationCallback(Function<void(PAL::SessionID, const RegistrableDomain&)>&& callback) 75 { 76 ASSERT(!m_logUserInteractionNotificationCallback); 77 m_logUserInteractionNotificationCallback = WTFMove(callback); 78 } 79 80 static inline bool is3xxRedirect(const ResourceResponse& response) 45 static bool is3xxRedirect(const ResourceResponse& response) 81 46 { 82 47 return response.httpStatusCode() >= 300 && response.httpStatusCode() <= 399; 83 48 } 84 49 85 bool ResourceLoadObserver::shouldLog(PAL::SessionID sessionID) const 86 { 87 return DeprecatedGlobalSettings::resourceLoadStatisticsEnabled() && !sessionID.isEphemeral() && m_notificationCallback; 88 } 89 90 void ResourceLoadObserver::logSubresourceLoading(const Frame* frame, const ResourceRequest& newRequest, const ResourceResponse& redirectResponse) 50 static bool shouldLogResourceLoadStatistics(PAL::SessionID sessionID) 51 { 52 return DeprecatedGlobalSettings::resourceLoadStatisticsEnabled() && !sessionID.isEphemeral(); 53 } 54 55 WebResourceLoadObserver::WebResourceLoadObserver() 56 : m_notificationTimer(*this, &WebResourceLoadObserver::updateCentralStatisticsStore) 57 { 58 } 59 60 void WebResourceLoadObserver::requestStorageAccessUnderOpener(PAL::SessionID sessionID, const RegistrableDomain& domainInNeedOfStorageAccess, PageIdentifier openerPageID, Document& openerDocument) 61 { 62 auto openerUrl = openerDocument.url(); 63 RegistrableDomain openerDomain { openerUrl }; 64 if (domainInNeedOfStorageAccess != openerDomain 65 && !openerDocument.hasRequestedPageSpecificStorageAccessWithUserInteraction(domainInNeedOfStorageAccess) 66 && !equalIgnoringASCIICase(openerUrl.string(), WTF::blankURL())) { 67 WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::RequestStorageAccessUnderOpener(sessionID, domainInNeedOfStorageAccess, openerPageID, openerDomain), 0); 68 69 // Remember user interaction-based requests since they don't need to be repeated. 70 openerDocument.setHasRequestedPageSpecificStorageAccessWithUserInteraction(domainInNeedOfStorageAccess); 71 } 72 } 73 74 ResourceLoadStatistics& WebResourceLoadObserver::ensureResourceStatisticsForRegistrableDomain(PAL::SessionID sessionID, const RegistrableDomain& domain) 75 { 76 auto addResult = m_perSessionResourceStatisticsMap.ensure(sessionID, [] { 77 return makeUnique<HashMap<RegistrableDomain, ResourceLoadStatistics>>(); 78 }); 79 80 auto addDomainResult = addResult.iterator->value->ensure(domain, [&domain] { 81 return ResourceLoadStatistics(domain); 82 }); 83 return addDomainResult.iterator->value; 84 } 85 86 void WebResourceLoadObserver::scheduleNotificationIfNeeded() 87 { 88 if (m_perSessionResourceStatisticsMap.isEmpty()) { 89 m_notificationTimer.stop(); 90 return; 91 } 92 93 if (!m_notificationTimer.isActive()) 94 m_notificationTimer.startOneShot(minimumNotificationInterval); 95 } 96 97 void WebResourceLoadObserver::updateCentralStatisticsStore() 98 { 99 m_notificationTimer.stop(); 100 WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::ResourceLoadStatisticsUpdated(takeStatistics()), 0); 101 } 102 103 String WebResourceLoadObserver::statisticsForURL(PAL::SessionID sessionID, const URL& url) 104 { 105 auto* resourceStatisticsByDomain = m_perSessionResourceStatisticsMap.get(sessionID); 106 if (!resourceStatisticsByDomain) 107 return emptyString(); 108 109 auto iter = resourceStatisticsByDomain->find(RegistrableDomain { url }); 110 if (iter == resourceStatisticsByDomain->end()) 111 return emptyString(); 112 113 return makeString("Statistics for ", url.host().toString(), ":\n", iter->value.toString()); 114 } 115 116 auto WebResourceLoadObserver::takeStatistics() -> PerSessionResourceLoadData 117 { 118 PerSessionResourceLoadData perSessionStatistics; 119 120 for (auto& iter : m_perSessionResourceStatisticsMap) { 121 Vector<ResourceLoadStatistics> statistics; 122 statistics.reserveInitialCapacity(iter.value->size()); 123 124 for (auto& statistic : iter.value->values()) 125 statistics.uncheckedAppend(WTFMove(statistic)); 126 127 perSessionStatistics.append(std::make_pair(iter.key, WTFMove(statistics))); 128 } 129 130 m_perSessionResourceStatisticsMap.clear(); 131 return perSessionStatistics; 132 } 133 134 void WebResourceLoadObserver::clearState() 135 { 136 m_notificationTimer.stop(); 137 m_perSessionResourceStatisticsMap.clear(); 138 m_lastReportedUserInteractionMap.clear(); 139 } 140 141 void WebResourceLoadObserver::logFontLoad(const Document& document, const String& familyName, bool loadStatus) 142 { 143 #if ENABLE(WEB_API_STATISTICS) 144 if (!shouldLogResourceLoadStatistics(document.sessionID())) 145 return; 146 147 RegistrableDomain registrableDomain { document.url() }; 148 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 149 bool shouldCallNotificationCallback = false; 150 if (!loadStatus) { 151 if (statistics.fontsFailedToLoad.add(familyName).isNewEntry) 152 shouldCallNotificationCallback = true; 153 } else { 154 if (statistics.fontsSuccessfullyLoaded.add(familyName).isNewEntry) 155 shouldCallNotificationCallback = true; 156 } 157 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 158 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 159 shouldCallNotificationCallback = true; 160 if (shouldCallNotificationCallback) 161 scheduleNotificationIfNeeded(); 162 #else 163 UNUSED_PARAM(document); 164 UNUSED_PARAM(familyName); 165 UNUSED_PARAM(loadStatus); 166 #endif 167 } 168 169 void WebResourceLoadObserver::logCanvasRead(const Document& document) 170 { 171 #if ENABLE(WEB_API_STATISTICS) 172 if (!shouldLogResourceLoadStatistics(document.sessionID())) 173 return; 174 175 RegistrableDomain registrableDomain { document.url() }; 176 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID(), registrableDomain); 177 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 178 statistics.canvasActivityRecord.wasDataRead = true; 179 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 180 scheduleNotificationIfNeeded(); 181 #else 182 UNUSED_PARAM(document); 183 #endif 184 } 185 186 void WebResourceLoadObserver::logCanvasWriteOrMeasure(const Document& document, const String& textWritten) 187 { 188 #if ENABLE(WEB_API_STATISTICS) 189 if (!shouldLogResourceLoadStatistics(document.sessionID())) 190 return; 191 192 RegistrableDomain registrableDomain { document.url() }; 193 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 194 bool shouldCallNotificationCallback = false; 195 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 196 if (statistics.canvasActivityRecord.recordWrittenOrMeasuredText(textWritten)) 197 shouldCallNotificationCallback = true; 198 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 199 shouldCallNotificationCallback = true; 200 if (shouldCallNotificationCallback) 201 scheduleNotificationIfNeeded(); 202 #else 203 UNUSED_PARAM(document); 204 UNUSED_PARAM(textWritten); 205 #endif 206 } 207 208 void WebResourceLoadObserver::logNavigatorAPIAccessed(const Document& document, const ResourceLoadStatistics::NavigatorAPI functionName) 209 { 210 #if ENABLE(WEB_API_STATISTICS) 211 if (!shouldLogResourceLoadStatistics(document.sessionID())) 212 return; 213 214 RegistrableDomain registrableDomain { document.url() }; 215 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 216 bool shouldCallNotificationCallback = false; 217 if (!statistics.navigatorFunctionsAccessed.contains(functionName)) { 218 statistics.navigatorFunctionsAccessed.add(functionName); 219 shouldCallNotificationCallback = true; 220 } 221 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 222 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 223 shouldCallNotificationCallback = true; 224 if (shouldCallNotificationCallback) 225 scheduleNotificationIfNeeded(); 226 #else 227 UNUSED_PARAM(document); 228 UNUSED_PARAM(functionName); 229 #endif 230 } 231 232 void WebResourceLoadObserver::logScreenAPIAccessed(const Document& document, const ResourceLoadStatistics::ScreenAPI functionName) 233 { 234 #if ENABLE(WEB_API_STATISTICS) 235 if (!shouldLogResourceLoadStatistics(document.sessionID())) 236 return; 237 238 RegistrableDomain registrableDomain { document.url() }; 239 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 240 bool shouldCallNotificationCallback = false; 241 if (!statistics.screenFunctionsAccessed.contains(functionName)) { 242 statistics.screenFunctionsAccessed.add(functionName); 243 shouldCallNotificationCallback = true; 244 } 245 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 246 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 247 shouldCallNotificationCallback = true; 248 if (shouldCallNotificationCallback) 249 scheduleNotificationIfNeeded(); 250 #else 251 UNUSED_PARAM(document); 252 UNUSED_PARAM(functionName); 253 #endif 254 } 255 256 void WebResourceLoadObserver::logSubresourceLoading(const Frame* frame, const ResourceRequest& newRequest, const ResourceResponse& redirectResponse) 91 257 { 92 258 ASSERT(frame->page()); … … 96 262 97 263 auto* page = frame->page(); 98 if (!page || !shouldLog (page->sessionID()))264 if (!page || !shouldLogResourceLoadStatistics(page->sessionID())) 99 265 return; 100 266 … … 136 302 } 137 303 138 void ResourceLoadObserver::logWebSocketLoading(const URL& targetURL, const URL& mainFrameURL, PAL::SessionID sessionID)139 { 140 if (!shouldLog (sessionID))304 void WebResourceLoadObserver::logWebSocketLoading(const URL& targetURL, const URL& mainFrameURL, PAL::SessionID sessionID) 305 { 306 if (!shouldLogResourceLoadStatistics(sessionID)) 141 307 return; 142 308 … … 162 328 } 163 329 164 void ResourceLoadObserver::logUserInteractionWithReducedTimeResolution(const Document& document)165 { 166 if (!document.sessionID().isValid() || !shouldLog (document.sessionID()))330 void WebResourceLoadObserver::logUserInteractionWithReducedTimeResolution(const Document& document) 331 { 332 if (!document.sessionID().isValid() || !shouldLogResourceLoadStatistics(document.sessionID())) 167 333 return; 168 334 … … 184 350 statistics.mostRecentUserInteractionTime = newTime; 185 351 186 #if ENABLE(RESOURCE_LOAD_STATISTICS)187 352 if (auto* frame = document.frame()) { 188 353 if (auto* opener = frame->loader().opener()) { … … 198 363 // We notify right away in case of a user interaction instead of waiting the usual 5 seconds because we want 199 364 // to update cookie blocking state as quickly as possible. 200 m_logUserInteractionNotificationCallback(document.sessionID(), topFrameDomain); 201 #endif 202 203 #if ENABLE(RESOURCE_LOAD_STATISTICS) && !RELEASE_LOG_DISABLED 204 if (shouldLogUserInteraction()) { 365 WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::LogUserInteraction(document.sessionID(), topFrameDomain), 0); 366 367 #if !RELEASE_LOG_DISABLED 368 if (m_shouldLogUserInteraction) { 205 369 auto counter = ++m_loggingCounter; 206 370 #define LOCAL_LOG(str, ...) \ … … 223 387 } 224 388 225 #if ENABLE(RESOURCE_LOAD_STATISTICS) 226 void ResourceLoadObserver::requestStorageAccessUnderOpener(PAL::SessionID sessionID, const RegistrableDomain& domainInNeedOfStorageAccess, PageIdentifier openerPageID, Document& openerDocument) 227 { 228 auto openerUrl = openerDocument.url(); 229 RegistrableDomain openerDomain { openerUrl }; 230 if (domainInNeedOfStorageAccess != openerDomain 231 && !openerDocument.hasRequestedPageSpecificStorageAccessWithUserInteraction(domainInNeedOfStorageAccess) 232 && !equalIgnoringASCIICase(openerUrl.string(), WTF::blankURL())) { 233 m_requestStorageAccessUnderOpenerCallback(sessionID, domainInNeedOfStorageAccess, openerPageID, openerDomain); 234 // Remember user interaction-based requests since they don't need to be repeated. 235 openerDocument.setHasRequestedPageSpecificStorageAccessWithUserInteraction(domainInNeedOfStorageAccess); 236 } 237 } 238 #endif 239 240 void ResourceLoadObserver::logFontLoad(const Document& document, const String& familyName, bool loadStatus) 241 { 242 #if ENABLE(WEB_API_STATISTICS) 243 if (!shouldLog(document.sessionID())) 244 return; 245 RegistrableDomain registrableDomain { document.url() }; 246 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 247 bool shouldCallNotificationCallback = false; 248 if (!loadStatus) { 249 if (statistics.fontsFailedToLoad.add(familyName).isNewEntry) 250 shouldCallNotificationCallback = true; 251 } else { 252 if (statistics.fontsSuccessfullyLoaded.add(familyName).isNewEntry) 253 shouldCallNotificationCallback = true; 254 } 255 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 256 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 257 shouldCallNotificationCallback = true; 258 if (shouldCallNotificationCallback) 259 scheduleNotificationIfNeeded(); 260 #else 261 UNUSED_PARAM(document); 262 UNUSED_PARAM(familyName); 263 UNUSED_PARAM(loadStatus); 264 #endif 265 } 266 267 void ResourceLoadObserver::logCanvasRead(const Document& document) 268 { 269 #if ENABLE(WEB_API_STATISTICS) 270 if (!shouldLog(document.sessionID())) 271 return; 272 RegistrableDomain registrableDomain { document.url() }; 273 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID(), registrableDomain); 274 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 275 statistics.canvasActivityRecord.wasDataRead = true; 276 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 277 scheduleNotificationIfNeeded(); 278 #else 279 UNUSED_PARAM(document); 280 #endif 281 } 282 283 void ResourceLoadObserver::logCanvasWriteOrMeasure(const Document& document, const String& textWritten) 284 { 285 #if ENABLE(WEB_API_STATISTICS) 286 if (!shouldLog(document.sessionID())) 287 return; 288 RegistrableDomain registrableDomain { document.url() }; 289 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 290 bool shouldCallNotificationCallback = false; 291 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 292 if (statistics.canvasActivityRecord.recordWrittenOrMeasuredText(textWritten)) 293 shouldCallNotificationCallback = true; 294 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 295 shouldCallNotificationCallback = true; 296 if (shouldCallNotificationCallback) 297 scheduleNotificationIfNeeded(); 298 #else 299 UNUSED_PARAM(document); 300 UNUSED_PARAM(textWritten); 301 #endif 302 } 303 304 void ResourceLoadObserver::logNavigatorAPIAccessed(const Document& document, const ResourceLoadStatistics::NavigatorAPI functionName) 305 { 306 #if ENABLE(WEB_API_STATISTICS) 307 if (!shouldLog(document.sessionID())) 308 return; 309 RegistrableDomain registrableDomain { document.url() }; 310 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 311 bool shouldCallNotificationCallback = false; 312 if (!statistics.navigatorFunctionsAccessed.contains(functionName)) { 313 statistics.navigatorFunctionsAccessed.add(functionName); 314 shouldCallNotificationCallback = true; 315 } 316 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 317 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 318 shouldCallNotificationCallback = true; 319 if (shouldCallNotificationCallback) 320 scheduleNotificationIfNeeded(); 321 #else 322 UNUSED_PARAM(document); 323 UNUSED_PARAM(functionName); 324 #endif 325 } 326 327 void ResourceLoadObserver::logScreenAPIAccessed(const Document& document, const ResourceLoadStatistics::ScreenAPI functionName) 328 { 329 #if ENABLE(WEB_API_STATISTICS) 330 if (!shouldLog(document.sessionID())) 331 return; 332 RegistrableDomain registrableDomain { document.url() }; 333 auto& statistics = ensureResourceStatisticsForRegistrableDomain(document.sessionID, registrableDomain); 334 bool shouldCallNotificationCallback = false; 335 if (!statistics.screenFunctionsAccessed.contains(functionName)) { 336 statistics.screenFunctionsAccessed.add(functionName); 337 shouldCallNotificationCallback = true; 338 } 339 RegistrableDomain mainFrameRegistrableDomain { document.topDocument().url() }; 340 if (statistics.topFrameRegistrableDomainsWhichAccessedWebAPIs.add(mainFrameRegistrableDomain.string()).isNewEntry) 341 shouldCallNotificationCallback = true; 342 if (shouldCallNotificationCallback) 343 scheduleNotificationIfNeeded(); 344 #else 345 UNUSED_PARAM(document); 346 UNUSED_PARAM(functionName); 347 #endif 348 } 349 350 ResourceLoadStatistics& ResourceLoadObserver::ensureResourceStatisticsForRegistrableDomain(PAL::SessionID sessionID, const RegistrableDomain& domain) 351 { 352 auto addResult = m_perSessionResourceStatisticsMap.ensure(sessionID, [] { 353 return makeUnique<HashMap<RegistrableDomain, ResourceLoadStatistics>>(); 354 }); 355 356 auto addDomainResult = addResult.iterator->value->ensure(domain, [&domain] { 357 return ResourceLoadStatistics(domain); 358 }); 359 return addDomainResult.iterator->value; 360 } 361 362 void ResourceLoadObserver::scheduleNotificationIfNeeded() 363 { 364 ASSERT(m_notificationCallback); 365 if (m_perSessionResourceStatisticsMap.isEmpty()) { 366 m_notificationTimer.stop(); 367 return; 368 } 369 370 if (!m_notificationTimer.isActive()) 371 m_notificationTimer.startOneShot(minimumNotificationInterval); 372 } 373 374 void ResourceLoadObserver::updateCentralStatisticsStore() 375 { 376 ASSERT(m_notificationCallback); 377 m_notificationTimer.stop(); 378 m_notificationCallback(takeStatistics()); 379 } 380 381 String ResourceLoadObserver::statisticsForURL(PAL::SessionID sessionID, const URL& url) 382 { 383 auto* resourceStatisticsByDomain = m_perSessionResourceStatisticsMap.get(sessionID); 384 if (!resourceStatisticsByDomain) 385 return emptyString(); 386 387 auto iter = resourceStatisticsByDomain->find(RegistrableDomain { url }); 388 if (iter == resourceStatisticsByDomain->end()) 389 return emptyString(); 390 391 return makeString("Statistics for ", url.host().toString(), ":\n", iter->value.toString()); 392 } 393 394 auto ResourceLoadObserver::takeStatistics() -> PerSessionResourceLoadData 395 { 396 PerSessionResourceLoadData perSessionStatistics; 397 398 for (auto& iter : m_perSessionResourceStatisticsMap) { 399 Vector<ResourceLoadStatistics> statistics; 400 statistics.reserveInitialCapacity(iter.value->size()); 401 402 for (auto& statistic : iter.value->values()) 403 statistics.uncheckedAppend(WTFMove(statistic)); 404 405 perSessionStatistics.append(std::make_pair(iter.key, WTFMove(statistics))); 406 } 407 408 m_perSessionResourceStatisticsMap.clear(); 409 return perSessionStatistics; 410 } 411 412 void ResourceLoadObserver::clearState() 413 { 414 m_notificationTimer.stop(); 415 m_perSessionResourceStatisticsMap.clear(); 416 m_lastReportedUserInteractionMap.clear(); 417 } 418 419 URL ResourceLoadObserver::nonNullOwnerURL(const Document& document) const 420 { 421 auto url = document.url(); 422 auto* frame = document.frame(); 423 auto host = document.url().host(); 424 425 while ((host.isNull() || host.isEmpty()) && frame && !frame->isMainFrame()) { 426 auto* ownerElement = frame->ownerElement(); 427 428 ASSERT(ownerElement != nullptr); 429 430 auto& doc = ownerElement->document(); 431 frame = doc.frame(); 432 url = doc.url(); 433 host = url.host(); 434 } 435 436 return url; 437 } 438 439 } // namespace WebCore 389 } // namespace WebKit 390 391 #endif // ENABLE(RESOURCE_LOAD_STATISTICS) -
trunk/Source/WebKit/WebProcess/WebProcess.cpp
r249501 r249603 68 68 #include "WebProcessPoolMessages.h" 69 69 #include "WebProcessProxyMessages.h" 70 #include "WebResourceLoadObserver.h" 70 71 #include "WebSWContextManagerConnection.h" 71 72 #include "WebSWContextManagerConnectionMessages.h" … … 111 112 #include <WebCore/ProcessWarming.h> 112 113 #include <WebCore/RegistrableDomain.h> 113 #include <WebCore/ResourceLoadObserver.h>114 114 #include <WebCore/ResourceLoadStatistics.h> 115 115 #include <WebCore/RuntimeApplicationChecks.h> … … 218 218 219 219 #if ENABLE(RESOURCE_LOAD_STATISTICS) 220 ResourceLoadObserver::shared().setStatisticsUpdatedCallback([this] (auto&& statistics) { 221 ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::ResourceLoadStatisticsUpdated(WTFMove(statistics)), 0); 222 }); 223 224 ResourceLoadObserver::shared().setRequestStorageAccessUnderOpenerCallback([this] (PAL::SessionID sessionID, const RegistrableDomain& domainInNeedOfStorageAccess, PageIdentifier openerPageID, const RegistrableDomain& openerDomain) { 225 ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::RequestStorageAccessUnderOpener(sessionID, domainInNeedOfStorageAccess, openerPageID, openerDomain), 0); 226 }); 227 228 ResourceLoadObserver::shared().setLogUserInteractionNotificationCallback([this] (PAL::SessionID sessionID, const RegistrableDomain& domain) { ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::LogUserInteraction(sessionID, domain), 0); 229 }); 220 ResourceLoadObserver::setShared(*new WebResourceLoadObserver); 230 221 #endif 231 222 … … 1656 1647 void WebProcess::clearResourceLoadStatistics() 1657 1648 { 1649 #if ENABLE(RESOURCE_LOAD_STATISTICS) 1658 1650 ResourceLoadObserver::shared().clearState(); 1651 #endif 1659 1652 } 1660 1653
Note: See TracChangeset
for help on using the changeset viewer.